]> git.decadent.org.uk Git - dak.git/blob - daklib/dbconn.py
32fbdb5526376e9dcdd0ca2af74756871fd1fa38
[dak.git] / daklib / dbconn.py
1 #!/usr/bin/python
2
3 """ DB access class
4
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
11 """
12
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.
17
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.
22
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
26
27 ################################################################################
28
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"
33
34 ################################################################################
35
36 import os
37 import psycopg2
38 import traceback
39
40 from sqlalchemy import create_engine, Table, MetaData, select
41 from sqlalchemy.orm import sessionmaker, mapper, relation
42
43 # Don't remove this, we re-export the exceptions to scripts which import us
44 from sqlalchemy.exc import *
45
46 from singleton import Singleton
47
48 ################################################################################
49
50 __all__ = []
51
52 ################################################################################
53
54 class Architecture(object):
55     def __init__(self, *args, **kwargs):
56         pass
57
58     def __repr__(self):
59         return '<Architecture %s>' % self.arch_string
60
61 __all__.append('Architecture')
62
63 def get_architecture(architecture, session=None):
64     """
65     Returns database id for given C{architecture}.
66
67     @type architecture: string
68     @param architecture: The name of the architecture
69
70     @type session: Session
71     @param session: Optional SQLA session object (a temporary one will be
72     generated if not supplied)
73
74     @rtype: Architecture
75     @return: Architecture object for the given arch (None if not present)
76
77     """
78     if session is None:
79         session = DBConn().session()
80     q = session.query(Architecture).filter_by(arch_string=architecture)
81     if q.count() == 0:
82         return None
83     return q.one()
84
85 __all__.append('get_architecture')
86
87 def get_architecture_suites(architecture, session=None):
88     """
89     Returns list of Suite objects for given C{architecture} name
90
91     @type source: str
92     @param source: Architecture name to search for
93
94     @type session: Session
95     @param session: Optional SQL session object (a temporary one will be
96     generated if not supplied)
97
98     @rtype: list
99     @return: list of Suite objects for the given name (may be empty)
100     """
101
102     if session is None:
103         session = DBConn().session()
104
105     q = session.query(Suite)
106     q = q.join(SuiteArchitecture)
107     q = q.join(Architecture).filter_by(arch_string=architecture).order_by('suite_name')
108     return q.all()
109
110 __all__.append('get_architecture_suites')
111
112 ################################################################################
113
114 class Archive(object):
115     def __init__(self, *args, **kwargs):
116         pass
117
118     def __repr__(self):
119         return '<Archive %s>' % self.name
120
121 __all__.append('Archive')
122
123 def get_archive(archive, session=None):
124     """
125     returns database id for given c{archive}.
126
127     @type archive: string
128     @param archive: the name of the arhive
129
130     @type session: Session
131     @param session: Optional SQLA session object (a temporary one will be
132     generated if not supplied)
133
134     @rtype: Archive
135     @return: Archive object for the given name (None if not present)
136
137     """
138     archive = archive.lower()
139     if session is None:
140         session = DBConn().session()
141     q = session.query(Archive).filter_by(archive_name=archive)
142     if q.count() == 0:
143         return None
144     return q.one()
145
146 __all__.append('get_archive')
147
148 ################################################################################
149
150 class BinAssociation(object):
151     def __init__(self, *args, **kwargs):
152         pass
153
154     def __repr__(self):
155         return '<BinAssociation %s (%s, %s)>' % (self.ba_id, self.binary, self.suite)
156
157 __all__.append('BinAssociation')
158
159 ################################################################################
160
161 class Binary(object):
162     def __init__(self, *args, **kwargs):
163         pass
164
165     def __repr__(self):
166         return '<Binary %s (%s, %s)>' % (self.package, self.version, self.architecture)
167
168 __all__.append('Binary')
169
170 def get_binary_from_id(id, session=None):
171     """
172     Returns Binary object for given C{id}
173
174     @type id: int
175     @param id: Id of the required binary
176
177     @type session: Session
178     @param session: Optional SQLA session object (a temporary one will be
179     generated if not supplied)
180
181     @rtype: Binary
182     @return: Binary object for the given binary (None if not present)
183     """
184     if session is None:
185         session = DBConn().session()
186     q = session.query(Binary).filter_by(binary_id=id)
187     if q.count() == 0:
188         return None
189     return q.one()
190
191 __all__.append('get_binary_from_id')
192
193 def get_binaries_from_name(package, session=None):
194     """
195     Returns list of Binary objects for given C{package} name
196
197     @type package: str
198     @param package: Binary package name to search for
199
200     @type session: Session
201     @param session: Optional SQL session object (a temporary one will be
202     generated if not supplied)
203
204     @rtype: list
205     @return: list of Binary objects for the given name (may be empty)
206     """
207     if session is None:
208         session = DBConn().session()
209     return session.query(Binary).filter_by(package=package).all()
210
211 __all__.append('get_binaries_from_name')
212
213 ################################################################################
214
215 class Component(object):
216     def __init__(self, *args, **kwargs):
217         pass
218
219     def __repr__(self):
220         return '<Component %s>' % self.component_name
221
222
223 __all__.append('Component')
224
225 def get_component(component, session=None):
226     """
227     Returns database id for given C{component}.
228
229     @type component: string
230     @param component: The name of the override type
231
232     @rtype: int
233     @return: the database id for the given component
234
235     """
236     component = component.lower()
237     if session is None:
238         session = DBConn().session()
239     q = session.query(Component).filter_by(component_name=component)
240     if q.count() == 0:
241         return None
242     return q.one()
243
244 __all__.append('get_component')
245
246 ################################################################################
247
248 class DBConfig(object):
249     def __init__(self, *args, **kwargs):
250         pass
251
252     def __repr__(self):
253         return '<DBConfig %s>' % self.name
254
255 __all__.append('DBConfig')
256
257 ################################################################################
258
259 class ContentFilename(object):
260     def __init__(self, *args, **kwargs):
261         pass
262
263     def __repr__(self):
264         return '<ContentFilename %s>' % self.filename
265
266 __all__.append('ContentFilename')
267
268 def get_or_set_contents_file_id(filename, session=None):
269     """
270     Returns database id for given filename.
271
272     If no matching file is found, a row is inserted.
273
274     @type filename: string
275     @param filename: The filename
276     @type session: SQLAlchemy
277     @param session: Optional SQL session object (a temporary one will be
278     generated if not supplied)
279
280     @rtype: int
281     @return: the database id for the given component
282     """
283     if session is None:
284         session = DBConn().session()
285
286     try:
287         q = session.query(ContentFilename).filter_by(filename=filename)
288         if q.count() < 1:
289             cf = ContentFilename()
290             cf.filename = filename
291             session.add(cf)
292             return cf.cafilename_id
293         else:
294             return q.one().cafilename_id
295
296     except:
297         traceback.print_exc()
298         raise
299
300 __all__.append('get_or_set_contents_file_id')
301
302 ################################################################################
303
304 class ContentFilepath(object):
305     def __init__(self, *args, **kwargs):
306         pass
307
308     def __repr__(self):
309         return '<ContentFilepath %s>' % self.filepath
310
311 __all__.append('ContentFilepath')
312
313 def get_or_set_contents_path_id(filepath, session):
314     """
315     Returns database id for given path.
316
317     If no matching file is found, a row is inserted.
318
319     @type filename: string
320     @param filename: The filepath
321     @type session: SQLAlchemy
322     @param session: Optional SQL session object (a temporary one will be
323     generated if not supplied)
324
325     @rtype: int
326     @return: the database id for the given path
327     """
328     if session is None:
329         session = DBConn().session()
330
331     try:
332         q = session.query(ContentFilepath).filter_by(filepath=filepath)
333         if q.count() < 1:
334             cf = ContentFilepath()
335             cf.filepath = filepath
336             session.add(cf)
337             return cf.cafilepath_id
338         else:
339             return q.one().cafilepath_id
340
341     except:
342         traceback.print_exc()
343         raise
344
345 __all__.append('get_or_set_contents_path_id')
346
347 ################################################################################
348
349 class ContentAssociation(object):
350     def __init__(self, *args, **kwargs):
351         pass
352
353     def __repr__(self):
354         return '<ContentAssociation %s>' % self.ca_id
355
356 __all__.append('ContentAssociation')
357
358 def insert_content_paths(binary_id, fullpaths, session=None):
359     """
360     Make sure given path is associated with given binary id
361
362     @type binary_id: int
363     @param binary_id: the id of the binary
364     @type fullpaths: list
365     @param fullpaths: the list of paths of the file being associated with the binary
366     @type session: SQLAlchemy session
367     @param session: Optional SQLAlchemy session.  If this is passed, the caller
368     is responsible for ensuring a transaction has begun and committing the
369     results or rolling back based on the result code.  If not passed, a commit
370     will be performed at the end of the function
371
372     @return: True upon success
373     """
374
375     privatetrans = False
376
377     if session is None:
378         session = DBConn().session()
379         privatetrans = True
380
381     try:
382         for fullpath in fullpaths:
383             (path, file) = os.path.split(fullpath)
384
385             # Get the necessary IDs ...
386             ca = ContentAssociation()
387             ca.binary_id = binary_id
388             ca.filename_id = get_or_set_contents_file_id(file)
389             ca.filepath_id = get_or_set_contents_path_id(path)
390             session.add(ca)
391
392         # Only commit if we set up the session ourself
393         if privatetrans:
394             session.commit()
395
396         return True
397     except:
398         traceback.print_exc()
399
400         # Only rollback if we set up the session ourself
401         if privatetrans:
402             session.rollback()
403
404         return False
405
406 __all__.append('insert_content_paths')
407
408 ################################################################################
409
410 class DSCFile(object):
411     def __init__(self, *args, **kwargs):
412         pass
413
414     def __repr__(self):
415         return '<DSCFile %s>' % self.dscfile_id
416
417 __all__.append('DSCFile')
418
419 ################################################################################
420
421 class PoolFile(object):
422     def __init__(self, *args, **kwargs):
423         pass
424
425     def __repr__(self):
426         return '<PoolFile %s>' % self.filename
427
428 __all__.append('PoolFile')
429
430 def get_poolfile_by_name(filename, location_id=None, session=None):
431     """
432     Returns an array of PoolFile objects for the given filename and
433     (optionally) location_id
434
435     @type filename: string
436     @param filename: the filename of the file to check against the DB
437
438     @type location_id: int
439     @param location_id: the id of the location to look in (optional)
440
441     @rtype: array
442     @return: array of PoolFile objects
443     """
444
445     if session is not None:
446         session = DBConn().session()
447
448     q = session.query(PoolFile).filter_by(filename=filename)
449
450     if location_id is not None:
451         q = q.join(Location).filter_by(location_id=location_id)
452
453     return q.all()
454
455 __all__.append('get_poolfile_by_name')
456
457 ################################################################################
458
459 class Fingerprint(object):
460     def __init__(self, *args, **kwargs):
461         pass
462
463     def __repr__(self):
464         return '<Fingerprint %s>' % self.fingerprint
465
466 __all__.append('Fingerprint')
467
468 ################################################################################
469
470 class Keyring(object):
471     def __init__(self, *args, **kwargs):
472         pass
473
474     def __repr__(self):
475         return '<Keyring %s>' % self.keyring_name
476
477 __all__.append('Keyring')
478
479 ################################################################################
480
481 class Location(object):
482     def __init__(self, *args, **kwargs):
483         pass
484
485     def __repr__(self):
486         return '<Location %s (%s)>' % (self.path, self.location_id)
487
488 __all__.append('Location')
489
490 def get_location(location, component=None, archive=None, session=None):
491     """
492     Returns Location object for the given combination of location, component
493     and archive
494
495     @type location: string
496     @param location: the path of the location, e.g. I{/srv/ftp.debian.org/ftp/pool/}
497
498     @type component: string
499     @param component: the component name (if None, no restriction applied)
500
501     @type archive: string
502     @param archive_id: the archive name (if None, no restriction applied)
503
504     @rtype: Location / None
505     @return: Either a Location object or None if one can't be found
506     """
507
508     if session is None:
509         session = DBConn().session()
510
511     q = session.query(Location).filter_by(path=location)
512
513     if archive is not None:
514         q = q.join(Archive).filter_by(archive_name=archive)
515
516     if component is not None:
517         q = q.join(Component).filter_by(component_name=component)
518
519     if q.count() < 1:
520         return None
521     else:
522         return q.one()
523
524 __all__.append('get_location')
525
526 ################################################################################
527
528 class Maintainer(object):
529     def __init__(self, *args, **kwargs):
530         pass
531
532     def __repr__(self):
533         return '''<Maintainer '%s' (%s)>''' % (self.name, self.maintainer_id)
534
535 __all__.append('Maintainer')
536
537 ################################################################################
538
539 class Override(object):
540     def __init__(self, *args, **kwargs):
541         pass
542
543     def __repr__(self):
544         return '<Override %s (%s)>' % (self.package, self.suite_id)
545
546 __all__.append('Override')
547
548 ################################################################################
549
550 class OverrideType(object):
551     def __init__(self, *args, **kwargs):
552         pass
553
554     def __repr__(self):
555         return '<OverrideType %s>' % self.overridetype
556
557 __all__.append('OverrideType')
558
559 def get_override_type(override_type, session=None):
560     """
561     Returns OverrideType object for given C{override type}.
562
563     @type override_type: string
564     @param override_type: The name of the override type
565
566     @type session: Session
567     @param session: Optional SQLA session object (a temporary one will be
568     generated if not supplied)
569
570     @rtype: int
571     @return: the database id for the given override type
572
573     """
574     if session is None:
575         session = DBConn().session()
576     q = session.query(Priority).filter_by(priority=priority)
577     if q.count() == 0:
578         return None
579     return q.one()
580
581 __all__.append('get_override_type')
582
583 ################################################################################
584
585 class PendingContentAssociation(object):
586     def __init__(self, *args, **kwargs):
587         pass
588
589     def __repr__(self):
590         return '<PendingContentAssociation %s>' % self.pca_id
591
592 __all__.append('PendingContentAssociation')
593
594 def insert_pending_content_paths(package, fullpaths, session=None):
595     """
596     Make sure given paths are temporarily associated with given
597     package
598
599     @type package: dict
600     @param package: the package to associate with should have been read in from the binary control file
601     @type fullpaths: list
602     @param fullpaths: the list of paths of the file being associated with the binary
603     @type session: SQLAlchemy session
604     @param session: Optional SQLAlchemy session.  If this is passed, the caller
605     is responsible for ensuring a transaction has begun and committing the
606     results or rolling back based on the result code.  If not passed, a commit
607     will be performed at the end of the function
608
609     @return: True upon success, False if there is a problem
610     """
611
612     privatetrans = False
613
614     if session is None:
615         session = DBConn().session()
616         privatetrans = True
617
618     try:
619         arch = get_architecture(package['Architecture'], session)
620         arch_id = arch.arch_id
621
622         # Remove any already existing recorded files for this package
623         q = session.query(PendingContentAssociation)
624         q = q.filter_by(package=package['Package'])
625         q = q.filter_by(version=package['Version'])
626         q = q.filter_by(architecture=arch_id)
627         q.delete()
628
629         # Insert paths
630         for fullpath in fullpaths:
631             (path, file) = os.path.split(fullpath)
632
633             if path.startswith( "./" ):
634                 path = path[2:]
635
636             pca = PendingContentAssociation()
637             pca.package = package['Package']
638             pca.version = package['Version']
639             pca.filename_id = get_or_set_contents_file_id(file, session)
640             pca.filepath_id = get_or_set_contents_path_id(path, session)
641             pca.architecture = arch_id
642             session.add(pca)
643
644         # Only commit if we set up the session ourself
645         if privatetrans:
646             session.commit()
647
648         return True
649     except:
650         traceback.print_exc()
651
652         # Only rollback if we set up the session ourself
653         if privatetrans:
654             session.rollback()
655
656         return False
657
658 __all__.append('insert_pending_content_paths')
659
660 ################################################################################
661
662 class Priority(object):
663     def __init__(self, *args, **kwargs):
664         pass
665
666     def __repr__(self):
667         return '<Priority %s (%s)>' % (self.priority, self.priority_id)
668
669 __all__.append('Priority')
670
671 def get_priority(priority, session=None):
672     """
673     Returns Priority object for given C{priority name}.
674
675     @type priority: string
676     @param priority: The name of the priority
677
678     @type session: Session
679     @param session: Optional SQLA session object (a temporary one will be
680     generated if not supplied)
681
682     @rtype: Priority
683     @return: Priority object for the given priority
684
685     """
686     if session is None:
687         session = DBConn().session()
688     q = session.query(Priority).filter_by(priority=priority)
689     if q.count() == 0:
690         return None
691     return q.one()
692
693 __all__.append('get_priority')
694
695 ################################################################################
696
697 class Queue(object):
698     def __init__(self, *args, **kwargs):
699         pass
700
701     def __repr__(self):
702         return '<Queue %s>' % self.queue_name
703
704 __all__.append('Queue')
705
706 ################################################################################
707
708 class QueueBuild(object):
709     def __init__(self, *args, **kwargs):
710         pass
711
712     def __repr__(self):
713         return '<QueueBuild %s (%s)>' % (self.filename, self.queue_id)
714
715 __all__.append('QueueBuild')
716
717 ################################################################################
718
719 class Section(object):
720     def __init__(self, *args, **kwargs):
721         pass
722
723     def __repr__(self):
724         return '<Section %s>' % self.section
725
726 __all__.append('Section')
727
728 def get_section(section, session=None):
729     """
730     Returns Section object for given C{section name}.
731
732     @type section: string
733     @param section: The name of the section
734
735     @type session: Session
736     @param session: Optional SQLA session object (a temporary one will be
737     generated if not supplied)
738
739     @rtype: Section
740     @return: Section object for the given section name
741
742     """
743     if session is None:
744         session = DBConn().session()
745     q = session.query(Section).filter_by(section=section)
746     if q.count() == 0:
747         return None
748     return q.one()
749
750 __all__.append('get_section')
751
752 ################################################################################
753
754 class Source(object):
755     def __init__(self, *args, **kwargs):
756         pass
757
758     def __repr__(self):
759         return '<Source %s (%s)>' % (self.source, self.version)
760
761 __all__.append('Source')
762
763 def get_sources_from_name(source, session=None):
764     """
765     Returns list of Source objects for given C{source} name
766
767     @type source: str
768     @param source: Source package name to search for
769
770     @type session: Session
771     @param session: Optional SQL session object (a temporary one will be
772     generated if not supplied)
773
774     @rtype: list
775     @return: list of Source objects for the given name (may be empty)
776     """
777     if session is None:
778         session = DBConn().session()
779     return session.query(Source).filter_by(source=source).all()
780
781 __all__.append('get_sources_from_name')
782
783 def get_source_in_suite(source, suite, session=None):
784     """
785     Returns list of Source objects for a combination of C{source} and C{suite}.
786
787       - B{source} - source package name, eg. I{mailfilter}, I{bbdb}, I{glibc}
788       - B{suite} - a suite name, eg. I{unstable}
789
790     @type source: string
791     @param source: source package name
792
793     @type suite: string
794     @param suite: the suite name
795
796     @rtype: string
797     @return: the version for I{source} in I{suite}
798
799     """
800     if session is None:
801         session = DBConn().session()
802     q = session.query(SrcAssociation)
803     q = q.join('source').filter_by(source=source)
804     q = q.join('suite').filter_by(suite_name=suite)
805     if q.count() == 0:
806         return None
807     # ???: Maybe we should just return the SrcAssociation object instead
808     return q.one().source
809
810 __all__.append('get_source_in_suite')
811
812 ################################################################################
813
814 class SrcAssociation(object):
815     def __init__(self, *args, **kwargs):
816         pass
817
818     def __repr__(self):
819         return '<SrcAssociation %s (%s, %s)>' % (self.sa_id, self.source, self.suite)
820
821 __all__.append('SrcAssociation')
822
823 ################################################################################
824
825 class SrcUploader(object):
826     def __init__(self, *args, **kwargs):
827         pass
828
829     def __repr__(self):
830         return '<SrcUploader %s>' % self.uploader_id
831
832 __all__.append('SrcUploader')
833
834 ################################################################################
835
836 class Suite(object):
837     def __init__(self, *args, **kwargs):
838         pass
839
840     def __repr__(self):
841         return '<Suite %s>' % self.suite_name
842
843 __all__.append('Suite')
844
845 def get_suite_architecture(suite, architecture, session=None):
846     """
847     Returns a SuiteArchitecture object given C{suite} and ${arch} or None if it
848     doesn't exist
849
850     @type suite: str
851     @param suite: Suite name to search for
852
853     @type architecture: str
854     @param architecture: Architecture name to search for
855
856     @type session: Session
857     @param session: Optional SQL session object (a temporary one will be
858     generated if not supplied)
859
860     @rtype: SuiteArchitecture
861     @return: the SuiteArchitecture object or None
862     """
863
864     if session is None:
865         session = DBConn().session()
866
867     q = session.query(SuiteArchitecture)
868     q = q.join(Architecture).filter_by(arch_string=architecture)
869     q = q.join(Suite).filter_by(suite_name=suite)
870     if q.count() == 0:
871         return None
872     return q.one()
873
874 __all__.append('get_suite_architecture')
875
876 def get_suite(suite, session=None):
877     """
878     Returns Suite object for given C{suite name}.
879
880     @type suite: string
881     @param suite: The name of the suite
882
883     @type session: Session
884     @param session: Optional SQLA session object (a temporary one will be
885     generated if not supplied)
886
887     @rtype: Suite
888     @return: Suite object for the requested suite name (None if not presenT)
889
890     """
891     if session is None:
892         session = DBConn().session()
893     q = session.query(Suite).filter_by(suite_name=suite)
894     if q.count() == 0:
895         return None
896     return q.one()
897
898 __all__.append('get_suite')
899
900 ################################################################################
901
902 class SuiteArchitecture(object):
903     def __init__(self, *args, **kwargs):
904         pass
905
906     def __repr__(self):
907         return '<SuiteArchitecture (%s, %s)>' % (self.suite_id, self.arch_id)
908
909 __all__.append('SuiteArchitecture')
910
911 def get_suite_architectures(suite, session=None):
912     """
913     Returns list of Architecture objects for given C{suite} name
914
915     @type source: str
916     @param source: Suite name to search for
917
918     @type session: Session
919     @param session: Optional SQL session object (a temporary one will be
920     generated if not supplied)
921
922     @rtype: list
923     @return: list of Architecture objects for the given name (may be empty)
924     """
925
926     if session is None:
927         session = DBConn().session()
928
929     q = session.query(Architecture)
930     q = q.join(SuiteArchitecture)
931     q = q.join(Suite).filter_by(suite_name=suite).order_by('arch_string')
932     return q.all()
933
934 __all__.append('get_suite_architectures')
935
936 ################################################################################
937
938 class Uid(object):
939     def __init__(self, *args, **kwargs):
940         pass
941
942     def __repr__(self):
943         return '<Uid %s (%s)>' % (self.uid, self.name)
944
945 __all__.append('Uid')
946
947 ################################################################################
948
949 class DBConn(Singleton):
950     """
951     database module init.
952     """
953     def __init__(self, *args, **kwargs):
954         super(DBConn, self).__init__(*args, **kwargs)
955
956     def _startup(self, *args, **kwargs):
957         self.debug = False
958         if kwargs.has_key('debug'):
959             self.debug = True
960         self.__createconn()
961
962     def __setuptables(self):
963         self.tbl_architecture = Table('architecture', self.db_meta, autoload=True)
964         self.tbl_archive = Table('archive', self.db_meta, autoload=True)
965         self.tbl_bin_associations = Table('bin_associations', self.db_meta, autoload=True)
966         self.tbl_binaries = Table('binaries', self.db_meta, autoload=True)
967         self.tbl_component = Table('component', self.db_meta, autoload=True)
968         self.tbl_config = Table('config', self.db_meta, autoload=True)
969         self.tbl_content_associations = Table('content_associations', self.db_meta, autoload=True)
970         self.tbl_content_file_names = Table('content_file_names', self.db_meta, autoload=True)
971         self.tbl_content_file_paths = Table('content_file_paths', self.db_meta, autoload=True)
972         self.tbl_dsc_files = Table('dsc_files', self.db_meta, autoload=True)
973         self.tbl_files = Table('files', self.db_meta, autoload=True)
974         self.tbl_fingerprint = Table('fingerprint', self.db_meta, autoload=True)
975         self.tbl_keyrings = Table('keyrings', self.db_meta, autoload=True)
976         self.tbl_location = Table('location', self.db_meta, autoload=True)
977         self.tbl_maintainer = Table('maintainer', self.db_meta, autoload=True)
978         self.tbl_override = Table('override', self.db_meta, autoload=True)
979         self.tbl_override_type = Table('override_type', self.db_meta, autoload=True)
980         self.tbl_pending_content_associations = Table('pending_content_associations', self.db_meta, autoload=True)
981         self.tbl_priority = Table('priority', self.db_meta, autoload=True)
982         self.tbl_queue = Table('queue', self.db_meta, autoload=True)
983         self.tbl_queue_build = Table('queue_build', self.db_meta, autoload=True)
984         self.tbl_section = Table('section', self.db_meta, autoload=True)
985         self.tbl_source = Table('source', self.db_meta, autoload=True)
986         self.tbl_src_associations = Table('src_associations', self.db_meta, autoload=True)
987         self.tbl_src_uploaders = Table('src_uploaders', self.db_meta, autoload=True)
988         self.tbl_suite = Table('suite', self.db_meta, autoload=True)
989         self.tbl_suite_architectures = Table('suite_architectures', self.db_meta, autoload=True)
990         self.tbl_uid = Table('uid', self.db_meta, autoload=True)
991
992     def __setupmappers(self):
993         mapper(Architecture, self.tbl_architecture,
994                properties = dict(arch_id = self.tbl_architecture.c.id))
995
996         mapper(Archive, self.tbl_archive,
997                properties = dict(archive_id = self.tbl_archive.c.id,
998                                  archive_name = self.tbl_archive.c.name))
999
1000         mapper(BinAssociation, self.tbl_bin_associations,
1001                properties = dict(ba_id = self.tbl_bin_associations.c.id,
1002                                  suite_id = self.tbl_bin_associations.c.suite,
1003                                  suite = relation(Suite),
1004                                  binary_id = self.tbl_bin_associations.c.bin,
1005                                  binary = relation(Binary)))
1006
1007         mapper(Binary, self.tbl_binaries,
1008                properties = dict(binary_id = self.tbl_binaries.c.id,
1009                                  package = self.tbl_binaries.c.package,
1010                                  version = self.tbl_binaries.c.version,
1011                                  maintainer_id = self.tbl_binaries.c.maintainer,
1012                                  maintainer = relation(Maintainer),
1013                                  source_id = self.tbl_binaries.c.source,
1014                                  source = relation(Source),
1015                                  arch_id = self.tbl_binaries.c.architecture,
1016                                  architecture = relation(Architecture),
1017                                  poolfile_id = self.tbl_binaries.c.file,
1018                                  poolfile = relation(PoolFile),
1019                                  binarytype = self.tbl_binaries.c.type,
1020                                  fingerprint_id = self.tbl_binaries.c.sig_fpr,
1021                                  fingerprint = relation(Fingerprint),
1022                                  install_date = self.tbl_binaries.c.install_date,
1023                                  binassociations = relation(BinAssociation,
1024                                                             primaryjoin=(self.tbl_binaries.c.id==self.tbl_bin_associations.c.bin))))
1025
1026         mapper(Component, self.tbl_component,
1027                properties = dict(component_id = self.tbl_component.c.id,
1028                                  component_name = self.tbl_component.c.name))
1029
1030         mapper(DBConfig, self.tbl_config,
1031                properties = dict(config_id = self.tbl_config.c.id))
1032
1033         mapper(ContentAssociation, self.tbl_content_associations,
1034                properties = dict(ca_id = self.tbl_content_associations.c.id,
1035                                  filename_id = self.tbl_content_associations.c.filename,
1036                                  filename    = relation(ContentFilename),
1037                                  filepath_id = self.tbl_content_associations.c.filepath,
1038                                  filepath    = relation(ContentFilepath),
1039                                  binary_id   = self.tbl_content_associations.c.binary_pkg,
1040                                  binary      = relation(Binary)))
1041
1042
1043         mapper(ContentFilename, self.tbl_content_file_names,
1044                properties = dict(cafilename_id = self.tbl_content_file_names.c.id,
1045                                  filename = self.tbl_content_file_names.c.file))
1046
1047         mapper(ContentFilepath, self.tbl_content_file_paths,
1048                properties = dict(cafilepath_id = self.tbl_content_file_paths.c.id,
1049                                  filepath = self.tbl_content_file_paths.c.path))
1050
1051         mapper(DSCFile, self.tbl_dsc_files,
1052                properties = dict(dscfile_id = self.tbl_dsc_files.c.id,
1053                                  source_id = self.tbl_dsc_files.c.source,
1054                                  source = relation(Source),
1055                                  poolfile_id = self.tbl_dsc_files.c.file,
1056                                  poolfile = relation(PoolFile)))
1057
1058         mapper(PoolFile, self.tbl_files,
1059                properties = dict(file_id = self.tbl_files.c.id,
1060                                  filesize = self.tbl_files.c.size,
1061                                  location_id = self.tbl_files.c.location,
1062                                  location = relation(Location)))
1063
1064         mapper(Fingerprint, self.tbl_fingerprint,
1065                properties = dict(fingerprint_id = self.tbl_fingerprint.c.id,
1066                                  uid_id = self.tbl_fingerprint.c.uid,
1067                                  uid = relation(Uid),
1068                                  keyring_id = self.tbl_fingerprint.c.keyring,
1069                                  keyring = relation(Keyring)))
1070
1071         mapper(Keyring, self.tbl_keyrings,
1072                properties = dict(keyring_name = self.tbl_keyrings.c.name,
1073                                  keyring_id = self.tbl_keyrings.c.id))
1074
1075         mapper(Location, self.tbl_location,
1076                properties = dict(location_id = self.tbl_location.c.id,
1077                                  component_id = self.tbl_location.c.component,
1078                                  component = relation(Component),
1079                                  archive_id = self.tbl_location.c.archive,
1080                                  archive = relation(Archive),
1081                                  archive_type = self.tbl_location.c.type))
1082
1083         mapper(Maintainer, self.tbl_maintainer,
1084                properties = dict(maintainer_id = self.tbl_maintainer.c.id))
1085
1086         mapper(Override, self.tbl_override,
1087                properties = dict(suite_id = self.tbl_override.c.suite,
1088                                  suite = relation(Suite),
1089                                  component_id = self.tbl_override.c.component,
1090                                  component = relation(Component),
1091                                  priority_id = self.tbl_override.c.priority,
1092                                  priority = relation(Priority),
1093                                  section_id = self.tbl_override.c.section,
1094                                  section = relation(Section),
1095                                  overridetype_id = self.tbl_override.c.type,
1096                                  overridetype = relation(OverrideType)))
1097
1098         mapper(OverrideType, self.tbl_override_type,
1099                properties = dict(overridetype = self.tbl_override_type.c.type,
1100                                  overridetype_id = self.tbl_override_type.c.id))
1101
1102         mapper(PendingContentAssociation, self.tbl_pending_content_associations,
1103                properties = dict(pca_id = self.tbl_pending_content_associations.c.id,
1104                                  filepath_id = self.tbl_pending_content_associations.c.filepath,
1105                                  filepath = relation(ContentFilepath),
1106                                  filename_id = self.tbl_pending_content_associations.c.filename,
1107                                  filename = relation(ContentFilename)))
1108
1109         mapper(Priority, self.tbl_priority,
1110                properties = dict(priority_id = self.tbl_priority.c.id))
1111
1112         mapper(Queue, self.tbl_queue,
1113                properties = dict(queue_id = self.tbl_queue.c.id))
1114
1115         mapper(QueueBuild, self.tbl_queue_build,
1116                properties = dict(suite_id = self.tbl_queue_build.c.suite,
1117                                  queue_id = self.tbl_queue_build.c.queue,
1118                                  queue = relation(Queue)))
1119
1120         mapper(Section, self.tbl_section,
1121                properties = dict(section_id = self.tbl_section.c.id))
1122
1123         mapper(Source, self.tbl_source,
1124                properties = dict(source_id = self.tbl_source.c.id,
1125                                  version = self.tbl_source.c.version,
1126                                  maintainer_id = self.tbl_source.c.maintainer,
1127                                  maintainer = relation(Maintainer,
1128                                                        primaryjoin=(self.tbl_source.c.maintainer==self.tbl_maintainer.c.id)),
1129                                  poolfile_id = self.tbl_source.c.file,
1130                                  poolfile = relation(PoolFile),
1131                                  fingerprint_id = self.tbl_source.c.sig_fpr,
1132                                  fingerprint = relation(Fingerprint),
1133                                  changedby_id = self.tbl_source.c.changedby,
1134                                  changedby = relation(Maintainer,
1135                                                       primaryjoin=(self.tbl_source.c.changedby==self.tbl_maintainer.c.id)),
1136                                  srcfiles = relation(DSCFile,
1137                                                      primaryjoin=(self.tbl_source.c.id==self.tbl_dsc_files.c.source)),
1138                                  srcassociations = relation(SrcAssociation,
1139                                                             primaryjoin=(self.tbl_source.c.id==self.tbl_src_associations.c.source))))
1140
1141         mapper(SrcAssociation, self.tbl_src_associations,
1142                properties = dict(sa_id = self.tbl_src_associations.c.id,
1143                                  suite_id = self.tbl_src_associations.c.suite,
1144                                  suite = relation(Suite),
1145                                  source_id = self.tbl_src_associations.c.source,
1146                                  source = relation(Source)))
1147
1148         mapper(SrcUploader, self.tbl_src_uploaders,
1149                properties = dict(uploader_id = self.tbl_src_uploaders.c.id,
1150                                  source_id = self.tbl_src_uploaders.c.source,
1151                                  source = relation(Source,
1152                                                    primaryjoin=(self.tbl_src_uploaders.c.source==self.tbl_source.c.id)),
1153                                  maintainer_id = self.tbl_src_uploaders.c.maintainer,
1154                                  maintainer = relation(Maintainer,
1155                                                        primaryjoin=(self.tbl_src_uploaders.c.maintainer==self.tbl_maintainer.c.id))))
1156
1157         mapper(Suite, self.tbl_suite,
1158                properties = dict(suite_id = self.tbl_suite.c.id))
1159
1160         mapper(SuiteArchitecture, self.tbl_suite_architectures,
1161                properties = dict(suite_id = self.tbl_suite_architectures.c.suite,
1162                                  suite = relation(Suite),
1163                                  arch_id = self.tbl_suite_architectures.c.architecture,
1164                                  architecture = relation(Architecture)))
1165
1166         mapper(Uid, self.tbl_uid,
1167                properties = dict(uid_id = self.tbl_uid.c.id))
1168
1169     ## Connection functions
1170     def __createconn(self):
1171         from config import Config
1172         cnf = Config()
1173         if cnf["DB::Host"]:
1174             # TCP/IP
1175             connstr = "postgres://%s" % cnf["DB::Host"]
1176             if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
1177                 connstr += ":%s" % cnf["DB::Port"]
1178             connstr += "/%s" % cnf["DB::Name"]
1179         else:
1180             # Unix Socket
1181             connstr = "postgres:///%s" % cnf["DB::Name"]
1182             if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
1183                 connstr += "?port=%s" % cnf["DB::Port"]
1184
1185         self.db_pg   = create_engine(connstr, echo=self.debug)
1186         self.db_meta = MetaData()
1187         self.db_meta.bind = self.db_pg
1188         self.db_smaker = sessionmaker(bind=self.db_pg,
1189                                       autoflush=True,
1190                                       autocommit=False)
1191
1192         self.__setuptables()
1193         self.__setupmappers()
1194
1195     def session(self):
1196         return self.db_smaker()
1197
1198 __all__.append('DBConn')
1199