X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=daklib%2Fdbconn.py;h=c0facc461fdaf4f18bddfbb2eccd49a5ba10efec;hb=2495bbed9a0904fbe1a15976cad2974b305fb9ce;hp=593b668f1889e54ec50910f80bef3af57619b518;hpb=40af2eb02193b19c69744ff47651dd009f5a1f6e;p=dak.git diff --git a/daklib/dbconn.py b/daklib/dbconn.py index 593b668f..c0facc46 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 @@ -79,12 +91,23 @@ def get_architecture(architecture, session=None): @return: Architecture object for the given arch (None if not present) """ + privatetrans = False + if session is None: session = DBConn().session() + privatetrans = True + q = session.query(Architecture).filter_by(arch_string=architecture) + if q.count() == 0: - return None - return q.one() + ret = None + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret __all__.append('get_architecture') @@ -102,14 +125,22 @@ def get_architecture_suites(architecture, session=None): @rtype: list @return: list of Suite objects for the given name (may be empty) """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True q = session.query(Suite) q = q.join(SuiteArchitecture) q = q.join(Architecture).filter_by(arch_string=architecture).order_by('suite_name') - return q.all() + + ret = q.all() + + if privatetrans: + session.close() + + return ret __all__.append('get_architecture_suites') @@ -140,12 +171,23 @@ def get_archive(archive, session=None): """ archive = archive.lower() + + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True + q = session.query(Archive).filter_by(archive_name=archive) + if q.count() == 0: - return None - return q.one() + ret = None + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret __all__.append('get_archive') @@ -171,6 +213,30 @@ 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 + """ + + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + ret = session.query(Suite).join(BinAssociation).join(DBBinary).filter_by(package=package).all() + + session.close() + + return ret + +__all__.append('get_suites_binary_in') + def get_binary_from_id(id, session=None): """ Returns DBBinary object for given C{id} @@ -185,22 +251,38 @@ def get_binary_from_id(id, session=None): @rtype: DBBinary @return: DBBinary object for the given binary (None if not present) """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True + q = session.query(DBBinary).filter_by(binary_id=id) + if q.count() == 0: - return None - return q.one() + ret = None + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret __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) @@ -208,17 +290,67 @@ def get_binaries_from_name(package, session=None): @rtype: list @return: list of DBBinary objects for the given name (may be empty) """ + privatetrans = False if session is None: session = DBConn().session() - return session.query(DBBinary).filter_by(package=package).all() + privatetrans = True + + 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)) + + ret = q.all() + + if privatetrans: + session.close() + + return ret __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) + """ + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + ret = session.query(DBBinary).filter_by(source_id=source_id).all() + + if privatetrans: + session.close() + + return ret + + +__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 + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True sql = """SELECT DISTINCT(b.package), b.version, c.name, su.suite_name FROM binaries b, files fi, location l, component c, bin_associations ba, suite su @@ -231,12 +363,17 @@ def get_binary_from_name_suite(package, suitename, session=None): AND su.suite_name=:suitename ORDER BY b.version DESC""" - return session.execute(sql, {'package': package, 'suitename': suitename}) + ret = session.execute(sql, {'package': package, 'suitename': suitename}) + + if privatetrans: + session.close() + + return ret __all__.append('get_binary_from_name_suite') def get_binary_components(package, suitename, arch, session=None): -# Check for packages that have moved from one component to another + # Check for packages that have moved from one component to another query = """SELECT c.name FROM binaries b, bin_associations ba, suite s, location l, component c, architecture a, files f WHERE b.package=:package AND s.suite_name=:suitename AND (a.arch_string = :arch OR a.arch_string = 'all') @@ -247,17 +384,38 @@ def get_binary_components(package, suitename, arch, session=None): vals = {'package': package, 'suitename': suitename, 'arch': arch} + privatetrans = False if session is None: session = DBConn().session() - return session.execute(query, vals) + privatetrans = True + + ret = session.execute(query, vals) + + if privatetrans: + session.close() + + return ret __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 @@ -276,12 +434,23 @@ def get_component(component, session=None): """ component = component.lower() + + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True + q = session.query(Component).filter_by(component_name=component) + if q.count() == 0: - return None - return q.one() + ret = None + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret __all__.append('get_component') @@ -328,21 +497,23 @@ def get_or_set_contents_file_id(filename, session=None): session = DBConn().session() privatetrans = True - try: - q = session.query(ContentFilename).filter_by(filename=filename) - if q.count() < 1: - cf = ContentFilename() - cf.filename = filename - session.add(cf) - if privatetrans: - session.commit() - return cf.cafilename_id + q = session.query(ContentFilename).filter_by(filename=filename) + if q.count() < 1: + cf = ContentFilename() + cf.filename = filename + session.add(cf) + if privatetrans: + session.commit() else: - return q.one().cafilename_id + session.flush() + ret = cf.cafilename_id + else: + ret = q.one().cafilename_id - except: - traceback.print_exc() - raise + if privatetrans: + session.close() + + return ret __all__.append('get_or_set_contents_file_id') @@ -369,8 +540,10 @@ def get_contents(suite, overridetype, section=None, session=None): package, arch_id) """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True # find me all of the contents for a given suite contents_q = """SELECT (p.path||'/'||n.file) AS fn, @@ -395,7 +568,12 @@ def get_contents(suite, overridetype, section=None, session=None): contents_q += " ORDER BY fn" - return session.execute(contents_q, vals) + ret = session.execute(contents_q, vals) + + if privatetrans: + session.close() + + return ret __all__.append('get_contents') @@ -410,7 +588,7 @@ class ContentFilepath(object): __all__.append('ContentFilepath') -def get_or_set_contents_path_id(filepath, session): +def get_or_set_contents_path_id(filepath, session=None): """ Returns database id for given path. @@ -431,21 +609,23 @@ def get_or_set_contents_path_id(filepath, session): session = DBConn().session() privatetrans = True - try: - q = session.query(ContentFilepath).filter_by(filepath=filepath) - if q.count() < 1: - cf = ContentFilepath() - cf.filepath = filepath - session.add(cf) - if privatetrans: - session.commit() - return cf.cafilepath_id + q = session.query(ContentFilepath).filter_by(filepath=filepath) + if q.count() < 1: + cf = ContentFilepath() + cf.filepath = filepath + session.add(cf) + if privatetrans: + session.commit() else: - return q.one().cafilepath_id + session.flush() + ret = cf.cafilepath_id + else: + ret = q.one().cafilepath_id - except: - traceback.print_exc() - raise + if privatetrans: + session.close() + + return ret __all__.append('get_or_set_contents_path_id') @@ -479,33 +659,45 @@ def insert_content_paths(binary_id, fullpaths, session=None): """ privatetrans = False - if session is None: session = DBConn().session() privatetrans = True try: + # Insert paths + pathcache = {} for fullpath in fullpaths: + # Get the necessary IDs ... (path, file) = os.path.split(fullpath) - # Get the necessary IDs ... + filepath_id = get_or_set_contents_path_id(path, session) + filename_id = get_or_set_contents_file_id(file, session) + + pathcache[fullpath] = (filepath_id, filename_id) + + for fullpath, dat in pathcache.items(): ca = ContentAssociation() ca.binary_id = binary_id - ca.filename_id = get_or_set_contents_file_id(file) - ca.filepath_id = get_or_set_contents_path_id(path) + ca.filepath_id = dat[0] + ca.filename_id = dat[1] session.add(ca) # Only commit if we set up the session ourself if privatetrans: session.commit() + session.close() + else: + session.flush() return True + except: traceback.print_exc() # Only rollback if we set up the session ourself if privatetrans: session.rollback() + session.close() return False @@ -522,6 +714,48 @@ 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 + """ + + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + 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) + + ret = q.all() + + if privatetrans: + session.close() + + return ret + +__all__.append('get_dscfiles') + ################################################################################ class PoolFile(object): @@ -533,6 +767,93 @@ 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 + """ + + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + q = session.query(PoolFile).filter_by(filename=filename) + q = q.join(Location).filter_by(location_id=location_id) + + ret = None + + 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 != filesize: + ret = (False, obj) + + if ret is None: + ret = (True, obj) + + if privatetrans: + session.close() + + return ret + +__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 + """ + + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + q = session.query(PoolFile).filter_by(file_id=file_id) + + if q.count() > 0: + ret = q.one() + else: + ret = None + + if privatetrans: + session.close() + + return ret + +__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,15 +869,22 @@ def get_poolfile_by_name(filename, location_id=None, session=None): @return: array of PoolFile objects """ - if session is not None: + privatetrans = False + if session is None: session = DBConn().session() + privatetrans = True 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() + ret = q.all() + + if privatetrans: + session.close() + + return ret __all__.append('get_poolfile_by_name') @@ -571,13 +899,20 @@ def get_poolfile_like_name(filename, session=None): @return: array of PoolFile objects """ - if session is not None: + privatetrans = False + if session is None: session = DBConn().session() + privatetrans = True # TODO: There must be a way of properly using bind parameters with %FOO% q = session.query(PoolFile).filter(PoolFile.filename.like('%%%s%%' % filename)) - return q.all() + ret = q.all() + + if privatetrans: + session.close() + + return ret __all__.append('get_poolfile_like_name') @@ -592,6 +927,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 + + 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() + ret = fingerprint + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret + +__all__.append('get_or_set_fingerprint') + ################################################################################ class Keyring(object): @@ -603,6 +981,42 @@ class Keyring(object): __all__.append('Keyring') +def get_or_set_keyring(keyring, session=None): + """ + If C{keyring} does not have an entry in the C{keyrings} table yet, create one + and return the new Keyring + If C{keyring} already has an entry, simply return the existing Keyring + + @type keyring: string + @param keyring: the keyring name + + @rtype: Keyring + @return: the Keyring object for this keyring + + """ + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + try: + obj = session.query(Keyring).filter_by(keyring_name=keyring).first() + + if obj is None: + obj = Keyring(keyring_name=keyring) + session.add(obj) + if privatetrans: + session.commit() + else: + session.flush() + + return obj + finally: + if privatetrans: + session.close() + +__all__.append('get_or_set_keyring') + ################################################################################ class Location(object): @@ -614,58 +1028,222 @@ class Location(object): __all__.append('Location') -def get_location(location, component=None, archive=None, session=None): - """ - Returns Location object for the given combination of location, component - and archive +def get_location(location, component=None, archive=None, session=None): + """ + Returns Location object for the given combination of location, component + and archive + + @type location: string + @param location: the path of the location, e.g. I{/srv/ftp.debian.org/ftp/pool/} + + @type component: string + @param component: the component name (if None, no restriction applied) + + @type archive: string + @param archive_id: the archive name (if None, no restriction applied) + + @rtype: Location / None + @return: Either a Location object or None if one can't be found + """ + + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + q = session.query(Location).filter_by(path=location) + + if archive is not None: + q = q.join(Archive).filter_by(archive_name=archive) + + if component is not None: + q = q.join(Component).filter_by(component_name=component) + + if q.count() < 1: + ret = None + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret + +__all__.append('get_location') + +################################################################################ + +class Maintainer(object): + def __init__(self, *args, **kwargs): + pass + + def __repr__(self): + return '''''' % (self.name, self.maintainer_id) + + def get_split_maintainer(self): + if not hasattr(self, 'name') or self.name is None: + return ('', '', '', '') + + return fix_maintainer(self.name.strip()) + +__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 + + 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() + ret = maintainer + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret + +__all__.append('get_or_set_maintainer') + +def get_maintainer(maintainer_id, session=None): + """ + Return the name of the maintainer behind C{maintainer_id} or None if that + maintainer_id is invalid. + + @type maintainer_id: int + @param maintainer_id: the id of the maintainer + + @rtype: Maintainer + @return: the Maintainer with this C{maintainer_id} + """ + + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + try: + return session.query(Maintainer).get(maintainer_id) + finally: + if privatetrans: + session.close() + +__all__.append('get_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 + """ + + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + q = session.query(NewComment) + q = q.filter_by(package=package) + q = q.filter_by(version=version) + + ret = q.count() > 0 - @type location: string - @param location: the path of the location, e.g. I{/srv/ftp.debian.org/ftp/pool/} + if privatetrans: + session.close() - @type component: string - @param component: the component name (if None, no restriction applied) + return ret - @type archive: string - @param archive_id: the archive name (if None, no restriction applied) +__all__.append('has_new_comment') - @rtype: Location / None - @return: Either a Location object or None if one can't be found +def get_new_comments(package=None, version=None, comment_id=None, session=None): """ + Returns (possibly empty) list of NewComment objects for the given + parameters - if session is None: - session = DBConn().session() + @type package: string (optional) + @param package: name of the package - q = session.query(Location).filter_by(path=location) + @type version: string (optional) + @param version: package version - if archive is not None: - q = q.join(Archive).filter_by(archive_name=archive) + @type comment_id: int (optional) + @param comment_id: An id of a comment - if component is not None: - q = q.join(Component).filter_by(component_name=component) + @type session: Session + @param session: Optional SQLA session object (a temporary one will be + generated if not supplied) - if q.count() < 1: - return None - else: - return q.one() + @rtype: list + @return: A (possibly empty) list of NewComment objects will be returned -__all__.append('get_location') + """ -################################################################################ + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True -class Maintainer(object): - def __init__(self, *args, **kwargs): - pass + 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) - def __repr__(self): - return '''''' % (self.name, self.maintainer_id) + ret = q.all() - def get_split_maintainer(self): - if not hasattr(self, 'name') or self.name is None: - return ('', '', '', '') + if privatetrans: + session.close() - return fix_maintainer(self.name.strip()) + return ret -__all__.append('Maintainer') +__all__.append('get_new_comments') ################################################################################ @@ -705,8 +1283,10 @@ def get_override(package, suite=None, component=None, overridetype=None, session @return: A (possibly empty) list of Override objects will be returned """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True q = session.query(Override) q = q.filter_by(package=package) @@ -723,7 +1303,12 @@ def get_override(package, suite=None, component=None, overridetype=None, session if not isinstance(overridetype, list): overridetype = [overridetype] q = q.join(OverrideType).filter(OverrideType.overridetype.in_(overridetype)) - return q.all() + ret = q.all() + + if privatetrans: + session.close() + + return ret __all__.append('get_override') @@ -754,12 +1339,22 @@ def get_override_type(override_type, session=None): @return: the database id for the given override type """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True + q = session.query(OverrideType).filter_by(overridetype=override_type) + if q.count() == 0: - return None - return q.one() + ret = None + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret __all__.append('get_override_type') @@ -810,31 +1405,42 @@ def insert_pending_content_paths(package, fullpaths, session=None): q.delete() # Insert paths + pathcache = {} for fullpath in fullpaths: (path, file) = os.path.split(fullpath) if path.startswith( "./" ): path = path[2:] + filepath_id = get_or_set_contents_path_id(path, session) + filename_id = get_or_set_contents_file_id(file, session) + + pathcache[fullpath] = (filepath_id, filename_id) + + for fullpath, dat in pathcache.items(): pca = PendingContentAssociation() pca.package = package['Package'] pca.version = package['Version'] - pca.filename_id = get_or_set_contents_file_id(file, session) - pca.filepath_id = get_or_set_contents_path_id(path, session) + pca.filepath_id = dat[0] + pca.filename_id = dat[1] pca.architecture = arch_id session.add(pca) # Only commit if we set up the session ourself if privatetrans: session.commit() + session.close() + else: + session.flush() return True - except: + except Exception, e: traceback.print_exc() # Only rollback if we set up the session ourself if privatetrans: session.rollback() + session.close() return False @@ -846,6 +1452,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) @@ -866,15 +1484,53 @@ def get_priority(priority, session=None): @return: Priority object for the given priority """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True + q = session.query(Priority).filter_by(priority=priority) + if q.count() == 0: - return None - return q.one() + ret = None + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret __all__.append('get_priority') +def get_priorities(session=None): + """ + Returns dictionary of priority names -> id mappings + + @type session: Session + @param session: Optional SQL session object (a temporary one will be + generated if not supplied) + + @rtype: dictionary + @return: dictionary of priority names -> id mappings + """ + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + ret = {} + q = session.query(Priority) + for x in q.all(): + ret[x.priority] = x.priority_id + + if privatetrans: + session.close() + + return ret + +__all__.append('get_priorities') + ################################################################################ class Queue(object): @@ -905,10 +1561,10 @@ class Queue(object): @return: None if the operation failed, a string describing the error if not """ - localcommit = False + privatetrans = False if session is None: session = DBConn().session() - localcommit = True + privatetrans = True # TODO: Remove by moving queue config into the database conf = Config() @@ -938,7 +1594,7 @@ class Queue(object): dest = os.path.join(dest_dir, file_entry) # TODO: Move into database as above - if Cnf.FindB("Dinstall::SecurityQueueBuild"): + if conf.FindB("Dinstall::SecurityQueueBuild"): # Copy it since the original won't be readable by www-data utils.copy(src, dest) else: @@ -953,23 +1609,26 @@ class Queue(object): session.add(qb) - # If the .orig.tar.gz is in the pool, create a symlink to - # it (if one doesn't already exist) - if changes.orig_tar_id: - # Determine the .orig.tar.gz file name - for dsc_file in changes.dsc_files.keys(): - if dsc_file.endswith(".orig.tar.gz"): - filename = dsc_file - - dest = os.path.join(dest_dir, filename) + # If the .orig tarballs are in the pool, create a symlink to + # them (if one doesn't already exist) + for dsc_file in changes.dsc_files.keys(): + # Skip all files except orig tarballs + if not re_is_orig_source.match(dsc_file): + continue + # Skip orig files not identified in the pool + if not (changes.orig_files.has_key(dsc_file) and + changes.orig_files[dsc_file].has_key("id")): + continue + orig_file_id = changes.orig_files[dsc_file]["id"] + dest = os.path.join(dest_dir, dsc_file) # If it doesn't exist, create a symlink if not os.path.exists(dest): q = session.execute("SELECT l.path, f.filename FROM location l, files f WHERE f.id = :id and f.location = l.id", - {'id': changes.orig_tar_id}) + {'id': orig_file_id}) res = q.fetchone() if not res: - return "[INTERNAL ERROR] Couldn't find id %s in files table." % (changes.orig_tar_id) + return "[INTERNAL ERROR] Couldn't find id %s in files table." % (orig_file_id) src = os.path.join(res[0], res[1]) os.symlink(src, dest) @@ -984,14 +1643,15 @@ class Queue(object): # If it does, update things to ensure it's not removed prematurely else: - qb = get_queue_build(dest, suite_id, session) + qb = get_queue_build(dest, s.suite_id, session) if qb is None: qb.in_queue = True qb.last_used = None session.add(qb) - if localcommit: + if privatetrans: session.commit() + session.close() return None @@ -1012,12 +1672,21 @@ def get_queue(queuename, session=None): @return: Queue object for the given queue """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True + q = session.query(Queue).filter_by(queue_name=queuename) if q.count() == 0: - return None - return q.one() + ret = None + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret __all__.append('get_queue') @@ -1032,15 +1701,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 @@ -1050,12 +1719,26 @@ def get_queue_build(filename, suite_id, session=None): @return: Queue object for the given queue """ + privatetrans = False if session is None: session = DBConn().session() - q = session.query(QueueBuild).filter_by(filename=filename).filter_by(suite_id=suite_id) + privatetrans = True + + 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() + ret = None + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret __all__.append('get_queue_build') @@ -1065,6 +1748,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 @@ -1085,15 +1780,52 @@ def get_section(section, session=None): @return: Section object for the given section name """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True + q = session.query(Section).filter_by(section=section) if q.count() == 0: - return None - return q.one() + ret = None + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret __all__.append('get_section') +def get_sections(session=None): + """ + Returns dictionary of section names -> id mappings + + @type session: Session + @param session: Optional SQL session object (a temporary one will be + generated if not supplied) + + @rtype: dictionary + @return: dictionary of section names -> id mappings + """ + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + ret = {} + q = session.query(Section) + for x in q.all(): + ret[x.section] = x.section_id + + if privatetrans: + session.close() + + return ret + +__all__.append('get_sections') + ################################################################################ class DBSource(object): @@ -1130,10 +1862,13 @@ def source_exists(source, source_version, suites = ["any"], session=None): """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True cnf = Config() + ret = 1 for suite in suites: q = session.query(DBSource).filter_by(source=source) @@ -1168,20 +1903,50 @@ def source_exists(source, source_version, suites = ["any"], session=None): continue # No source found so return not ok - return 0 + ret = 0 - # We're good - return 1 + if privatetrans: + session.close() + + return ret __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 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 + """ + + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + ret = session.query(Suite).join(SrcAssociation).join(DBSource).filter_by(source=source).all() + + if privatetrans: + session.close() + + return ret + +__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 + 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 @@ -1193,14 +1958,25 @@ def get_sources_from_name(source, dm_upload_allowed=None, session=None): @rtype: list @return: list of DBSource objects for the given name (may be empty) """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True 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) - return q.all() + ret = q.all() + + if privatetrans: + session.close() + + return ret __all__.append('get_sources_from_name') @@ -1221,15 +1997,25 @@ def get_source_in_suite(source, suite, session=None): @return: the version for I{source} in I{suite} """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True + q = session.query(SrcAssociation) q = q.join('source').filter_by(source=source) q = q.join('suite').filter_by(suite_name=suite) + if q.count() == 0: - return None - # ???: Maybe we should just return the SrcAssociation object instead - return q.one().source + ret = None + else: + # ???: Maybe we should just return the SrcAssociation object instead + ret = q.one().source + + if privatetrans: + session.close() + + return ret __all__.append('get_source_in_suite') @@ -1246,6 +2032,17 @@ __all__.append('SrcAssociation') ################################################################################ +class SrcFormat(object): + def __init__(self, *args, **kwargs): + pass + + def __repr__(self): + return '' % (self.format_name) + +__all__.append('SrcFormat') + +################################################################################ + class SrcUploader(object): def __init__(self, *args, **kwargs): pass @@ -1284,6 +2081,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: @@ -1314,15 +2123,24 @@ def get_suite_architecture(suite, architecture, session=None): @return: the SuiteArchitecture object or None """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True q = session.query(SuiteArchitecture) q = q.join(Architecture).filter_by(arch_string=architecture) q = q.join(Suite).filter_by(suite_name=suite) + if q.count() == 0: - return None - return q.one() + ret = None + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret __all__.append('get_suite_architecture') @@ -1341,12 +2159,22 @@ def get_suite(suite, session=None): @return: Suite object for the requested suite name (None if not presenT) """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True + q = session.query(Suite).filter_by(suite_name=suite) + if q.count() == 0: - return None - return q.one() + ret = None + else: + ret = q.one() + + if privatetrans: + session.close() + + return ret __all__.append('get_suite') @@ -1384,27 +2212,95 @@ def get_suite_architectures(suite, skipsrc=False, skipall=False, session=None): @return: list of Architecture objects for the given name (may be empty) """ + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True 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() + + ret = q.all() + + if privatetrans: + session.close() + + return ret __all__.append('get_suite_architectures') ################################################################################ +class SuiteSrcFormat(object): + def __init__(self, *args, **kwargs): + pass + + def __repr__(self): + return '' % (self.suite_id, self.src_format_id) + +__all__.append('SuiteSrcFormat') + +def get_suite_src_formats(suite, session=None): + """ + Returns list of allowed SrcFormat for C{suite}. + + @type suite: str + @param suite: Suite name to search for + + @type session: Session + @param session: Optional SQL session object (a temporary one will be + generated if not supplied) + + @rtype: list + @return: the list of allowed source formats for I{suite} + """ + + privatetrans = False + if session is None: + session = DBConn().session() + privatetrans = True + + q = session.query(SrcFormat) + q = q.join(SuiteSrcFormat) + q = q.join(Suite).filter_by(suite_name=suite) + q = q.order_by('format_name') + + ret = q.all() + + if privatetrans: + session.close() + + return ret + +__all__.append('get_suite_src_formats') + +################################################################################ + 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) @@ -1425,18 +2321,17 @@ def add_database_user(uidname, session=None): @rtype: Uid @return: the uid object for the given uidname """ + privatetrans = False if session is None: session = DBConn().session() privatetrans = True - try: - session.execute("CREATE USER :uid", {'uid': uidname}) - if privatetrans: - session.commit() - except: - traceback.print_exc() - raise + session.execute("CREATE USER :uid", {'uid': uidname}) + + if privatetrans: + session.commit() + session.close() __all__.append('add_database_user') @@ -1457,41 +2352,52 @@ def get_or_set_uid(uidname, session=None): @rtype: Uid @return: the uid object for the given uidname """ + privatetrans = False if session is None: session = DBConn().session() privatetrans = True - try: - q = session.query(Uid).filter_by(uid=uidname) - if q.count() < 1: - uid = Uid() - uid.uid = uidname - session.add(uid) - if privatetrans: - session.commit() - return uid + q = session.query(Uid).filter_by(uid=uidname) + + if q.count() < 1: + uid = Uid() + uid.uid = uidname + session.add(uid) + if privatetrans: + session.commit() else: - return q.one() + session.flush() + ret = uid + else: + ret = q.one() - except: - traceback.print_exc() - raise + if privatetrans: + session.close() + + return ret __all__.append('get_or_set_uid') def get_uid_from_fingerprint(fpr, session=None): + privatetrans = False if session is None: session = DBConn().session() + privatetrans = True q = session.query(Uid) q = q.join(Fingerprint).filter_by(fingerprint=fpr) if q.count() != 1: - return None + ret = None else: - return q.one() + ret = q.one() + + if privatetrans: + session.close() + + return ret __all__.append('get_uid_from_fingerprint') @@ -1526,6 +2432,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) @@ -1535,9 +2442,11 @@ class DBConn(Singleton): self.tbl_section = Table('section', self.db_meta, autoload=True) self.tbl_source = Table('source', self.db_meta, autoload=True) self.tbl_src_associations = Table('src_associations', self.db_meta, autoload=True) + self.tbl_src_format = Table('src_format', self.db_meta, autoload=True) self.tbl_src_uploaders = Table('src_uploaders', self.db_meta, autoload=True) self.tbl_suite = Table('suite', self.db_meta, autoload=True) self.tbl_suite_architectures = Table('suite_architectures', self.db_meta, autoload=True) + self.tbl_suite_src_formats = Table('suite_src_formats', self.db_meta, autoload=True) self.tbl_uid = Table('uid', self.db_meta, autoload=True) def __setupmappers(self): @@ -1634,6 +2543,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), @@ -1696,6 +2608,10 @@ class DBConn(Singleton): source_id = self.tbl_src_associations.c.source, source = relation(DBSource))) + mapper(SrcFormat, self.tbl_src_format, + properties = dict(src_format_id = self.tbl_src_format.c.id, + format_name = self.tbl_src_format.c.format_name)) + mapper(SrcUploader, self.tbl_src_uploaders, properties = dict(uploader_id = self.tbl_src_uploaders.c.id, source_id = self.tbl_src_uploaders.c.source, @@ -1714,6 +2630,12 @@ class DBConn(Singleton): 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'), + src_format_id = self.tbl_suite_src_formats.c.src_format, + src_format = relation(SrcFormat))) + mapper(Uid, self.tbl_uid, properties = dict(uid_id = self.tbl_uid.c.id, fingerprint = relation(Fingerprint)))