remove all references to samba_3_master and mark as a removed tree
[build-farm.git] / buildfarm / sqldb.py
1 #!/usr/bin/python
2
3 # Samba.org buildfarm
4 # Copyright (C) 2010 Jelmer Vernooij <jelmer@samba.org>
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #
19
20 from buildfarm.tree import (
21     Tree,
22     )
23 from buildfarm.build import (
24     StormBuild,
25     Test,
26     TestResult,
27     )
28 from buildfarm.hostdb import (
29     Host,
30     HostDatabase,
31     HostAlreadyExists,
32     NoSuchHost,
33     )
34
35
36 try:
37     from pysqlite2 import dbapi2 as sqlite3
38 except ImportError:
39     import sqlite3
40 from storm.database import create_database
41 from storm.expr import EXPR, FuncExpr, compile
42 from storm.locals import Bool, Desc, Int, RawStr, Reference, Unicode
43 from storm.store import Store
44
45
46 class Cast(FuncExpr):
47     __slots__ = ("column", "type")
48     name = "CAST"
49
50     def __init__(self, column, type):
51         self.column = column
52         self.type = type
53
54 @compile.when(Cast)
55 def compile_count(compile, cast, state):
56     state.push("context", EXPR)
57     column = compile(cast.column, state)
58     state.pop()
59     return "CAST(%s AS %s)" % (column, cast.type)
60
61
62 class StormHost(Host):
63     __storm_table__ = "host"
64
65     id = Int(primary=True)
66     name = RawStr()
67     owner_name = Unicode(name="owner")
68     owner_email = Unicode()
69     password = Unicode()
70     ssh_access = Bool()
71     fqdn = RawStr()
72     platform = Unicode()
73     permission = Unicode()
74     last_dead_mail = Int()
75     join_time = Int()
76
77     def _set_owner(self, value):
78         if value is None:
79             self.owner_name = None
80             self.owner_email = None
81         else:
82             (self.owner_name, self.owner_email) = value
83
84     def _get_owner(self):
85         if self.owner_name is None:
86             return None
87         else:
88             return (self.owner_name, self.owner_email)
89
90     owner = property(_get_owner, _set_owner)
91
92
93 class StormHostDatabase(HostDatabase):
94
95     def __init__(self, store=None):
96         if store is None:
97             self.store = memory_store()
98         else:
99             self.store = store
100
101     def createhost(self, name, platform=None, owner=None, owner_email=None,
102             password=None, permission=None):
103         """See `HostDatabase.createhost`."""
104         newhost = StormHost(name, owner=owner, owner_email=owner_email,
105                 password=password, permission=permission, platform=platform)
106         try:
107             self.store.add(newhost)
108             self.store.flush()
109         except sqlite3.IntegrityError:
110             raise HostAlreadyExists(name)
111         return newhost
112
113     def deletehost(self, name):
114         """Remove a host."""
115         self.store.remove(self[name])
116
117     def hosts(self):
118         """Retrieve an iterable over all hosts."""
119         return self.store.find(StormHost).order_by(StormHost.name)
120
121     def __getitem__(self, name):
122         result = self.store.find(StormHost,
123             Cast(StormHost.name, "TEXT") == Cast(name, "TEXT"))
124         ret = result.one()
125         if ret is None:
126             raise NoSuchHost(name)
127         return ret
128
129     def commit(self):
130         self.store.commit()
131
132
133 def distinct_builds(builds):
134     done = set()
135     for build in builds:
136         key = (build.tree, build.compiler, build.host)
137         if key in done:
138             continue
139         done.add(key)
140         yield build
141
142
143 class StormTree(Tree):
144     __storm_table__ = "tree"
145
146     id = Int(primary=True)
147     name = RawStr()
148     scm = Int()
149     branch = RawStr()
150     subdir = RawStr()
151     repo = RawStr()
152     scm = RawStr()
153
154
155 class StormTest(Test):
156     __storm_table__ = "test"
157
158     id = Int(primary=True)
159     name = RawStr()
160
161
162 class StormTestResult(TestResult):
163     __storm_table__ = "test_result"
164
165     id = Int(primary=True)
166     build_id = Int(name="build")
167     build = Reference(build_id, StormBuild)
168
169     test_id = Int(name="test")
170     test = Reference(test_id, StormTest)
171
172
173 def setup_schema(db):
174     db.execute("PRAGMA foreign_keys = 1;", noresult=True)
175     db.execute("""
176 CREATE TABLE IF NOT EXISTS host (
177     id integer primary key autoincrement,
178     name blob not null,
179     owner text,
180     owner_email text,
181     password text,
182     ssh_access int,
183     fqdn text,
184     platform text,
185     permission text,
186     last_dead_mail int,
187     join_time int
188 );""", noresult=True)
189     db.execute("CREATE UNIQUE INDEX IF NOT EXISTS unique_hostname ON host (name);", noresult=True)
190     db.execute("""
191 CREATE TABLE IF NOT EXISTS build (
192     id integer primary key autoincrement,
193     tree blob not null,
194     tree_id int,
195     revision blob,
196     host blob not null,
197     host_id integer,
198     compiler blob not null,
199     compiler_id int,
200     checksum blob,
201     age int,
202     status blob,
203     basename blob,
204     FOREIGN KEY (host_id) REFERENCES host (id),
205     FOREIGN KEY (tree_id) REFERENCES tree (id),
206     FOREIGN KEY (compiler_id) REFERENCES compiler (id)
207 );""", noresult=True)
208     db.execute("CREATE UNIQUE INDEX IF NOT EXISTS unique_checksum ON build (checksum);", noresult=True)
209     db.execute("""
210 CREATE TABLE IF NOT EXISTS tree (
211     id integer primary key autoincrement,
212     name blob not null,
213     scm int,
214     branch blob,
215     subdir blob,
216     repo blob
217     );
218     """, noresult=True)
219     db.execute("""
220 CREATE UNIQUE INDEX IF NOT EXISTS unique_tree_name ON tree(name);
221 """, noresult=True)
222     db.execute("""
223 CREATE TABLE IF NOT EXISTS compiler (
224     id integer primary key autoincrement,
225     name blob not null
226     );
227     """, noresult=True)
228     db.execute("""
229 CREATE UNIQUE INDEX IF NOT EXISTS unique_compiler_name ON compiler(name);
230 """, noresult=True)
231     db.execute("""
232 CREATE TABLE IF NOT EXISTS test (
233     id integer primary key autoincrement,
234     name text not null);
235     """, noresult=True)
236     db.execute("CREATE UNIQUE INDEX IF NOT EXISTS test_name ON test(name);",
237         noresult=True)
238     db.execute("""CREATE TABLE IF NOT EXISTS test_result (
239         build int,
240         test int,
241         result int
242         );""", noresult=True)
243     db.execute("""CREATE UNIQUE INDEX IF NOT EXISTS build_test_result ON test_result(build, test);""", noresult=True)
244
245
246 def memory_store():
247     db = create_database("sqlite:")
248     store = Store(db)
249     setup_schema(store)
250     return store