X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=daklib%2Fdbconn.py;h=e685d9190f9bc8b2460e1f379696f05ff83efcaa;hb=b330cb76fe5d7067655b34b755de70c6a26643d9;hp=59fe5dc3c0f6fd5a1ce8c8ca1edda8958b4064cf;hpb=c11e2b4f33f57e89d02e55a9216f9ae6f91b18ca;p=dak.git diff --git a/daklib/dbconn.py b/daklib/dbconn.py index 59fe5dc3..e685d919 100755 --- a/daklib/dbconn.py +++ b/daklib/dbconn.py @@ -46,7 +46,7 @@ from inspect import getargspec import sqlalchemy from sqlalchemy import create_engine, Table, MetaData, Column, Integer -from sqlalchemy.orm import sessionmaker, mapper, relation +from sqlalchemy.orm import sessionmaker, mapper, relation, object_session, backref from sqlalchemy import types as sqltypes # Don't remove this, we re-export the exceptions to scripts which import us @@ -59,6 +59,16 @@ from config import Config from textutils import fix_maintainer from dak_exceptions import NoSourceFieldError +# suppress some deprecation warnings in squeeze related to sqlalchemy +import warnings +warnings.filterwarnings('ignore', \ + "The SQLAlchemy PostgreSQL dialect has been renamed from 'postgres' to 'postgresql'.*", \ + SADeprecationWarning) +# TODO: sqlalchemy needs some extra configuration to correctly reflect +# the ind_deb_contents_* indexes - we ignore the warnings at the moment +warnings.filterwarnings("ignore", 'Predicate of partial index', SAWarning) + + ################################################################################ # Patch in support for the debversion field type so that it works during @@ -193,6 +203,7 @@ def get_architecture(architecture, session=None): __all__.append('get_architecture') +# TODO: should be removed because the implementation is too trivial @session_wrapper def get_architecture_suites(architecture, session=None): """ @@ -209,13 +220,7 @@ def get_architecture_suites(architecture, session=None): @return: list of Suite objects for the given name (may be empty) """ - q = session.query(Suite) - q = q.join(SuiteArchitecture) - q = q.join(Architecture).filter_by(arch_string=architecture).order_by('suite_name') - - ret = q.all() - - return ret + return get_architecture(architecture, session).suites __all__.append('get_architecture_suites') @@ -1065,8 +1070,12 @@ __all__.append('get_dscfiles') ################################################################################ class PoolFile(object): - def __init__(self, *args, **kwargs): - pass + def __init__(self, filename = None, location = None, filesize = -1, \ + md5sum = None): + self.filename = filename + self.location = location + self.filesize = filesize + self.md5sum = md5sum def __repr__(self): return '' % self.filename @@ -1075,13 +1084,16 @@ class PoolFile(object): def fullpath(self): return os.path.join(self.location.path, self.filename) + def is_valid(self, filesize = -1, md5sum = None):\ + return self.filesize == filesize and self.md5sum == md5sum + __all__.append('PoolFile') @session_wrapper def check_poolfile(filename, filesize, md5sum, location_id, session=None): """ Returns a tuple: - (ValidFileFound [boolean or None], PoolFile object or None) + (ValidFileFound [boolean], PoolFile object or None) @type filename: string @param filename: the filename of the file to check against the DB @@ -1097,34 +1109,24 @@ def check_poolfile(filename, filesize, md5sum, location_id, session=None): @rtype: tuple @return: Tuple of length 2. - - If more than one file found with that name: (C{None}, C{None}) - If valid pool file found: (C{True}, C{PoolFile object}) - If valid pool file not found: - (C{False}, C{None}) if no file found - (C{False}, C{PoolFile object}) if file found with size/md5sum mismatch """ - q = session.query(PoolFile).filter_by(filename=filename) - q = q.join(Location).filter_by(location_id=location_id) - - ret = None + poolfile = session.query(Location).get(location_id). \ + files.filter_by(filename=filename).first() + valid = False + if poolfile and poolfile.is_valid(filesize = filesize, md5sum = md5sum): + valid = True - if q.count() > 1: - ret = (None, None) - elif q.count() < 1: - ret = (False, None) - else: - obj = q.one() - if obj.md5sum != md5sum or obj.filesize != int(filesize): - ret = (False, obj) - - if ret is None: - ret = (True, obj) - - return ret + return (valid, poolfile) __all__.append('check_poolfile') +# TODO: the implementation can trivially be inlined at the place where the +# function is called @session_wrapper def get_poolfile_by_id(file_id, session=None): """ @@ -1137,41 +1139,10 @@ def get_poolfile_by_id(file_id, session=None): @return: either the PoolFile object or None """ - q = session.query(PoolFile).filter_by(file_id=file_id) - - try: - return q.one() - except NoResultFound: - return None + return session.query(PoolFile).get(file_id) __all__.append('get_poolfile_by_id') - -@session_wrapper -def get_poolfile_by_name(filename, location_id=None, session=None): - """ - Returns an array of PoolFile objects for the given filename and - (optionally) location_id - - @type filename: string - @param filename: the filename of the file to check against the DB - - @type location_id: int - @param location_id: the id of the location to look in (optional) - - @rtype: array - @return: array of PoolFile objects - """ - - q = session.query(PoolFile).filter_by(filename=filename) - - if location_id is not None: - q = q.join(Location).filter_by(location_id=location_id) - - return q.all() - -__all__.append('get_poolfile_by_name') - @session_wrapper def get_poolfile_like_name(filename, session=None): """ @@ -1517,8 +1488,10 @@ __all__.append('get_dbchange') ################################################################################ class Location(object): - def __init__(self, *args, **kwargs): - pass + def __init__(self, path = None): + self.path = path + # the column 'type' should go away, see comment at mapper + self.archive_type = 'pool' def __repr__(self): return '' % (self.path, self.location_id) @@ -1562,8 +1535,8 @@ __all__.append('get_location') ################################################################################ class Maintainer(object): - def __init__(self, *args, **kwargs): - pass + def __init__(self, name = None): + self.name = name def __repr__(self): return '''''' % (self.name, self.maintainer_id) @@ -2101,8 +2074,9 @@ __all__.append('get_sections') ################################################################################ class DBSource(object): - def __init__(self, *args, **kwargs): - pass + def __init__(self, maintainer = None, changedby = None): + self.maintainer = maintainer + self.changedby = changedby def __repr__(self): return '' % (self.source, self.version) @@ -2530,38 +2504,31 @@ class Suite(object): return "\n".join(ret) -__all__.append('Suite') - -@session_wrapper -def get_suite_architecture(suite, architecture, session=None): - """ - Returns a SuiteArchitecture object given C{suite} and ${arch} or None if it - doesn't exist - - @type suite: str - @param suite: Suite name to search for - - @type architecture: str - @param architecture: Architecture name to search for + def get_architectures(self, skipsrc=False, skipall=False): + """ + Returns list of Architecture objects - @type session: Session - @param session: Optional SQL session object (a temporary one will be - generated if not supplied) + @type skipsrc: boolean + @param skipsrc: Whether to skip returning the 'source' architecture entry + (Default False) - @rtype: SuiteArchitecture - @return: the SuiteArchitecture object or None - """ + @type skipall: boolean + @param skipall: Whether to skip returning the 'all' architecture entry + (Default False) - q = session.query(SuiteArchitecture) - q = q.join(Architecture).filter_by(arch_string=architecture) - q = q.join(Suite).filter_by(suite_name=suite) + @rtype: list + @return: list of Architecture objects for the given name (may be empty) + """ - try: - return q.one() - except NoResultFound: - return None + q = object_session(self).query(Architecture). \ + filter(Architecture.suites.contains(self)) + if skipsrc: + q = q.filter(Architecture.arch_string != 'source') + if skipall: + q = q.filter(Architecture.arch_string != 'all') + return q.order_by(Architecture.arch_string).all() -__all__.append('get_suite_architecture') +__all__.append('Suite') @session_wrapper def get_suite(suite, session=None): @@ -2590,15 +2557,7 @@ __all__.append('get_suite') ################################################################################ -class SuiteArchitecture(object): - def __init__(self, *args, **kwargs): - pass - - def __repr__(self): - return '' % (self.suite_id, self.arch_id) - -__all__.append('SuiteArchitecture') - +# TODO: should be removed because the implementation is too trivial @session_wrapper def get_suite_architectures(suite, skipsrc=False, skipall=False, session=None): """ @@ -2623,19 +2582,7 @@ def get_suite_architectures(suite, skipsrc=False, skipall=False, session=None): @return: list of Architecture objects for the given name (may be empty) """ - q = session.query(Architecture) - q = q.join(SuiteArchitecture) - q = q.join(Suite).filter_by(suite_name=suite) - - if skipsrc: - q = q.filter(Architecture.arch_string != 'source') - - if skipall: - q = q.filter(Architecture.arch_string != 'all') - - q = q.order_by('arch_string') - - return q.all() + return get_suite(suite, session).get_architectures(skipsrc, skipall) __all__.append('get_suite_architectures') @@ -2874,8 +2821,10 @@ class DBConn(object): def __setupmappers(self): mapper(Architecture, self.tbl_architecture, - properties = dict(arch_id = self.tbl_architecture.c.id, - suites = relation(Suite, secondary=self.tbl_suite_architectures, backref='architectures'))) + properties = dict(arch_id = self.tbl_architecture.c.id, + suites = relation(Suite, secondary=self.tbl_suite_architectures, + order_by='suite_name', + backref=backref('architectures', order_by='arch_string')))) mapper(Archive, self.tbl_archive, properties = dict(archive_id = self.tbl_archive.c.id, @@ -2964,7 +2913,11 @@ class DBConn(object): properties = dict(file_id = self.tbl_files.c.id, filesize = self.tbl_files.c.size, location_id = self.tbl_files.c.location, - location = relation(Location))) + location = relation(Location, + # using lazy='dynamic' in the back + # reference because we have A LOT of + # files in one location + backref=backref('files', lazy='dynamic')))) mapper(Fingerprint, self.tbl_fingerprint, properties = dict(fingerprint_id = self.tbl_fingerprint.c.id, @@ -3037,10 +2990,16 @@ class DBConn(object): component = relation(Component), archive_id = self.tbl_location.c.archive, archive = relation(Archive), + # FIXME: the 'type' column is old cruft and + # should be removed in the future. archive_type = self.tbl_location.c.type)) mapper(Maintainer, self.tbl_maintainer, - properties = dict(maintainer_id = self.tbl_maintainer.c.id)) + properties = dict(maintainer_id = self.tbl_maintainer.c.id, + maintains_sources = relation(DBSource, backref='maintainer', + primaryjoin=(self.tbl_maintainer.c.id==self.tbl_source.c.maintainer)), + changed_sources = relation(DBSource, backref='changedby', + primaryjoin=(self.tbl_maintainer.c.id==self.tbl_source.c.changedby)))) mapper(NewComment, self.tbl_new_comments, properties = dict(comment_id = self.tbl_new_comments.c.id)) @@ -3076,19 +3035,15 @@ class DBConn(object): properties = dict(source_id = self.tbl_source.c.id, version = self.tbl_source.c.version, maintainer_id = self.tbl_source.c.maintainer, - maintainer = relation(Maintainer, - primaryjoin=(self.tbl_source.c.maintainer==self.tbl_maintainer.c.id)), poolfile_id = self.tbl_source.c.file, poolfile = relation(PoolFile), fingerprint_id = self.tbl_source.c.sig_fpr, fingerprint = relation(Fingerprint), changedby_id = self.tbl_source.c.changedby, - changedby = relation(Maintainer, - primaryjoin=(self.tbl_source.c.changedby==self.tbl_maintainer.c.id)), srcfiles = relation(DSCFile, primaryjoin=(self.tbl_source.c.id==self.tbl_dsc_files.c.source)), - srcassociations = relation(SrcAssociation, - primaryjoin=(self.tbl_source.c.id==self.tbl_src_associations.c.source)), + suites = relation(Suite, secondary=self.tbl_src_associations, + backref='sources'), srcuploaders = relation(SrcUploader))) mapper(SourceACL, self.tbl_source_acl, @@ -3119,12 +3074,6 @@ class DBConn(object): policy_queue = relation(PolicyQueue), copy_queues = relation(BuildQueue, secondary=self.tbl_suite_build_queue_copy))) - mapper(SuiteArchitecture, self.tbl_suite_architectures, - properties = dict(suite_id = self.tbl_suite_architectures.c.suite, - suite = relation(Suite, backref='suitearchitectures'), - arch_id = self.tbl_suite_architectures.c.architecture, - architecture = relation(Architecture))) - mapper(SuiteSrcFormat, self.tbl_suite_src_formats, properties = dict(suite_id = self.tbl_suite_src_formats.c.suite, suite = relation(Suite, backref='suitesrcformats'),