X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;ds=sidebyside;f=daklib%2Fdbconn.py;h=ef6f639af99e94836586f8ed203bed6975a1451b;hb=a9e44d5d3a064ec00762102dd3b8f56d398b07cf;hp=a2d869c9ac264f634ff0e67c86fc218bf905de2d;hpb=27f4ea910d56ef91ed713563b1b92dd2dc9b6f40;p=dak.git diff --git a/daklib/dbconn.py b/daklib/dbconn.py index a2d869c9..ef6f639a 100755 --- a/daklib/dbconn.py +++ b/daklib/dbconn.py @@ -38,348 +38,611 @@ import psycopg2 import traceback from sqlalchemy import create_engine, Table, MetaData, select -from sqlalchemy.orm import sessionmaker, mapper +from sqlalchemy.orm import sessionmaker, mapper, relation + +# Don't remove this, we re-export the exceptions to scripts which import us +from sqlalchemy.exc import * from singleton import Singleton -from config import Config ################################################################################ -class Cache(object): - def __init__(self, hashfunc=None): - if hashfunc: - self.hashfunc = hashfunc - else: - self.hashfunc = lambda x: str(x) - - self.data = {} - - def SetValue(self, keys, value): - self.data[self.hashfunc(keys)] = value - - def GetValue(self, keys): - return self.data.get(self.hashfunc(keys)) +__all__ = [] ################################################################################ class Architecture(object): - def __init__(self, arch_id=None, arch_string=None, description=None): - self.arch_id = arch_id - self.arch_string = arch_string - self.description = description + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.arch_string +__all__.append('Architecture') + +def get_architecture(architecture, session=None): + """ + Returns database id for given C{architecture}. + + @type architecture: string + @param architecture: The name of the architecture + + @type session: Session + @param session: Optional SQLA session object (a temporary one will be + generated if not supplied) + + @rtype: Architecture + @return: Architecture object for the given arch (None if not present) + + """ + if session is None: + session = DBConn().session() + q = session.query(Architecture).filter_by(arch_string=architecture) + if q.count() == 0: + return None + return q.one() + +__all__.append('get_architecture') + +def get_architecture_suites(architecture, session=None): + """ + Returns list of Suite objects for given C{architecture} name + + @type source: str + @param source: Architecture 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: list of Suite objects for the given name (may be empty) + """ + + if session is None: + session = DBConn().session() + + q = session.query(Suite) + q = q.join(SuiteArchitecture) + q = q.join(Architecture).filter_by(arch_string=architecture).order_by('suite_name') + return q.all() + +__all__.append('get_architecture_suites') + class Archive(object): - def __init__(self, archive_id=None, archive_name=None, origin_server=None, - description=None): - self.archive_id = archive_id - self.archive_name = archive_name - self.origin_server = origin_server - self.description = description + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.name +__all__.append('Archive') + +def get_archive(archive, session=None): + """ + returns database id for given c{archive}. + + @type archive: string + @param archive: the name of the arhive + + @type session: Session + @param session: Optional SQLA session object (a temporary one will be + generated if not supplied) + + @rtype: Archive + @return: Archive object for the given name (None if not present) + + """ + archive = archive.lower() + if session is None: + session = DBConn().session() + q = session.query(Archive).filter_by(archive_name=archive) + if q.count() == 0: + return None + return q.one() + +__all__.append('get_archive') + class BinAssociation(object): - def __init__(self, ba_id=None, suite_id=None, bin_id=None): - self.ba_id = ba_id - self.suite_id = suite_id - self.bin_id = bin_id + def __init__(self, *args, **kwargs): + pass def __repr__(self): - return '' % self.ba_id + return '' % (self.ba_id, self.binary, self.suite) + +__all__.append('BinAssociation') class Binary(object): - def __init__(self, binary_id=None, package=None, version=None, - maintainer_id=None, source_id=None, arch_id=None, - file_id=None, filetype=None, fingerprint_id=None, - install_date=None): - self.binary_id = binary_id - self.package = package - self.version = version - self.maintainer_id = maintainer_id - self.source_id = source_id - self.arch_id = arch_id - self.file_id = file_id - self.filetype = filetype - self.fingerprint_id = fingerprint_id - self.install_date = install_date + def __init__(self, *args, **kwargs): + pass def __repr__(self): - return '' % (self.package, self.version, self.arch_id) + return '' % (self.package, self.version, self.architecture) + +__all__.append('Binary') + +def get_binary_from_id(id, session=None): + """ + Returns Binary object for given C{id} + + @type id: int + @param id: Id of the required binary + + @type session: Session + @param session: Optional SQLA session object (a temporary one will be + generated if not supplied) + + @rtype: Binary + @return: Binary object for the given binary (None if not present) + """ + if session is None: + session = DBConn().session() + q = session.query(Binary).filter_by(binary_id=id) + if q.count() == 0: + return None + return q.one() + +__all__.append('get_binary_from_id') + +def get_binaries_from_name(package, session=None): + """ + Returns list of Binary objects for given C{package} name + + @type package: str + @param package: Binary package 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: list of Binary objects for the given name (may be empty) + """ + if session is None: + session = DBConn().session() + return session.query(Binary).filter_by(package=package).all() + +__all__.append('get_binaries_from_name') class Component(object): - def __init__(self, component_id=None, component_name=None, - description=None, meets_dfsg=None,): - self.component_id = component_id - self.component_name = component_name - self.description = description - self.meets_dfsg = meets_dfsg + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.component_name + +__all__.append('Component') + +def get_component(component, session=None): + """ + Returns database id for given C{component}. + + @type component: string + @param component: The name of the override type + + @rtype: int + @return: the database id for the given component + + """ + component = component.lower() + if session is None: + session = DBConn().session() + q = session.query(Component).filter_by(component_name=component) + if q.count() == 0: + return None + return q.one() + +__all__.append('get_component') + class DBConfig(object): - def __init__(self, config_id=None, name=None, value=None): - self.config_id = config_id - self.name = name - self.value = value + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.name +__all__.append('DBConfig') + class ContentFilename(object): - def __init__(self, cafilename_id=None, filename=None): - self.cafilename_id = cafilename_id - self.filename = filename + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.filename +__all__.append('ContentFilename') + class ContentFilepath(object): - def __init__(self, cafilepath_id=None, filepath=None): - self.cafilepath_id = cafilepath_id - self.filepath = filepath + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.filepath -class ContentAssociations(object): - def __init__(self, binary_id=None, filename_id=None, filepath_id=None, - ca_id=None): - self.binary_id = binary_id - self.filename_id = filename_id - self.filepath_id = filepath_id - self.ca_id = ca_id +__all__.append('ContentFilepath') + +class ContentAssociation(object): + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.ca_id +__all__.append('ContentAssociation') + class DSCFile(object): - def __init__(self, dscfile_id=None, source_id=None, file_id=None): - self.dscfile_id = dscfile_id - self.source_id = source_id - self.file_id = file_id + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.dscfile_id +__all__.append('DSCFile') + class PoolFile(object): - def __init__(self, file_id=None, filename=None, filesize=None, - location_id=None, last_used=None, md5sum=None, - sha1sum=None, sha256sum=None): - self.file_id = file_id - self.filename = filename - self.filesize = filesize - self.location_id = location_id - self.last_used = last_used - self.md5sum = md5sum - self.sha1sum = sha1sum - self.sha256sum = sha256sum + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.filename +__all__.append('PoolFile') + class Fingerprint(object): - def __init__(self, fingerprint_id=None, fingerprint=None, - uid_id=None, keyring_id=None): - self.fingerprint_id = fingerprint_id - self.fingerprint = fingerprint - self.uid_id = uid_id - self.keyring_id = keyring_id + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.fingerprint +__all__.append('Fingerprint') + class Keyring(object): - def __init__(self, keyring_id=None, keyring_name=None, - debian_maintainer=None): - self.keyring_id = keyring_id - self.keyring_name = keyring_name - self.debian_maintainer = debian_maintainer + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.keyring_name +__all__.append('Keyring') + class Location(object): - def __init__(self, location_id=None, path=None, - component_id=None, archive_id=None, - archive_type=None): - self.location_id = location_id - self.path = path - self.component_id = component_id - self.archive_id = archive_id - self.archive_type = archive_type + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % (self.path, self.location_id) +__all__.append('Location') + class Maintainer(object): - def __init__(self, maintainer_id=None, name=None): - self.maintainer_id = maintainer_id - self.name = name + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '''''' % (self.name, self.maintainer_id) +__all__.append('Maintainer') + class Override(object): - def __init__(self, package, suite_id=None, component_id=None, - priority_id=None, section_id=None, overridetype_id=None, - maintainer=None): - self.package = package - self.suite_id = suite_id - self.component_id = component_id - self.priority_id = priority_id - self.section_id = section_id - self.overridetype_id = overridetype_id - self.maintainer = maintainer + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % (self.package, self.suite_id) +__all__.append('Override') + class OverrideType(object): - def __init__(self, overridetype_id=None, overridetype=None): - self.overridetype_id = overridetype_id - self.overridetype = overridetype + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.overridetype +__all__.append('OverrideType') + +def get_override_type(override_type, session=None): + """ + Returns OverrideType object for given C{override type}. + + @type override_type: string + @param override_type: The name of the override type + + @type session: Session + @param session: Optional SQLA session object (a temporary one will be + generated if not supplied) + + @rtype: int + @return: the database id for the given override type + + """ + if session is None: + session = DBConn().session() + q = session.query(Priority).filter_by(priority=priority) + if q.count() == 0: + return None + return q.one() + +__all__.append('get_override_type') + class PendingContentAssociation(object): - def __init__(self, pca_id=None, package=None, version=None, - filepath_id=None, filename_id=None): - self.pca_id = pca_id - self.package = package - self.version = version - self.filepath_id = filepath_id - self.filename_id = filename_id + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.pca_id +__all__.append('PendingContentAssociation') + class Priority(object): - def __init__(self, priority_id=None, priority=None, level=None): - self.priority_id = priority_id - self.priority = priority - self.level = level + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % (self.priority, self.priority_id) +__all__.append('Priority') + +def get_priority(priority, session=None): + """ + Returns Priority object for given C{priority name}. + + @type priority: string + @param priority: The name of the priority + + @type session: Session + @param session: Optional SQLA session object (a temporary one will be + generated if not supplied) + + @rtype: Priority + @return: Priority object for the given priority + + """ + if session is None: + session = DBConn().session() + q = session.query(Priority).filter_by(priority=priority) + if q.count() == 0: + return None + return q.one() + +__all__.append('get_priority') + class Queue(object): - def __init__(self, queue_id=None, queue_name=None): - self.queue_id = queue_id - self.queue_name = queue_name + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.queue_name +__all__.append('Queue') + class QueueBuild(object): - def __init__(self, suite_id=None, queue_id=None, filename=None, - in_queue=None, last_used=None): - self.suite_id = suite_id - self.queue_id = queue_id - self.filename = filename - self.in_queue = in_queue - self.last_used = last_used + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % (self.filename, self.queue_id) +__all__.append('QueueBuild') + class Section(object): - def __init__(self, section_id=None, section=None): - self.section_id = section_id - self.section = section + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '
' % self.section +__all__.append('Section') + +def get_section(section, session=None): + """ + Returns Section object for given C{section name}. + + @type section: string + @param section: The name of the section + + @type session: Session + @param session: Optional SQLA session object (a temporary one will be + generated if not supplied) + + @rtype: Section + @return: Section object for the given section name + + """ + if session is None: + session = DBConn().session() + q = session.query(Section).filter_by(section=section) + if q.count() == 0: + return None + return q.one() + +__all__.append('get_section') + class Source(object): - def __init__(self, source_id=None, source=None, version=None, - maintainer_id=None, file_id=None, fingerprint_id=None, - install_date=None, changedby_id=None, dm_upload_allowed=None): - self.source_id = source_id - self.source = source - self.version = version - self.maintainer_id = maintainer_id - self.file_id = file_id - self.fingerprint_id = fingerprint_id - self.install_date = install_date - self.changedby_id = changedby_id - self.dm_upload_allowed = dm_upload_allowed + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % (self.source, self.version) +__all__.append('Source') + +def get_sources_from_name(source, session=None): + """ + Returns list of Source objects for given C{source} name + + @type source: str + @param source: Source package 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: list of Source objects for the given name (may be empty) + """ + if session is None: + session = DBConn().session() + return session.query(Source).filter_by(source=source).all() + +__all__.append('get_sources_from_name') + +def get_source_in_suite(source, suite, session=None): + """ + Returns list of Source objects for a combination of C{source} and C{suite}. + + - B{source} - source package name, eg. I{mailfilter}, I{bbdb}, I{glibc} + - B{suite} - a suite name, eg. I{unstable} + + @type source: string + @param source: source package name + + @type suite: string + @param suite: the suite name + + @rtype: string + @return: the version for I{source} in I{suite} + + """ + if session is None: + session = DBConn().session() + 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 + +__all__.append('get_source_in_suite') + class SrcAssociation(object): - def __init__(self, sa_id=None, suite_id=None, source_id=None): - self.sa_id = sa_id - self.suite_id = suite_id - self.source_id = source_id + def __init__(self, *args, **kwargs): + pass def __repr__(self): - return '' % self.sa_id + return '' % (self.sa_id, self.source, self.suite) + +__all__.append('SrcAssociation') class SrcUploader(object): - def __init__(self, uploader_id=None, source_id=None, maintainer_id=None): - self.uploader_id = uploader_id - self.source_id = source_id - self.maintainer_id = maintainer_id + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.uploader_id +__all__.append('SrcUploader') + class Suite(object): - def __init__(self, suite_id=None, suite_name=None, version=None, - origin=None, label=None, policy_engine=None, - description=None, untouchable=None, announce=None, - codename=None, overridecodename=None, validtime=None, - priority=None, notautomatic=None, copychanges=None, - copydotdak=None, commentsdir=None, overridesuite=None, - changelogbase=None): - - self.suite_id = suite_id - self.suite_name = suite_name - self.version = version - self.origin = origin - self.label = label - self.policy_engine = policy_engine - self.description = description - self.untouchable = untouchable - self.announce = announce - self.codename = codename - self.overridecodename = overridecodename - self.validtime = validtime - self.priority = priority - self.notautomatic = notautomatic - self.copychanges = copychanges - self.copydotdak = copydotdak - self.commentsdir = commentsdir - self.overridesuite = overridesuite - self.changelogbase = changelogbase + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % self.suite_name +__all__.append('Suite') + +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 + + @type session: Session + @param session: Optional SQL session object (a temporary one will be + generated if not supplied) + + @rtype: SuiteArchitecture + @return: the SuiteArchitecture object or None + """ + + if session is None: + session = DBConn().session() + + 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() + +__all__.append('get_suite_architecture') + +def get_suite(suite, session=None): + """ + Returns Suite object for given C{suite name}. + + @type suite: string + @param suite: The name of the suite + + @type session: Session + @param session: Optional SQLA session object (a temporary one will be + generated if not supplied) + + @rtype: Suite + @return: Suite object for the requested suite name (None if not presenT) + + """ + if session is None: + session = DBConn().session() + q = session.query(Suite).filter_by(suite_name=suite) + if q.count() == 0: + return None + return q.one() + +__all__.append('get_suite') + class SuiteArchitecture(object): - def __init__(self, suite_id=None, arch_id=None): - self.suite_id = suite_id - self.arch_id = arch_id + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % (self.suite_id, self.arch_id) +__all__.append('SuiteArchitecture') + +def get_suite_architectures(suite, session=None): + """ + Returns list of Architecture objects for given C{suite} name + + @type source: str + @param source: 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: list of Architecture objects for the given name (may be empty) + """ + + if session is None: + session = DBConn().session() + + q = session.query(Architecture) + q = q.join(SuiteArchitecture) + q = q.join(Suite).filter_by(suite_name=suite).order_by('arch_string') + return q.all() + +__all__.append('get_suite_architectures') + class Uid(object): - def __init__(self, uid_id=None, uid=None, name=None): - self.uid_id = uid_id - self.uid = uid - self.name = name + def __init__(self, *args, **kwargs): + pass def __repr__(self): return '' % (self.uid, self.name) +__all__.append('Uid') + ################################################################################ class DBConn(Singleton): @@ -390,164 +653,221 @@ class DBConn(Singleton): super(DBConn, self).__init__(*args, **kwargs) def _startup(self, *args, **kwargs): + self.debug = False + if kwargs.has_key('debug'): + self.debug = True self.__createconn() - self.__init_caches() def __setuptables(self): self.tbl_architecture = Table('architecture', self.db_meta, autoload=True) + self.tbl_archive = Table('archive', self.db_meta, autoload=True) + self.tbl_bin_associations = Table('bin_associations', self.db_meta, autoload=True) + self.tbl_binaries = Table('binaries', self.db_meta, autoload=True) + self.tbl_component = Table('component', self.db_meta, autoload=True) + self.tbl_config = Table('config', self.db_meta, autoload=True) + self.tbl_content_associations = Table('content_associations', self.db_meta, autoload=True) + self.tbl_content_file_names = Table('content_file_names', self.db_meta, autoload=True) + self.tbl_content_file_paths = Table('content_file_paths', self.db_meta, autoload=True) + self.tbl_dsc_files = Table('dsc_files', self.db_meta, autoload=True) + self.tbl_files = Table('files', self.db_meta, autoload=True) + self.tbl_fingerprint = Table('fingerprint', self.db_meta, autoload=True) + 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_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) + self.tbl_priority = Table('priority', self.db_meta, autoload=True) + self.tbl_queue = Table('queue', self.db_meta, autoload=True) + self.tbl_queue_build = Table('queue_build', self.db_meta, autoload=True) + 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_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_uid = Table('uid', self.db_meta, autoload=True) + + def __setupmappers(self): mapper(Architecture, self.tbl_architecture, properties = dict(arch_id = self.tbl_architecture.c.id)) - self.tbl_archive = Table('archive', self.db_meta, autoload=True) mapper(Archive, self.tbl_archive, properties = dict(archive_id = self.tbl_archive.c.id, archive_name = self.tbl_archive.c.name)) - self.tbl_bin_associations = Table('bin_associations', self.db_meta, autoload=True) mapper(BinAssociation, self.tbl_bin_associations, properties = dict(ba_id = self.tbl_bin_associations.c.id, suite_id = self.tbl_bin_associations.c.suite, - bin_id = self.tbl_bin_associations.c.bin)) + suite = relation(Suite), + binary_id = self.tbl_bin_associations.c.bin, + binary = relation(Binary))) - self.tbl_binaries = Table('binaries', self.db_meta, autoload=True) mapper(Binary, self.tbl_binaries, properties = dict(binary_id = self.tbl_binaries.c.id, - file_id = self.tbl_binaries.c.file, - filetype = self.tbl_binaries.c.type, + package = self.tbl_binaries.c.package, + version = self.tbl_binaries.c.version, maintainer_id = self.tbl_binaries.c.maintainer, + maintainer = relation(Maintainer), source_id = self.tbl_binaries.c.source, + source = relation(Source), arch_id = self.tbl_binaries.c.architecture, - fingerprint_id = self.tbl_binaries.c.sig_fpr)) + architecture = relation(Architecture), + poolfile_id = self.tbl_binaries.c.file, + poolfile = relation(PoolFile), + binarytype = self.tbl_binaries.c.type, + fingerprint_id = self.tbl_binaries.c.sig_fpr, + fingerprint = relation(Fingerprint), + install_date = self.tbl_binaries.c.install_date, + binassociations = relation(BinAssociation, + primaryjoin=(self.tbl_binaries.c.id==self.tbl_bin_associations.c.bin)))) - self.tbl_component = Table('component', self.db_meta, autoload=True) mapper(Component, self.tbl_component, properties = dict(component_id = self.tbl_component.c.id, component_name = self.tbl_component.c.name)) - self.tbl_config = Table('config', self.db_meta, autoload=True) mapper(DBConfig, self.tbl_config, properties = dict(config_id = self.tbl_config.c.id)) - self.tbl_content_associations = Table('content_associations', self.db_meta, autoload=True) - mapper(ContentAssociations, self.tbl_content_associations, + mapper(ContentAssociation, self.tbl_content_associations, properties = dict(ca_id = self.tbl_content_associations.c.id, filename_id = self.tbl_content_associations.c.filename, + filename = relation(ContentFilename), filepath_id = self.tbl_content_associations.c.filepath, - binary_id = self.tbl_content_associations.c.binary_pkg)) + filepath = relation(ContentFilepath), + binary_id = self.tbl_content_associations.c.binary_pkg, + binary = relation(Binary))) + - self.tbl_content_file_names = Table('content_file_names', self.db_meta, autoload=True) mapper(ContentFilename, self.tbl_content_file_names, properties = dict(cafilename_id = self.tbl_content_file_names.c.id, filename = self.tbl_content_file_names.c.file)) - self.tbl_content_file_paths = Table('content_file_paths', self.db_meta, autoload=True) mapper(ContentFilepath, self.tbl_content_file_paths, properties = dict(cafilepath_id = self.tbl_content_file_paths.c.id, filepath = self.tbl_content_file_paths.c.path)) - self.tbl_dsc_files = Table('dsc_files', self.db_meta, autoload=True) mapper(DSCFile, self.tbl_dsc_files, properties = dict(dscfile_id = self.tbl_dsc_files.c.id, source_id = self.tbl_dsc_files.c.source, - file_id = self.tbl_dsc_files.c.file)) + source = relation(Source), + poolfile_id = self.tbl_dsc_files.c.file, + poolfile = relation(PoolFile))) - self.tbl_files = Table('files', self.db_meta, autoload=True) mapper(PoolFile, self.tbl_files, properties = dict(file_id = self.tbl_files.c.id, filesize = self.tbl_files.c.size, - location_id = self.tbl_files.c.location)) + location_id = self.tbl_files.c.location, + location = relation(Location))) - self.tbl_fingerprint = Table('fingerprint', self.db_meta, autoload=True) mapper(Fingerprint, self.tbl_fingerprint, properties = dict(fingerprint_id = self.tbl_fingerprint.c.id, uid_id = self.tbl_fingerprint.c.uid, - keyring_id = self.tbl_fingerprint.c.keyring)) + uid = relation(Uid), + keyring_id = self.tbl_fingerprint.c.keyring, + keyring = relation(Keyring))) - self.tbl_keyrings = Table('keyrings', self.db_meta, autoload=True) mapper(Keyring, self.tbl_keyrings, properties = dict(keyring_name = self.tbl_keyrings.c.name, keyring_id = self.tbl_keyrings.c.id)) - self.tbl_location = Table('location', self.db_meta, autoload=True) mapper(Location, self.tbl_location, properties = dict(location_id = self.tbl_location.c.id, component_id = self.tbl_location.c.component, + component = relation(Component), archive_id = self.tbl_location.c.archive, + archive = relation(Archive), archive_type = self.tbl_location.c.type)) - self.tbl_maintainer = Table('maintainer', self.db_meta, autoload=True) mapper(Maintainer, self.tbl_maintainer, properties = dict(maintainer_id = self.tbl_maintainer.c.id)) - self.tbl_override = Table('override', self.db_meta, autoload=True) mapper(Override, self.tbl_override, properties = dict(suite_id = self.tbl_override.c.suite, + suite = relation(Suite), component_id = self.tbl_override.c.component, + component = relation(Component), priority_id = self.tbl_override.c.priority, + priority = relation(Priority), section_id = self.tbl_override.c.section, - overridetype_id = self.tbl_override.c.type)) + section = relation(Section), + overridetype_id = self.tbl_override.c.type, + overridetype = relation(OverrideType))) - self.tbl_override_type = Table('override_type', self.db_meta, autoload=True) mapper(OverrideType, self.tbl_override_type, properties = dict(overridetype = self.tbl_override_type.c.type, overridetype_id = self.tbl_override_type.c.id)) - self.tbl_pending_content_associations = Table('pending_content_associations', self.db_meta, autoload=True) mapper(PendingContentAssociation, self.tbl_pending_content_associations, properties = dict(pca_id = self.tbl_pending_content_associations.c.id, filepath_id = self.tbl_pending_content_associations.c.filepath, - filename_id = self.tbl_pending_content_associations.c.filename)) + filepath = relation(ContentFilepath), + filename_id = self.tbl_pending_content_associations.c.filename, + filename = relation(ContentFilename))) - self.tbl_priority = Table('priority', self.db_meta, autoload=True) mapper(Priority, self.tbl_priority, properties = dict(priority_id = self.tbl_priority.c.id)) - self.tbl_queue = Table('queue', self.db_meta, autoload=True) mapper(Queue, self.tbl_queue, properties = dict(queue_id = self.tbl_queue.c.id)) - self.tbl_queue_build = Table('queue_build', self.db_meta, autoload=True) mapper(QueueBuild, self.tbl_queue_build, properties = dict(suite_id = self.tbl_queue_build.c.suite, - queue_id = self.tbl_queue_build.c.queue)) + queue_id = self.tbl_queue_build.c.queue, + queue = relation(Queue))) - self.tbl_section = Table('section', self.db_meta, autoload=True) mapper(Section, self.tbl_section, properties = dict(section_id = self.tbl_section.c.id)) - self.tbl_source = Table('source', self.db_meta, autoload=True) mapper(Source, self.tbl_source, properties = dict(source_id = self.tbl_source.c.id, + version = self.tbl_source.c.version, maintainer_id = self.tbl_source.c.maintainer, - file_id = self.tbl_source.c.file, + 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, - changedby_id = self.tbl_source.c.changedby)) + 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)))) - self.tbl_src_associations = Table('src_associations', self.db_meta, autoload=True) mapper(SrcAssociation, self.tbl_src_associations, - properties = dict(sa_id = self.tbl_src_associations.c.id)) + properties = dict(sa_id = self.tbl_src_associations.c.id, + suite_id = self.tbl_src_associations.c.suite, + suite = relation(Suite), + source_id = self.tbl_src_associations.c.source, + source = relation(Source))) - self.tbl_src_uploaders = Table('src_uploaders', self.db_meta, autoload=True) mapper(SrcUploader, self.tbl_src_uploaders, properties = dict(uploader_id = self.tbl_src_uploaders.c.id, source_id = self.tbl_src_uploaders.c.source, - maintainer_id = self.tbl_src_uploaders.c.maintainer)) + source = relation(Source, + primaryjoin=(self.tbl_src_uploaders.c.source==self.tbl_source.c.id)), + maintainer_id = self.tbl_src_uploaders.c.maintainer, + maintainer = relation(Maintainer, + primaryjoin=(self.tbl_src_uploaders.c.maintainer==self.tbl_maintainer.c.id)))) - self.tbl_suite = Table('suite', self.db_meta, autoload=True) mapper(Suite, self.tbl_suite, properties = dict(suite_id = self.tbl_suite.c.id)) - self.tbl_suite_architectures = Table('suite_architectures', self.db_meta, autoload=True) mapper(SuiteArchitecture, self.tbl_suite_architectures, properties = dict(suite_id = self.tbl_suite_architectures.c.suite, - arch_id = self.tbl_suite_architectures.c.architecture)) + suite = relation(Suite), + arch_id = self.tbl_suite_architectures.c.architecture, + architecture = relation(Architecture))) - self.tbl_uid = Table('uid', self.db_meta, autoload=True) mapper(Uid, self.tbl_uid, properties = dict(uid_id = self.tbl_uid.c.id)) ## Connection functions def __createconn(self): + from config import Config cnf = Config() if cnf["DB::Host"]: # TCP/IP @@ -561,196 +881,21 @@ class DBConn(Singleton): if cnf["DB::Port"] and cnf["DB::Port"] != "-1": connstr += "?port=%s" % cnf["DB::Port"] - self.db_pg = create_engine(connstr) + self.db_pg = create_engine(connstr, echo=self.debug) self.db_meta = MetaData() self.db_meta.bind = self.db_pg self.db_smaker = sessionmaker(bind=self.db_pg, autoflush=True, - transactional=True) + autocommit=False) self.__setuptables() + self.__setupmappers() def session(self): return self.db_smaker() - ## Cache functions - def __init_caches(self): - self.caches = {'suite': Cache(), - 'section': Cache(), - 'priority': Cache(), - 'override_type': Cache(), - 'architecture': Cache(), - 'archive': Cache(), - 'component': Cache(), - 'content_path_names': Cache(), - 'content_file_names': Cache(), - 'location': Cache(lambda x: '%s_%s_%s' % (x['location'], x['component'], x['location'])), - 'maintainer': {}, # TODO - 'keyring': {}, # TODO - 'source': Cache(lambda x: '%s_%s_' % (x['source'], x['version'])), - 'files': Cache(lambda x: '%s_%s_' % (x['filename'], x['location'])), - 'maintainer': {}, # TODO - 'fingerprint': {}, # TODO - 'queue': {}, # TODO - 'uid': {}, # TODO - 'suite_version': Cache(lambda x: '%s_%s' % (x['source'], x['suite'])), - } - - self.prepared_statements = {} - - def prepare(self,name,statement): - if not self.prepared_statements.has_key(name): - pgc.execute(statement) - self.prepared_statements[name] = statement - - def clear_caches(self): - self.__init_caches() - - ## Get functions - def __get_id(self, retfield, selectobj, cachekey, cachename=None): - # This is a bit of a hack but it's an internal function only - if cachename is not None: - res = self.caches[cachename].GetValue(cachekey) - if res: - return res - - c = selectobj.execute() - - if c.rowcount != 1: - return None - - res = c.fetchone() - - if retfield not in res.keys(): - return None - - res = res[retfield] - - if cachename is not None: - self.caches[cachename].SetValue(cachekey, res) - - return res - - def get_suite_id(self, suite): - """ - Returns database id for given C{suite}. - Results are kept in a cache during runtime to minimize database queries. - - @type suite: string - @param suite: The name of the suite - - @rtype: int - @return: the database id for the given suite - - """ - return int(self.__get_id('id', - self.tbl_suite.select(self.tbl_suite.columns.suite_name == suite), - suite, - 'suite')) - - def get_section_id(self, section): - """ - Returns database id for given C{section}. - Results are kept in a cache during runtime to minimize database queries. - - @type section: string - @param section: The name of the section - - @rtype: int - @return: the database id for the given section - - """ - return self.__get_id('id', - self.tbl_section.select(self.tbl_section.columns.section == section), - section, - 'section') - - def get_priority_id(self, priority): - """ - Returns database id for given C{priority}. - Results are kept in a cache during runtime to minimize database queries. - - @type priority: string - @param priority: The name of the priority +__all__.append('DBConn') - @rtype: int - @return: the database id for the given priority - - """ - return self.__get_id('id', - self.tbl_priority.select(self.tbl_priority.columns.priority == priority), - priority, - 'priority') - - def get_override_type_id(self, override_type): - """ - Returns database id for given override C{type}. - Results are kept in a cache during runtime to minimize database queries. - - @type override_type: string - @param override_type: The name of the override type - - @rtype: int - @return: the database id for the given override type - - """ - return self.__get_id('id', - self.tbl_override_type.select(self.tbl_override_type.columns.type == override_type), - override_type, - 'override_type') - - def get_architecture_id(self, architecture): - """ - Returns database id for given C{architecture}. - Results are kept in a cache during runtime to minimize database queries. - - @type architecture: string - @param architecture: The name of the override type - - @rtype: int - @return: the database id for the given architecture - - """ - return self.__get_id('id', - self.tbl_architecture.select(self.tbl_architecture.columns.arch_string == architecture), - architecture, - 'architecture') - - def get_archive_id(self, archive): - """ - returns database id for given c{archive}. - results are kept in a cache during runtime to minimize database queries. - - @type archive: string - @param archive: the name of the override type - - @rtype: int - @return: the database id for the given archive - - """ - archive = archive.lower() - return self.__get_id('id', - self.tbl_archive.select(self.tbl_archive.columns.name == archive), - archive, - 'archive') - - def get_component_id(self, component): - """ - Returns database id for given C{component}. - Results are kept in a cache during runtime to minimize database queries. - - @type component: string - @param component: The name of the override type - - @rtype: int - @return: the database id for the given component - - """ - component = component.lower() - return self.__get_id('id', - self.tbl_component.select(self.tbl_component.columns.name == component), - component.lower(), - 'component') def get_location_id(self, location, component, archive): """ @@ -763,327 +908,233 @@ class DBConn(Singleton): @type location: string @param location: the path of the location - @type component: string - @param component: the name of the component + @type component: int + @param component: the id of the component - @type archive: string - @param archive: the name of the archive + @type archive: int + @param archive: the id of the archive @rtype: int @return: the database id for the location """ - archive = archive.lower() - component = component.lower() - - values = {'archive': archive, 'location': location, 'component': component} - - s = self.tbl_location.join(self.tbl_archive).join(self.tbl_component) - - s = s.select(self.tbl_location.columns.path == location) - s = s.where(self.tbl_archive.columns.name == archive) - s = s.where(self.tbl_component.columns.name == component) - - return self.__get_id('location.id', s, values, 'location') - - def get_source_id(self, source, version): - """ - Returns database id for the combination of C{source} and C{version} - - B{source} - source package name, eg. I{mailfilter}, I{bbdb}, I{glibc} - - B{version} - Results are kept in a cache during runtime to minimize database queries. - - @type source: string - @param source: source package name - - @type version: string - @param version: the source version - - @rtype: int - @return: the database id for the source - - """ - s = self.tbl_source.select() - s = s.where(self.tbl_source.columns.source == source) - s = s.where(self.tbl_source.columns.version == version) + archive_id = self.get_archive_id(archive) - return self.__get_id('id', s, {'source': source, 'version': version}, 'source') - - def get_suite(self, suite): - if isinstance(suite, str): - suite_id = self.get_suite_id(suite.lower()) - elif type(suite) == int: - suite_id = suite - - s = self.tbl_suite.select(self.tbl_suite.columns.id == suite_id) - c = s.execute() - if c.rowcount < 1: + if not archive_id: return None - else: - return c.fetchone() - - def get_suite_version(self, source, suite): - """ - Returns database id for a combination of C{source} and C{suite}. - - B{source} - source package name, eg. I{mailfilter}, I{bbdb}, I{glibc} - - B{suite} - a suite name, eg. I{unstable} + res = None - Results are kept in a cache during runtime to minimize database queries. - - @type source: string - @param source: source package name - - @type suite: string - @param suite: the suite name - - @rtype: string - @return: the version for I{source} in I{suite} - - """ - s = select([self.tbl_source.columns.source, self.tbl_source.columns.version]) -# s = self.tbl_source.join(self.tbl_src_associations).join(self.tbl_suite) + if component: + component_id = self.get_component_id(component) + if component_id: + res = self.__get_single_id("SELECT id FROM location WHERE path=%(location)s AND component=%(component)s AND archive=%(archive)s", + {'location': location, + 'archive': int(archive_id), + 'component': component_id}, cachename='location') + else: + res = self.__get_single_id("SELECT id FROM location WHERE path=%(location)s AND archive=%(archive)d", + {'location': location, 'archive': archive_id, 'component': ''}, cachename='location') - s = s.select(self.tbl_suite.columns.suite_name == suite, use_labels=True) - s = s.select(self.tbl_source.columns.source == source) + return res - return self.__get_id('source.version', s, {'suite': suite, 'source': source}, 'suite_version') - def get_files_id (self, filename, size, md5sum, location_id): - """ - Returns -1, -2 or the file_id for filename, if its C{size} and C{md5sum} match an - existing copy. +def get_files_id (self, filename, size, md5sum, location_id): + """ + Returns -1, -2 or the file_id for filename, if its C{size} and C{md5sum} match an + existing copy. - The database is queried using the C{filename} and C{location_id}. If a file does exist - at that location, the existing size and md5sum are checked against the provided - parameters. A size or checksum mismatch returns -2. If more than one entry is - found within the database, a -1 is returned, no result returns None, otherwise - the file id. + The database is queried using the C{filename} and C{location_id}. If a file does exist + at that location, the existing size and md5sum are checked against the provided + parameters. A size or checksum mismatch returns -2. If more than one entry is + found within the database, a -1 is returned, no result returns None, otherwise + the file id. - Results are kept in a cache during runtime to minimize database queries. + @type filename: string + @param filename: the filename of the file to check against the DB - @type filename: string - @param filename: the filename of the file to check against the DB + @type size: int + @param size: the size of the file to check against the DB - @type size: int - @param size: 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 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 as returned by L{get_location_id} - @type location_id: int - @param location_id: the id of the location as returned by L{get_location_id} + @rtype: int / None + @return: Various return values are possible: + - -2: size/checksum error + - -1: more than one file found in database + - None: no file found in database + - int: file id - @rtype: int / None - @return: Various return values are possible: - - -2: size/checksum error - - -1: more than one file found in database - - None: no file found in database - - int: file id + """ + values = {'filename' : filename, + 'location' : location_id} - """ - values = {'filename' : filename, - 'location' : location_id} + if not res: + query = """SELECT id, size, md5sum + FROM files + WHERE filename = %(filename)s AND location = %(location)s""" - res = self.caches['files'].GetValue( values ) + cursor = self.db_con.cursor() + cursor.execute( query, values ) - if not res: - query = """SELECT id, size, md5sum - FROM files - WHERE filename = %(filename)s AND location = %(location)s""" + if cursor.rowcount == 0: + res = None - cursor = self.db_con.cursor() - cursor.execute( query, values ) + elif cursor.rowcount != 1: + res = -1 - if cursor.rowcount == 0: - res = None + else: + row = cursor.fetchone() - elif cursor.rowcount != 1: - res = -1 + if row[1] != int(size) or row[2] != md5sum: + res = -2 else: - row = cursor.fetchone() + res = row[0] - if row[1] != int(size) or row[2] != md5sum: - res = -2 - - else: - self.caches['files'].SetValue(values, row[0]) - res = row[0] - - return res - - - def get_or_set_contents_file_id(self, filename): - """ - Returns database id for given filename. - - Results are kept in a cache during runtime to minimize database queries. - If no matching file is found, a row is inserted. + return res - @type filename: string - @param filename: The filename - @rtype: int - @return: the database id for the given component - """ - try: - values={'value': filename} - query = "SELECT id FROM content_file_names WHERE file = %(value)s" - id = self.__get_single_id(query, values, cachename='content_file_names') - if not id: - c = self.db_con.cursor() - c.execute( "INSERT INTO content_file_names VALUES (DEFAULT, %(value)s) RETURNING id", - values ) - - id = c.fetchone()[0] - self.caches['content_file_names'].SetValue(values, id) - - return id - except: - traceback.print_exc() - raise - - def get_or_set_contents_path_id(self, path): - """ - Returns database id for given path. +def get_or_set_contents_file_id(self, filename): + """ + Returns database id for given filename. - Results are kept in a cache during runtime to minimize database queries. - If no matching file is found, a row is inserted. + If no matching file is found, a row is inserted. - @type path: string - @param path: The filename + @type filename: string + @param filename: The filename - @rtype: int - @return: the database id for the given component - """ - try: - values={'value': path} - query = "SELECT id FROM content_file_paths WHERE path = %(value)s" - id = self.__get_single_id(query, values, cachename='content_path_names') - if not id: - c = self.db_con.cursor() - c.execute( "INSERT INTO content_file_paths VALUES (DEFAULT, %(value)s) RETURNING id", - values ) - - id = c.fetchone()[0] - self.caches['content_path_names'].SetValue(values, id) - - return id - except: - traceback.print_exc() - raise - - def get_suite_architectures(self, suite): - """ - Returns list of architectures for C{suite}. + @rtype: int + @return: the database id for the given component + """ + try: + values={'value': filename} + query = "SELECT id FROM content_file_names WHERE file = %(value)s" + if not id: + c = self.db_con.cursor() + c.execute( "INSERT INTO content_file_names VALUES (DEFAULT, %(value)s) RETURNING id", + values ) + + id = c.fetchone()[0] + + return id + except: + traceback.print_exc() + raise + +def get_or_set_contents_path_id(self, path): + """ + Returns database id for given path. - @type suite: string, int - @param suite: the suite name or the suite_id + If no matching file is found, a row is inserted. - @rtype: list - @return: the list of architectures for I{suite} - """ + @type path: string + @param path: The filename - suite_id = None - if type(suite) == str: - suite_id = self.get_suite_id(suite) - elif type(suite) == int: - suite_id = suite - else: - return None + @rtype: int + @return: the database id for the given component + """ + try: + values={'value': path} + query = "SELECT id FROM content_file_paths WHERE path = %(value)s" + if not id: + c = self.db_con.cursor() + c.execute( "INSERT INTO content_file_paths VALUES (DEFAULT, %(value)s) RETURNING id", + values ) - c = self.db_con.cursor() - c.execute( """SELECT a.arch_string FROM suite_architectures sa - JOIN architecture a ON (a.id = sa.architecture) - WHERE suite='%s'""" % suite_id ) + id = c.fetchone()[0] - return map(lambda x: x[0], c.fetchall()) + return id + except: + traceback.print_exc() + raise - def insert_content_paths(self, bin_id, fullpaths): - """ - Make sure given path is associated with given binary id - @type bin_id: int - @param bin_id: the id of the binary - @type fullpaths: list - @param fullpaths: the list of paths of the file being associated with the binary +def insert_content_paths(self, bin_id, fullpaths): + """ + Make sure given path is associated with given binary id - @return: True upon success - """ + @type bin_id: int + @param bin_id: the id of the binary + @type fullpaths: list + @param fullpaths: the list of paths of the file being associated with the binary - c = self.db_con.cursor() + @return: True upon success + """ - c.execute("BEGIN WORK") - try: + c = self.db_con.cursor() - for fullpath in fullpaths: - (path, file) = os.path.split(fullpath) + c.execute("BEGIN WORK") + try: - if path.startswith( "./" ): - path = path[2:] - # Get the necessary IDs ... - file_id = self.get_or_set_contents_file_id(file) - path_id = self.get_or_set_contents_path_id(path) + for fullpath in fullpaths: + (path, file) = os.path.split(fullpath) - c.execute("""INSERT INTO content_associations - (binary_pkg, filepath, filename) - VALUES ( '%d', '%d', '%d')""" % (bin_id, path_id, file_id) ) + # Get the necessary IDs ... + file_id = self.get_or_set_contents_file_id(file) + path_id = self.get_or_set_contents_path_id(path) - c.execute("COMMIT") - return True - except: - traceback.print_exc() - c.execute("ROLLBACK") - return False + c.execute("""INSERT INTO content_associations + (binary_pkg, filepath, filename) + VALUES ( '%d', '%d', '%d')""" % (bin_id, path_id, file_id) ) - def insert_pending_content_paths(self, package, fullpaths): - """ - Make sure given paths are temporarily associated with given - package + c.execute("COMMIT") + return True + except: + traceback.print_exc() + c.execute("ROLLBACK") + return False - @type package: dict - @param package: the package to associate with should have been read in from the binary control file - @type fullpaths: list - @param fullpaths: the list of paths of the file being associated with the binary +def insert_pending_content_paths(self, package, fullpaths): + """ + Make sure given paths are temporarily associated with given + package - @return: True upon success - """ + @type package: dict + @param package: the package to associate with should have been read in from the binary control file + @type fullpaths: list + @param fullpaths: the list of paths of the file being associated with the binary - c = self.db_con.cursor() - - c.execute("BEGIN WORK") - try: - arch_id = self.get_architecture_id(package['Architecture']) - - # Remove any already existing recorded files for this package - c.execute("""DELETE FROM pending_content_associations - WHERE package=%(Package)s - AND version=%(Version)s - AND architecture=%(ArchID)s""", {'Package': package['Package'], - 'Version': package['Version'], - 'ArchID': arch_id}) - - for fullpath in fullpaths: - (path, file) = os.path.split(fullpath) - - if path.startswith( "./" ): - path = path[2:] - # Get the necessary IDs ... - file_id = self.get_or_set_contents_file_id(file) - path_id = self.get_or_set_contents_path_id(path) - - c.execute("""INSERT INTO pending_content_associations - (package, version, architecture, filepath, filename) - VALUES (%%(Package)s, %%(Version)s, '%d', '%d', '%d')""" - % (arch_id, path_id, file_id), package ) - - c.execute("COMMIT") - return True - except: - traceback.print_exc() - c.execute("ROLLBACK") - return False + @return: True upon success + """ + c = self.db_con.cursor() + + c.execute("BEGIN WORK") + try: + arch_id = self.get_architecture_id(package['Architecture']) + + # Remove any already existing recorded files for this package + c.execute("""DELETE FROM pending_content_associations + WHERE package=%(Package)s + AND version=%(Version)s + AND architecture=%(ArchID)s""", {'Package': package['Package'], + 'Version': package['Version'], + 'ArchID': arch_id}) + + for fullpath in fullpaths: + (path, file) = os.path.split(fullpath) + + if path.startswith( "./" ): + path = path[2:] + # Get the necessary IDs ... + file_id = self.get_or_set_contents_file_id(file) + path_id = self.get_or_set_contents_path_id(path) + + c.execute("""INSERT INTO pending_content_associations + (package, version, architecture, filepath, filename) + VALUES (%%(Package)s, %%(Version)s, '%d', '%d', '%d')""" + % (arch_id, path_id, file_id), package ) + + c.execute("COMMIT") + return True + except: + traceback.print_exc() + c.execute("ROLLBACK") + return False