import sqlalchemy
from sqlalchemy import create_engine, Table, MetaData, Column, Integer
-from sqlalchemy.orm import sessionmaker, mapper, relation
+from sqlalchemy.orm import sessionmaker, mapper, relation, object_session, backref
from sqlalchemy import types as sqltypes
# Don't remove this, we re-export the exceptions to scripts which import us
from textutils import fix_maintainer
from dak_exceptions import NoSourceFieldError
+# suppress some deprecation warnings in squeeze related to sqlalchemy
+import warnings
+warnings.filterwarnings('ignore', \
+ "The SQLAlchemy PostgreSQL dialect has been renamed from 'postgres' to 'postgresql'.*", \
+ SADeprecationWarning)
+# TODO: sqlalchemy needs some extra configuration to correctly reflect
+# the ind_deb_contents_* indexes - we ignore the warnings at the moment
+warnings.filterwarnings("ignore", 'Predicate of partial index', SAWarning)
+
+
################################################################################
# Patch in support for the debversion field type so that it works during
################################################################################
class Architecture(object):
- def __init__(self, *args, **kwargs):
- pass
+ def __init__(self, arch_string = None, description = None):
+ self.arch_string = arch_string
+ self.description = description
def __eq__(self, val):
if isinstance(val, str):
__all__.append('get_architecture')
+# TODO: should be removed because the implementation is too trivial
@session_wrapper
def get_architecture_suites(architecture, session=None):
"""
@return: list of Suite objects for the given name (may be empty)
"""
- q = session.query(Suite)
- q = q.join(SuiteArchitecture)
- q = q.join(Architecture).filter_by(arch_string=architecture).order_by('suite_name')
-
- ret = q.all()
-
- return ret
+ return get_architecture(architecture, session).suites
__all__.append('get_architecture_suites')
################################################################################
class PoolFile(object):
- def __init__(self, *args, **kwargs):
- pass
+ def __init__(self, filename = None, location = None, filesize = -1, \
+ md5sum = None):
+ self.filename = filename
+ self.location = location
+ self.filesize = filesize
+ self.md5sum = md5sum
def __repr__(self):
return '<PoolFile %s>' % self.filename
def fullpath(self):
return os.path.join(self.location.path, self.filename)
+ def is_valid(self, filesize = -1, md5sum = None):\
+ return self.filesize == filesize and self.md5sum == md5sum
+
__all__.append('PoolFile')
@session_wrapper
def check_poolfile(filename, filesize, md5sum, location_id, session=None):
"""
Returns a tuple:
- (ValidFileFound [boolean or None], PoolFile object or None)
+ (ValidFileFound [boolean], PoolFile object or None)
@type filename: string
@param filename: the filename of the file to check against the DB
@rtype: tuple
@return: Tuple of length 2.
- - If more than one file found with that name: (C{None}, C{None})
- If valid pool file found: (C{True}, C{PoolFile object})
- If valid pool file not found:
- (C{False}, C{None}) if no file found
- (C{False}, C{PoolFile object}) if file found with size/md5sum mismatch
"""
- q = session.query(PoolFile).filter_by(filename=filename)
- q = q.join(Location).filter_by(location_id=location_id)
+ poolfile = session.query(Location).get(location_id). \
+ files.filter_by(filename=filename).first()
+ valid = False
+ if poolfile and poolfile.is_valid(filesize = filesize, md5sum = md5sum):
+ valid = True
- 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 != int(filesize):
- ret = (False, obj)
-
- if ret is None:
- ret = (True, obj)
-
- return ret
+ return (valid, poolfile)
__all__.append('check_poolfile')
+# TODO: the implementation can trivially be inlined at the place where the
+# function is called
@session_wrapper
def get_poolfile_by_id(file_id, session=None):
"""
@return: either the PoolFile object or None
"""
- q = session.query(PoolFile).filter_by(file_id=file_id)
-
- try:
- return q.one()
- except NoResultFound:
- return None
+ return session.query(PoolFile).get(file_id)
__all__.append('get_poolfile_by_id')
-
-@session_wrapper
-def get_poolfile_by_name(filename, location_id=None, session=None):
- """
- Returns an array of PoolFile objects for the given filename and
- (optionally) location_id
-
- @type filename: string
- @param filename: the filename of the file to check against the DB
-
- @type location_id: int
- @param location_id: the id of the location to look in (optional)
-
- @rtype: array
- @return: array of PoolFile objects
- """
-
- q = session.query(PoolFile).filter_by(filename=filename)
-
- if location_id is not None:
- q = q.join(Location).filter_by(location_id=location_id)
-
- return q.all()
-
-__all__.append('get_poolfile_by_name')
-
@session_wrapper
def get_poolfile_like_name(filename, session=None):
"""
################################################################################
class Fingerprint(object):
- def __init__(self, *args, **kwargs):
- pass
+ def __init__(self, fingerprint = None):
+ self.fingerprint = fingerprint
def __repr__(self):
return '<Fingerprint %s>' % self.fingerprint
################################################################################
class Location(object):
- def __init__(self, *args, **kwargs):
- pass
+ def __init__(self, path = None):
+ self.path = path
+ # the column 'type' should go away, see comment at mapper
+ self.archive_type = 'pool'
def __repr__(self):
return '<Location %s (%s)>' % (self.path, self.location_id)
################################################################################
class Maintainer(object):
- def __init__(self, *args, **kwargs):
- pass
+ def __init__(self, name = None):
+ self.name = name
def __repr__(self):
return '''<Maintainer '%s' (%s)>''' % (self.name, self.maintainer_id)
################################################################################
class DBSource(object):
- def __init__(self, *args, **kwargs):
- pass
+ def __init__(self, maintainer = None, changedby = None):
+ self.maintainer = maintainer
+ self.changedby = changedby
def __repr__(self):
return '<DBSource %s (%s)>' % (self.source, self.version)
('OverrideSuite', 'overridesuite')]
class Suite(object):
- def __init__(self, *args, **kwargs):
- pass
+ def __init__(self, suite_name = None, version = None):
+ self.suite_name = suite_name
+ self.version = version
def __repr__(self):
return '<Suite %s>' % self.suite_name
return "\n".join(ret)
-__all__.append('Suite')
-
-@session_wrapper
-def get_suite_architecture(suite, architecture, session=None):
- """
- Returns a SuiteArchitecture object given C{suite} and ${arch} or None if it
- doesn't exist
-
- @type suite: str
- @param suite: Suite name to search for
+ def get_architectures(self, skipsrc=False, skipall=False):
+ """
+ Returns list of Architecture objects
- @type architecture: str
- @param architecture: Architecture name to search for
+ @type skipsrc: boolean
+ @param skipsrc: Whether to skip returning the 'source' architecture entry
+ (Default False)
- @type session: Session
- @param session: Optional SQL session object (a temporary one will be
- generated if not supplied)
+ @type skipall: boolean
+ @param skipall: Whether to skip returning the 'all' architecture entry
+ (Default False)
- @rtype: SuiteArchitecture
- @return: the SuiteArchitecture object or None
- """
+ @rtype: list
+ @return: list of Architecture objects for the given name (may be empty)
+ """
- q = session.query(SuiteArchitecture)
- q = q.join(Architecture).filter_by(arch_string=architecture)
- q = q.join(Suite).filter_by(suite_name=suite)
+ q = object_session(self).query(Architecture). \
+ filter(Architecture.suites.contains(self))
+ if skipsrc:
+ q = q.filter(Architecture.arch_string != 'source')
+ if skipall:
+ q = q.filter(Architecture.arch_string != 'all')
+ return q.order_by(Architecture.arch_string).all()
- try:
- return q.one()
- except NoResultFound:
- return None
-
-__all__.append('get_suite_architecture')
+__all__.append('Suite')
@session_wrapper
def get_suite(suite, session=None):
################################################################################
-class SuiteArchitecture(object):
- def __init__(self, *args, **kwargs):
- pass
-
- def __repr__(self):
- return '<SuiteArchitecture (%s, %s)>' % (self.suite_id, self.arch_id)
-
-__all__.append('SuiteArchitecture')
-
+# TODO: should be removed because the implementation is too trivial
@session_wrapper
def get_suite_architectures(suite, skipsrc=False, skipall=False, session=None):
"""
@return: list of Architecture objects for the given name (may be empty)
"""
- q = session.query(Architecture)
- q = q.join(SuiteArchitecture)
- q = q.join(Suite).filter_by(suite_name=suite)
-
- if skipsrc:
- q = q.filter(Architecture.arch_string != 'source')
-
- if skipall:
- q = q.filter(Architecture.arch_string != 'all')
-
- q = q.order_by('arch_string')
-
- return q.all()
+ return get_suite(suite, session).get_architectures(skipsrc, skipall)
__all__.append('get_suite_architectures')
################################################################################
class Uid(object):
- def __init__(self, *args, **kwargs):
- pass
+ def __init__(self, uid = None, name = None):
+ self.uid = uid
+ self.name = name
def __eq__(self, val):
if isinstance(val, str):
def __setupmappers(self):
mapper(Architecture, self.tbl_architecture,
- properties = dict(arch_id = self.tbl_architecture.c.id))
+ properties = dict(arch_id = self.tbl_architecture.c.id,
+ suites = relation(Suite, secondary=self.tbl_suite_architectures,
+ order_by='suite_name',
+ backref=backref('architectures', order_by='arch_string'))))
mapper(Archive, self.tbl_archive,
properties = dict(archive_id = self.tbl_archive.c.id,
properties = dict(file_id = self.tbl_files.c.id,
filesize = self.tbl_files.c.size,
location_id = self.tbl_files.c.location,
- location = relation(Location)))
+ location = relation(Location,
+ # using lazy='dynamic' in the back
+ # reference because we have A LOT of
+ # files in one location
+ backref=backref('files', lazy='dynamic'))))
mapper(Fingerprint, self.tbl_fingerprint,
properties = dict(fingerprint_id = self.tbl_fingerprint.c.id,
component = relation(Component),
archive_id = self.tbl_location.c.archive,
archive = relation(Archive),
+ # FIXME: the 'type' column is old cruft and
+ # should be removed in the future.
archive_type = self.tbl_location.c.type))
mapper(Maintainer, self.tbl_maintainer,
- properties = dict(maintainer_id = self.tbl_maintainer.c.id))
+ properties = dict(maintainer_id = self.tbl_maintainer.c.id,
+ maintains_sources = relation(DBSource, backref='maintainer',
+ primaryjoin=(self.tbl_maintainer.c.id==self.tbl_source.c.maintainer)),
+ changed_sources = relation(DBSource, backref='changedby',
+ primaryjoin=(self.tbl_maintainer.c.id==self.tbl_source.c.changedby))))
mapper(NewComment, self.tbl_new_comments,
properties = dict(comment_id = self.tbl_new_comments.c.id))
properties = dict(source_id = self.tbl_source.c.id,
version = self.tbl_source.c.version,
maintainer_id = self.tbl_source.c.maintainer,
- maintainer = relation(Maintainer,
- primaryjoin=(self.tbl_source.c.maintainer==self.tbl_maintainer.c.id)),
poolfile_id = self.tbl_source.c.file,
poolfile = relation(PoolFile),
fingerprint_id = self.tbl_source.c.sig_fpr,
fingerprint = relation(Fingerprint),
changedby_id = self.tbl_source.c.changedby,
- changedby = relation(Maintainer,
- primaryjoin=(self.tbl_source.c.changedby==self.tbl_maintainer.c.id)),
srcfiles = relation(DSCFile,
primaryjoin=(self.tbl_source.c.id==self.tbl_dsc_files.c.source)),
- srcassociations = relation(SrcAssociation,
- primaryjoin=(self.tbl_source.c.id==self.tbl_src_associations.c.source)),
+ suites = relation(Suite, secondary=self.tbl_src_associations,
+ backref='sources'),
srcuploaders = relation(SrcUploader)))
mapper(SourceACL, self.tbl_source_acl,
policy_queue = relation(PolicyQueue),
copy_queues = relation(BuildQueue, secondary=self.tbl_suite_build_queue_copy)))
- mapper(SuiteArchitecture, self.tbl_suite_architectures,
- properties = dict(suite_id = self.tbl_suite_architectures.c.suite,
- suite = relation(Suite, backref='suitearchitectures'),
- arch_id = self.tbl_suite_architectures.c.architecture,
- architecture = relation(Architecture)))
-
mapper(SuiteSrcFormat, self.tbl_suite_src_formats,
properties = dict(suite_id = self.tbl_suite_src_formats.c.suite,
suite = relation(Suite, backref='suitesrcformats'),