@contact: Debian FTPMaster <ftpmaster@debian.org>
@copyright: 2000, 2001, 2002, 2003, 2004, 2006 James Troup <james@nocrew.org>
@copyright: 2008-2009 Mark Hymers <mhy@debian.org>
-@copyright: 2009 Joerg Jaspert <joerg@debian.org>
+@copyright: 2009, 2010 Joerg Jaspert <joerg@debian.org>
@copyright: 2009 Mike O'Connor <stew@debian.org>
@license: GNU General Public License version 2 or later
"""
import re
import psycopg2
import traceback
-from datetime import datetime
+import commands
+from datetime import datetime, timedelta
+from errno import ENOENT
+from tempfile import mkstemp, mkdtemp
from inspect import getargspec
from sqlalchemy.exc import *
from sqlalchemy.orm.exc import NoResultFound
+# Only import Config until Queue stuff is changed to store its config
+# in the database
from config import Config
-from singleton import Singleton
from textutils import fix_maintainer
################################################################################
# reflection
class DebVersion(sqltypes.Text):
+ """
+ Support the debversion type
+ """
+
def get_col_spec(self):
return "DEBVERSION"
"""
Returns list of Suite objects for given C{architecture} name
- @type source: str
- @param source: Architecture 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
"""
Returns list of Suite objects which given C{package} name is in
- @type source: str
- @param source: DBBinary package name to search for
+ @type package: str
+ @param package: DBBinary package name to search for
@rtype: list
@return: list of Suite objects for the given package
@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 architecture: str, list or None
+ @param architecture: Architectures to limit to (or None if no limit)
@type session: Session
@param session: Optional SQL session object (a temporary one will be
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
- WHERE b.package=:package
+ WHERE b.package='%(package)s'
AND b.file = fi.id
AND fi.location = l.id
AND l.component = c.id
AND ba.bin=b.id
AND ba.suite = su.id
- AND su.suite_name=:suitename
+ AND su.suite_name %(suitename)s
ORDER BY b.version DESC"""
- return session.execute(sql, {'package': package, 'suitename': suitename})
+ return session.execute(sql % {'package': package, 'suitename': suitename})
__all__.append('get_binary_from_name_suite')
################################################################################
+MINIMAL_APT_CONF="""
+Dir
+{
+ ArchiveDir "%(archivepath)s";
+ OverrideDir "%(overridedir)s";
+ CacheDir "%(cachedir)s";
+};
+
+Default
+{
+ Packages::Compress ". bzip2 gzip";
+ Sources::Compress ". bzip2 gzip";
+ DeLinkLimit 0;
+ FileMode 0664;
+}
+
+bindirectory "incoming"
+{
+ Packages "Packages";
+ Contents " ";
+
+ BinOverride "override.sid.all3";
+ BinCacheDB "packages-accepted.db";
+
+ FileList "%(filelist)s";
+
+ PathPrefix "";
+ Packages::Extensions ".deb .udeb";
+};
+
+bindirectory "incoming/"
+{
+ Sources "Sources";
+ BinOverride "override.sid.all3";
+ SrcOverride "override.sid.all3.src";
+ FileList "%(filelist)s";
+};
+"""
+
class BuildQueue(object):
def __init__(self, *args, **kwargs):
pass
def __repr__(self):
- return '<Queue %s>' % self.queue_name
+ return '<BuildQueue %s>' % self.queue_name
+
+ def write_metadata(self, starttime, force=False):
+ # Do we write out metafiles?
+ if not (force or self.generate_metadata):
+ return
+
+ session = DBConn().session().object_session(self)
+
+ fl_fd = fl_name = ac_fd = ac_name = None
+ tempdir = None
+ arches = " ".join([ a.arch_string for a in session.query(Architecture).all() if a.arch_string != 'source' ])
+ startdir = os.getcwd()
+
+ try:
+ # Grab files we want to include
+ newer = session.query(BuildQueueFile).filter_by(build_queue_id = self.queue_id).filter(BuildQueueFile.lastused + timedelta(seconds=self.stay_of_execution) > starttime).all()
+ # Write file list with newer files
+ (fl_fd, fl_name) = mkstemp()
+ for n in newer:
+ os.write(fl_fd, '%s\n' % n.fullpath)
+ os.close(fl_fd)
+
+ cnf = Config()
+
+ # Write minimal apt.conf
+ # TODO: Remove hardcoding from template
+ (ac_fd, ac_name) = mkstemp()
+ os.write(ac_fd, MINIMAL_APT_CONF % {'archivepath': self.path,
+ 'filelist': fl_name,
+ 'cachedir': cnf["Dir::Cache"],
+ 'overridedir': cnf["Dir::Override"],
+ })
+ os.close(ac_fd)
+
+ # Run apt-ftparchive generate
+ os.chdir(os.path.dirname(ac_name))
+ os.system('apt-ftparchive -qq -o APT::FTPArchive::Contents=off generate %s' % os.path.basename(ac_name))
+
+ # Run apt-ftparchive release
+ # TODO: Eww - fix this
+ bname = os.path.basename(self.path)
+ os.chdir(self.path)
+ os.chdir('..')
+
+ # We have to remove the Release file otherwise it'll be included in the
+ # new one
+ try:
+ os.unlink(os.path.join(bname, 'Release'))
+ except OSError:
+ pass
+
+ os.system("""apt-ftparchive -qq -o APT::FTPArchive::Release::Origin="%s" -o APT::FTPArchive::Release::Label="%s" -o APT::FTPArchive::Release::Description="%s" -o APT::FTPArchive::Release::Architectures="%s" release %s > Release""" % (self.origin, self.label, self.releasedescription, arches, bname))
+
+ # Crude hack with open and append, but this whole section is and should be redone.
+ if self.notautomatic:
+ release=open("Release", "a")
+ release.write("NotAutomatic: yes")
+ release.close()
+
+ # Sign if necessary
+ if self.signingkey:
+ keyring = "--secret-keyring \"%s\"" % cnf["Dinstall::SigningKeyring"]
+ if cnf.has_key("Dinstall::SigningPubKeyring"):
+ keyring += " --keyring \"%s\"" % cnf["Dinstall::SigningPubKeyring"]
+
+ os.system("gpg %s --no-options --batch --no-tty --armour --default-key %s --detach-sign -o Release.gpg Release""" % (keyring, self.signingkey))
+
+ # Move the files if we got this far
+ os.rename('Release', os.path.join(bname, 'Release'))
+ if self.signingkey:
+ os.rename('Release.gpg', os.path.join(bname, 'Release.gpg'))
+
+ # Clean up any left behind files
+ finally:
+ os.chdir(startdir)
+ if fl_fd:
+ try:
+ os.close(fl_fd)
+ except OSError:
+ pass
+
+ if fl_name:
+ try:
+ os.unlink(fl_name)
+ except OSError:
+ pass
+
+ if ac_fd:
+ try:
+ os.close(ac_fd)
+ except OSError:
+ pass
+
+ if ac_name:
+ try:
+ os.unlink(ac_name)
+ except OSError:
+ pass
+
+ def clean_and_update(self, starttime, Logger, dryrun=False):
+ """WARNING: This routine commits for you"""
+ session = DBConn().session().object_session(self)
+
+ if self.generate_metadata and not dryrun:
+ self.write_metadata(starttime)
+
+ # Grab files older than our execution time
+ older = session.query(BuildQueueFile).filter_by(build_queue_id = self.queue_id).filter(BuildQueueFile.lastused + timedelta(seconds=self.stay_of_execution) <= starttime).all()
+
+ for o in older:
+ killdb = False
+ try:
+ if dryrun:
+ Logger.log(["I: Would have removed %s from the queue" % o.fullpath])
+ else:
+ Logger.log(["I: Removing %s from the queue" % o.fullpath])
+ os.unlink(o.fullpath)
+ killdb = True
+ except OSError, e:
+ # If it wasn't there, don't worry
+ if e.errno == ENOENT:
+ killdb = True
+ else:
+ # TODO: Replace with proper logging call
+ Logger.log(["E: Could not remove %s" % o.fullpath])
+
+ if killdb:
+ session.delete(o)
+
+ session.commit()
+
+ for f in os.listdir(self.path):
+ if f.startswith('Packages') or f.startswith('Source') or f.startswith('Release'):
+ continue
+
+ try:
+ r = session.query(BuildQueueFile).filter_by(build_queue_id = self.queue_id).filter_by(filename = f).one()
+ except NoResultFound:
+ fp = os.path.join(self.path, f)
+ if dryrun:
+ Logger.log(["I: Would remove unused link %s" % fp])
+ else:
+ Logger.log(["I: Removing unused link %s" % fp])
+ try:
+ os.unlink(fp)
+ except OSError:
+ Logger.log(["E: Failed to unlink unreferenced file %s" % r.fullpath])
def add_file_from_pool(self, poolfile):
"""Copies a file into the pool. Assumes that the PoolFile object is
for f in self.queuefiles:
if f.fileid is not None and f.fileid == poolfile.file_id or \
f.poolfile.filename == poolfile_basename:
- # In this case, update the QueueFile entry so we
+ # In this case, update the BuildQueueFile entry so we
# don't remove it too early
f.lastused = datetime.now()
- DBConn().session().object_session(pf).add(f)
+ DBConn().session().object_session(poolfile).add(f)
return f
- # Prepare QueueFile object
- qf = QueueFile()
- qf.queue_id = self.queue_id
+ # Prepare BuildQueueFile object
+ qf = BuildQueueFile()
+ qf.build_queue_id = self.queue_id
qf.lastused = datetime.now()
- qf.filename = dest
+ qf.filename = poolfile_basename
- targetpath = qf.fullpath
+ targetpath = poolfile.fullpath
queuepath = os.path.join(self.path, poolfile_basename)
try:
- if self.copy_pool_files:
+ if self.copy_files:
# We need to copy instead of symlink
import utils
- utils.copy(targetfile, queuepath)
+ utils.copy(targetpath, queuepath)
# NULL in the fileid field implies a copy
qf.fileid = None
else:
- os.symlink(targetfile, queuepath)
+ os.symlink(targetpath, queuepath)
qf.fileid = poolfile.file_id
except OSError:
return None
__all__.append('BuildQueue')
@session_wrapper
-def get_queue(queuename, session=None):
+def get_build_queue(queuename, session=None):
"""
- Returns Queue object for given C{queue name}, creating it if it does not
+ Returns BuildQueue object for given C{queue name}, creating it if it does not
exist.
@type queuename: string
@param session: Optional SQLA session object (a temporary one will be
generated if not supplied)
- @rtype: Queue
- @return: Queue object for the given queue
+ @rtype: BuildQueue
+ @return: BuildQueue object for the given queue
"""
- q = session.query(Queue).filter_by(queue_name=queuename)
+ q = session.query(BuildQueue).filter_by(queue_name=queuename)
try:
return q.one()
except NoResultFound:
return None
-__all__.append('get_queue')
+__all__.append('get_build_queue')
################################################################################
pass
def __repr__(self):
- return '<BuildQueueFile %s (%s)>' % (self.filename, self.queue_id)
+ return '<BuildQueueFile %s (%s)>' % (self.filename, self.build_queue_id)
+
+ @property
+ def fullpath(self):
+ return os.path.join(self.buildqueue.path, self.filename)
+
__all__.append('BuildQueueFile')
If no matching file is found, a row is inserted.
- @type filename: string
- @param filename: The filepath
+ @type filepath: string
+ @param filepath: The filepath
+
@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
try:
# Insert paths
- pathcache = {}
- for fullpath in fullpaths:
- if fullpath.startswith( './' ):
- fullpath = fullpath[2:]
+ def generate_path_dicts():
+ for fullpath in fullpaths:
+ if fullpath.startswith( './' ):
+ fullpath = fullpath[2:]
- session.execute( "INSERT INTO bin_contents ( file, binary_id ) VALUES ( :filename, :id )", { 'filename': fullpath, 'id': binary_id} )
+ yield {'filename':fullpath, 'id': binary_id }
+
+ for d in generate_path_dicts():
+ session.execute( "INSERT INTO bin_contents ( file, binary_id ) VALUES ( :filename, :id )",
+ d )
session.commit()
if privatetrans:
def check_poolfile(filename, filesize, md5sum, location_id, session=None):
"""
Returns a tuple:
- (ValidFileFound [boolean or None], PoolFile object or None)
+ (ValidFileFound [boolean or None], PoolFile object or None)
@type filename: string
@param filename: the filename of the file to check against the DB
@rtype: tuple
@return: Tuple of length 2.
- If more than one file found with that name:
- (None, None)
- If valid pool file found: (True, PoolFile object)
- If valid pool file not found:
- (False, None) if no file found
- (False, PoolFile object) if file found with size/md5sum mismatch
+ - If more than one file found with that name: (C{None}, C{None})
+ - If valid pool file found: (C{True}, C{PoolFile object})
+ - If valid pool file not found:
+ - (C{False}, C{None}) if no file found
+ - (C{False}, C{PoolFile object}) if file found with size/md5sum mismatch
"""
q = session.query(PoolFile).filter_by(filename=filename)
"""
# TODO: There must be a way of properly using bind parameters with %FOO%
- q = session.query(PoolFile).filter(PoolFile.filename.like('%%%s%%' % filename))
+ q = session.query(PoolFile).filter(PoolFile.filename.like('%%/%s' % filename))
return q.all()
################################################################################
-class KnownChange(object):
+class DBChange(object):
def __init__(self, *args, **kwargs):
pass
def __repr__(self):
- return '<KnownChange %s>' % self.changesname
+ return '<DBChange %s>' % self.changesname
+
+ def clean_from_queue(self):
+ session = DBConn().session().object_session(self)
+
+ # Remove changes_pool_files entries
+ self.poolfiles = []
+
+ # Remove changes_pending_files references
+ self.files = []
-__all__.append('KnownChange')
+ # Clear out of queue
+ self.in_queue = None
+ self.approved_for_id = None
+
+__all__.append('DBChange')
@session_wrapper
-def get_knownchange(filename, session=None):
+def get_dbchange(filename, session=None):
"""
- returns knownchange object for given C{filename}.
+ returns DBChange object for given C{filename}.
- @type archive: string
- @param archive: the name of the arhive
+ @type filename: string
+ @param filename: the name of the file
@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)
+ @rtype: DBChange
+ @return: DBChange object for the given filename (C{None} if not present)
"""
- q = session.query(KnownChange).filter_by(changesname=filename)
+ q = session.query(DBChange).filter_by(changesname=filename)
try:
return q.one()
except NoResultFound:
return None
-__all__.append('get_knownchange')
+__all__.append('get_dbchange')
################################################################################
and archive
@type location: string
- @param location: the path of the location, e.g. I{/srv/ftp.debian.org/ftp/pool/}
+ @param location: the path of the location, e.g. I{/srv/ftp-master.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)
+ @param archive: the archive name (if None, no restriction applied)
@rtype: Location / None
@return: Either a Location object or None if one can't be found
################################################################################
-class PendingContentAssociation(object):
+class DebContents(object):
+ def __init__(self, *args, **kwargs):
+ pass
+
+ def __repr__(self):
+ return '<DebConetnts %s: %s>' % (self.package.package,self.file)
+
+__all__.append('DebContents')
+
+
+class UdebContents(object):
+ def __init__(self, *args, **kwargs):
+ pass
+
+ def __repr__(self):
+ return '<UdebConetnts %s: %s>' % (self.package.package,self.file)
+
+__all__.append('UdebContents')
+
+class PendingBinContents(object):
def __init__(self, *args, **kwargs):
pass
def __repr__(self):
- return '<PendingContentAssociation %s>' % self.pca_id
+ return '<PendingBinContents %s>' % self.contents_id
-__all__.append('PendingContentAssociation')
+__all__.append('PendingBinContents')
-def insert_pending_content_paths(package, fullpaths, session=None):
+def insert_pending_content_paths(package,
+ is_udeb,
+ fullpaths,
+ session=None):
"""
Make sure given paths are temporarily associated with given
package
arch_id = arch.arch_id
# Remove any already existing recorded files for this package
- q = session.query(PendingContentAssociation)
+ q = session.query(PendingBinContents)
q = q.filter_by(package=package['Package'])
q = q.filter_by(version=package['Version'])
q = q.filter_by(architecture=arch_id)
q.delete()
- # Insert paths
- pathcache = {}
for fullpath in fullpaths:
- (path, filename) = 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(filename, session)
-
- pathcache[fullpath] = (filepath_id, filename_id)
+ if fullpath.startswith( "./" ):
+ fullpath = fullpath[2:]
- for fullpath, dat in pathcache.items():
- pca = PendingContentAssociation()
+ pca = PendingBinContents()
pca.package = package['Package']
pca.version = package['Version']
- pca.filepath_id = dat[0]
- pca.filename_id = dat[1]
+ pca.file = fullpath
pca.architecture = arch_id
+
+ if isudeb:
+ pca.type = 8 # gross
+ else:
+ pca.type = 7 # also gross
session.add(pca)
# Only commit if we set up the session ourself
__all__.append('PolicyQueue')
+@session_wrapper
+def get_policy_queue(queuename, session=None):
+ """
+ Returns PolicyQueue object for given C{queue name}
+
+ @type queuename: string
+ @param queuename: The name of the queue
+
+ @type session: Session
+ @param session: Optional SQLA session object (a temporary one will be
+ generated if not supplied)
+
+ @rtype: PolicyQueue
+ @return: PolicyQueue object for the given queue
+ """
+
+ q = session.query(PolicyQueue).filter_by(queue_name=queuename)
+
+ try:
+ return q.one()
+ except NoResultFound:
+ return None
+
+__all__.append('get_policy_queue')
+
+@session_wrapper
+def get_policy_queue_from_path(pathname, session=None):
+ """
+ Returns PolicyQueue object for given C{path name}
+
+ @type queuename: string
+ @param queuename: The path
+
+ @type session: Session
+ @param session: Optional SQLA session object (a temporary one will be
+ generated if not supplied)
+
+ @rtype: PolicyQueue
+ @return: PolicyQueue object for the given queue
+ """
+
+ q = session.query(PolicyQueue).filter_by(path=pathname)
+
+ try:
+ return q.one()
+ except NoResultFound:
+ return None
+
+__all__.append('get_policy_queue_from_path')
+
################################################################################
class Priority(object):
1. exact match => 1.0-3
2. bin-only NMU => 1.0-3+b1 , 1.0-3.1+b1
- @type package: string
- @param package: package source name
+ @type source: string
+ @param source: source name
@type source_version: string
@param source_version: expected source version
@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 version: str or None
+ @param version: 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
def add_dsc_to_db(u, filename, session=None):
entry = u.pkg.files[filename]
source = DBSource()
+ pfs = []
source.source = u.pkg.dsc["source"]
source.version = u.pkg.dsc["version"] # NB: not files[file]["version"], that has no epoch
filename = entry["pool name"] + filename
poolfile = add_poolfile(filename, entry, dsc_location_id, session)
session.flush()
+ pfs.append(poolfile)
entry["files id"] = poolfile.file_id
source.poolfile_id = entry["files id"]
# FIXME: needs to check for -1/-2 and or handle exception
if found and obj is not None:
files_id = obj.file_id
+ pfs.append(obj)
# If still not found, add it
if files_id is None:
dentry["sha1sum"] = dfentry["sha1sum"]
dentry["sha256sum"] = dfentry["sha256sum"]
poolfile = add_poolfile(filename, dentry, dsc_location_id, session)
+ pfs.append(poolfile)
files_id = poolfile.file_id
+ else:
+ poolfile = get_poolfile_by_id(files_id, session)
+ if poolfile is None:
+ utils.fubar("INTERNAL ERROR. Found no poolfile with id %d" % files_id)
+ pfs.append(poolfile)
df.poolfile_id = files_id
session.add(df)
# Add the src_uploaders to the DB
uploader_ids = [source.maintainer_id]
if u.pkg.dsc.has_key("uploaders"):
- for up in u.pkg.dsc["uploaders"].split(","):
+ for up in u.pkg.dsc["uploaders"].replace(">, ", ">\t").split("\t"):
up = up.strip()
uploader_ids.append(get_or_set_maintainer(up, session).maintainer_id)
added_ids = {}
- for up in uploader_ids:
- if added_ids.has_key(up):
- utils.warn("Already saw uploader %s for source %s" % (up, source.source))
+ for up_id in uploader_ids:
+ if added_ids.has_key(up_id):
+ import utils
+ utils.warn("Already saw uploader %s for source %s" % (up_id, source.source))
continue
- added_ids[u]=1
+ added_ids[up_id]=1
su = SrcUploader()
- su.maintainer_id = up
+ su.maintainer_id = up_id
su.source_id = source.source_id
session.add(su)
session.flush()
- return dsc_component, dsc_location_id
+ return source, dsc_component, dsc_location_id, pfs
__all__.append('add_dsc_to_db')
filename = entry["pool name"] + filename
fullpath = os.path.join(cnf["Dir::Pool"], filename)
if not entry.get("location id", None):
- entry["location id"] = get_location(cnf["Dir::Pool"], entry["component"], utils.where_am_i(), session).location_id
+ entry["location id"] = get_location(cnf["Dir::Pool"], entry["component"], session=session).location_id
- if not entry.get("files id", None):
+ if entry.get("files id", None):
+ poolfile = get_poolfile_by_id(bin.poolfile_id)
+ bin.poolfile_id = entry["files id"]
+ else:
poolfile = add_poolfile(filename, entry, entry["location id"], session)
- entry["files id"] = poolfile.file_id
-
- bin.poolfile_id = entry["files id"]
+ bin.poolfile_id = entry["files id"] = poolfile.file_id
# Find source id
bin_sources = get_sources_from_name(entry["source package"], entry["source version"], session=session)
# session.rollback()
# raise MissingContents, "No contents stored for package %s, and couldn't determine contents of %s" % (bin.package, filename)
+ return poolfile
+
__all__.append('add_deb_to_db')
################################################################################
('OverrideSuite', 'overridesuite'),
('ChangelogBase', 'changelogbase')]
-
class Suite(object):
def __init__(self, *args, **kwargs):
pass
"""
Returns list of Architecture objects for given C{suite} name
- @type source: str
- @param source: Suite name to search for
+ @type suite: str
+ @param suite: Suite name to search for
@type skipsrc: boolean
@param skipsrc: Whether to skip returning the 'source' architecture entry
__all__.append('Uid')
-@session_wrapper
-def add_database_user(uidname, session=None):
- """
- Adds a database user
-
- @type uidname: string
- @param uidname: The uid of the user 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.
-
- @rtype: Uid
- @return: the uid object for the given uidname
- """
-
- session.execute("CREATE USER :uid", {'uid': uidname})
- session.commit_or_flush()
-
-__all__.append('add_database_user')
-
@session_wrapper
def get_or_set_uid(uidname, session=None):
"""
################################################################################
-class DBConn(Singleton):
+class DBConn(object):
"""
database module init.
"""
+ __shared_state = {}
+
def __init__(self, *args, **kwargs):
- super(DBConn, self).__init__(*args, **kwargs)
+ self.__dict__ = self.__shared_state
- def _startup(self, *args, **kwargs):
- self.debug = False
- if kwargs.has_key('debug'):
- self.debug = True
- self.__createconn()
+ if not getattr(self, 'initialised', False):
+ self.initialised = True
+ self.debug = kwargs.has_key('debug')
+ self.__createconn()
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_binary_acl = Table('binary_acl', self.db_meta, autoload=True)
- self.tbl_binary_acl_map = Table('binary_acl_map', self.db_meta, autoload=True)
- self.tbl_build_queue = Table('build_queue', self.db_meta, autoload=True)
- self.tbl_build_queue_files = Table('build_queue_files', 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_changes_pending_binary = Table('changes_pending_binaries', self.db_meta, autoload=True)
- self.tbl_changes_pending_files = Table('changes_pending_files', self.db_meta, autoload=True)
- self.tbl_changes_pending_source = Table('changes_pending_source', self.db_meta, autoload=True)
- self.tbl_changes_pending_source_files = Table('changes_pending_source_files', self.db_meta, autoload=True)
- self.tbl_changes_pool_files = Table('changes_pool_files', 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_known_changes = Table('known_changes', self.db_meta, autoload=True)
- self.tbl_keyring_acl_map = Table('keyring_acl_map', 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)
- self.tbl_policy_queue = Table('policy_queue', self.db_meta, autoload=True)
- self.tbl_priority = Table('priority', 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_source_acl = Table('source_acl', 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_suite_build_queue_copy = Table('suite_build_queue_copy', self.db_meta, autoload=True)
- self.tbl_uid = Table('uid', self.db_meta, autoload=True)
- self.tbl_upload_blocks = Table('upload_blocks', self.db_meta, autoload=True)
+ tables = (
+ 'architecture',
+ 'archive',
+ 'bin_associations',
+ 'binaries',
+ 'binary_acl',
+ 'binary_acl_map',
+ 'bin_contents',
+ 'build_queue',
+ 'build_queue_files',
+ 'component',
+ 'config',
+ 'changes_pending_binaries',
+ 'changes_pending_files',
+ 'changes_pending_files_map',
+ 'changes_pending_source',
+ 'changes_pending_source_files',
+ 'changes_pool_files',
+ 'deb_contents',
+ 'dsc_files',
+ 'files',
+ 'fingerprint',
+ 'keyrings',
+ 'changes',
+ 'keyring_acl_map',
+ 'location',
+ 'maintainer',
+ 'new_comments',
+ 'override',
+ 'override_type',
+ 'pending_bin_contents',
+ 'policy_queue',
+ 'priority',
+ 'section',
+ 'source',
+ 'source_acl',
+ 'src_associations',
+ 'src_format',
+ 'src_uploaders',
+ 'suite',
+ 'suite_architectures',
+ 'suite_src_formats',
+ 'suite_build_queue_copy',
+ 'udeb_contents',
+ 'uid',
+ 'upload_blocks',
+ )
+
+ for table_name in tables:
+ table = Table(table_name, self.db_meta, autoload=True)
+ setattr(self, 'tbl_%s' % table_name, table)
def __setupmappers(self):
mapper(Architecture, self.tbl_architecture,
binary_id = self.tbl_bin_associations.c.bin,
binary = relation(DBBinary)))
+ mapper(PendingBinContents, self.tbl_pending_bin_contents,
+ properties = dict(contents_id =self.tbl_pending_bin_contents.c.id,
+ filename = self.tbl_pending_bin_contents.c.filename,
+ package = self.tbl_pending_bin_contents.c.package,
+ version = self.tbl_pending_bin_contents.c.version,
+ arch = self.tbl_pending_bin_contents.c.arch,
+ otype = self.tbl_pending_bin_contents.c.type))
+
+ mapper(DebContents, self.tbl_deb_contents,
+ properties = dict(binary_id=self.tbl_deb_contents.c.binary_id,
+ package=self.tbl_deb_contents.c.package,
+ suite=self.tbl_deb_contents.c.suite,
+ arch=self.tbl_deb_contents.c.arch,
+ section=self.tbl_deb_contents.c.section,
+ filename=self.tbl_deb_contents.c.filename))
+
+ mapper(UdebContents, self.tbl_udeb_contents,
+ properties = dict(binary_id=self.tbl_udeb_contents.c.binary_id,
+ package=self.tbl_udeb_contents.c.package,
+ suite=self.tbl_udeb_contents.c.suite,
+ arch=self.tbl_udeb_contents.c.arch,
+ section=self.tbl_udeb_contents.c.section,
+ filename=self.tbl_udeb_contents.c.filename))
+
mapper(BuildQueue, self.tbl_build_queue,
properties = dict(queue_id = self.tbl_build_queue.c.id))
properties = dict(keyring_name = self.tbl_keyrings.c.name,
keyring_id = self.tbl_keyrings.c.id))
- mapper(KnownChange, self.tbl_known_changes,
- properties = dict(known_change_id = self.tbl_known_changes.c.id,
+ mapper(DBChange, self.tbl_changes,
+ properties = dict(change_id = self.tbl_changes.c.id,
poolfiles = relation(PoolFile,
secondary=self.tbl_changes_pool_files,
backref="changeslinks"),
- files = relation(ChangePendingFile, backref="changesfile")))
-
- mapper(ChangePendingBinary, self.tbl_changes_pending_binary,
- properties = dict(change_pending_binary_id = self.tbl_changes_pending_binary.c.id))
+ seen = self.tbl_changes.c.seen,
+ source = self.tbl_changes.c.source,
+ binaries = self.tbl_changes.c.binaries,
+ architecture = self.tbl_changes.c.architecture,
+ distribution = self.tbl_changes.c.distribution,
+ urgency = self.tbl_changes.c.urgency,
+ maintainer = self.tbl_changes.c.maintainer,
+ changedby = self.tbl_changes.c.changedby,
+ date = self.tbl_changes.c.date,
+ version = self.tbl_changes.c.version,
+ files = relation(ChangePendingFile,
+ secondary=self.tbl_changes_pending_files_map,
+ backref="changesfile"),
+ in_queue_id = self.tbl_changes.c.in_queue,
+ in_queue = relation(PolicyQueue,
+ primaryjoin=(self.tbl_changes.c.in_queue==self.tbl_policy_queue.c.id)),
+ approved_for_id = self.tbl_changes.c.approved_for))
+
+ mapper(ChangePendingBinary, self.tbl_changes_pending_binaries,
+ properties = dict(change_pending_binary_id = self.tbl_changes_pending_binaries.c.id))
mapper(ChangePendingFile, self.tbl_changes_pending_files,
- properties = dict(change_pending_file_id = self.tbl_changes_pending_files.c.id))
+ properties = dict(change_pending_file_id = self.tbl_changes_pending_files.c.id,
+ filename = self.tbl_changes_pending_files.c.filename,
+ size = self.tbl_changes_pending_files.c.size,
+ md5sum = self.tbl_changes_pending_files.c.md5sum,
+ sha1sum = self.tbl_changes_pending_files.c.sha1sum,
+ sha256sum = self.tbl_changes_pending_files.c.sha256sum))
mapper(ChangePendingSource, self.tbl_changes_pending_source,
properties = dict(change_pending_source_id = self.tbl_changes_pending_source.c.id,
- change = relation(KnownChange),
+ change = relation(DBChange),
maintainer = relation(Maintainer,
primaryjoin=(self.tbl_changes_pending_source.c.maintainer_id==self.tbl_maintainer.c.id)),
changedby = relation(Maintainer,
secondary=self.tbl_changes_pending_source_files,
backref="pending_sources")))
+
mapper(KeyringACLMap, self.tbl_keyring_acl_map,
properties = dict(keyring_acl_map_id = self.tbl_keyring_acl_map.c.id,
keyring = relation(Keyring, backref="keyring_acl_map"),
mapper(Override, self.tbl_override,
properties = dict(suite_id = self.tbl_override.c.suite,
suite = relation(Suite),
+ package = self.tbl_override.c.package,
component_id = self.tbl_override.c.component,
component = relation(Component),
priority_id = self.tbl_override.c.priority,
properties = dict(priority_id = self.tbl_priority.c.id))
mapper(Section, self.tbl_section,
- properties = dict(section_id = self.tbl_section.c.id))
+ properties = dict(section_id = self.tbl_section.c.id,
+ section=self.tbl_section.c.section))
mapper(DBSource, self.tbl_source,
properties = dict(source_id = self.tbl_source.c.id,