]> git.ipfire.org Git - people/jschlag/pbs.git/blob - src/buildservice/sources.py
Drop dependency on textile
[people/jschlag/pbs.git] / src / buildservice / sources.py
1 #!/usr/bin/python
2
3 import datetime
4 import logging
5 import os
6 import subprocess
7
8 import base
9 import builds
10 import database
11 import packages
12
13 class Sources(base.Object):
14 def get_all(self):
15 sources = self.db.query("SELECT id FROM sources ORDER BY id")
16
17 return [Source(self.pakfire, s.id) for s in sources]
18
19 def get_by_id(self, id):
20 return Source(self.pakfire, id)
21
22 def get_by_distro(self, distro):
23 sources = self.db.query("SELECT id FROM sources WHERE distro_id = %s", distro.id)
24
25 return [Source(self.pakfire, s.id) for s in sources]
26
27 def update_revision(self, source_id, revision):
28 query = "UPDATE sources SET revision = %s WHERE id = %s"
29
30 return self.db.execute(query, revision, source_id)
31
32 def get_pending_commits(self, limit=None):
33 query = "SELECT id FROM sources_commits WHERE state = 'pending' ORDER BY id ASC"
34 args = []
35
36 if limit:
37 query += " LIMIT %s"
38 args.append(limit)
39
40 rows = self.db.query(query, *args)
41
42 commits = []
43 for row in rows:
44 commit = Commit(self.pakfire, row.id)
45 commits.append(commit)
46
47 return commits
48
49 def get_commit_by_id(self, commit_id):
50 commit = self.db.get("SELECT id FROM sources_commits WHERE id = %s", commit_id)
51
52 if commit:
53 return Commit(self.pakfire, commit.id)
54
55
56 class Commit(base.Object):
57 def __init__(self, pakfire, id):
58 base.Object.__init__(self, pakfire)
59
60 self.id = id
61
62 # Cache.
63 self._data = None
64 self._source = None
65 self._packages = None
66
67 @classmethod
68 def create(cls, pakfire, source, revision, author, committer, subject, body, date):
69 try:
70 id = pakfire.db.execute("INSERT INTO sources_commits(source_id, revision, \
71 author, committer, subject, body, date) VALUES(%s, %s, %s, %s, %s, %s, %s)",
72 source.id, revision, author, committer, subject, body, date)
73 except database.IntegrityError:
74 # If the commit (apperently) already existed, we return nothing.
75 return
76
77 return cls(pakfire, id)
78
79 @property
80 def data(self):
81 if self._data is None:
82 data = self.db.get("SELECT * FROM sources_commits WHERE id = %s", self.id)
83
84 self._data = data
85 assert self._data
86
87 return self._data
88
89 @property
90 def revision(self):
91 return self.data.revision
92
93 @property
94 def source_id(self):
95 return self.data.source_id
96
97 @property
98 def source(self):
99 if self._source is None:
100 self._source = Source(self.pakfire, self.source_id)
101
102 return self._source
103
104 @property
105 def distro(self):
106 """
107 A shortcut to the distribution this commit
108 belongs to.
109 """
110 return self.source.distro
111
112 def get_state(self):
113 return self.data.state
114
115 def set_state(self, state):
116 self.db.execute("UPDATE sources_commits SET state = %s WHERE id = %s",
117 state, self.id)
118
119 if self._data:
120 self._data["state"] = state
121
122 state = property(get_state, set_state)
123
124 @property
125 def author(self):
126 return self.data.author
127
128 @property
129 def committer(self):
130 return self.data.committer
131
132 @property
133 def subject(self):
134 return self.data.subject.strip()
135
136 @property
137 def message(self):
138 return self.data.body.strip()
139
140 @property
141 def message_full(self):
142 msg = [self.subject, ""] + self.message.splitlines()
143
144 return "\n".join(msg)
145
146 @property
147 def date(self):
148 return self.data.date
149
150 @property
151 def packages(self):
152 if self._packages is None:
153 self._packages = []
154
155 for pkg in self.db.query("SELECT id FROM packages WHERE commit_id = %s", self.id):
156 pkg = packages.Package(self.pakfire, pkg.id)
157 self._packages.append(pkg)
158
159 self._packages.sort()
160
161 return self._packages
162
163 def reset(self):
164 """
165 Removes all packages that have been created by this commit and
166 resets the state so it will be processed again.
167 """
168 # Remove all packages and corresponding builds.
169 for pkg in self.packages:
170 # Check if there is a build associated with the package.
171 # If so, the whole build will be deleted.
172 if pkg.build:
173 pkg.build.delete()
174
175 else:
176 # Delete the package.
177 pkg.delete()
178
179 # Clear the cache.
180 self._packages = None
181
182 # Reset the state to 'pending'.
183 self.state = "pending"
184
185
186 class Source(base.Object):
187 def __init__(self, pakfire, id):
188 base.Object.__init__(self, pakfire)
189
190 self.id = id
191
192 self._data = None
193 self._head_revision = None
194
195 @property
196 def data(self):
197 if self._data is None:
198 data = self.db.get("SELECT * FROM sources WHERE id = %s", self.id)
199
200 self._data = data
201 assert self._data
202
203 return self._data
204
205 def __cmp__(self, other):
206 return cmp(self.id, other.id)
207
208 @property
209 def info(self):
210 return {
211 "id" : self.id,
212 "name" : self.name,
213 "url" : self.url,
214 "path" : self.path,
215 "targetpath" : self.targetpath,
216 "revision" : self.revision,
217 "branch" : self.branch,
218 }
219
220 def _import_revision(self, revision):
221 logging.debug("Going to import revision: %s" % revision)
222
223 rev_author = self._git("log -1 --format=\"%%an <%%ae>\" %s" % revision)
224 rev_committer = self._git("log -1 --format=\"%%cn <%%ce>\" %s" % revision)
225 rev_subject = self._git("log -1 --format=\"%%s\" %s" % revision)
226 rev_body = self._git("log -1 --format=\"%%b\" %s" % revision)
227 rev_date = self._git("log -1 --format=\"%%at\" %s" % revision)
228 rev_date = datetime.datetime.utcfromtimestamp(float(rev_date))
229
230 # Convert strings properly. No idea why I have to do that.
231 rev_author = rev_author.decode("latin-1").strip()
232 rev_committer = rev_committer.decode("latin-1").strip()
233 rev_subject = rev_subject.decode("latin-1").strip()
234 rev_body = rev_body.decode("latin-1").rstrip()
235
236 # Create a new source build object.
237 build.SourceBuild.new(self.pakfire, self.id, revision, rev_author,
238 rev_committer, rev_subject, rev_body, rev_date)
239
240 @property
241 def name(self):
242 return self.data.name
243
244 @property
245 def identifier(self):
246 return self.data.identifier
247
248 @property
249 def url(self):
250 return self.data.url
251
252 @property
253 def gitweb(self):
254 return self.data.gitweb
255
256 @property
257 def revision(self):
258 return self.data.revision
259
260 @property
261 def branch(self):
262 return self.data.branch
263
264 @property
265 def builds(self):
266 return self.pakfire.builds.get_by_source(self.id)
267
268 @property
269 def distro(self):
270 return self.pakfire.distros.get_by_id(self.data.distro_id)
271
272 @property
273 def start_revision(self):
274 return self.data.revision
275
276 @property
277 def head_revision(self):
278 if self._head_revision is None:
279 commit = self.db.get("SELECT id FROM sources_commits \
280 WHERE source_id = %s ORDER BY id DESC LIMIT 1", self.id)
281
282 if commit:
283 self._head_revision = Commit(self.pakfire, commit.id)
284
285 return self._head_revision
286
287 @property
288 def num_commits(self):
289 ret = self.db.get("SELECT COUNT(*) AS num FROM sources_commits \
290 WHERE source_id = %s", self.id)
291
292 return ret.num
293
294 def get_commits(self, limit=None, offset=None):
295 query = "SELECT id FROM sources_commits WHERE source_id = %s \
296 ORDER BY id DESC"
297 args = [self.id,]
298
299 if limit:
300 if offset:
301 query += " LIMIT %s,%s"
302 args += [offset, limit]
303 else:
304 query += " LIMIT %s"
305 args += [limit,]
306
307 commits = []
308 for commit in self.db.query(query, *args):
309 commit = Commit(self.pakfire, commit.id)
310 commits.append(commit)
311
312 return commits
313
314 def get_commit(self, revision):
315 commit = self.db.get("SELECT id FROM sources_commits WHERE source_id = %s \
316 AND revision = %s LIMIT 1", self.id, revision)
317
318 if not commit:
319 return
320
321 commit = Commit(self.pakfire, commit.id)
322 commit._source = self
323
324 return commit