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 from singleton import Singleton
45 ################################################################################
47 class Architecture(object):
48 def __init__(self, *args, **kwargs):
52 return '<Architecture %s>' % self.arch_string
54 def get_architecture(architecture, session=None):
56 Returns database id for given C{architecture}.
58 @type architecture: string
59 @param architecture: The name of the architecture
61 @type session: Session
62 @param session: Optional SQLA session object (a temporary one will be
63 generated if not supplied)
66 @return: Architecture object for the given arch (None if not present)
70 session = DBConn().session()
71 q = session.query(Architecture).filter_by(arch_string=architecture)
76 class Archive(object):
77 def __init__(self, *args, **kwargs):
81 return '<Archive %s>' % self.name
83 def get_archive(archive, session=None):
85 returns database id for given c{archive}.
88 @param archive: the name of the arhive
90 @type session: Session
91 @param session: Optional SQLA session object (a temporary one will be
92 generated if not supplied)
95 @return: Archive object for the given name (None if not present)
98 archive = archive.lower()
100 session = DBConn().session()
101 q = session.query(Archive).filter_by(archive_name=archive)
107 class BinAssociation(object):
108 def __init__(self, *args, **kwargs):
112 return '<BinAssociation %s (%s, %s)>' % (self.ba_id, self.binary, self.suite)
114 class Binary(object):
115 def __init__(self, *args, **kwargs):
119 return '<Binary %s (%s, %s)>' % (self.package, self.version, self.architecture)
121 def get_binary_from_id(id, session=None):
123 Returns Binary object for given C{id}
126 @param id: Id of the required binary
128 @type session: Session
129 @param session: Optional SQLA session object (a temporary one will be
130 generated if not supplied)
133 @return: Binary object for the given binary (None if not present)
136 session = DBConn().session()
137 q = session.query(Binary).filter_by(binary_id=id)
142 def get_binaries_from_name(package, session=None):
144 Returns list of Binary objects for given C{package} name
147 @param package: Binary package name to search for
149 @type session: Session
150 @param session: Optional SQL session object (a temporary one will be
151 generated if not supplied)
154 @return: list of Binary objects for the given name (may be empty)
157 session = DBConn().session()
158 return session.query(Binary).filter_by(package=package).all()
160 class Component(object):
161 def __init__(self, *args, **kwargs):
165 return '<Component %s>' % self.component_name
167 def get_component(component, session=None):
169 Returns database id for given C{component}.
171 @type component: string
172 @param component: The name of the override type
175 @return: the database id for the given component
178 component = component.lower()
180 session = DBConn().session()
181 q = session.query(Component).filter_by(component_name=component)
186 class DBConfig(object):
187 def __init__(self, *args, **kwargs):
191 return '<DBConfig %s>' % self.name
193 class ContentFilename(object):
194 def __init__(self, *args, **kwargs):
198 return '<ContentFilename %s>' % self.filename
200 class ContentFilepath(object):
201 def __init__(self, *args, **kwargs):
205 return '<ContentFilepath %s>' % self.filepath
207 class ContentAssociations(object):
208 def __init__(self, *args, **kwargs):
212 return '<ContentAssociation %s>' % self.ca_id
214 class DSCFile(object):
215 def __init__(self, *args, **kwargs):
219 return '<DSCFile %s>' % self.dscfile_id
221 class PoolFile(object):
222 def __init__(self, *args, **kwargs):
226 return '<PoolFile %s>' % self.filename
228 class Fingerprint(object):
229 def __init__(self, *args, **kwargs):
233 return '<Fingerprint %s>' % self.fingerprint
235 class Keyring(object):
236 def __init__(self, *args, **kwargs):
240 return '<Keyring %s>' % self.keyring_name
242 class Location(object):
243 def __init__(self, *args, **kwargs):
247 return '<Location %s (%s)>' % (self.path, self.location_id)
249 class Maintainer(object):
250 def __init__(self, *args, **kwargs):
254 return '''<Maintainer '%s' (%s)>''' % (self.name, self.maintainer_id)
256 class Override(object):
257 def __init__(self, *args, **kwargs):
261 return '<Override %s (%s)>' % (self.package, self.suite_id)
263 class OverrideType(object):
264 def __init__(self, *args, **kwargs):
268 return '<OverrideType %s>' % self.overridetype
270 def get_override_type(override_type, session=None):
272 Returns OverrideType object for given C{override type}.
274 @type override_type: string
275 @param override_type: The name of the override type
277 @type session: Session
278 @param session: Optional SQLA session object (a temporary one will be
279 generated if not supplied)
282 @return: the database id for the given override type
286 session = DBConn().session()
287 q = session.query(Priority).filter_by(priority=priority)
292 class PendingContentAssociation(object):
293 def __init__(self, *args, **kwargs):
297 return '<PendingContentAssociation %s>' % self.pca_id
299 class Priority(object):
300 def __init__(self, *args, **kwargs):
304 return '<Priority %s (%s)>' % (self.priority, self.priority_id)
306 def get_priority(priority, session=None):
308 Returns Priority object for given C{priority name}.
310 @type priority: string
311 @param priority: The name of the priority
313 @type session: Session
314 @param session: Optional SQLA session object (a temporary one will be
315 generated if not supplied)
318 @return: Priority object for the given priority
322 session = DBConn().session()
323 q = session.query(Priority).filter_by(priority=priority)
329 def __init__(self, *args, **kwargs):
333 return '<Queue %s>' % self.queue_name
335 class QueueBuild(object):
336 def __init__(self, *args, **kwargs):
340 return '<QueueBuild %s (%s)>' % (self.filename, self.queue_id)
342 class Section(object):
343 def __init__(self, *args, **kwargs):
347 return '<Section %s>' % self.section
349 def get_section(section, session=None):
351 Returns Section object for given C{section name}.
353 @type section: string
354 @param section: The name of the section
356 @type session: Session
357 @param session: Optional SQLA session object (a temporary one will be
358 generated if not supplied)
361 @return: Section object for the given section name
365 session = DBConn().session()
366 q = session.query(Section).filter_by(section=section)
371 class Source(object):
372 def __init__(self, *args, **kwargs):
376 return '<Source %s (%s)>' % (self.source, self.version)
378 def get_sources_from_name(source, session=None):
380 Returns list of Source objects for given C{source} name
383 @param source: Source package name to search for
385 @type session: Session
386 @param session: Optional SQL session object (a temporary one will be
387 generated if not supplied)
390 @return: list of Source objects for the given name (may be empty)
393 session = DBConn().session()
394 return session.query(Source).filter_by(source=source).all()
396 def get_source_in_suite(source, suite, session=None):
398 Returns list of Source objects for a combination of C{source} and C{suite}.
400 - B{source} - source package name, eg. I{mailfilter}, I{bbdb}, I{glibc}
401 - B{suite} - a suite name, eg. I{unstable}
404 @param source: source package name
407 @param suite: the suite name
410 @return: the version for I{source} in I{suite}
414 session = DBConn().session()
415 q = session.query(SrcAssociation)
416 q = q.join('source').filter_by(source=source)
417 q = q.join('suite').filter_by(suite_name=suite)
420 # ???: Maybe we should just return the SrcAssociation object instead
421 return q.one().source
423 class SrcAssociation(object):
424 def __init__(self, *args, **kwargs):
428 return '<SrcAssociation %s (%s, %s)>' % (self.sa_id, self.source, self.suite)
430 class SrcUploader(object):
431 def __init__(self, *args, **kwargs):
435 return '<SrcUploader %s>' % self.uploader_id
438 def __init__(self, *args, **kwargs):
442 return '<Suite %s>' % self.suite_name
444 def get_suite(suite, session=None):
446 Returns Suite object for given C{suite name}.
449 @param suite: The name of the suite
451 @type session: Session
452 @param session: Optional SQLA session object (a temporary one will be
453 generated if not supplied)
456 @return: Suite object for the requested suite name (None if not presenT)
460 session = DBConn().session()
461 q = session.query(Suite).filter_by(suite_name=suite)
466 class SuiteArchitecture(object):
467 def __init__(self, *args, **kwargs):
471 return '<SuiteArchitecture (%s, %s)>' % (self.suite_id, self.arch_id)
474 def __init__(self, *args, **kwargs):
478 return '<Uid %s (%s)>' % (self.uid, self.name)
480 ################################################################################
482 class DBConn(Singleton):
484 database module init.
486 def __init__(self, *args, **kwargs):
487 super(DBConn, self).__init__(*args, **kwargs)
489 def _startup(self, *args, **kwargs):
491 if kwargs.has_key('debug'):
495 def __setuptables(self):
496 self.tbl_architecture = Table('architecture', self.db_meta, autoload=True)
497 self.tbl_archive = Table('archive', self.db_meta, autoload=True)
498 self.tbl_bin_associations = Table('bin_associations', self.db_meta, autoload=True)
499 self.tbl_binaries = Table('binaries', self.db_meta, autoload=True)
500 self.tbl_component = Table('component', self.db_meta, autoload=True)
501 self.tbl_config = Table('config', self.db_meta, autoload=True)
502 self.tbl_content_associations = Table('content_associations', self.db_meta, autoload=True)
503 self.tbl_content_file_names = Table('content_file_names', self.db_meta, autoload=True)
504 self.tbl_content_file_paths = Table('content_file_paths', self.db_meta, autoload=True)
505 self.tbl_dsc_files = Table('dsc_files', self.db_meta, autoload=True)
506 self.tbl_files = Table('files', self.db_meta, autoload=True)
507 self.tbl_fingerprint = Table('fingerprint', self.db_meta, autoload=True)
508 self.tbl_keyrings = Table('keyrings', self.db_meta, autoload=True)
509 self.tbl_location = Table('location', self.db_meta, autoload=True)
510 self.tbl_maintainer = Table('maintainer', self.db_meta, autoload=True)
511 self.tbl_override = Table('override', self.db_meta, autoload=True)
512 self.tbl_override_type = Table('override_type', self.db_meta, autoload=True)
513 self.tbl_pending_content_associations = Table('pending_content_associations', self.db_meta, autoload=True)
514 self.tbl_priority = Table('priority', self.db_meta, autoload=True)
515 self.tbl_queue = Table('queue', self.db_meta, autoload=True)
516 self.tbl_queue_build = Table('queue_build', self.db_meta, autoload=True)
517 self.tbl_section = Table('section', self.db_meta, autoload=True)
518 self.tbl_source = Table('source', self.db_meta, autoload=True)
519 self.tbl_src_associations = Table('src_associations', self.db_meta, autoload=True)
520 self.tbl_src_uploaders = Table('src_uploaders', self.db_meta, autoload=True)
521 self.tbl_suite = Table('suite', self.db_meta, autoload=True)
522 self.tbl_suite_architectures = Table('suite_architectures', self.db_meta, autoload=True)
523 self.tbl_uid = Table('uid', self.db_meta, autoload=True)
525 def __setupmappers(self):
526 mapper(Architecture, self.tbl_architecture,
527 properties = dict(arch_id = self.tbl_architecture.c.id))
529 mapper(Archive, self.tbl_archive,
530 properties = dict(archive_id = self.tbl_archive.c.id,
531 archive_name = self.tbl_archive.c.name))
533 mapper(BinAssociation, self.tbl_bin_associations,
534 properties = dict(ba_id = self.tbl_bin_associations.c.id,
535 suite_id = self.tbl_bin_associations.c.suite,
536 suite = relation(Suite),
537 binary_id = self.tbl_bin_associations.c.bin,
538 binary = relation(Binary)))
540 mapper(Binary, self.tbl_binaries,
541 properties = dict(binary_id = self.tbl_binaries.c.id,
542 package = self.tbl_binaries.c.package,
543 version = self.tbl_binaries.c.version,
544 maintainer_id = self.tbl_binaries.c.maintainer,
545 maintainer = relation(Maintainer),
546 source_id = self.tbl_binaries.c.source,
547 source = relation(Source),
548 arch_id = self.tbl_binaries.c.architecture,
549 architecture = relation(Architecture),
550 poolfile_id = self.tbl_binaries.c.file,
551 poolfile = relation(PoolFile),
552 binarytype = self.tbl_binaries.c.type,
553 fingerprint_id = self.tbl_binaries.c.sig_fpr,
554 fingerprint = relation(Fingerprint),
555 install_date = self.tbl_binaries.c.install_date,
556 binassociations = relation(BinAssociation,
557 primaryjoin=(self.tbl_binaries.c.id==self.tbl_bin_associations.c.bin))))
559 mapper(Component, self.tbl_component,
560 properties = dict(component_id = self.tbl_component.c.id,
561 component_name = self.tbl_component.c.name))
563 mapper(DBConfig, self.tbl_config,
564 properties = dict(config_id = self.tbl_config.c.id))
566 mapper(ContentAssociations, self.tbl_content_associations,
567 properties = dict(ca_id = self.tbl_content_associations.c.id,
568 filename_id = self.tbl_content_associations.c.filename,
569 filename = relation(ContentFilename),
570 filepath_id = self.tbl_content_associations.c.filepath,
571 filepath = relation(ContentFilepath),
572 binary_id = self.tbl_content_associations.c.binary_pkg,
573 binary = relation(Binary)))
576 mapper(ContentFilename, self.tbl_content_file_names,
577 properties = dict(cafilename_id = self.tbl_content_file_names.c.id,
578 filename = self.tbl_content_file_names.c.file))
580 mapper(ContentFilepath, self.tbl_content_file_paths,
581 properties = dict(cafilepath_id = self.tbl_content_file_paths.c.id,
582 filepath = self.tbl_content_file_paths.c.path))
584 mapper(DSCFile, self.tbl_dsc_files,
585 properties = dict(dscfile_id = self.tbl_dsc_files.c.id,
586 source_id = self.tbl_dsc_files.c.source,
587 source = relation(Source),
588 poolfile_id = self.tbl_dsc_files.c.file,
589 poolfile = relation(PoolFile)))
591 mapper(PoolFile, self.tbl_files,
592 properties = dict(file_id = self.tbl_files.c.id,
593 filesize = self.tbl_files.c.size,
594 location_id = self.tbl_files.c.location,
595 location = relation(Location)))
597 mapper(Fingerprint, self.tbl_fingerprint,
598 properties = dict(fingerprint_id = self.tbl_fingerprint.c.id,
599 uid_id = self.tbl_fingerprint.c.uid,
601 keyring_id = self.tbl_fingerprint.c.keyring,
602 keyring = relation(Keyring)))
604 mapper(Keyring, self.tbl_keyrings,
605 properties = dict(keyring_name = self.tbl_keyrings.c.name,
606 keyring_id = self.tbl_keyrings.c.id))
608 mapper(Location, self.tbl_location,
609 properties = dict(location_id = self.tbl_location.c.id,
610 component_id = self.tbl_location.c.component,
611 component = relation(Component),
612 archive_id = self.tbl_location.c.archive,
613 archive = relation(Archive),
614 archive_type = self.tbl_location.c.type))
616 mapper(Maintainer, self.tbl_maintainer,
617 properties = dict(maintainer_id = self.tbl_maintainer.c.id))
619 mapper(Override, self.tbl_override,
620 properties = dict(suite_id = self.tbl_override.c.suite,
621 suite = relation(Suite),
622 component_id = self.tbl_override.c.component,
623 component = relation(Component),
624 priority_id = self.tbl_override.c.priority,
625 priority = relation(Priority),
626 section_id = self.tbl_override.c.section,
627 section = relation(Section),
628 overridetype_id = self.tbl_override.c.type,
629 overridetype = relation(OverrideType)))
631 mapper(OverrideType, self.tbl_override_type,
632 properties = dict(overridetype = self.tbl_override_type.c.type,
633 overridetype_id = self.tbl_override_type.c.id))
635 mapper(PendingContentAssociation, self.tbl_pending_content_associations,
636 properties = dict(pca_id = self.tbl_pending_content_associations.c.id,
637 filepath_id = self.tbl_pending_content_associations.c.filepath,
638 filepath = relation(ContentFilepath),
639 filename_id = self.tbl_pending_content_associations.c.filename,
640 filename = relation(ContentFilename)))
642 mapper(Priority, self.tbl_priority,
643 properties = dict(priority_id = self.tbl_priority.c.id))
645 mapper(Queue, self.tbl_queue,
646 properties = dict(queue_id = self.tbl_queue.c.id))
648 mapper(QueueBuild, self.tbl_queue_build,
649 properties = dict(suite_id = self.tbl_queue_build.c.suite,
650 queue_id = self.tbl_queue_build.c.queue,
651 queue = relation(Queue)))
653 mapper(Section, self.tbl_section,
654 properties = dict(section_id = self.tbl_section.c.id))
656 mapper(Source, self.tbl_source,
657 properties = dict(source_id = self.tbl_source.c.id,
658 version = self.tbl_source.c.version,
659 maintainer_id = self.tbl_source.c.maintainer,
660 maintainer = relation(Maintainer,
661 primaryjoin=(self.tbl_source.c.maintainer==self.tbl_maintainer.c.id)),
662 poolfile_id = self.tbl_source.c.file,
663 poolfile = relation(PoolFile),
664 fingerprint_id = self.tbl_source.c.sig_fpr,
665 fingerprint = relation(Fingerprint),
666 changedby_id = self.tbl_source.c.changedby,
667 changedby = relation(Maintainer,
668 primaryjoin=(self.tbl_source.c.changedby==self.tbl_maintainer.c.id)),
669 srcfiles = relation(DSCFile,
670 primaryjoin=(self.tbl_source.c.id==self.tbl_dsc_files.c.source)),
671 srcassociations = relation(SrcAssociation,
672 primaryjoin=(self.tbl_source.c.id==self.tbl_src_associations.c.source))))
674 mapper(SrcAssociation, self.tbl_src_associations,
675 properties = dict(sa_id = self.tbl_src_associations.c.id,
676 suite_id = self.tbl_src_associations.c.suite,
677 suite = relation(Suite),
678 source_id = self.tbl_src_associations.c.source,
679 source = relation(Source)))
681 mapper(SrcUploader, self.tbl_src_uploaders,
682 properties = dict(uploader_id = self.tbl_src_uploaders.c.id,
683 source_id = self.tbl_src_uploaders.c.source,
684 source = relation(Source,
685 primaryjoin=(self.tbl_src_uploaders.c.source==self.tbl_source.c.id)),
686 maintainer_id = self.tbl_src_uploaders.c.maintainer,
687 maintainer = relation(Maintainer,
688 primaryjoin=(self.tbl_src_uploaders.c.maintainer==self.tbl_maintainer.c.id))))
690 mapper(Suite, self.tbl_suite,
691 properties = dict(suite_id = self.tbl_suite.c.id))
693 mapper(SuiteArchitecture, self.tbl_suite_architectures,
694 properties = dict(suite_id = self.tbl_suite_architectures.c.suite,
695 suite = relation(Suite),
696 arch_id = self.tbl_suite_architectures.c.architecture,
697 architecture = relation(Architecture)))
699 mapper(Uid, self.tbl_uid,
700 properties = dict(uid_id = self.tbl_uid.c.id))
702 ## Connection functions
703 def __createconn(self):
704 from config import Config
708 connstr = "postgres://%s" % cnf["DB::Host"]
709 if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
710 connstr += ":%s" % cnf["DB::Port"]
711 connstr += "/%s" % cnf["DB::Name"]
714 connstr = "postgres:///%s" % cnf["DB::Name"]
715 if cnf["DB::Port"] and cnf["DB::Port"] != "-1":
716 connstr += "?port=%s" % cnf["DB::Port"]
718 self.db_pg = create_engine(connstr, echo=self.debug)
719 self.db_meta = MetaData()
720 self.db_meta.bind = self.db_pg
721 self.db_smaker = sessionmaker(bind=self.db_pg,
726 self.__setupmappers()
729 return self.db_smaker()
731 def prepare(self,name,statement):
732 if not self.prepared_statements.has_key(name):
733 pgc.execute(statement)
734 self.prepared_statements[name] = statement
737 def get_location_id(self, location, component, archive):
739 Returns database id for the location behind the given combination of
740 - B{location} - the path of the location, eg. I{/srv/ftp.debian.org/ftp/pool/}
741 - B{component} - the id of the component as returned by L{get_component_id}
742 - B{archive} - the id of the archive as returned by L{get_archive_id}
743 Results are kept in a cache during runtime to minimize database queries.
745 @type location: string
746 @param location: the path of the location
749 @param component: the id of the component
752 @param archive: the id of the archive
755 @return: the database id for the location
759 archive_id = self.get_archive_id(archive)
767 component_id = self.get_component_id(component)
769 res = self.__get_single_id("SELECT id FROM location WHERE path=%(location)s AND component=%(component)s AND archive=%(archive)s",
770 {'location': location,
771 'archive': int(archive_id),
772 'component': component_id}, cachename='location')
774 res = self.__get_single_id("SELECT id FROM location WHERE path=%(location)s AND archive=%(archive)d",
775 {'location': location, 'archive': archive_id, 'component': ''}, cachename='location')
781 def get_files_id (self, filename, size, md5sum, location_id):
783 Returns -1, -2 or the file_id for filename, if its C{size} and C{md5sum} match an
786 The database is queried using the C{filename} and C{location_id}. If a file does exist
787 at that location, the existing size and md5sum are checked against the provided
788 parameters. A size or checksum mismatch returns -2. If more than one entry is
789 found within the database, a -1 is returned, no result returns None, otherwise
792 @type filename: string
793 @param filename: the filename of the file to check against the DB
796 @param size: the size of the file to check against the DB
799 @param md5sum: the md5sum of the file to check against the DB
801 @type location_id: int
802 @param location_id: the id of the location as returned by L{get_location_id}
805 @return: Various return values are possible:
806 - -2: size/checksum error
807 - -1: more than one file found in database
808 - None: no file found in database
812 values = {'filename' : filename,
813 'location' : location_id}
816 query = """SELECT id, size, md5sum
818 WHERE filename = %(filename)s AND location = %(location)s"""
820 cursor = self.db_con.cursor()
821 cursor.execute( query, values )
823 if cursor.rowcount == 0:
826 elif cursor.rowcount != 1:
830 row = cursor.fetchone()
832 if row[1] != int(size) or row[2] != md5sum:
841 def get_or_set_contents_file_id(self, filename):
843 Returns database id for given filename.
845 If no matching file is found, a row is inserted.
847 @type filename: string
848 @param filename: The filename
851 @return: the database id for the given component
854 values={'value': filename}
855 query = "SELECT id FROM content_file_names WHERE file = %(value)s"
857 c = self.db_con.cursor()
858 c.execute( "INSERT INTO content_file_names VALUES (DEFAULT, %(value)s) RETURNING id",
865 traceback.print_exc()
868 def get_or_set_contents_path_id(self, path):
870 Returns database id for given path.
872 If no matching file is found, a row is inserted.
875 @param path: The filename
878 @return: the database id for the given component
881 values={'value': path}
882 query = "SELECT id FROM content_file_paths WHERE path = %(value)s"
884 c = self.db_con.cursor()
885 c.execute( "INSERT INTO content_file_paths VALUES (DEFAULT, %(value)s) RETURNING id",
892 traceback.print_exc()
895 def get_suite_architectures(self, suite):
897 Returns list of architectures for C{suite}.
899 @type suite: string, int
900 @param suite: the suite name or the suite_id
903 @return: the list of architectures for I{suite}
907 if type(suite) == str:
908 suite_id = self.get_suite_id(suite)
909 elif type(suite) == int:
914 c = self.db_con.cursor()
915 c.execute( """SELECT a.arch_string FROM suite_architectures sa
916 JOIN architecture a ON (a.id = sa.architecture)
917 WHERE suite='%s'""" % suite_id )
919 return map(lambda x: x[0], c.fetchall())
921 def insert_content_paths(self, bin_id, fullpaths):
923 Make sure given path is associated with given binary id
926 @param bin_id: the id of the binary
927 @type fullpaths: list
928 @param fullpaths: the list of paths of the file being associated with the binary
930 @return: True upon success
933 c = self.db_con.cursor()
935 c.execute("BEGIN WORK")
938 for fullpath in fullpaths:
939 (path, file) = os.path.split(fullpath)
941 # Get the necessary IDs ...
942 file_id = self.get_or_set_contents_file_id(file)
943 path_id = self.get_or_set_contents_path_id(path)
945 c.execute("""INSERT INTO content_associations
946 (binary_pkg, filepath, filename)
947 VALUES ( '%d', '%d', '%d')""" % (bin_id, path_id, file_id) )
952 traceback.print_exc()
953 c.execute("ROLLBACK")
956 def insert_pending_content_paths(self, package, fullpaths):
958 Make sure given paths are temporarily associated with given
962 @param package: the package to associate with should have been read in from the binary control file
963 @type fullpaths: list
964 @param fullpaths: the list of paths of the file being associated with the binary
966 @return: True upon success
969 c = self.db_con.cursor()
971 c.execute("BEGIN WORK")
973 arch_id = self.get_architecture_id(package['Architecture'])
975 # Remove any already existing recorded files for this package
976 c.execute("""DELETE FROM pending_content_associations
977 WHERE package=%(Package)s
978 AND version=%(Version)s
979 AND architecture=%(ArchID)s""", {'Package': package['Package'],
980 'Version': package['Version'],
983 for fullpath in fullpaths:
984 (path, file) = os.path.split(fullpath)
986 if path.startswith( "./" ):
988 # Get the necessary IDs ...
989 file_id = self.get_or_set_contents_file_id(file)
990 path_id = self.get_or_set_contents_path_id(path)
992 c.execute("""INSERT INTO pending_content_associations
993 (package, version, architecture, filepath, filename)
994 VALUES (%%(Package)s, %%(Version)s, '%d', '%d', '%d')"""
995 % (arch_id, path_id, file_id), package )
1000 traceback.print_exc()
1001 c.execute("ROLLBACK")