]>
git.ipfire.org Git - people/jschlag/pbs.git/blob - src/buildservice/packages.py
9 import pakfire
.packages
as packages
12 from . import database
15 log
= logging
.getLogger("packages")
18 from .constants
import *
19 from .decorators
import *
21 class Packages(base
.Object
):
22 def _get_package(self
, query
, *args
):
23 res
= self
.db
.get(query
, *args
)
26 return Package(self
.backend
, res
.id, data
=res
)
28 def _get_packages(self
, query
, *args
):
29 res
= self
.db
.query(query
, *args
)
32 yield Package(self
.backend
, row
.id, data
=row
)
34 def get_by_id(self
, pkg_id
):
35 return self
._get
_package
("SELECT * FROM packages \
36 WHERE id = %s", pkg_id
)
38 def get_all_names(self
, user
=None, states
=None):
39 query
= "SELECT DISTINCT packages.name AS name, summary FROM packages \
40 JOIN builds ON builds.pkg_id = packages.id \
41 WHERE packages.type = 'source'"
46 if user
and not user
.is_admin():
47 conditions
.append("builds.owner_id = %s")
52 conditions
.append("builds.state = %s")
56 query
+= " AND (%s)" % " OR ".join(conditions
)
58 query
+= " ORDER BY packages.name"
60 return [(n
.name
, n
.summary
) for n
in self
.db
.query(query
, *args
)]
62 def get_by_uuid(self
, uuid
):
63 pkg
= self
.db
.get("SELECT * FROM packages WHERE uuid = %s LIMIT 1", uuid
)
67 return Package(self
.backend
, pkg
.id, pkg
)
69 def create(self
, path
):
70 # Just check if the file really exist
71 assert os
.path
.exists(path
)
73 _pkg
= packages
.open(pakfire
.PakfireServer(), None, path
)
75 hash_sha512
= misc
.calc_hash(path
, "sha512")
80 ("epoch", _pkg
.epoch
),
81 ("version", _pkg
.version
),
82 ("release", _pkg
.release
),
86 ("groups", " ".join(_pkg
.groups
)),
87 ("maintainer", _pkg
.maintainer
),
88 ("license", _pkg
.license
),
90 ("summary", _pkg
.summary
),
91 ("description", _pkg
.description
),
92 ("size", _pkg
.inst_size
),
96 ("build_id", _pkg
.build_id
),
97 ("build_host", _pkg
.build_host
),
98 ("build_time", datetime
.datetime
.utcfromtimestamp(_pkg
.build_time
)),
102 ("filesize", os
.path
.getsize(path
)),
103 ("hash_sha512", hash_sha512
),
106 if _pkg
.type == "source":
107 query
.append(("supported_arches", _pkg
.supported_arches
))
111 for key
, val
in query
:
115 _query
= "INSERT INTO packages(%s)" % ", ".join(keys
)
116 _query
+= " VALUES(%s) RETURNING *" % ", ".join("%s" for v
in vals
)
118 # Create package entry in the database.
119 pkg
= self
._get
_package
(_query
, *vals
)
121 # Dependency information.
122 for d
in _pkg
.prerequires
:
123 pkg
.add_dependency("prerequires", d
)
125 for d
in _pkg
.requires
:
126 pkg
.add_dependency("requires", d
)
128 for d
in _pkg
.provides
:
129 pkg
.add_dependency("provides", d
)
131 for d
in _pkg
.conflicts
:
132 pkg
.add_dependency("conflicts", d
)
134 for d
in _pkg
.obsoletes
:
135 pkg
.add_dependency("obsoletes", d
)
137 # Add all files to filelists table
138 for f
in _pkg
.filelist
:
139 pkg
.add_file(f
.name
, f
.size
, f
.hash1
, f
.type, f
.config
, f
.mode
,
140 f
.user
, f
.group
, f
.mtime
, f
.capabilities
)
142 # Return the newly created object
145 def search(self
, pattern
, limit
=None):
147 Searches for packages that do match the query.
149 This function does not work for UUIDs or filenames.
151 query
= "SELECT * FROM packages \
152 WHERE type = %s AND ( \
155 description LIKE %s \
159 pattern
= "%%%s%%" % pattern
160 args
= ("source", pattern
, pattern
, pattern
)
162 res
= self
.db
.query(query
, *args
)
166 pkg
= Package(self
.backend
, row
.id, row
)
169 if limit
and len(pkgs
) >= limit
:
174 def search_by_filename(self
, filename
, limit
=None):
175 query
= "SELECT filelists.* FROM filelists \
176 JOIN packages ON filelists.pkg_id = packages.id \
177 WHERE filelists.name = %s ORDER BY packages.build_time DESC"
185 for result
in self
.db
.query(query
, *args
):
186 pkg
= Package(self
.backend
, result
.pkg_id
)
187 files
.append((pkg
, result
))
191 def autocomplete(self
, query
, limit
=8):
192 res
= self
.db
.query("SELECT DISTINCT name FROM packages \
193 WHERE packages.name LIKE %s AND packages.type = %s \
194 ORDER BY packages.name LIMIT %s", "%%%s%%" % query
, "source", limit
)
196 return [row
.name
for row
in res
]
199 class Package(base
.DataObject
):
203 return "<%s %s>" % (self
.__class
__.__name
__, self
.friendly_name
)
205 def __eq__(self
, other
):
206 if isinstance(other
, self
.__class
__):
207 return self
.id == other
.id
209 def __lt__(self
, other
):
210 if isinstance(other
, self
.__class
__):
211 return pakfire
.util
.version_compare(self
.backend
, self
.friendly_name
, other
.friendly_name
) < 0
214 self
.db
.execute("INSERT INTO queue_delete(path) VALUES(%s)", self
.path
)
216 # Delete all files from the filelist.
217 self
.db
.execute("DELETE FROM filelists WHERE pkg_id = %s", self
.id)
219 # Delete the package.
220 self
.db
.execute("DELETE FROM packages WHERE id = %s", self
.id)
224 return self
.data
.uuid
228 return self
.data
.name
232 return self
.data
.epoch
236 return self
.data
.version
240 return self
.data
.release
244 return self
.data
.arch
248 return self
.data
.type
251 def friendly_name(self
):
252 return "%s-%s.%s" % (self
.name
, self
.friendly_version
, self
.arch
)
255 def friendly_version(self
):
256 s
= "%s-%s" % (self
.version
, self
.release
)
259 s
= "%s:%s" % (self
.epoch
, s
)
265 return self
.data
.groups
.split()
268 def maintainer(self
):
269 return self
.backend
.users
.find_maintainer(self
.data
.maintainer
) or self
.data
.maintainer
273 return self
.data
.license
281 return self
.data
.summary
284 def description(self
):
285 return self
.data
.description
288 def supported_arches(self
):
289 return self
.data
.supported_arches
293 return self
.data
.size
295 def add_dependency(self
, type, what
):
296 self
.db
.execute("INSERT INTO packages_deps(pkg_id, type, what) \
297 VALUES(%s, %s, %s)", self
.id, type, what
)
299 self
.deps
.append((type, what
))
303 Returns True if the package has got dependencies.
305 Always filter out the uuid provides.
307 return len(self
.deps
) > 1
311 res
= self
.db
.query("SELECT type, what FROM packages_deps \
312 WHERE pkg_id = %s", self
.id)
316 ret
.append((row
.type, row
.what
))
321 def prerequires(self
):
322 return [d
[1] for d
in self
.deps
if d
[0] == "prerequires"]
326 return [d
[1] for d
in self
.deps
if d
[0] == "requires"]
330 return [d
[1] for d
in self
.deps
if d
[0] == "provides" and not d
[1].startswith("uuid(")]
334 return [d
[1] for d
in self
.deps
if d
[0] == "conflicts"]
338 return [d
[1] for d
in self
.deps
if d
[0] == "obsoletes"]
342 return [d
[1] for d
in self
.deps
if d
[0] == "suggests"]
345 def recommends(self
):
346 return [d
[1] for d
in self
.deps
if d
[0] == "recommends"]
348 def get_commit(self
):
349 if self
.data
.commit_id
:
350 return self
.backend
.sources
.get_commit_by_id(self
.data
.commit_id
)
352 def set_commit(self
, commit
):
353 self
._set
_attribute
("commit_id", commit
.id)
355 commit
= lazy_property(get_commit
, set_commit
)
359 # XXX THIS CANNOT RETURN None
362 return self
.commit
.distro
366 return self
.data
.build_id
369 def build_host(self
):
370 return self
.data
.build_host
373 def build_time(self
):
374 return self
.data
.build_time
378 return self
.data
.path
382 return os
.path
.basename(self
.path
)
385 def hash_sha512(self
):
386 return self
.data
.hash_sha512
390 return self
.data
.filesize
393 if os
.path
.isdir(dst
):
394 dst
= os
.path
.join(dst
, self
.filename
)
396 if os
.path
.exists(dst
):
397 raise IOError("Destination file exists: %s" % dst
)
399 src
= os
.path
.join(PACKAGES_DIR
, self
.path
)
401 log
.debug("Copying %s to %s" % (src
, dst
))
403 shutil
.copy2(src
, dst
)
405 def move(self
, target_dir
):
406 # Create directory if it does not exist, yet.
407 if not os
.path
.exists(target_dir
):
408 os
.makedirs(target_dir
)
410 # Make full path where to put the file.
411 target
= os
.path
.join(target_dir
, os
.path
.basename(self
.path
))
413 # Copy the file to the target directory (keeping metadata).
414 shutil
.move(self
.path
, target
)
416 # Update file path in the database.
417 self
._set
_attribute
("path", os
.path
.relpath(target
, PACKAGES_DIR
))
422 return self
.job
.build
424 return self
.backend
.builds
._get
_build
("SELECT * FROM builds \
425 WHERE pkg_id = %s" % self
.id)
429 return self
.backend
.jobs
._get
_job
("SELECT jobs.* FROM jobs \
430 LEFT JOIN jobs_packages pkgs ON jobs.id = pkgs.job_id \
431 WHERE pkgs.pkg_id = %s", self
.id)
435 res
= self
.db
.query("SELECT * FROM filelists \
436 WHERE pkg_id = %s ORDER BY name", self
.id)
440 f
= File(self
.backend
, row
)
445 def get_file(self
, filename
):
446 res
= self
.db
.get("SELECT * FROM filelists \
447 WHERE pkg_id = %s AND name = %s", self
.id, filename
)
450 return File(self
.backend
, res
)
452 def add_file(self
, name
, size
, hash_sha512
, type, config
, mode
, user
, group
, mtime
, capabilities
):
453 # Convert mtime from seconds since epoch to datetime
454 mtime
= datetime
.datetime
.utcfromtimestamp(float(mtime
))
456 self
.db
.execute("INSERT INTO filelists(pkg_id, name, size, hash_sha512, type, config, mode, \
457 \"user\", \"group\", mtime, capabilities) VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
458 self
.id, name
, size
, hash_sha512
, type, config
, mode
, user
, group
, mtime
, capabilities
)
461 path
= os
.path
.join(PACKAGES_DIR
, self
.path
)
463 if os
.path
.exists(path
):
464 return pakfire
.packages
.open(None, None, path
)
468 def update_property(self
, key
, value
):
470 self
.db
.execute("UPDATE packages_properties SET %s = %%s WHERE name = %%s" % key
, value
, self
.name
)
472 self
.db
.execute("INSERT INTO packages_properties(name, %s) VALUES(%%s, %%s)" % key
, self
.name
, value
)
475 self
.property[key
] = value
478 def properties(self
):
479 res
= self
.db
.get("SELECT * FROM packages_properties WHERE name = %s", self
.name
)
485 if key
in ("id", "name"):
493 def critical_path(self
):
494 return self
.properties
.get("critical_path", False)
497 class File(base
.Object
):
498 def init(self
, data
):
501 def __getattr__(self
, attr
):
503 return self
.data
[attr
]
505 raise AttributeError(attr
)
508 def downloadable(self
):
509 # All regular files are downloadable.
510 return self
.type == 0
514 # Empty files cannot be viewed.
518 for ext
in FILE_EXTENSIONS_VIEWABLE
:
519 if self
.name
.endswith(ext
):