Package daklib :: Module dbconn
[hide private]
[frames] | no frames]

Source Code for Module daklib.dbconn

   1  """ DB access class 
   2   
   3  @contact: Debian FTPMaster <ftpmaster@debian.org> 
   4  @copyright: 2000, 2001, 2002, 2003, 2004, 2006  James Troup <james@nocrew.org> 
   5  @copyright: 2008-2009  Mark Hymers <mhy@debian.org> 
   6  @copyright: 2009, 2010  Joerg Jaspert <joerg@debian.org> 
   7  @copyright: 2009  Mike O'Connor <stew@debian.org> 
   8  @license: GNU General Public License version 2 or later 
   9  """ 
  10   
  11  # This program is free software; you can redistribute it and/or modify 
  12  # it under the terms of the GNU General Public License as published by 
  13  # the Free Software Foundation; either version 2 of the License, or 
  14  # (at your option) any later version. 
  15   
  16  # This program is distributed in the hope that it will be useful, 
  17  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  18  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  19  # GNU General Public License for more details. 
  20   
  21  # You should have received a copy of the GNU General Public License 
  22  # along with this program; if not, write to the Free Software 
  23  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  24   
  25  ################################################################################ 
  26   
  27  # < mhy> I need a funny comment 
  28  # < sgran> two peanuts were walking down a dark street 
  29  # < sgran> one was a-salted 
  30  #  * mhy looks up the definition of "funny" 
  31   
  32  ################################################################################ 
  33   
  34  import apt_pkg 
  35  from daklib.gpg import GpgException 
  36  import functools 
  37  import inspect 
  38  import os 
  39  from os.path import normpath 
  40  import re 
  41  import subprocess 
  42  import warnings 
  43   
  44  from debian.debfile import Deb822 
  45  from tarfile import TarFile 
  46   
  47  import sqlalchemy 
  48  from sqlalchemy import create_engine, Table, desc 
  49  from sqlalchemy.orm import sessionmaker, mapper, relation, object_session, \ 
  50      backref, object_mapper 
  51  import sqlalchemy.types 
  52  from sqlalchemy.orm.collections import attribute_mapped_collection 
  53  from sqlalchemy.ext.associationproxy import association_proxy 
  54   
  55  # Don't remove this, we re-export the exceptions to scripts which import us 
  56  from sqlalchemy.exc import * 
  57  from sqlalchemy.orm.exc import NoResultFound 
  58   
  59  from .aptversion import AptVersion 
  60  # Only import Config until Queue stuff is changed to store its config 
  61  # in the database 
  62  from .config import Config 
  63  from .textutils import fix_maintainer 
  64   
  65  # suppress some deprecation warnings in squeeze related to sqlalchemy 
  66  warnings.filterwarnings('ignore', 
  67      "Predicate of partial index .* ignored during reflection", 
  68      SAWarning) 
  69   
  70  from .database.base import Base 
