X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=daklib%2Fdbconn.py;h=43c0b6985e7ebf723423cce58f6a1c59d353bfe3;hb=d2abbacce6a354ff538275797387570df81ef813;hp=593b668f1889e54ec50910f80bef3af57619b518;hpb=40af2eb02193b19c69744ff47651dd009f5a1f6e;p=dak.git diff --git a/daklib/dbconn.py b/daklib/dbconn.py index 593b668f..43c0b698 100755 --- a/daklib/dbconn.py +++ b/daklib/dbconn.py @@ -59,6 +59,18 @@ class Architecture(object): def __init__(self, *args, **kwargs): pass + def __eq__(self, val): + if isinstance(val, str): + return (self.arch_string== val) + # This signals to use the normal comparison operator + return NotImplemented + + def __ne__(self, val): + if isinstance(val, str): + return (self.arch_string != val) + # This signals to use the normal comparison operator + return NotImplemented + def __repr__(self): return '' % self.arch_string @@ -171,6 +183,24 @@ class DBBinary(object): __all__.append('DBBinary') +def get_suites_binary_in(package, session=None): + """ + Returns list of Suite objects which given C{package} name is in + + @type source: str + @param source: DBBinary package name to search for + + @rtype: list + @return: list of Suite objects for the given package + """ + + if session is None: + session = DBConn().session() + + return session.query(Suite).join(BinAssociation).join(DBBinary).filter_by(package=package).all() + +__all__.append('get_suites_binary_in') + def get_binary_from_id(id, session=None): """ Returns DBBinary object for given C{id} @@ -194,13 +224,19 @@ def get_binary_from_id(id, session=None): __all__.append('get_binary_from_id') -def get_binaries_from_name(package, session=None): +def get_binaries_from_name(package, version=None, architecture=None, session=None): """ Returns list of DBBinary objects for given C{package} name @type package: str @param package: DBBinary package name to search for + @type version: str or None + @param version: Version to search for (or None) + + @type package: str, list or None + @param package: Architectures to limit to (or None if no limit) + @type session: Session @param session: Optional SQL session object (a temporary one will be generated if not supplied) @@ -210,10 +246,42 @@ def get_binaries_from_name(package, session=None): """ if session is None: session = DBConn().session() - return session.query(DBBinary).filter_by(package=package).all() + + q = session.query(DBBinary).filter_by(package=package) + + if version is not None: + q = q.filter_by(version=version) + + if architecture is not None: + if not isinstance(architecture, list): + architecture = [architecture] + q = q.join(Architecture).filter(Architecture.arch_string.in_(architecture)) + + return q.all() __all__.append('get_binaries_from_name') +def get_binaries_from_source_id(source_id, session=None): + """ + Returns list of DBBinary objects for given C{source_id} + + @type source_id: int + @param source_id: source_id to search for + + @type session: Session + @param session: Optional SQL session object (a temporary one will be + generated if not supplied) + + @rtype: list + @return: list of DBBinary objects for the given name (may be empty) + """ + if session is None: + session = DBConn().session() + return session.query(DBBinary).filter_by(source_id=source_id).all() + +__all__.append('get_binaries_from_source_id') + + def get_binary_from_name_suite(package, suitename, session=None): ### For dak examine-package ### XXX: Doesn't use object API yet @@ -252,12 +320,25 @@ def get_binary_components(package, suitename, arch, session=None): return session.execute(query, vals) __all__.append('get_binary_components') + ################################################################################ class Component(object): def __init__(self, *args, **kwargs): pass + def __eq__(self, val): + if isinstance(val, str): + return (self.component_name == val) + # This signals to use the normal comparison operator + return NotImplemented + + def __ne__(self, val): + if isinstance(val, str): + return (self.component_name != val) + # This signals to use the normal comparison operator + return NotImplemented + def __repr__(self): return '' % self.component_name @@ -522,6 +603,41 @@ class DSCFile(object): __all__.append('DSCFile') +def get_dscfiles(dscfile_id=None, source_id=None, poolfile_id=None, session=None): + """ + Returns a list of DSCFiles which may be empty + + @type dscfile_id: int (optional) + @param dscfile_id: the dscfile_id of the DSCFiles to find + + @type source_id: int (optional) + @param source_id: the source id related to the DSCFiles to find + + @type poolfile_id: int (optional) + @param poolfile_id: the poolfile id related to the DSCFiles to find + + @rtype: list + @return: Possibly empty list of DSCFiles + """ + + if session is None: + session = DBConn().session() + + q = session.query(DSCFile) + + if dscfile_id is not None: + q = q.filter_by(dscfile_id=dscfile_id) + + if source_id is not None: + q = q.filter_by(source_id=source_id) + + if poolfile_id is not None: + q = q.filter_by(poolfile_id=poolfile_id) + + return q.all() + +__all__.append('get_dscfiles') + ################################################################################ class PoolFile(object): @@ -533,6 +649,76 @@ class PoolFile(object): __all__.append('PoolFile') +def check_poolfile(filename, filesize, md5sum, location_id, session=None): + """ + Returns a tuple: + (ValidFileFound [boolean or None], PoolFile object or None) + + @type filename: string + @param filename: the filename of the file to check against the DB + + @type filesize: int + @param filesize: the size of the file to check against the DB + + @type md5sum: string + @param md5sum: the md5sum of the file to check against the DB + + @type location_id: int + @param location_id: the id of the location to look in + + @rtype: tuple + @return: Tuple of length 2. + If more than one file found with that name: + (None, None) + If valid pool file found: (True, PoolFile object) + If valid pool file not found: + (False, None) if no file found + (False, PoolFile object) if file found with size/md5sum mismatch + """ + + if session is None: + session = DBConn().session() + + q = session.query(PoolFile).filter_by(filename=filename) + q = q.join(Location).filter_by(location_id=location_id) + + if q.count() > 1: + return (None, None) + if q.count() < 1: + return (False, None) + + obj = q.one() + if obj.md5sum != md5sum or obj.filesize != filesize: + return (False, obj) + + return (True, obj) + +__all__.append('check_poolfile') + +def get_poolfile_by_id(file_id, session=None): + """ + Returns a PoolFile objects or None for the given id + + @type file_id: int + @param file_id: the id of the file to look for + + @rtype: PoolFile or None + @return: either the PoolFile object or None + """ + + if session is None: + session = DBConn().session() + + q = session.query(PoolFile).filter_by(file_id=file_id) + + if q.count() > 0: + return q.one() + + return None + +__all__.append('get_poolfile_by_id') + + def get_poolfile_by_name(filename, location_id=None, session=None): """ Returns an array of PoolFile objects for the given filename and @@ -548,7 +734,7 @@ def get_poolfile_by_name(filename, location_id=None, session=None): @return: array of PoolFile objects """ - if session is not None: + if session is None: session = DBConn().session() q = session.query(PoolFile).filter_by(filename=filename) @@ -571,7 +757,7 @@ def get_poolfile_like_name(filename, session=None): @return: array of PoolFile objects """ - if session is not None: + if session is None: session = DBConn().session() # TODO: There must be a way of properly using bind parameters with %FOO% @@ -592,6 +778,49 @@ class Fingerprint(object): __all__.append('Fingerprint') +def get_or_set_fingerprint(fpr, session=None): + """ + Returns Fingerprint object for given fpr. + + If no matching fpr is found, a row is inserted. + + @type fpr: string + @param fpr: The fpr to find / add + + @type session: SQLAlchemy + @param session: Optional SQL session object (a temporary one will be + generated if not supplied). If not passed, a commit will be performed at + the end of the function, otherwise the caller is responsible for commiting. + A flush will be performed either way. + + @rtype: Fingerprint + @return: the Fingerprint object for the given fpr + """ + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + try: + q = session.query(Fingerprint).filter_by(fingerprint=fpr) + if q.count() < 1: + fingerprint = Fingerprint() + fingerprint.fingerprint = fpr + session.add(fingerprint) + if privatetrans: + session.commit() + else: + session.flush() + return fingerprint + else: + return q.one() + + except: + traceback.print_exc() + raise + +__all__.append('get_or_set_fingerprint') + ################################################################################ class Keyring(object): @@ -667,6 +896,123 @@ class Maintainer(object): __all__.append('Maintainer') +def get_or_set_maintainer(name, session=None): + """ + Returns Maintainer object for given maintainer name. + + If no matching maintainer name is found, a row is inserted. + + @type name: string + @param name: The maintainer name to add + + @type session: SQLAlchemy + @param session: Optional SQL session object (a temporary one will be + generated if not supplied). If not passed, a commit will be performed at + the end of the function, otherwise the caller is responsible for commiting. + A flush will be performed either way. + + @rtype: Maintainer + @return: the Maintainer object for the given maintainer + """ + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + try: + q = session.query(Maintainer).filter_by(name=name) + if q.count() < 1: + maintainer = Maintainer() + maintainer.name = name + session.add(maintainer) + if privatetrans: + session.commit() + else: + session.flush() + return maintainer + else: + return q.one() + + except: + traceback.print_exc() + raise + +__all__.append('get_or_set_maintainer') + +################################################################################ + +class NewComment(object): + def __init__(self, *args, **kwargs): + pass + + def __repr__(self): + return '''''' % (self.package, self.version, self.comment_id) + +__all__.append('NewComment') + +def has_new_comment(package, version, session=None): + """ + Returns true if the given combination of C{package}, C{version} has a comment. + + @type package: string + @param package: name of the package + + @type version: string + @param version: package version + + @type session: Session + @param session: Optional SQLA session object (a temporary one will be + generated if not supplied) + + @rtype: boolean + @return: true/false + """ + + if session is None: + session = DBConn().session() + + q = session.query(NewComment) + q = q.filter_by(package=package) + q = q.filter_by(version=version) + return q.count() > 0 + +__all__.append('has_new_comment') + +def get_new_comments(package=None, version=None, comment_id=None, session=None): + """ + Returns (possibly empty) list of NewComment objects for the given + parameters + + @type package: string (optional) + @param package: name of the package + + @type version: string (optional) + @param version: package version + + @type comment_id: int (optional) + @param comment_id: An id of a comment + + @type session: Session + @param session: Optional SQLA session object (a temporary one will be + generated if not supplied) + + @rtype: list + @return: A (possibly empty) list of NewComment objects will be returned + + """ + + if session is None: + session = DBConn().session() + + q = session.query(NewComment) + if package is not None: q = q.filter_by(package=package) + if version is not None: q = q.filter_by(version=version) + if comment_id is not None: q = q.filter_by(comment_id=comment_id) + + return q.all() + +__all__.append('get_new_comments') + ################################################################################ class Override(object): @@ -846,6 +1192,18 @@ class Priority(object): def __init__(self, *args, **kwargs): pass + def __eq__(self, val): + if isinstance(val, str): + return (self.priority == val) + # This signals to use the normal comparison operator + return NotImplemented + + def __ne__(self, val): + if isinstance(val, str): + return (self.priority != val) + # This signals to use the normal comparison operator + return NotImplemented + def __repr__(self): return '' % (self.priority, self.priority_id) @@ -1032,15 +1390,15 @@ class QueueBuild(object): __all__.append('QueueBuild') -def get_queue_build(filename, suite_id, session=None): +def get_queue_build(filename, suite, session=None): """ - Returns QueueBuild object for given C{filename} and C{suite id}. + Returns QueueBuild object for given C{filename} and C{suite}. @type filename: string @param filename: The name of the file - @type suiteid: int - @param suiteid: Suite ID + @type suiteid: int or str + @param suiteid: Suite name or ID @type session: Session @param session: Optional SQLA session object (a temporary one will be @@ -1052,7 +1410,12 @@ def get_queue_build(filename, suite_id, session=None): """ if session is None: session = DBConn().session() - q = session.query(QueueBuild).filter_by(filename=filename).filter_by(suite_id=suite_id) + if isinstance(suite, int): + q = session.query(QueueBuild).filter_by(filename=filename).filter_by(suite_id=suite) + else: + q = session.query(QueueBuild).filter_by(filename=filename) + q = q.join(Suite).filter_by(suite_name=suite) + if q.count() == 0: return None return q.one() @@ -1065,6 +1428,18 @@ class Section(object): def __init__(self, *args, **kwargs): pass + def __eq__(self, val): + if isinstance(val, str): + return (self.section == val) + # This signals to use the normal comparison operator + return NotImplemented + + def __ne__(self, val): + if isinstance(val, str): + return (self.section != val) + # This signals to use the normal comparison operator + return NotImplemented + def __repr__(self): return '
' % self.section @@ -1175,13 +1550,34 @@ def source_exists(source, source_version, suites = ["any"], session=None): __all__.append('source_exists') -def get_sources_from_name(source, dm_upload_allowed=None, session=None): +def get_suites_source_in(source, session=None): """ - Returns list of DBSource objects for given C{source} name + Returns list of Suite objects which given C{source} name is in @type source: str @param source: DBSource package name to search for + @rtype: list + @return: list of Suite objects for the given source + """ + + if session is None: + session = DBConn().session() + + return session.query(Suite).join(SrcAssociation).join(DBSource).filter_by(source=source).all() + +__all__.append('get_suites_source_in') + +def get_sources_from_name(source, version=None, dm_upload_allowed=None, session=None): + """ + Returns list of DBSource objects for given C{source} name and other parameters + + @type source: str + @param source: DBSource package name to search for + + @type source: str or None + @param source: DBSource version name to search for or None if not applicable + @type dm_upload_allowed: bool @param dm_upload_allowed: If None, no effect. If True or False, only return packages with that dm_upload_allowed setting @@ -1197,6 +1593,10 @@ def get_sources_from_name(source, dm_upload_allowed=None, session=None): session = DBConn().session() q = session.query(DBSource).filter_by(source=source) + + if version is not None: + q = q.filter_by(version=version) + if dm_upload_allowed is not None: q = q.filter_by(dm_upload_allowed=dm_upload_allowed) @@ -1284,6 +1684,18 @@ class Suite(object): def __repr__(self): return '' % self.suite_name + def __eq__(self, val): + if isinstance(val, str): + return (self.suite_name == val) + # This signals to use the normal comparison operator + return NotImplemented + + def __ne__(self, val): + if isinstance(val, str): + return (self.suite_name != val) + # This signals to use the normal comparison operator + return NotImplemented + def details(self): ret = [] for disp, field in SUITE_FIELDS: @@ -1405,6 +1817,18 @@ class Uid(object): def __init__(self, *args, **kwargs): pass + def __eq__(self, val): + if isinstance(val, str): + return (self.uid == val) + # This signals to use the normal comparison operator + return NotImplemented + + def __ne__(self, val): + if isinstance(val, str): + return (self.uid != val) + # This signals to use the normal comparison operator + return NotImplemented + def __repr__(self): return '' % (self.uid, self.name) @@ -1470,6 +1894,8 @@ def get_or_set_uid(uidname, session=None): session.add(uid) if privatetrans: session.commit() + else: + session.flush() return uid else: return q.one() @@ -1526,6 +1952,7 @@ class DBConn(Singleton): self.tbl_keyrings = Table('keyrings', self.db_meta, autoload=True) self.tbl_location = Table('location', self.db_meta, autoload=True) self.tbl_maintainer = Table('maintainer', self.db_meta, autoload=True) + self.tbl_new_comments = Table('new_comments', self.db_meta, autoload=True) self.tbl_override = Table('override', self.db_meta, autoload=True) self.tbl_override_type = Table('override_type', self.db_meta, autoload=True) self.tbl_pending_content_associations = Table('pending_content_associations', self.db_meta, autoload=True) @@ -1634,6 +2061,9 @@ class DBConn(Singleton): mapper(Maintainer, self.tbl_maintainer, properties = dict(maintainer_id = self.tbl_maintainer.c.id)) + mapper(NewComment, self.tbl_new_comments, + properties = dict(comment_id = self.tbl_new_comments.c.id)) + mapper(Override, self.tbl_override, properties = dict(suite_id = self.tbl_override.c.suite, suite = relation(Suite),