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