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
48 ################################################################################
50 __all__ = ['IntegrityError', 'SQLAlchemyError']
52 ################################################################################
54 class Architecture(object):
55 def __init__(self, *args, **kwargs):
59 return '<Architecture %s>' % self.arch_string
61 __all__.append('Architecture')
63 def get_architecture(architecture, session=None):
65 Returns database id for given C{architecture}.
67 @type architecture: string
68 @param architecture: The name of the architecture
70 @type session: Session
71 @param session: Optional SQLA session object (a temporary one will be
72 generated if not supplied)
75 @return: Architecture object for the given arch (None if not present)
79 session = DBConn().session()
80 q = session.query(Architecture).filter_by(arch_string=architecture)
85 __all__.append('get_architecture')
87 def get_architecture_suites(architecture, session=None):
89 Returns list of Suite objects for given C{architecture} name
92 @param source: Architecture name to search for
94 @type session: Session
95 @param session: Optional SQL session object (a temporary one will be
96 generated if not supplied)
99 @return: list of Suite objects for the given name (may be empty)
103 session = DBConn().session()
105 q = session.query(Suite)
106 q = q.join(SuiteArchitecture)
107 q = q.join(Architecture).filter_by(arch_string=architecture).order_by('suite_name')
110 __all__.append('get_architecture_suites')
112 ################################################################################
114 class Archive(object):
115 def __init__(self, *args, **kwargs):
119 return '<Archive %s>' % self.name
121 __all__.append('Archive')
123 def get_archive(archive, session=None):
125 returns database id for given c{archive}.
127 @type archive: string
128 @param archive: the name of the arhive
130 @type session: Session
131 @param session: Optional SQLA session object (a temporary one will be
132 generated if not supplied)
135 @return: Archive object for the given name (None if not present)
138 archive = archive.lower()
140 session = DBConn().session()
141 q = session.query(Archive).filter_by(archive_name=archive)
146 __all__.append('get_archive')
148 ################################################################################
150 class BinAssociation(object):
151 def __init__(self, *args, **kwargs):
155 return '<BinAssociation %s (%s, %s)>' % (self.ba_id, self.binary, self.suite)
157 __all__.append('BinAssociation')
159 ################################################################################
161 class DBBinary(object):
162 def __init__(self, *args, **kwargs):
166 return '<DBBinary %s (%s, %s)>' % (self.package, self.version, self.architecture)
168 __all__.append('DBBinary')
170 def get_binary_from_id(id, session=None):
172 Returns DBBinary object for given C{id}
175 @param id: Id of the required binary
177 @type session: Session
178 @param session: Optional SQLA session object (a temporary one will be
179 generated if not supplied)
182 @return: DBBinary object for the given binary (None if not present)
185 session = DBConn().session()
186 q = session.query(DBBinary).filter_by(binary_id=id)
191 __all__.append('get_binary_from_id')
193 def get_binaries_from_name(package, session=None):
195 Returns list of DBBinary objects for given C{package} name
198 @param package: DBBinary package name to search for
200 @type session: Session
201 @param session: Optional SQL session object (a temporary one will be
202 generated if not supplied)
205 @return: list of DBBinary objects for the given name (may be empty)
208 session = DBConn().session()
209 return session.query(DBBinary).filter_by(package=package).all()
211 __all__.append('get_binaries_from_name')
213 def get_binary_components(package, suitename, arch, session=None):
214 # Check for packages that have moved from one component to another
215 query = """SELECT c.name FROM binaries b, bin_associations ba, suite s, location l, component c, architecture a, files f
216 WHERE b.package=:package AND s.suite_name=:suitename
217 AND (a.arch_string = :arch OR a.arch_string = 'all')
218 AND ba.bin = b.id AND ba.suite = s.id AND b.architecture = a.id
219 AND f.location = l.id
220 AND l.component = c.id
223 vals = {'package': package, 'suitename': suitename, 'arch': arch}
226 session = DBConn().session()
227 return session.execute(query, vals)
229 __all__.append('get_binary_components')
230 ################################################################################
232 class Component(object):
233 def __init__(self, *args, **kwargs):
237 return '<Component %s>' % self.component_name
240 __all__.append('Component')
242 def get_component(component, session=None):
244 Returns database id for given C{component}.
246 @type component: string
247 @param component: The name of the override type
250 @return: the database id for the given component
253 component = component.lower()
255 session = DBConn().session()
256 q = session.query(Component).filter_by(component_name=component)
261 __all__.append('get_component')
263 ################################################################################
265 class DBConfig(object):
266 def __init__(self, *args, **kwargs):
270 return '<DBConfig %s>' % self.name
272 __all__.append('DBConfig')
274 ################################################################################
276 class ContentFilename(object):
277 def __init__(self, *args, **kwargs):
281 return '<ContentFilename %s>' % self.filename
283 __all__.append('ContentFilename')
285 def get_or_set_contents_file_id(filename, session=None):
287 Returns database id for given filename.
289 If no matching file is found, a row is inserted.
291 @type filename: string
292 @param filename: The filename
293 @type session: SQLAlchemy
294 @param session: Optional SQL session object (a temporary one will be
295 generated if not supplied)
298 @return: the database id for the given component
301 session = DBConn().session()
304 q = session.query(ContentFilename).filter_by(filename=filename)
306 cf = ContentFilename()
307 cf.filename = filename
309 return cf.cafilename_id
311 return q.one().cafilename_id
314 traceback.print_exc()
317 __all__.append('get_or_set_contents_file_id')
319 ################################################################################
321 class ContentFilepath(object):
322 def __init__(self, *args, **kwargs):
326 return '<ContentFilepath %s>' % self.filepath
328 __all__.append('ContentFilepath')
330 def get_or_set_contents_path_id(filepath, session):
332 Returns database id for given path.
334 If no matching file is found, a row is inserted.
336 @type filename: string
337 @param filename: The filepath
338 @type session: SQLAlchemy
339 @param session: Optional SQL session object (a temporary one will be
340 generated if not supplied)
343 @return: the database id for the given path
346 session = DBConn().session()
349 q = session.query(ContentFilepath).filter_by(filepath=filepath)
351 cf = ContentFilepath()
352 cf.filepath = filepath
354 return cf.cafilepath_id
356 return q.one().cafilepath_id
359 traceback.print_exc()
362 __all__.append('get_or_set_contents_path_id')
364 ################################################################################
366 class ContentAssociation(object):
367 def __init__(self, *args, **kwargs):
371 return '<ContentAssociation %s>' % self.ca_id
373 __all__.append('ContentAssociation')
375 def insert_content_paths(binary_id, fullpaths, session=None):
377 Make sure given path is associated with given binary id
380 @param binary_id: the id of the binary
381 @type fullpaths: list
382 @param fullpaths: the list of paths of the file being associated with the binary
383 @type session: SQLAlchemy session
384 @param session: Optional SQLAlchemy session. If this is passed, the caller
385 is responsible for ensuring a transaction has begun and committing the
386 results or rolling back based on the result code. If not passed, a commit
387 will be performed at the end of the function
389 @return: True upon success
395 session = DBConn().session()
399 for fullpath in fullpaths:
400 (path, file) = os.path.split(fullpath)
402 # Get the necessary IDs ...
403 ca = ContentAssociation()
404 ca.binary_id = binary_id
405 ca.filename_id = get_or_set_contents_file_id(file)
406 ca.filepath_id = get_or_set_contents_path_id(path)
409 # Only commit if we set up the session ourself
415 traceback.print_exc()
417 # Only rollback if we set up the session ourself
423 __all__.append('insert_content_paths')
425 ################################################################################
427 class DSCFile(object):
428 def __init__(self, *args, **kwargs):
432 return '<DSCFile %s>' % self.dscfile_id
434 __all__.append('DSCFile')
436 ################################################################################
438 class PoolFile(object):
439 def __init__(self, *args, **kwargs):
443 return '<PoolFile %s>' % self.filename
445 __all__.append('PoolFile')
447 def get_poolfile_by_name(filename, location_id=None, session=None):
449 Returns an array of PoolFile objects for the given filename and
450 (optionally) location_id
452 @type filename: string
453 @param filename: the filename of the file to check against the DB
455 @type location_id: int
456 @param location_id: the id of the location to look in (optional)
459 @return: array of PoolFile objects
462 if session is not None:
463 session = DBConn().session()
465 q = session.query(PoolFile).filter_by(filename=filename)
467 if location_id is not None:
468 q = q.join(Location).filter_by(location_id=location_id)
472 __all__.append('get_poolfile_by_name')
474 ################################################################################
476 class Fingerprint(object):
477 def __init__(self, *args, **kwargs):
481 return '<Fingerprint %s>' % self.fingerprint
483 __all__.append('Fingerprint')
485 ################################################################################
487 class Keyring(object):
488 def __init__(self, *args, **kwargs):
492 return '<Keyring %s>' % self.keyring_name
494 __all__.append('Keyring')
496 ################################################################################
498 class Location(object):
499 def __init__(self, *args, **kwargs):
503 return '<Location %s (%s)>' % (self.path, self.location_id)
505 __all__.append('Location')
507 def get_location(location, component=None, archive=None, session=None):
509 Returns Location object for the given combination of location, component
512 @type location: string
513 @param location: the path of the location, e.g. I{/srv/ftp.debian.org/ftp/pool/}
515 @type component: string
516 @param component: the component name (if None, no restriction applied)
518 @type archive: string
519 @param archive_id: the archive name (if None, no restriction applied)
521 @rtype: Location / None
522 @return: Either a Location object or None if one can't be found
526 session = DBConn().session()
528 q = session.query(Location).filter_by(path=location)
530 if archive is not None:
531 q = q.join(Archive).filter_by(archive_name=archive)
533 if component is not None:
534 q = q.join(Component).filter_by(component_name=component)
541 __all__.append('get_location')
543 ################################################################################
545 class Maintainer(object):
546 def __init__(self, *args, **kwargs):
550 return '''<Maintainer '%s' (%s)>''' % (self.name, self.maintainer_id)
552 __all__.append('Maintainer')
554 ################################################################################
556 class Override(object):
557 def __init__(self, *args, **kwargs):
561 return '<Override %s (%s)>' % (self.package, self.suite_id)
563 __all__.append('Override')
565 ################################################################################
567 class OverrideType(object):
568 def __init__(self, *args, **kwargs):
572 return '<OverrideType %s>' % self.overridetype
574 __all__.append('OverrideType')
576 def get_override_type(override_type, session=None):
578 Returns OverrideType object for given C{override type}.
580 @type override_type: string
581 @param override_type: The name of the override type
583 @type session: Session
584 @param session: Optional SQLA session object (a temporary one will be
585 generated if not supplied)
588 @return: the database id for the given override type
592 session = DBConn().session()
593 q = session.query(Priority).filter_by(priority=priority)
598 __all__.append('get_override_type')
600 ################################################################################
602 class PendingContentAssociation(object):
603 def __init__(self, *args, **kwargs):
607 return '<PendingContentAssociation %s>' % self.pca_id
609 __all__.append('PendingContentAssociation')
611 def insert_pending_content_paths(package, fullpaths, session=None):
613 Make sure given paths are temporarily associated with given
617 @param package: the package to associate with should have been read in from the binary control file
618 @type fullpaths: list
619 @param fullpaths: the list of paths of the file being associated with the binary
620 @type session: SQLAlchemy session
621 @param session: Optional SQLAlchemy session. If this is passed, the caller
622 is responsible for ensuring a transaction has begun and committing the
623 results or rolling back based on the result code. If not passed, a commit
624 will be performed at the end of the function
626 @return: True upon success, False if there is a problem
632 session = DBConn().session()
636 arch = get_architecture(package['Architecture'], session)
637 arch_id = arch.arch_id
639 # Remove any already existing recorded files for this package
640 q = session.query(PendingContentAssociation)
641 q = q.filter_by(package=package['Package'])
642 q = q.filter_by(version=package['Version'])
643 q = q.filter_by(architecture=arch_id)
647 for fullpath in fullpaths:
648 (path, file) = os.path.split(fullpath)
650 if path.startswith( "./" ):
653 pca = PendingContentAssociation()
654 pca.package = package['Package']
655 pca.version = package['Version']
656 pca.filename_id = get_or_set_contents_file_id(file, session)
657 pca.filepath_id = get_or_set_contents_path_id(path, session)
658 pca.architecture = arch_id
661 # Only commit if we set up the session ourself
667 traceback.print_exc()
669 # Only rollback if we set up the session ourself
675 __all__.append('insert_pending_content_paths')
677 ################################################################################
679 class Priority(object):
680 def __init__(self, *args, **kwargs):
684 return '<Priority %s (%s)>' % (self.priority, self.priority_id)
686 __all__.append('Priority')
688 def get_priority(priority, session=None):
690 Returns Priority object for given C{priority name}.
692 @type priority: string
693 @param priority: The name of the priority
695 @type session: Session
696 @param session: Optional SQLA session object (a temporary one will be
697 generated if not supplied)
700 @return: Priority object for the given priority
704 session = DBConn().session()
705 q = session.query(Priority).filter_by(priority=priority)
710 __all__.append('get_priority')
712 ################################################################################
715 def __init__(self, *args, **kwargs):
719 return '<Queue %s>' % self.queue_name
721 __all__.append('Queue')
723 ################################################################################
725 class QueueBuild(object):
726 def __init__(self, *args, **kwargs):
730 return '<QueueBuild %s (%s)>' % (self.filename, self.queue_id)
732 __all__.append('QueueBuild')
734 ################################################################################
736 class Section(object):
737 def __init__(self, *args, **kwargs):
741 return '<Section %s>' % self.section
743 __all__.append('Section')
745 def get_section(section, session=None):
747 Returns Section object for given C{section name}.
749 @type section: string
750 @param section: The name of the section
752 @type session: Session
753 @param session: Optional SQLA session object (a temporary one will be
754 generated if not supplied)
757 @return: Section object for the given section name
761 session = DBConn().session()
762 q = session.query(Section).filter_by(section=section)
767 __all__.append('get_section')
769 ################################################################################
771 class DBSource(object):
772 def __init__(self, *args, **kwargs):
776 return '<DBSource %s (%s)>' % (self.source, self.version)
778 __all__.append('DBSource')
780 def get_sources_from_name(source, dm_upload_allowed=None, session=None):
782 Returns list of DBSource objects for given C{source} name
785 @param source: DBSource package name to search for
787 @type dm_upload_allowed: bool
788 @param dm_upload_allowed: If None, no effect. If True or False, only
789 return packages with that dm_upload_allowed setting
791 @type session: Session
792 @param session: Optional SQL session object (a temporary one will be
793 generated if not supplied)
796 @return: list of DBSource objects for the given name (may be empty)
799 session = DBConn().session()
801 q = session.query(DBSource).filter_by(source=source)
802 if dm_upload_allowed is not None:
803 q = q.filter_by(dm_upload_allowed=dm_upload_allowed)
807 __all__.append('get_sources_from_name')
809 def get_source_in_suite(source, suite, session=None):
811 Returns list of DBSource objects for a combination of C{source} and C{suite}.
813 - B{source} - source package name, eg. I{mailfilter}, I{bbdb}, I{glibc}
814 - B{suite} - a suite name, eg. I{unstable}
817 @param source: source package name
820 @param suite: the suite name
823 @return: the version for I{source} in I{suite}
827 session = DBConn().session()
828 q = session.query(SrcAssociation)
829 q = q.join('source').filter_by(source=source)
830 q = q.join('suite').filter_by(suite_name=suite)
833 # ???: Maybe we should just return the SrcAssociation object instead
834 return q.one().source
836 __all__.append('get_source_in_suite')
838 ################################################################################
840 class SrcAssociation(object):
841 def __init__(self, *args, **kwargs):
845 return '<SrcAssociation %s (%s, %s)>' % (self.sa_id, self.source, self.suite)
847 __all__.append('SrcAssociation')
849 ################################################################################
851 class SrcUploader(object):
852 def __init__(self, *args, **kwargs):
856 return '<SrcUploader %s>' % self.uploader_id
858 __all__.append('SrcUploader')
860 ################################################################################
863 def __init__(self, *args, **kwargs):
867 return '<Suite %s>' % self.suite_name
869 __all__.append('Suite')
871 def get_suite_architecture(suite, architecture, session=None):
873 Returns a SuiteArchitecture object given C{suite} and ${arch} or None if it
877 @param suite: Suite name to search for
879 @type architecture: str
880 @param architecture: Architecture name to search for
882 @type session: Session
883 @param session: Optional SQL session object (a temporary one will be
884 generated if not supplied)
886 @rtype: SuiteArchitecture
887 @return: the SuiteArchitecture object or None
891 session = DBConn().session()
893 q = session.query(SuiteArchitecture)
894 q = q.join(Architecture).filter_by(arch_string=architecture)
895 q = q.join(Suite).filter_by(suite_name=suite)
900 __all__.append('get_suite_architecture')
902 def get_suite(suite, session=None):
904 Returns Suite object for given C{suite name}.
907 @param suite: The name of the suite
909 @type session: Session
910 @param session: Optional SQLA session object (a temporary one will be
911 generated if not supplied)
914 @return: Suite object for the requested suite name (None if not presenT)
918 session = DBConn().session()
919 q = session.query(Suite).filter_by(suite_name=suite)
924 __all__.append('get_suite')
926 ################################################################################
928 class SuiteArchitecture(object):
929 def __init__(self, *args, **kwargs):
933 return '<SuiteArchitecture (%s, %s)>' % (self.suite_id, self.arch_id)
935 __all__.append('SuiteArchitecture')
937 def get_suite_architectures(suite, skipsrc=False, skipall=False, session=None):
939 Returns list of Architecture objects for given C{suite} name
942 @param source: Suite name to search for
944 @type skipsrc: boolean
945 @param skipsrc: Whether to skip returning the 'source' architecture entry
948 @type skipall: boolean
949 @param skipall: Whether to skip returning the 'all' architecture entry
952 @type session: Session
953 @param session: Optional SQL session object (a temporary one will be
954 generated if not supplied)
957 @return: list of Architecture objects for the given name (may be empty)
961 session = DBConn().session()
963 q = session.query(Architecture)
964 q = q.join(SuiteArchitecture)
965 q = q.join(Suite).filter_by(suite_name=suite)
967 q = q.filter(Architecture.arch_string != 'source')
969 q = q.filter(Architecture.arch_string != 'all')
970 q = q.order_by('arch_string')
973 __all__.append('get_suite_architectures')
975 ################################################################################
978 def __init__(self, *args, **kwargs):
982 return '<Uid %s (%s)>' % (self.uid, self.name)
984 __all__.append('Uid')
986 def get_uid_from_fingerprint(fpr, session=None):
988 session = DBConn().session()
990 q = session.query(Uid)
991 q = q.join(Fingerprint).filter_by(fingerprint=fpr)
998 __all__.append('get_uid_from_fingerprint')
1000 ################################################################################
1002 class DBConn(Singleton):
1004 database module init.
1006 def __init__(self, *args, **kwargs):
1007 super(DBConn, self).__init__(*args, **kwargs)
1009 def _startup(self, *args, **kwargs):
1011 if kwargs.has_key('debug'):
1015 def __setuptables(self):
1016 self.tbl_architecture = Table('architecture', self.db_meta, autoload=True)
1017 self.tbl_archive = Table('archive', self.db_meta, autoload=True)
1018 self.tbl_bin_associations = Table('bin_associations', self.db_meta, autoload=True)
1019 self.tbl_binaries = Table('binaries', self.db_meta, autoload=True)
1020 self.tbl_component = Table('component', self.db_meta, autoload=True)
1021 self.tbl_config = Table('config', self.db_meta, autoload=True)
1022 self.tbl_content_associations = Table('content_associations', self.db_meta, autoload=True)
1023 self.tbl_content_file_names = Table('content_file_names', self.db_meta, autoload=True)
1024 self.tbl_content_file_paths = Table('content_file_paths', self.db_meta, autoload=True)
1025 self.tbl_dsc_files = Table('dsc_files', self.db_meta, autoload=True)
1026 self.tbl_files = Table('files', self.db_meta, autoload=True)
1027 self.tbl_fingerprint = Table('fingerprint', self.db_meta, autoload=True)
1028 self.tbl_keyrings = Table('keyrings', self.db_meta, autoload=True)
1029 self.tbl_location = Table('location', self.db_meta, autoload=True)
1030 self.tbl_maintainer = Table('maintainer', self.db_meta, autoload=True)
1031 self.tbl_override = Table('override', self.db_meta, autoload=True)
1032 self.tbl_override_type = Table('override_type', self.db_meta, autoload=True)
1033 self.tbl_pending_content_associations = Table('pending_content_associations', self.db_meta, autoload=True)
1034 self.tbl_priority = Table('priority', self.db_meta, autoload=True)
1035 self.tbl_queue = Table('queue', self.db_meta, autoload=True)
1036 self.tbl_queue_build = Table('queue_build', self.db_meta, autoload=True)
1037 self.tbl_section = Table('section', self.db_meta, autoload=True)
1038 self.tbl_source = Table('source', self.db_meta, autoload=True)
1039 self.tbl_src_associations = Table('src_associations', self.db_meta, autoload=True)
1040 self.tbl_src_uploaders = Table('src_uploaders', self.db_meta, autoload=True)
1041 self.tbl_suite = Table('suite', self.db_meta, autoload=True)
1042 self.tbl_suite_architectures = Table('suite_architectures', self.db_meta, autoload=True)
1043 self.tbl_uid = Table('uid', self.db_meta, autoload=True)
1045 def __setupmappers(self):
1046 mapper(Architecture, self.tbl_architecture,
1047 properties = dict(arch_id = self.tbl_architecture.c.id))
1049 mapper(Archive, self.tbl_archive,
1050 properties = dict(archive_id = self.tbl_archive.c.id,
1051 archive_name = self.tbl_archive.c.name))
1053 mapper(BinAssociation, self.tbl_bin_associations,
1054 properties = dict(ba_id = self.tbl_bin_associations.c.id,
1055 suite_id = self.tbl_bin_associations.c.suite,
1056 suite = relation(Suite),
1057 binary_id = self.tbl_bin_associations.c.bin,
1058 binary = relation(DBBinary)))
1060 mapper(DBBinary, self.tbl_binaries,
1061 properties = dict(binary_id = self.tbl_binaries.c.id,
1062 package = self.tbl_binaries.c.package,
1063 version = self.tbl_binaries.c.version,
1064 maintainer_id = self.tbl_binaries.c.maintainer,
1065 maintainer = relation(Maintainer),
1066 source_id = self.tbl_binaries.c.source,
1067 source = relation(DBSource),
1068 arch_id = self.tbl_binaries.c.architecture,
1069 architecture = relation(Architecture),
1070 poolfile_id = self.tbl_binaries.c.file,
1071 poolfile = relation(PoolFile),
1072 binarytype = self.tbl_binaries.c.type,
1073 fingerprint_id = self.tbl_binaries.c.sig_fpr,
1074 fingerprint = relation(Fingerprint),
1075 install_date = self.tbl_binaries.c.install_date,
1076 binassociations = relation(BinAssociation,
1077 primaryjoin=(self.tbl_binaries.c.id==self.tbl_bin_associations.c.bin))))
1079 mapper(Component, self.tbl_component,
1080 properties = dict(component_id = self.tbl_component.c.id,
1081 component_name = self.tbl_component.c.name))
1083 mapper(DBConfig, self.tbl_config,
1084 properties = dict(config_id = self.tbl_config.c.id))
1086 mapper(ContentAssociation, self.tbl_content_associations,
1087 properties = dict(ca_id = self.tbl_content_associations.c.id,
1088 filename_id = self.tbl_content_associations.c.filename,
1089 filename = relation(ContentFilename),
1090 filepath_id = self.tbl_content_associations.c.filepath,
1091 filepath = relation(ContentFilepath),
1092 binary_id = self.tbl_content_associations.c.binary_pkg,
1093 binary = relation(DBBinary)))
1096 mapper(ContentFilename, self.tbl_content_file_names,
1097 properties = dict(cafilename_id = self.tbl_content_file_names.c.id,
1098 filename = self.tbl_content_file_names.c.file))
1100 mapper(ContentFilepath, self.tbl_content_file_paths,
1101 properties = dict(cafilepath_id = self.tbl_content_file_paths.c.id,
1102 filepath = self.tbl_content_file_paths.c.path))
1104 mapper(DSCFile, self.tbl_dsc_files,
1105 properties = dict(dscfile_id = self.tbl_dsc_files.c.id,
1106 source_id = self.tbl_dsc_files.c.source,
1107 source = relation(DBSource),
1108 poolfile_id = self.tbl_dsc_files.c.file,
1109 poolfile = relation(PoolFile)))
1111 mapper(PoolFile, self.tbl_files,
1112 properties = dict(file_id = self.tbl_files.c.id,
1113 filesize = self.tbl_files.c.size,
1114 location_id = self.tbl_files.c.location,
1115 location = relation(Location)))
1117 mapper(Fingerprint, self.tbl_fingerprint,
1118 properties = dict(fingerprint_id = self.tbl_fingerprint.c.id,
1119 uid_id = self.tbl_fingerprint.c.uid,
1120 uid = relation(Uid),
1121 keyring_id = self.tbl_fingerprint.c.keyring,
1122 keyring = relation(Keyring)))
1124 mapper(Keyring, self.tbl_keyrings,
1125 properties = dict(keyring_name = self.tbl_keyrings.c.name,
1126 keyring_id = self.tbl_keyrings.c.id))
1128 mapper(Location, self.tbl_location,
1129 properties = dict(location_id = self.tbl_location.c.id,
1130 component_id = self.tbl_location.c.component,
1131 component = relation(Component),
1132 archive_id = self.tbl_location.c.archive,
1133 archive = relation(Archive),
1134 archive_type = self.tbl_location.c.type))
1136 mapper(Maintainer, self.tbl_maintainer,
1137 properties = dict(maintainer_id = self.tbl_maintainer.c.id))
1139 mapper(Override, self.tbl_override,
1140 properties = dict(suite_id = self.tbl_override.c.suite,
1141 suite = relation(Suite),
1142 component_id = self.tbl_override.c.component,
1143 component = relation(Component),
1144 priority_id = self.tbl_override.c.priority,
1145 priority = relation(Priority),
1146 section_id = self.tbl_override.c.section,
1147 section = relation(Section),
1148 overridetype_id = self.tbl_override.c.type,
1149 overridetype = relation(OverrideType)))
1151 mapper(OverrideType, self.tbl_override_type,
1152 properties = dict(overridetype = self.tbl_override_type.c.type,
1153 overridetype_id = self.tbl_override_type.c.id))
1155 mapper(PendingContentAssociation, self.tbl_pending_content_associations,
1156 properties = dict(pca_id = self.tbl_pending_content_associations.c.id,
1157 filepath_id = self.tbl_pending_content_associations.c.filepath,
1158 filepath = relation(ContentFilepath),
1159 filename_id = self.tbl_pending_content_associations.c.filename,
1160 filename = relation(ContentFilename)))
1162 mapper(Priority, self.tbl_priority,
1163 properties = dict(priority_id = self.tbl_priority.c.id))
1165 mapper(Queue, self.tbl_queue,
1166 properties = dict(queue_id = self.tbl_queue.c.id))
1168 mapper(QueueBuild, self.tbl_queue_build,
1169 properties = dict(suite_id = self.tbl_queue_build.c.suite,
1170 queue_id = self.tbl_queue_build.c.queue,
1171 queue = relation(Queue)))
1173 mapper(Section, self.tbl_section,
1174 properties = dict(section_id = self.tbl_section.c.id))
1176 mapper(DBSource, self.tbl_source,
1177 properties = dict(source_id = self.tbl_source.c.id,
1178 version = self.tbl_source.c.version,
1179 maintainer_id = self.tbl_source.c.maintainer,
1180 maintainer = relation(Maintainer,
1181 primaryjoin=(self.tbl_source.c.maintainer==self.tbl_maintainer.c.id)),
1182 poolfile_id = self.tbl_source.c.file,
1183 poolfile = relation(PoolFile),
1184 fingerprint_id = self.tbl_source.c.sig_fpr,
1185 fingerprint = relation(Fingerprint),
1186 changedby_id = self.tbl_source.c.changedby,
1187 changedby = relation(Maintainer,
1188 primaryjoin=(self.tbl_source.c.changedby==self.tbl_maintainer.c.id)),
1189 srcfiles = relation(DSCFile,
1190 primaryjoin=(self.tbl_source.c.id==self.tbl_dsc_files.c.source)),
1191 srcassociations = relation(SrcAssociation,
1192 primaryjoin=(self.tbl_source.c.id==self.tbl_src_associations.c.source))))
1194 mapper(SrcAssociation, self.tbl_src_associations,
1195 properties = dict(sa_id = self.tbl_src_associations.c.id,
1196 suite_id = self.tbl_src_associations.c.suite,
1197 suite = relation(Suite),
1198 source_id = self.tbl_src_associations.c.source,
1199 source = relation(DBSource)))
1201 mapper(SrcUploader, self.tbl_src_uploaders,
1202 properties = dict(uploader_id = self.tbl_src_uploaders.c.id,
1203 source_id = self.tbl_src_uploaders.c.source,
1204 source = relation(DBSource,
1205 primaryjoin=(self.tbl_src_uploaders.c.source==self.tbl_source.c.id)),
1206 maintainer_id = self.tbl_src_uploaders.c.maintainer,
1207 maintainer = relation(Maintainer,
1208 primaryjoin=(self.tbl_src_uploaders.c.maintainer==self.tbl_maintainer.c.id))))
1210 mapper(Suite, self.tbl_suite,
1211 properties = dict(suite_id = self.tbl_suite.c.id))
1213 mapper(SuiteArchitecture, self.tbl_suite_architectures,
1214 properties = dict(suite_id = self.tbl_suite_architectures.c.suite,
1215 suite = relation(Suite, backref='suitearchitectures'),
1216 arch_id = self.tbl_suite_architectures.c.architecture,
1217 architecture = relation(Architecture)))
1219 mapper(Uid, self.tbl_uid,
1220 properties = dict(uid_id = self.tbl_uid.c.id,
1221 fingerprint = relation(Fingerprint)))
1223 ## Connection functions
1224 def __createconn(self):
1225 from config import Config
1229 connstr = "postgres://%s" % cnf["DB::Host"]
1230 if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
1231 connstr += ":%s" % cnf["DB::Port"]
1232 connstr += "/%s" % cnf["DB::Name"]
1235 connstr = "postgres:///%s" % cnf["DB::Name"]
1236 if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
1237 connstr += "?port=%s" % cnf["DB::Port"]
1239 self.db_pg = create_engine(connstr, echo=self.debug)
1240 self.db_meta = MetaData()
1241 self.db_meta.bind = self.db_pg
1242 self.db_smaker = sessionmaker(bind=self.db_pg,
1246 self.__setuptables()
1247 self.__setupmappers()
1250 return self.db_smaker()
1252 __all__.append('DBConn')