]> git.ipfire.org Git - people/jschlag/pbs.git/blob - backend/repository.py
settings: Add lazy caching for settings.
[people/jschlag/pbs.git] / backend / repository.py
1 #!/usr/bin/python
2
3 import os.path
4
5 import base
6 import builds
7 import logs
8 import packages
9
10 class Repositories(base.Object):
11 def get_all(self):
12 repos = self.db.query("SELECT * FROM repositories")
13
14 return [Repository(self.pakfire, r.id, r) for r in repos]
15
16 def get_by_id(self, repo_id):
17 repo = self.db.get("SELECT * FROM repositories WHERE id = %s", repo_id)
18
19 if repo:
20 return Repository(self.pakfire, repo.id, repo)
21
22 def get_needs_update(self, limit=None):
23 query = "SELECT id FROM repositories WHERE needs_update = 'Y'"
24 query += " ORDER BY last_update ASC"
25
26 # Append limit if any
27 if limit:
28 query += " LIMIT %d" % limit
29
30 repos = self.db.query(query)
31
32 return [Repository(self.pakfire, r.id) for r in repos]
33
34 def get_history(self, limit=None, offset=None, build=None, repo=None, user=None):
35 query = "SELECT * FROM repositories_history"
36 args = []
37
38 query += " ORDER BY time DESC"
39
40 if limit:
41 if offset:
42 query += " LIMIT %s,%s"
43 args += [offset, limit,]
44 else:
45 query += " LIMIT %s"
46 args += [limit,]
47
48 entries = []
49 for entry in self.db.query(query, *args):
50 entry = logs.RepositoryLogEntry(self.pakfire, entry)
51 entries.append(entry)
52
53 return entries
54
55
56 class Repository(base.Object):
57 def __init__(self, pakfire, id, data=None):
58 base.Object.__init__(self, pakfire)
59 self.id = id
60
61 # Cache.
62 self._data = data
63 self._next = None
64 self._prev = None
65 self._key = None
66 self._distro = None
67
68 @property
69 def data(self):
70 if self._data is None:
71 self._data = self.db.get("SELECT * FROM repositories WHERE id = %s", self.id)
72
73 return self._data
74
75 def __cmp__(self, other):
76 if other is None:
77 return 1
78
79 if self.id == other.id:
80 return 0
81
82 elif self.id == other.parent_id:
83 return 1
84
85 elif self.parent_id == other.id:
86 return -1
87
88 return 1
89
90 def next(self):
91 if self._next is None:
92 repo = self.db.get("SELECT id FROM repositories \
93 WHERE parent_id = %s LIMIT 1", self.id)
94
95 if not repo:
96 return
97
98 self._next = Repository(self.pakfire, repo.id)
99
100 return self._next
101
102 def prev(self):
103 if not self.parent_id:
104 return
105
106 if self._prev is None:
107 self._prev = Repository(self.pakfire, self.parent_id)
108
109 return self._prev
110
111 @property
112 def parent(self):
113 return self.prev()
114
115 @classmethod
116 def create(cls, pakfire, distro, name, description):
117 id = pakfire.db.execute("INSERT INTO repositories(distro_id, name, description)"
118 " VALUES(%s, %s, %s)", distro.id, name, description)
119
120 return cls(pakfire, id)
121
122 @property
123 def distro(self):
124 if self._distro is None:
125 self._distro = self.pakfire.distros.get_by_id(self.data.distro_id)
126 assert self._distro
127
128 return self._distro
129
130 @property
131 def info(self):
132 return {
133 "id" : self.id,
134 "distro" : self.distro.info,
135 "name" : self.name,
136 "arches" : self.arches,
137 }
138
139 @property
140 def url(self):
141 url = os.path.join(
142 self.settings.get("repository_baseurl", "http://pakfire.ipfire.org/repositories/"),
143 self.distro.identifier,
144 self.identifier,
145 "%{arch}"
146 )
147
148 return url
149
150 @property
151 def mirrorlist(self):
152 url = os.path.join(
153 self.settings.get("mirrorlist_baseurl", "https://pakfire.ipfire.org/"),
154 "distro", self.distro.identifier,
155 "repo", self.identifier,
156 "mirrorlist?arch=%{arch}"
157 )
158
159 return url
160
161 def get_conf(self):
162 prioritymap = {
163 "stable" : 500,
164 "unstable" : 200,
165 "testing" : 100,
166 }
167
168 try:
169 priority = prioritymap[self.type]
170 except KeyError:
171 priority = None
172
173 lines = [
174 "[repo:%s]" % self.identifier,
175 "description = %s - %s" % (self.distro.name, self.summary),
176 "enabled = 1",
177 "baseurl = %s" % self.url,
178 "mirrors = %s" % self.mirrorlist,
179 ]
180
181 if priority:
182 lines.append("priority = %s" % priority)
183
184 return "\n".join(lines)
185
186 @property
187 def name(self):
188 return self.data.name
189
190 @property
191 def identifier(self):
192 return self.name.lower()
193
194 @property
195 def type(self):
196 return self.data.type
197
198 @property
199 def summary(self):
200 lines = self.description.splitlines()
201
202 if lines:
203 return lines[0]
204
205 return "N/A"
206
207 @property
208 def description(self):
209 return self.data.description or ""
210
211 @property
212 def parent_id(self):
213 return self.data.parent_id
214
215 @property
216 def key(self):
217 if not self.data.key_id:
218 return
219
220 if self._key is None:
221 self._key = self.pakfire.keys.get_by_id(self.data.key_id)
222 assert self._key
223
224 return self._key
225
226 @property
227 def arches(self):
228 return self.distro.arches
229
230 @property
231 def mirrored(self):
232 return self.data.mirrored == "Y"
233
234 def get_enabled_for_builds(self):
235 return self.data.enabled_for_builds == "Y"
236
237 def set_enabled_for_builds(self, state):
238 if state:
239 state = "Y"
240 else:
241 state = "N"
242
243 self.db.execute("UPDATE repositories SET enabled_for_builds = %s WHERE id = %s",
244 state, self.id)
245
246 if self._data:
247 self._data["enabled_for_builds"] = state
248
249 enabled_for_builds = property(get_enabled_for_builds, set_enabled_for_builds)
250
251 @property
252 def score_needed(self):
253 return self.data.score_needed
254
255 @property
256 def time_min(self):
257 return self.data.time_min
258
259 @property
260 def time_max(self):
261 return self.data.time_max
262
263 def _log_build(self, action, build, from_repo=None, to_repo=None, user=None):
264 user_id = None
265 if user:
266 user_id = user.id
267
268 from_repo_id = None
269 if from_repo:
270 from_repo_id = from_repo.id
271
272 to_repo_id = None
273 if to_repo:
274 to_repo_id = to_repo.id
275
276 self.db.execute("INSERT INTO repositories_history(action, build_id, from_repo_id, to_repo_id, user_id, time) \
277 VALUES(%s, %s, %s, %s, %s, NOW())", action, build.id, from_repo_id, to_repo_id, user_id)
278
279 def add_build(self, build, user=None, log=True):
280 self.db.execute("INSERT INTO repositories_builds(repo_id, build_id, time_added)"
281 " VALUES(%s, %s, NOW())", self.id, build.id)
282
283 # Update bug status.
284 build._update_bugs_helper(self)
285
286 if log:
287 self._log_build("added", build, to_repo=self, user=user)
288
289 def rem_build(self, build, user=None, log=True):
290 self.db.execute("DELETE FROM repositories_builds \
291 WHERE repo_id = %s AND build_id = %s", self.id, build.id)
292
293 if log:
294 self._log_build("removed", build, from_repo=self, user=user)
295
296 def move_build(self, build, to_repo, user=None, log=True):
297 self.db.execute("UPDATE repositories_builds SET repo_id = %s, time_added = NOW() \
298 WHERE repo_id = %s AND build_id = %s", to_repo.id, self.id, build.id)
299
300 # Update bug status.
301 build._update_bugs_helper(to_repo)
302
303 if log:
304 self._log_build("moved", build, from_repo=self, to_repo=to_repo,
305 user=user)
306
307 def build_count(self):
308 query = self.db.get("SELECT COUNT(*) AS count FROM repositories_builds \
309 WHERE repo_id = %s", self.id)
310
311 if query:
312 return query.count
313
314 def get_builds(self, limit=None, offset=None):
315 query = "SELECT build_id AS id FROM repositories_builds \
316 WHERE repo_id = %s ORDER BY time_added DESC"
317 args = [self.id,]
318
319 if limit:
320 if offset:
321 query += " LIMIT %s,%s"
322 args += [offset, limit,]
323 else:
324 query += " LIMIT %s"
325 args += [limit,]
326
327 _builds = []
328 for build in self.db.query(query, *args):
329 build = builds.Build(self.pakfire, build.id)
330 build._repo = self
331
332 _builds.append(build)
333
334 return _builds
335
336 def _get_packages(self, arch):
337 if arch.name == "src":
338 pkgs = self.db.query("SELECT packages.id AS id, packages.path AS path FROM packages \
339 JOIN builds ON builds.pkg_id = packages.id \
340 JOIN repositories_builds ON builds.id = repositories_builds.build_id \
341 WHERE packages.arch = %s AND repositories_builds.repo_id = %s",
342 arch.id, self.id)
343
344 else:
345 noarch = self.pakfire.arches.get_by_name("noarch")
346 assert noarch
347
348 pkgs = self.db.query("SELECT packages.id AS id, packages.path AS path FROM packages \
349 JOIN jobs_packages ON jobs_packages.pkg_id = packages.id \
350 JOIN jobs ON jobs_packages.job_id = jobs.id \
351 JOIN builds ON builds.id = jobs.build_id \
352 JOIN repositories_builds ON builds.id = repositories_builds.build_id \
353 WHERE (jobs.arch_id = %s OR jobs.arch_id = %s) AND \
354 repositories_builds.repo_id = %s",
355 arch.id, noarch.id, self.id)
356
357 return pkgs
358
359 def get_packages(self, arch):
360 pkgs = [packages.Package(self.pakfire, p.id) for p in self._get_packages(arch)]
361 pkgs.sort()
362
363 return pkgs
364
365 def get_paths(self, arch):
366 paths = [p.path for p in self._get_packages(arch)]
367 paths.sort()
368
369 return paths
370
371 @property
372 def packages(self):
373 return self.get_packages()
374
375 def get_unpushed_builds(self):
376 query = self.db.query("SELECT build_id FROM repositories_builds \
377 WHERE repo_id = %s AND \
378 time_added > (SELECT last_update FROM repositories WHERE id = %s)",
379 self.id, self.id)
380
381 ret = []
382 for row in query:
383 b = builds.Build(self.pakfire, row.build_id)
384 ret.append(b)
385
386 return ret
387
388 def get_obsolete_builds(self):
389 #query = self.db.query("SELECT build_id AS id FROM repositories_builds \
390 # JOIN builds ON repositories.build_id = builds.id \
391 # WHERE repositories_builds.repo_id = %s AND builds.state = 'obsolete'",
392 # self.id)
393 #
394 #ret = []
395 #for row in query:
396 # b = builds.Build(self.pakfire, row.id)
397 # ret.append(b)
398 #
399 #return ret
400 return self.pakfire.builds.get_obsolete(self)
401
402 def needs_update(self):
403 if self.get_unpushed_builds:
404 return True
405
406 return False
407
408 def updated(self):
409 self.db.execute("UPDATE repositories SET last_update = NOW() \
410 WHERE id = %s", self.id)
411
412 def get_history(self, **kwargs):
413 kwargs.update({
414 "repo" : self,
415 })
416
417 return self.pakfire.repos.get_history(**kwargs)
418
419 def get_build_times(self):
420 noarch = self.pakfire.arches.get_by_name("noarch")
421 assert noarch
422
423 times = []
424 for arch in self.pakfire.arches.get_all():
425 time = self.db.get("SELECT SUM(UNIX_TIMESTAMP(jobs.time_finished) - UNIX_TIMESTAMP(jobs.time_started)) AS time FROM jobs \
426 JOIN builds ON builds.id = jobs.build_id \
427 JOIN repositories_builds ON builds.id = repositories_builds.build_id \
428 WHERE (jobs.arch_id = %s OR jobs.arch_id = %s) AND \
429 jobs.type = 'build' AND \
430 repositories_builds.repo_id = %s", arch.id, noarch.id, self.id)
431
432 times.append((arch, time.time))
433
434 return times
435
436
437 class RepositoryAux(base.Object):
438 def __init__(self, pakfire, id):
439 base.Object.__init__(self, pakfire)
440
441 self.id = id
442
443 # Cache.
444 self._data = None
445 self._distro = None
446
447 @property
448 def data(self):
449 if self._data is None:
450 self._data = self.db.get("SELECT * FROM repositories_aux WHERE id = %s", self.id)
451 assert self._data
452
453 return self._data
454
455 @property
456 def name(self):
457 return self.data.name
458
459 @property
460 def description(self):
461 return self.data.description or ""
462
463 @property
464 def url(self):
465 return self.data.url
466
467 @property
468 def identifier(self):
469 return self.name.lower()
470
471 @property
472 def distro(self):
473 if self._distro is None:
474 self._distro = self.pakfire.distros.get_by_id(self.data.distro_id)
475 assert self._distro
476
477 return self._distro
478
479 def get_conf(self):
480 lines = [
481 "[repo:%s]" % self.identifier,
482 "description = %s - %s" % (self.distro.name, self.name),
483 "enabled = 1",
484 "baseurl = %s" % self.url,
485 "priority = 0",
486 ]
487
488 return "\n".join(lines)