5 @contact: Debian FTPMaster <ftpmaster@debian.org>
6 @copyright: 2000, 2001, 2002, 2003, 2004, 2006 James Troup <james@nocrew.org>
7 @copyright: 2008-2009 Mark Hymers <mhy@debian.org>
8 @copyright: 2009 Joerg Jaspert <joerg@debian.org>
9 @copyright: 2009 Mike O'Connor <stew@debian.org>
10 @license: GNU General Public License version 2 or later
13 # This program is free software; you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation; either version 2 of the License, or
16 # (at your option) any later version.
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 ################################################################################
29 # < mhy> I need a funny comment
30 # < sgran> two peanuts were walking down a dark street
31 # < sgran> one was a-salted
32 # * mhy looks up the definition of "funny"
34 ################################################################################
40 from sqlalchemy import create_engine, Table, MetaData, select
41 from sqlalchemy.orm import sessionmaker, mapper, relation
43 # Don't remove this, we re-export the exceptions to scripts which import us
44 from sqlalchemy.exc import *
46 from singleton import Singleton
47 from textutils import fix_maintainer
49 ################################################################################
51 __all__ = ['IntegrityError', 'SQLAlchemyError']
53 ################################################################################
55 class Architecture(object):
56 def __init__(self, *args, **kwargs):
60 return '<Architecture %s>' % self.arch_string
62 __all__.append('Architecture')
64 def get_architecture(architecture, session=None):
66 Returns database id for given C{architecture}.
68 @type architecture: string
69 @param architecture: The name of the architecture
71 @type session: Session
72 @param session: Optional SQLA session object (a temporary one will be
73 generated if not supplied)
76 @return: Architecture object for the given arch (None if not present)
80 session = DBConn().session()
81 q = session.query(Architecture).filter_by(arch_string=architecture)
86 __all__.append('get_architecture')
88 def get_architecture_suites(architecture, session=None):
90 Returns list of Suite objects for given C{architecture} name
93 @param source: Architecture name to search for
95 @type session: Session
96 @param session: Optional SQL session object (a temporary one will be
97 generated if not supplied)
100 @return: list of Suite objects for the given name (may be empty)
104 session = DBConn().session()
106 q = session.query(Suite)
107 q = q.join(SuiteArchitecture)
108 q = q.join(Architecture).filter_by(arch_string=architecture).order_by('suite_name')
111 __all__.append('get_architecture_suites')
113 ################################################################################
115 class Archive(object):
116 def __init__(self, *args, **kwargs):
120 return '<Archive %s>' % self.name
122 __all__.append('Archive')
124 def get_archive(archive, session=None):
126 returns database id for given c{archive}.
128 @type archive: string
129 @param archive: the name of the arhive
131 @type session: Session
132 @param session: Optional SQLA session object (a temporary one will be
133 generated if not supplied)
136 @return: Archive object for the given name (None if not present)
139 archive = archive.lower()
141 session = DBConn().session()
142 q = session.query(Archive).filter_by(archive_name=archive)
147 __all__.append('get_archive')
149 ################################################################################
151 class BinAssociation(object):
152 def __init__(self, *args, **kwargs):
156 return '<BinAssociation %s (%s, %s)>' % (self.ba_id, self.binary, self.suite)
158 __all__.append('BinAssociation')
160 ################################################################################
162 class DBBinary(object):
163 def __init__(self, *args, **kwargs):
167 return '<DBBinary %s (%s, %s)>' % (self.package, self.version, self.architecture)
169 __all__.append('DBBinary')
171 def get_binary_from_id(id, session=None):
173 Returns DBBinary object for given C{id}
176 @param id: Id of the required binary
178 @type session: Session
179 @param session: Optional SQLA session object (a temporary one will be
180 generated if not supplied)
183 @return: DBBinary object for the given binary (None if not present)
186 session = DBConn().session()
187 q = session.query(DBBinary).filter_by(binary_id=id)
192 __all__.append('get_binary_from_id')
194 def get_binaries_from_name(package, session=None):
196 Returns list of DBBinary objects for given C{package} name
199 @param package: DBBinary package name to search for
201 @type session: Session
202 @param session: Optional SQL session object (a temporary one will be
203 generated if not supplied)
206 @return: list of DBBinary objects for the given name (may be empty)
209 session = DBConn().session()
210 return session.query(DBBinary).filter_by(package=package).all()
212 __all__.append('get_binaries_from_name')
214 def get_binary_components(package, suitename, arch, session=None):
215 # Check for packages that have moved from one component to another
216 query = """SELECT c.name FROM binaries b, bin_associations ba, suite s, location l, component c, architecture a, files f
217 WHERE b.package=:package AND s.suite_name=:suitename
218 AND (a.arch_string = :arch OR a.arch_string = 'all')
219 AND ba.bin = b.id AND ba.suite = s.id AND b.architecture = a.id
220 AND f.location = l.id
221 AND l.component = c.id
224 vals = {'package': package, 'suitename': suitename, 'arch': arch}
227 session = DBConn().session()
228 return session.execute(query, vals)
230 __all__.append('get_binary_components')
231 ################################################################################
233 class Component(object):
234 def __init__(self, *args, **kwargs):
238 return '<Component %s>' % self.component_name
241 __all__.append('Component')
243 def get_component(component, session=None):
245 Returns database id for given C{component}.
247 @type component: string
248 @param component: The name of the override type
251 @return: the database id for the given component
254 component = component.lower()
256 session = DBConn().session()
257 q = session.query(Component).filter_by(component_name=component)
262 __all__.append('get_component')
264 ################################################################################
266 class DBConfig(object):
267 def __init__(self, *args, **kwargs):
271 return '<DBConfig %s>' % self.name
273 __all__.append('DBConfig')
275 ################################################################################
277 class ContentFilename(object):
278 def __init__(self, *args, **kwargs):
282 return '<ContentFilename %s>' % self.filename
284 __all__.append('ContentFilename')
286 def get_or_set_contents_file_id(filename, session=None):
288 Returns database id for given filename.
290 If no matching file is found, a row is inserted.
292 @type filename: string
293 @param filename: The filename
294 @type session: SQLAlchemy
295 @param session: Optional SQL session object (a temporary one will be
296 generated if not supplied)
299 @return: the database id for the given component
302 session = DBConn().session()
305 q = session.query(ContentFilename).filter_by(filename=filename)
307 cf = ContentFilename()
308 cf.filename = filename
310 return cf.cafilename_id
312 return q.one().cafilename_id
315 traceback.print_exc()
318 __all__.append('get_or_set_contents_file_id')
320 ################################################################################
322 class ContentFilepath(object):
323 def __init__(self, *args, **kwargs):
327 return '<ContentFilepath %s>' % self.filepath
329 __all__.append('ContentFilepath')
331 def get_or_set_contents_path_id(filepath, session):
333 Returns database id for given path.
335 If no matching file is found, a row is inserted.
337 @type filename: string
338 @param filename: The filepath
339 @type session: SQLAlchemy
340 @param session: Optional SQL session object (a temporary one will be
341 generated if not supplied)
344 @return: the database id for the given path
347 session = DBConn().session()
350 q = session.query(ContentFilepath).filter_by(filepath=filepath)
352 cf = ContentFilepath()
353 cf.filepath = filepath
355 return cf.cafilepath_id
357 return q.one().cafilepath_id
360 traceback.print_exc()
363 __all__.append('get_or_set_contents_path_id')
365 ################################################################################
367 class ContentAssociation(object):
368 def __init__(self, *args, **kwargs):
372 return '<ContentAssociation %s>' % self.ca_id
374 __all__.append('ContentAssociation')
376 def insert_content_paths(binary_id, fullpaths, session=None):
378 Make sure given path is associated with given binary id
381 @param binary_id: the id of the binary
382 @type fullpaths: list
383 @param fullpaths: the list of paths of the file being associated with the binary
384 @type session: SQLAlchemy session
385 @param session: Optional SQLAlchemy session. If this is passed, the caller
386 is responsible for ensuring a transaction has begun and committing the
387 results or rolling back based on the result code. If not passed, a commit
388 will be performed at the end of the function
390 @return: True upon success
396 session = DBConn().session()
400 for fullpath in fullpaths:
401 (path, file) = os.path.split(fullpath)
403 # Get the necessary IDs ...
404 ca = ContentAssociation()
405 ca.binary_id = binary_id
406 ca.filename_id = get_or_set_contents_file_id(file)
407 ca.filepath_id = get_or_set_contents_path_id(path)
410 # Only commit if we set up the session ourself
416 traceback.print_exc()
418 # Only rollback if we set up the session ourself
424 __all__.append('insert_content_paths')
426 ################################################################################
428 class DSCFile(object):
429 def __init__(self, *args, **kwargs):
433 return '<DSCFile %s>' % self.dscfile_id
435 __all__.append('DSCFile')
437 ################################################################################
439 class PoolFile(object):
440 def __init__(self, *args, **kwargs):
444 return '<PoolFile %s>' % self.filename
446 __all__.append('PoolFile')
448 def get_poolfile_by_name(filename, location_id=None, session=None):
450 Returns an array of PoolFile objects for the given filename and
451 (optionally) location_id
453 @type filename: string
454 @param filename: the filename of the file to check against the DB
456 @type location_id: int
457 @param location_id: the id of the location to look in (optional)
460 @return: array of PoolFile objects
463 if session is not None:
464 session = DBConn().session()
466 q = session.query(PoolFile).filter_by(filename=filename)
468 if location_id is not None:
469 q = q.join(Location).filter_by(location_id=location_id)
473 __all__.append('get_poolfile_by_name')
475 ################################################################################
477 class Fingerprint(object):
478 def __init__(self, *args, **kwargs):
482 return '<Fingerprint %s>' % self.fingerprint
484 __all__.append('Fingerprint')
486 ################################################################################
488 class Keyring(object):
489 def __init__(self, *args, **kwargs):
493 return '<Keyring %s>' % self.keyring_name
495 __all__.append('Keyring')
497 ################################################################################
499 class Location(object):
500 def __init__(self, *args, **kwargs):
504 return '<Location %s (%s)>' % (self.path, self.location_id)
506 __all__.append('Location')
508 def get_location(location, component=None, archive=None, session=None):
510 Returns Location object for the given combination of location, component
513 @type location: string
514 @param location: the path of the location, e.g. I{/srv/ftp.debian.org/ftp/pool/}
516 @type component: string
517 @param component: the component name (if None, no restriction applied)
519 @type archive: string
520 @param archive_id: the archive name (if None, no restriction applied)
522 @rtype: Location / None
523 @return: Either a Location object or None if one can't be found
527 session = DBConn().session()
529 q = session.query(Location).filter_by(path=location)
531 if archive is not None:
532 q = q.join(Archive).filter_by(archive_name=archive)
534 if component is not None:
535 q = q.join(Component).filter_by(component_name=component)
542 __all__.append('get_location')
544 ################################################################################
546 class Maintainer(object):
547 def __init__(self, *args, **kwargs):
551 return '''<Maintainer '%s' (%s)>''' % (self.name, self.maintainer_id)
553 def get_split_maintainer(self):
554 if not hasattr(self, 'name') or self.name is None:
555 return ('', '', '', '')
557 return fix_maintainer(self.name.strip())
559 __all__.append('Maintainer')
561 ################################################################################
563 class Override(object):
564 def __init__(self, *args, **kwargs):
568 return '<Override %s (%s)>' % (self.package, self.suite_id)
570 __all__.append('Override')
572 ################################################################################
574 class OverrideType(object):
575 def __init__(self, *args, **kwargs):
579 return '<OverrideType %s>' % self.overridetype
581 __all__.append('OverrideType')
583 def get_override_type(override_type, session=None):
585 Returns OverrideType object for given C{override type}.
587 @type override_type: string
588 @param override_type: The name of the override type
590 @type session: Session
591 @param session: Optional SQLA session object (a temporary one will be
592 generated if not supplied)
595 @return: the database id for the given override type
599 session = DBConn().session()
600 q = session.query(OverrideType).filter_by(overridetype=override_type)
605 __all__.append('get_override_type')
607 ################################################################################
609 class PendingContentAssociation(object):
610 def __init__(self, *args, **kwargs):
614 return '<PendingContentAssociation %s>' % self.pca_id
616 __all__.append('PendingContentAssociation')
618 def insert_pending_content_paths(package, fullpaths, session=None):
620 Make sure given paths are temporarily associated with given
624 @param package: the package to associate with should have been read in from the binary control file
625 @type fullpaths: list
626 @param fullpaths: the list of paths of the file being associated with the binary
627 @type session: SQLAlchemy session
628 @param session: Optional SQLAlchemy session. If this is passed, the caller
629 is responsible for ensuring a transaction has begun and committing the
630 results or rolling back based on the result code. If not passed, a commit
631 will be performed at the end of the function
633 @return: True upon success, False if there is a problem
639 session = DBConn().session()
643 arch = get_architecture(package['Architecture'], session)
644 arch_id = arch.arch_id
646 # Remove any already existing recorded files for this package
647 q = session.query(PendingContentAssociation)
648 q = q.filter_by(package=package['Package'])
649 q = q.filter_by(version=package['Version'])
650 q = q.filter_by(architecture=arch_id)
654 for fullpath in fullpaths:
655 (path, file) = os.path.split(fullpath)
657 if path.startswith( "./" ):
660 pca = PendingContentAssociation()
661 pca.package = package['Package']
662 pca.version = package['Version']
663 pca.filename_id = get_or_set_contents_file_id(file, session)
664 pca.filepath_id = get_or_set_contents_path_id(path, session)
665 pca.architecture = arch_id
668 # Only commit if we set up the session ourself
674 traceback.print_exc()
676 # Only rollback if we set up the session ourself
682 __all__.append('insert_pending_content_paths')
684 ################################################################################
686 class Priority(object):
687 def __init__(self, *args, **kwargs):
691 return '<Priority %s (%s)>' % (self.priority, self.priority_id)
693 __all__.append('Priority')
695 def get_priority(priority, session=None):
697 Returns Priority object for given C{priority name}.
699 @type priority: string
700 @param priority: The name of the priority
702 @type session: Session
703 @param session: Optional SQLA session object (a temporary one will be
704 generated if not supplied)
707 @return: Priority object for the given priority
711 session = DBConn().session()
712 q = session.query(Priority).filter_by(priority=priority)
717 __all__.append('get_priority')
719 ################################################################################
722 def __init__(self, *args, **kwargs):
726 return '<Queue %s>' % self.queue_name
728 __all__.append('Queue')
730 ################################################################################
732 class QueueBuild(object):
733 def __init__(self, *args, **kwargs):
737 return '<QueueBuild %s (%s)>' % (self.filename, self.queue_id)
739 __all__.append('QueueBuild')
741 ################################################################################
743 class Section(object):
744 def __init__(self, *args, **kwargs):
748 return '<Section %s>' % self.section
750 __all__.append('Section')
752 def get_section(section, session=None):
754 Returns Section object for given C{section name}.
756 @type section: string
757 @param section: The name of the section
759 @type session: Session
760 @param session: Optional SQLA session object (a temporary one will be
761 generated if not supplied)
764 @return: Section object for the given section name
768 session = DBConn().session()
769 q = session.query(Section).filter_by(section=section)
774 __all__.append('get_section')
776 ################################################################################
778 class DBSource(object):
779 def __init__(self, *args, **kwargs):
783 return '<DBSource %s (%s)>' % (self.source, self.version)
785 __all__.append('DBSource')
787 def get_sources_from_name(source, dm_upload_allowed=None, session=None):
789 Returns list of DBSource objects for given C{source} name
792 @param source: DBSource package name to search for
794 @type dm_upload_allowed: bool
795 @param dm_upload_allowed: If None, no effect. If True or False, only
796 return packages with that dm_upload_allowed setting
798 @type session: Session
799 @param session: Optional SQL session object (a temporary one will be
800 generated if not supplied)
803 @return: list of DBSource objects for the given name (may be empty)
806 session = DBConn().session()
808 q = session.query(DBSource).filter_by(source=source)
809 if dm_upload_allowed is not None:
810 q = q.filter_by(dm_upload_allowed=dm_upload_allowed)
814 __all__.append('get_sources_from_name')
816 def get_source_in_suite(source, suite, session=None):
818 Returns list of DBSource objects for a combination of C{source} and C{suite}.
820 - B{source} - source package name, eg. I{mailfilter}, I{bbdb}, I{glibc}
821 - B{suite} - a suite name, eg. I{unstable}
824 @param source: source package name
827 @param suite: the suite name
830 @return: the version for I{source} in I{suite}
834 session = DBConn().session()
835 q = session.query(SrcAssociation)
836 q = q.join('source').filter_by(source=source)
837 q = q.join('suite').filter_by(suite_name=suite)
840 # ???: Maybe we should just return the SrcAssociation object instead
841 return q.one().source
843 __all__.append('get_source_in_suite')
845 ################################################################################
847 class SrcAssociation(object):
848 def __init__(self, *args, **kwargs):
852 return '<SrcAssociation %s (%s, %s)>' % (self.sa_id, self.source, self.suite)
854 __all__.append('SrcAssociation')
856 ################################################################################
858 class SrcUploader(object):
859 def __init__(self, *args, **kwargs):
863 return '<SrcUploader %s>' % self.uploader_id
865 __all__.append('SrcUploader')
867 ################################################################################
870 def __init__(self, *args, **kwargs):
874 return '<Suite %s>' % self.suite_name
876 __all__.append('Suite')
878 def get_suite_architecture(suite, architecture, session=None):
880 Returns a SuiteArchitecture object given C{suite} and ${arch} or None if it
884 @param suite: Suite name to search for
886 @type architecture: str
887 @param architecture: Architecture name to search for
889 @type session: Session
890 @param session: Optional SQL session object (a temporary one will be
891 generated if not supplied)
893 @rtype: SuiteArchitecture
894 @return: the SuiteArchitecture object or None
898 session = DBConn().session()
900 q = session.query(SuiteArchitecture)
901 q = q.join(Architecture).filter_by(arch_string=architecture)
902 q = q.join(Suite).filter_by(suite_name=suite)
907 __all__.append('get_suite_architecture')
909 def get_suite(suite, session=None):
911 Returns Suite object for given C{suite name}.
914 @param suite: The name of the suite
916 @type session: Session
917 @param session: Optional SQLA session object (a temporary one will be
918 generated if not supplied)
921 @return: Suite object for the requested suite name (None if not presenT)
925 session = DBConn().session()
926 q = session.query(Suite).filter_by(suite_name=suite)
931 __all__.append('get_suite')
933 ################################################################################
935 class SuiteArchitecture(object):
936 def __init__(self, *args, **kwargs):
940 return '<SuiteArchitecture (%s, %s)>' % (self.suite_id, self.arch_id)
942 __all__.append('SuiteArchitecture')
944 def get_suite_architectures(suite, skipsrc=False, skipall=False, session=None):
946 Returns list of Architecture objects for given C{suite} name
949 @param source: Suite name to search for
951 @type skipsrc: boolean
952 @param skipsrc: Whether to skip returning the 'source' architecture entry
955 @type skipall: boolean
956 @param skipall: Whether to skip returning the 'all' architecture entry
959 @type session: Session
960 @param session: Optional SQL session object (a temporary one will be
961 generated if not supplied)
964 @return: list of Architecture objects for the given name (may be empty)
968 session = DBConn().session()
970 q = session.query(Architecture)
971 q = q.join(SuiteArchitecture)
972 q = q.join(Suite).filter_by(suite_name=suite)
974 q = q.filter(Architecture.arch_string != 'source')
976 q = q.filter(Architecture.arch_string != 'all')
977 q = q.order_by('arch_string')
980 __all__.append('get_suite_architectures')
982 ################################################################################
985 def __init__(self, *args, **kwargs):
989 return '<Uid %s (%s)>' % (self.uid, self.name)
991 __all__.append('Uid')
993 def get_uid_from_fingerprint(fpr, session=None):
995 session = DBConn().session()
997 q = session.query(Uid)
998 q = q.join(Fingerprint).filter_by(fingerprint=fpr)
1005 __all__.append('get_uid_from_fingerprint')
1007 ################################################################################
1009 class DBConn(Singleton):
1011 database module init.
1013 def __init__(self, *args, **kwargs):
1014 super(DBConn, self).__init__(*args, **kwargs)
1016 def _startup(self, *args, **kwargs):
1018 if kwargs.has_key('debug'):
1022 def __setuptables(self):
1023 self.tbl_architecture = Table('architecture', self.db_meta, autoload=True)
1024 self.tbl_archive = Table('archive', self.db_meta, autoload=True)
1025 self.tbl_bin_associations = Table('bin_associations', self.db_meta, autoload=True)
1026 self.tbl_binaries = Table('binaries', self.db_meta, autoload=True)
1027 self.tbl_component = Table('component', self.db_meta, autoload=True)
1028 self.tbl_config = Table('config', self.db_meta, autoload=True)
1029 self.tbl_content_associations = Table('content_associations', self.db_meta, autoload=True)
1030 self.tbl_content_file_names = Table('content_file_names', self.db_meta, autoload=True)
1031 self.tbl_content_file_paths = Table('content_file_paths', self.db_meta, autoload=True)
1032 self.tbl_dsc_files = Table('dsc_files', self.db_meta, autoload=True)
1033 self.tbl_files = Table('files', self.db_meta, autoload=True)
1034 self.tbl_fingerprint = Table('fingerprint', self.db_meta, autoload=True)
1035 self.tbl_keyrings = Table('keyrings', self.db_meta, autoload=True)
1036 self.tbl_location = Table('location', self.db_meta, autoload=True)
1037 self.tbl_maintainer = Table('maintainer', self.db_meta, autoload=True)
1038 self.tbl_override = Table('override', self.db_meta, autoload=True)
1039 self.tbl_override_type = Table('override_type', self.db_meta, autoload=True)
1040 self.tbl_pending_content_associations = Table('pending_content_associations', self.db_meta, autoload=True)
1041 self.tbl_priority = Table('priority', self.db_meta, autoload=True)
1042 self.tbl_queue = Table('queue', self.db_meta, autoload=True)
1043 self.tbl_queue_build = Table('queue_build', self.db_meta, autoload=True)
1044 self.tbl_section = Table('section', self.db_meta, autoload=True)
1045 self.tbl_source = Table('source', self.db_meta, autoload=True)
1046 self.tbl_src_associations = Table('src_associations', self.db_meta, autoload=True)
1047 self.tbl_src_uploaders = Table('src_uploaders', self.db_meta, autoload=True)
1048 self.tbl_suite = Table('suite', self.db_meta, autoload=True)
1049 self.tbl_suite_architectures = Table('suite_architectures', self.db_meta, autoload=True)
1050 self.tbl_uid = Table('uid', self.db_meta, autoload=True)
1052 def __setupmappers(self):
1053 mapper(Architecture, self.tbl_architecture,
1054 properties = dict(arch_id = self.tbl_architecture.c.id))
1056 mapper(Archive, self.tbl_archive,
1057 properties = dict(archive_id = self.tbl_archive.c.id,
1058 archive_name = self.tbl_archive.c.name))
1060 mapper(BinAssociation, self.tbl_bin_associations,
1061 properties = dict(ba_id = self.tbl_bin_associations.c.id,
1062 suite_id = self.tbl_bin_associations.c.suite,
1063 suite = relation(Suite),
1064 binary_id = self.tbl_bin_associations.c.bin,
1065 binary = relation(DBBinary)))
1067 mapper(DBBinary, self.tbl_binaries,
1068 properties = dict(binary_id = self.tbl_binaries.c.id,
1069 package = self.tbl_binaries.c.package,
1070 version = self.tbl_binaries.c.version,
1071 maintainer_id = self.tbl_binaries.c.maintainer,
1072 maintainer = relation(Maintainer),
1073 source_id = self.tbl_binaries.c.source,
1074 source = relation(DBSource),
1075 arch_id = self.tbl_binaries.c.architecture,
1076 architecture = relation(Architecture),
1077 poolfile_id = self.tbl_binaries.c.file,
1078 poolfile = relation(PoolFile),
1079 binarytype = self.tbl_binaries.c.type,
1080 fingerprint_id = self.tbl_binaries.c.sig_fpr,
1081 fingerprint = relation(Fingerprint),
1082 install_date = self.tbl_binaries.c.install_date,
1083 binassociations = relation(BinAssociation,
1084 primaryjoin=(self.tbl_binaries.c.id==self.tbl_bin_associations.c.bin))))
1086 mapper(Component, self.tbl_component,
1087 properties = dict(component_id = self.tbl_component.c.id,
1088 component_name = self.tbl_component.c.name))
1090 mapper(DBConfig, self.tbl_config,
1091 properties = dict(config_id = self.tbl_config.c.id))
1093 mapper(ContentAssociation, self.tbl_content_associations,
1094 properties = dict(ca_id = self.tbl_content_associations.c.id,
1095 filename_id = self.tbl_content_associations.c.filename,
1096 filename = relation(ContentFilename),
1097 filepath_id = self.tbl_content_associations.c.filepath,
1098 filepath = relation(ContentFilepath),
1099 binary_id = self.tbl_content_associations.c.binary_pkg,
1100 binary = relation(DBBinary)))
1103 mapper(ContentFilename, self.tbl_content_file_names,
1104 properties = dict(cafilename_id = self.tbl_content_file_names.c.id,
1105 filename = self.tbl_content_file_names.c.file))
1107 mapper(ContentFilepath, self.tbl_content_file_paths,
1108 properties = dict(cafilepath_id = self.tbl_content_file_paths.c.id,
1109 filepath = self.tbl_content_file_paths.c.path))
1111 mapper(DSCFile, self.tbl_dsc_files,
1112 properties = dict(dscfile_id = self.tbl_dsc_files.c.id,
1113 source_id = self.tbl_dsc_files.c.source,
1114 source = relation(DBSource),
1115 poolfile_id = self.tbl_dsc_files.c.file,
1116 poolfile = relation(PoolFile)))
1118 mapper(PoolFile, self.tbl_files,
1119 properties = dict(file_id = self.tbl_files.c.id,
1120 filesize = self.tbl_files.c.size,
1121 location_id = self.tbl_files.c.location,
1122 location = relation(Location)))
1124 mapper(Fingerprint, self.tbl_fingerprint,
1125 properties = dict(fingerprint_id = self.tbl_fingerprint.c.id,
1126 uid_id = self.tbl_fingerprint.c.uid,
1127 uid = relation(Uid),
1128 keyring_id = self.tbl_fingerprint.c.keyring,
1129 keyring = relation(Keyring)))
1131 mapper(Keyring, self.tbl_keyrings,
1132 properties = dict(keyring_name = self.tbl_keyrings.c.name,
1133 keyring_id = self.tbl_keyrings.c.id))
1135 mapper(Location, self.tbl_location,
1136 properties = dict(location_id = self.tbl_location.c.id,
1137 component_id = self.tbl_location.c.component,
1138 component = relation(Component),
1139 archive_id = self.tbl_location.c.archive,
1140 archive = relation(Archive),
1141 archive_type = self.tbl_location.c.type))
1143 mapper(Maintainer, self.tbl_maintainer,
1144 properties = dict(maintainer_id = self.tbl_maintainer.c.id))
1146 mapper(Override, self.tbl_override,
1147 properties = dict(suite_id = self.tbl_override.c.suite,
1148 suite = relation(Suite),
1149 component_id = self.tbl_override.c.component,
1150 component = relation(Component),
1151 priority_id = self.tbl_override.c.priority,
1152 priority = relation(Priority),
1153 section_id = self.tbl_override.c.section,
1154 section = relation(Section),
1155 overridetype_id = self.tbl_override.c.type,
1156 overridetype = relation(OverrideType)))
1158 mapper(OverrideType, self.tbl_override_type,
1159 properties = dict(overridetype = self.tbl_override_type.c.type,
1160 overridetype_id = self.tbl_override_type.c.id))
1162 mapper(PendingContentAssociation, self.tbl_pending_content_associations,
1163 properties = dict(pca_id = self.tbl_pending_content_associations.c.id,
1164 filepath_id = self.tbl_pending_content_associations.c.filepath,
1165 filepath = relation(ContentFilepath),
1166 filename_id = self.tbl_pending_content_associations.c.filename,
1167 filename = relation(ContentFilename)))
1169 mapper(Priority, self.tbl_priority,
1170 properties = dict(priority_id = self.tbl_priority.c.id))
1172 mapper(Queue, self.tbl_queue,
1173 properties = dict(queue_id = self.tbl_queue.c.id))
1175 mapper(QueueBuild, self.tbl_queue_build,
1176 properties = dict(suite_id = self.tbl_queue_build.c.suite,
1177 queue_id = self.tbl_queue_build.c.queue,
1178 queue = relation(Queue)))
1180 mapper(Section, self.tbl_section,
1181 properties = dict(section_id = self.tbl_section.c.id))
1183 mapper(DBSource, self.tbl_source,
1184 properties = dict(source_id = self.tbl_source.c.id,
1185 version = self.tbl_source.c.version,
1186 maintainer_id = self.tbl_source.c.maintainer,
1187 maintainer = relation(Maintainer,
1188 primaryjoin=(self.tbl_source.c.maintainer==self.tbl_maintainer.c.id)),
1189 poolfile_id = self.tbl_source.c.file,
1190 poolfile = relation(PoolFile),
1191 fingerprint_id = self.tbl_source.c.sig_fpr,
1192 fingerprint = relation(Fingerprint),
1193 changedby_id = self.tbl_source.c.changedby,
1194 changedby = relation(Maintainer,
1195 primaryjoin=(self.tbl_source.c.changedby==self.tbl_maintainer.c.id)),
1196 srcfiles = relation(DSCFile,
1197 primaryjoin=(self.tbl_source.c.id==self.tbl_dsc_files.c.source)),
1198 srcassociations = relation(SrcAssociation,
1199 primaryjoin=(self.tbl_source.c.id==self.tbl_src_associations.c.source))))
1201 mapper(SrcAssociation, self.tbl_src_associations,
1202 properties = dict(sa_id = self.tbl_src_associations.c.id,
1203 suite_id = self.tbl_src_associations.c.suite,
1204 suite = relation(Suite),
1205 source_id = self.tbl_src_associations.c.source,
1206 source = relation(DBSource)))
1208 mapper(SrcUploader, self.tbl_src_uploaders,
1209 properties = dict(uploader_id = self.tbl_src_uploaders.c.id,
1210 source_id = self.tbl_src_uploaders.c.source,
1211 source = relation(DBSource,
1212 primaryjoin=(self.tbl_src_uploaders.c.source==self.tbl_source.c.id)),
1213 maintainer_id = self.tbl_src_uploaders.c.maintainer,
1214 maintainer = relation(Maintainer,
1215 primaryjoin=(self.tbl_src_uploaders.c.maintainer==self.tbl_maintainer.c.id))))
1217 mapper(Suite, self.tbl_suite,
1218 properties = dict(suite_id = self.tbl_suite.c.id))
1220 mapper(SuiteArchitecture, self.tbl_suite_architectures,
1221 properties = dict(suite_id = self.tbl_suite_architectures.c.suite,
1222 suite = relation(Suite, backref='suitearchitectures'),
1223 arch_id = self.tbl_suite_architectures.c.architecture,
1224 architecture = relation(Architecture)))
1226 mapper(Uid, self.tbl_uid,
1227 properties = dict(uid_id = self.tbl_uid.c.id,
1228 fingerprint = relation(Fingerprint)))
1230 ## Connection functions
1231 def __createconn(self):
1232 from config import Config
1236 connstr = "postgres://%s" % cnf["DB::Host"]
1237 if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
1238 connstr += ":%s" % cnf["DB::Port"]
1239 connstr += "/%s" % cnf["DB::Name"]
1242 connstr = "postgres:///%s" % cnf["DB::Name"]
1243 if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
1244 connstr += "?port=%s" % cnf["DB::Port"]
1246 self.db_pg = create_engine(connstr, echo=self.debug)
1247 self.db_meta = MetaData()
1248 self.db_meta.bind = self.db_pg
1249 self.db_smaker = sessionmaker(bind=self.db_pg,
1253 self.__setuptables()
1254 self.__setupmappers()
1257 return self.db_smaker()
1259 __all__.append('DBConn')