71 72 73 ################################################################################ 74 75 # Patch in support for the debversion field type so that it works during 76 # reflection 77 78 -class DebVersion(sqlalchemy.types.UserDefinedType):
79 - def get_col_spec(self):
80 return "DEBVERSION"
81
82 - def bind_processor(self, dialect):
83 return None
84
85 - def result_processor(self, dialect, coltype):
86 return None
87 88 89 from sqlalchemy.databases import postgresql 90 postgresql.ischema_names['debversion'] = DebVersion 91 92 ################################################################################ 93 94 __all__ = ['IntegrityError', 'SQLAlchemyError', 'DebVersion']
95 96 ################################################################################ 97 98 99 -def session_wrapper(fn):
100 """ 101 Wrapper around common ".., session=None):" handling. If the wrapped 102 function is called without passing 'session', we create a local one 103 and destroy it when the function ends. 104 105 Also attaches a commit_or_flush method to the session; if we created a 106 local session, this is a synonym for session.commit(), otherwise it is a 107 synonym for session.flush(). 108 """ 109 110 def wrapped(*args, **kwargs): 111 private_transaction = False 112 113 # Find the session object 114 session = kwargs.get('session') 115 116 if session is None: 117 if len(args) < len(inspect.getfullargspec(fn).args): 118 # No session specified as last argument or in kwargs 119 private_transaction = True 120 session = kwargs['session'] = DBConn().session() 121 else: 122 # Session is last argument in args 123 session = args[-1] 124 if session is None: 125 args = list(args) 126 session = args[-1] = DBConn().session() 127 private_transaction = True 128 129 if private_transaction: 130 session.commit_or_flush = session.commit 131 else: 132 session.commit_or_flush = session.flush 133 134 try: 135 return fn(*args, **kwargs) 136 finally: 137 if private_transaction: 138 # We created a session; close it. 139 session.close()
140 141 wrapped.__doc__ = fn.__doc__ 142 wrapped.__name__ = fn.__name__ 143 144 return wrapped 145 146 147 __all__.append('session_wrapper')
148 149 ################################################################################ 150 151 152 -class ORMObject:
153 """ 154 ORMObject is a base class for all ORM classes mapped by SQLalchemy. All 155 derived classes must implement the properties() method. 156 """ 157
158 - def properties(self):
159 ''' 160 This method should be implemented by all derived classes and returns a 161 list of the important properties. The properties 'created' and 162 'modified' will be added automatically. A suffix '_count' should be 163 added to properties that are lists or query objects. The most important 164 property name should be returned as the first element in the list 165 because it is used by repr(). 166 ''' 167 return []
168
169 - def classname(self):
170 ''' 171 Returns the name of the class. 172 ''' 173 return type(self).__name__
174
175 - def __repr__(self):
176 ''' 177 Returns a short string representation of the object using the first 178 element from the properties() method. 179 ''' 180 primary_property = self.properties()[0] 181 value = getattr(self, primary_property) 182 return '<%s %s>' % (self.classname(), str(value))
183
184 - def __str__(self):
185 ''' 186 Returns a human readable form of the object using the properties() 187 method. 188 ''' 189 return '<%s(...)>' % (self.classname())
190 191 @classmethod 192 @session_wrapper
193 - def get(cls, primary_key, session=None):
194 ''' 195 This is a support function that allows getting an object by its primary 196 key. 197 198 Architecture.get(3[, session]) 199 200 instead of the more verbose 201 202 session.query(Architecture).get(3) 203 ''' 204 return session.query(cls).get(primary_key)
205
206 - def session(self):
207 ''' 208 Returns the current session that is associated with the object. May 209 return None is object is in detached state. 210 ''' 211 212 return object_session(self)
213
214 - def clone(self, session=None):
215 """ 216 Clones the current object in a new session and returns the new clone. A 217 fresh session is created if the optional session parameter is not 218 provided. The function will fail if a session is provided and has 219 unflushed changes. 220 221 RATIONALE: SQLAlchemy's session is not thread safe. This method clones 222 an existing object to allow several threads to work with their own 223 instances of an ORMObject. 224 225 WARNING: Only persistent (committed) objects can be cloned. Changes 226 made to the original object that are not committed yet will get lost. 227 The session of the new object will always be rolled back to avoid 228 resource leaks. 229 """ 230 231 if self.session() is None: 232 raise RuntimeError( 233 'Method clone() failed for detached object:\n%s' % self) 234 self.session().flush() 235 mapper = object_mapper(self) 236 primary_key = mapper.primary_key_from_instance(self) 237 object_class = self.__class__ 238 if session is None: 239 session = DBConn().session() 240 elif len(session.new) + len(session.dirty) + len(session.deleted) > 0: 241 raise RuntimeError( 242 'Method clone() failed due to unflushed changes in session.') 243 new_object = session.query(object_class).get(primary_key) 244 session.rollback() 245 if new_object is None: 246 raise RuntimeError( 247 'Method clone() failed for non-persistent object:\n%s' % self) 248 return new_object
249 250 251 __all__.append('ORMObject')
252 253 ################################################################################ 254 255 256 -class ACL(ORMObject):
257 - def __repr__(self):
258 return "<ACL {0}>".format(self.name)
259 260 261 __all__.append('ACL')
262 263 264 -class ACLPerSource(ORMObject):
265 - def __repr__(self):
266 return "<ACLPerSource acl={0} fingerprint={1} source={2} reason={3}>".format(self.acl.name, self.fingerprint.fingerprint, self.source, self.reason)
267 268 269 __all__.append('ACLPerSource') 270 271 ################################################################################ 272 273 274 from .database.architecture import Architecture 275 276 __all__.append('Architecture')
277 278 279 @session_wrapper 280 -def get_architecture(architecture, session=None):
281 """ 282 Returns database id for given C{architecture}. 283 284 @type architecture: string 285 @param architecture: The name of the architecture 286 287 @type session: Session 288 @param session: Optional SQLA session object (a temporary one will be 289 generated if not supplied) 290 291 @rtype: Architecture 292 @return: Architecture object for the given arch (None if not present) 293 """ 294 295 q = session.query(Architecture).filter_by(arch_string=architecture) 296 return q.one_or_none()
297 298 299 __all__.append('get_architecture')
300 301 ################################################################################ 302 303 304 -class Archive:
305 - def __init__(self, *args, **kwargs):
306 pass
307
308 - def __repr__(self):
309 return '<Archive %s>' % self.archive_name
310 311 312 __all__.append('Archive')
313 314 315 @session_wrapper 316 -def get_archive(archive, session=None):
317 """ 318 returns database id for given C{archive}. 319 320 @type archive: string 321 @param archive: the name of the arhive 322 323 @type session: Session 324 @param session: Optional SQLA session object (a temporary one will be 325 generated if not supplied) 326 327 @rtype: Archive 328 @return: Archive object for the given name (None if not present) 329 330 """ 331 archive = archive.lower() 332 333 q = session.query(Archive).filter_by(archive_name=archive) 334 return q.one_or_none()
335 336 337 __all__.append('get_archive')
338 339 ################################################################################ 340 341 342 -class ArchiveFile:
343 - def __init__(self, archive=None, component=None, file=None):
344 self.archive = archive 345 self.component = component 346 self.file = file
347 348 @property
349 - def path(self):
350 return os.path.join(self.archive.path, 'pool', self.component.component_name, self.file.filename)
351 352 353 __all__.append('ArchiveFile')
354 355 ################################################################################ 356 357 358 -class BinContents(ORMObject):
359 - def __init__(self, file=None, binary=None):
360 self.file = file 361 self.binary = binary
362
363 - def properties(self):
364 return ['file', 'binary']
365 366 367 __all__.append('BinContents')
368 369 ################################################################################ 370 371 372 -class DBBinary(ORMObject):
373 - def __init__(self, package=None, source=None, version=None, 374 maintainer=None, architecture=None, poolfile=None, 375 binarytype='deb', fingerprint=None):
376 self.package = package 377 self.source = source 378 self.version = version 379 self.maintainer = maintainer 380 self.architecture = architecture 381 self.poolfile = poolfile 382 self.binarytype = binarytype 383 self.fingerprint = fingerprint
384 385 @property
386 - def pkid(self):
387 return self.binary_id
388 389 @property
390 - def name(self):
391 return self.package
392 393 @property
394 - def arch_string(self):
395 return "%s" % self.architecture
396
397 - def properties(self):
398 return ['package', 'version', 'maintainer', 'source', 'architecture', 399 'poolfile', 'binarytype', 'fingerprint', 'install_date', 400 'suites_count', 'binary_id', 'contents_count', 'extra_sources']
401 402 metadata = association_proxy('key', 'value') 403
404 - def scan_contents(self):
405 ''' 406 Yields the contents of the package. Only regular files are yielded and 407 the path names are normalized after converting them from either utf-8 408 or iso8859-1 encoding. It yields the string ' <EMPTY PACKAGE>' if the 409 package does not contain any regular file. 410 ''' 411 fullpath = self.poolfile.fullpath 412 dpkg_cmd = ('dpkg-deb', '--fsys-tarfile', fullpath) 413 dpkg = subprocess.Popen(dpkg_cmd, stdout=subprocess.PIPE) 414 tar = TarFile.open(fileobj=dpkg.stdout, mode='r|') 415 for member in tar.getmembers(): 416 if not member.isdir(): 417 name = normpath(member.name) 418 yield name 419 tar.close() 420 dpkg.stdout.close() 421 dpkg.wait()
422
423 - def read_control(self):
424 ''' 425 Reads the control information from a binary. 426 427 @rtype: text 428 @return: stanza text of the control section. 429 ''' 430 from . import utils 431 fullpath = self.poolfile.fullpath 432 return utils.deb_extract_control(fullpath)
433
434 - def read_control_fields(self):
435 ''' 436 Reads the control information from a binary and return 437 as a dictionary. 438 439 @rtype: dict 440 @return: fields of the control section as a dictionary. 441 ''' 442 stanza = self.read_control() 443 return apt_pkg.TagSection(stanza)
444 445 @property
446 - def proxy(self):
447 session = object_session(self) 448 query = session.query(BinaryMetadata).filter_by(binary=self) 449 return MetadataProxy(session, query)
450 451 452 __all__.append('DBBinary')
453 454 455 @session_wrapper 456 -def get_suites_binary_in(package, session=None):
457 """ 458 Returns list of Suite objects which given C{package} name is in 459 460 @type package: str 461 @param package: DBBinary package name to search for 462 463 @rtype: list 464 @return: list of Suite objects for the given package 465 """ 466 467 return session.query(Suite).filter(Suite.binaries.any(DBBinary.package == package)).all()
468 469 470 __all__.append('get_suites_binary_in')
471 472 473 @session_wrapper 474 -def get_component_by_package_suite(package, suite_list, arch_list=None, session=None):
475 ''' 476 Returns the component name of the newest binary package in suite_list or 477 None if no package is found. The result can be optionally filtered by a list 478 of architecture names. 479 480 @type package: str 481 @param package: DBBinary package name to search for 482 483 @type suite_list: list of str 484 @param suite_list: list of suite_name items 485 486 @type arch_list: list of str 487 @param arch_list: optional list of arch_string items that defaults to [] 488 489 @rtype: str or NoneType 490 @return: name of component or None 491 ''' 492 493 q = session.query(DBBinary).filter_by(package=package). \ 494 join(DBBinary.suites).filter(Suite.suite_name.in_(suite_list)) 495 if arch_list: 496 q = q.join(DBBinary.architecture). \ 497 filter(Architecture.arch_string.in_(arch_list)) 498 binary = q.order_by(desc(DBBinary.version)).first() 499 if binary is None: 500 return None 501 else: 502 return binary.poolfile.component.component_name
503 504 505 __all__.append('get_component_by_package_suite')
506 507 ################################################################################ 508 509 510 -class BuildQueue:
511 - def __init__(self, *args, **kwargs):
512 pass
513
514 - def __repr__(self):
515 return '<BuildQueue %s>' % self.queue_name
516 517 518 __all__.append('BuildQueue')
519 520 ################################################################################ 521 522 523 -class Component(ORMObject):
524 - def __init__(self, component_name=None):
525 self.component_name = component_name
526
527 - def __eq__(self, val):
528 if isinstance(val, str): 529 warnings.warn("comparison with a `str` is deprecated", DeprecationWarning, stacklevel=2) 530 return (self.component_name == val) 531 # This signals to use the normal comparison operator 532 return NotImplemented
533
534 - def __ne__(self, val):
535 if isinstance(val, str): 536 warnings.warn("comparison with a `str` is deprecated", DeprecationWarning, stacklevel=2) 537 return (self.component_name != val) 538 # This signals to use the normal comparison operator 539 return NotImplemented
540 541 __hash__ = ORMObject.__hash__ 542
543 - def properties(self):
544 return ['component_name', 'component_id', 'description', 545 'meets_dfsg', 'overrides_count']
546 547 548 __all__.append('Component')
549 550 551 @session_wrapper 552 -def get_component(component, session=None):
553 """ 554 Returns database id for given C{component}. 555 556 @type component: string 557 @param component: The name of the override type 558 559 @rtype: int 560 @return: the database id for the given component 561 562 """ 563 component = component.lower() 564 565 q = session.query(Component).filter_by(component_name=component) 566 567 return q.one_or_none()
568 569 570 __all__.append('get_component')
571 572 573 -def get_mapped_component_name(component_name):
574 cnf = Config() 575 for m in cnf.value_list("ComponentMappings"): 576 (src, dst) = m.split() 577 if component_name == src: 578 component_name = dst 579 return component_name
580 581 582 __all__.append('get_mapped_component_name')
583 584 585 @session_wrapper 586 -def get_mapped_component(component_name, session=None):
587 """get component after mappings 588 589 Evaluate component mappings from ComponentMappings in dak.conf for the 590 given component name. 591 592 @todo: ansgar wants to get rid of this. It's currently only used for 593 the security archive 594 595 @type component_name: str 596 @param component_name: component name 597 598 @param session: database session 599 600 @rtype: L{daklib.dbconn.Component} or C{None} 601 @return: component after applying maps or C{None} 602 """ 603 component_name = get_mapped_component_name(component_name) 604 component = session.query(Component).filter_by(component_name=component_name).first() 605 return component
606 607 608 __all__.append('get_mapped_component')
609 610 611 @session_wrapper 612 -def get_component_names(session=None):
613 """ 614 Returns list of strings of component names. 615 616 @rtype: list 617 @return: list of strings of component names 618 """ 619 620 return [x.component_name for x in session.query(Component).all()]
621 622 623 __all__.append('get_component_names')
624 625 ################################################################################ 626 627 628 -class DBConfig:
629 - def __init__(self, *args, **kwargs):
630 pass
631
632 - def __repr__(self):
633 return '<DBConfig %s>' % self.name
634 635 636 __all__.append('DBConfig')
637 638 ################################################################################ 639 640 641 -class DSCFile:
642 - def __init__(self, *args, **kwargs):
643 pass
644
645 - def __repr__(self):
646 return '<DSCFile %s>' % self.dscfile_id
647 648 649 __all__.append('DSCFile')
650 651 652 @session_wrapper 653 -def get_dscfiles(dscfile_id=None, source_id=None, poolfile_id=None, session=None):
654 """ 655 Returns a list of DSCFiles which may be empty 656 657 @type dscfile_id: int (optional) 658 @param dscfile_id: the dscfile_id of the DSCFiles to find 659 660 @type source_id: int (optional) 661 @param source_id: the source id related to the DSCFiles to find 662 663 @type poolfile_id: int (optional) 664 @param poolfile_id: the poolfile id related to the DSCFiles to find 665 666 @rtype: list 667 @return: Possibly empty list of DSCFiles 668 """ 669 670 q = session.query(DSCFile) 671 672 if dscfile_id is not None: 673 q = q.filter_by(dscfile_id=dscfile_id) 674 675 if source_id is not None: 676 q = q.filter_by(source_id=source_id) 677 678 if poolfile_id is not None: 679 q = q.filter_by(poolfile_id=poolfile_id) 680 681 return q.all()
682 683 684 __all__.append('get_dscfiles')
685 686 ################################################################################ 687 688 689 -class ExternalOverride(ORMObject):
690 - def __init__(self, *args, **kwargs):
691 pass
692
693 - def __repr__(self):
694 return '<ExternalOverride %s = %s: %s>' % (self.package, self.key, self.value)
695 696 697 __all__.append('ExternalOverride')
698 699 ################################################################################ 700 701 702 -class PoolFile(ORMObject):
703 - def __init__(self, filename=None, filesize=-1, 704 md5sum=None):
705 self.filename = filename 706 self.filesize = filesize 707 self.md5sum = md5sum
708 709 @property
710 - def fullpath(self):
711 session = DBConn().session().object_session(self) 712 af = session.query(ArchiveFile).join(Archive) \ 713 .filter(ArchiveFile.file == self) \ 714 .order_by(Archive.tainted.desc()).first() 715 return af.path
716 717 @property
718 - def component(self):
719 session = DBConn().session().object_session(self) 720 component_id = session.query(ArchiveFile.component_id).filter(ArchiveFile.file == self) \ 721 .group_by(ArchiveFile.component_id).one() 722 return session.query(Component).get(component_id)
723 724 @property
725 - def basename(self):
726 return os.path.basename(self.filename)
727
728 - def properties(self):
729 return ['filename', 'file_id', 'filesize', 'md5sum', 'sha1sum', 730 'sha256sum', 'source', 'binary', 'last_used']
731 732 733 __all__.append('PoolFile')
734 735 ################################################################################ 736 737 738 -class Fingerprint(ORMObject):
739 - def __init__(self, fingerprint=None):
741
742 - def properties(self):
743 return ['fingerprint', 'fingerprint_id', 'keyring', 'uid', 744 'binary_reject']
745 746 747 __all__.append('Fingerprint')
748 749 750 @session_wrapper 751 -def get_fingerprint(fpr, session=None):
752 """ 753 Returns Fingerprint object for given fpr. 754 755 @type fpr: string 756 @param fpr: The fpr to find / add 757 758 @type session: SQLAlchemy 759 @param session: Optional SQL session object (a temporary one will be 760 generated if not supplied). 761 762 @rtype: Fingerprint 763 @return: the Fingerprint object for the given fpr or None 764 """ 765 766 q = session.query(Fingerprint).filter_by(fingerprint=fpr) 767 return q.one_or_none()
768 769 770 __all__.append('get_fingerprint')
771 772 773 @session_wrapper 774 -def get_or_set_fingerprint(fpr, session=None):
775 """ 776 Returns Fingerprint object for given fpr. 777 778 If no matching fpr is found, a row is inserted. 779 780 @type fpr: string 781 @param fpr: The fpr to find / add 782 783 @type session: SQLAlchemy 784 @param session: Optional SQL session object (a temporary one will be 785 generated if not supplied). If not passed, a commit will be performed at 786 the end of the function, otherwise the caller is responsible for commiting. 787 A flush will be performed either way. 788 789 @rtype: Fingerprint 790 @return: the Fingerprint object for the given fpr 791 """ 792 793 q = session.query(Fingerprint).filter_by(fingerprint=fpr) 794 795 try: 796 ret = q.one() 797 except NoResultFound: 798 fingerprint = Fingerprint() 799 fingerprint.fingerprint = fpr 800 session.add(fingerprint) 801 session.commit_or_flush() 802 ret = fingerprint 803 804 return ret
805 806 807 __all__.append('get_or_set_fingerprint')
808 809 ################################################################################ 810 811 # Helper routine for Keyring class 812 813 814 -def get_ldap_name(entry):
815 name = [] 816 for k in ["cn", "mn", "sn"]: 817 ret = entry.get(k) 818 if not ret: 819 continue 820 value = ret[0].decode() 821 if value and value[0] != "-": 822 name.append(value) 823 return " ".join(name)
824
825 ################################################################################ 826 827 828 -class Keyring:
829 keys = {} 830 fpr_lookup = {} 831
832 - def __init__(self, *args, **kwargs):
833 pass
834
835 - def __repr__(self):
836 return '<Keyring %s>' % self.keyring_name
837
838 - def de_escape_gpg_str(self, txt):
839 esclist = re.split(r'(\\x..)', txt) 840 for x in range(1, len(esclist), 2): 841 esclist[x] = "%c" % (int(esclist[x][2:], 16)) 842 return "".join(esclist)
843
844 - def parse_address(self, uid):
845 """parses uid and returns a tuple of real name and email address""" 846 import email.utils 847 (name, address) = email.utils.parseaddr(uid) 848 name = re.sub(r"\s*[(].*[)]", "", name) 849 name = self.de_escape_gpg_str(name) 850 if name == "": 851 name = uid 852 return (name, address)
853
854 - def load_keys(self, keyring):
855 if not self.keyring_id: 856 raise Exception('Must be initialized with database information') 857 858 cmd = ["gpg", "--no-default-keyring", "--keyring", keyring, 859 "--with-colons", "--fingerprint", "--fingerprint"] 860 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 861 862 key = None 863 need_fingerprint = False 864 865 for line_raw in p.stdout: 866 try: 867 line = line_raw.decode() 868 except UnicodeDecodeError: 869 # Some old UIDs might not use UTF-8 encoding. We assume they 870 # use latin1. 871 line = line_raw.decode('latin1') 872 field = line.split(":") 873 if field[0] == "pub": 874 key = field[4] 875 self.keys[key] = {} 876 (name, addr) = self.parse_address(field[9]) 877 if "@" in addr: 878 self.keys[key]["email"] = addr 879 self.keys[key]["name"] = name 880 need_fingerprint = True 881 elif key and field[0] == "uid": 882 (name, addr) = self.parse_address(field[9]) 883 if "email" not in self.keys[key] and "@" in addr: 884 self.keys[key]["email"] = addr 885 self.keys[key]["name"] = name 886 elif need_fingerprint and field[0] == "fpr": 887 self.keys[key]["fingerprints"] = [field[9]] 888 self.fpr_lookup[field[9]] = key 889 need_fingerprint = False 890 891 (out, err) = p.communicate() 892 r = p.returncode 893 if r != 0: 894 raise GpgException("command failed: %s\nstdout: %s\nstderr: %s\n" % (cmd, out, err))
895
896 - def import_users_from_ldap(self, session):
897 from .utils import open_ldap_connection 898 import ldap 899 l = open_ldap_connection() 900 cnf = Config() 901 LDAPDn = cnf["Import-LDAP-Fingerprints::LDAPDn"] 902 Attrs = l.search_s(LDAPDn, ldap.SCOPE_ONELEVEL, 903 "(&(keyfingerprint=*)(supplementaryGid=%s))" % (cnf["Import-Users-From-Passwd::ValidGID"]), 904 ["uid", "keyfingerprint", "cn", "mn", "sn"]) 905 906 byuid = {} 907 byname = {} 908 909 for i in Attrs: 910 entry = i[1] 911 uid = entry["uid"][0].decode() 912 name = get_ldap_name(entry) 913 fingerprints = entry["keyFingerPrint"] 914 keyid = None 915 for f_raw in fingerprints: 916 f = f_raw.decode() 917 key = self.fpr_lookup.get(f, None) 918 if key not in self.keys: 919 continue 920 self.keys[key]["uid"] = uid 921 922 if keyid is not None: 923 continue 924 keyid = get_or_set_uid(uid, session).uid_id 925 byuid[keyid] = (uid, name) 926 byname[uid] = (keyid, name) 927 928 return (byname, byuid)
929
930 - def generate_users_from_keyring(self, format, session):
931 byuid = {} 932 byname = {} 933 any_invalid = False 934 for x in list(self.keys.keys()): 935 if "email" not in self.keys[x]: 936 any_invalid = True 937 self.keys[x]["uid"] = format % "invalid-uid" 938 else: 939 uid = format % self.keys[x]["email"] 940 keyid = get_or_set_uid(uid, session).uid_id 941 byuid[keyid] = (uid, self.keys[x]["name"]) 942 byname[uid] = (keyid, self.keys[x]["name"]) 943 self.keys[x]["uid"] = uid 944 945 if any_invalid: 946 uid = format % "invalid-uid" 947 keyid = get_or_set_uid(uid, session).uid_id 948 byuid[keyid] = (uid, "ungeneratable user id") 949 byname[uid] = (keyid, "ungeneratable user id") 950 951 return (byname, byuid)
952 953 954 __all__.append('Keyring')
955 956 957 @session_wrapper 958 -def get_keyring(keyring, session=None):
959 """ 960 If C{keyring} does not have an entry in the C{keyrings} table yet, return None 961 If C{keyring} already has an entry, simply return the existing Keyring 962 963 @type keyring: string 964 @param keyring: the keyring name 965 966 @rtype: Keyring 967 @return: the Keyring object for this keyring 968 """ 969 970 q = session.query(Keyring).filter_by(keyring_name=keyring) 971 return q.one_or_none()
972 973 974 __all__.append('get_keyring')
975 976 977 @session_wrapper 978 -def get_active_keyring_paths(session=None):
979 """ 980 @rtype: list 981 @return: list of active keyring paths 982 """ 983 return [x.keyring_name for x in session.query(Keyring).filter(Keyring.active == True).order_by(desc(Keyring.priority)).all()] # noqa:E712
984 985 986 __all__.append('get_active_keyring_paths')
987 988 ################################################################################ 989 990 991 -class DBChange:
992 - def __init__(self, *args, **kwargs):
993 pass
994
995 - def __repr__(self):
996 return '<DBChange %s>' % self.changesname
997 998 999 __all__.append('DBChange')
1000 1001 1002 @session_wrapper 1003 -def get_dbchange(filename, session=None):
1004 """ 1005 returns DBChange object for given C{filename}. 1006 1007 @type filename: string 1008 @param filename: the name of the file 1009 1010 @type session: Session 1011 @param session: Optional SQLA session object (a temporary one will be 1012 generated if not supplied) 1013 1014 @rtype: DBChange 1015 @return: DBChange object for the given filename (C{None} if not present) 1016 1017 """ 1018 q = session.query(DBChange).filter_by(changesname=filename) 1019 return q.one_or_none()
1020 1021 1022 __all__.append('get_dbchange')
1023 1024 ################################################################################ 1025 1026 1027 -class Maintainer(ORMObject):
1028 - def __init__(self, name=None):
1029 self.name = name
1030
1031 - def properties(self):
1032 return ['name', 'maintainer_id']
1033
1034 - def get_split_maintainer(self):
1035 if not hasattr(self, 'name') or self.name is None: 1036 return ('', '', '', '') 1037 1038 return fix_maintainer(self.name.strip())
1039 1040 1041 __all__.append('Maintainer')
1042 1043 1044 @session_wrapper 1045 -def get_or_set_maintainer(name, session=None):
1046 """ 1047 Returns Maintainer object for given maintainer name. 1048 1049 If no matching maintainer name is found, a row is inserted. 1050 1051 @type name: string 1052 @param name: The maintainer name to add 1053 1054 @type session: SQLAlchemy 1055 @param session: Optional SQL session object (a temporary one will be 1056 generated if not supplied). If not passed, a commit will be performed at 1057 the end of the function, otherwise the caller is responsible for commiting. 1058 A flush will be performed either way. 1059 1060 @rtype: Maintainer 1061 @return: the Maintainer object for the given maintainer 1062 """ 1063 1064 q = session.query(Maintainer).filter_by(name=name) 1065 try: 1066 ret = q.one() 1067 except NoResultFound: 1068 maintainer = Maintainer() 1069 maintainer.name = name 1070 session.add(maintainer) 1071 session.commit_or_flush() 1072 ret = maintainer 1073 1074 return ret
1075 1076 1077 __all__.append('get_or_set_maintainer')
1078 1079 1080 @session_wrapper 1081 -def get_maintainer(maintainer_id, session=None):
1082 """ 1083 Return the name of the maintainer behind C{maintainer_id} or None if that 1084 maintainer_id is invalid. 1085 1086 @type maintainer_id: int 1087 @param maintainer_id: the id of the maintainer 1088 1089 @rtype: Maintainer 1090 @return: the Maintainer with this C{maintainer_id} 1091 """ 1092 1093 return session.query(Maintainer).get(maintainer_id)
1094 1095 1096 __all__.append('get_maintainer')
1097 1098 ################################################################################ 1099 1100 1101 -class NewComment:
1102 - def __init__(self, *args, **kwargs):
1103 pass
1104
1105 - def __repr__(self):
1106 return '''<NewComment for '%s %s' (%s)>''' % (self.package, self.version, self.comment_id)
1107 1108 1109 __all__.append('NewComment')
1110 1111 1112 @session_wrapper 1113 -def has_new_comment(policy_queue, package, version, session=None):
1114 """ 1115 Returns true if the given combination of C{package}, C{version} has a comment. 1116 1117 @type package: string 1118 @param package: name of the package 1119 1120 @type version: string 1121 @param version: package version 1122 1123 @type session: Session 1124 @param session: Optional SQLA session object (a temporary one will be 1125 generated if not supplied) 1126 1127 @rtype: boolean 1128 @return: true/false 1129 """ 1130 1131 q = session.query(NewComment).filter_by(policy_queue=policy_queue) 1132 q = q.filter_by(package=package) 1133 q = q.filter_by(version=version) 1134 1135 return bool(q.count() > 0)
1136 1137 1138 __all__.append('has_new_comment')
1139 1140 1141 @session_wrapper 1142 -def get_new_comments(policy_queue, package=None, version=None, comment_id=None, session=None):
1143 """ 1144 Returns (possibly empty) list of NewComment objects for the given 1145 parameters 1146 1147 @type package: string (optional) 1148 @param package: name of the package 1149 1150 @type version: string (optional) 1151 @param version: package version 1152 1153 @type comment_id: int (optional) 1154 @param comment_id: An id of a comment 1155 1156 @type session: Session 1157 @param session: Optional SQLA session object (a temporary one will be 1158 generated if not supplied) 1159 1160 @rtype: list 1161 @return: A (possibly empty) list of NewComment objects will be returned 1162 """ 1163 1164 q = session.query(NewComment).filter_by(policy_queue=policy_queue) 1165 if package is not None: 1166 q = q.filter_by(package=package) 1167 if version is not None: 1168 q = q.filter_by(version=version) 1169 if comment_id is not None: 1170 q = q.filter_by(comment_id=comment_id) 1171 1172 return q.all()
1173 1174 1175 __all__.append('get_new_comments')
1176 1177 ################################################################################ 1178 1179 1180 -class Override(ORMObject):
1181 - def __init__(self, package=None, suite=None, component=None, overridetype=None, 1182 section=None, priority=None):
1183 self.package = package 1184 self.suite = suite 1185 self.component = component 1186 self.overridetype = overridetype 1187 self.section = section 1188 self.priority = priority
1189
1190 - def properties(self):
1191 return ['package', 'suite', 'component', 'overridetype', 'section', 1192 'priority']
1193 1194 1195 __all__.append('Override')
1196 1197 1198 @session_wrapper 1199 -def get_override(package, suite=None, component=None, overridetype=None, session=None):
1200 """ 1201 Returns Override object for the given parameters 1202 1203 @type package: string 1204 @param package: The name of the package 1205 1206 @type suite: string, list or None 1207 @param suite: The name of the suite (or suites if a list) to limit to. If 1208 None, don't limit. Defaults to None. 1209 1210 @type component: string, list or None 1211 @param component: The name of the component (or components if a list) to 1212 limit to. If None, don't limit. Defaults to None. 1213 1214 @type overridetype: string, list or None 1215 @param overridetype: The name of the overridetype (or overridetypes if a list) to 1216 limit to. If None, don't limit. Defaults to None. 1217 1218 @type session: Session 1219 @param session: Optional SQLA session object (a temporary one will be 1220 generated if not supplied) 1221 1222 @rtype: list 1223 @return: A (possibly empty) list of Override objects will be returned 1224 """ 1225 1226 q = session.query(Override) 1227 q = q.filter_by(package=package) 1228 1229 if suite is not None: 1230 if not isinstance(suite, list): 1231 suite = [suite] 1232 q = q.join(Suite).filter(Suite.suite_name.in_(suite)) 1233 1234 if component is not None: 1235 if not isinstance(component, list): 1236 component = [component] 1237 q = q.join(Component).filter(Component.component_name.in_(component)) 1238 1239 if overridetype is not None: 1240 if not isinstance(overridetype, list): 1241 overridetype = [overridetype] 1242 q = q.join(OverrideType).filter(OverrideType.overridetype.in_(overridetype)) 1243 1244 return q.all()
1245 1246 1247 __all__.append('get_override')
1248 1249 1250 ################################################################################ 1251 1252 -class OverrideType(ORMObject):
1253 - def __init__(self, overridetype=None):
1254 self.overridetype = overridetype
1255
1256 - def properties(self):
1257 return ['overridetype', 'overridetype_id', 'overrides_count']
1258 1259 1260 __all__.append('OverrideType')
1261 1262 1263 @session_wrapper 1264 -def get_override_type(override_type, session=None):
1265 """ 1266 Returns OverrideType object for given C{override type}. 1267 1268 @type override_type: string 1269 @param override_type: The name of the override type 1270 1271 @type session: Session 1272 @param session: Optional SQLA session object (a temporary one will be 1273 generated if not supplied) 1274 1275 @rtype: int 1276 @return: the database id for the given override type 1277 """ 1278 1279 q = session.query(OverrideType).filter_by(overridetype=override_type) 1280 return q.one_or_none()
1281 1282 1283 __all__.append('get_override_type')
1284 1285 ################################################################################ 1286 1287 1288 -class PolicyQueue:
1289 - def __init__(self, *args, **kwargs):
1290 pass
1291
1292 - def __repr__(self):
1293 return '<PolicyQueue %s>' % self.queue_name
1294 1295 1296 __all__.append('PolicyQueue')
1297 1298 1299 @session_wrapper 1300 -def get_policy_queue(queuename, session=None):
1301 """ 1302 Returns PolicyQueue object for given C{queue name} 1303 1304 @type queuename: string 1305 @param queuename: The name of the queue 1306 1307 @type session: Session 1308 @param session: Optional SQLA session object (a temporary one will be 1309 generated if not supplied) 1310 1311 @rtype: PolicyQueue 1312 @return: PolicyQueue object for the given queue 1313 """ 1314 1315 q = session.query(PolicyQueue).filter_by(queue_name=queuename) 1316 return q.one_or_none()
1317 1318 1319 __all__.append('get_policy_queue')
1320 1321 ################################################################################ 1322 1323 1324 @functools.total_ordering 1325 -class PolicyQueueUpload:
1326 - def _key(self):
1327 return ( 1328 self.changes.source, 1329 AptVersion(self.changes.version), 1330 self.source is None, 1331 self.changes.changesname 1332 )
1333
1334 - def __eq__(self, other):
1335 return self._key() == other._key()
1336
1337 - def __lt__(self, other):
1338 return self._key() < other._key()
1339 1340 1341 __all__.append('PolicyQueueUpload')
1342 1343 ################################################################################ 1344 1345 1346 -class PolicyQueueByhandFile:
1347 pass
1348 1349 1350 __all__.append('PolicyQueueByhandFile')
1351 1352 ################################################################################ 1353 1354 1355 -class Priority(ORMObject):
1356 - def __init__(self, priority=None, level=None):
1357 self.priority = priority 1358 self.level = level
1359
1360 - def properties(self):
1361 return ['priority', 'priority_id', 'level', 'overrides_count']
1362
1363 - def __eq__(self, val):
1364 if isinstance(val, str): 1365 warnings.warn("comparison with a `str` is deprecated", DeprecationWarning, stacklevel=2) 1366 return (self.priority == val) 1367 # This signals to use the normal comparison operator 1368 return NotImplemented
1369
1370 - def __ne__(self, val):
1371 if isinstance(val, str): 1372 warnings.warn("comparison with a `str` is deprecated", DeprecationWarning, stacklevel=2) 1373 return (self.priority != val) 1374 # This signals to use the normal comparison operator 1375 return NotImplemented
1376 1377 __hash__ = ORMObject.__hash__
1378 1379 1380 __all__.append('Priority')
1381 1382 1383 @session_wrapper 1384 -def get_priority(priority, session=None):
1385 """ 1386 Returns Priority object for given C{priority name}. 1387 1388 @type priority: string 1389 @param priority: The name of the priority 1390 1391 @type session: Session 1392 @param session: Optional SQLA session object (a temporary one will be 1393 generated if not supplied) 1394 1395 @rtype: Priority 1396 @return: Priority object for the given priority 1397 """ 1398 1399 q = session.query(Priority).filter_by(priority=priority) 1400 return q.one_or_none()
1401 1402 1403 __all__.append('get_priority')
1404 1405 1406 @session_wrapper 1407 -def get_priorities(session=None):
1408 """ 1409 Returns dictionary of priority names -> id mappings 1410 1411 @type session: Session 1412 @param session: Optional SQL session object (a temporary one will be 1413 generated if not supplied) 1414 1415 @rtype: dictionary 1416 @return: dictionary of priority names -> id mappings 1417 """ 1418 1419 ret = {} 1420 q = session.query(Priority) 1421 for x in q.all(): 1422 ret[x.priority] = x.priority_id 1423 1424 return ret
1425 1426 1427 __all__.append('get_priorities') 1428 1429 ################################################################################ 1430 1431 1432 from .database.section import Section 1433 1434 __all__.append('Section')
1435 1436 1437 @session_wrapper 1438 -def get_section(section, session=None):
1439 """ 1440 Returns Section object for given C{section name}. 1441 1442 @type section: string 1443 @param section: The name of the section 1444 1445 @type session: Session 1446 @param session: Optional SQLA session object (a temporary one will be 1447 generated if not supplied) 1448 1449 @rtype: Section 1450 @return: Section object for the given section name 1451 """ 1452 1453 q = session.query(Section).filter_by(section=section) 1454 return q.one_or_none()
1455 1456 1457 __all__.append('get_section')
1458 1459 1460 @session_wrapper 1461 -def get_sections(session=None):
1462 """ 1463 Returns dictionary of section names -> id mappings 1464 1465 @type session: Session 1466 @param session: Optional SQL session object (a temporary one will be 1467 generated if not supplied) 1468 1469 @rtype: dictionary 1470 @return: dictionary of section names -> id mappings 1471 """ 1472 1473 ret = {} 1474 q = session.query(Section) 1475 for x in q.all(): 1476 ret[x.section] = x.section_id 1477 1478 return ret
1479 1480 1481 __all__.append('get_sections')
1482 1483 ################################################################################ 1484 1485 1486 -class SignatureHistory(ORMObject):
1487 @classmethod
1488 - def from_signed_file(cls, signed_file):
1489 """signature history entry from signed file 1490 1491 @type signed_file: L{daklib.gpg.SignedFile} 1492 @param signed_file: signed file 1493 1494 @rtype: L{SignatureHistory} 1495 """ 1496 self = cls() 1497 self.fingerprint = signed_file.primary_fingerprint 1498 self.signature_timestamp = signed_file.signature_timestamp 1499 self.contents_sha1 = signed_file.contents_sha1() 1500 return self
1501
1502 - def query(self, session):
1504 1505 1506 __all__.append('SignatureHistory')
1507 1508 ################################################################################ 1509 1510 1511 -class SrcContents(ORMObject):
1512 - def __init__(self, file=None, source=None):
1513 self.file = file 1514 self.source = source
1515
1516 - def properties(self):
1517 return ['file', 'source']
1518 1519 1520 __all__.append('SrcContents')
1521 1522 ################################################################################ 1523 1524 1525 -class DBSource(ORMObject):
1526 - def __init__(self, source=None, version=None, maintainer=None, 1527 changedby=None, poolfile=None, install_date=None, fingerprint=None):
1528 self.source = source 1529 self.version = version 1530 self.maintainer = maintainer 1531 self.changedby = changedby 1532 self.poolfile = poolfile 1533 self.install_date = install_date 1534 self.fingerprint = fingerprint
1535 1536 @property
1537 - def pkid(self):
1538 return self.source_id
1539 1540 @property
1541 - def name(self):
1542 return self.source
1543 1544 @property
1545 - def arch_string(self):
1546 return 'source'
1547
1548 - def properties(self):
1549 return ['source', 'source_id', 'maintainer', 'changedby', 1550 'fingerprint', 'poolfile', 'version', 'suites_count', 1551 'install_date', 'binaries_count', 'uploaders_count']
1552
1553 - def read_control_fields(self):
1554 ''' 1555 Reads the control information from a dsc 1556 1557 @rtype: tuple 1558 @return: fields is the dsc information in a dictionary form 1559 ''' 1560 with open(self.poolfile.fullpath, 'r') as fd: 1561 fields = Deb822(fd) 1562 return fields
1563 1564 metadata = association_proxy('key', 'value') 1565
1566 - def scan_contents(self):
1567 ''' 1568 Returns a set of names for non directories. The path names are 1569 normalized after converting them from either utf-8 or iso8859-1 1570 encoding. 1571 ''' 1572 fullpath = self.poolfile.fullpath 1573 from daklib.contents import UnpackedSource 1574 unpacked = UnpackedSource(fullpath) 1575 fileset = set() 1576 for name in unpacked.get_all_filenames(): 1577 fileset.add(name) 1578 return fileset
1579 1580 @property
1581 - def proxy(self):
1582 session = object_session(self) 1583 query = session.query(SourceMetadata).filter_by(source=self) 1584 return MetadataProxy(session, query)
1585 1586 1587 __all__.append('DBSource')
1588 1589 1590 @session_wrapper 1591 -def get_suites_source_in(source, session=None):
1592 """ 1593 Returns list of Suite objects which given C{source} name is in 1594 1595 @type source: str 1596 @param source: DBSource package name to search for 1597 1598 @rtype: list 1599 @return: list of Suite objects for the given source 1600 """ 1601 1602 return session.query(Suite).filter(Suite.sources.any(source=source)).all()
1603 1604 1605 __all__.append('get_suites_source_in')
1606 1607 # FIXME: This function fails badly if it finds more than 1 source package and 1608 # its implementation is trivial enough to be inlined. 1609 1610 1611 @session_wrapper 1612 -def get_source_in_suite(source, suite_name, session=None):
1613 """ 1614 Returns a DBSource object for a combination of C{source} and C{suite_name}. 1615 1616 - B{source} - source package name, eg. I{mailfilter}, I{bbdb}, I{glibc} 1617 - B{suite_name} - a suite name, eg. I{unstable} 1618 1619 @type source: string 1620 @param source: source package name 1621 1622 @type suite_name: string 1623 @param suite_name: the suite name 1624 1625 @rtype: string 1626 @return: the version for I{source} in I{suite} 1627 1628 """ 1629 suite = get_suite(suite_name, session) 1630 if suite is None: 1631 return None 1632 return suite.get_sources(source).one_or_none()
1633 1634 1635 __all__.append('get_source_in_suite')
1636 1637 1638 @session_wrapper 1639 -def import_metadata_into_db(obj, session=None):
1640 """ 1641 This routine works on either DBBinary or DBSource objects and imports 1642 their metadata into the database 1643 """ 1644 fields = obj.read_control_fields() 1645 for k in fields.keys(): 1646 try: 1647 # Try raw ASCII 1648 val = str(fields[k]) 1649 except UnicodeEncodeError: 1650 # Fall back to UTF-8 1651 try: 1652 val = fields[k].encode('utf-8') 1653 except UnicodeEncodeError: 1654 # Finally try iso8859-1 1655 val = fields[k].encode('iso8859-1') 1656 # Otherwise we allow the exception to percolate up and we cause 1657 # a reject as someone is playing silly buggers 1658 1659 obj.metadata[get_or_set_metadatakey(k, session)] = val 1660 1661 session.commit_or_flush()
1662 1663 1664 __all__.append('import_metadata_into_db')
1665 1666 ################################################################################ 1667 1668 1669 -class SrcFormat:
1670 - def __init__(self, *args, **kwargs):
1671 pass
1672
1673 - def __repr__(self):
1674 return '<SrcFormat %s>' % (self.format_name)
1675 1676 1677 __all__.append('SrcFormat') 1678 1679 ################################################################################ 1680 1681 SUITE_FIELDS = [('SuiteName', 'suite_name'), 1682 ('SuiteID', 'suite_id'), 1683 ('Version', 'version'), 1684 ('Origin', 'origin'), 1685 ('Label', 'label'), 1686 ('Description', 'description'), 1687 ('Untouchable', 'untouchable'), 1688 ('Announce', 'announce'), 1689 ('Codename', 'codename'), 1690 ('OverrideCodename', 'overridecodename'), 1691 ('ValidTime', 'validtime'), 1692 ('Priority', 'priority'), 1693 ('NotAutomatic', 'notautomatic'), 1694 ('CopyChanges', 'copychanges'), 1695 ('OverrideSuite', 'overridesuite')]
1696 1697 # Why the heck don't we have any UNIQUE constraints in table suite? 1698 # TODO: Add UNIQUE constraints for appropriate columns. 1699 1700 1701 -class Suite(ORMObject):
1702 - def __init__(self, suite_name=None, version=None):
1703 self.suite_name = suite_name 1704 self.version = version
1705
1706 - def properties(self):
1707 return ['suite_name', 'version', 'sources_count', 'binaries_count', 1708 'overrides_count']
1709
1710 - def __eq__(self, val):
1711 if isinstance(val, str): 1712 warnings.warn("comparison with a `str` is deprecated", DeprecationWarning, stacklevel=2) 1713 return (self.suite_name == val) 1714 # This signals to use the normal comparison operator 1715 return NotImplemented
1716
1717 - def __ne__(self, val):
1718 if isinstance(val, str): 1719 warnings.warn("comparison with a `str` is deprecated", DeprecationWarning, stacklevel=2) 1720 return (self.suite_name != val) 1721 # This signals to use the normal comparison operator 1722 return NotImplemented
1723 1724 __hash__ = ORMObject.__hash__ 1725
1726 - def details(self):
1727 ret = [] 1728 for disp, field in SUITE_FIELDS: 1729 val = getattr(self, field, None) 1730 if val is not None: 1731 ret.append("%s: %s" % (disp, val)) 1732 1733 return "\n".join(ret)
1734
1735 - def get_architectures(self, skipsrc=False, skipall=False):
1736 """ 1737 Returns list of Architecture objects 1738 1739 @type skipsrc: boolean 1740 @param skipsrc: Whether to skip returning the 'source' architecture entry 1741 (Default False) 1742 1743 @type skipall: boolean 1744 @param skipall: Whether to skip returning the 'all' architecture entry 1745 (Default False) 1746 1747 @rtype: list 1748 @return: list of Architecture objects for the given name (may be empty) 1749 """ 1750 1751 q = object_session(self).query(Architecture).with_parent(self) 1752 if skipsrc: 1753 q = q.filter(Architecture.arch_string != 'source') 1754 if skipall: 1755 q = q.filter(Architecture.arch_string != 'all') 1756 return q.order_by(Architecture.arch_string).all()
1757
1758 - def get_sources(self, source):
1759 """ 1760 Returns a query object representing DBSource that is part of C{suite}. 1761 1762 - B{source} - source package name, eg. I{mailfilter}, I{bbdb}, I{glibc} 1763 1764 @type source: string 1765 @param source: source package name 1766 1767 @rtype: sqlalchemy.orm.query.Query 1768 @return: a query of DBSource 1769 1770 """ 1771 1772 session = object_session(self) 1773 return session.query(DBSource).filter_by(source=source). \ 1774 with_parent(self)
1775
1776 - def get_overridesuite(self):
1777 if self.overridesuite is None: 1778 return self 1779 else: 1780 return object_session(self).query(Suite).filter_by(suite_name=self.overridesuite).one()
1781
1782 - def update_last_changed(self):
1783 self.last_changed = sqlalchemy.func.now()
1784 1785 @property
1786 - def path(self):
1787 return os.path.join(self.archive.path, 'dists', self.suite_name)
1788 1789 @property
1790 - def release_suite_output(self):
1791 if self.release_suite is not None: 1792 return self.release_suite 1793 return self.suite_name
1794 1795 1796 __all__.append('Suite')
1797 1798 1799 @session_wrapper 1800 -def get_suite(suite, session=None):
1801 """ 1802 Returns Suite object for given C{suite name}. 1803 1804 @type suite: string 1805 @param suite: The name of the suite 1806 1807 @type session: Session 1808 @param session: Optional SQLA session object (a temporary one will be 1809 generated if not supplied) 1810 1811 @rtype: Suite 1812 @return: Suite object for the requested suite name (None if not present) 1813 """ 1814 1815 # Start by looking for the dak internal name 1816 q = session.query(Suite).filter_by(suite_name=suite) 1817 try: 1818 return q.one() 1819 except NoResultFound: 1820 pass 1821 1822 # Now try codename 1823 q = session.query(Suite).filter_by(codename=suite) 1824 try: 1825 return q.one() 1826 except NoResultFound: 1827 pass 1828 1829 # Finally give release_suite a try 1830 q = session.query(Suite).filter_by(release_suite=suite) 1831 return q.one_or_none()
1832 1833 1834 __all__.append('get_suite')
1835 1836 ################################################################################ 1837 1838 1839 @session_wrapper 1840 -def get_suite_architectures(suite, skipsrc=False, skipall=False, session=None):
1841 """ 1842 Returns list of Architecture objects for given C{suite} name. The list is 1843 empty if suite does not exist. 1844 1845 @type suite: str 1846 @param suite: Suite name to search for 1847 1848 @type skipsrc: boolean 1849 @param skipsrc: Whether to skip returning the 'source' architecture entry 1850 (Default False) 1851 1852 @type skipall: boolean 1853 @param skipall: Whether to skip returning the 'all' architecture entry 1854 (Default False) 1855 1856 @type session: Session 1857 @param session: Optional SQL session object (a temporary one will be 1858 generated if not supplied) 1859 1860 @rtype: list 1861 @return: list of Architecture objects for the given name (may be empty) 1862 """ 1863 1864 try: 1865 return get_suite(suite, session).get_architectures(skipsrc, skipall) 1866 except AttributeError: 1867 return []
1868 1869 1870 __all__.append('get_suite_architectures')
1871 1872 ################################################################################ 1873 1874 1875 -class Uid(ORMObject):
1876 - def __init__(self, uid=None, name=None):
1877 self.uid = uid 1878 self.name = name
1879
1880 - def __eq__(self, val):
1881 if isinstance(val, str): 1882 warnings.warn("comparison with a `str` is deprecated", DeprecationWarning, stacklevel=2) 1883 return (self.uid == val) 1884 # This signals to use the normal comparison operator 1885 return NotImplemented
1886
1887 - def __ne__(self, val):
1888 if isinstance(val, str): 1889 warnings.warn("comparison with a `str` is deprecated", DeprecationWarning, stacklevel=2) 1890 return (self.uid != val) 1891 # This signals to use the normal comparison operator 1892 return NotImplemented
1893 1894 __hash__ = ORMObject.__hash__ 1895
1896 - def properties(self):
1897 return ['uid', 'name', 'fingerprint']
1898 1899 1900 __all__.append('Uid')
1901 1902 1903 @session_wrapper 1904 -def get_or_set_uid(uidname, session=None):
1905 """ 1906 Returns uid object for given uidname. 1907 1908 If no matching uidname is found, a row is inserted. 1909 1910 @type uidname: string 1911 @param uidname: The uid to add 1912 1913 @type session: SQLAlchemy 1914 @param session: Optional SQL session object (a temporary one will be 1915 generated if not supplied). If not passed, a commit will be performed at 1916 the end of the function, otherwise the caller is responsible for commiting. 1917 1918 @rtype: Uid 1919 @return: the uid object for the given uidname 1920 """ 1921 1922 q = session.query(Uid).filter_by(uid=uidname) 1923 1924 try: 1925 ret = q.one() 1926 except NoResultFound: 1927 uid = Uid() 1928 uid.uid = uidname 1929 session.add(uid) 1930 session.commit_or_flush() 1931 ret = uid 1932 1933 return ret
1934 1935 1936 __all__.append('get_or_set_uid')
1937 1938 1939 @session_wrapper 1940 -def get_uid_from_fingerprint(fpr, session=None):
1941 q = session.query(Uid) 1942 q = q.join(Fingerprint).filter_by(fingerprint=fpr) 1943 1944 return q.one_or_none()
1945 1946 1947 __all__.append('get_uid_from_fingerprint')
1948 1949 ################################################################################ 1950 1951 1952 -class MetadataKey(ORMObject):
1953 - def __init__(self, key=None):
1954 self.key = key
1955
1956 - def properties(self):
1957 return ['key']
1958 1959 1960 __all__.append('MetadataKey')
1961 1962 1963 @session_wrapper 1964 -def get_or_set_metadatakey(keyname, session=None):
1965 """ 1966 Returns MetadataKey object for given uidname. 1967 1968 If no matching keyname is found, a row is inserted. 1969 1970 @type keyname: string 1971 @param keyname: The keyname to add 1972 1973 @type session: SQLAlchemy 1974 @param session: Optional SQL session object (a temporary one will be 1975 generated if not supplied). If not passed, a commit will be performed at 1976 the end of the function, otherwise the caller is responsible for commiting. 1977 1978 @rtype: MetadataKey 1979 @return: the metadatakey object for the given keyname 1980 """ 1981 1982 q = session.query(MetadataKey).filter_by(key=keyname) 1983 1984 try: 1985 ret = q.one() 1986 except NoResultFound: 1987 ret = MetadataKey(keyname) 1988 session.add(ret) 1989 session.commit_or_flush() 1990 1991 return ret
1992 1993 1994 __all__.append('get_or_set_metadatakey')
1995 1996 ################################################################################ 1997 1998 1999 -class BinaryMetadata(ORMObject):
2000 - def __init__(self, key=None, value=None, binary=None):
2001 self.key = key 2002 self.value = value 2003 if binary is not None: 2004 self.binary = binary
2005
2006 - def properties(self):
2007 return ['binary', 'key', 'value']
2008 2009 2010 __all__.append('BinaryMetadata')
2011 2012 ################################################################################ 2013 2014 2015 -class SourceMetadata(ORMObject):
2016 - def __init__(self, key=None, value=None, source=None):
2017 self.key = key 2018 self.value = value 2019 if source is not None: 2020 self.source = source
2021
2022 - def properties(self):
2023 return ['source', 'key', 'value']
2024 2025 2026 __all__.append('SourceMetadata')
2027 2028 ################################################################################ 2029 2030 2031 -class MetadataProxy:
2032 - def __init__(self, session, query):
2033 self.session = session 2034 self.query = query
2035
2036 - def _get(self, key):
2037 metadata_key = self.session.query(MetadataKey).filter_by(key=key).first() 2038 if metadata_key is None: 2039 return None 2040 metadata = self.query.filter_by(key=metadata_key).first() 2041 return metadata
2042
2043 - def __contains__(self, key):
2044 if self._get(key) is not None: 2045 return True 2046 return False
2047
2048 - def __getitem__(self, key):
2049 metadata = self._get(key) 2050 if metadata is None: 2051 raise KeyError 2052 return metadata.value
2053
2054 - def get(self, key, default=None):
2055 try: 2056 return self[key] 2057 except KeyError: 2058 return default
2059
2060 ################################################################################ 2061 2062 2063 -class VersionCheck(ORMObject):
2064 - def __init__(self, *args, **kwargs):
2065 pass
2066
2067 - def properties(self):
2068 return ['check']
2069 2070 2071 __all__.append('VersionCheck')
2072 2073 2074 @session_wrapper 2075 -def get_version_checks(suite_name, check=None, session=None):
2076 suite = get_suite(suite_name, session) 2077 if not suite: 2078 # Make sure that what we return is iterable so that list comprehensions 2079 # involving this don't cause a traceback 2080 return [] 2081 q = session.query(VersionCheck).filter_by(suite=suite) 2082 if check: 2083 q = q.filter_by(check=check) 2084 return q.all()
2085 2086 2087 __all__.append('get_version_checks')
2088 2089 ################################################################################ 2090 2091 2092 -class DBConn:
2093 """ 2094 database module init. 2095 """ 2096 __shared_state = {} 2097 2098 db_meta = None 2099 2100 tbl_architecture = Architecture.__table__ 2101 2102 tables = ( 2103 'acl', 2104 'acl_architecture_map', 2105 'acl_fingerprint_map', 2106 'acl_per_source', 2107 'archive', 2108 'bin_associations', 2109 'bin_contents', 2110 'binaries', 2111 'binaries_metadata', 2112 'build_queue', 2113 'changelogs_text', 2114 'changes', 2115 'component', 2116 'component_suite', 2117 'config', 2118 'dsc_files', 2119 'external_files', 2120 'external_overrides', 2121 'external_signature_requests', 2122 'extra_src_references', 2123 'files', 2124 'files_archive_map', 2125 'fingerprint', 2126 'hashfile', 2127 'keyrings', 2128 'maintainer', 2129 'metadata_keys', 2130 'new_comments', 2131 # TODO: the maintainer column in table override should be removed. 2132 'override', 2133 'override_type', 2134 'policy_queue', 2135 'policy_queue_upload', 2136 'policy_queue_upload_binaries_map', 2137 'policy_queue_byhand_file', 2138 'priority', 2139 'signature_history', 2140 'source', 2141 'source_metadata', 2142 'src_associations', 2143 'src_contents', 2144 'src_format', 2145 'src_uploaders', 2146 'suite', 2147 'suite_acl_map', 2148 'suite_architectures', 2149 'suite_build_queue_copy', 2150 'suite_permission', 2151 'suite_src_formats', 2152 'uid', 2153 'version_check', 2154 ) 2155 2156 views = ( 2157 'bin_associations_binaries', 2158 'changelogs', 2159 'newest_source', 2160 'newest_src_association', 2161 'package_list', 2162 'source_suite', 2163 'src_associations_src', 2164 ) 2165
2166 - def __init__(self, *args, **kwargs):
2167 self.__dict__ = self.__shared_state 2168 2169 if not getattr(self, 'initialised', False): 2170 self.initialised = True 2171 self.debug = 'debug' in kwargs 2172 self.__createconn()
2173
2174 - def __setuptables(self):
2175 for table_name in self.tables: 2176 table = Table(table_name, self.db_meta, 2177 autoload=True, extend_existing=True) 2178 setattr(self, 'tbl_%s' % table_name, table) 2179 2180 for view_name in self.views: 2181 view = Table(view_name, self.db_meta, autoload=True) 2182 setattr(self, 'view_%s' % view_name, view)
2183
2184 - def __setupmappers(self):
2185 mapper(ACL, self.tbl_acl, 2186 properties=dict( 2187 architectures=relation(Architecture, secondary=self.tbl_acl_architecture_map, collection_class=set), 2188 fingerprints=relation(Fingerprint, secondary=self.tbl_acl_fingerprint_map, collection_class=set), 2189 match_keyring=relation(Keyring, primaryjoin=(self.tbl_acl.c.match_keyring_id == self.tbl_keyrings.c.id)), 2190 per_source=relation(ACLPerSource, collection_class=set), 2191 )) 2192 2193 mapper(ACLPerSource, self.tbl_acl_per_source, 2194 properties=dict( 2195 acl=relation(ACL), 2196 fingerprint=relation(Fingerprint, primaryjoin=(self.tbl_acl_per_source.c.fingerprint_id == self.tbl_fingerprint.c.id)), 2197 created_by=relation(Fingerprint, primaryjoin=(self.tbl_acl_per_source.c.created_by_id == self.tbl_fingerprint.c.id)), 2198 )) 2199 2200 mapper(Archive, self.tbl_archive, 2201 properties=dict(archive_id=self.tbl_archive.c.id, 2202 archive_name=self.tbl_archive.c.name)) 2203 2204 mapper(ArchiveFile, self.tbl_files_archive_map, 2205 properties=dict(archive=relation(Archive, backref='files'), 2206 component=relation(Component), 2207 file=relation(PoolFile, backref='archives'))) 2208 2209 mapper(BuildQueue, self.tbl_build_queue, 2210 properties=dict(queue_id=self.tbl_build_queue.c.id, 2211 suite=relation(Suite, primaryjoin=(self.tbl_build_queue.c.suite_id == self.tbl_suite.c.id)))) 2212 2213 mapper(DBBinary, self.tbl_binaries, 2214 properties=dict(binary_id=self.tbl_binaries.c.id, 2215 package=self.tbl_binaries.c.package, 2216 version=self.tbl_binaries.c.version, 2217 maintainer_id=self.tbl_binaries.c.maintainer, 2218 maintainer=relation(Maintainer), 2219 source_id=self.tbl_binaries.c.source, 2220 source=relation(DBSource, backref='binaries'), 2221 arch_id=self.tbl_binaries.c.architecture, 2222 architecture=relation(Architecture), 2223 poolfile_id=self.tbl_binaries.c.file, 2224 poolfile=relation(PoolFile), 2225 binarytype=self.tbl_binaries.c.type, 2226 fingerprint_id=self.tbl_binaries.c.sig_fpr, 2227 fingerprint=relation(Fingerprint), 2228 install_date=self.tbl_binaries.c.install_date, 2229 suites=relation(Suite, secondary=self.tbl_bin_associations, 2230 backref=backref('binaries', lazy='dynamic')), 2231 extra_sources=relation(DBSource, secondary=self.tbl_extra_src_references, 2232 backref=backref('extra_binary_references', lazy='dynamic')), 2233 key=relation(BinaryMetadata, cascade='all', 2234 collection_class=attribute_mapped_collection('key'))), 2235 ) 2236 2237 mapper(Component, self.tbl_component, 2238 properties=dict(component_id=self.tbl_component.c.id, 2239 component_name=self.tbl_component.c.name), 2240 ) 2241 2242 mapper(DBConfig, self.tbl_config, 2243 properties=dict(config_id=self.tbl_config.c.id)) 2244 2245 mapper(DSCFile, self.tbl_dsc_files, 2246 properties=dict(dscfile_id=self.tbl_dsc_files.c.id, 2247 source_id=self.tbl_dsc_files.c.source, 2248 source=relation(DBSource), 2249 poolfile_id=self.tbl_dsc_files.c.file, 2250 poolfile=relation(PoolFile))) 2251 2252 mapper(ExternalOverride, self.tbl_external_overrides, 2253 properties=dict( 2254 suite_id=self.tbl_external_overrides.c.suite, 2255 suite=relation(Suite), 2256 component_id=self.tbl_external_overrides.c.component, 2257 component=relation(Component))) 2258 2259 mapper(PoolFile, self.tbl_files, 2260 properties=dict(file_id=self.tbl_files.c.id, 2261 filesize=self.tbl_files.c.size), 2262 ) 2263 2264 mapper(Fingerprint, self.tbl_fingerprint, 2265 properties=dict(fingerprint_id=self.tbl_fingerprint.c.id, 2266 uid_id=self.tbl_fingerprint.c.uid, 2267 uid=relation(Uid), 2268 keyring_id=self.tbl_fingerprint.c.keyring, 2269 keyring=relation(Keyring), 2270 acl=relation(ACL)), 2271 ) 2272 2273 mapper(Keyring, self.tbl_keyrings, 2274 properties=dict(keyring_name=self.tbl_keyrings.c.name, 2275 keyring_id=self.tbl_keyrings.c.id, 2276 acl=relation(ACL, primaryjoin=(self.tbl_keyrings.c.acl_id == self.tbl_acl.c.id)))), 2277 2278 mapper(DBChange, self.tbl_changes, 2279 properties=dict(change_id=self.tbl_changes.c.id, 2280 seen=self.tbl_changes.c.seen, 2281 source=self.tbl_changes.c.source, 2282 binaries=self.tbl_changes.c.binaries, 2283 architecture=self.tbl_changes.c.architecture, 2284 distribution=self.tbl_changes.c.distribution, 2285 urgency=self.tbl_changes.c.urgency, 2286 maintainer=self.tbl_changes.c.maintainer, 2287 changedby=self.tbl_changes.c.changedby, 2288 date=self.tbl_changes.c.date, 2289 version=self.tbl_changes.c.version)) 2290 2291 mapper(Maintainer, self.tbl_maintainer, 2292 properties=dict(maintainer_id=self.tbl_maintainer.c.id, 2293 maintains_sources=relation(DBSource, backref='maintainer', 2294 primaryjoin=(self.tbl_maintainer.c.id == self.tbl_source.c.maintainer)), 2295 changed_sources=relation(DBSource, backref='changedby', 2296 primaryjoin=(self.tbl_maintainer.c.id == self.tbl_source.c.changedby))), 2297 ) 2298 2299 mapper(NewComment, self.tbl_new_comments, 2300 properties=dict(comment_id=self.tbl_new_comments.c.id, 2301 policy_queue=relation(PolicyQueue))) 2302 2303 mapper(Override, self.tbl_override, 2304 properties=dict(suite_id=self.tbl_override.c.suite, 2305 suite=relation(Suite, 2306 backref=backref('overrides', lazy='dynamic')), 2307 package=self.tbl_override.c.package, 2308 component_id=self.tbl_override.c.component, 2309 component=relation(Component, 2310 backref=backref('overrides', lazy='dynamic')), 2311 priority_id=self.tbl_override.c.priority, 2312 priority=relation(Priority, 2313 backref=backref('overrides', lazy='dynamic')), 2314 section_id=self.tbl_override.c.section, 2315 section=relation(Section, 2316 backref=backref('overrides', lazy='dynamic')), 2317 overridetype_id=self.tbl_override.c.type, 2318 overridetype=relation(OverrideType, 2319 backref=backref('overrides', lazy='dynamic')))) 2320 2321 mapper(OverrideType, self.tbl_override_type, 2322 properties=dict(overridetype=self.tbl_override_type.c.type, 2323 overridetype_id=self.tbl_override_type.c.id)) 2324 2325 mapper(PolicyQueue, self.tbl_policy_queue, 2326 properties=dict(policy_queue_id=self.tbl_policy_queue.c.id, 2327 suite=relation(Suite, primaryjoin=(self.tbl_policy_queue.c.suite_id == self.tbl_suite.c.id)))) 2328 2329 mapper(PolicyQueueUpload, self.tbl_policy_queue_upload, 2330 properties=dict( 2331 changes=relation(DBChange), 2332 policy_queue=relation(PolicyQueue, backref='uploads'), 2333 target_suite=relation(Suite), 2334 source=relation(DBSource), 2335 binaries=relation(DBBinary, secondary=self.tbl_policy_queue_upload_binaries_map), 2336 )) 2337 2338 mapper(PolicyQueueByhandFile, self.tbl_policy_queue_byhand_file, 2339 properties=dict( 2340 upload=relation(PolicyQueueUpload, backref='byhand'), 2341 )) 2342 2343 mapper(Priority, self.tbl_priority, 2344 properties=dict(priority_id=self.tbl_priority.c.id)) 2345 2346 mapper(SignatureHistory, self.tbl_signature_history) 2347 2348 mapper(DBSource, self.tbl_source, 2349 properties=dict(source_id=self.tbl_source.c.id, 2350 version=self.tbl_source.c.version, 2351 maintainer_id=self.tbl_source.c.maintainer, 2352 poolfile_id=self.tbl_source.c.file, 2353 poolfile=relation(PoolFile), 2354 fingerprint_id=self.tbl_source.c.sig_fpr, 2355 fingerprint=relation(Fingerprint), 2356 changedby_id=self.tbl_source.c.changedby, 2357 srcfiles=relation(DSCFile, 2358 primaryjoin=(self.tbl_source.c.id == self.tbl_dsc_files.c.source)), 2359 suites=relation(Suite, secondary=self.tbl_src_associations, 2360 backref=backref('sources', lazy='dynamic')), 2361 uploaders=relation(Maintainer, 2362 secondary=self.tbl_src_uploaders), 2363 key=relation(SourceMetadata, cascade='all', 2364 collection_class=attribute_mapped_collection('key'))), 2365 ) 2366 2367 mapper(SrcFormat, self.tbl_src_format, 2368 properties=dict(src_format_id=self.tbl_src_format.c.id, 2369 format_name=self.tbl_src_format.c.format_name)) 2370 2371 mapper(Suite, self.tbl_suite, 2372 properties=dict(suite_id=self.tbl_suite.c.id, 2373 policy_queue=relation(PolicyQueue, primaryjoin=(self.tbl_suite.c.policy_queue_id == self.tbl_policy_queue.c.id)), 2374 new_queue=relation(PolicyQueue, primaryjoin=(self.tbl_suite.c.new_queue_id == self.tbl_policy_queue.c.id)), 2375 debug_suite=relation(Suite, remote_side=[self.tbl_suite.c.id]), 2376 copy_queues=relation(BuildQueue, 2377 secondary=self.tbl_suite_build_queue_copy), 2378 srcformats=relation(SrcFormat, secondary=self.tbl_suite_src_formats, 2379 backref=backref('suites', lazy='dynamic')), 2380 archive=relation(Archive, backref='suites'), 2381 acls=relation(ACL, secondary=self.tbl_suite_acl_map, collection_class=set), 2382 components=relation(Component, secondary=self.tbl_component_suite, 2383 order_by=self.tbl_component.c.ordering, 2384 backref=backref('suites')), 2385 architectures=relation(Architecture, secondary=self.tbl_suite_architectures, 2386 backref=backref('suites'))), 2387 ) 2388 2389 mapper(Uid, self.tbl_uid, 2390 properties=dict(uid_id=self.tbl_uid.c.id, 2391 fingerprint=relation(Fingerprint)), 2392 ) 2393 2394 mapper(BinContents, self.tbl_bin_contents, 2395 properties=dict( 2396 binary=relation(DBBinary, 2397 backref=backref('contents', lazy='dynamic', cascade='all')), 2398 file=self.tbl_bin_contents.c.file)) 2399 2400 mapper(SrcContents, self.tbl_src_contents, 2401 properties=dict( 2402 source=relation(DBSource, 2403 backref=backref('contents', lazy='dynamic', cascade='all')), 2404 file=self.tbl_src_contents.c.file)) 2405 2406 mapper(MetadataKey, self.tbl_metadata_keys, 2407 properties=dict( 2408 key_id=self.tbl_metadata_keys.c.key_id, 2409 key=self.tbl_metadata_keys.c.key)) 2410 2411 mapper(BinaryMetadata, self.tbl_binaries_metadata, 2412 properties=dict( 2413 binary_id=self.tbl_binaries_metadata.c.bin_id, 2414 binary=relation(DBBinary), 2415 key_id=self.tbl_binaries_metadata.c.key_id, 2416 key=relation(MetadataKey), 2417 value=self.tbl_binaries_metadata.c.value)) 2418 2419 mapper(SourceMetadata, self.tbl_source_metadata, 2420 properties=dict( 2421 source_id=self.tbl_source_metadata.c.src_id, 2422 source=relation(DBSource), 2423 key_id=self.tbl_source_metadata.c.key_id, 2424 key=relation(MetadataKey), 2425 value=self.tbl_source_metadata.c.value)) 2426 2427 mapper(VersionCheck, self.tbl_version_check, 2428 properties=dict( 2429 suite_id=self.tbl_version_check.c.suite, 2430 suite=relation(Suite, primaryjoin=self.tbl_version_check.c.suite == self.tbl_suite.c.id), 2431 reference_id=self.tbl_version_check.c.reference, 2432 reference=relation(Suite, primaryjoin=self.tbl_version_check.c.reference == self.tbl_suite.c.id, lazy='joined')))
2433 2434 ## Connection functions
2435 - def __createconn(self):
2436 from .config import Config 2437 cnf = Config() 2438 if "DB::Service" in cnf: 2439 connstr = "postgresql://service=%s" % cnf["DB::Service"] 2440 elif "DB::Host" in cnf: 2441 # TCP/IP 2442 connstr = "postgresql://%s" % cnf["DB::Host"] 2443 if "DB::Port" in cnf and cnf["DB::Port"] != "-1": 2444 connstr += ":%s" % cnf["DB::Port"] 2445 connstr += "/%s" % cnf["DB::Name"] 2446 else: 2447 # Unix Socket 2448 connstr = "postgresql:///%s" % cnf["DB::Name"] 2449 if "DB::Port" in cnf and cnf["DB::Port"] != "-1": 2450 connstr += "?port=%s" % cnf["DB::Port"] 2451 2452 engine_args = {'echo': self.debug} 2453 if 'DB::PoolSize' in cnf: 2454 engine_args['pool_size'] = int(cnf['DB::PoolSize']) 2455 if 'DB::MaxOverflow' in cnf: 2456 engine_args['max_overflow'] = int(cnf['DB::MaxOverflow']) 2457 # we don't support non-utf-8 connections 2458 engine_args['client_encoding'] = 'utf-8' 2459 2460 # Monkey patch a new dialect in in order to support service= syntax 2461 import sqlalchemy.dialects.postgresql 2462 from sqlalchemy.dialects.postgresql.psycopg2 import PGDialect_psycopg2 2463 2464 class PGDialect_psycopg2_dak(PGDialect_psycopg2): 2465 def create_connect_args(self, url): 2466 if str(url).startswith('postgresql://service='): 2467 # Eww 2468 servicename = str(url)[21:] 2469 return (['service=%s' % servicename], {}) 2470 else: 2471 return PGDialect_psycopg2.create_connect_args(self, url)
2472 2473 sqlalchemy.dialects.postgresql.base.dialect = PGDialect_psycopg2_dak 2474 2475 try: 2476 self.db_pg = create_engine(connstr, **engine_args) 2477 self.db_smaker = sessionmaker(bind=self.db_pg, 2478 autoflush=True, 2479 autocommit=False) 2480 2481 if self.db_meta is None: 2482 self.__class__.db_meta = Base.metadata 2483 self.__class__.db_meta.bind = self.db_pg 2484 self.__setuptables() 2485 self.__setupmappers() 2486 2487 except OperationalError as e: 2488 from . import utils 2489 utils.fubar("Cannot connect to database (%s)" % str(e)) 2490 2491 self.pid = os.getpid() 2492
2493 - def session(self, work_mem=0):
2494 ''' 2495 Returns a new session object. If a work_mem parameter is provided a new 2496 transaction is started and the work_mem parameter is set for this 2497 transaction. The work_mem parameter is measured in MB. A default value 2498 will be used if the parameter is not set. 2499 ''' 2500 # reinitialize DBConn in new processes 2501 if self.pid != os.getpid(): 2502 self.__createconn() 2503 session = self.db_smaker() 2504 if work_mem > 0: 2505 session.execute("SET LOCAL work_mem TO '%d MB'" % work_mem) 2506 return session
2507 2508 2509 __all__.append('DBConn') 2510