Package entropy :: Package db

Source Code for Package entropy.db

   1  # -*- coding: utf-8 -*- 
   2  """ 
   3   
   4      @author: Fabio Erculiani <lxnay@sabayonlinux.org> 
   5      @contact: lxnay@sabayonlinux.org 
   6      @copyright: Fabio Erculiani 
   7      @license: GPL-2 
   8   
   9      B{Entropy Framework repository database module}. 
  10      Entropy repositories (server and client) are implemented as relational 
  11      databases. Currently, EntropyRepository class is the object that wraps 
  12      sqlite3 database queries and repository logic: there are no more 
  13      abstractions between the two because there is only one implementation 
  14      available at this time. In future, entropy.db will feature more backends 
  15      such as MySQL embedded, SparQL, remote repositories support via TCP socket, 
  16      etc. This will require a new layer between the repository interface now 
  17      offered by EntropyRepository and the underlying data retrieval logic. 
  18      Every repository interface available inherits from EntropyRepository 
  19      class and has to reimplement its own Schema subclass and its get_init 
  20      method (see EntropyRepository documentation for more information). 
  21   
  22      I{EntropyRepository} is the sqlite3 implementation of the repository 
  23      interface, as written above. 
  24   
  25      @todo: migrate to "_" (underscore) convention 
  26   
  27  """ 
  28  import sys 
  29  import os 
  30  import shutil 
  31  from entropy.const import etpConst, etpCache, const_setup_file, \ 
  32      const_isunicode, const_convert_to_unicode, const_get_buffer, \ 
  33      const_convert_to_rawstring, const_cmp 
  34  from entropy.exceptions import IncorrectParameter, InvalidAtom, \ 
  35      SystemDatabaseError, OperationNotPermitted, RepositoryPluginError, SPMError 
  36  from entropy.i18n import _ 
  37  from entropy.output import brown, bold, red, blue, purple, darkred, darkgreen, \ 
  38      TextInterface 
  39  from entropy.cache import EntropyCacher 
  40  from entropy.core.settings.base import SystemSettings 
  41  from entropy.spm.plugins.factory import get_default_instance as get_spm 
  42  from entropy.db.plugin_store import EntropyRepositoryPluginStore 
  43   
  44  try: # try with sqlite3 from >=python 2.5 
  45      from sqlite3 import dbapi2 
  46  except ImportError: # fallback to pysqlite 
  47      try: 
  48          from pysqlite2 import dbapi2 
  49      except ImportError as e: 
  50          raise SystemError( 
  51              "%s. %s: %s" % ( 
  52                  _("Entropy needs Python compiled with sqlite3 support"), 
  53                  _("Error"), 
  54                  e, 
  55              ) 
  56          ) 
  57   
58 -class EntropyRepository(EntropyRepositoryPluginStore, TextInterface):
59 60 """ 61 EntropyRepository implements SQLite3 based storage. In a Model-View based 62 pattern, it can be considered the "model". 63 Actually it's the only one available but more model backends will be 64 supported in future (which will inherit this class directly). 65 66 Every Entropy repository storage interface MUST inherit from this base 67 class. 68 69 @todo: refactoring and generalization needed 70 """ 71 72 SETTING_KEYS = [ "arch", "on_delete_cascade" ] 73
74 - class Schema:
75
76 - def get_init(self):
77 return """ 78 CREATE TABLE baseinfo ( 79 idpackage INTEGER PRIMARY KEY AUTOINCREMENT, 80 atom VARCHAR, 81 idcategory INTEGER, 82 name VARCHAR, 83 version VARCHAR, 84 versiontag VARCHAR, 85 revision INTEGER, 86 branch VARCHAR, 87 slot VARCHAR, 88 idlicense INTEGER, 89 etpapi INTEGER, 90 trigger INTEGER 91 ); 92 93 CREATE TABLE extrainfo ( 94 idpackage INTEGER PRIMARY KEY, 95 description VARCHAR, 96 homepage VARCHAR, 97 download VARCHAR, 98 size VARCHAR, 99 idflags INTEGER, 100 digest VARCHAR, 101 datecreation VARCHAR, 102 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 103 ); 104 105 CREATE TABLE content ( 106 idpackage INTEGER, 107 file VARCHAR, 108 type VARCHAR, 109 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 110 ); 111 112 CREATE TABLE provide ( 113 idpackage INTEGER, 114 atom VARCHAR, 115 is_default INTEGER DEFAULT 0, 116 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 117 ); 118 119 CREATE TABLE dependencies ( 120 idpackage INTEGER, 121 iddependency INTEGER, 122 type INTEGER, 123 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 124 ); 125 126 CREATE TABLE dependenciesreference ( 127 iddependency INTEGER PRIMARY KEY AUTOINCREMENT, 128 dependency VARCHAR 129 ); 130 131 CREATE TABLE dependstable ( 132 iddependency INTEGER PRIMARY KEY, 133 idpackage INTEGER 134 ); 135 136 CREATE TABLE conflicts ( 137 idpackage INTEGER, 138 conflict VARCHAR, 139 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 140 ); 141 142 CREATE TABLE mirrorlinks ( 143 mirrorname VARCHAR, 144 mirrorlink VARCHAR 145 ); 146 147 CREATE TABLE sources ( 148 idpackage INTEGER, 149 idsource INTEGER, 150 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 151 ); 152 153 CREATE TABLE sourcesreference ( 154 idsource INTEGER PRIMARY KEY AUTOINCREMENT, 155 source VARCHAR 156 ); 157 158 CREATE TABLE useflags ( 159 idpackage INTEGER, 160 idflag INTEGER, 161 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 162 ); 163 164 CREATE TABLE useflagsreference ( 165 idflag INTEGER PRIMARY KEY AUTOINCREMENT, 166 flagname VARCHAR 167 ); 168 169 CREATE TABLE keywords ( 170 idpackage INTEGER, 171 idkeyword INTEGER, 172 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 173 ); 174 175 CREATE TABLE keywordsreference ( 176 idkeyword INTEGER PRIMARY KEY AUTOINCREMENT, 177 keywordname VARCHAR 178 ); 179 180 CREATE TABLE categories ( 181 idcategory INTEGER PRIMARY KEY AUTOINCREMENT, 182 category VARCHAR 183 ); 184 185 CREATE TABLE licenses ( 186 idlicense INTEGER PRIMARY KEY AUTOINCREMENT, 187 license VARCHAR 188 ); 189 190 CREATE TABLE flags ( 191 idflags INTEGER PRIMARY KEY AUTOINCREMENT, 192 chost VARCHAR, 193 cflags VARCHAR, 194 cxxflags VARCHAR 195 ); 196 197 CREATE TABLE configprotect ( 198 idpackage INTEGER PRIMARY KEY, 199 idprotect INTEGER, 200 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 201 ); 202 203 CREATE TABLE configprotectmask ( 204 idpackage INTEGER PRIMARY KEY, 205 idprotect INTEGER, 206 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 207 ); 208 209 CREATE TABLE configprotectreference ( 210 idprotect INTEGER PRIMARY KEY AUTOINCREMENT, 211 protect VARCHAR 212 ); 213 214 CREATE TABLE systempackages ( 215 idpackage INTEGER PRIMARY KEY, 216 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 217 ); 218 219 CREATE TABLE injected ( 220 idpackage INTEGER PRIMARY KEY, 221 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 222 ); 223 224 CREATE TABLE installedtable ( 225 idpackage INTEGER PRIMARY KEY, 226 repositoryname VARCHAR, 227 source INTEGER, 228 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 229 ); 230 231 CREATE TABLE sizes ( 232 idpackage INTEGER PRIMARY KEY, 233 size INTEGER, 234 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 235 ); 236 237 CREATE TABLE messages ( 238 idpackage INTEGER, 239 message VARCHAR, 240 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 241 ); 242 243 CREATE TABLE counters ( 244 counter INTEGER, 245 idpackage INTEGER, 246 branch VARCHAR, 247 PRIMARY KEY(idpackage,branch), 248 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 249 ); 250 251 CREATE TABLE trashedcounters ( 252 counter INTEGER 253 ); 254 255 CREATE TABLE eclasses ( 256 idpackage INTEGER, 257 idclass INTEGER, 258 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 259 ); 260 261 CREATE TABLE eclassesreference ( 262 idclass INTEGER PRIMARY KEY AUTOINCREMENT, 263 classname VARCHAR 264 ); 265 266 CREATE TABLE needed ( 267 idpackage INTEGER, 268 idneeded INTEGER, 269 elfclass INTEGER, 270 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 271 ); 272 273 CREATE TABLE neededreference ( 274 idneeded INTEGER PRIMARY KEY AUTOINCREMENT, 275 library VARCHAR 276 ); 277 278 CREATE TABLE provided_libs ( 279 idpackage INTEGER, 280 library VARCHAR, 281 path VARCHAR, 282 elfclass INTEGER, 283 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 284 ); 285 286 CREATE TABLE treeupdates ( 287 repository VARCHAR PRIMARY KEY, 288 digest VARCHAR 289 ); 290 291 CREATE TABLE treeupdatesactions ( 292 idupdate INTEGER PRIMARY KEY AUTOINCREMENT, 293 repository VARCHAR, 294 command VARCHAR, 295 branch VARCHAR, 296 date VARCHAR 297 ); 298 299 CREATE TABLE licensedata ( 300 licensename VARCHAR UNIQUE, 301 text BLOB, 302 compressed INTEGER 303 ); 304 305 CREATE TABLE licenses_accepted ( 306 licensename VARCHAR UNIQUE 307 ); 308 309 CREATE TABLE triggers ( 310 idpackage INTEGER PRIMARY KEY, 311 data BLOB, 312 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 313 ); 314 315 CREATE TABLE entropy_misc_counters ( 316 idtype INTEGER PRIMARY KEY, 317 counter INTEGER 318 ); 319 320 CREATE TABLE categoriesdescription ( 321 category VARCHAR, 322 locale VARCHAR, 323 description VARCHAR 324 ); 325 326 CREATE TABLE packagesets ( 327 setname VARCHAR, 328 dependency VARCHAR 329 ); 330 331 CREATE TABLE packagechangelogs ( 332 category VARCHAR, 333 name VARCHAR, 334 changelog BLOB, 335 PRIMARY KEY (category, name) 336 ); 337 338 CREATE TABLE automergefiles ( 339 idpackage INTEGER, 340 configfile VARCHAR, 341 md5 VARCHAR, 342 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 343 ); 344 345 CREATE TABLE packagesignatures ( 346 idpackage INTEGER PRIMARY KEY, 347 sha1 VARCHAR, 348 sha256 VARCHAR, 349 sha512 VARCHAR, 350 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 351 ); 352 353 CREATE TABLE packagespmphases ( 354 idpackage INTEGER PRIMARY KEY, 355 phases VARCHAR, 356 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 357 ); 358 359 CREATE TABLE packagespmrepository ( 360 idpackage INTEGER PRIMARY KEY, 361 repository VARCHAR, 362 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 363 ); 364 365 CREATE TABLE entropy_branch_migration ( 366 repository VARCHAR, 367 from_branch VARCHAR, 368 to_branch VARCHAR, 369 post_migration_md5sum VARCHAR, 370 post_upgrade_md5sum VARCHAR, 371 PRIMARY KEY (repository, from_branch, to_branch) 372 ); 373 374 CREATE TABLE xpakdata ( 375 idpackage INTEGER PRIMARY KEY, 376 data BLOB 377 ); 378 379 CREATE TABLE settings ( 380 setting_name VARCHAR, 381 setting_value VARCHAR, 382 PRIMARY KEY(setting_name) 383 ); 384 385 """
386 387 import entropy.tools as entropyTools 388 import entropy.dump as dumpTools 389 import threading
390 - def __init__(self, readOnly = False, dbFile = None, xcache = False, 391 dbname = 'etpdb:', indexing = True, skipChecks = False):
392 393 """ 394 EntropyRepository constructor. 395 396 @keyword readOnly: open file in read-only mode 397 @type readOnly: bool 398 @keyword dbFile: path to database to open 399 @type dbFile: string 400 @keyword xcache: enable on-disk cache 401 @type xcache: bool 402 @keyword dbname: EntropyRepository instance identifier 403 @type dbname: string 404 @keyword indexing: enable database indexes 405 @type indexing: bool 406 @keyword skipChecks: if True, skip integrity checks 407 @type skipChecks: bool 408 """ 409 EntropyRepositoryPluginStore.__init__(self) 410 411 self.dbclosed = True 412 self.SystemSettings = SystemSettings() 413 self.dbMatchCacheKey = etpCache['dbMatch'] 414 self.client_settings_plugin_id = \ 415 etpConst['system_settings_plugins_ids']['client_plugin'] 416 self.db_branch = self.SystemSettings['repositories']['branch'] 417 self.Cacher = EntropyCacher() 418 419 self.dbname = dbname 420 if self.dbname == etpConst['clientdbid']: 421 self.db_branch = None 422 423 if dbFile is None: 424 raise IncorrectParameter("IncorrectParameter: %s" % ( 425 _("valid database path needed"),) ) 426 427 self.__write_mutex = self.threading.RLock() 428 self.dbapi2 = dbapi2 429 # setup service interface 430 self.readOnly = readOnly 431 self.xcache = xcache 432 self.indexing = indexing 433 self.skipChecks = skipChecks 434 self.dbFile = dbFile 435 self.live_cache = {} 436 437 # create connection 438 self.connection = self.dbapi2.connect(dbFile, timeout=300.0, 439 check_same_thread = False) 440 self.cursor = self.connection.cursor() 441 442 # !!! enable foreign keys pragma !!! do not remove this 443 # otherwise removePackage won't work properly 444 self.cursor.execute("pragma foreign_keys = 1") 445 446 structure_update = False 447 if not self.skipChecks: 448 449 if not self.entropyTools.is_user_in_entropy_group(): 450 # forcing since we won't have write access to db 451 self.indexing = False 452 # live systems don't like wasting RAM 453 if self.entropyTools.islive(): 454 self.indexing = False 455 456 try: 457 if os.access(self.dbFile, os.W_OK) and \ 458 self._doesTableExist('baseinfo') and \ 459 self._doesTableExist('extrainfo'): 460 461 if self.entropyTools.islive(): # this works 462 if etpConst['systemroot']: 463 structure_update = True 464 else: 465 structure_update = True 466 467 except self.dbapi2.Error: 468 self.cursor.close() 469 self.connection.close() 470 raise 471 472 # now we can set this to False 473 self.dbclosed = False 474 475 if structure_update: 476 self._databaseStructureUpdates()
477
478 - def setCacheSize(self, size):
479 """ 480 Change low-level, storage engine based cache size. 481 482 @param size: new size 483 @type size: int 484 """ 485 self.cursor.execute('PRAGMA cache_size = %s' % (size,))
486
487 - def setDefaultCacheSize(self, size):
488 """ 489 Change default low-level, storage engine based cache size. 490 491 @param size: new default size 492 @type size: int 493 """ 494 self.cursor.execute('PRAGMA default_cache_size = %s' % (size,))
495 496
497 - def __del__(self):
498 if not self.dbclosed: 499 self.closeDB()
500
501 - def closeDB(self):
502 """ 503 Close repository storage communication. 504 Note: once issues this, you won't be able to use such instance 505 anymore. 506 """ 507 self.dbclosed = True 508 509 try: 510 511 if not self.readOnly: 512 self.commitChanges() 513 514 plugins = self.get_plugins() 515 for plugin_id in sorted(plugins): 516 plug_inst = plugins[plugin_id] 517 exec_rc = plug_inst.close_repo_hook(self) 518 if exec_rc: 519 raise RepositoryPluginError( 520 "[close_repo_hook] %s: status: %s" % ( 521 plug_inst.get_id(), exec_rc,)) 522 523 finally: 524 self.cursor.close() 525 self.connection.close()
526
527 - def vacuum(self):
528 """ 529 Repository storage cleanup and optimization function. 530 """ 531 self.cursor.execute("vacuum")
532
533 - def commitChanges(self, force = False, no_plugins = False):
534 """ 535 Commit actual changes and make them permanently stored. 536 537 @keyword force: force commit, despite read-only bit being set 538 @type force: bool 539 """ 540 541 if force or (not self.readOnly): 542 try: 543 self.connection.commit() 544 except self.dbapi2.Error: 545 pass 546 547 if no_plugins: 548 return 549 550 plugins = self.get_plugins() 551 for plugin_id in sorted(plugins): 552 plug_inst = plugins[plugin_id] 553 exec_rc = plug_inst.commit_hook(self) 554 if exec_rc: 555 raise RepositoryPluginError("[commit_hook] %s: status: %s" % ( 556 plug_inst.get_id(), exec_rc,))
557
558 - def initializeDatabase(self):
559 """ 560 WARNING: it will erase your database. 561 This method (re)initializes the repository, dropping all its content. 562 """ 563 my = self.Schema() 564 for table in self.listAllTables(): 565 try: 566 self.cursor.execute("DROP TABLE %s" % (table,)) 567 except self.dbapi2.OperationalError: 568 # skip tables that can't be dropped 569 continue 570 self.cursor.executescript(my.get_init()) 571 self._databaseStructureUpdates() 572 # set cache size 573 self.setCacheSize(8192) 574 self.setDefaultCacheSize(8192) 575 self._setupInitialSettings() 576 577 plugins = self.get_plugins() 578 for plugin_id in sorted(plugins): 579 plug_inst = plugins[plugin_id] 580 exec_rc = plug_inst.initialize_repo_hook(self) 581 if exec_rc: 582 raise RepositoryPluginError( 583 "[initialize_repo_hook] %s: status: %s" % ( 584 plug_inst.get_id(), exec_rc,)) 585 586 self.commitChanges()
587
588 - def filterTreeUpdatesActions(self, actions):
589 """ 590 This method should be considered internal and not suited for general 591 audience. Given a raw package name/slot updates list, it returns 592 the action that should be really taken because not applied. 593 594 @param actions: list of raw treeupdates actions, for example: 595 ['move x11-foo/bar app-foo/bar', 'slotmove x11-foo/bar 2 3'] 596 @type actions: list 597 @return: list of raw treeupdates actions that should be really 598 worked out 599 @rtype: list 600 """ 601 new_actions = [] 602 for action in actions: 603 604 if action in new_actions: # skip dupies 605 continue 606 607 doaction = action.split() 608 if doaction[0] == "slotmove": 609 610 # slot move 611 atom = doaction[1] 612 from_slot = doaction[2] 613 to_slot = doaction[3] 614 atom_key = self.entropyTools.dep_getkey(atom) 615 category = atom_key.split("/")[0] 616 matches, sm_rc = self.atomMatch(atom, matchSlot = from_slot, 617 multiMatch = True) 618 if sm_rc == 1: 619 # nothing found in repo that matches atom 620 # this means that no packages can effectively 621 # reference to it 622 continue 623 found = False 624 # found atoms, check category 625 for idpackage in matches: 626 myslot = self.retrieveSlot(idpackage) 627 mycategory = self.retrieveCategory(idpackage) 628 if mycategory == category: 629 if (myslot != to_slot) and \ 630 (action not in new_actions): 631 new_actions.append(action) 632 found = True 633 break 634 if found: 635 continue 636 # if we get here it means found == False 637 # search into dependencies 638 dep_atoms = self.searchDependency(atom_key, like = True, 639 multi = True, strings = True) 640 dep_atoms = [x for x in dep_atoms if x.endswith(":"+from_slot) \ 641 and self.entropyTools.dep_getkey(x) == atom_key] 642 if dep_atoms: 643 new_actions.append(action) 644 645 elif doaction[0] == "move": 646 647 atom = doaction[1] # usually a key 648 atom_key = self.entropyTools.dep_getkey(atom) 649 category = atom_key.split("/")[0] 650 matches, m_rc = self.atomMatch(atom, multiMatch = True) 651 if m_rc == 1: 652 # nothing found in repo that matches atom 653 # this means that no packages can effectively 654 # reference to it 655 continue 656 found = False 657 for idpackage in matches: 658 mycategory = self.retrieveCategory(idpackage) 659 if (mycategory == category) and (action \ 660 not in new_actions): 661 new_actions.append(action) 662 found = True 663 break 664 if found: 665 continue 666 # if we get here it means found == False 667 # search into dependencies 668 dep_atoms = self.searchDependency(atom_key, like = True, 669 multi = True, strings = True) 670 dep_atoms = [x for x in dep_atoms if \ 671 self.entropyTools.dep_getkey(x) == atom_key] 672 if dep_atoms: 673 new_actions.append(action) 674 675 return new_actions
676
677 - def runTreeUpdatesActions(self, actions):
678 # this is the place to add extra actions support 679 """ 680 Method not suited for general purpose usage. 681 Executes package name/slot update actions passed. 682 683 @param actions: list of raw treeupdates actions, for example: 684 ['move x11-foo/bar app-foo/bar', 'slotmove x11-foo/bar 2 3'] 685 @type actions: list 686 687 @return: list (set) of packages that should be repackaged 688 @rtype: set 689 """ 690 mytxt = "%s: %s, %s." % ( 691 bold(_("SPM")), 692 blue(_("Running fixpackages")), 693 red(_("it could take a while")), 694 ) 695 self.updateProgress( 696 mytxt, 697 importance = 1, 698 type = "warning", 699 header = darkred(" * ") 700 ) 701 try: 702 spm = get_spm(self) 703 spm.packages_repositories_metadata_update() 704 except: 705 self.entropyTools.print_traceback() 706 707 spm_moves = set() 708 quickpkg_atoms = set() 709 for action in actions: 710 command = action.split() 711 mytxt = "%s: %s: %s." % ( 712 bold(_("ENTROPY")), 713 red(_("action")), 714 blue(action), 715 ) 716 self.updateProgress( 717 mytxt, 718 importance = 1, 719 type = "warning", 720 header = darkred(" * ") 721 ) 722 if command[0] == "move": 723 spm_moves.add(action) 724 quickpkg_atoms |= self.runTreeUpdatesMoveAction(command[1:], 725 quickpkg_atoms) 726 elif command[0] == "slotmove": 727 quickpkg_atoms |= self.runTreeUpdatesSlotmoveAction(command[1:], 728 quickpkg_atoms) 729 730 mytxt = "%s: %s." % ( 731 bold(_("ENTROPY")), 732 blue(_("package move actions complete")), 733 ) 734 self.updateProgress( 735 mytxt, 736 importance = 1, 737 type = "info", 738 header = purple(" @@ ") 739 ) 740 741 if spm_moves: 742 try: 743 self.doTreeupdatesSpmCleanup(spm_moves) 744 except Exception as e: 745 mytxt = "%s: %s: %s, %s." % ( 746 bold(_("WARNING")), 747 red(_("Cannot run SPM cleanup, error")), 748 Exception, 749 e, 750 ) 751 self.entropyTools.print_traceback() 752 753 mytxt = "%s: %s." % ( 754 bold(_("ENTROPY")), 755 blue(_("package moves completed successfully")), 756 ) 757 self.updateProgress( 758 mytxt, 759 importance = 1, 760 type = "info", 761 header = brown(" @@ ") 762 ) 763 764 # discard cache 765 self.clearCache() 766 767 return quickpkg_atoms
768 769
770 - def runTreeUpdatesMoveAction(self, move_command, quickpkg_queue):
771 # -- move action: 772 # 1) move package key to the new name: category + name + atom 773 # 2) update all the dependencies in dependenciesreference to the new key 774 # 3) run fixpackages which will update /var/db/pkg files 775 # 4) automatically run quickpkg() to build the new binary and 776 # tainted binaries owning tainted iddependency and taint database 777 """ 778 Method not suited for general purpose usage. 779 Executes package name move action passed. 780 781 @param move_command: raw treeupdates move action, for example: 782 'move x11-foo/bar app-foo/bar' 783 @type move_command: string 784 @param quickpkg_queue: current package regeneration queue 785 @type quickpkg_queue: list 786 @return: updated package regeneration queue 787 @rtype: list 788 """ 789 dep_from = move_command[0] 790 key_from = self.entropyTools.dep_getkey(dep_from) 791 key_to = move_command[1] 792 cat_to = key_to.split("/")[0] 793 name_to = key_to.split("/")[1] 794 matches = self.atomMatch(dep_from, multiMatch = True) 795 iddependencies = set() 796 797 for idpackage in matches[0]: 798 799 slot = self.retrieveSlot(idpackage) 800 old_atom = self.retrieveAtom(idpackage) 801 new_atom = old_atom.replace(key_from, key_to) 802 803 ### UPDATE DATABASE 804 # update category 805 self.setCategory(idpackage, cat_to) 806 # update name 807 self.setName(idpackage, name_to) 808 # update atom 809 self.setAtom(idpackage, new_atom) 810 811 # look for packages we need to quickpkg again 812 quickpkg_queue.add(key_to+":"+slot) 813 814 plugins = self.get_plugins() 815 for plugin_id in sorted(plugins): 816 plug_inst = plugins[plugin_id] 817 exec_rc = plug_inst.treeupdates_move_action_hook(self, 818 idpackage) 819 if exec_rc: 820 raise RepositoryPluginError( 821 "[treeupdates_move_action_hook] %s: status: %s" % ( 822 plug_inst.get_id(), exec_rc,)) 823 824 iddeps = self.searchDependency(key_from, like = True, multi = True) 825 for iddep in iddeps: 826 # update string 827 mydep = self.getDependency(iddep) 828 mydep_key = self.entropyTools.dep_getkey(mydep) 829 # avoid changing wrong atoms -> dev-python/qscintilla-python would 830 # become x11-libs/qscintilla if we don't do this check 831 if mydep_key != key_from: 832 continue 833 mydep = mydep.replace(key_from, key_to) 834 # now update 835 # dependstable on server is always re-generated 836 self.setDependency(iddep, mydep) 837 # we have to repackage also package owning this iddep 838 iddependencies |= self.searchIdpackageFromIddependency(iddep) 839 840 self.commitChanges() 841 quickpkg_queue = list(quickpkg_queue) 842 for x in range(len(quickpkg_queue)): 843 myatom = quickpkg_queue[x] 844 myatom = myatom.replace(key_from, key_to) 845 quickpkg_queue[x] = myatom 846 quickpkg_queue = set(quickpkg_queue) 847 for idpackage_owner in iddependencies: 848 myatom = self.retrieveAtom(idpackage_owner) 849 myatom = myatom.replace(key_from, key_to) 850 quickpkg_queue.add(myatom) 851 return quickpkg_queue
852 853
854 - def runTreeUpdatesSlotmoveAction(self, slotmove_command, quickpkg_queue):
855 # -- slotmove action: 856 # 1) move package slot 857 # 2) update all the dependencies in dependenciesreference owning 858 # same matched atom + slot 859 # 3) run fixpackages which will update /var/db/pkg files 860 # 4) automatically run quickpkg() to build the new 861 # binary and tainted binaries owning tainted iddependency 862 # and taint database 863 """ 864 Method not suited for general purpose usage. 865 Executes package slot move action passed. 866 867 @param slotmove_command: raw treeupdates slot move action, for example: 868 'slotmove x11-foo/bar 2 3' 869 @type slotmove_command: string 870 @param quickpkg_queue: current package regeneration queue 871 @type quickpkg_queue: list 872 @return: updated package regeneration queue 873 @rtype: list 874 """ 875 atom = slotmove_command[0] 876 atomkey = self.entropyTools.dep_getkey(atom) 877 slot_from = slotmove_command[1] 878 slot_to = slotmove_command[2] 879 matches = self.atomMatch(atom, multiMatch = True) 880 iddependencies = set() 881 882 matched_idpackages = matches[0] 883 for idpackage in matched_idpackages: 884 885 ### UPDATE DATABASE 886 # update slot 887 self.setSlot(idpackage, slot_to) 888 889 # look for packages we need to quickpkg again 890 # note: quickpkg_queue is simply ignored if client_repo == True 891 quickpkg_queue.add(atom+":"+slot_to) 892 893 # only if we've found VALID matches ! 894 iddeps = self.searchDependency(atomkey, like = True, multi = True) 895 for iddep in iddeps: 896 # update string 897 mydep = self.getDependency(iddep) 898 mydep_key = self.entropyTools.dep_getkey(mydep) 899 if mydep_key != atomkey: 900 continue 901 if not mydep.endswith(":"+slot_from): # probably slotted dep 902 continue 903 mydep_match = self.atomMatch(mydep) 904 if mydep_match not in matched_idpackages: 905 continue 906 mydep = mydep.replace(":"+slot_from, ":"+slot_to) 907 # now update 908 # dependstable on server is always re-generated 909 self.setDependency(iddep, mydep) 910 # we have to repackage also package owning this iddep 911 iddependencies |= self.searchIdpackageFromIddependency(iddep) 912 913 plugins = self.get_plugins() 914 for plugin_id in sorted(plugins): 915 plug_inst = plugins[plugin_id] 916 exec_rc = plug_inst.treeupdates_slot_move_action_hook(self, 917 idpackage) 918 if exec_rc: 919 raise RepositoryPluginError( 920 "[treeupdates_slot_move_action_hook] %s: status: %s" % ( 921 plug_inst.get_id(), exec_rc,)) 922 923 self.commitChanges() 924 for idpackage_owner in iddependencies: 925 myatom = self.retrieveAtom(idpackage_owner) 926 quickpkg_queue.add(myatom) 927 return quickpkg_queue
928
929 - def doTreeupdatesSpmCleanup(self, spm_moves):
930 """ 931 Erase dead Source Package Manager db entries. 932 933 @todo: make more Portage independent (create proper entropy.spm 934 methods for dealing with this) 935 @param spm_moves: list of raw package name/slot update actions. 936 @type spm_moves: list 937 """ 938 # now erase Spm entries if necessary 939 for action in spm_moves: 940 command = action.split() 941 if len(command) < 2: 942 continue 943 944 key = command[1] 945 category, name = key.split("/", 1) 946 dep_key = self.entropyTools.dep_getkey(key) 947 948 try: 949 spm = get_spm(self) 950 except: 951 self.entropyTools.print_traceback() 952 continue 953 954 script_path = spm.get_installed_package_build_script_path(dep_key) 955 pkg_path = os.path.dirname(os.path.dirname(script_path)) 956 if not os.path.isdir(pkg_path): 957 # no dir, no party! 958 continue 959 960 mydirs = [os.path.join(pkg_path, x) for x in \ 961 os.listdir(pkg_path) if \ 962 self.entropyTools.dep_getkey(os.path.join(category, x)) \ 963 == dep_key] 964 mydirs = [x for x in mydirs if os.path.isdir(x)] 965 966 # now move these dirs 967 for mydir in mydirs: 968 to_path = os.path.join(etpConst['packagestmpdir'], 969 os.path.basename(mydir)) 970 mytxt = "%s: %s '%s' %s '%s'" % ( 971 bold(_("SPM")), 972 red(_("Moving old entry")), 973 blue(mydir), 974 red(_("to")), 975 blue(to_path), 976 ) 977 self.updateProgress( 978 mytxt, 979 importance = 1, 980 type = "warning", 981 header = darkred(" * ") 982 ) 983 if os.path.isdir(to_path): 984 shutil.rmtree(to_path, True) 985 try: 986 os.rmdir(to_path) 987 except OSError: 988 pass 989 shutil.move(mydir, to_path)
990 991
992 - def handlePackage(self, pkg_data, forcedRevision = -1, 993 formattedContent = False):
994 """ 995 Update or add a package to repository automatically handling 996 its scope and thus removal of previous versions if requested by 997 the given metadata. 998 pkg_data is a dict() containing all the information bound to 999 a package: 1000 1001 { 1002 'signatures': 1003 { 1004 'sha256': 'zzz', 1005 'sha1': 'zzz', 1006 'sha512': 'zzz' 1007 }, 1008 'slot': '0', 1009 'datecreation': '1247681752.93', 1010 'description': 'Standard (de)compression library', 1011 'useflags': set(['kernel_linux']), 1012 'eclasses': set(['multilib']), 1013 'config_protect_mask': 'string string', 'etpapi': 3, 1014 'mirrorlinks': [], 1015 'cxxflags': '-Os -march=x86-64 -pipe', 1016 'injected': False, 1017 'licensedata': {'ZLIB': u"lictext"}, 1018 'dependencies': {}, 1019 'chost': 'x86_64-pc-linux-gn', 1020 'config_protect': 'string string', 1021 'download': 'packages/amd64/4/sys-libs:zlib-1.2.3-r1.tbz2', 1022 'conflicts': set([]), 1023 'digest': 'fd54248ae060c287b1ec939de3e55332', 1024 'size': '136302', 1025 'category': 'sys-libs', 1026 'license': 'ZLIB', 1027 'sources': set(), 1028 'name': 'zlib', 1029 'versiontag': '', 1030 'changelog': u"text", 1031 'provide': set([]), 1032 'trigger': 'text', 1033 'counter': 22331, 1034 'messages': [], 1035 'branch': '4', 1036 'content': {}, 1037 'needed': [('libc.so.6', 2)], 1038 'version': '1.2.3-r1', 1039 'keywords': set(), 1040 'cflags': '-Os -march=x86-64 -pipe', 1041 'disksize': 932206, 'spm_phases': None, 1042 'homepage': 'http://www.zlib.net/', 1043 'systempackage': True, 1044 'revision': 0 1045 } 1046 1047 @param pkg_data: Entropy package metadata dict 1048 @type pkg_data: dict 1049 @keyword forcedRevision: force a specific package revision 1050 @type forcedRevision: int 1051 @keyword formattedContent: tells whether content metadata is already 1052 formatted for insertion 1053 @type formattedContent: bool 1054 @return: tuple composed by 1055 - idpackage: unique Entropy Repository package identifier 1056 - revision: final package revision selected 1057 - pkg_data: new Entropy package metadata dict 1058 @rtype: tuple 1059 """ 1060 1061 def remove_conflicting_packages(pkgdata): 1062 1063 manual_deps = set() 1064 removelist = self.retrieve_packages_to_remove( 1065 pkgdata['name'], pkgdata['category'], 1066 pkgdata['slot'], pkgdata['injected'] 1067 ) 1068 1069 for r_idpackage in removelist: 1070 manual_deps |= self.retrieveManualDependencies(r_idpackage) 1071 self.removePackage(r_idpackage, do_cleanup = False, 1072 do_commit = False) 1073 1074 # inject old manual dependencies back to package metadata 1075 for manual_dep in manual_deps: 1076 if manual_dep in pkgdata['dependencies']: 1077 continue 1078 pkgdata['dependencies'][manual_dep] = \ 1079 etpConst['dependency_type_ids']['mdepend_id']
1080 1081 # FIXME: this is Entropy Client related but also part of the 1082 # currently implemented metaphor, so let's wait to have a Rule 1083 # Engine in place before removing the oddity of client_repo 1084 # metadatum. 1085 client_repo = self.get_plugins_metadata().get('client_repo') 1086 if client_repo: 1087 remove_conflicting_packages(pkg_data) 1088 return self.addPackage(pkg_data, revision = forcedRevision, 1089 formatted_content = formattedContent) 1090 1091 # build atom string, server side 1092 pkgatom = self.entropyTools.create_package_atom_string( 1093 pkg_data['category'], pkg_data['name'], pkg_data['version'], 1094 pkg_data['versiontag']) 1095 1096 foundid = self.isAtomAvailable(pkgatom) 1097 if foundid < 0: # same atom doesn't exist in any branch 1098 remove_conflicting_packages(pkg_data) 1099 return self.addPackage(pkg_data, revision = forcedRevision, 1100 formatted_content = formattedContent) 1101 1102 idpackages = self.getIDPackages(pkgatom) 1103 current_rev = forcedRevision 1104 1105 for idpackage in idpackages: 1106 1107 if forcedRevision == -1: 1108 myrev = self.retrieveRevision(idpackage) 1109 if myrev > current_rev: 1110 current_rev = myrev 1111 1112 # injected packages wouldn't be removed by addPackage 1113 self.removePackage(idpackage, do_cleanup = False, do_commit = False) 1114 1115 if forcedRevision == -1: 1116 current_rev += 1 1117 1118 # add the new one 1119 remove_conflicting_packages(pkg_data) 1120 return self.addPackage(pkg_data, revision = current_rev, 1121 formatted_content = formattedContent)
1122
1123 - def retrieve_packages_to_remove(self, name, category, slot, injected):
1124 """ 1125 Return a list of packages that would be removed given name, category, 1126 slot and injection status. 1127 1128 @param name: package name 1129 @type name: string 1130 @param category: package category 1131 @type category: string 1132 @param slot: package slot 1133 @type slot: string 1134 @param injected: injection status (packages marked as injected are 1135 always considered not automatically removable) 1136 @type injected: bool 1137 1138 @return: list (set) of removable packages (idpackages) 1139 @rtype: set 1140 """ 1141 1142 removelist = set() 1143 if injected: 1144 # read: if package has been injected, we'll skip 1145 # the removal of packages in the same slot, 1146 # usually used server side btw 1147 return removelist 1148 1149 searchsimilar = self.searchPackagesByNameAndCategory( 1150 name = name, 1151 category = category, 1152 sensitive = True 1153 ) 1154 1155 # FIXME: This is marginally, Entropy server-side stuff but also 1156 # part of the currently implemented metaphor (that will be moved 1157 # to separate class and used through future Rule Engine). 1158 1159 # support for expiration-based packages handling, also internally 1160 # called Fat Scope. 1161 filter_similar = False 1162 srv_ss_plg = etpConst['system_settings_plugins_ids']['server_plugin'] 1163 srv_ss_fs_plg = \ 1164 etpConst['system_settings_plugins_ids']['server_plugin_fatscope'] 1165 1166 srv_plug_settings = self.SystemSettings.get(srv_ss_plg) 1167 if srv_plug_settings is not None: 1168 if srv_plug_settings['server']['exp_based_scope']: 1169 # in case support is enabled, return an empty set 1170 filter_similar = True 1171 1172 if filter_similar: 1173 # filter out packages in the same scope that are allowed to stay 1174 idpkgs = self.SystemSettings[srv_ss_fs_plg]['repos'].get( 1175 self.dbname) 1176 if idpkgs: 1177 if -1 in idpkgs: 1178 del searchsimilar[:] 1179 else: 1180 searchsimilar = [x for x in searchsimilar if x[1] \ 1181 not in idpkgs] 1182 1183 # :-) 1184 # end of FIXME 1185 # :-) 1186 1187 for atom, idpackage in searchsimilar: 1188 # get the package slot 1189 myslot = self.retrieveSlot(idpackage) 1190 # we merely ignore packages with 1191 # negative counters, since they're the injected ones 1192 if self.isInjected(idpackage): 1193 continue 1194 if slot == myslot: 1195 # remove! 1196 removelist.add(idpackage) 1197 1198 return removelist
1199
1200 - def addPackage(self, pkg_data, revision = -1, idpackage = None, 1201 do_commit = True, formatted_content = False):
1202 """ 1203 Add package to this Entropy repository. The main difference between 1204 handlePackage and this is that from here, no packages are going to be 1205 removed, in any case. 1206 For more information about pkg_data layout, please see 1207 I{handlePackage()}. 1208 1209 @param pkg_data: Entropy package metadata 1210 @type pkg_data: dict 1211 @keyword revision: force a specific Entropy package revision 1212 @type revision: int 1213 @keyword idpackage: add package to Entropy repository using the 1214 provided package identifier, this is very dangerous and could 1215 cause packages with the same identifier to be removed. 1216 @type idpackage: int 1217 @keyword do_commit: if True, automatically commits the executed 1218 transaction (could cause slowness) 1219 @type do_commit: bool 1220 @keyword formatted_content: if True, determines whether the content 1221 metadata (usually the biggest part) in pkg_data is already 1222 prepared for insertion 1223 @type formatted_content: bool 1224 @return: tuple composed by 1225 - idpackage: unique Entropy Repository package identifier 1226 - revision: final package revision selected 1227 - pkg_data: new Entropy package metadata dict 1228 @rtype: tuple 1229 """ 1230 if revision == -1: 1231 try: 1232 revision = int(pkg_data['revision']) 1233 except (KeyError, ValueError): 1234 pkg_data['revision'] = 0 # revision not specified 1235 revision = 0 1236 elif 'revision' not in pkg_data: 1237 pkg_data['revision'] = revision 1238 1239 # create new category if it doesn't exist 1240 catid = self.isCategoryAvailable(pkg_data['category']) 1241 if catid == -1: 1242 catid = self.addCategory(pkg_data['category']) 1243 1244 # create new license if it doesn't exist 1245 licid = self.isLicenseAvailable(pkg_data['license']) 1246 if licid == -1: 1247 licid = self.addLicense(pkg_data['license']) 1248 1249 idprotect = self.isProtectAvailable(pkg_data['config_protect']) 1250 if idprotect == -1: 1251 idprotect = self.addProtect(pkg_data['config_protect']) 1252 1253 idprotect_mask = self.isProtectAvailable( 1254 pkg_data['config_protect_mask']) 1255 if idprotect_mask == -1: 1256 idprotect_mask = self.addProtect(pkg_data['config_protect_mask']) 1257 1258 idflags = self.areCompileFlagsAvailable(pkg_data['chost'], 1259 pkg_data['cflags'], pkg_data['cxxflags']) 1260 if idflags == -1: 1261 idflags = self.addCompileFlags(pkg_data['chost'], 1262 pkg_data['cflags'], pkg_data['cxxflags']) 1263 1264 trigger = 0 1265 if pkg_data['trigger']: 1266 trigger = 1 1267 1268 # baseinfo 1269 pkgatom = self.entropyTools.create_package_atom_string( 1270 pkg_data['category'], pkg_data['name'], pkg_data['version'], 1271 pkg_data['versiontag']) 1272 # add atom metadatum 1273 pkg_data['atom'] = pkgatom 1274 1275 mybaseinfo_data = (pkgatom, catid, pkg_data['name'], 1276 pkg_data['version'], pkg_data['versiontag'], revision, 1277 pkg_data['branch'], pkg_data['slot'], 1278 licid, pkg_data['etpapi'], trigger, 1279 ) 1280 1281 myidpackage_string = 'NULL' 1282 if isinstance(idpackage, int): 1283 1284 manual_deps = self.retrieveManualDependencies(idpackage) 1285 1286 # does it exist? 1287 self.removePackage(idpackage, do_cleanup = False, 1288 do_commit = False, from_add_package = True) 1289 myidpackage_string = '?' 1290 mybaseinfo_data = (idpackage,)+mybaseinfo_data 1291 1292 # merge old manual dependencies 1293 dep_dict = pkg_data['dependencies'] 1294 for manual_dep in manual_deps: 1295 if manual_dep in dep_dict: 1296 continue 1297 dep_dict[manual_dep] = \ 1298 etpConst['dependency_type_ids']['mdepend_id'] 1299 1300 else: 1301 # force to None 1302 idpackage = None 1303 1304 1305 with self.__write_mutex: 1306 1307 cur = self.cursor.execute(""" 1308 INSERT INTO baseinfo VALUES (%s,?,?,?,?,?,?,?,?,?,?,?)""" % ( 1309 myidpackage_string,), mybaseinfo_data) 1310 if idpackage is None: 1311 idpackage = cur.lastrowid 1312 1313 # extrainfo 1314 self.cursor.execute( 1315 'INSERT INTO extrainfo VALUES (?,?,?,?,?,?,?,?)', 1316 ( idpackage, 1317 pkg_data['description'], 1318 pkg_data['homepage'], 1319 pkg_data['download'], 1320 pkg_data['size'], 1321 idflags, 1322 pkg_data['digest'], 1323 pkg_data['datecreation'], 1324 ) 1325 ) 1326 ### other information iserted below are not as 1327 ### critical as these above 1328 1329 # tables using a select 1330 self.insertEclasses(idpackage, pkg_data['eclasses']) 1331 self.insertNeeded(idpackage, pkg_data['needed']) 1332 self.insertDependencies(idpackage, pkg_data['dependencies']) 1333 self.insertSources(idpackage, pkg_data['sources']) 1334 self.insertUseflags(idpackage, pkg_data['useflags']) 1335 self.insertKeywords(idpackage, pkg_data['keywords']) 1336 self.insertLicenses(pkg_data['licensedata']) 1337 self.insertMirrors(pkg_data['mirrorlinks']) 1338 # package ChangeLog 1339 if pkg_data.get('changelog'): 1340 self.insertChangelog(pkg_data['category'], pkg_data['name'], 1341 pkg_data['changelog']) 1342 # package signatures 1343 if pkg_data.get('signatures'): 1344 signatures = pkg_data['signatures'] 1345 sha1, sha256, sha512 = signatures['sha1'], \ 1346 signatures['sha256'], signatures['sha512'] 1347 self.insertSignatures(idpackage, sha1, sha256, sha512) 1348 1349 if pkg_data.get('provided_libs'): 1350 self._insertProvidedLibraries(idpackage, pkg_data['provided_libs']) 1351 1352 # spm phases 1353 if pkg_data.get('spm_phases') is not None: 1354 self._insertSpmPhases(idpackage, pkg_data['spm_phases']) 1355 1356 if pkg_data.get('spm_repository') is not None: 1357 self._insertSpmRepository(idpackage, pkg_data['spm_repository']) 1358 1359 # not depending on other tables == no select done 1360 self.insertContent(idpackage, pkg_data['content'], 1361 already_formatted = formatted_content) 1362 1363 # handle SPM UID<->idpackage binding 1364 pkg_data['counter'] = int(pkg_data['counter']) 1365 if not pkg_data['injected'] and (pkg_data['counter'] != -1): 1366 pkg_data['counter'] = self.bindSpmPackageUid( 1367 idpackage, pkg_data['counter'], pkg_data['branch']) 1368 1369 self.insertOnDiskSize(idpackage, pkg_data['disksize']) 1370 if pkg_data['trigger']: 1371 self.insertTrigger(idpackage, pkg_data['trigger']) 1372 self.insertConflicts(idpackage, pkg_data['conflicts']) 1373 1374 if "provide_extended" not in pkg_data: 1375 self.insertProvide(idpackage, pkg_data['provide']) 1376 else: 1377 self.insertProvide(idpackage, pkg_data['provide_extended']) 1378 1379 self.insertMessages(idpackage, pkg_data['messages']) 1380 self.insertConfigProtect(idpackage, idprotect) 1381 self.insertConfigProtect(idpackage, idprotect_mask, mask = True) 1382 # injected? 1383 if pkg_data.get('injected'): 1384 self.setInjected(idpackage, do_commit = False) 1385 # is it a system package? 1386 if pkg_data.get('systempackage'): 1387 self.setSystemPackage(idpackage, do_commit = False) 1388 1389 self.clearCache() # we do live_cache.clear() here too 1390 if do_commit: 1391 self.commitChanges() 1392 1393 plugins = self.get_plugins() 1394 for plugin_id in sorted(plugins): 1395 plug_inst = plugins[plugin_id] 1396 exec_rc = plug_inst.add_package_hook(self, idpackage, pkg_data) 1397 if exec_rc: 1398 raise RepositoryPluginError( 1399 "[add_package_hook] %s: status: %s" % ( 1400 plug_inst.get_id(), exec_rc,)) 1401 1402 return idpackage, revision, pkg_data
1403
1404 - def removePackage(self, idpackage, do_cleanup = True, do_commit = True, 1405 from_add_package = False):
1406 """ 1407 Remove package from this Entropy repository using it's identifier 1408 (idpackage). 1409 1410 @param idpackage: Entropy repository package indentifier 1411 @type idpackage: int 1412 @keyword do_cleanup: if True, executes repository metadata cleanup 1413 at the end 1414 @type do_cleanup: bool 1415 @keyword do_commit: if True, commits the transaction (could cause 1416 slowness) 1417 @type do_commit: bool 1418 @keyword from_add_package: inform function that it's being called from 1419 inside addPackage(). 1420 @type from_add_package: bool 1421 """ 1422 # clear caches 1423 self.clearCache() 1424 1425 plugins = self.get_plugins() 1426 for plugin_id in sorted(plugins): 1427 plug_inst = plugins[plugin_id] 1428 exec_rc = plug_inst.remove_package_hook(self, idpackage, 1429 from_add_package) 1430 if exec_rc: 1431 raise RepositoryPluginError( 1432 "[remove_package_hook] %s: status: %s" % ( 1433 plug_inst.get_id(), exec_rc,)) 1434 1435 with self.__write_mutex: 1436 1437 try: 1438 new_way = self.getSetting("on_delete_cascade") 1439 except KeyError: 1440 new_way = '' 1441 # TODO: deprecate this someday 1442 if new_way: 1443 # this will work thanks to ON DELETE CASCADE ! 1444 self.cursor.execute( 1445 "DELETE FROM baseinfo WHERE idpackage = (?)", (idpackage,)) 1446 else: 1447 r_tup = (idpackage,)*20 1448 self.cursor.executescript(""" 1449 DELETE FROM baseinfo WHERE idpackage = %d; 1450 DELETE FROM extrainfo WHERE idpackage = %d; 1451 DELETE FROM dependencies WHERE idpackage = %d; 1452 DELETE FROM provide WHERE idpackage = %d; 1453 DELETE FROM conflicts WHERE idpackage = %d; 1454 DELETE FROM configprotect WHERE idpackage = %d; 1455 DELETE FROM configprotectmask WHERE idpackage = %d; 1456 DELETE FROM sources WHERE idpackage = %d; 1457 DELETE FROM useflags WHERE idpackage = %d; 1458 DELETE FROM keywords WHERE idpackage = %d; 1459 DELETE FROM content WHERE idpackage = %d; 1460 DELETE FROM messages WHERE idpackage = %d; 1461 DELETE FROM counters WHERE idpackage = %d; 1462 DELETE FROM sizes WHERE idpackage = %d; 1463 DELETE FROM eclasses WHERE idpackage = %d; 1464 DELETE FROM needed WHERE idpackage = %d; 1465 DELETE FROM triggers WHERE idpackage = %d; 1466 DELETE FROM systempackages WHERE idpackage = %d; 1467 DELETE FROM injected WHERE idpackage = %d; 1468 DELETE FROM installedtable WHERE idpackage = %d; 1469 """ % r_tup) 1470 1471 if do_cleanup: 1472 # Cleanups if at least one package has been removed 1473 self.doCleanups() 1474 1475 if do_commit: 1476 self.commitChanges()
1477
1478 - def removeMirrorEntries(self, mirrorname):
1479 """ 1480 Remove source packages mirror entries from database for the given 1481 mirror name. This is a representation of Portage's "thirdpartymirrors". 1482 1483 @param mirrorname: mirror name 1484 @type mirrorname: string 1485 """ 1486 with self.__write_mutex: 1487 self.cursor.execute(""" 1488 DELETE FROM mirrorlinks WHERE mirrorname = (?) 1489 """, (mirrorname,))
1490
1491 - def addMirrors(self, mirrorname, mirrorlist):
1492 """ 1493 Add source package mirror entry to database. 1494 This is a representation of Portage's "thirdpartymirrors". 1495 1496 @param mirrorname: name of the mirror from which "mirrorlist" belongs 1497 @type mirrorname: string 1498 @param mirrorlist: list of URLs belonging to the given mirror name 1499 @type mirrorlist: list 1500 """ 1501 with self.__write_mutex: 1502 self.cursor.executemany(""" 1503 INSERT into mirrorlinks VALUES (?,?) 1504 """, [(mirrorname, x,) for x in mirrorlist])
1505
1506 - def addCategory(self, category):
1507 """ 1508 Add package category string to repository. Return its identifier 1509 (idcategory). 1510 1511 @param category: name of the category to add 1512 @type category: string 1513 @return: category identifier (idcategory) 1514 @rtype: int 1515 """ 1516 with self.__write_mutex: 1517 cur = self.cursor.execute(""" 1518 INSERT into categories VALUES (NULL,?) 1519 """, (category,)) 1520 return cur.lastrowid
1521
1522 - def addProtect(self, protect):
1523 """ 1524 Add a single, generic CONFIG_PROTECT (not defined as _MASK/whatever 1525 here) path. Return its identifier (idprotect). 1526 1527 @param protect: CONFIG_PROTECT path to add 1528 @type protect: string 1529 @return: protect identifier (idprotect) 1530 @rtype: int 1531 """ 1532 with self.__write_mutex: 1533 cur = self.cursor.execute(""" 1534 INSERT into configprotectreference VALUES (NULL,?) 1535 """, (protect,)) 1536 return cur.lastrowid
1537
1538 - def addSource(self, source):
1539 """ 1540 Add source code package download path to repository. Return its 1541 identifier (idsource). 1542 1543 @param source: source package download path 1544 @type source: string 1545 @return: source identifier (idprotect) 1546 @rtype: int 1547 """ 1548 with self.__write_mutex: 1549 cur = self.cursor.execute(""" 1550 INSERT into sourcesreference VALUES (NULL,?) 1551 """, (source,)) 1552 return cur.lastrowid
1553
1554 - def addDependency(self, dependency):
1555 """ 1556 Add dependency string to repository. Return its identifier 1557 (iddependency). 1558 1559 @param dependency: dependency string 1560 @type dependency: string 1561 @return: dependency identifier (iddependency) 1562 @rtype: int 1563 """ 1564 with self.__write_mutex: 1565 cur = self.cursor.execute(""" 1566 INSERT into dependenciesreference VALUES (NULL,?) 1567 """, (dependency,)) 1568 return cur.lastrowid
1569
1570 - def addKeyword(self, keyword):
1571 """ 1572 Add package SPM keyword string to repository. 1573 Return its identifier (idkeyword). 1574 1575 @param keyword: keyword string 1576 @type keyword: string 1577 @return: keyword identifier (idkeyword) 1578 @rtype: int 1579 """ 1580 with self.__write_mutex: 1581 cur = self.cursor.execute(""" 1582 INSERT into keywordsreference VALUES (NULL,?) 1583 """, (keyword,)) 1584 return cur.lastrowid
1585
1586 - def addUseflag(self, useflag):
1587 """ 1588 Add package USE flag string to repository. 1589 Return its identifier (iduseflag). 1590 1591 @param useflag: useflag string 1592 @type useflag: string 1593 @return: useflag identifier (iduseflag) 1594 @rtype: int 1595 """ 1596 with self.__write_mutex: 1597 cur = self.cursor.execute(""" 1598 INSERT into useflagsreference VALUES (NULL,?) 1599 """, (useflag,)) 1600 return cur.lastrowid
1601
1602 - def addEclass(self, eclass):
1603 """ 1604 Add package SPM Eclass string to repository. 1605 Return its identifier (ideclass). 1606 1607 @param eclass: eclass string 1608 @type eclass: string 1609 @return: eclass identifier (ideclass) 1610 @rtype: int 1611 """ 1612 with self.__write_mutex: 1613 cur = self.cursor.execute(""" 1614 INSERT into eclassesreference VALUES (NULL,?) 1615 """, (eclass,)) 1616 return cur.lastrowid
1617
1618 - def addNeeded(self, needed):
1619 """ 1620 Add package libraries' ELF object NEEDED string to repository. 1621 Return its identifier (idneeded). 1622 1623 @param needed: NEEDED string (as shown in `readelf -d elf.so`) 1624 @type needed: string 1625 @return: needed identifier (idneeded) 1626 @rtype: int 1627 """ 1628 with self.__write_mutex: 1629 cur = self.cursor.execute(""" 1630 INSERT into neededreference VALUES (NULL,?) 1631 """, (needed,)) 1632 return cur.lastrowid
1633
1634 - def addLicense(self, pkglicense):
1635 """ 1636 Add package license name string to repository. 1637 Return its identifier (idlicense). 1638 1639 @param pkglicense: license name string 1640 @type pkglicense: string 1641 @return: license name identifier (idlicense) 1642 @rtype: int 1643 """ 1644 if not self.entropyTools.is_valid_string(pkglicense): 1645 pkglicense = ' ' # workaround for broken license entries 1646 with self.__write_mutex: 1647 cur = self.cursor.execute(""" 1648 INSERT into licenses VALUES (NULL,?) 1649 """, (pkglicense,)) 1650 return cur.lastrowid
1651
1652 - def addCompileFlags(self, chost, cflags, cxxflags):
1653 """ 1654 Add package Compiler flags used to repository. 1655 Return its identifier (idflags). 1656 1657 @param chost: CHOST string 1658 @type chost: string 1659 @param cflags: CFLAGS string 1660 @type cflags: string 1661 @param cxxflags: CXXFLAGS string 1662 @type cxxflags: string 1663 @return: Compiler flags triple identifier (idflags) 1664 @rtype: int 1665 """ 1666 with self.__write_mutex: 1667 cur = self.cursor.execute(""" 1668 INSERT into flags VALUES (NULL,?,?,?) 1669 """, (chost, cflags, cxxflags,)) 1670 return cur.lastrowid
1671
1672 - def setSystemPackage(self, idpackage, do_commit = True):
1673 """ 1674 Mark a package as system package, which means that entropy.client 1675 will deny its removal. 1676 1677 @param idpackage: package identifier 1678 @type idpackage: int 1679 @keyword do_commit: determine whether executing commit or not 1680 @type do_commit: bool 1681 """ 1682 with self.__write_mutex: 1683 self.cursor.execute(""" 1684 INSERT into systempackages VALUES (?) 1685 """, (idpackage,)) 1686 if do_commit: 1687 self.commitChanges()
1688
1689 - def setInjected(self, idpackage, do_commit = True):
1690 """ 1691 Mark package as injected, injection is usually set for packages 1692 manually added to repository. Injected packages are not removed 1693 automatically even when featuring conflicting scope with other 1694 that are being added. If a package is injected, it means that 1695 maintainers have to handle it manually. 1696 1697 @param idpackage: package indentifier 1698 @type idpackage: int 1699 @keyword do_commit: determine whether executing commit or not 1700 @type do_commit: bool 1701 """ 1702 with self.__write_mutex: 1703 if not self.isInjected(idpackage): 1704 self.cursor.execute(""" 1705 INSERT into injected VALUES (?) 1706 """, (idpackage,)) 1707 if do_commit: 1708 self.commitChanges()
1709
1710 - def setCreationDate(self, idpackage, date):
1711 """ 1712 Update the creation date for package. Creation date is stored in 1713 string based unix time format. 1714 1715 @param idpackage: package indentifier 1716 @type idpackage: int 1717 @param date: unix time in string form 1718 @type date: string 1719 """ 1720 with self.__write_mutex: 1721 self.cursor.execute(""" 1722 UPDATE extrainfo SET datecreation = (?) WHERE idpackage = (?) 1723 """, (str(date), idpackage,)) 1724 self.commitChanges()
1725
1726 - def setDigest(self, idpackage, digest):
1727 """ 1728 Set package file md5sum for package. This information is used 1729 by entropy.client when downloading packages. 1730 1731 @param idpackage: package indentifier 1732 @type idpackage: int 1733 @param digest: md5 hash for package file 1734 @type digest: string 1735 """ 1736 with self.__write_mutex: 1737 self.cursor.execute(""" 1738 UPDATE extrainfo SET digest = (?) WHERE idpackage = (?) 1739 """, (digest, idpackage,)) 1740 self.commitChanges()
1741
1742 - def setSignatures(self, idpackage, sha1, sha256, sha512):
1743 """ 1744 Set package file extra hashes (sha1, sha256, sha512) for package. 1745 1746 @param idpackage: package indentifier 1747 @type idpackage: int 1748 @param sha1: SHA1 hash for package file 1749 @type sha1: string 1750 @param sha256: SHA256 hash for package file 1751 @type sha256: string 1752 @param sha512: SHA512 hash for package file 1753 @type sha512: string 1754 """ 1755 with self.__write_mutex: 1756 self.cursor.execute(""" 1757 UPDATE packagesignatures SET sha1 = (?), sha256 = (?), sha512 = (?) 1758 WHERE idpackage = (?) 1759 """, (sha1, sha256, sha512, idpackage))
1760
1761 - def setDownloadURL(self, idpackage, url):
1762 """ 1763 Set download URL prefix for package. 1764 1765 @param idpackage: package indentifier 1766 @type idpackage: int 1767 @param url: URL prefix to set 1768 @type url: string 1769 """ 1770 with self.__write_mutex: 1771 self.cursor.execute(""" 1772 UPDATE extrainfo SET download = (?) WHERE idpackage = (?) 1773 """, (url, idpackage,)) 1774 self.commitChanges()
1775
1776 - def setCategory(self, idpackage, category):
1777 """ 1778 Set category name for package. 1779 1780 @param idpackage: package indentifier 1781 @type idpackage: int 1782 @param category: category to set 1783 @type category: string 1784 """ 1785 # create new category if it doesn't exist 1786 catid = self.isCategoryAvailable(category) 1787 if catid == -1: 1788 # create category 1789 catid = self.addCategory(category) 1790 1791 with self.__write_mutex: 1792 self.cursor.execute(""" 1793 UPDATE baseinfo SET idcategory = (?) WHERE idpackage = (?) 1794 """, (catid, idpackage,)) 1795 self.commitChanges()
1796
1797 - def setCategoryDescription(self, category, description_data):
1798 """ 1799 Set description for given category name. 1800 1801 @param category: category name 1802 @type category: string 1803 @param description_data: category description for several locales. 1804 {'en': "This is blah", 'it': "Questo e' blah", ... } 1805 @type description_data: dict 1806 """ 1807 with self.__write_mutex: 1808 1809 self.cursor.execute(""" 1810 DELETE FROM categoriesdescription WHERE category = (?) 1811 """, (category,)) 1812 for locale in description_data: 1813 mydesc = description_data[locale] 1814 self.cursor.execute(""" 1815 INSERT INTO categoriesdescription VALUES (?,?,?) 1816 """, (category, locale, mydesc,)) 1817 1818 self.commitChanges()
1819
1820 - def setName(self, idpackage, name):
1821 """ 1822 Set name for package. 1823 1824 @param idpackage: package indentifier 1825 @type idpackage: int 1826 @param name: package name 1827 @type name: string 1828 1829 """ 1830 with self.__write_mutex: 1831 self.cursor.execute(""" 1832 UPDATE baseinfo SET name = (?) WHERE idpackage = (?) 1833 """, (name, idpackage,)) 1834 self.commitChanges()
1835
1836 - def setDependency(self, iddependency, dependency):
1837 """ 1838 Set dependency string for iddependency (dependency identifier). 1839 1840 @param iddependency: dependency string identifier 1841 @type iddependency: int 1842 @param dependency: dependency string 1843 @type dependency: string 1844 """ 1845 with self.__write_mutex: 1846 self.cursor.execute(""" 1847 UPDATE dependenciesreference SET dependency = (?) 1848 WHERE iddependency = (?) 1849 """, (dependency, iddependency,)) 1850 self.commitChanges()
1851
1852 - def setAtom(self, idpackage, atom):
1853 """ 1854 Set atom string for package. "Atom" is the full, unique name of 1855 a package. 1856 1857 @param idpackage: package indentifier 1858 @type idpackage: int 1859 @param atom: atom string 1860 @type atom: string 1861 """ 1862 with self.__write_mutex: 1863 self.cursor.execute(""" 1864 UPDATE baseinfo SET atom = (?) WHERE idpackage = (?) 1865 """, (atom, idpackage,)) 1866 self.commitChanges()
1867
1868 - def setSlot(self, idpackage, slot):
1869 """ 1870 Set slot string for package. Please refer to Portage SLOT documentation 1871 for more info. 1872 1873 @param idpackage: package indentifier 1874 @type idpackage: int 1875 @param slot: slot string 1876 @type slot: string 1877 """ 1878 with self.__write_mutex: 1879 self.cursor.execute(""" 1880 UPDATE baseinfo SET slot = (?) WHERE idpackage = (?) 1881 """, (slot, idpackage,)) 1882 self.commitChanges()
1883
1884 - def setRevision(self, idpackage, revision):
1885 """ 1886 Set Entropy revision for package. 1887 1888 @param idpackage: package indentifier 1889 @type idpackage: int 1890 @param revision: new revision 1891 @type revision: int 1892 """ 1893 with self.__write_mutex: 1894 self.cursor.execute(""" 1895 UPDATE baseinfo SET revision = (?) WHERE idpackage = (?) 1896 """, (revision, idpackage,)) 1897 self.commitChanges()
1898
1899 - def removeLicensedata(self, license_name):
1900 """ 1901 Remove license text for given license name identifier. 1902 1903 @param license_name: available license name identifier 1904 @type license_name: string 1905 """ 1906 with self.__write_mutex: 1907 self.cursor.execute(""" 1908 DELETE FROM licensedata WHERE licensename = (?) 1909 """, (license_name,))
1910
1911 - def removeDependencies(self, idpackage):
1912 """ 1913 Remove all the dependencies of package. 1914 1915 @param idpackage: package indentifier 1916 @type idpackage: int 1917 """ 1918 with self.__write_mutex: 1919 self.cursor.execute(""" 1920 DELETE FROM dependencies WHERE idpackage = (?) 1921 """, (idpackage,)) 1922 self.commitChanges()
1923
1924 - def insertDependencies(self, idpackage, depdata):
1925 """ 1926 Insert dependencies for package. "depdata" is a dict() with dependency 1927 strings as keys and dependency type as values. 1928 1929 @param idpackage: package indentifier 1930 @type idpackage: int 1931 @param depdata: dependency dictionary 1932 {'app-foo/foo': dep_type_integer, ...} 1933 @type depdata: dict 1934 """ 1935 1936 dcache = set() 1937 add_dep = self.addDependency 1938 is_dep_avail = self.isDependencyAvailable 1939 def mymf(dep): 1940 1941 if dep in dcache: 1942 return 0 1943 iddep = is_dep_avail(dep) 1944 if iddep == -1: 1945 iddep = add_dep(dep) 1946 1947 deptype = 0 1948 if isinstance(depdata, dict): 1949 deptype = depdata[dep] 1950 1951 dcache.add(dep) 1952 return (idpackage, iddep, deptype,)
1953 1954 deps = [x for x in map(mymf, depdata) if not isinstance(x, int)] 1955 with self.__write_mutex: 1956 self.cursor.executemany(""" 1957 INSERT into dependencies VALUES (?,?,?) 1958 """, deps) 1959
1960 - def insertManualDependencies(self, idpackage, manual_deps):
1961 """ 1962 Insert manually added dependencies to dep. list of package. 1963 1964 @param idpackage: package indentifier 1965 @type idpackage: int 1966 @param manual_deps: list of dependency strings 1967 @type manual_deps: list 1968 """ 1969 mydict = {} 1970 for manual_dep in manual_deps: 1971 mydict[manual_dep] = etpConst['dependency_type_ids']['mdepend_id'] 1972 return self.insertDependencies(idpackage, mydict)
1973
1974 - def removeContent(self, idpackage):
1975 """ 1976 Remove content metadata for package. 1977 1978 @param idpackage: package indentifier 1979 @type idpackage: int 1980 """ 1981 with self.__write_mutex: 1982 self.cursor.execute("DELETE FROM content WHERE idpackage = (?)", (idpackage,)) 1983 self.commitChanges()
1984
1985 - def insertContent(self, idpackage, content, already_formatted = False):
1986 """ 1987 Insert content metadata for package. "content" can either be a dict() 1988 or a list of triples (tuples of length 3, (idpackage, path, type,)). 1989 1990 @param idpackage: package indentifier 1991 @type idpackage: int 1992 @param content: content metadata to insert. 1993 {'/path/to/foo': 'obj(content type)',} 1994 or 1995 [(idpackage, path, type,) ...] 1996 @type content: dict, list 1997 @keyword already_formatted: if True, "content" is expected to be 1998 already formatted for insertion, this means that "content" must be 1999 a list of tuples of length 3. 2000 @type already_formatted: bool 2001 """ 2002 2003 with self.__write_mutex: 2004 2005 if already_formatted: 2006 self.cursor.executemany(""" 2007 INSERT INTO content VALUES (?,?,?) 2008 """, [(idpackage, x, y,) for a, x, y in content]) 2009 else: 2010 self.cursor.executemany(""" 2011 INSERT INTO content VALUES (?,?,?) 2012 """, [(idpackage, x, content[x],) for x in content])
2013
2014 - def _insertProvidedLibraries(self, idpackage, libs_metadata):
2015 """ 2016 Insert library metadata owned by package. 2017 2018 @param idpackage: package indentifier 2019 @type idpackage: int 2020 @param libs_metadata: provided library metadata composed by list of 2021 tuples of length 3 containing library name, path and ELF class. 2022 @type libs_metadata: list 2023 """ 2024 # TODO: remove this in future 2025 if not self._doesTableExist('provided_libs'): 2026 self._createProvidedLibs() 2027 2028 with self.__write_mutex: 2029 self.cursor.executemany(""" 2030 INSERT INTO provided_libs VALUES (?,?,?,?) 2031 """, [(idpackage, x, y, z,) for x, y, z in libs_metadata])
2032
2033 - def insertAutomergefiles(self, idpackage, automerge_data):
2034 """ 2035 Insert configuration files automerge information for package. 2036 "automerge_data" contains configuration files paths and their belonging 2037 md5 hash. 2038 This features allows entropy.client to "auto-merge" or "auto-remove" 2039 configuration files never touched by user. 2040 2041 @param idpackage: package indentifier 2042 @type idpackage: int 2043 @param automerge_data: list of tuples of length 2. 2044 [('/path/to/conf/file', 'md5_checksum_string',) ... ] 2045 @type automerge_data: list 2046 """ 2047 with self.__write_mutex: 2048 self.cursor.executemany('INSERT INTO automergefiles VALUES (?,?,?)', 2049 [(idpackage, x, y,) for x, y in automerge_data])
2050
2051 - def insertChangelog(self, category, name, changelog_txt):
2052 """ 2053 Insert package changelog for package (in this case using category + 2054 name as key). 2055 2056 @param category: package category 2057 @type category: string 2058 @param name: package name 2059 @type name: string 2060 @param changelog_txt: changelog text 2061 @type changelog_txt: string 2062 """ 2063 with self.__write_mutex: 2064 2065 mytxt = changelog_txt.encode('raw_unicode_escape') 2066 2067 self.cursor.execute(""" 2068 DELETE FROM packagechangelogs WHERE category = (?) AND name = (?) 2069 """, (category, name,)) 2070 2071 self.cursor.execute(""" 2072 INSERT INTO packagechangelogs VALUES (?,?,?) 2073 """, (category, name, const_get_buffer()(mytxt),))
2074
2075 - def insertLicenses(self, licenses_data):
2076 """ 2077 insert license data (license names and text) into repository. 2078 2079 @param licenses_data: dictionary containing license names as keys and 2080 text as values 2081 @type licenses_data: dict 2082 """ 2083 2084 mylicenses = list(licenses_data.keys()) 2085 def my_mf(mylicense): 2086 return not self.isLicensedataKeyAvailable(mylicense)
2087 2088 def my_mm(mylicense): 2089 2090 lic_data = licenses_data.get(mylicense, '') 2091 2092 # support both utf8 and str input 2093 if const_isunicode(lic_data): # encode to str 2094 try: 2095 lic_data = lic_data.encode('raw_unicode_escape') 2096 except (UnicodeDecodeError,): 2097 lic_data = lic_data.encode('utf-8') 2098 2099 return (mylicense, const_get_buffer()(lic_data), 0,) 2100 2101 with self.__write_mutex: 2102 # set() used after filter to remove duplicates 2103 self.cursor.executemany(""" 2104 INSERT into licensedata VALUES (?,?,?) 2105 """, list(map(my_mm, set(filter(my_mf, mylicenses))))) 2106
2107 - def insertConfigProtect(self, idpackage, idprotect, mask = False):
2108 """ 2109 Insert CONFIG_PROTECT (configuration files protection) entry identifier 2110 for package. This entry is usually a space separated string of directory 2111 and files which are used to handle user-protected configuration files 2112 or directories, those that are going to be stashed in separate paths 2113 waiting for user merge decisions. 2114 2115 @param idpackage: package indentifier 2116 @type idpackage: int 2117 @param idprotect: configuration files protection identifier 2118 @type idprotect: int 2119 @keyword mask: if True, idproctect will be considered a "mask" entry, 2120 meaning that configuration files starting with paths referenced 2121 by idprotect will be forcefully merged. 2122 @type mask: bool 2123 """ 2124 2125 mytable = 'configprotect' 2126 if mask: 2127 mytable += 'mask' 2128 with self.__write_mutex: 2129 self.cursor.execute(""" 2130 INSERT into %s VALUES (?,?) 2131 """ % (mytable,), (idpackage, idprotect,))
2132
2133 - def insertMirrors(self, mirrors):
2134 """ 2135 Insert list of "mirror name" and "mirror list" into repository. 2136 The term "mirror" in this case references to Source Package Manager 2137 package download mirrors. 2138 Argument format is like this for historical reasons and may change in 2139 future. 2140 2141 @todo: change argument format 2142 @param mirrors: list of tuples of length 2 containing string as first 2143 item and list as second. 2144 [('openoffice', ['http://openoffice1', 'http://..."],), ...] 2145 @type mirrors: list 2146 """ 2147 2148 for mirrorname, mirrorlist in mirrors: 2149 # remove old 2150 self.removeMirrorEntries(mirrorname) 2151 # add new 2152 self.addMirrors(mirrorname, mirrorlist)
2153
2154 - def insertKeywords(self, idpackage, keywords):
2155 """ 2156 Insert keywords for package. Keywords are strings contained in package 2157 metadata stating what architectures or subarchitectures are supported 2158 by package. It is historically used also for masking packages (making 2159 them not available). 2160 2161 @param idpackage: package indentifier 2162 @type idpackage: int 2163 @param keywords: list of keywords 2164 @type keywords: list 2165 """ 2166 2167 def mymf(key): 2168 idkeyword = self.isKeywordAvailable(key) 2169 if idkeyword == -1: 2170 # create category 2171 idkeyword = self.addKeyword(key) 2172 return (idpackage, idkeyword,)
2173 2174 with self.__write_mutex: 2175 self.cursor.executemany(""" 2176 INSERT into keywords VALUES (?,?) 2177 """, list(map(mymf, keywords))) 2178
2179 - def insertUseflags(self, idpackage, useflags):
2180 """ 2181 Insert Source Package Manager USE (components build) flags for package. 2182 2183 @param idpackage: package indentifier 2184 @type idpackage: int 2185 @param useflags: list of use flags strings 2186 @type useflags: list 2187 """ 2188 2189 def mymf(flag): 2190 iduseflag = self.isUseflagAvailable(flag) 2191 if iduseflag == -1: 2192 # create category 2193 iduseflag = self.addUseflag(flag) 2194 return (idpackage, iduseflag,)
2195 2196 with self.__write_mutex: 2197 self.cursor.executemany(""" 2198 INSERT into useflags VALUES (?,?) 2199 """, list(map(mymf, useflags))) 2200
2201 - def insertSignatures(self, idpackage, sha1, sha256, sha512):
2202 """ 2203 Insert package file extra hashes (sha1, sha256, sha512) for package. 2204 2205 @param idpackage: package indentifier 2206 @type idpackage: int 2207 @param sha1: SHA1 hash for package file 2208 @type sha1: string 2209 @param sha256: SHA256 hash for package file 2210 @type sha256: string 2211 @param sha512: SHA512 hash for package file 2212 @type sha512: string 2213 """ 2214 with self.__write_mutex: 2215 self.cursor.execute(""" 2216 INSERT INTO packagesignatures VALUES (?,?,?,?) 2217 """, (idpackage, sha1, sha256, sha512))
2218
2219 - def _insertSpmPhases(self, idpackage, phases):
2220 """ 2221 Insert Source Package Manager phases for package. 2222 Entropy can call several Source Package Manager (the PM which Entropy 2223 relies on) package installation/removal phases. 2224 Such phase names are listed here. 2225 2226 @param idpackage: package indentifier 2227 @type idpackage: int 2228 @param phases: list of available Source Package Manager phases 2229 @type phases: list 2230 """ 2231 with self.__write_mutex: 2232 self.cursor.execute(""" 2233 INSERT INTO packagespmphases VALUES (?,?) 2234 """, (idpackage, phases,))
2235
2236 - def _insertSpmRepository(self, idpackage, repository):
2237 """ 2238 Insert Source Package Manager repository for package. 2239 This medatatum describes the source repository where package has 2240 been compiled from. 2241 2242 @param idpackage: package indentifier 2243 @type idpackage: int 2244 @param repository: Source Package Manager repository 2245 @type repository: string 2246 """ 2247 with self.__write_mutex: 2248 self.cursor.execute(""" 2249 INSERT INTO packagespmrepository VALUES (?,?) 2250 """, (idpackage, repository,))
2251
2252 - def insertSources(self, idpackage, sources):
2253 """ 2254 Insert source code package download URLs for idpackage. 2255 2256 @param idpackage: package indentifier 2257 @type idpackage: int 2258 @param sources: list of source URLs 2259 @type sources: list 2260 """ 2261 def mymf(source): 2262 2263 if (not source) or \ 2264 (not self.entropyTools.is_valid_string(source)): 2265 return 0 2266 2267 idsource = self.isSourceAvailable(source) 2268 if idsource == -1: 2269 idsource = self.addSource(source) 2270 2271 return (idpackage, idsource,)
2272 2273 with self.__write_mutex: 2274 self.cursor.executemany(""" 2275 INSERT into sources VALUES (?,?) 2276 """, [x for x in map(mymf, sources) if x != 0]) 2277
2278 - def insertConflicts(self, idpackage, conflicts):
2279 """ 2280 Insert dependency conflicts for package. 2281 2282 @param idpackage: package indentifier 2283 @type idpackage: int 2284 @param conflicts: list of dep. conflicts 2285 @type conflicts: list 2286 """ 2287 with self.__write_mutex: 2288 self.cursor.executemany(""" 2289 INSERT into conflicts VALUES (?,?) 2290 """, [(idpackage, x,) for x in conflicts])
2291
2292 - def insertMessages(self, idpackage, messages):
2293 """ 2294 Insert user messages for package. 2295 2296 @param idpackage: package indentifier 2297 @type idpackage: int 2298 @param messages: list of messages 2299 @type messages: list 2300 """ 2301 with self.__write_mutex: 2302 self.cursor.executemany(""" 2303 INSERT into messages VALUES (?,?) 2304 """, [(idpackage, x,) for x in messages])
2305
2306 - def insertProvide(self, idpackage, provides):
2307 """ 2308 Insert PROVIDE metadata for idpackage. 2309 This has been added for supporting Portage Source Package Manager 2310 old-style meta-packages support. 2311 Packages can provide extra atoms, you can see it like aliases, where 2312 these can be given by multiple packages. This allowed to make available 2313 multiple applications providing the same functionality which depending 2314 packages can reference, without forcefully being bound to a single 2315 package. 2316 2317 @param idpackage: package indentifier 2318 @type idpackage: int 2319 @param provides: list of atom strings 2320 @type provides: list 2321 """ 2322 # FIXME: backward compat, remove someday 2323 # this adds default provide information to set data if not available 2324 my_provides = set() 2325 for prov in provides: 2326 if not isinstance(prov, tuple): 2327 my_provides.add((prov, 0,)) 2328 else: 2329 my_provides.add(prov) 2330 2331 default_provides = [x for x in my_provides if x[1]] 2332 2333 with self.__write_mutex: 2334 2335 self.cursor.executemany(""" 2336 INSERT into provide VALUES (?,?,?) 2337 """, [(idpackage, x, y,) for x, y in my_provides]) 2338 2339 if default_provides: 2340 # reset previously set default provides 2341 self.cursor.executemany(""" 2342 UPDATE provide SET is_default=0 WHERE atom = (?) AND 2343 idpackage != (?) 2344 """, default_provides)
2345
2346 - def insertNeeded(self, idpackage, neededs):
2347 """ 2348 Insert package libraries' ELF object NEEDED string for package. 2349 Return its identifier (idneeded). 2350 2351 @param idpackage: package indentifier 2352 @type idpackage: int 2353 @param neededs: list of NEEDED string (as shown in `readelf -d elf.so`) 2354 @type neededs: string 2355 """ 2356 def mymf(needed_data): 2357 needed, elfclass = needed_data 2358 idneeded = self.isNeededAvailable(needed) 2359 if idneeded == -1: 2360 # create eclass 2361 idneeded = self.addNeeded(needed) 2362 return (idpackage, idneeded, elfclass,)
2363 2364 with self.__write_mutex: 2365 self.cursor.executemany(""" 2366 INSERT into needed VALUES (?,?,?) 2367 """, list(map(mymf, neededs))) 2368
2369 - def insertEclasses(self, idpackage, eclasses):
2370 """ 2371 Insert Source Package Manager used build specification file classes. 2372 The term "eclasses" is derived from Portage. 2373 2374 @param idpackage: package indentifier 2375 @type idpackage: int 2376 @param eclasses: list of classes 2377 @type eclasses: list 2378 """ 2379 2380 def mymf(eclass): 2381 idclass = self.isEclassAvailable(eclass) 2382 if idclass == -1: 2383 idclass = self.addEclass(eclass) 2384 return (idpackage, idclass,)
2385 2386 with self.__write_mutex: 2387 self.cursor.executemany(""" 2388 INSERT into eclasses VALUES (?,?) 2389 """, list(map(mymf, eclasses))) 2390
2391 - def insertOnDiskSize(self, idpackage, mysize):
2392 """ 2393 Insert on-disk size (bytes) for package. 2394 2395 @param idpackage: package indentifier 2396 @type idpackage: int 2397 @param mysize: package size (bytes) 2398 @type mysize: int 2399 """ 2400 with self.__write_mutex: 2401 self.cursor.execute(""" 2402 INSERT into sizes VALUES (?,?) 2403 """, (idpackage, mysize,))
2404
2405 - def insertTrigger(self, idpackage, trigger):
2406 """ 2407 Insert built-in trigger script for package, containing 2408 pre-install, post-install, pre-remove, post-remove hooks. 2409 This feature should be considered DEPRECATED, and kept for convenience. 2410 Please use Source Package Manager features if possible. 2411 2412 @param idpackage: package indentifier 2413 @type idpackage: int 2414 @param trigger: trigger file dump 2415 @type trigger: string 2416 """ 2417 with self.__write_mutex: 2418 self.cursor.execute(""" 2419 INSERT into triggers VALUES (?,?) 2420 """, (idpackage, const_get_buffer()(trigger),))
2421
2422 - def insertBranchMigration(self, repository, from_branch, to_branch, 2423 post_migration_md5sum, post_upgrade_md5sum):
2424 """ 2425 Insert Entropy Client "branch migration" scripts hash metadata. 2426 When upgrading from a branch to another, it can happen that repositories 2427 ship with scripts aiming to ease the upgrade. 2428 This method stores in the repository information on such scripts. 2429 2430 @param repository: repository identifier 2431 @type repository: string 2432 @param from_branch: original branch 2433 @type from_branch: string 2434 @param to_branch: destination branch 2435 @type to_branch: string 2436 @param post_migration_md5sum: md5 hash related to "post-migration" 2437 branch script file 2438 @type post_migration_md5sum: string 2439 @param post_upgrade_md5sum: md5 hash related to "post-upgrade on new 2440 branch" script file 2441 @type post_upgrade_md5sum: string 2442 """ 2443 with self.__write_mutex: 2444 self.cursor.execute(""" 2445 INSERT OR REPLACE INTO entropy_branch_migration VALUES (?,?,?,?,?) 2446 """, ( 2447 repository, from_branch, 2448 to_branch, post_migration_md5sum, 2449 post_upgrade_md5sum, 2450 ) 2451 )
2452
2453 - def setBranchMigrationPostUpgradeMd5sum(self, repository, from_branch, 2454 to_branch, post_upgrade_md5sum):
2455 """ 2456 Update "post-upgrade on new branch" script file md5 hash. 2457 When upgrading from a branch to another, it can happen that repositories 2458 ship with scripts aiming to ease the upgrade. 2459 This method stores in the repository information on such scripts. 2460 2461 @param repository: repository identifier 2462 @type repository: string 2463 @param from_branch: original branch 2464 @type from_branch: string 2465 @param to_branch: destination branch 2466 @type to_branch: string 2467 @param post_upgrade_md5sum: md5 hash related to "post-upgrade on new 2468 branch" script file 2469 @type post_upgrade_md5sum: string 2470 """ 2471 with self.__write_mutex: 2472 self.cursor.execute(""" 2473 UPDATE entropy_branch_migration SET post_upgrade_md5sum = (?) WHERE 2474 repository = (?) AND from_branch = (?) AND to_branch = (?) 2475 """, (post_upgrade_md5sum, repository, from_branch, to_branch,))
2476 2477
2478 - def bindSpmPackageUid(self, idpackage, spm_package_uid, branch):
2479 """ 2480 Bind Source Package Manager package identifier ("COUNTER" metadata 2481 for Portage) to Entropy package. 2482 If uid <= -2, a new negative UID will be allocated and returned. 2483 Negative UIDs are considered auto-allocated by Entropy. 2484 This is mainly used for binary packages not belonging to any SPM 2485 packages which are just "injected" inside the repository. 2486 2487 @param idpackage: package indentifier 2488 @type idpackage: int 2489 @param spm_package_uid: Source package Manager unique package identifier 2490 @type spm_package_uid: int 2491 @param branch: current running Entropy branch 2492 @type branch: string 2493 @return: uid set 2494 @rtype: int 2495 """ 2496 2497 my_uid = spm_package_uid 2498 2499 if my_uid <= -2: 2500 # special cases 2501 my_uid = self.getNewNegativeSpmUid() 2502 2503 with self.__write_mutex: 2504 try: 2505 self.cursor.execute('INSERT into counters VALUES (?,?,?)', 2506 (my_uid, idpackage, branch,)) 2507 except self.dbapi2.IntegrityError: 2508 # we have a PRIMARY KEY we need to remove 2509 self._migrateCountersTable() 2510 self.cursor.execute('INSERT into counters VALUES (?,?,?)', 2511 (my_uid, idpackage, branch,)) 2512 2513 return my_uid
2514
2515 - def insertSpmUid(self, idpackage, spm_package_uid, branch = None):
2516 """ 2517 Insert Source Package Manager unique package identifier and bind it 2518 to Entropy package identifier given (idpackage). This method is used 2519 by Entropy Client and differs from "bindSpmPackageUid" because 2520 any other colliding idpackage<->uid binding is overwritten by design. 2521 2522 @param idpackage: package indentifier 2523 @type idpackage: int 2524 @param spm_package_uid: Source package Manager unique package identifier 2525 @type spm_package_uid: int 2526 @param branch: current running Entropy branch 2527 @type branch: string 2528 """ 2529 if not branch: 2530 branch = self.db_branch 2531 if not branch: 2532 branch = self.SystemSettings['repositories']['branch'] 2533 2534 with self.__write_mutex: 2535 2536 self.cursor.execute(""" 2537 DELETE FROM counters WHERE (counter = (?) OR 2538 idpackage = (?)) AND branch = (?); 2539 """, (spm_package_uid, idpackage, branch,)) 2540 self.cursor.execute(""" 2541 INSERT INTO counters VALUES (?,?,?); 2542 """, (spm_package_uid, idpackage, branch,)) 2543 2544 self.commitChanges()
2545
2546 - def setTrashedUid(self, spm_package_uid):
2547 """ 2548 Mark given Source Package Manager unique package identifier as 2549 "trashed". This is a trick to allow Entropy Server to support 2550 multiple repositories and parallel handling of them without 2551 make it messing with removed packages from the underlying system. 2552 2553 @param spm_package_uid: Source package Manager unique package identifier 2554 @type spm_package_uid: int 2555 """ 2556 with self.__write_mutex: 2557 self.cursor.execute(""" 2558 INSERT OR REPLACE INTO trashedcounters VALUES (?) 2559 """, (spm_package_uid,))
2560
2561 - def setSpmUid(self, idpackage, spm_package_uid, branch = None):
2562 """ 2563 Update Source Package Manager unique package identifier for given 2564 Entropy package identifier (idpackage). 2565 This method *only* updates a currently available binding setting a new 2566 "spm_package_uid" 2567 2568 @param idpackage: package indentifier 2569 @type idpackage: int 2570 @param spm_package_uid: Source package Manager unique package identifier 2571 @type spm_package_uid: int 2572 @keyword branch: current Entropy repository branch 2573 @type branch: string 2574 """ 2575 branchstring = '' 2576 insertdata = [spm_package_uid, idpackage] 2577 if branch: 2578 branchstring = ', branch = (?)' 2579 insertdata.insert(1, branch) 2580 2581 with self.__write_mutex: 2582 try: 2583 self.cursor.execute(""" 2584 UPDATE counters SET counter = (?) %s 2585 WHERE idpackage = (?)""" % (branchstring,), insertdata) 2586 except self.dbapi2.Error: 2587 if self.dbname == etpConst['clientdbid']: 2588 raise 2589 self.commitChanges()
2590
2591 - def contentDiff(self, idpackage, dbconn, dbconn_idpackage):
2592 """ 2593 Return content metadata difference between two packages. 2594 2595 @param idpackage: package indentifier available in this repository 2596 @type idpackage: int 2597 @param dbconn: other repository class instance 2598 @type dbconn: EntropyRepository 2599 @param dbconn_idpackage: package identifier available in other 2600 repository 2601 @type dbconn_idpackage: int 2602 @return: content difference 2603 @rtype: set 2604 @raise AttributeError: when self instance and dbconn are the same 2605 """ 2606 2607 if self is dbconn: 2608 raise AttributeError("cannot diff inside the same db") 2609 2610 self.connection.text_factory = lambda x: const_convert_to_unicode(x) 2611 2612 # setup random table name 2613 randomtable = "cdiff%s" % (self.entropyTools.get_random_number(),) 2614 while self._doesTableExist(randomtable): 2615 randomtable = "cdiff%s" % (self.entropyTools.get_random_number(),) 2616 2617 # create random table 2618 self.cursor.execute(""" 2619 CREATE TEMPORARY TABLE %s ( file VARCHAR )""" % (randomtable,) 2620 ) 2621 2622 try: 2623 dbconn.connection.text_factory = lambda x: \ 2624 const_convert_to_unicode(x) 2625 2626 cur = dbconn.cursor.execute(""" 2627 SELECT file FROM content WHERE idpackage = (?) 2628 """, (dbconn_idpackage,)) 2629 self.cursor.executemany(""" 2630 INSERT INTO %s VALUES (?)""" % (randomtable,), cur) 2631 2632 # now compare 2633 cur = self.cursor.execute(""" 2634 SELECT file FROM content 2635 WHERE content.idpackage = (?) AND 2636 content.file NOT IN (SELECT file from %s)""" % (randomtable,), 2637 (idpackage,)) 2638 2639 # suck back 2640 return self._cur2set(cur) 2641 2642 finally: 2643 self.cursor.execute('DROP TABLE IF EXISTS %s' % (randomtable,))
2644
2645 - def doCleanups(self):
2646 """ 2647 Run repository metadata cleanup over unused references. 2648 """ 2649 self.cleanupUseflags() 2650 self.cleanupSources() 2651 self.cleanupEclasses() 2652 self.cleanupNeeded() 2653 self.cleanupDependencies() 2654 self.cleanupChangelogs()
2655
2656 - def cleanupUseflags(self):
2657 """ 2658 Cleanup "USE flags" metadata unused references to save space. 2659 """ 2660 with self.__write_mutex: 2661 self.cursor.execute(""" 2662 DELETE FROM useflagsreference 2663 WHERE idflag NOT IN (SELECT idflag FROM useflags)""")
2664
2665 - def cleanupSources(self):
2666 """ 2667 Cleanup "sources" metadata unused references to save space. 2668 """ 2669 with self.__write_mutex: 2670 self.cursor.execute(""" 2671 DELETE FROM sourcesreference 2672 WHERE idsource NOT IN (SELECT idsource FROM sources)""")
2673
2674 - def cleanupEclasses(self):
2675 """ 2676 Cleanup "eclass" metadata unused references to save space. 2677 """ 2678 with self.__write_mutex: 2679 self.cursor.execute(""" 2680 DELETE FROM eclassesreference 2681 WHERE idclass NOT IN (SELECT idclass FROM eclasses)""")
2682
2683 - def cleanupNeeded(self):
2684 """ 2685 Cleanup "needed" metadata unused references to save space. 2686 """ 2687 with self.__write_mutex: 2688 self.cursor.execute(""" 2689 DELETE FROM neededreference 2690 WHERE idneeded NOT IN (SELECT idneeded FROM needed)""")
2691
2692 - def cleanupDependencies(self):
2693 """ 2694 Cleanup "dependencies" metadata unused references to save space. 2695 """ 2696 with self.__write_mutex: 2697 self.cursor.execute(""" 2698 DELETE FROM dependenciesreference 2699 WHERE iddependency NOT IN (SELECT iddependency FROM dependencies) 2700 """)
2701
2702 - def cleanupChangelogs(self):
2703 """ 2704 Cleanup "changelog" metadata unused references to save space. 2705 """ 2706 with self.__write_mutex: 2707 self.cursor.execute(""" 2708 DELETE FROM packagechangelogs 2709 WHERE category || "/" || name NOT IN 2710 (SELECT categories.category || "/" || baseinfo.name 2711 FROM baseinfo, categories 2712 WHERE baseinfo.idcategory = categories.idcategory) 2713 """)
2714
2715 - def getNewNegativeSpmUid(self):
2716 """ 2717 Obtain auto-generated available negative Source Package Manager 2718 package identifier. 2719 2720 @return: new negative spm uid 2721 @rtype: int 2722 """ 2723 try: 2724 cur = self.cursor.execute('SELECT min(counter) FROM counters') 2725 dbcounter = cur.fetchone() 2726 mycounter = 0 2727 if dbcounter: 2728 mycounter = dbcounter[0] 2729 2730 if mycounter >= -1 or mycounter is None: 2731 counter = -2 2732 else: 2733 counter = mycounter-1 2734 2735 except self.dbapi2.Error: 2736 counter = -2 # first available counter 2737 2738 return counter
2739
2740 - def getApi(self):
2741 """ 2742 Get Entropy repository API. 2743 2744 @return: Entropy repository API 2745 @rtype: int 2746 """ 2747 cur = self.cursor.execute('SELECT max(etpapi) FROM baseinfo') 2748 api = cur.fetchone() 2749 if api: 2750 return api[0] 2751 return -1
2752
2753 - def getDependency(self, iddependency):
2754 """ 2755 Return dependency string for given dependency identifier. 2756 2757 @param iddependency: dependency identifier 2758 @type iddependency: int 2759 @return: dependency string 2760 @rtype: string or None 2761 """ 2762 cur = self.cursor.execute(""" 2763 SELECT dependency FROM dependenciesreference WHERE iddependency = (?) 2764 LIMIT 1 2765 """, (iddependency,)) 2766 dep = cur.fetchone() 2767 if dep: 2768 return dep[0]
2769
2770 - def getCategory(self, idcategory):
2771 """ 2772 Get category name from category identifier. 2773 2774 @param idcategory: category identifier 2775 @type idcategory: int 2776 @return: category name 2777 @rtype: string 2778 """ 2779 cur = self.cursor.execute(""" 2780 SELECT category from categories WHERE idcategory = (?) LIMIT 1 2781 """, (idcategory,)) 2782 cat = cur.fetchone() 2783 if cat: 2784 return cat[0] 2785 return cat
2786
2787 - def getSystemPackages(self):
2788 """ 2789 Obtain a list of system packages on this repository. 2790 2791 @return: list (set) of system package identifiers 2792 @rtype: set 2793 """ 2794 cur = self.cursor.execute("SELECT idpackage FROM systempackages") 2795 return self._cur2set(cur)
2796
2797 - def getIDPackages(self, atom):
2798 """ 2799 Obtain repository package identifiers from atom string. 2800 2801 @param atom: package atom 2802 @type atom: string 2803 @return: list of matching idpackages found 2804 @rtype: set 2805 """ 2806 cur = self.cursor.execute(""" 2807 SELECT idpackage FROM baseinfo WHERE atom = (?) 2808 """, (atom,)) 2809 return self._cur2set(cur)
2810
2811 - def getIDPackageFromDownload(self, download_relative_path, 2812 endswith = False):
2813 """ 2814 Obtain repository package identifier from its relative download path 2815 string. 2816 2817 @param download_relative_path: relative download path string returned 2818 by "retrieveDownloadURL" method 2819 @type download_relative_path: string 2820 @keyword endswith: search for idpackage which download metadata ends 2821 with the one provided by download_relative_path 2822 @type endswith: bool 2823 @return: idpackage in repository or -1 if not found 2824 @rtype: int 2825 """ 2826 if endswith: 2827 cur = self.cursor.execute(""" 2828 SELECT baseinfo.idpackage FROM baseinfo,extrainfo 2829 WHERE extrainfo.download LIKE (?) AND 2830 baseinfo.idpackage = extrainfo.idpackage 2831 LIMIT 1 2832 """, ("%"+download_relative_path,)) 2833 else: 2834 cur = self.cursor.execute(""" 2835 SELECT baseinfo.idpackage FROM baseinfo,extrainfo 2836 WHERE extrainfo.download = (?) AND 2837 baseinfo.idpackage = extrainfo.idpackage 2838 LIMIT 1 2839 """, (download_relative_path,)) 2840 2841 idpackage = cur.fetchone() 2842 if idpackage: 2843 return idpackage[0] 2844 return -1
2845
2846 - def getIDPackagesFromFile(self, file):
2847 """ 2848 Obtain repository package identifiers for packages owning the provided 2849 path string (file). 2850 2851 @param file: path to file (or directory) to match 2852 @type file: string 2853 @return: list (set) of idpackages found 2854 @rtype: set 2855 """ 2856 cur = self.cursor.execute(""" 2857 SELECT idpackage FROM content WHERE file = (?) 2858 """, (file,)) 2859 return self._cur2list(cur)
2860
2861 - def getIDCategory(self, category):
2862 """ 2863 Obtain category identifier from category name. 2864 2865 @param category: category name 2866 @type category: string 2867 @return: idcategory or -1 if not found 2868 @rtype: int 2869 """ 2870 cur = self.cursor.execute(""" 2871 SELECT "idcategory" FROM categories WHERE category = (?) 2872 LIMIT 1 2873 """, (category,)) 2874 idcat = cur.fetchone() 2875 if idcat: 2876 return idcat[0] 2877 return -1
2878
2879 - def getVersioningData(self, idpackage):
2880 """ 2881 Get package version information for provided package identifier. 2882 2883 @param idpackage: package indentifier 2884 @type idpackage: int 2885 @return: tuple of length 3 composed by (version, tag, revision,) 2886 belonging to idpackage 2887 @rtype: tuple 2888 """ 2889 cur = self.cursor.execute(""" 2890 SELECT version, versiontag, revision FROM baseinfo WHERE idpackage = (?) 2891 LIMIT 1 2892 """, (idpackage,)) 2893 return cur.fetchone()
2894
2895 - def getStrictData(self, idpackage):
2896 """ 2897 Get a restricted (optimized) set of package metadata for provided 2898 package identifier. 2899 2900 @param idpackage: package indentifier 2901 @type idpackage: int 2902 @return: tuple of length 6 composed by 2903 (package key, slot, version, tag, revision, atom) 2904 belonging to idpackage 2905 @rtype: tuple 2906 """ 2907 self.cursor.execute(""" 2908 SELECT categories.category || "/" || baseinfo.name, 2909 baseinfo.slot,baseinfo.version,baseinfo.versiontag, 2910 baseinfo.revision,baseinfo.atom FROM baseinfo, categories 2911 WHERE baseinfo.idpackage = (?) AND 2912 baseinfo.idcategory = categories.idcategory""", (idpackage,)) 2913 return self.cursor.fetchone()
2914
2915 - def getStrictScopeData(self, idpackage):
2916 """ 2917 Get a restricted (optimized) set of package metadata for provided 2918 identifier that can be used to determine the scope of package. 2919 2920 @param idpackage: package indentifier 2921 @type idpackage: int 2922 @return: tuple of length 3 composed by (atom, slot, revision,) 2923 belonging to idpackage 2924 @rtype: tuple 2925 """ 2926 self.cursor.execute(""" 2927 SELECT atom, slot, revision FROM baseinfo 2928 WHERE idpackage = (?)""", (idpackage,)) 2929 rslt = self.cursor.fetchone() 2930 return rslt
2931
2932 - def getScopeData(self, idpackage):
2933 """ 2934 Get a set of package metadata for provided identifier that can be 2935 used to determine the scope of package. 2936 2937 @param idpackage: package indentifier 2938 @type idpackage: int 2939 @return: tuple of length 9 composed by 2940 (atom, category name, name, version, 2941 slot, tag, revision, branch, api,) 2942 belonging to idpackage 2943 @rtype: tuple 2944 """ 2945 self.cursor.execute(""" 2946 SELECT 2947 baseinfo.atom, 2948 categories.category, 2949 baseinfo.name, 2950 baseinfo.version, 2951 baseinfo.slot, 2952 baseinfo.versiontag, 2953 baseinfo.revision, 2954 baseinfo.branch, 2955 baseinfo.etpapi 2956 FROM 2957 baseinfo, 2958 categories 2959 WHERE 2960 baseinfo.idpackage = (?) 2961 and baseinfo.idcategory = categories.idcategory 2962 """, (idpackage,)) 2963 return self.cursor.fetchone()
2964
2965 - def getBaseData(self, idpackage):
2966 """ 2967 Get a set of basic package metadata for provided package identifier. 2968 2969 @param idpackage: package indentifier 2970 @type idpackage: int 2971 @return: tuple of length 19 composed by 2972 (atom, name, version, tag, description, category name, CHOST, 2973 CFLAGS, CXXFLAGS, homepage, license, branch, download path, digest, 2974 slot, api, creation date, package size, revision,) 2975 belonging to idpackage 2976 @rtype: tuple 2977 """ 2978 sql = """ 2979 SELECT 2980 baseinfo.atom, 2981 baseinfo.name, 2982 baseinfo.version, 2983 baseinfo.versiontag, 2984 extrainfo.description, 2985 categories.category, 2986 flags.chost, 2987 flags.cflags, 2988 flags.cxxflags, 2989 extrainfo.homepage, 2990 licenses.license, 2991 baseinfo.branch, 2992 extrainfo.download, 2993 extrainfo.digest, 2994 baseinfo.slot, 2995 baseinfo.etpapi, 2996 extrainfo.datecreation, 2997 extrainfo.size, 2998 baseinfo.revision 2999 FROM 3000 baseinfo, 3001 extrainfo, 3002 categories, 3003 flags, 3004 licenses 3005 WHERE 3006 baseinfo.idpackage = (?) 3007 and baseinfo.idpackage = extrainfo.idpackage 3008 and baseinfo.idcategory = categories.idcategory 3009 and extrainfo.idflags = flags.idflags 3010 and baseinfo.idlicense = licenses.idlicense 3011 """ 3012 self.cursor.execute(sql, (idpackage,)) 3013 return self.cursor.fetchone()
3014
3015 - def getTriggerInfo(self, idpackage, content = True):
3016 """ 3017 Get a set of basic package metadata for provided package identifier. 3018 This method is optimized to work with Entropy Client installation 3019 triggers returning only what is strictly needed. 3020 3021 @param idpackage: package indentifier 3022 @type idpackage: int 3023 @keyword content: if True, grabs the "content" metadata too, othewise 3024 such dict key value will be shown as empty set(). 3025 @type content: bool 3026 @return: dictionary containing package metadata 3027 3028 data = { 3029 'atom': atom, 3030 'category': category, 3031 'name': name, 3032 'version': version, 3033 'versiontag': versiontag, 3034 'revision': revision, 3035 'branch': branch, 3036 'chost': chost, 3037 'cflags': cflags, 3038 'cxxflags': cxxflags, 3039 'etpapi': etpapi, 3040 'trigger': self.retrieveTrigger(idpackage), 3041 'eclasses': self.retrieveEclasses(idpackage), 3042 'content': pkg_content, 3043 'spm_phases': self.retrieveSpmPhases(idpackage), 3044 } 3045 3046 @rtype: dict 3047 """ 3048 3049 atom, category, name, \ 3050 version, slot, versiontag, \ 3051 revision, branch, etpapi = self.getScopeData(idpackage) 3052 chost, cflags, cxxflags = self.retrieveCompileFlags(idpackage) 3053 3054 pkg_content = set() 3055 if content: 3056 pkg_content = self.retrieveContent(idpackage) 3057 3058 data = { 3059 'atom': atom, 3060 'category': category, 3061 'name': name, 3062 'version': version, 3063 'versiontag': versiontag, 3064 'revision': revision, 3065 'branch': branch, 3066 'chost': chost, 3067 'cflags': cflags, 3068 'cxxflags': cxxflags, 3069 'etpapi': etpapi, 3070 'trigger': self.retrieveTrigger(idpackage), 3071 'eclasses': self.retrieveEclasses(idpackage), 3072 'content': pkg_content, 3073 'spm_phases': self.retrieveSpmPhases(idpackage), 3074 } 3075 return data
3076
3077 - def getPackageData(self, idpackage, get_content = True, 3078 content_insert_formatted = False, trigger_unicode = False):
3079 """ 3080 Reconstruct all the package metadata belonging to provided package 3081 identifier into a dict object. 3082 3083 @param idpackage: package indentifier 3084 @type idpackage: int 3085 @keyword get_content: 3086 @type get_content: bool 3087 @keyword content_insert_formatted: 3088 @type content_insert_formatted: bool 3089 @keyword trigger_unicode: 3090 @type trigger_unicode: bool 3091 @return: package metadata in dict() form 3092 3093 >>> data = { 3094 'atom': atom, 3095 'name': name, 3096 'version': version, 3097 'versiontag':versiontag, 3098 'description': description, 3099 'category': category, 3100 'chost': chost, 3101 'cflags': cflags, 3102 'cxxflags': cxxflags, 3103 'homepage': homepage, 3104 'license': mylicense, 3105 'branch': branch, 3106 'download': download, 3107 'digest': digest, 3108 'slot': slot, 3109 'etpapi': etpapi, 3110 'datecreation': datecreation, 3111 'size': size, 3112 'revision': revision, 3113 'counter': self.retrieveSpmUid(idpackage), 3114 'messages': self.retrieveMessages(idpackage), 3115 'trigger': self.retrieveTrigger(idpackage, 3116 get_unicode = trigger_unicode), 3117 'disksize': self.retrieveOnDiskSize(idpackage), 3118 'changelog': self.retrieveChangelog(idpackage), 3119 'injected': self.isInjected(idpackage), 3120 'systempackage': self.isSystemPackage(idpackage), 3121 'config_protect': self.retrieveProtect(idpackage), 3122 'config_protect_mask': self.retrieveProtectMask(idpackage), 3123 'useflags': self.retrieveUseflags(idpackage), 3124 'keywords': self.retrieveKeywords(idpackage), 3125 'sources': sources, 3126 'eclasses': self.retrieveEclasses(idpackage), 3127 'needed': self.retrieveNeeded(idpackage, extended = True), 3128 'provided_libs': self.retrieveProvidedLibraries(idpackage), 3129 'provide': provide (the old provide metadata version) 3130 'provide_extended': self.retrieveProvide(idpackage), 3131 'conflicts': self.retrieveConflicts(idpackage), 3132 'licensedata': self.retrieveLicensedata(idpackage), 3133 'content': content, 3134 'dependencies': dict((x, y,) for x, y in \ 3135 self.retrieveDependencies(idpackage, extended = True)), 3136 'mirrorlinks': [[x,self.retrieveMirrorInfo(x)] for x in mirrornames], 3137 'signatures': signatures, 3138 'spm_phases': self.retrieveSpmPhases(idpackage), 3139 'spm_repository': self.retrieveSpmRepository(idpackage), 3140 } 3141 3142 @rtype: dict 3143 """ 3144 3145 data = {} 3146 try: 3147 atom, name, version, versiontag, \ 3148 description, category, chost, \ 3149 cflags, cxxflags, homepage, \ 3150 mylicense, branch, download, \ 3151 digest, slot, etpapi, \ 3152 datecreation, size, revision = self.getBaseData(idpackage) 3153 except TypeError: 3154 return None 3155 3156 content = {} 3157 if get_content: 3158 content = self.retrieveContent( 3159 idpackage, extended = True, 3160 formatted = True, insert_formatted = content_insert_formatted 3161 ) 3162 3163 sources = self.retrieveSources(idpackage) 3164 mirrornames = set() 3165 for x in sources: 3166 if x.startswith("mirror://"): 3167 mirrornames.add(x.split("/")[2]) 3168 3169 sha1, sha256, sha512 = self.retrieveSignatures(idpackage) 3170 signatures = { 3171 'sha1': sha1, 3172 'sha256': sha256, 3173 'sha512': sha512, 3174 } 3175 3176 provide_extended = self.retrieveProvide(idpackage) 3177 # FIXME: backward compat, remove someday 3178 old_provide = set() 3179 for x in provide_extended: 3180 if isinstance(x, tuple): 3181 old_provide.add(x[0]) 3182 else: 3183 old_provide.add(x) 3184 3185 data = { 3186 'atom': atom, 3187 'name': name, 3188 'version': version, 3189 'versiontag': versiontag, 3190 'description': description, 3191 'category': category, 3192 'chost': chost, 3193 'cflags': cflags, 3194 'cxxflags': cxxflags, 3195 'homepage': homepage, 3196 'license': mylicense, 3197 'branch': branch, 3198 'download': download, 3199 'digest': digest, 3200 'slot': slot, 3201 'etpapi': etpapi, 3202 'datecreation': datecreation, 3203 'size': size, 3204 'revision': revision, 3205 # risky to add to the sql above, still 3206 'counter': self.retrieveSpmUid(idpackage), 3207 'messages': self.retrieveMessages(idpackage), 3208 'trigger': self.retrieveTrigger(idpackage, 3209 get_unicode = trigger_unicode), 3210 'disksize': self.retrieveOnDiskSize(idpackage), 3211 'changelog': self.retrieveChangelog(idpackage), 3212 'injected': self.isInjected(idpackage), 3213 'systempackage': self.isSystemPackage(idpackage), 3214 'config_protect': self.retrieveProtect(idpackage), 3215 'config_protect_mask': self.retrieveProtectMask(idpackage), 3216 'useflags': self.retrieveUseflags(idpackage), 3217 'keywords': self.retrieveKeywords(idpackage), 3218 'sources': sources, 3219 'eclasses': self.retrieveEclasses(idpackage), 3220 'needed': self.retrieveNeeded(idpackage, extended = True), 3221 'provided_libs': self.retrieveProvidedLibraries(idpackage), 3222 'provide': old_provide, 3223 'provide_extended': provide_extended, 3224 'conflicts': self.retrieveConflicts(idpackage), 3225 'licensedata': self.retrieveLicensedata(idpackage), 3226 'content': content, 3227 'dependencies': dict((x, y,) for x, y in \ 3228 self.retrieveDependencies(idpackage, extended = True)), 3229 'mirrorlinks': [[x, self.retrieveMirrorInfo(x)] for x in mirrornames], 3230 'signatures': signatures, 3231 'spm_phases': self.retrieveSpmPhases(idpackage), 3232 'spm_repository': self.retrieveSpmRepository(idpackage), 3233 } 3234 3235 return data
3236
3237 - def _cur2set(self, cur):
3238 mycontent = set() 3239 for x in cur: 3240 mycontent |= set(x) 3241 return mycontent
3242
3243 - def _fetchall2set(self, item):
3244 mycontent = set() 3245 for x in item: 3246 mycontent |= set(x) 3247 return mycontent
3248
3249 - def _fetchall2list(self, item):
3250 content = [] 3251 for x in item: 3252 content += x 3253 return content
3254
3255 - def _cur2list(self, cur):
3256 content = [] 3257 for x in cur: 3258 content += x 3259 return content
3260
3261 - def clearCache(self, depends = False):
3262 """ 3263 Clear on-disk repository cache. 3264 3265 @keyword depends: if True, clear reverse dependencies cache 3266 @type depends: bool 3267 """ 3268 3269 plugins = self.get_plugins() 3270 for plugin_id in sorted(plugins): 3271 plug_inst = plugins[plugin_id] 3272 exec_rc = plug_inst.clear_cache_hook(self) 3273 if exec_rc: 3274 raise RepositoryPluginError( 3275 "[clear_cache_hook] %s: status: %s" % ( 3276 plug_inst.get_id(), exec_rc,)) 3277 3278 self.live_cache.clear() 3279 def do_clear(name): 3280 """ 3281 docstring_title 3282 3283 @param name: 3284 @type name: 3285 @return: 3286 @rtype: 3287 3288 """ 3289 dump_path = os.path.join(etpConst['dumpstoragedir'], name) 3290 dump_dir = os.path.dirname(dump_path) 3291 if os.path.isdir(dump_dir): 3292 for item in os.listdir(dump_dir): 3293 try: 3294 os.remove(os.path.join(dump_dir, item)) 3295 except OSError: 3296 pass
3297 3298 do_clear("%s/%s/" % (self.dbMatchCacheKey, self.dbname,)) 3299 if depends: 3300 do_clear(etpCache['depends_tree']) 3301 do_clear(etpCache['dep_tree']) 3302 do_clear(etpCache['filter_satisfied_deps']) 3303
3304 - def retrieveRepositoryUpdatesDigest(self, repository):
3305 """ 3306 This method should be considered internal and not suited for general 3307 audience. Return digest (md5 hash) bound to repository package 3308 names/slots updates. 3309 3310 @param repository: repository identifier 3311 @type repository: string 3312 @return: digest string 3313 @rtype: string 3314 """ 3315 cur = self.cursor.execute(""" 3316 SELECT digest FROM treeupdates WHERE repository = (?) LIMIT 1 3317 """, (repository,)) 3318 3319 mydigest = cur.fetchone() 3320 if mydigest: 3321 return mydigest[0] 3322 return -1
3323
3324 - def listAllTreeUpdatesActions(self, no_ids_repos = False):
3325 """ 3326 This method should be considered internal and not suited for general 3327 audience. 3328 List all the available "treeupdates" (package names/slots changes 3329 directives) actions. 3330 3331 @keyword no_ids_repos: if True, it will just return a 3-length tuple 3332 list containing [(command, branch, unix_time,), ...] 3333 @type no_ids_repos: bool 3334 @return: list of tuples 3335 @rtype: list 3336 3337 """ 3338 if no_ids_repos: 3339 self.cursor.execute(""" 3340 SELECT command, branch, date FROM treeupdatesactions 3341 """) 3342 else: 3343 self.cursor.execute('SELECT * FROM treeupdatesactions') 3344 return self.cursor.fetchall()
3345
3346 - def retrieveTreeUpdatesActions(self, repository, forbranch = None):
3347 """ 3348 This method should be considered internal and not suited for general 3349 audience. 3350 Return all the available "treeupdates (package names/slots changes 3351 directives) actions for provided repository. 3352 3353 @param repository: repository identifier 3354 @type repository: string 3355 @keyword forbranch: filter for specific Entropy branch, provide 3356 alternative branch string 3357 @type forbranch: string 3358 @return: list of raw-string commands to run 3359 @rtype: list 3360 """ 3361 if forbranch is None: 3362 forbranch = self.db_branch 3363 if not forbranch: 3364 forbranch = self.SystemSettings['repositories']['branch'] 3365 3366 params = (repository,) 3367 branch_string = '' 3368 if forbranch: 3369 branch_string = 'and branch = (?)' 3370 params = (repository, forbranch,) 3371 3372 self.cursor.execute(""" 3373 SELECT command FROM treeupdatesactions WHERE 3374 repository = (?) %s order by date""" % (branch_string,), params) 3375 return self._fetchall2list(self.cursor.fetchall())
3376
3377 - def bumpTreeUpdatesActions(self, updates):
3378 # mainly used to restore a previous table, 3379 # used by reagent in --initialize 3380 """ 3381 This method should be considered internal and not suited for general 3382 audience. 3383 This method rewrites "treeupdates" metadata in repository. 3384 3385 @param updates: new treeupdates metadata 3386 @type updates: list 3387 """ 3388 with self.__write_mutex: 3389 self.cursor.execute('DELETE FROM treeupdatesactions') 3390 self.cursor.executemany(""" 3391 INSERT INTO treeupdatesactions VALUES (?,?,?,?,?) 3392 """, updates) 3393 self.commitChanges()
3394
3395 - def removeTreeUpdatesActions(self, repository):
3396 """ 3397 This method should be considered internal and not suited for general 3398 audience. 3399 This method removes "treeupdates" metadata in repository. 3400 3401 @param repository: remove treeupdates metadata for provided repository 3402 @type repository: string 3403 """ 3404 with self.__write_mutex: 3405 self.cursor.execute(""" 3406 DELETE FROM treeupdatesactions WHERE repository = (?) 3407 """, (repository,)) 3408 self.commitChanges()
3409
3410 - def insertTreeUpdatesActions(self, updates, repository):
3411 """ 3412 This method should be considered internal and not suited for general 3413 audience. 3414 This method insert "treeupdates" metadata in repository. 3415 3416 @param updates: new treeupdates metadata 3417 @type updates: list 3418 @param repository: insert treeupdates metadata for provided repository 3419 @type repository: string 3420 """ 3421 with self.__write_mutex: 3422 myupdates = [[repository]+list(x) for x in updates] 3423 self.cursor.executemany(""" 3424 INSERT INTO treeupdatesactions VALUES (NULL,?,?,?,?) 3425 """, myupdates) 3426 self.commitChanges()
3427
3428 - def setRepositoryUpdatesDigest(self, repository, digest):
3429 """ 3430 This method should be considered internal and not suited for general 3431 audience. 3432 Set "treeupdates" checksum (digest) for provided repository. 3433 3434 @param repository: repository identifier 3435 @type repository: string 3436 @param digest: treeupdates checksum string (md5) 3437 @type digest: string 3438 """ 3439 with self.__write_mutex: 3440 self.cursor.execute(""" 3441 DELETE FROM treeupdates where repository = (?) 3442 """, (repository,)) 3443 self.cursor.execute(""" 3444 INSERT INTO treeupdates VALUES (?,?) 3445 """, (repository, digest,))
3446
3447 - def addRepositoryUpdatesActions(self, repository, actions, branch):
3448 """ 3449 This method should be considered internal and not suited for general 3450 audience. 3451 Add "treeupdates" actions for repository and branch provided. 3452 3453 @param repository: repository identifier 3454 @type repository: string 3455 @param actions: list of raw treeupdates action strings 3456 @type actions: list 3457 @param branch: branch metadata to bind to the provided actions 3458 @type branch: string 3459 """ 3460 3461 mytime = str(self.entropyTools.get_current_unix_time()) 3462 with self.__write_mutex: 3463 myupdates = [ 3464 (repository, x, branch, mytime,) for x in actions \ 3465 if not self.doesTreeupdatesActionExist(repository, x, branch) 3466 ] 3467 self.cursor.executemany(""" 3468 INSERT INTO treeupdatesactions VALUES (NULL,?,?,?,?) 3469 """, myupdates)
3470
3471 - def doesTreeupdatesActionExist(self, repository, command, branch):
3472 """ 3473 This method should be considered internal and not suited for general 3474 audience. 3475 Return whether provided "treeupdates" action in repository with 3476 provided branch exists. 3477 3478 @param repository: repository identifier 3479 @type repository: string 3480 @param command: treeupdates command 3481 @type command: string 3482 @param branch: branch metadata bound to command argument value given 3483 @type branch: string 3484 @return: if True, provided treeupdates action already exists 3485 @rtype: bool 3486 """ 3487 self.cursor.execute(""" 3488 SELECT * FROM treeupdatesactions 3489 WHERE repository = (?) and command = (?) 3490 and branch = (?)""", (repository, command, branch,)) 3491 3492 result = self.cursor.fetchone() 3493 if result: 3494 return True 3495 return False
3496
3497 - def clearPackageSets(self):
3498 """ 3499 Clear Package sets (group of packages) entries in repository. 3500 """ 3501 self.cursor.execute('DELETE FROM packagesets')
3502
3503 - def insertPackageSets(self, sets_data):
3504 """ 3505 Insert Package sets metadata into repository. 3506 3507 @param sets_data: dictionary containing package set names as keys and 3508 list (set) of dependencies as value 3509 @type sets_data: dict 3510 """ 3511 mysets = [] 3512 for setname in sorted(sets_data): 3513 for dependency in sorted(sets_data[setname]): 3514 try: 3515 mysets.append((const_convert_to_unicode(setname), 3516 const_convert_to_unicode(dependency),)) 3517 except (UnicodeDecodeError, UnicodeEncodeError,): 3518 continue 3519 3520 with self.__write_mutex: 3521 self.cursor.executemany('INSERT INTO packagesets VALUES (?,?)', 3522 mysets)
3523
3524 - def retrievePackageSets(self):
3525 """ 3526 Return Package sets metadata stored in repository. 3527 3528 @return: dictionary containing package set names as keys and 3529 list (set) of dependencies as value 3530 @rtype: dict 3531 """ 3532 # FIXME backward compatibility 3533 if not self._doesTableExist('packagesets'): 3534 return {} 3535 3536 cur = self.cursor.execute("SELECT setname, dependency FROM packagesets") 3537 data = cur.fetchall() 3538 3539 sets = {} 3540 for setname, dependency in data: 3541 obj = sets.setdefault(setname, set()) 3542 obj.add(dependency) 3543 return sets
3544
3545 - def retrievePackageSet(self, setname):
3546 """ 3547 Return dependencies belonging to given package set name. 3548 This method does not check if the given package set name is 3549 available and returns an empty list (set) in these cases. 3550 3551 @param setname: Package set name 3552 @type setname: string 3553 @return: list (set) of dependencies belonging to given package set name 3554 @rtype: set 3555 """ 3556 cur = self.cursor.execute(""" 3557 SELECT dependency FROM packagesets WHERE setname = (?)""", 3558 (setname,)) 3559 return self._cur2set(cur)
3560
3561 - def retrieveSystemPackages(self):
3562 """ 3563 Return a list of package identifiers that are part of the base 3564 system (thus, marked as system packages). 3565 3566 @return: list (set) of system package identifiers 3567 @rtype: set 3568 """ 3569 cur = self.cursor.execute('SELECT idpackage FROM systempackages') 3570 return self._cur2set(cur)
3571
3572 - def retrieveAtom(self, idpackage):
3573 """ 3574 Return "atom" metadatum for given package identifier. 3575 3576 @param idpackage: package indentifier 3577 @type idpackage: int 3578 @return: atom string 3579 @rtype: string or None 3580 """ 3581 cur = self.cursor.execute(""" 3582 SELECT atom FROM baseinfo WHERE idpackage = (?) LIMIT 1 3583 """, (idpackage,)) 3584 atom = cur.fetchone() 3585 if atom: 3586 return atom[0]
3587
3588 - def retrieveBranch(self, idpackage):
3589 """ 3590 Return "branch" metadatum for given package identifier. 3591 3592 @param idpackage: package indentifier 3593 @type idpackage: int 3594 @return: branch metadatum 3595 @rtype: string or None 3596 """ 3597 cur = self.cursor.execute(""" 3598 SELECT branch FROM baseinfo WHERE idpackage = (?) LIMIT 1 3599 """, (idpackage,)) 3600 branch = cur.fetchone() 3601 if branch: 3602 return branch[0]
3603
3604 - def retrieveTrigger(self, idpackage, get_unicode = False):
3605 """ 3606 Return "trigger" script content for given package identifier. 3607 3608 @param idpackage: package indentifier 3609 @type idpackage: int 3610 @keyword get_unicode: return in unicode format 3611 @type get_unicode: bool 3612 @return: trigger script content 3613 @rtype: string or None 3614 """ 3615 cur = self.cursor.execute(""" 3616 SELECT data FROM triggers WHERE idpackage = (?) LIMIT 1 3617 """, (idpackage,)) 3618 trigger = cur.fetchone() 3619 if not trigger: 3620 # backward compatibility with <=0.52.x 3621 if get_unicode: 3622 return const_convert_to_unicode('') 3623 return const_convert_to_rawstring('') 3624 if not get_unicode: 3625 return const_convert_to_rawstring(trigger[0]) 3626 # cross fingers... 3627 return const_convert_to_unicode(trigger[0])
3628
3629 - def retrieveDownloadURL(self, idpackage):
3630 """ 3631 Return "download URL" metadatum for given package identifier. 3632 3633 @param idpackage: package indentifier 3634 @type idpackage: int 3635 @return: download url metadatum 3636 @rtype: string or None 3637 """ 3638 cur = self.cursor.execute(""" 3639 SELECT download FROM extrainfo WHERE idpackage = (?) LIMIT 1 3640 """, (idpackage,)) 3641 download = cur.fetchone() 3642 if download: 3643 return download[0]
3644
3645 - def retrieveDescription(self, idpackage):
3646 """ 3647 Return "description" metadatum for given package identifier. 3648 3649 @param idpackage: package indentifier 3650 @type idpackage: int 3651 @return: package description 3652 @rtype: string or None 3653 """ 3654 cur = self.cursor.execute(""" 3655 SELECT description FROM extrainfo WHERE idpackage = (?) LIMIT 1 3656 """, (idpackage,)) 3657 description = cur.fetchone() 3658 if description: 3659 return description[0]
3660
3661 - def retrieveHomepage(self, idpackage):
3662 """ 3663 Return "homepage" metadatum for given package identifier. 3664 3665 @param idpackage: package indentifier 3666 @type idpackage: int 3667 @return: package homepage 3668 @rtype: string or None 3669 """ 3670 cur = self.cursor.execute(""" 3671 SELECT homepage FROM extrainfo WHERE idpackage = (?) LIMIT 1 3672 """, (idpackage,)) 3673 home = cur.fetchone() 3674 if home: 3675 return home[0]
3676
3677 - def retrieveSpmUid(self, idpackage):
3678 """ 3679 Return Source Package Manager unique identifier bound to Entropy 3680 package identifier. 3681 3682 @param idpackage: package indentifier 3683 @type idpackage: int 3684 @return: Spm UID or -1 (if not bound, valid for injected packages) 3685 @rtype: int 3686 """ 3687 cur = self.cursor.execute(""" 3688 SELECT counters.counter FROM counters,baseinfo 3689 WHERE counters.idpackage = (?) AND 3690 baseinfo.idpackage = counters.idpackage AND 3691 baseinfo.branch = counters.branch LIMIT 1 3692 """, (idpackage,)) 3693 mycounter = cur.fetchone() 3694 if mycounter: 3695 return mycounter[0] 3696 return -1
3697
3698 - def retrieveMessages(self, idpackage):
3699 """ 3700 Return "messages" metadatum for given package identifier. 3701 3702 @param idpackage: package indentifier 3703 @type idpackage: int 3704 @return: list of package messages (for making user aware of stuff) 3705 @rtype: list 3706 """ 3707 cur = self.cursor.execute(""" 3708 SELECT message FROM messages WHERE idpackage = (?)""", (idpackage,)) 3709 return self._cur2list(cur)
3710
3711 - def retrieveSize(self, idpackage):
3712 """ 3713 Return "size" metadatum for given package identifier. 3714 "size" refers to Entropy package file size in bytes. 3715 3716 @param idpackage: package indentifier 3717 @type idpackage: int 3718 @return: size of Entropy package for given package identifier 3719 @rtype: int or None 3720 """ 3721 cur = self.cursor.execute(""" 3722 SELECT size FROM extrainfo WHERE idpackage = (?) LIMIT 1 3723 """, (idpackage,)) 3724 size = cur.fetchone() 3725 if size: 3726 try: 3727 return int(size[0]) 3728 except ValueError: # wtf? 3729 return 0
3730 3731 # in bytes
3732 - def retrieveOnDiskSize(self, idpackage):
3733 """ 3734 Return "on disk size" metadatum for given package identifier. 3735 "on disk size" refers to unpacked Entropy package file size in bytes, 3736 which is in other words, the amount of space required on live system 3737 to have it installed (simplified explanation). 3738 3739 @param idpackage: package indentifier 3740 @type idpackage: int 3741 @return: on disk size metadatum 3742 @rtype: int 3743 3744 """ 3745 cur = self.cursor.execute(""" 3746 SELECT size FROM sizes WHERE idpackage = (?) LIMIT 1 3747 """, (idpackage,)) 3748 size = cur.fetchone() 3749 if size: 3750 return size[0] 3751 return 0
3752
3753 - def retrieveDigest(self, idpackage):
3754 """ 3755 Return "digest" metadatum for given package identifier. 3756 "digest" refers to Entropy package file md5 checksum bound to given 3757 package identifier. 3758 3759 @param idpackage: package indentifier 3760 @type idpackage: int 3761 @return: md5 checksum for given package identifier 3762 @rtype: string or None 3763 """ 3764 cur = self.cursor.execute(""" 3765 SELECT digest FROM extrainfo WHERE idpackage = (?) LIMIT 1 3766 """, (idpackage,)) 3767 digest = cur.fetchone() 3768 if digest: 3769 return digest[0]
3770
3771 - def retrieveSignatures(self, idpackage):
3772 """ 3773 Return package file extra hashes (sha1, sha256, sha512) for given 3774 package identifier. 3775 3776 @param idpackage: package indentifier 3777 @type idpackage: int 3778 @return: tuple of length 3, sha1, sha256, sha512 package extra 3779 hashes if available, otherwise the same but with None as values. 3780 @rtype: tuple 3781 """ 3782 # FIXME backward compatibility 3783 if not self._doesTableExist('packagesignatures'): 3784 return None, None, None 3785 3786 cur = self.cursor.execute(""" 3787 SELECT sha1, sha256, sha512 FROM packagesignatures 3788 WHERE idpackage = (?) LIMIT 1 3789 """, (idpackage,)) 3790 data = cur.fetchone() 3791 3792 if data: 3793 return data 3794 return None, None, None
3795
3796 - def retrieveName(self, idpackage):
3797 """ 3798 Return "name" metadatum for given package identifier. 3799 Attention: package name != atom, the former is just a subset of the 3800 latter. 3801 3802 @param idpackage: package indentifier 3803 @type idpackage: int 3804 @return: "name" metadatum for given package identifier 3805 @rtype: string or None 3806 3807 """ 3808 self.cursor.execute(""" 3809 SELECT name FROM baseinfo WHERE idpackage = (?) LIMIT 1 3810 """, (idpackage,)) 3811 name = self.cursor.fetchone() 3812 if name: 3813 return name[0]
3814
3815 - def retrieveKeySlot(self, idpackage):
3816 """ 3817 Return a tuple composed by package key and slot for given package 3818 identifier. 3819 3820 @param idpackage: package indentifier 3821 @type idpackage: int 3822 @return: tuple of length 2 composed by (package_key, package_slot,) 3823 @rtupe: tuple or None 3824 """ 3825 cur = self.cursor.execute(""" 3826 SELECT categories.category || "/" || baseinfo.name,baseinfo.slot 3827 FROM baseinfo,categories 3828 WHERE baseinfo.idpackage = (?) AND 3829 baseinfo.idcategory = categories.idcategory LIMIT 1 3830 """, (idpackage,)) 3831 return cur.fetchone()
3832
3833 - def retrieveKeySlotAggregated(self, idpackage):
3834 """ 3835 Return package key and package slot string (aggregated form through 3836 ":", for eg.: app-foo/foo:2). 3837 This method has been implemented for performance reasons. 3838 3839 @param idpackage: package indentifier 3840 @type idpackage: int 3841 @return: package key + ":" + slot string 3842 @rtype: string or None 3843 """ 3844 cur = self.cursor.execute(""" 3845 SELECT categories.category || "/" || baseinfo.name || ":" || 3846 baseinfo.slot FROM baseinfo,categories 3847 WHERE baseinfo.idpackage = (?) AND 3848 baseinfo.idcategory = categories.idcategory LIMIT 1 3849 """, (idpackage,)) 3850 data = cur.fetchone() 3851 if data: 3852 return data[0]
3853
3854 - def retrieveKeySlotTag(self, idpackage):
3855 """ 3856 Return package key, slot and tag tuple for given package identifier. 3857 3858 @param idpackage: package indentifier 3859 @type idpackage: int 3860 @return: tuple of length 3 providing (package_key, slot, package_tag,) 3861 @rtype: tuple 3862 """ 3863 cur = self.cursor.execute(""" 3864 SELECT categories.category || "/" || baseinfo.name, baseinfo.slot, 3865 baseinfo.versiontag FROM baseinfo, categories WHERE 3866 baseinfo.idpackage = (?) AND 3867 baseinfo.idcategory = categories.idcategory LIMIT 1 3868 """, (idpackage,)) 3869 return cur.fetchone()
3870
3871 - def retrieveVersion(self, idpackage):
3872 """ 3873 Return package version for given package identifier. 3874 3875 @param idpackage: package indentifier 3876 @type idpackage: int 3877 @return: package version 3878 @rtype: string or None 3879 """ 3880 cur = self.cursor.execute(""" 3881 SELECT version FROM baseinfo WHERE idpackage = (?) LIMIT 1 3882 """, (idpackage,)) 3883 ver = cur.fetchone() 3884 if ver: 3885 return ver[0]
3886
3887 - def retrieveRevision(self, idpackage):
3888 """ 3889 Return package Entropy-revision for given package identifier. 3890 3891 @param idpackage: package indentifier 3892 @type idpackage: int 3893 @return: Entropy-revision for given package indentifier 3894 @rtype: int or None 3895 3896 """ 3897 cur = self.cursor.execute(""" 3898 SELECT revision FROM baseinfo WHERE idpackage = (?) LIMIT 1 3899 """, (idpackage,)) 3900 rev = cur.fetchone() 3901 if rev: 3902 return rev[0]
3903
3904 - def retrieveCreationDate(self, idpackage):
3905 """ 3906 Return creation date for given package identifier. 3907 Creation date returned is a string representation of UNIX time format. 3908 3909 @param idpackage: package indentifier 3910 @type idpackage: int 3911 @return: creation date for given package identifier 3912 @rtype: string or None 3913 3914 """ 3915 cur = self.cursor.execute(""" 3916 SELECT datecreation FROM extrainfo WHERE idpackage = (?) LIMIT 1 3917 """, (idpackage,)) 3918 date = cur.fetchone() 3919 if date: 3920 return date[0]
3921
3922 - def retrieveApi(self, idpackage):
3923 """ 3924 Return Entropy API in use when given package identifier was added. 3925 3926 @param idpackage: package indentifier 3927 @type idpackage: int 3928 @return: Entropy API for given package identifier 3929 @rtype: int or None 3930 """ 3931 cur = self.cursor.execute(""" 3932 SELECT etpapi FROM baseinfo WHERE idpackage = (?) LIMIT 1 3933 """, (idpackage,)) 3934 api = cur.fetchone() 3935 if api: 3936 return api[0]
3937
3938 - def retrieveUseflags(self, idpackage):
3939 """ 3940 Return "USE flags" metadatum for given package identifier. 3941 3942 @param idpackage: package indentifier 3943 @type idpackage: int 3944 @return: list (set) of USE flags for given package identifier. 3945 @rtype: set 3946 """ 3947 cur = self.cursor.execute(""" 3948 SELECT flagname FROM useflags,useflagsreference 3949 WHERE useflags.idpackage = (?) AND 3950 useflags.idflag = useflagsreference.idflag 3951 """, (idpackage,)) 3952 return self._cur2set(cur)
3953
3954 - def retrieveEclasses(self, idpackage):
3955 """ 3956 Return "eclass" metadatum for given package identifier. 3957 3958 @param idpackage: package indentifier 3959 @type idpackage: int 3960 @return: list (set) of eclasses for given package identifier 3961 @rtype: set 3962 """ 3963 cur = self.cursor.execute(""" 3964 SELECT classname FROM eclasses,eclassesreference 3965 WHERE eclasses.idpackage = (?) AND 3966 eclasses.idclass = eclassesreference.idclass""", (idpackage,)) 3967 return self._cur2set(cur)
3968
3969 - def retrieveSpmPhases(self, idpackage):
3970 """ 3971 Return "Source Package Manager install phases" for given package 3972 identifier. 3973 3974 @param idpackage: package indentifier 3975 @type idpackage: int 3976 @return: "Source Package Manager available install phases" string 3977 @rtype: string or None 3978 """ 3979 # FIXME backward compatibility 3980 if not self._doesTableExist('packagespmphases'): 3981 return None 3982 3983 cur = self.cursor.execute(""" 3984 SELECT phases FROM packagespmphases WHERE idpackage = (?) LIMIT 1 3985 """, (idpackage,)) 3986 spm_phases = cur.fetchone() 3987 3988 if spm_phases: 3989 return spm_phases[0]
3990
3991 - def retrieveSpmRepository(self, idpackage):
3992 """ 3993 Return Source Package Manager source repository used at compile time. 3994 3995 @param idpackage: package indentifier 3996 @type idpackage: int 3997 @return: Source Package Manager source repository 3998 @rtype: string or None 3999 """ 4000 # FIXME backward compatibility 4001 if not self._doesTableExist('packagespmrepository'): 4002 return None 4003 cur = self.cursor.execute(""" 4004 SELECT repository FROM packagespmrepository 4005 WHERE idpackage = (?) LIMIT 1 4006 """, (idpackage,)) 4007 spm_repo = cur.fetchone() 4008 4009 if spm_repo: 4010 return spm_repo[0]
4011
4012 - def retrieveNeededRaw(self, idpackage):
4013 """ 4014 Return (raw format) "NEEDED" ELF metadata for libraries contained 4015 in given package. 4016 4017 @param idpackage: package indentifier 4018 @type idpackage: int 4019 @return: list (set) of "NEEDED" entries contained in ELF objects 4020 packed into package file 4021 @rtype: set 4022 """ 4023 cur = self.cursor.execute(""" 4024 SELECT library FROM needed,neededreference 4025 WHERE needed.idpackage = (?) AND 4026 needed.idneeded = neededreference.idneeded""", (idpackage,)) 4027 return self._cur2set(cur)
4028
4029 - def retrieveNeeded(self, idpackage, extended = False, format = False):
4030 """ 4031 Return "NEEDED" elf metadata for libraries contained in given package. 4032 4033 @param idpackage: package indentifier 4034 @type idpackage: int 4035 @keyword extended: also return ELF class information for every 4036 library name 4037 @type extended: bool 4038 @keyword format: properly format output, returning a dictionary with 4039 library name as key and ELF class as value 4040 @type format: bool 4041 @return: "NEEDED" metadata for libraries contained in given package. 4042 @rtype: list or set 4043 """ 4044 if extended: 4045 4046 cur = self.cursor.execute(""" 4047 SELECT library,elfclass FROM needed,neededreference 4048 WHERE needed.idpackage = (?) AND 4049 needed.idneeded = neededreference.idneeded order by library 4050 """, (idpackage,)) 4051 needed = cur.fetchall() 4052 4053 else: 4054 4055 cur = self.cursor.execute(""" 4056 SELECT library FROM needed,neededreference 4057 WHERE needed.idpackage = (?) AND 4058 needed.idneeded = neededreference.idneeded ORDER BY library 4059 """, (idpackage,)) 4060 needed = self._cur2list(cur) 4061 4062 if extended and format: 4063 return dict((lib, elfclass,) for lib, elfclass in needed) 4064 return needed
4065
4066 - def retrieveProvidedLibraries(self, idpackage):
4067 """ 4068 Return list of library names (from NEEDED ELF metadata) provided by 4069 given package identifier. 4070 4071 @param idpackage: package indentifier 4072 @type idpackage: int 4073 @return: list of tuples of length 2 composed by library name and ELF 4074 class 4075 @rtype: list 4076 """ 4077 # TODO: remove this in future, backward compat. 4078 if not self._doesTableExist('provided_libs'): 4079 return set() 4080 4081 cur = self.cursor.execute(""" 4082 SELECT library, path, elfclass FROM provided_libs 4083 WHERE idpackage = (?) 4084 """, (idpackage,)) 4085 return set(cur.fetchall())
4086
4087 - def retrieveConflicts(self, idpackage):
4088 """ 4089 Return list of conflicting dependencies for given package identifier. 4090 4091 @param idpackage: package indentifier 4092 @type idpackage: int 4093 @return: list (set) of conflicting package dependencies 4094 @rtype: set 4095 4096 """ 4097 cur = self.cursor.execute(""" 4098 SELECT conflict FROM conflicts WHERE idpackage = (?) 4099 """, (idpackage,)) 4100 return self._cur2set(cur)
4101
4102 - def retrieveProvide(self, idpackage):
4103 """ 4104 Return list of dependencies/atoms are provided by the given package 4105 identifier (see Portage documentation about old-style PROVIDEs). 4106 4107 @param idpackage: package indentifier 4108 @type idpackage: int 4109 @return: list (set) of atoms provided by package 4110 @rtype: set 4111 """ 4112 # FIXME: added for backward compatibility, remove someday 4113 is_default_str = ',0' 4114 if self._doesColumnInTableExist("provide", "is_default"): 4115 is_default_str = ',is_default ' 4116 4117 cur = self.cursor.execute(""" 4118 SELECT atom%s FROM provide WHERE idpackage = (?) 4119 """ % (is_default_str,), (idpackage,)) 4120 if is_default_str: 4121 return set(cur.fetchall()) 4122 return self._cur2set(cur)
4123
4124 - def retrieveDependenciesList(self, idpackage):
4125 """ 4126 Return list of dependencies, including conflicts for given package 4127 identifier. 4128 4129 @param idpackage: package indentifier 4130 @type idpackage: int 4131 @return: list (set) of dependencies of package 4132 @rtype: set 4133 """ 4134 cur = self.cursor.execute(""" 4135 SELECT dependenciesreference.dependency 4136 FROM dependencies, dependenciesreference 4137 WHERE dependencies.idpackage = (?) AND 4138 dependencies.iddependency = dependenciesreference.iddependency 4139 UNION SELECT "!" || conflict FROM conflicts 4140 WHERE idpackage = (?)""", (idpackage, idpackage,)) 4141 return self._cur2set(cur)
4142
4143 - def retrievePostDependencies(self, idpackage, extended = False):
4144 """ 4145 Return list of post-merge package dependencies for given package 4146 identifier. 4147 Note: this function is just a wrapper of retrieveDependencies() 4148 providing deptype (dependency type) = post-dependencies. 4149 4150 @param idpackage: package indentifier 4151 @type idpackage: int 4152 @keyword extended: return in extended format 4153 @type extended: bool 4154 """ 4155 return self.retrieveDependencies(idpackage, extended = extended, 4156 deptype = etpConst['dependency_type_ids']['pdepend_id'])
4157
4158 - def retrieveManualDependencies(self, idpackage, extended = False):
4159 """ 4160 Return manually added dependencies for given package identifier. 4161 Note: this function is just a wrapper of retrieveDependencies() 4162 providing deptype (dependency type) = manual-dependencies. 4163 4164 @param idpackage: package indentifier 4165 @type idpackage: int 4166 @keyword extended: return in extended format 4167 @type extended: bool 4168 """ 4169 return self.retrieveDependencies(idpackage, extended = extended, 4170 deptype = etpConst['dependency_type_ids']['mdepend_id'])
4171
4172 - def retrieveDependencies(self, idpackage, extended = False, deptype = None, 4173 exclude_deptypes = None):
4174 """ 4175 Return dependencies for given package identifier. 4176 4177 @param idpackage: package indentifier 4178 @type idpackage: int 4179 @keyword extended: return in extended format (list of tuples of length 2 4180 composed by dependency name and dependency type) 4181 @type extended: bool 4182 @keyword deptype: return only given type of dependencies 4183 see etpConst['dependency_type_ids']['*depend_id'] for dependency type 4184 identifiers 4185 @type deptype: bool 4186 @keyword exclude_deptypes: list of dependency types to exclude 4187 @type exclude_deptypes: list 4188 @return: dependencies of given package 4189 @rtype: list or set 4190 """ 4191 searchdata = [idpackage] 4192 4193 depstring = '' 4194 if deptype is not None: 4195 depstring = ' and dependencies.type = (?)' 4196 searchdata.append(deptype) 4197 4198 excluded_deptypes_query = "" 4199 if exclude_deptypes is not None: 4200 for dep_type in exclude_deptypes: 4201 if not isinstance(dep_type, int): 4202 # filter out crap 4203 continue 4204 excluded_deptypes_query += " AND dependencies.type != %s" % ( 4205 dep_type,) 4206 4207 if extended: 4208 cur = self.cursor.execute(""" 4209 SELECT dependenciesreference.dependency,dependencies.type 4210 FROM dependencies,dependenciesreference 4211 WHERE dependencies.idpackage = (?) AND 4212 dependencies.iddependency = 4213 dependenciesreference.iddependency %s %s""" % ( 4214 depstring, excluded_deptypes_query,), searchdata) 4215 return cur.fetchall() 4216 else: 4217 cur = self.cursor.execute(""" 4218 SELECT dependenciesreference.dependency 4219 FROM dependencies,dependenciesreference 4220 WHERE dependencies.idpackage = (?) AND 4221 dependencies.iddependency = 4222 dependenciesreference.iddependency %s %s""" % ( 4223 depstring, excluded_deptypes_query,), searchdata) 4224 return self._cur2set(cur)
4225
4226 - def retrieveIdDependencies(self, idpackage):
4227 """ 4228 Return list of dependency identifiers for given package identifier. 4229 4230 @param idpackage: package indentifier 4231 @type idpackage: int 4232 @return: list (set) of dependency identifiers 4233 @rtype: set 4234 """ 4235 cur = self.cursor.execute(""" 4236 SELECT iddependency FROM dependencies WHERE idpackage = (?) 4237 """, (idpackage,)) 4238 return self._cur2set(cur)
4239
4240 - def retrieveKeywords(self, idpackage):
4241 """ 4242 Return package SPM keyword list for given package identifier. 4243 4244 @param idpackage: package indentifier 4245 @type idpackage: int 4246 @return: list (set) of keywords for given package identifier 4247 @rtype: set 4248 """ 4249 cur = self.cursor.execute(""" 4250 SELECT keywordname FROM keywords,keywordsreference 4251 WHERE keywords.idpackage = (?) AND 4252 keywords.idkeyword = keywordsreference.idkeyword""", (idpackage,)) 4253 return self._cur2set(cur)
4254
4255 - def retrieveProtect(self, idpackage):
4256 """ 4257 Return CONFIG_PROTECT (configuration file protection) string 4258 (containing a list of space reparated paths) metadata for given 4259 package identifier. 4260 4261 @param idpackage: package indentifier 4262 @type idpackage: int 4263 @return: CONFIG_PROTECT string 4264 @rtype: string 4265 """ 4266 cur = self.cursor.execute(""" 4267 SELECT protect FROM configprotect,configprotectreference 4268 WHERE configprotect.idpackage = (?) AND 4269 configprotect.idprotect = configprotectreference.idprotect 4270 LIMIT 1 4271 """, (idpackage,)) 4272 4273 protect = cur.fetchone() 4274 if protect: 4275 return protect[0] 4276 return ''
4277
4278 - def retrieveProtectMask(self, idpackage):
4279 """ 4280 Return CONFIG_PROTECT_MASK (mask for configuration file protection) 4281 string (containing a list of space reparated paths) metadata for given 4282 package identifier. 4283 4284 @param idpackage: package indentifier 4285 @type idpackage: int 4286 @return: CONFIG_PROTECT_MASK string 4287 @rtype: string 4288 """ 4289 self.cursor.execute(""" 4290 SELECT protect FROM configprotectmask,configprotectreference 4291 WHERE idpackage = (?) AND 4292 configprotectmask.idprotect = configprotectreference.idprotect 4293 """, (idpackage,)) 4294 4295 protect = self.cursor.fetchone() 4296 if protect: 4297 return protect[0] 4298 return ''
4299
4300 - def retrieveSources(self, idpackage, extended = False):
4301 """ 4302 Return source package URLs for given package identifier. 4303 "source" as in source code. 4304 4305 @param idpackage: package indentifier 4306 @type idpackage: int 4307 @keyword extended: 4308 @type extended: bool 4309 @return: if extended is True, dict composed by source URLs as key 4310 and list of mirrors as value, otherwise just a list (set) of 4311 source package URLs. 4312 @rtype: dict or set 4313 """ 4314 cur = self.cursor.execute(""" 4315 SELECT sourcesreference.source FROM sources, sourcesreference 4316 WHERE idpackage = (?) AND 4317 sources.idsource = sourcesreference.idsource 4318 """, (idpackage,)) 4319 sources = self._cur2set(cur) 4320 if not extended: 4321 return sources 4322 4323 source_data = {} 4324 mirror_str = "mirror://" 4325 for source in sources: 4326 4327 source_data[source] = set() 4328 if source.startswith(mirror_str): 4329 4330 mirrorname = source.split("/")[2] 4331 mirror_url = source.split("/", 3)[3:][0] 4332 source_data[source] |= set( 4333 [os.path.join(url, mirror_url) for url in \ 4334 self.retrieveMirrorInfo(mirrorname)]) 4335 4336 else: 4337 source_data[source].add(source) 4338 4339 return source_data
4340
4341 - def retrieveAutomergefiles(self, idpackage, get_dict = False):
4342 """ 4343 Return previously merged protected configuration files list and 4344 their md5 hashes for given package identifier. 4345 This is part of the "automerge" feature which uses file md5 checksum 4346 to determine if a protected configuration file can be merged auto- 4347 matically. 4348 4349 @param idpackage: package indentifier 4350 @type idpackage: int 4351 @keyword get_dict: return a dictionary with configuration file as key 4352 and md5 hash as value 4353 @type get_dict: bool 4354 @return: automerge metadata for given package identifier 4355 @rtype: list or set 4356 """ 4357 # FIXME backward compatibility 4358 if not self._doesTableExist('automergefiles'): 4359 self._createAutomergefilesTable() 4360 4361 # like portage does 4362 self.connection.text_factory = lambda x: const_convert_to_unicode(x) 4363 4364 cur = self.cursor.execute(""" 4365 SELECT configfile, md5 FROM automergefiles WHERE idpackage = (?) 4366 """, (idpackage,)) 4367 data = cur.fetchall() 4368 4369 if get_dict: 4370 data = dict(((x, y,) for x, y in data)) 4371 return data
4372
4373 - def retrieveContent(self, idpackage, extended = False, contentType = None, 4374 formatted = False, insert_formatted = False, order_by = ''):
4375 """ 4376 Return files contained in given package. 4377 4378 @param idpackage: package indentifier 4379 @type idpackage: int 4380 @keyword extended: return in extended format 4381 @type extended: bool 4382 @keyword contentType: only return given entry type, which can be: 4383 "obj", "sym" or "dir" 4384 @type contentType: int 4385 @keyword formatted: return in dict() form 4386 @type formatted: bool 4387 @keyword insert_formatted: return in list of tuples form, ready to 4388 be added with insertContent() 4389 @keyword order_by: order by string, valid values are: 4390 "type" (if extended is True), "file" or "idpackage" 4391 @type order_by: string 4392 @return: content metadata 4393 @rtype: dict or list or set 4394 """ 4395 extstring = '' 4396 if extended: 4397 extstring = ",type" 4398 extstring_idpackage = '' 4399 if insert_formatted: 4400 extstring_idpackage = 'idpackage,' 4401 4402 searchkeywords = [idpackage] 4403 contentstring = '' 4404 if contentType: 4405 searchkeywords.append(contentType) 4406 contentstring = ' and type = (?)' 4407 4408 order_by_string = '' 4409 if order_by: 4410 order_by_string = ' order by %s' % (order_by,) 4411 4412 did_try = False 4413 while True: 4414 try: 4415 4416 cur = self.cursor.execute(""" 4417 SELECT %s file%s FROM content WHERE idpackage = (?) %s%s""" % ( 4418 extstring_idpackage, extstring, 4419 contentstring, order_by_string,), 4420 searchkeywords) 4421 4422 if extended and insert_formatted: 4423 fl = cur.fetchall() 4424 4425 elif extended and formatted: 4426 fl = {} 4427 items = cur.fetchone() 4428 while items: 4429 fl[items[0]] = items[1] 4430 items = cur.fetchone() 4431 4432 elif extended: 4433 fl = cur.fetchall() 4434 4435 else: 4436 if order_by: 4437 fl = self._cur2list(cur) 4438 else: 4439 fl = self._cur2set(cur) 4440 4441 break 4442 4443 except self.dbapi2.OperationalError: 4444 4445 if did_try: 4446 raise 4447 did_try = True 4448 4449 # FIXME support for old entropy db entries, which were 4450 # not inserted in utf-8 4451 self.connection.text_factory = lambda x: \ 4452 const_convert_to_unicode(x) 4453 continue 4454 4455 return fl
4456
4457 - def retrieveChangelog(self, idpackage):
4458 """ 4459 Return Source Package Manager ChangeLog for given package identifier. 4460 4461 @param idpackage: package indentifier 4462 @type idpackage: int 4463 @return: ChangeLog content 4464 @rtype: string or None 4465 """ 4466 # FIXME backward compatibility 4467 if not self._doesTableExist('packagechangelogs'): 4468 return None 4469 4470 cur = self.cursor.execute(""" 4471 SELECT packagechangelogs.changelog 4472 FROM packagechangelogs, baseinfo, categories 4473 WHERE baseinfo.idpackage = (?) AND 4474 baseinfo.idcategory = categories.idcategory AND 4475 packagechangelogs.name = baseinfo.name AND 4476 packagechangelogs.category = categories.category 4477 LIMIT 1 4478 """, (idpackage,)) 4479 changelog = cur.fetchone() 4480 if changelog: 4481 changelog = changelog[0] 4482 try: 4483 return const_convert_to_unicode(changelog) 4484 except UnicodeDecodeError: 4485 return const_convert_to_unicode(changelog, enctype = 'utf-8')
4486
4487 - def retrieveChangelogByKey(self, category, name):
4488 """ 4489 Return Source Package Manager ChangeLog content for given package 4490 category and name. 4491 4492 @param category: package category 4493 @type category: string 4494 @param name: package name 4495 @type name: string 4496 @return: ChangeLog content 4497 @rtype: string or None 4498 """ 4499 # FIXME backward compatibility 4500 if not self._doesTableExist('packagechangelogs'): 4501 return None 4502 4503 self.connection.text_factory = lambda x: const_convert_to_unicode(x) 4504 4505 cur = self.cursor.execute(""" 4506 SELECT changelog FROM packagechangelogs WHERE category = (?) AND 4507 name = (?) LIMIT 1 4508 """, (category, name,)) 4509 4510 changelog = cur.fetchone() 4511 if changelog: 4512 return const_convert_to_unicode(changelog[0])
4513
4514 - def retrieveSlot(self, idpackage):
4515 """ 4516 Return "slot" metadatum for given package identifier. 4517 4518 @param idpackage: package indentifier 4519 @type idpackage: int 4520 @return: package slot 4521 @rtype: string or None 4522 """ 4523 cur = self.cursor.execute(""" 4524 SELECT slot FROM baseinfo WHERE idpackage = (?) LIMIT 1 4525 """, (idpackage,)) 4526 slot = cur.fetchone() 4527 if slot: 4528 return slot[0]
4529
4530 - def retrieveVersionTag(self, idpackage):
4531 """ 4532 Return "tag" metadatum for given package identifier. 4533 Tagging packages allows, for example, to support multiple 4534 different, colliding atoms in the same repository and still being 4535 able to exactly reference them. It's actually used to provide 4536 versions of external kernel modules for different kernels. 4537 4538 @param idpackage: package indentifier 4539 @type idpackage: int 4540 @return: tag string 4541 @rtype: string or None 4542 """ 4543 cur = self.cursor.execute(""" 4544 SELECT versiontag FROM baseinfo WHERE idpackage = (?) LIMIT 1 4545 """, (idpackage,)) 4546 vtag = cur.fetchone() 4547 if vtag: 4548 return vtag[0]
4549
4550 - def retrieveMirrorInfo(self, mirrorname):
4551 """ 4552 Return available mirror URls for given mirror name. 4553 4554 @param mirrorname: mirror name (for eg. "openoffice") 4555 @type mirrorname: string 4556 @return: list (set) of URLs providing the "openoffice" mirroring service 4557 @rtype: set 4558 """ 4559 cur = self.cursor.execute(""" 4560 SELECT mirrorlink FROM mirrorlinks WHERE mirrorname = (?) 4561 """, (mirrorname,)) 4562 return self._cur2set(cur)
4563
4564 - def retrieveCategory(self, idpackage):
4565 """ 4566 Return category name for given package identifier. 4567 4568 @param idpackage: package indentifier 4569 @type idpackage: int 4570 @return: category where package is in 4571 @rtype: string or None 4572 """ 4573 cur = self.cursor.execute(""" 4574 SELECT category FROM baseinfo,categories 4575 WHERE baseinfo.idpackage = (?) AND 4576 baseinfo.idcategory = categories.idcategory LIMIT 1 4577 """, (idpackage,)) 4578 4579 cat = cur.fetchone() 4580 if cat: 4581 return cat[0]
4582
4583 - def retrieveCategoryDescription(self, category):
4584 """ 4585 Return description text for given category. 4586 4587 @param category: category name 4588 @type category: string 4589 @return: category description dict, locale as key, description as value 4590 @rtype: dict 4591 """ 4592 cur = self.cursor.execute(""" 4593 SELECT description, locale FROM categoriesdescription 4594 WHERE category = (?) 4595 """, (category,)) 4596 4597 return dict((locale, desc,) for desc, locale in cur.fetchall())
4598
4599 - def retrieveLicensedata(self, idpackage):
4600 """ 4601 Return license metadata for given package identifier. 4602 4603 @param idpackage: package indentifier 4604 @type idpackage: int 4605 @return: dictionary composed by license name as key and license text 4606 as value 4607 @rtype: dict 4608 """ 4609 4610 licenses = self.retrieveLicense(idpackage) 4611 if licenses is None: 4612 return {} 4613 4614 licdata = {} 4615 for licname in licenses.split(): 4616 4617 if not licname.strip(): 4618 continue 4619 4620 if not self.entropyTools.is_valid_string(licname): 4621 continue 4622 4623 cur = self.cursor.execute(""" 4624 SELECT text FROM licensedata WHERE licensename = (?) LIMIT 1 4625 """, (licname,)) 4626 lictext = cur.fetchone() 4627 if lictext is not None: 4628 lictext = lictext[0] 4629 try: 4630 licdata[licname] = const_convert_to_unicode(lictext) 4631 except UnicodeDecodeError: 4632 licdata[licname] = \ 4633 const_convert_to_unicode(lictext, enctype = 'utf-8') 4634 4635 return licdata
4636
4637 - def retrieveLicensedataKeys(self, idpackage):
4638 """ 4639 Return license names available for given package identifier. 4640 4641 @param idpackage: package indentifier 4642 @type idpackage: int 4643 @return: list (set) of license names which text is available in 4644 repository 4645 @rtype: set 4646 """ 4647 4648 licenses = self.retrieveLicense(idpackage) 4649 if licenses is None: 4650 return set() 4651 4652 licdata = set() 4653 for licname in licenses.split(): 4654 4655 if not licname.strip(): 4656 continue 4657 4658 if not self.entropyTools.is_valid_string(licname): 4659 continue 4660 4661 cur = self.cursor.execute(""" 4662 SELECT licensename FROM licensedata WHERE licensename = (?) LIMIT 1 4663 """, (licname,)) 4664 lic_id = cur.fetchone() 4665 if lic_id: 4666 licdata.add(lic_id[0]) 4667 4668 return licdata
4669
4670 - def retrieveLicenseText(self, license_name):
4671 """ 4672 Return license text for given license name. 4673 4674 @param license_name: license name (for eg. GPL-2) 4675 @type license_name: string 4676 @return: license text 4677 @rtype: string (raw format) or None 4678 """ 4679 4680 self.connection.text_factory = lambda x: const_convert_to_unicode(x) 4681 4682 cur = self.cursor.execute(""" 4683 SELECT text FROM licensedata WHERE licensename = (?) LIMIT 1 4684 """, (license_name,)) 4685 4686 text = cur.fetchone() 4687 if text: 4688 return const_convert_to_rawstring(text[0])
4689
4690 - def retrieveLicense(self, idpackage):
4691 """ 4692 Return "license" metadatum for given package identifier. 4693 4694 @param idpackage: package indentifier 4695 @type idpackage: int 4696 @return: license string 4697 @rtype: string or None 4698 """ 4699 cur = self.cursor.execute(""" 4700 SELECT license FROM baseinfo,licenses 4701 WHERE baseinfo.idpackage = (?) AND 4702 baseinfo.idlicense = licenses.idlicense LIMIT 1 4703 """, (idpackage,)) 4704 4705 licname = cur.fetchone() 4706 if licname: 4707 return licname[0]
4708
4709 - def retrieveCompileFlags(self, idpackage):
4710 """ 4711 Return Compiler flags during building of package. 4712 (CHOST, CXXFLAGS, LDFLAGS) 4713 4714 @param idpackage: package indentifier 4715 @type idpackage: int 4716 @return: tuple of length 3 composed by (CHOST, CFLAGS, CXXFLAGS) 4717 @rtype: tuple 4718 """ 4719 self.cursor.execute(""" 4720 SELECT chost,cflags,cxxflags FROM flags,extrainfo 4721 WHERE extrainfo.idpackage = (?) AND 4722 extrainfo.idflags = flags.idflags""", (idpackage,)) 4723 flags = self.cursor.fetchone() 4724 if not flags: 4725 flags = ("N/A", "N/A", "N/A",) 4726 return flags
4727
4728 - def retrieveReverseDependencies(self, idpackage, atoms = False, 4729 key_slot = False, exclude_deptypes = None):
4730 """ 4731 Return reverse (or inverse) dependencies for given package. 4732 4733 @param idpackage: package indentifier 4734 @type idpackage: int 4735 @keyword atoms: if True, method returns list of atoms 4736 @type atoms: bool 4737 @keyword key_slot: if True, method returns list of dependencies in 4738 key:slot form, example: [('app-foo/bar','2',), ...] 4739 @type key_slot: bool 4740 @keyword exclude_deptypes: exclude given dependency types from returned 4741 data 4742 @type exclude_deptypes: iterable 4743 @return: reverse dependency list 4744 @rtype: list or set 4745 4746 """ 4747 4748 # WARNING: never remove this, otherwise equo.db 4749 # (client database) dependstable will be always broken (trust me) 4750 # sanity check on the table 4751 c_tup = ("retrieveReverseDependencies_check",) 4752 if not self.live_cache.get(c_tup): 4753 self.live_cache[c_tup] = True 4754 if not self._isDependsTableSane(): # is empty, need generation 4755 self.generateReverseDependenciesMetadata(verbose = False) 4756 4757 excluded_deptypes_query = "" 4758 if exclude_deptypes is not None: 4759 for dep_type in exclude_deptypes: 4760 excluded_deptypes_query += " AND dependencies.type != %s" % ( 4761 dep_type,) 4762 4763 if atoms: 4764 cur = self.cursor.execute(""" 4765 SELECT baseinfo.atom FROM dependstable,dependencies,baseinfo 4766 WHERE dependstable.idpackage = (?) AND 4767 dependstable.iddependency = dependencies.iddependency AND 4768 baseinfo.idpackage = dependencies.idpackage %s""" % ( 4769 excluded_deptypes_query,), (idpackage,)) 4770 result = self._cur2set(cur) 4771 elif key_slot: 4772 cur = self.cursor.execute(""" 4773 SELECT categories.category || "/" || baseinfo.name,baseinfo.slot 4774 FROM baseinfo,categories,dependstable,dependencies 4775 WHERE dependstable.idpackage = (?) AND 4776 dependstable.iddependency = dependencies.iddependency AND 4777 baseinfo.idpackage = dependencies.idpackage AND 4778 categories.idcategory = baseinfo.idcategory %s""" % ( 4779 excluded_deptypes_query,), (idpackage,)) 4780 result = cur.fetchall() 4781 else: 4782 cur = self.cursor.execute(""" 4783 SELECT dependencies.idpackage FROM dependstable,dependencies 4784 WHERE dependstable.idpackage = (?) AND 4785 dependstable.iddependency = dependencies.iddependency %s""" % ( 4786 excluded_deptypes_query,), (idpackage,)) 4787 result = self._cur2set(cur) 4788 4789 return result
4790
4791 - def retrieveUnusedIdpackages(self):
4792 """ 4793 Return packages (through their identifiers) not referenced by any 4794 other as dependency (unused packages). 4795 4796 @return: unused idpackages ordered by atom 4797 @rtype: list 4798 """ 4799 4800 # WARNING: never remove this, otherwise equo.db (client database) 4801 # dependstable will be always broken (trust me) 4802 # sanity check on the table 4803 c_tup = ("retrieveUnusedIdpackages_check",) 4804 if not self.live_cache.get(c_tup): 4805 self.live_cache[c_tup] = True 4806 if not self._isDependsTableSane(): # is empty, need generation 4807 self.generateReverseDependenciesMetadata(verbose = False) 4808 4809 cur = self.cursor.execute(""" 4810 SELECT idpackage FROM baseinfo 4811 WHERE idpackage NOT IN (SELECT idpackage FROM dependstable) 4812 ORDER BY atom 4813 """) 4814 return self._cur2list(cur)
4815
4816 - def isAtomAvailable(self, atom):
4817 """ 4818 Return whether given atom is available in repository. 4819 4820 @param atom: package atom 4821 @type atom: string 4822 @return: idpackage or -1 if not found 4823 @rtype: int 4824 """ 4825 cur = self.cursor.execute(""" 4826 SELECT idpackage FROM baseinfo WHERE atom = (?) LIMIT 1 4827 """, (atom,)) 4828 result = cur.fetchone() 4829 if result: 4830 return result[0] 4831 return -1
4832
4833 - def areIdpackagesAvailable(self, idpackages):
4834 """ 4835 Return whether list of package identifiers are available. 4836 They must be all available to return True 4837 4838 @param idpackages: list of package indentifiers 4839 @type idpackages: iterable 4840 @return: availability (True if all are available) 4841 @rtype: bool 4842 """ 4843 sql = """SELECT count(idpackage) FROM baseinfo 4844 WHERE idpackage IN (%s)""" % (','.join( 4845 [str(x) for x in set(idpackages)]), 4846 ) 4847 cur = self.cursor.execute(sql) 4848 count = cur.fetchone()[0] 4849 if count != len(idpackages): 4850 return False 4851 return True
4852
4853 - def isIdpackageAvailable(self, idpackage):
4854 """ 4855 Return whether given package identifier is available in repository. 4856 4857 @param idpackage: package indentifier 4858 @type idpackage: int 4859 @return: availability (True if available) 4860 @rtype: bool 4861 """ 4862 cur = self.cursor.execute(""" 4863 SELECT idpackage FROM baseinfo WHERE idpackage = (?) LIMIT 1 4864 """, (idpackage,)) 4865 result = cur.fetchone() 4866 if not result: 4867 return False 4868 return True
4869
4870 - def isCategoryAvailable(self, category):
4871 """ 4872 Return whether given category is available in repository. 4873 4874 @param category: category name 4875 @type category: string 4876 @return: availability (True if available) 4877 @rtype: bool 4878 """ 4879 cur = self.cursor.execute(""" 4880 SELECT idcategory FROM categories WHERE category = (?) LIMIT 1 4881 """, (category,)) 4882 result = cur.fetchone() 4883 if result: 4884 return result[0] 4885 return -1
4886
4887 - def isProtectAvailable(self, protect):
4888 """ 4889 Return whether given CONFIG_PROTECT* entry is available in repository. 4890 4891 @param protect: CONFIG_PROTECT* entry (path to a protected directory 4892 or file that won't be overwritten by Entropy Client during 4893 package merge) 4894 @type protect: string 4895 @return: availability (True if available) 4896 @rtype: bool 4897 """ 4898 cur = self.cursor.execute(""" 4899 SELECT idprotect FROM configprotectreference WHERE protect = (?) 4900 LIMIT 1 4901 """, (protect,)) 4902 result = cur.fetchone() 4903 if result: 4904 return result[0] 4905 return -1
4906
4907 - def isFileAvailable(self, myfile, get_id = False):
4908 """ 4909 Return whether given file path is available in repository (owned by 4910 one or more packages). 4911 4912 @param myfile: path to file or directory 4913 @type myfile: string 4914 @keyword get_id: return list (set) of idpackages owning myfile 4915 @type get_id: bool 4916 @return: availability (True if available), when get_id is True, 4917 it returns a list (set) of idpackages owning myfile 4918 @rtype: bool or set 4919 """ 4920 cur = self.cursor.execute(""" 4921 SELECT idpackage FROM content WHERE file = (?)""", (myfile,)) 4922 result = cur.fetchall() 4923 if get_id: 4924 return self._fetchall2set(result) 4925 elif result: 4926 return True 4927 return False
4928
4929 - def resolveNeeded(self, needed, elfclass = -1, extended = False):
4930 """ 4931 Resolve NEEDED ELF entry (a library name) to idpackages owning given 4932 needed (stressing, needed = library name) 4933 4934 @param needed: library name 4935 @type needed: string 4936 @keyword elfclass: look for library name matching given ELF class 4937 @type elfclass: int 4938 @keyword extended: return a list of tuple of length 2, first element 4939 is idpackage, second is actual library path 4940 @type extended: bool 4941 @return: list of packages owning given library 4942 @rtype: list or set 4943 """ 4944 # TODO: remove this in future, backward compat. 4945 if not self._doesTableExist('provided_libs'): 4946 self._createProvidedLibs() 4947 4948 args = (needed,) 4949 elfclass_txt = '' 4950 if elfclass != -1: 4951 elfclass_txt = ' AND provided_libs.elfclass = (?)' 4952 args = (needed, elfclass,) 4953 4954 if extended: 4955 cur = self.cursor.execute(""" 4956 SELECT idpackage, path FROM provided_libs 4957 WHERE library = (?)""" + elfclass_txt, args) 4958 return cur.fetchall() 4959 4960 cur = self.cursor.execute(""" 4961 SELECT idpackage FROM provided_libs 4962 WHERE library = (?)""" + elfclass_txt, args) 4963 return self._cur2set(cur)
4964
4965 - def isSourceAvailable(self, source):
4966 """ 4967 Return whether given source package URL is available in repository. 4968 Returns source package URL identifier (idsource). 4969 4970 @param source: source package URL 4971 @type source: string 4972 @return: source package URL identifier (idsource) or -1 if not found 4973 @rtype: int 4974 4975 """ 4976 cur = self.cursor.execute(""" 4977 SELECT idsource FROM sourcesreference WHERE source = (?) LIMIT 1 4978 """, (source,)) 4979 result = cur.fetchone() 4980 if result: 4981 return result[0] 4982 return -1
4983
4984 - def isDependencyAvailable(self, dependency):
4985 """ 4986 Return whether given dependency string is available in repository. 4987 Returns dependency identifier (iddependency). 4988 4989 @param dependency: dependency string 4990 @type dependency: string 4991 @return: dependency identifier (iddependency) or -1 if not found 4992 @rtype: int 4993 """ 4994 cur = self.cursor.execute(""" 4995 SELECT iddependency FROM dependenciesreference WHERE dependency = (?) 4996 LIMIT 1""", (dependency,)) 4997 result = cur.fetchone() 4998 if result: 4999 return result[0] 5000 return -1
5001
5002 - def isKeywordAvailable(self, keyword):
5003 """ 5004 Return whether keyword string is available in repository. 5005 Returns keyword identifier (idkeyword) 5006 5007 @param keyword: keyword string 5008 @type keyword: string 5009 @return: keyword identifier (idkeyword) or -1 if not found 5010 @rtype: int 5011 """ 5012 cur = self.cursor.execute(""" 5013 SELECT idkeyword FROM keywordsreference WHERE keywordname = (?) LIMIT 1 5014 """, (keyword,)) 5015 result = cur.fetchone() 5016 if result: 5017 return result[0] 5018 return -1
5019
5020 - def isUseflagAvailable(self, useflag):
5021 """ 5022 Return whether USE flag name is available in repository. 5023 Returns USE flag identifier (idflag). 5024 5025 @param useflag: USE flag name 5026 @type useflag: string 5027 @return: USE flag identifier or -1 if not found 5028 @rtype: int 5029 """ 5030 cur = self.cursor.execute(""" 5031 SELECT idflag FROM useflagsreference WHERE flagname = (?) LIMIT 1 5032 """, (useflag,)) 5033 result = cur.fetchone() 5034 if result: 5035 return result[0] 5036 return -1
5037
5038 - def isEclassAvailable(self, eclass):
5039 """ 5040 Return whether eclass name is available in repository. 5041 Returns Eclass identifier (idclass) 5042 5043 @param eclass: eclass name 5044 @type eclass: string 5045 @return: Eclass identifier or -1 if not found 5046 @rtype: int 5047 """ 5048 cur = self.cursor.execute(""" 5049 SELECT idclass FROM eclassesreference WHERE classname = (?) LIMIT 1 5050 """, (eclass,)) 5051 result = cur.fetchone() 5052 if result: 5053 return result[0] 5054 return -1
5055
5056 - def isNeededAvailable(self, needed):
5057 """ 5058 Return whether NEEDED ELF entry (library name) is available in 5059 repository. 5060 Returns NEEDED entry identifier 5061 5062 @param needed: NEEDED ELF entry (library name) 5063 @type needed: string 5064 @return: NEEDED entry identifier or -1 if not found 5065 @rtype: int 5066 """ 5067 cur = self.cursor.execute(""" 5068 SELECT idneeded FROM neededreference WHERE library = (?) LIMIT 1 5069 """, (needed,)) 5070 result = cur.fetchone() 5071 if result: 5072 return result[0] 5073 return -1
5074
5075 - def isSpmUidAvailable(self, spm_uid):
5076 """ 5077 Return whether Source Package Manager package identifier is available 5078 in repository. 5079 5080 @param spm_uid: Source Package Manager package identifier 5081 @type spm_uid: int 5082 @return: availability (True, if available) 5083 @rtype: bool 5084 """ 5085 cur = self.cursor.execute(""" 5086 SELECT counter FROM counters WHERE counter = (?) LIMIT 1 5087 """, (spm_uid,)) 5088 result = cur.fetchone() 5089 if result: 5090 return True 5091 return False
5092
5093 - def isSpmUidTrashed(self, spm_uid):
5094 """ 5095 Return whether Source Package Manager package identifier has been 5096 trashed. One is trashed when it gets removed from a repository while 5097 still sitting there in place on live system. This is a trick to allow 5098 multiple-repositories management to work fine when shitting around. 5099 5100 @param spm_uid: Source Package Manager package identifier 5101 @type spm_uid: int 5102 @return: availability (True, if available) 5103 @rtype: bool 5104 """ 5105 cur = self.cursor.execute(""" 5106 SELECT counter FROM trashedcounters WHERE counter = (?) LIMIT 1 5107 """, (spm_uid,)) 5108 result = cur.fetchone() 5109 if result: 5110 return True 5111 return False
5112
5113 - def isLicensedataKeyAvailable(self, license_name):
5114 """ 5115 Return whether license name is available in License database, which is 5116 the one containing actual license texts. 5117 5118 @param license_name: license name which license text is available 5119 @type license_name: string 5120 @return: availability (True, if available) 5121 @rtype: bool 5122 """ 5123 cur = self.cursor.execute(""" 5124 SELECT licensename FROM licensedata WHERE licensename = (?) LIMIT 1 5125 """, (license_name,)) 5126 result = cur.fetchone() 5127 if not result: 5128 return False 5129 return True
5130
5131 - def isLicenseAccepted(self, license_name):
5132 """ 5133 Return whether given license (through its name) has been accepted by 5134 user. 5135 5136 @param license_name: license name 5137 @type license_name: string 5138 @return: if license name has been accepted by user 5139 @rtype: bool 5140 """ 5141 cur = self.cursor.execute(""" 5142 SELECT licensename FROM licenses_accepted WHERE licensename = (?) 5143 LIMIT 1 5144 """, (license_name,)) 5145 result = cur.fetchone() 5146 if not result: 5147 return False 5148 return True
5149
5150 - def acceptLicense(self, license_name):
5151 """ 5152 Mark license name as accepted by user. 5153 Only and only if user is allowed to accept them: 5154 - in entropy group 5155 - db not open in read only mode 5156 5157 @param license_name: license name 5158 @type license_name: string 5159 @todo: check if readOnly is really required 5160 @todo: check if is_user_in_entropy_group is really required 5161 """ 5162 if self.readOnly: 5163 return 5164 if not self.entropyTools.is_user_in_entropy_group(): 5165 return 5166 5167 plugins = self.get_plugins() 5168 for plugin_id in sorted(plugins): 5169 plug_inst = plugins[plugin_id] 5170 exec_rc = plug_inst.accept_license_hook(self) 5171 if exec_rc: 5172 raise RepositoryPluginError( 5173 "[accept_license_hook] %s: status: %s" % ( 5174 plug_inst.get_id(), exec_rc,)) 5175 5176 with self.__write_mutex: 5177 self.cursor.execute(""" 5178 INSERT OR IGNORE INTO licenses_accepted VALUES (?) 5179 """, (license_name,)) 5180 self.commitChanges()
5181
5182 - def isLicenseAvailable(self, pkglicense):
5183 """ 5184 Return whether license metdatatum (NOT license name) is available 5185 in repository. 5186 5187 @param pkglicense: "license" package metadatum (returned by 5188 retrieveLicense) 5189 @type pkglicense: string 5190 @return: "license" metadatum identifier (idlicense) 5191 @rtype: int 5192 """ 5193 if not self.entropyTools.is_valid_string(pkglicense): 5194 pkglicense = ' ' 5195 5196 cur = self.cursor.execute(""" 5197 SELECT idlicense FROM licenses WHERE license = (?) LIMIT 1 5198 """, (pkglicense,)) 5199 result = cur.fetchone() 5200 5201 if result: 5202 return result[0] 5203 return -1
5204
5205 - def isSystemPackage(self, idpackage):
5206 """ 5207 Return whether package is part of core system (though, a system 5208 package). 5209 5210 @param idpackage: package indentifier 5211 @type idpackage: int 5212 @return: if True, package is part of core system 5213 @rtype: bool 5214 """ 5215 cur = self.cursor.execute(""" 5216 SELECT idpackage FROM systempackages WHERE idpackage = (?) LIMIT 1 5217 """, (idpackage,)) 5218 result = cur.fetchone() 5219 if result: 5220 return True 5221 return False
5222
5223 - def isInjected(self, idpackage):
5224 """ 5225 Return whether package has been injected into repository (means that 5226 will be never ever removed due to colliding scope when other 5227 packages will be added). 5228 5229 @param idpackage: package indentifier 5230 @type idpackage: int 5231 @return: injection status (True if injected) 5232 @rtype: bool 5233 """ 5234 cur = self.cursor.execute(""" 5235 SELECT idpackage FROM injected WHERE idpackage = (?) LIMIT 1 5236 """, (idpackage,)) 5237 result = cur.fetchone() 5238 if result: 5239 return True 5240 return False
5241
5242 - def areCompileFlagsAvailable(self, chost, cflags, cxxflags):
5243 """ 5244 Return whether given Compiler FLAGS are available in repository. 5245 5246 @param chost: CHOST flag 5247 @type chost: string 5248 @param cflags: CFLAGS flag 5249 @type cflags: string 5250 @param cxxflags: CXXFLAGS flag 5251 @type cxxflags: string 5252 @return: availability (True if available) 5253 @rtype: bool 5254 """ 5255 cur = self.cursor.execute(""" 5256 SELECT idflags FROM flags WHERE chost = (?) 5257 AND cflags = (?) AND cxxflags = (?) LIMIT 1 5258 """, 5259 (chost, cflags, cxxflags,) 5260 ) 5261 result = cur.fetchone() 5262 if result: 5263 return result[0] 5264 return -1
5265
5266 - def searchBelongs(self, file, like = False):
5267 """ 5268 Search packages which given file path belongs to. 5269 5270 @param file: file path to search 5271 @type file: string 5272 @keyword like: do not match exact case 5273 @type like: bool 5274 @return: list (set) of package identifiers owning given file 5275 @rtype: set 5276 """ 5277 if like: 5278 cur = self.cursor.execute(""" 5279 SELECT content.idpackage FROM content,baseinfo 5280 WHERE file LIKE (?) AND 5281 content.idpackage = baseinfo.idpackage""", (file,)) 5282 else: 5283 cur = self.cursor.execute("""SELECT content.idpackage 5284 FROM content, baseinfo WHERE file = (?) 5285 AND content.idpackage = baseinfo.idpackage""", (file,)) 5286 5287 return self._cur2set(cur)
5288
5289 - def searchEclassedPackages(self, eclass, atoms = False): # atoms = return atoms directly
5290 """ 5291 Search packages which their Source Package Manager counterpar are using 5292 given eclass. 5293 5294 @param eclass: eclass name to search 5295 @type eclass: string 5296 @keyword atoms: return list of atoms instead of package identifiers 5297 @type atoms: bool 5298 @return: list of packages using given eclass 5299 @rtype: set or list 5300 """ 5301 if atoms: 5302 cur = self.cursor.execute(""" 5303 SELECT baseinfo.atom,eclasses.idpackage 5304 FROM baseinfo, eclasses, eclassesreference 5305 WHERE eclassesreference.classname = (?) AND 5306 eclassesreference.idclass = eclasses.idclass AND 5307 eclasses.idpackage = baseinfo.idpackage""", (eclass,)) 5308 return cur.fetchall() 5309 5310 cur = self.cursor.execute(""" 5311 SELECT idpackage FROM baseinfo WHERE versiontag = (?)""", (eclass,)) 5312 return self._cur2set(cur) 5313
5314 - def searchTaggedPackages(self, tag, atoms = False):
5315 """ 5316 Search packages which "tag" metadatum matches the given one. 5317 5318 @param tag: tag name to search 5319 @type tag: string 5320 @keyword atoms: return list of atoms instead of package identifiers 5321 @type atoms: bool 5322 @return: list of packages using given tag 5323 @rtype: set or list 5324 """ 5325 if atoms: 5326 cur = self.cursor.execute(""" 5327 SELECT atom, idpackage FROM baseinfo WHERE versiontag = (?) 5328 """, (tag,)) 5329 return cur.fetchall() 5330 5331 cur = self.cursor.execute(""" 5332 SELECT idpackage FROM baseinfo WHERE versiontag = (?) 5333 """, (tag,)) 5334 return self._cur2set(cur)
5335
5336 - def searchLicenses(self, mylicense, caseSensitive = False, atoms = False):
5337 """ 5338 Search packages using given license (mylicense). 5339 5340 @param mylicense: license name to search 5341 @type mylicense: string 5342 @keyword caseSensitive: search in case sensitive mode (default off) 5343 @type caseSensitive: bool 5344 @keyword atoms: return list of atoms instead of package identifiers 5345 @type atoms: bool 5346 @return: list of packages using given license 5347 @rtype: set or list 5348 @todo: check if is_valid_string is really required 5349 """ 5350 if not self.entropyTools.is_valid_string(mylicense): 5351 return [] 5352 5353 request = "baseinfo.idpackage" 5354 if atoms: 5355 request = "baseinfo.atom,baseinfo.idpackage" 5356 5357 if caseSensitive: 5358 cur = self.cursor.execute(""" 5359 SELECT %s FROM baseinfo,licenses 5360 WHERE licenses.license LIKE (?) AND 5361 licenses.idlicense = baseinfo.idlicense 5362 """ % (request,), ("%"+mylicense+"%",)) 5363 else: 5364 cur = self.cursor.execute(""" 5365 SELECT %s FROM baseinfo,licenses 5366 WHERE LOWER(licenses.license) LIKE (?) AND 5367 licenses.idlicense = baseinfo.idlicense 5368 """ % (request,), ("%"+mylicense+"%".lower(),)) 5369 5370 if atoms: 5371 return cur.fetchall() 5372 return self._cur2set(cur)
5373
5374 - def searchSlottedPackages(self, slot, atoms = False):
5375 """ 5376 Search packages with given slot string. 5377 5378 @param slot: slot to search 5379 @type slot: string 5380 @keyword atoms: return list of atoms instead of package identifiers 5381 @type atoms: bool 5382 @return: list of packages using given slot 5383 @rtype: set or list 5384 """ 5385 if atoms: 5386 cur = self.cursor.execute(""" 5387 SELECT atom,idpackage FROM baseinfo WHERE slot = (?) 5388 """, (slot,)) 5389 return cur.fetchall() 5390 5391 cur = self.cursor.execute(""" 5392 SELECT idpackage FROM baseinfo WHERE slot = (?)""", (slot,)) 5393 return self._cur2set(cur)
5394
5395 - def searchKeySlot(self, key, slot):
5396 """ 5397 Search package with given key and slot 5398 5399 @param key: package key 5400 @type key: string 5401 @param slot: package slot 5402 @type slot: string 5403 @return: list (set) of package identifiers 5404 @rtype: set 5405 """ 5406 cat, name = key.split("/") 5407 cur = self.cursor.execute(""" 5408 SELECT idpackage FROM baseinfo, categories 5409 WHERE baseinfo.idcategory = categories.idcategory AND 5410 categories.category = (?) AND 5411 baseinfo.name = (?) AND 5412 baseinfo.slot = (?)""", (cat, name, slot,)) 5413 5414 return cur.fetchall()
5415
5416 - def searchNeeded(self, needed, elfclass = -1, like = False):
5417 """ 5418 Search packages that need given NEEDED ELF entry (library name). 5419 5420 @param needed: NEEDED ELF entry (shared object library name) 5421 @type needed: string 5422 @param elfclass: search NEEDEDs only with given ELF class 5423 @type elfclass: int 5424 @keyword like: do not match exact case 5425 @type like: bool 5426 @return: list (set) of package identifiers 5427 @rtype: set 5428 """ 5429 elfsearch = '' 5430 search_args = (needed,) 5431 if elfclass != -1: 5432 elfsearch = ' AND needed.elfclass = (?)' 5433 search_args = (needed, elfclass,) 5434 5435 if like: 5436 cur = self.cursor.execute(""" 5437 SELECT needed.idpackage FROM needed,neededreference 5438 WHERE library LIKE (?) %s AND 5439 needed.idneeded = neededreference.idneeded 5440 """ % (elfsearch,), search_args) 5441 else: 5442 cur = self.cursor.execute(""" 5443 SELECT needed.idpackage FROM needed,neededreference 5444 WHERE library = (?) %s AND 5445 needed.idneeded = neededreference.idneeded 5446 """ % (elfsearch,), search_args) 5447 5448 return self._cur2set(cur)
5449
5450 - def searchDependency(self, dep, like = False, multi = False, 5451 strings = False):
5452 """ 5453 Search dependency name in repository. 5454 Returns dependency identifier (iddependency) or dependency strings 5455 (if strings argument is True). 5456 5457 @param dep: dependency name 5458 @type dep: string 5459 @keyword like: do not match exact case 5460 @type like: bool 5461 @keyword multi: return all the matching dependency names 5462 @type multi: bool 5463 @keyword strings: return dependency names rather than dependency 5464 identifiers 5465 @type strings: bool 5466 @return: list of dependency identifiers (if multi is True) or 5467 strings (if strings is True) or dependency identifier 5468 @rtype: int or set 5469 """ 5470 sign = "=" 5471 if like: 5472 sign = "LIKE" 5473 dep = "%"+dep+"%" 5474 item = 'iddependency' 5475 if strings: 5476 item = 'dependency' 5477 5478 cur = self.cursor.execute(""" 5479 SELECT %s FROM dependenciesreference WHERE dependency %s (?) 5480 """ % (item, sign,), (dep,)) 5481 5482 if multi: 5483 return self._cur2set(cur) 5484 iddep = cur.fetchone() 5485 5486 if iddep: 5487 return iddep[0] 5488 return -1
5489
5490 - def searchIdpackageFromIddependency(self, iddep):
5491 """ 5492 Search package identifiers owning dependency given (in form of 5493 dependency identifier). 5494 5495 @param iddep: dependency identifier 5496 @type iddep: int 5497 @return: list (set) of package identifiers owning given dependency 5498 identifier 5499 @rtype: set 5500 """ 5501 cur = self.cursor.execute(""" 5502 SELECT idpackage FROM dependencies WHERE iddependency = (?) 5503 """, (iddep,)) 5504 return self._cur2set(cur)
5505
5506 - def searchSets(self, keyword):
5507 """ 5508 Search package sets in repository using given search keyword. 5509 5510 @param keyword: package set name to search 5511 @type keyword: string 5512 @return: list (set) of package sets available matching given keyword 5513 @rtype: set 5514 5515 """ 5516 cur = self.cursor.execute(""" 5517 SELECT DISTINCT(setname) FROM packagesets WHERE setname LIKE (?) 5518 """, ("%"+keyword+"%",)) 5519 5520 return self._cur2set(cur)
5521
5522 - def searchSimilarPackages(self, mystring, atom = False):
5523 """ 5524 Search similar packages (basing on package string given by mystring 5525 argument) using SOUNDEX algorithm (ahhh Google...). 5526 5527 @param mystring: package string to search 5528 @type mystring: string 5529 @keyword atom: return full atoms instead of package names 5530 @type atom: bool 5531 @return: list of similar package names 5532 @rtype: set 5533 """ 5534 s_item = 'name' 5535 if atom: 5536 s_item = 'atom' 5537 cur = self.cursor.execute(""" 5538 SELECT idpackage FROM baseinfo 5539 WHERE soundex(%s) = soundex((?)) ORDER BY %s 5540 """ % (s_item, s_item,), (mystring,)) 5541 5542 return self._cur2list(cur)
5543
5544 - def searchPackages(self, keyword, sensitive = False, slot = None, 5545 tag = None, order_by = 'atom', just_id = False):
5546 """ 5547 Search packages using given package name "keyword" argument. 5548 5549 @param keyword: package string 5550 @type keyword: string 5551 @keyword sensitive: case sensitive? 5552 @type sensitive: bool 5553 @keyword slot: search matching given slot 5554 @type slot: string 5555 @keyword tag: search matching given package tag 5556 @type tag: string 5557 @keyword order_by: order results by "atom", "name" or "version" 5558 @type order_by: string 5559 @keyword just_id: just return package identifiers (returning set()) 5560 @type just_id: bool 5561 @return: packages found matching given search criterias 5562 @rtype: set or list 5563 """ 5564 searchkeywords = ["%"+keyword+"%"] 5565 5566 slotstring = '' 5567 if slot: 5568 searchkeywords.append(slot) 5569 slotstring = ' and slot = (?)' 5570 5571 tagstring = '' 5572 if tag: 5573 searchkeywords.append(tag) 5574 tagstring = ' and versiontag = (?)' 5575 5576 order_by_string = '' 5577 if order_by in ("atom", "idpackage", "branch",): 5578 order_by_string = ' order by %s' % (order_by,) 5579 5580 search_elements = 'atom,idpackage,branch' 5581 if just_id: 5582 search_elements = 'idpackage' 5583 5584 if sensitive: 5585 cur = self.cursor.execute(""" 5586 SELECT %s FROM baseinfo WHERE atom LIKE (?) %s %s %s""" % ( 5587 search_elements, slotstring, tagstring, order_by_string,), 5588 searchkeywords 5589 ) 5590 else: 5591 cur = self.cursor.execute(""" 5592 SELECT %s FROM baseinfo WHERE 5593 LOWER(atom) LIKE (?) %s %s %s""" % ( 5594 search_elements, slotstring, tagstring, order_by_string,), 5595 searchkeywords 5596 ) 5597 5598 if just_id: 5599 return self._cur2list(cur) 5600 return cur.fetchall()
5601
5602 - def searchProvide(self, keyword, slot = None, tag = None, justid = False, 5603 get_extended = False):
5604 """ 5605 Search in old-style Portage PROVIDE metadata. 5606 WARNING: this method is deprecated and will be removed someday. 5607 5608 @param keyword: search term 5609 @type keyword: string 5610 @keyword slot: match given package slot 5611 @type slot: string 5612 @keyword tag: match given package tag 5613 @type tag: string 5614 @keyword justid: return list of package identifiers (set()) 5615 @type justid: bool 5616 @keyword get_extended: return data in extended format 5617 @type get_extended: bool 5618 @return: found PROVIDE metadata 5619 @rtype: list or set 5620 """ 5621 searchkeywords = [keyword] 5622 5623 slotstring = '' 5624 if slot: 5625 searchkeywords.append(slot) 5626 slotstring = ' and baseinfo.slot = (?)' 5627 5628 tagstring = '' 5629 if tag: 5630 searchkeywords.append(tag) 5631 tagstring = ' and baseinfo.versiontag = (?)' 5632 5633 atomstring = '' 5634 if not justid: 5635 atomstring = 'baseinfo.atom,' 5636 5637 get_def_string = '' 5638 if get_extended: 5639 # FIXME: this small snipped is here for backward compat 5640 if self._doesColumnInTableExist("provide", "is_default"): 5641 get_def_string = ",provide.is_default" 5642 else: 5643 get_def_string = ",0" 5644 5645 cur = self.cursor.execute(""" 5646 SELECT %s baseinfo.idpackage%s FROM baseinfo,provide 5647 WHERE provide.atom = (?) AND 5648 provide.idpackage = baseinfo.idpackage %s %s""" % ( 5649 atomstring, get_def_string, slotstring, tagstring,), 5650 searchkeywords 5651 ) 5652 5653 if justid and not get_extended: 5654 return self._cur2list(cur) 5655 return cur.fetchall()
5656
5657 - def searchPackagesByDescription(self, keyword):
5658 """ 5659 Search packages using given description string as keyword. 5660 5661 @param keyword: description sub-string to search 5662 @type keyword: string 5663 @return: list of tuples of length 2 containing atom and idpackage 5664 values 5665 @rtype: list 5666 """ 5667 cur = self.cursor.execute(""" 5668 SELECT baseinfo.atom, baseinfo.idpackage FROM extrainfo, baseinfo 5669 WHERE LOWER(extrainfo.description) LIKE (?) AND 5670 baseinfo.idpackage = extrainfo.idpackage 5671 """, ("%"+keyword.lower()+"%",)) 5672 return cur.fetchall()
5673
5674 - def searchPackagesByName(self, keyword, sensitive = False, justid = False):
5675 """ 5676 Search packages by package name. 5677 5678 @param keyword: package name to search 5679 @type keyword: string 5680 @keyword sensitive: case sensitive? 5681 @type sensitive: bool 5682 @keyword justid: return list of package identifiers (set()) otherwise 5683 return a list of tuples of length 2 containing atom and idpackage 5684 values 5685 @type justid: bool 5686 @return: list of packages found 5687 @rtype: list or set 5688 """ 5689 5690 atomstring = '' 5691 if not justid: 5692 atomstring = 'atom,' 5693 5694 if sensitive: 5695 cur = self.cursor.execute(""" 5696 SELECT %s idpackage FROM baseinfo 5697 WHERE name = (?) 5698 """ % (atomstring,), (keyword,)) 5699 else: 5700 cur = self.cursor.execute(""" 5701 SELECT %s idpackage FROM baseinfo 5702 WHERE LOWER(name) = (?) 5703 """ % (atomstring,), (keyword.lower(),)) 5704 5705 if justid: 5706 return self._cur2list(cur) 5707 return cur.fetchall()
5708 5709
5710 - def searchPackagesByCategory(self, keyword, like = False, branch = None):
5711 """ 5712 Search packages by category name. 5713 5714 @param keyword: category name 5715 @type keyword: string 5716 @keyword like: do not match exact case 5717 @type like: bool 5718 @keyword branch: search in given package branch 5719 @type branch: string 5720 @return: list of tuples of length 2 containing atom and idpackage 5721 values 5722 @rtype: list 5723 """ 5724 searchkeywords = [keyword] 5725 branchstring = '' 5726 if branch: 5727 searchkeywords.append(branch) 5728 branchstring = 'and branch = (?)' 5729 5730 if like: 5731 cur = self.cursor.execute(""" 5732 SELECT baseinfo.atom,baseinfo.idpackage FROM baseinfo,categories 5733 WHERE categories.category LIKE (?) AND 5734 baseinfo.idcategory = categories.idcategory %s 5735 """ % (branchstring,), searchkeywords) 5736 else: 5737 cur = self.cursor.execute(""" 5738 SELECT baseinfo.atom,baseinfo.idpackage FROM baseinfo,categories 5739 WHERE categories.category = (?) AND 5740 baseinfo.idcategory = categories.idcategory %s 5741 """ % (branchstring,), searchkeywords) 5742 5743 return cur.fetchall()
5744
5745 - def searchPackagesByNameAndCategory(self, name, category, sensitive = False, 5746 justid = False):
5747 """ 5748 Search packages matching given name and category strings. 5749 5750 @param name: package name to search 5751 @type name: string 5752 @param category: package category to search 5753 @type category: string 5754 @keyword sensitive: case sensitive? 5755 @type sensitive: bool 5756 @keyword justid: return list of package identifiers (set()) otherwise 5757 return a list of tuples of length 2 containing atom and idpackage 5758 values 5759 @type justid: bool 5760 @return: list of packages found 5761 @rtype: list or set 5762 """ 5763 5764 atomstring = '' 5765 if not justid: 5766 atomstring = 'atom,' 5767 5768 if sensitive: 5769 cur = self.cursor.execute(""" 5770 SELECT %s idpackage FROM baseinfo 5771 WHERE name = (?) AND 5772 idcategory IN ( 5773 SELECT idcategory FROM categories 5774 WHERE category = (?) 5775 )""" % (atomstring,), (name, category,)) 5776 else: 5777 cur = self.cursor.execute(""" 5778 SELECT %s idpackage FROM baseinfo 5779 WHERE LOWER(name) = (?) AND 5780 idcategory IN ( 5781 SELECT idcategory FROM categories 5782 WHERE LOWER(category) = (?) 5783 )""" % (atomstring,), (name.lower(), category.lower(),)) 5784 5785 if justid: 5786 return self._cur2list(cur) 5787 return cur.fetchall()
5788
5789 - def isPackageScopeAvailable(self, atom, slot, revision):
5790 """ 5791 Return whether given package scope is available. 5792 Also check if package found is masked and return masking reason 5793 identifier. 5794 5795 @param atom: package atom string 5796 @type atom: string 5797 @param slot: package slot string 5798 @type slot: string 5799 @param revision: entropy package revision 5800 @type revision: int 5801 @return: tuple composed by (idpackage or -1, idreason or 0,) 5802 @rtype: tuple 5803 5804 """ 5805 searchdata = (atom, slot, revision,) 5806 cur = self.cursor.execute(""" 5807 SELECT idpackage FROM baseinfo 5808 where atom = (?) AND slot = (?) AND revision = (?) LIMIT 1 5809 """, searchdata) 5810 rslt = cur.fetchone() 5811 5812 if rslt: # check if it's masked 5813 return self.idpackageValidator(rslt[0]) 5814 return -1, 0
5815
5816 - def isBranchMigrationAvailable(self, repository, from_branch, to_branch):
5817 """ 5818 Returns whether branch migration metadata given by the provided key 5819 (repository, from_branch, to_branch,) is available. 5820 5821 @param repository: repository identifier 5822 @type repository: string 5823 @param from_branch: original branch 5824 @type from_branch: string 5825 @param to_branch: destination branch 5826 @type to_branch: string 5827 @return: tuple composed by (1)post migration script md5sum and 5828 (2)post upgrade script md5sum 5829 @rtype: tuple 5830 """ 5831 cur = self.cursor.execute(""" 5832 SELECT post_migration_md5sum, post_upgrade_md5sum 5833 FROM entropy_branch_migration 5834 WHERE repository = (?) AND from_branch = (?) AND to_branch = (?) 5835 LIMIT 1 5836 """, (repository, from_branch, to_branch,)) 5837 return cur.fetchone()
5838
5839 - def listAllPackages(self, get_scope = False, order_by = None):
5840 """ 5841 List all packages in repository. 5842 5843 @keyword get_scope: return also entropy package revision 5844 @type get_scope: bool 5845 @keyword order_by: order by given metadatum, "atom", "slot", "revision" 5846 or "idpackage" 5847 @type order_by: string 5848 @return: list of tuples of length 3 (or 4 if get_scope is True), 5849 containing (atom, idpackage, branch,) if get_scope is False and 5850 (idpackage, atom, slot, revision,) if get_scope is True 5851 @rtype: list 5852 """ 5853 order_txt = '' 5854 if order_by: 5855 order_txt = ' ORDER BY %s' % (order_by,) 5856 5857 if get_scope: 5858 cur = self.cursor.execute(""" 5859 SELECT idpackage,atom,slot,revision FROM baseinfo""" + order_txt) 5860 else: 5861 cur = self.cursor.execute(""" 5862 SELECT atom,idpackage,branch FROM baseinfo""" + order_txt) 5863 5864 return cur.fetchall()
5865
5866 - def listAllInjectedPackages(self, just_files = False):
5867 """ 5868 List all the "injected" package download URLs in repository. 5869 5870 @keyword just_files: just return download URLs 5871 @type just_files: bool 5872 @return: list (set) of download URLs (if just_files) otherwise list 5873 of tuples of length 2 composed by (download URL, idpackage,) 5874 @rtype: set 5875 """ 5876 cur = self.cursor.execute('SELECT idpackage FROM injected') 5877 injecteds = self._cur2set(cur) 5878 results = set() 5879 5880 for injected in injecteds: 5881 download = self.retrieveDownloadURL(injected) 5882 if just_files: 5883 results.add(download) 5884 else: 5885 results.add((download, injected)) 5886 5887 return results
5888
5889 - def listAllSpmUids(self):
5890 """ 5891 List all Source Package Manager unique package identifiers bindings 5892 with packages in repository. 5893 @return: list of tuples of length 2 composed by (spm_uid, idpackage,) 5894 @rtype: list 5895 """ 5896 cur = self.cursor.execute('SELECT counter, idpackage FROM counters') 5897 return cur.fetchall()
5898
5899 - def listAllIdpackages(self, order_by = None):
5900 """ 5901 List all package identifiers available in repository. 5902 5903 @keyword order_by: order by "atom", "idpackage", "version", "name", 5904 "idcategory" 5905 @type order_by: string 5906 @return: list (if order_by) or set of package identifiers 5907 @rtype: list or set 5908 """ 5909 orderbystring = '' 5910 if order_by: 5911 orderbystring = ' ORDER BY '+order_by 5912 5913 cur = self.cursor.execute(""" 5914 SELECT idpackage FROM baseinfo""" + orderbystring) 5915 5916 try: 5917 if order_by: 5918 return self._cur2list(cur) 5919 return self._cur2set(cur) 5920 except self.dbapi2.OperationalError: 5921 if order_by: 5922 return [] 5923 return set()
5924
5925 - def listAllDependencies(self):
5926 """ 5927 List all dependencies available in repository. 5928 5929 @return: list of tuples of length 2 containing (iddependency, dependency 5930 name,) 5931 @rtype: list 5932 """ 5933 cur = self.cursor.execute(""" 5934 SELECT iddependency, dependency FROM dependenciesreference""") 5935 return cur.fetchall()
5936
5937 - def listIdPackagesInIdcategory(self, idcategory, order_by = 'atom'):
5938 """ 5939 List package identifiers available in given category identifier. 5940 5941 @param idcategory: cateogory identifier 5942 @type idcategory: int 5943 @keyword order_by: order by "atom", "name", "version" 5944 @type order_by: string 5945 @return: list (set) of available package identifiers in category. 5946 @rtype: set 5947 """ 5948 order_by_string = '' 5949 if order_by in ("atom", "name", "version",): 5950 order_by_string = ' ORDER BY %s' % (order_by,) 5951 5952 cur = self.cursor.execute(""" 5953 SELECT idpackage FROM baseinfo where idcategory = (?) 5954 """ + order_by_string, (idcategory,)) 5955 5956 return self._cur2set(cur)
5957
5958 - def listAllDownloads(self, do_sort = True, full_path = False):
5959 """ 5960 List all package download URLs stored in repository. 5961 5962 @keyword do_sort: sort by name 5963 @type do_sort: bool 5964 @keyword full_path: return full URL (not just package file name) 5965 @type full_path: bool 5966 @return: list (or set if do_sort is True) of package download URLs 5967 @rtype: list or set 5968 """ 5969 5970 order_string = '' 5971 if do_sort: 5972 order_string = 'ORDER BY extrainfo.download' 5973 5974 cur = self.cursor.execute(""" 5975 SELECT extrainfo.download FROM baseinfo, extrainfo 5976 WHERE baseinfo.idpackage = extrainfo.idpackage %s 5977 """ % (order_string,)) 5978 5979 if do_sort: 5980 results = self._cur2list(cur) 5981 else: 5982 results = self._cur2set(cur) 5983 5984 if not full_path: 5985 results = [os.path.basename(x) for x in results] 5986 5987 return results
5988
5989 - def listAllFiles(self, clean = False, count = False):
5990 """ 5991 List all file paths owned by packaged stored in repository. 5992 5993 @keyword clean: return a clean list (not duplicates) 5994 @type clean: bool 5995 @keyword count: count elements and return number 5996 @type count: bool 5997 @return: list of files available or their count 5998 @rtype: int or list or set 5999 """ 6000 self.connection.text_factory = lambda x: const_convert_to_unicode(x) 6001 6002 if count: 6003 cur = self.cursor.execute('SELECT count(file) FROM content') 6004 else: 6005 cur = self.cursor.execute('SELECT file FROM content') 6006 6007 if count: 6008 return cur.fetchone()[0] 6009 if clean: 6010 return self._cur2set(cur) 6011 return self._cur2list(cur)
6012
6013 - def listAllCategories(self, order_by = ''):
6014 """ 6015 List all categories available in repository. 6016 6017 @keyword order_by: order by "category", "idcategory" 6018 @type order_by: string 6019 @return: list of tuples of length 2 composed by (idcategory, category,) 6020 @rtype: list 6021 """ 6022 order_by_string = '' 6023 if order_by: order_by_string = ' order by %s' % (order_by,) 6024 self.cursor.execute('SELECT idcategory,category FROM categories %s' % ( 6025 order_by_string,)) 6026 return self.cursor.fetchall()
6027
6028 - def listConfigProtectEntries(self, mask = False):
6029 """ 6030 List CONFIG_PROTECT* entries (configuration file/directories 6031 protection). 6032 6033 @keyword mask: return CONFIG_PROTECT_MASK metadata instead of 6034 CONFIG_PROTECT 6035 @type mask: bool 6036 @return: list of protected/masked directories 6037 @rtype: list 6038 """ 6039 mask_t = '' 6040 if mask: 6041 mask_t = 'mask' 6042 cur = self.cursor.execute(""" 6043 SELECT protect FROM configprotectreference WHERE idprotect IN 6044 (SELECT distinct(idprotect) FROM configprotect%s) 6045 ORDER BY protect""" % (mask_t,)) 6046 6047 results = self._cur2set(cur) 6048 dirs = set() 6049 for mystr in results: 6050 dirs.update(mystr.split()) 6051 6052 return sorted(dirs)
6053
6054 - def switchBranch(self, idpackage, tobranch):
6055 """ 6056 Switch branch string in repository to new value. 6057 6058 @param idpackage: package identifier 6059 @type idpackage: int 6060 @param tobranch: new branch value 6061 @type tobranch: string 6062 """ 6063 with self.__write_mutex: 6064 self.cursor.execute(""" 6065 UPDATE baseinfo SET branch = (?) 6066 WHERE idpackage = (?)""", (tobranch, idpackage,)) 6067 self.commitChanges() 6068 self.clearCache()
6069
6070 - def getSetting(self, setting_name):
6071 """ 6072 Return stored Repository setting. 6073 For currently supported setting_name values look at 6074 EntropyRepository.SETTING_KEYS. 6075 6076 @param setting_name: name of repository setting 6077 @type setting_name: string 6078 @return: setting value 6079 @rtype: string 6080 @raise KeyError: if setting_name is not valid or available 6081 """ 6082 if setting_name not in EntropyRepository.SETTING_KEYS: 6083 raise KeyError 6084 try: 6085 self.cursor.execute(""" 6086 SELECT setting_value FROM settings WHERE setting_name = (?) 6087 """, (setting_name,)) 6088 except self.dbapi2.Error: 6089 raise KeyError 6090 6091 setting = self.cursor.fetchone() 6092 if setting is None: 6093 raise KeyError 6094 return setting[0]
6095
6096 - def _setupInitialSettings(self):
6097 """ 6098 Setup initial repository settings 6099 """ 6100 self.cursor.executescript(""" 6101 INSERT OR REPLACE INTO settings VALUES ("arch", "%s"); 6102 INSERT OR REPLACE INTO settings VALUES ("on_delete_cascade", "%s"); 6103 """ % (etpConst['currentarch'], "1",) 6104 )
6105
6106 - def _databaseStructureUpdates(self):
6107 6108 old_readonly = self.readOnly 6109 self.readOnly = False 6110 6111 if not self._doesTableExist("licenses_accepted"): 6112 self._createLicensesAcceptedTable() 6113 6114 if not self._doesColumnInTableExist("installedtable", "source"): 6115 self._createInstalledTableSource() 6116 6117 if not self._doesColumnInTableExist("provide", "is_default"): 6118 self._createProvideDefault() 6119 6120 if not self._doesTableExist('packagesets'): 6121 self._createPackagesetsTable() 6122 6123 if not self._doesTableExist('packagechangelogs'): 6124 self._createPackagechangelogsTable() 6125 6126 if not self._doesTableExist('automergefiles'): 6127 self._createAutomergefilesTable() 6128 6129 if not self._doesTableExist('packagesignatures'): 6130 self._createPackagesignaturesTable() 6131 6132 if not self._doesTableExist('packagespmphases'): 6133 self._createPackagespmphases() 6134 6135 if not self._doesTableExist('packagespmrepository'): 6136 self._createPackagespmrepository() 6137 6138 if not self._doesTableExist('entropy_branch_migration'): 6139 self._createEntropyBranchMigrationTable() 6140 6141 if not self._doesTableExist('dependstable'): 6142 self._createDependsTable() 6143 6144 if not self._doesTableExist('settings'): 6145 self._createSettingsTable() 6146 6147 self._foreignKeySupport() 6148 6149 self.readOnly = old_readonly 6150 self.connection.commit()
6151
6152 - def validateDatabase(self):
6153 """ 6154 Validates Entropy repository by doing basic integrity checks. 6155 6156 @raise SystemDatabaseError: when repository is not reliable 6157 """ 6158 self.cursor.execute(""" 6159 SELECT name FROM SQLITE_MASTER WHERE type = (?) AND name = (?) 6160 """, ("table", "baseinfo")) 6161 rslt = self.cursor.fetchone() 6162 if rslt is None: 6163 mytxt = _("baseinfo error. Either does not exist or corrupted.") 6164 raise SystemDatabaseError("SystemDatabaseError: %s" % (mytxt,)) 6165 6166 self.cursor.execute(""" 6167 SELECT name FROM SQLITE_MASTER WHERE type = (?) AND name = (?) 6168 """, ("table", "extrainfo")) 6169 rslt = self.cursor.fetchone() 6170 if rslt is None: 6171 mytxt = _("extrainfo error. Either does not exist or corrupted.") 6172 raise SystemDatabaseError("SystemDatabaseError: %s" % (mytxt,))
6173
6174 - def getIdpackagesDifferences(self, foreign_idpackages):
6175 """ 6176 Return differences between in-repository package identifiers and 6177 list provided. 6178 6179 @param foreign_idpackages: list of foreign idpackages 6180 @type foreign_idpackages: iterable 6181 @return: tuple composed by idpackages that would be added and idpackages 6182 that would be removed 6183 @rtype: tuple 6184 """ 6185 myids = self.listAllIdpackages() 6186 if isinstance(foreign_idpackages, (list, tuple)): 6187 outids = set(foreign_idpackages) 6188 else: 6189 outids = foreign_idpackages 6190 added_ids = outids - myids 6191 removed_ids = myids - outids 6192 return added_ids, removed_ids
6193
6194 - def uniformBranch(self, branch):
6195 """ 6196 Enforce given branch string to all currently available packages. 6197 6198 @param branch: branch string to enforce 6199 @type branch: string 6200 """ 6201 with self.__write_mutex: 6202 self.cursor.execute('UPDATE baseinfo SET branch = (?)', (branch,)) 6203 self.commitChanges() 6204 self.clearCache()
6205
6206 - def alignDatabases(self, dbconn, force = False, output_header = " ", 6207 align_limit = 300):
6208 """ 6209 Align packages contained in foreign repository "dbconn" and this 6210 instance. 6211 6212 @param dbconn: foreign repository instance 6213 @type dbconn: entropy.db.EntropyRepository 6214 @keyword force: force alignment even if align_limit threshold is 6215 exceeded 6216 @type force: bool 6217 @keyword output_header: output header for printing purposes 6218 @type output_header: string 6219 @keyword align_limit: threshold within alignment is done if force is 6220 False 6221 @type align_limit: int 6222 @return: alignment status (0 = all good; 1 = dbs checksum not matching; 6223 -1 = nothing to do) 6224 @rtype: int 6225 """ 6226 added_ids, removed_ids = self.getIdpackagesDifferences( 6227 dbconn.listAllIdpackages()) 6228 6229 if not force: 6230 if len(added_ids) > align_limit: # too much hassle 6231 return 0 6232 if len(removed_ids) > align_limit: # too much hassle 6233 return 0 6234 6235 if not added_ids and not removed_ids: 6236 return -1 6237 6238 mytxt = red("%s, %s ...") % ( 6239 _("Syncing current database"), 6240 _("please wait"), 6241 ) 6242 self.updateProgress( 6243 mytxt, 6244 importance = 1, 6245 type = "info", 6246 header = output_header, 6247 back = True 6248 ) 6249 6250 maxcount = len(removed_ids) 6251 mycount = 0 6252 for idpackage in removed_ids: 6253 mycount += 1 6254 mytxt = "%s: %s" % ( 6255 red(_("Removing entry")), 6256 blue(str(self.retrieveAtom(idpackage))), 6257 ) 6258 self.updateProgress( 6259 mytxt, 6260 importance = 0, 6261 type = "info", 6262 header = output_header, 6263 back = True, 6264 count = (mycount, maxcount) 6265 ) 6266 6267 self.removePackage(idpackage, do_cleanup = False, do_commit = False) 6268 6269 maxcount = len(added_ids) 6270 mycount = 0 6271 for idpackage in added_ids: 6272 mycount += 1 6273 mytxt = "%s: %s" % ( 6274 red(_("Adding entry")), 6275 blue(str(dbconn.retrieveAtom(idpackage))), 6276 ) 6277 self.updateProgress( 6278 mytxt, 6279 importance = 0, 6280 type = "info", 6281 header = output_header, 6282 back = True, 6283 count = (mycount, maxcount) 6284 ) 6285 mydata = dbconn.getPackageData(idpackage, get_content = True, 6286 content_insert_formatted = True) 6287 self.addPackage( 6288 mydata, 6289 revision = mydata['revision'], 6290 idpackage = idpackage, 6291 do_commit = False, 6292 formatted_content = True 6293 ) 6294 6295 # do some cleanups 6296 self.doCleanups() 6297 # clear caches 6298 self.clearCache() 6299 self.commitChanges() 6300 self.generateReverseDependenciesMetadata(verbose = False) 6301 dbconn.clearCache() 6302 6303 # verify both checksums, if they don't match, bomb out 6304 mycheck = self.checksum(do_order = True, strict = False) 6305 outcheck = dbconn.checksum(do_order = True, strict = False) 6306 if mycheck == outcheck: 6307 return 1 6308 return 0
6309
6310 - def checkDatabaseApi(self):
6311 """ 6312 Check if repository EAPI (Entropy API) is not greater than the one 6313 that entropy.const ships. 6314 """ 6315 6316 dbapi = self.getApi() 6317 if int(dbapi) > int(etpConst['etpapi']): 6318 self.updateProgress( 6319 red(_("Repository EAPI > Entropy EAPI.")), 6320 importance = 1, 6321 type = "warning", 6322 header = " * ! * ! * ! * " 6323 ) 6324 self.updateProgress( 6325 red(_("Please update Equo/Entropy as soon as possible !")), 6326 importance = 1, 6327 type = "warning", 6328 header = " * ! * ! * ! * " 6329 )
6330
6331 - def doDatabaseImport(self, dumpfile, dbfile):
6332 """ 6333 Import SQLite3 dump file to this database. 6334 6335 @param dumpfile: SQLite3 dump file to read 6336 @type dumpfile: string 6337 @param dbfile: database file to write to 6338 @type dbfile: string 6339 @return: sqlite3 import return code 6340 @rtype: int 6341 @todo: remove /usr/bin/sqlite3 dependency 6342 """ 6343 import subprocess 6344 sqlite3_exec = "/usr/bin/sqlite3 %s < %s" % (dbfile, dumpfile,) 6345 retcode = subprocess.call(sqlite3_exec, shell = True) 6346 return retcode
6347
6348 - def doDatabaseExport(self, dumpfile, gentle_with_tables = True, 6349 exclude_tables = None):
6350 """ 6351 Export running SQLite3 database to file. 6352 6353 @param dumpfile: dump file object to write to 6354 @type dumpfile: file object (hint: open()) 6355 @keyword gentle_with_tables: append "IF NOT EXISTS" to "CREATE TABLE" 6356 statements 6357 @type gentle_with_tables: bool 6358 @todo: when Python 2.6, look ad Connection.iterdump and replace this :) 6359 """ 6360 if not exclude_tables: 6361 exclude_tables = [] 6362 6363 toraw = const_convert_to_rawstring 6364 6365 dumpfile.write(toraw("BEGIN TRANSACTION;\n")) 6366 self.cursor.execute(""" 6367 SELECT name, type, sql FROM sqlite_master 6368 WHERE sql NOT NULL AND type=='table' 6369 """) 6370 for name, x, sql in self.cursor.fetchall(): 6371 6372 self.updateProgress( 6373 red("%s " % ( 6374 _("Exporting database table"), 6375 ) ) + "["+blue(str(name))+"]", 6376 importance = 0, 6377 type = "info", 6378 back = True, 6379 header = " " 6380 ) 6381 6382 if name == "sqlite_sequence": 6383 dumpfile.write(toraw("DELETE FROM sqlite_sequence;\n")) 6384 elif name == "sqlite_stat1": 6385 dumpfile.write(toraw("ANALYZE sqlite_master;\n")) 6386 elif name.startswith("sqlite_"): 6387 continue 6388 else: 6389 t_cmd = "CREATE TABLE" 6390 if sql.startswith(t_cmd) and gentle_with_tables: 6391 sql = "CREATE TABLE IF NOT EXISTS"+sql[len(t_cmd):] 6392 dumpfile.write(toraw("%s;\n" % sql)) 6393 6394 if name in exclude_tables: 6395 continue 6396 6397 self.cursor.execute("PRAGMA table_info('%s')" % name) 6398 cols = [r[1] for r in self.cursor.fetchall()] 6399 q = "SELECT 'INSERT INTO \"%(tbl_name)s\" VALUES(" 6400 q += ", ".join(["'||quote(" + x + ")||'" for x in cols]) 6401 q += ")' FROM '%(tbl_name)s'" 6402 self.cursor.execute(q % {'tbl_name': name}) 6403 self.connection.text_factory = lambda x: \ 6404 const_convert_to_unicode(x) 6405 for row in self.cursor: 6406 dumpfile.write(toraw("%s;\n" % (row[0],))) 6407 6408 self.cursor.execute(""" 6409 SELECT name, type, sql FROM sqlite_master 6410 WHERE sql NOT NULL AND type!='table' AND type!='meta' 6411 """) 6412 for name, x, sql in self.cursor.fetchall(): 6413 dumpfile.write(toraw("%s;\n" % sql)) 6414 6415 dumpfile.write(toraw("COMMIT;\n")) 6416 try: 6417 dumpfile.flush() 6418 except: 6419 pass 6420 self.updateProgress( 6421 red(_("Database Export complete.")), 6422 importance = 0, 6423 type = "info", 6424 header = " " 6425 )
6426 # remember to close the file 6427
6428 - def listAllTables(self):
6429 """ 6430 List all available tables in this repository database. 6431 6432 @return: available tables 6433 @rtype: list 6434 """ 6435 cur = self.cursor.execute(""" 6436 SELECT name FROM SQLITE_MASTER WHERE type = "table" 6437 """) 6438 return self._cur2list(cur)
6439
6440 - def _doesTableExist(self, table):
6441 6442 # speed up a bit if we already reported a column as existing 6443 c_tup = ("_doesTableExist", table,) 6444 cached = self.live_cache.get(c_tup) 6445 if cached is not None: 6446 return cached 6447 6448 cur = self.cursor.execute(""" 6449 select name from SQLITE_MASTER where type = "table" and name = (?) 6450 LIMIT 1 6451 """, (table,)) 6452 rslt = cur.fetchone() 6453 exists = rslt is not None 6454 if exists: 6455 self.live_cache[c_tup] = True 6456 return exists
6457
6458 - def _doesColumnInTableExist(self, table, column):
6459 6460 # speed up a bit if we already reported a column as existing 6461 c_tup = ("_doesColumnInTableExist", table, column,) 6462 cached = self.live_cache.get(c_tup) 6463 if cached is not None: 6464 return cached 6465 6466 cur = self.cursor.execute('PRAGMA table_info( %s )' % (table,)) 6467 rslt = (x[1] for x in cur.fetchall()) 6468 if column in rslt: 6469 self.live_cache[c_tup] = True 6470 return True 6471 return False
6472
6473 - def checksum(self, do_order = False, strict = True, 6474 strings = False):
6475 """ 6476 Get Repository metadata checksum, useful for integrity verification. 6477 Note: result is cached in EntropyRepository.live_cache (dict). 6478 6479 @keyword do_order: order metadata collection alphabetically 6480 @type do_order: bool 6481 @keyword strict: improve checksum accuracy 6482 @type strict: bool 6483 @keyword strings: return checksum in md5 hex form 6484 @type strings: bool 6485 @return: repository checksum 6486 @rtype: string 6487 """ 6488 6489 c_tup = ("checksum", do_order, strict, strings,) 6490 cache = self.live_cache.get(c_tup) 6491 if cache is not None: 6492 return cache 6493 6494 idpackage_order = '' 6495 category_order = '' 6496 license_order = '' 6497 flags_order = '' 6498 if do_order: 6499 idpackage_order = 'order by idpackage' 6500 category_order = 'order by category' 6501 license_order = 'order by license' 6502 flags_order = 'order by chost' 6503 6504 def do_update_md5(m, cursor): 6505 mydata = cursor.fetchall() 6506 for record in mydata: 6507 for item in record: 6508 m.update(const_convert_to_rawstring(item))
6509 6510 if strings: 6511 import hashlib 6512 m = hashlib.md5() 6513 6514 6515 cur = self.cursor.execute(""" 6516 SELECT idpackage,atom,name,version,versiontag, 6517 revision,branch,slot,etpapi,trigger FROM 6518 baseinfo %s""" % (idpackage_order,)) 6519 if strings: 6520 do_update_md5(m, cur) 6521 else: 6522 a_hash = hash(tuple(cur.fetchall())) 6523 6524 6525 cur = self.cursor.execute(""" 6526 SELECT idpackage, description, homepage, 6527 download, size, digest, datecreation FROM 6528 extrainfo %s""" % (idpackage_order,)) 6529 if strings: 6530 do_update_md5(m, cur) 6531 else: 6532 b_hash = hash(tuple(cur.fetchall())) 6533 6534 6535 cur = self.cursor.execute(""" 6536 SELECT category FROM categories %s 6537 """ % (category_order,)) 6538 if strings: 6539 do_update_md5(m, cur) 6540 else: 6541 c_hash = hash(tuple(cur.fetchall())) 6542 6543 6544 d_hash = '0' 6545 e_hash = '0' 6546 if strict: 6547 cur = self.cursor.execute(""" 6548 SELECT * FROM licenses %s""" % (license_order,)) 6549 if strings: 6550 do_update_md5(m, cur) 6551 else: 6552 d_hash = hash(tuple(cur.fetchall())) 6553 6554 cur = self.cursor.execute('select * from flags %s' % (flags_order,)) 6555 if strings: 6556 do_update_md5(m, cur) 6557 else: 6558 e_hash = hash(tuple(cur.fetchall())) 6559 6560 if strings: 6561 result = m.hexdigest() 6562 else: 6563 result = "%s:%s:%s:%s:%s" % (a_hash, b_hash, c_hash, d_hash, 6564 e_hash,) 6565 6566 self.live_cache[c_tup] = result[:] 6567 return result 6568 6569
6570 - def storeInstalledPackage(self, idpackage, repoid, source = 0):
6571 """ 6572 Note: this is used by installed packages repository (also known as 6573 client db). 6574 Add package identifier to the "installed packages table", 6575 which contains repository identifier from where package has been 6576 installed and its install request source (user, pulled in 6577 dependency, etc). 6578 6579 @param idpackage: package indentifier 6580 @type idpackage: int 6581 @param repoid: repository identifier 6582 @type repoid: string 6583 @param source: source identifier (pleas see: 6584 etpConst['install_sources']) 6585 @type source: int 6586 """ 6587 with self.__write_mutex: 6588 self.cursor.execute('INSERT into installedtable VALUES (?,?,?)', 6589 (idpackage, repoid, source,))
6590
6591 - def getInstalledPackageRepository(self, idpackage):
6592 """ 6593 Note: this is used by installed packages repository (also known as 6594 client db). 6595 Return repository identifier stored inside the "installed packages 6596 table". 6597 6598 @param idpackage: package indentifier 6599 @type idpackage: int 6600 @return: repository identifier 6601 @rtype: string or None 6602 """ 6603 with self.__write_mutex: 6604 try: 6605 cur = self.cursor.execute(""" 6606 SELECT repositoryname FROM installedtable 6607 WHERE idpackage = (?) LIMIT 1""", (idpackage,)) 6608 return cur.fetchone()[0] 6609 except (self.dbapi2.OperationalError, TypeError,): 6610 return None
6611
6612 - def dropInstalledPackageFromStore(self, idpackage):
6613 """ 6614 Note: this is used by installed packages repository (also known as 6615 client db). 6616 Remove installed package metadata from "installed packages table". 6617 Note: this just removes extra metadata information such as repository 6618 identifier from where package has been installed and its install 6619 request source (user, pulled in dependency, etc). 6620 This method DOES NOT remove package from repository (see 6621 removePackage() instead). 6622 6623 @param idpackage: package indentifier 6624 @type idpackage: int 6625 """ 6626 with self.__write_mutex: 6627 self.cursor.execute(""" 6628 DELETE FROM installedtable 6629 WHERE idpackage = (?)""", (idpackage,))
6630
6631 - def _removePackageFromDependsTable(self, idpackage):
6632 with self.__write_mutex: 6633 try: 6634 self.cursor.execute(""" 6635 DELETE FROM dependstable WHERE idpackage = (?) 6636 """, (idpackage,)) 6637 return 0 6638 except (self.dbapi2.OperationalError,): 6639 return 1 # need reinit
6640
6641 - def _createDependsTable(self):
6642 with self.__write_mutex: 6643 self.cursor.executescript(""" 6644 CREATE TABLE IF NOT EXISTS dependstable 6645 ( iddependency INTEGER PRIMARY KEY, idpackage INTEGER, 6646 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE ); 6647 INSERT INTO dependstable VALUES (-1,NULL); 6648 """) 6649 if self.indexing: 6650 self.cursor.execute(""" 6651 CREATE INDEX IF NOT EXISTS dependsindex_idpackage 6652 ON dependstable ( idpackage ) 6653 """) 6654 self.commitChanges()
6655
6656 - def _sanitizeDependsTable(self):
6657 with self.__write_mutex: 6658 self.cursor.execute(""" 6659 DELETE FROM dependstable where iddependency = -1 6660 """) 6661 self.commitChanges()
6662
6663 - def _isDependsTableSane(self):
6664 try: 6665 cur = self.cursor.execute(""" 6666 SELECT iddependency FROM dependstable WHERE iddependency = -1 6667 """) 6668 except (self.dbapi2.OperationalError,): 6669 return False # table does not exist, please regenerate and re-run 6670 6671 status = cur.fetchone() 6672 if status: 6673 return False 6674 6675 cur = self.cursor.execute("SELECT count(*) FROM dependstable") 6676 try: 6677 dependstable_count = cur.fetchone()[0] 6678 except IndexError: 6679 dependstable_count = 0 6680 if dependstable_count < 2: 6681 return False 6682 return True
6683
6684 - def storeXpakMetadata(self, idpackage, blob):
6685 """ 6686 Xpak metadata is Source Package Manager package metadata. 6687 This method stores such metadata inside repository. 6688 6689 @param idpackage: package indentifier 6690 @type idpackage: int 6691 @param blob: metadata blob 6692 @type blob: string or buffer 6693 """ 6694 with self.__write_mutex: 6695 self.cursor.execute('INSERT into xpakdata VALUES (?,?)', 6696 (int(idpackage), const_get_buffer()(blob),) 6697 ) 6698 self.commitChanges()
6699
6700 - def retrieveXpakMetadata(self, idpackage):
6701 """ 6702 Xpak metadata is Source Package Manager package metadata. 6703 This method returns such stored metadata inside repository. 6704 6705 @param idpackage: package indentifier 6706 @type idpackage: int 6707 @return: stored metadata 6708 @rtype: buffer 6709 """ 6710 try: 6711 cur = self.cursor.execute(""" 6712 SELECT data from xpakdata where idpackage = (?) LIMIT 1 6713 """, (idpackage,)) 6714 mydata = cur.fetchone() 6715 if not mydata: 6716 return "" 6717 return mydata[0] 6718 except (self.dbapi2.Error, TypeError, IndexError,): 6719 return ""
6720
6721 - def retrieveBranchMigration(self, to_branch):
6722 """ 6723 This method returns branch migration metadata stored in Entropy 6724 Client database (installed packages database). It is used to 6725 determine whether to run per-repository branch migration scripts. 6726 6727 @param to_branch: usually the current branch string 6728 @type to_branch: string 6729 @return: branch migration metadata contained in database 6730 @rtype: dict 6731 """ 6732 if not self._doesTableExist('entropy_branch_migration'): 6733 return {} 6734 6735 cur = self.cursor.execute(""" 6736 SELECT repository, from_branch, post_migration_md5sum, 6737 post_upgrade_md5sum FROM entropy_branch_migration WHERE to_branch = (?) 6738 """, (to_branch,)) 6739 6740 data = cur.fetchall() 6741 meta = {} 6742 for repo, from_branch, post_migration_md5, post_upgrade_md5 in data: 6743 obj = meta.setdefault(repo, {}) 6744 obj[from_branch] = (post_migration_md5, post_upgrade_md5,) 6745 return meta
6746
6747 - def dropContent(self):
6748 """ 6749 Drop all "content" metadata from repository, usually a memory hog. 6750 Content metadata contains files and directories owned by packages. 6751 """ 6752 with self.__write_mutex: 6753 self.cursor.execute('DELETE FROM content')
6754
6755 - def dropAllIndexes(self):
6756 """ 6757 Drop all repository metadata indexes. 6758 """ 6759 cur = self.cursor.execute(""" 6760 SELECT name FROM SQLITE_MASTER WHERE type = "index" 6761 """) 6762 indexes = self._cur2set(cur) 6763 with self.__write_mutex: 6764 for index in indexes: 6765 try: 6766 self.cursor.execute('DROP INDEX IF EXISTS %s' % (index,)) 6767 except self.dbapi2.Error: 6768 continue
6769
6770 - def listAllIndexes(self, only_entropy = True):
6771 """ 6772 List all the available repository metadata index names. 6773 6774 @keyword only_entropy: if True, return only entropy related indexes 6775 @type only_entropy: bool 6776 @return: list (set) of index names 6777 @rtype: set 6778 """ 6779 cur = self.cursor.execute(""" 6780 SELECT name FROM SQLITE_MASTER WHERE type = "index" 6781 """) 6782 indexes = self._cur2set(cur) 6783 6784 if not only_entropy: 6785 return indexes 6786 return set([x for x in indexes if not x.startswith("sqlite")])
6787
6788 - def createAllIndexes(self):
6789 """ 6790 Create all the repository metadata indexes internally available. 6791 """ 6792 self._createMirrorlinksIndex() 6793 self._createContentIndex() 6794 self._createBaseinfoIndex() 6795 self._createKeywordsIndex() 6796 self._createDependenciesIndex() 6797 self._createProvideIndex() 6798 self._createConflictsIndex() 6799 self._createExtrainfoIndex() 6800 self._createNeededIndex() 6801 self._createUseflagsIndex() 6802 self._createLicensedataIndex() 6803 self._createLicensesIndex() 6804 self._createConfigProtectReferenceIndex() 6805 self._createMessagesIndex() 6806 self._createSourcesIndex() 6807 self._createCountersIndex() 6808 self._createEclassesIndex() 6809 self._createCategoriesIndex() 6810 self._createCompileFlagsIndex() 6811 self._createPackagesetsIndex() 6812 self._createAutomergefilesIndex() 6813 self._createProvidedLibsIndex()
6814
6815 - def _createMirrorlinksIndex(self):
6816 if self.indexing: 6817 with self.__write_mutex: 6818 self.cursor.execute(""" 6819 CREATE INDEX IF NOT EXISTS mirrorlinks_mirrorname 6820 ON mirrorlinks ( mirrorname )""")
6821
6822 - def _createPackagesetsIndex(self):
6823 if self.indexing: 6824 with self.__write_mutex: 6825 try: 6826 self.cursor.execute(""" 6827 CREATE INDEX IF NOT EXISTS packagesetsindex 6828 ON packagesets ( setname )""") 6829 except self.dbapi2.OperationalError: 6830 pass
6831
6832 - def _createProvidedLibsIndex(self):
6833 if self.indexing: 6834 with self.__write_mutex: 6835 try: 6836 self.cursor.executescript(""" 6837 CREATE INDEX IF NOT EXISTS provided_libs_library 6838 ON provided_libs ( library ); 6839 CREATE INDEX IF NOT EXISTS provided_libs_idpackage 6840 ON provided_libs ( idpackage ); 6841 CREATE INDEX IF NOT EXISTS provided_libs_lib_elf 6842 ON provided_libs ( library, elfclass ); 6843 """) 6844 except self.dbapi2.OperationalError: 6845 pass
6846
6847 - def _createAutomergefilesIndex(self):
6848 if self.indexing: 6849 with self.__write_mutex: 6850 try: 6851 self.cursor.executescript(""" 6852 CREATE INDEX IF NOT EXISTS automergefiles_idpackage 6853 ON automergefiles ( idpackage ); 6854 CREATE INDEX IF NOT EXISTS automergefiles_file_md5 6855 ON automergefiles ( configfile, md5 ); 6856 """) 6857 except self.dbapi2.OperationalError: 6858 pass
6859
6860 - def _createNeededIndex(self):
6861 if self.indexing: 6862 with self.__write_mutex: 6863 self.cursor.executescript(""" 6864 CREATE INDEX IF NOT EXISTS neededindex ON neededreference 6865 ( library ); 6866 CREATE INDEX IF NOT EXISTS neededindex_idneeded ON needed 6867 ( idneeded ); 6868 CREATE INDEX IF NOT EXISTS neededindex_idpackage ON needed 6869 ( idpackage ); 6870 CREATE INDEX IF NOT EXISTS neededindex_elfclass ON needed 6871 ( elfclass ); 6872 """)
6873
6874 - def _createMessagesIndex(self):
6875 if self.indexing: 6876 with self.__write_mutex: 6877 self.cursor.execute(""" 6878 CREATE INDEX IF NOT EXISTS messagesindex ON messages 6879 ( idpackage ) 6880 """)
6881
6882 - def _createCompileFlagsIndex(self):
6883 if self.indexing: 6884 with self.__write_mutex: 6885 self.cursor.execute(""" 6886 CREATE INDEX IF NOT EXISTS flagsindex ON flags 6887 ( chost, cflags, cxxflags ) 6888 """)
6889
6890 - def _createUseflagsIndex(self):
6891 if self.indexing: 6892 with self.__write_mutex: 6893 self.cursor.executescript(""" 6894 CREATE INDEX IF NOT EXISTS useflagsindex_useflags_idpackage 6895 ON useflags ( idpackage ); 6896 CREATE INDEX IF NOT EXISTS useflagsindex_useflags_idflag 6897 ON useflags ( idflag ); 6898 CREATE INDEX IF NOT EXISTS useflagsindex 6899 ON useflagsreference ( flagname ); 6900 """)
6901
6902 - def _createContentIndex(self):
6903 if self.indexing: 6904 with self.__write_mutex: 6905 if self._doesTableExist("content"): 6906 self.cursor.executescript(""" 6907 CREATE INDEX IF NOT EXISTS contentindex_couple 6908 ON content ( idpackage ); 6909 CREATE INDEX IF NOT EXISTS contentindex_file 6910 ON content ( file ); 6911 """)
6912
6913 - def _createConfigProtectReferenceIndex(self):
6914 if self.indexing: 6915 with self.__write_mutex: 6916 self.cursor.execute(""" 6917 CREATE INDEX IF NOT EXISTS configprotectreferenceindex 6918 ON configprotectreference ( protect ) 6919 """)
6920
6921 - def _createBaseinfoIndex(self):
6922 if self.indexing: 6923 with self.__write_mutex: 6924 self.cursor.executescript(""" 6925 CREATE INDEX IF NOT EXISTS baseindex_atom 6926 ON baseinfo ( atom ); 6927 CREATE INDEX IF NOT EXISTS baseindex_branch_name 6928 ON baseinfo ( name,branch ); 6929 CREATE INDEX IF NOT EXISTS baseindex_branch_name_idcategory 6930 ON baseinfo ( name,idcategory,branch ); 6931 CREATE INDEX IF NOT EXISTS baseindex_idcategory 6932 ON baseinfo ( idcategory ); 6933 """)
6934
6935 - def _createLicensedataIndex(self):
6936 if self.indexing: 6937 with self.__write_mutex: 6938 self.cursor.execute(""" 6939 CREATE INDEX IF NOT EXISTS licensedataindex 6940 ON licensedata ( licensename ) 6941 """)
6942
6943 - def _createLicensesIndex(self):
6944 if self.indexing: 6945 with self.__write_mutex: 6946 self.cursor.execute(""" 6947 CREATE INDEX IF NOT EXISTS licensesindex ON licenses ( license ) 6948 """)
6949
6950 - def _createCategoriesIndex(self):
6951 if self.indexing: 6952 with self.__write_mutex: 6953 self.cursor.execute(""" 6954 CREATE INDEX IF NOT EXISTS categoriesindex_category 6955 ON categories ( category ) 6956 """)
6957
6958 - def _createKeywordsIndex(self):
6959 if self.indexing: 6960 with self.__write_mutex: 6961 self.cursor.executescript(""" 6962 CREATE INDEX IF NOT EXISTS keywordsreferenceindex 6963 ON keywordsreference ( keywordname ); 6964 CREATE INDEX IF NOT EXISTS keywordsindex_idpackage 6965 ON keywords ( idpackage ); 6966 CREATE INDEX IF NOT EXISTS keywordsindex_idkeyword 6967 ON keywords ( idkeyword ); 6968 """)
6969
6970 - def _createDependenciesIndex(self):
6971 if self.indexing: 6972 with self.__write_mutex: 6973 self.cursor.executescript(""" 6974 CREATE INDEX IF NOT EXISTS dependenciesindex_idpackage 6975 ON dependencies ( idpackage ); 6976 CREATE INDEX IF NOT EXISTS dependenciesindex_iddependency 6977 ON dependencies ( iddependency ); 6978 CREATE INDEX IF NOT EXISTS dependenciesreferenceindex_dependency 6979 ON dependenciesreference ( dependency ); 6980 """)
6981
6982 - def _createCountersIndex(self):
6983 if self.indexing: 6984 with self.__write_mutex: 6985 self.cursor.executescript(""" 6986 CREATE INDEX IF NOT EXISTS countersindex_idpackage 6987 ON counters ( idpackage ); 6988 CREATE INDEX IF NOT EXISTS countersindex_counter 6989 ON counters ( counter ); 6990 """)
6991
6992 - def _createSourcesIndex(self):
6993 if self.indexing: 6994 with self.__write_mutex: 6995 self.cursor.executescript(""" 6996 CREATE INDEX IF NOT EXISTS sourcesindex_idpackage 6997 ON sources ( idpackage ); 6998 CREATE INDEX IF NOT EXISTS sourcesindex_idsource 6999 ON sources ( idsource ); 7000 CREATE INDEX IF NOT EXISTS sourcesreferenceindex_source 7001 ON sourcesreference ( source ); 7002 """)
7003
7004 - def _createProvideIndex(self):
7005 if self.indexing: 7006 with self.__write_mutex: 7007 self.cursor.executescript(""" 7008 CREATE INDEX IF NOT EXISTS provideindex_idpackage 7009 ON provide ( idpackage ); 7010 CREATE INDEX IF NOT EXISTS provideindex_atom 7011 ON provide ( atom ); 7012 """)
7013
7014 - def _createConflictsIndex(self):
7015 if self.indexing: 7016 with self.__write_mutex: 7017 self.cursor.executescript(""" 7018 CREATE INDEX IF NOT EXISTS conflictsindex_idpackage 7019 ON conflicts ( idpackage ); 7020 CREATE INDEX IF NOT EXISTS conflictsindex_atom 7021 ON conflicts ( conflict ); 7022 """)
7023
7024 - def _createExtrainfoIndex(self):
7025 if self.indexing: 7026 with self.__write_mutex: 7027 self.cursor.executescript(""" 7028 CREATE INDEX IF NOT EXISTS extrainfoindex 7029 ON extrainfo ( description ); 7030 CREATE INDEX IF NOT EXISTS extrainfoindex_pkgindex 7031 ON extrainfo ( idpackage ); 7032 """)
7033
7034 - def _createEclassesIndex(self):
7035 if self.indexing: 7036 with self.__write_mutex: 7037 self.cursor.executescript(""" 7038 CREATE INDEX IF NOT EXISTS eclassesindex_idpackage 7039 ON eclasses ( idpackage ); 7040 CREATE INDEX IF NOT EXISTS eclassesindex_idclass 7041 ON eclasses ( idclass ); 7042 CREATE INDEX IF NOT EXISTS eclassesreferenceindex_classname 7043 ON eclassesreference ( classname ); 7044 """)
7045
7046 - def dropContentIndex(self, only_file = False):
7047 """ 7048 Drop "content" metadata index. 7049 7050 @keyword only_file: drop only "file" index 7051 @type only_file: bool 7052 """ 7053 with self.__write_mutex: 7054 self.cursor.execute("DROP INDEX IF EXISTS contentindex_file") 7055 if not only_file: 7056 self.cursor.executescript(""" 7057 DROP INDEX IF EXISTS contentindex_couple; 7058 """)
7059
7060 - def regenerateSpmUidTable(self, verbose = False):
7061 """ 7062 Regenerate Source Package Manager package identifiers table. 7063 This method will use the Source Package Manger interface. 7064 7065 @keyword verbose: run in verbose mode 7066 @type verbose: bool 7067 """ 7068 7069 # Poll SPM, load variables 7070 spm = get_spm(self) 7071 7072 # this is necessary now, counters table should be empty 7073 with self.__write_mutex: 7074 7075 self.cursor.executescript(""" 7076 DROP TABLE IF EXISTS counters_regen; 7077 CREATE TEMPORARY TABLE counters_regen ( 7078 counter INTEGER, 7079 idpackage INTEGER, 7080 branch VARCHAR, 7081 PRIMARY KEY(idpackage, branch) 7082 ); 7083 """) 7084 insert_data = [] 7085 for myid in self.listAllIdpackages(): 7086 7087 try: 7088 spm_uid = spm.resolve_package_uid(self, myid) 7089 except SPMError as err: 7090 if verbose: 7091 mytxt = "%s: %s: %s" % ( 7092 bold(_("ATTENTION")), 7093 red(_("Spm error occured")), 7094 str(err), 7095 ) 7096 self.updateProgress( 7097 mytxt, 7098 importance = 1, 7099 type = "warning" 7100 ) 7101 continue 7102 7103 if spm_uid is None: 7104 if verbose: 7105 mytxt = "%s: %s: %s" % ( 7106 bold(_("ATTENTION")), 7107 red(_("Spm Unique Identifier not found for")), 7108 self.retrieveAtom(myid), 7109 ) 7110 self.updateProgress( 7111 mytxt, 7112 importance = 1, 7113 type = "warning" 7114 ) 7115 continue 7116 7117 mybranch = self.retrieveBranch(myid) 7118 insert_data.append((spm_uid, myid, mybranch)) 7119 7120 self.cursor.executemany(""" 7121 INSERT OR REPLACE into counters_regen VALUES (?,?,?) 7122 """, insert_data) 7123 7124 self.cursor.executescript(""" 7125 DELETE FROM counters; 7126 INSERT INTO counters (counter, idpackage, branch) 7127 SELECT counter, idpackage, branch FROM counters_regen; 7128 """) 7129 7130 self.commitChanges()
7131
7132 - def clearTreeupdatesEntries(self, repository):
7133 """ 7134 This method should be considered internal and not suited for general 7135 audience. Clear "treeupdates" metadata for given repository identifier. 7136 7137 @param repository: repository identifier 7138 @type repository: string 7139 """ 7140 with self.__write_mutex: 7141 self.cursor.execute(""" 7142 DELETE FROM treeupdates WHERE repository = (?) 7143 """, (repository,)) 7144 self.commitChanges()
7145
7146 - def resetTreeupdatesDigests(self):
7147 """ 7148 This method should be considered internal and not suited for general 7149 audience. Reset "treeupdates" digest metadata. 7150 """ 7151 with self.__write_mutex: 7152 self.cursor.execute('UPDATE treeupdates SET digest = "-1"') 7153 self.commitChanges()
7154
7155 - def _foreignKeySupport(self):
7156 7157 # TODO: remove this by 2011/12/31 7158 7159 tables = ("extrainfo", "dependencies" ,"provide", 7160 "conflicts", "configprotect", "configprotectmask", "sources", 7161 "useflags", "keywords", "content", "messages", "counters", "sizes", 7162 "eclasses", "needed", "triggers", "systempackages", "injected", 7163 "installedtable", "automergefiles", "packagesignatures", 7164 "packagespmphases", "provided_libs", "dependstable" 7165 ) 7166 7167 done_something = False 7168 for table in tables: 7169 if not self._doesTableExist(table): # wtf 7170 continue 7171 7172 cur = self.cursor.execute("PRAGMA foreign_key_list(%s)" % (table,)) 7173 foreign_keys = cur.fetchone() 7174 7175 # print table, "foreign keys", foreign_keys 7176 if foreign_keys is not None: 7177 continue 7178 7179 done_something = True 7180 # need to add foreign key to this table 7181 cur = self.cursor.execute("""SELECT sql FROM sqlite_master 7182 WHERE type='table' and name = (?)""", (table,)) 7183 cur_sql = cur.fetchone()[0] 7184 7185 # change table name 7186 tmp_table = table+"_fk_sup" 7187 self.cursor.execute("DROP TABLE IF EXISTS %s" % (tmp_table,)) 7188 7189 bracket_idx = cur_sql.find("(") 7190 cur_sql = cur_sql[bracket_idx:] 7191 cur_sql = "CREATE TABLE %s %s" % (tmp_table, cur_sql) 7192 7193 # remove final parenthesis and strip 7194 cur_sql = cur_sql[:-1].strip() 7195 # add foreign key stmt 7196 cur_sql += """, 7197 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE );""" 7198 self.cursor.executescript(cur_sql) 7199 self._moveContent(table, tmp_table) 7200 self._atomicRename(tmp_table, table) 7201 7202 if done_something: 7203 self.cursor.execute(""" 7204 INSERT OR REPLACE INTO settings 7205 VALUES ("on_delete_cascade", "1") 7206 """)
7207
7208 - def _moveContent(self, from_table, to_table):
7209 self.cursor.execute(""" 7210 INSERT INTO %s SELECT * FROM %s 7211 """ % (to_table, from_table,))
7212
7213 - def _atomicRename(self, from_table, to_table):
7214 self.cursor.executescript(""" 7215 BEGIN TRANSACTION; 7216 DROP TABLE IF EXISTS %s; 7217 ALTER TABLE %s RENAME TO %s; 7218 COMMIT; 7219 """ % (to_table, from_table, to_table,))
7220
7221 - def _migrateCountersTable(self):
7222 with self.__write_mutex: 7223 self.cursor.executescript(""" 7224 DROP TABLE IF EXISTS counterstemp; 7225 CREATE TABLE counterstemp ( 7226 counter INTEGER, idpackage INTEGER, branch VARCHAR, 7227 PRIMARY KEY(idpackage,branch), 7228 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 7229 ); 7230 INSERT INTO counterstemp (counter, idpackage, branch) 7231 SELECT counter, idpackage, branch FROM counters; 7232 DROP TABLE counters; 7233 ALTER TABLE counterstemp RENAME TO counters; 7234 """) 7235 self.commitChanges()
7236
7237 - def _createSettingsTable(self):
7238 with self.__write_mutex: 7239 self.cursor.executescript(""" 7240 CREATE TABLE settings ( 7241 setting_name VARCHAR, 7242 setting_value VARCHAR, 7243 PRIMARY KEY(setting_name) 7244 ); 7245 """) 7246 self._setupInitialSettings()
7247
7248 - def _createProvidedLibs(self):
7249 7250 def do_create(): 7251 self.cursor.executescript(""" 7252 CREATE TABLE provided_libs ( 7253 idpackage INTEGER, 7254 library VARCHAR, 7255 path VARCHAR, 7256 elfclass INTEGER, 7257 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 7258 ); 7259 """)
7260 7261 # TODO: this is going to be removed soon 7262 client_repo = self.get_plugins_metadata().get('client_repo') 7263 with self.__write_mutex: 7264 7265 if client_repo and (self.dbname != etpConst['clientdbid']): 7266 return do_create() 7267 7268 mytxt = "%s: %s" % ( 7269 bold(_("ATTENTION")), 7270 red(_("generating provided_libs metadata, please wait!")), 7271 ) 7272 self.updateProgress( 7273 mytxt, 7274 importance = 1, 7275 type = "warning" 7276 ) 7277 7278 try: 7279 self._generateProvidedLibsMetadata() 7280 except (IOError, OSError, self.dbapi2.Error) as err: 7281 mytxt = "%s: %s: [%s]" % ( 7282 bold(_("ATTENTION")), 7283 red("cannot generate provided_libs metadata"), 7284 err, 7285 ) 7286 self.updateProgress( 7287 mytxt, 7288 importance = 1, 7289 type = "warning" 7290 ) 7291 do_create() 7292 7293
7294 - def _generateProvidedLibsMetadata(self):
7295 7296 def collect_provided(pkg_dir, content): 7297 7298 provided_libs = set() 7299 ldpaths = self.entropyTools.collect_linker_paths() 7300 for obj, ftype in list(content.items()): 7301 7302 if ftype == "dir": 7303 continue 7304 obj_dir, obj_name = os.path.split(obj) 7305 7306 if obj_dir not in ldpaths: 7307 continue 7308 7309 unpack_obj = os.path.join(pkg_dir, obj) 7310 try: 7311 os.stat(unpack_obj) 7312 except OSError: 7313 continue 7314 7315 # do not trust ftype 7316 if os.path.isdir(unpack_obj): 7317 continue 7318 if not self.entropyTools.is_elf_file(unpack_obj): 7319 continue 7320 7321 elf_class = self.entropyTools.read_elf_class(unpack_obj) 7322 provided_libs.add((obj_name, obj, elf_class,)) 7323 7324 return provided_libs
7325 7326 self.cursor.executescript(""" 7327 DROP TABLE IF EXISTS provided_libs_tmp; 7328 CREATE TABLE provided_libs_tmp ( 7329 idpackage INTEGER, 7330 library VARCHAR, 7331 path VARCHAR, 7332 elfclass INTEGER, 7333 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 7334 ); 7335 """) 7336 7337 pkgs = self.listAllIdpackages() 7338 for idpackage in pkgs: 7339 7340 content = self.retrieveContent(idpackage, extended = True, 7341 formatted = True) 7342 provided_libs = collect_provided(etpConst['systemroot'], content) 7343 7344 self.cursor.executemany(""" 7345 INSERT INTO provided_libs_tmp VALUES (?,?,?,?) 7346 """, [(idpackage, x, y, z,) for x, y, z in provided_libs]) 7347 7348 # rename 7349 self.cursor.execute(""" 7350 ALTER TABLE provided_libs_tmp RENAME TO provided_libs; 7351 """) 7352
7353 - def _createProvideDefault(self):
7354 self.cursor.execute(""" 7355 ALTER TABLE provide ADD COLUMN is_default INTEGER DEFAULT 0 7356 """)
7357
7358 - def _createInstalledTableSource(self):
7359 with self.__write_mutex: 7360 self.cursor.execute(""" 7361 ALTER TABLE installedtable ADD source INTEGER; 7362 """) 7363 self.cursor.execute(""" 7364 UPDATE installedtable SET source = (?) 7365 """, (etpConst['install_sources']['unknown'],))
7366
7367 - def _createPackagechangelogsTable(self):
7368 with self.__write_mutex: 7369 self.cursor.execute(""" 7370 CREATE TABLE packagechangelogs ( category VARCHAR, 7371 name VARCHAR, changelog BLOB, PRIMARY KEY (category, name)); 7372 """)
7373
7374 - def _createAutomergefilesTable(self):
7375 with self.__write_mutex: 7376 self.cursor.execute(""" 7377 CREATE TABLE automergefiles ( idpackage INTEGER, 7378 configfile VARCHAR, md5 VARCHAR, 7379 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE ); 7380 """)
7381
7382 - def _createPackagesignaturesTable(self):
7383 with self.__write_mutex: 7384 self.cursor.execute(""" 7385 CREATE TABLE packagesignatures ( 7386 idpackage INTEGER PRIMARY KEY, 7387 sha1 VARCHAR, 7388 sha256 VARCHAR, 7389 sha512 VARCHAR, 7390 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE ); 7391 """)
7392
7393 - def _createPackagespmphases(self):
7394 with self.__write_mutex: 7395 self.cursor.execute(""" 7396 CREATE TABLE packagespmphases ( 7397 idpackage INTEGER PRIMARY KEY, 7398 phases VARCHAR, 7399 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 7400 ); 7401 """)
7402
7403 - def _createPackagespmrepository(self):
7404 with self.__write_mutex: 7405 self.cursor.execute(""" 7406 CREATE TABLE packagespmrepository ( 7407 idpackage INTEGER PRIMARY KEY, 7408 repository VARCHAR, 7409 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE 7410 ); 7411 """)
7412
7413 - def _createEntropyBranchMigrationTable(self):
7414 with self.__write_mutex: 7415 self.cursor.execute(""" 7416 CREATE TABLE entropy_branch_migration ( 7417 repository VARCHAR, 7418 from_branch VARCHAR, 7419 to_branch VARCHAR, 7420 post_migration_md5sum VARCHAR, 7421 post_upgrade_md5sum VARCHAR, 7422 PRIMARY KEY (repository, from_branch, to_branch) 7423 ); 7424 """)
7425
7426 - def _createPackagesetsTable(self):
7427 with self.__write_mutex: 7428 self.cursor.execute(""" 7429 CREATE TABLE packagesets ( setname VARCHAR, dependency VARCHAR ); 7430 """)
7431
7432 - def createCategoriesdescriptionTable(self):
7433 with self.__write_mutex: 7434 self.cursor.execute(""" 7435 CREATE TABLE categoriesdescription ( category VARCHAR, 7436 locale VARCHAR, description VARCHAR ); 7437 """)
7438
7439 - def createLicensedataTable(self):
7440 with self.__write_mutex: 7441 self.cursor.execute(""" 7442 CREATE TABLE licensedata ( licensename VARCHAR UNIQUE, 7443 text BLOB, compressed INTEGER ); 7444 """)
7445
7446 - def _createLicensesAcceptedTable(self):
7447 with self.__write_mutex: 7448 self.cursor.execute(""" 7449 CREATE TABLE licenses_accepted ( licensename VARCHAR UNIQUE ); 7450 """)
7451
7452 - def _addDependsRelationToDependsTable(self, iterable):
7453 with self.__write_mutex: 7454 self.cursor.executemany('INSERT into dependstable VALUES (?,?)', 7455 iterable)
7456
7457 - def taintReverseDependenciesMetadata(self):
7458 """ 7459 Taint reverse (or inverse) dependencies metadata so that will be 7460 generated during the next request. 7461 """ 7462 # FIXME: backward compatibility 7463 if not self._doesTableExist("dependstable"): 7464 return 7465 self.cursor.executescript(""" 7466 DELETE FROM dependstable; 7467 INSERT INTO dependstable VALUES (-1,NULL); 7468 """)
7469
7470 - def generateReverseDependenciesMetadata(self, verbose = True):
7471 """ 7472 Regenerate reverse (or inverse) dependencies metadata. 7473 7474 @keyword verbose: enable verbosity 7475 @type verbose: bool 7476 """ 7477 depends = self.listAllDependencies() 7478 count = 0 7479 total = len(depends) 7480 mydata = set() 7481 am = self.atomMatch 7482 up = self.updateProgress 7483 self.taintReverseDependenciesMetadata() 7484 self.commitChanges() 7485 for iddep, atom in depends: 7486 count += 1 7487 7488 if verbose and ((count == 0) or (count % 150 == 0) or \ 7489 (count == total)): 7490 up( red("Resolving %s") % (atom,), importance = 0, 7491 type = "info", back = True, count = (count, total) 7492 ) 7493 7494 idpackage, rc = am(atom) 7495 if idpackage == -1: 7496 continue 7497 if iddep == -1: 7498 continue 7499 mydata.add((iddep, idpackage,)) 7500 7501 if mydata: 7502 try: 7503 self._addDependsRelationToDependsTable(mydata) 7504 except self.dbapi2.IntegrityError: 7505 # try to cope for the last time 7506 self.taintReverseDependenciesMetadata() 7507 self.commitChanges() 7508 self._addDependsRelationToDependsTable(mydata) 7509 7510 # now validate dependstable 7511 self._sanitizeDependsTable() 7512 7513 plugins = self.get_plugins() 7514 for plugin_id in sorted(plugins): 7515 plug_inst = plugins[plugin_id] 7516 exec_rc = plug_inst.reverse_dependencies_tree_generation_hook(self) 7517 if exec_rc: 7518 raise RepositoryPluginError( 7519 "[reverse_dependencies_tree_generation_hook] %s: status: %s" % ( 7520 plug_inst.get_id(), exec_rc,))
7521
7522 - def moveSpmUidsToBranch(self, to_branch, from_branch = None):
7523 """ 7524 Note: this is not intended for general audience. 7525 Move "branch" metadata contained in Source Package Manager package 7526 identifiers binding metadata to new value given by "from_branch" 7527 argument. 7528 7529 @param to_branch: 7530 @type to_branch: 7531 @keyword from_branch: 7532 @type from_branch: 7533 @return: 7534 @rtype: 7535 7536 """ 7537 with self.__write_mutex: 7538 if from_branch is not None: 7539 self.cursor.execute(""" 7540 UPDATE counters SET branch = (?) WHERE branch = (?) 7541 """, (to_branch, from_branch,)) 7542 else: 7543 self.cursor.execute(""" 7544 UPDATE counters SET branch = (?) 7545 """, (to_branch,)) 7546 self.commitChanges() 7547 self.clearCache()
7548
7549 - def __atomMatchFetchCache(self, *args):
7550 if self.xcache: 7551 ck_sum = hash(self.checksum()) 7552 cached = self.dumpTools.loadobj("%s/%s/%s_%s" % ( 7553 self.dbMatchCacheKey, self.dbname, ck_sum, hash(tuple(args)),)) 7554 if cached is not None: 7555 return cached
7556
7557 - def __atomMatchStoreCache(self, *args, **kwargs):
7558 if self.xcache: 7559 ck_sum = hash(self.checksum(strict = False)) 7560 self.Cacher.push("%s/%s/%s_%s" % ( 7561 self.dbMatchCacheKey, self.dbname, ck_sum, hash(tuple(args)),), 7562 kwargs.get('result') 7563 )
7564
7565 - def __atomMatchValidateCache(self, cached_obj, multiMatch, extendedResults):
7566 7567 # time wasted for a reason 7568 data, rc = cached_obj 7569 if rc != 0: 7570 return cached_obj 7571 7572 # data must be int ! 7573 if not self.entropyTools.isnumber(data): 7574 return None 7575 7576 if (not extendedResults) and (not multiMatch): 7577 if not self.isIdpackageAvailable(data): 7578 return None 7579 7580 elif extendedResults and (not multiMatch): 7581 if not self.isIdpackageAvailable(data[0]): 7582 return None 7583 7584 elif extendedResults and multiMatch: 7585 idpackages = set([x[0] for x in data]) 7586 if not self.areIdpackagesAvailable(idpackages): 7587 return None 7588 7589 elif (not extendedResults) and multiMatch: 7590 # (set([x[0] for x in dbpkginfo]),0) 7591 idpackages = set(data) 7592 if not self.areIdpackagesAvailable(idpackages): 7593 return None 7594 7595 return cached_obj
7596
7597 - def _idpackageValidator_live(self, idpackage, reponame):
7598 7599 ref = self.SystemSettings['pkg_masking_reference'] 7600 if (idpackage, reponame) in \ 7601 self.SystemSettings['live_packagemasking']['mask_matches']: 7602 7603 # do not cache this 7604 return -1, ref['user_live_mask'] 7605 7606 elif (idpackage, reponame) in \ 7607 self.SystemSettings['live_packagemasking']['unmask_matches']: 7608 7609 return idpackage, ref['user_live_unmask']
7610
7611 - def _idpackageValidator_user_package_mask(self, idpackage, reponame, live):
7612 7613 mykw = "%smask_ids" % (reponame,) 7614 user_package_mask_ids = self.SystemSettings.get(mykw) 7615 7616 if not isinstance(user_package_mask_ids, (list, set)): 7617 user_package_mask_ids = set() 7618 7619 for atom in self.SystemSettings['mask']: 7620 matches, r = self.atomMatch(atom, multiMatch = True, 7621 packagesFilter = False) 7622 if r != 0: 7623 continue 7624 user_package_mask_ids |= set(matches) 7625 7626 self.SystemSettings[mykw] = user_package_mask_ids 7627 7628 if idpackage in user_package_mask_ids: 7629 # sorry, masked 7630 ref = self.SystemSettings['pkg_masking_reference'] 7631 myr = ref['user_package_mask'] 7632 7633 try: 7634 7635 cl_data = self.SystemSettings[self.client_settings_plugin_id] 7636 validator_cache = cl_data['masking_validation']['cache'] 7637 validator_cache[(idpackage, reponame, live)] = -1, myr 7638 7639 except KeyError: # system settings client plugin not found 7640 pass 7641 7642 return -1, myr
7643
7644 - def _idpackageValidator_user_package_unmask(self, idpackage, reponame, 7645 live):
7646 7647 # see if we can unmask by just lookin into user 7648 # package.unmask stuff -> self.SystemSettings['unmask'] 7649 mykw = "%sunmask_ids" % (reponame,) 7650 user_package_unmask_ids = self.SystemSettings.get(mykw) 7651 7652 if not isinstance(user_package_unmask_ids, (list, set)): 7653 7654 user_package_unmask_ids = set() 7655 for atom in self.SystemSettings['unmask']: 7656 matches, r = self.atomMatch(atom, multiMatch = True, 7657 packagesFilter = False) 7658 if r != 0: 7659 continue 7660 user_package_unmask_ids |= set(matches) 7661 7662 self.SystemSettings[mykw] = user_package_unmask_ids 7663 7664 if idpackage in user_package_unmask_ids: 7665 7666 ref = self.SystemSettings['pkg_masking_reference'] 7667 myr = ref['user_package_unmask'] 7668 try: 7669 7670 cl_data = self.SystemSettings[self.client_settings_plugin_id] 7671 validator_cache = cl_data['masking_validation']['cache'] 7672 validator_cache[(idpackage, reponame, live)] = idpackage, myr 7673 7674 except KeyError: # system settings client plugin not found 7675 pass 7676 7677 return idpackage, myr
7678
7679 - def _idpackageValidator_packages_db_mask(self, idpackage, reponame, live):
7680 7681 # check if repository packages.db.mask needs it masked 7682 repos_mask = {} 7683 client_plg_id = etpConst['system_settings_plugins_ids']['client_plugin'] 7684 client_settings = self.SystemSettings.get(client_plg_id, {}) 7685 if client_settings: 7686 repos_mask = client_settings['repositories']['mask'] 7687 7688 repomask = repos_mask.get(reponame) 7689 if isinstance(repomask, (list, set)): 7690 7691 # first, seek into generic masking, all branches 7692 # (below) avoid issues with repository names 7693 mask_repo_id = "%s_ids@@:of:%s" % (reponame, reponame,) 7694 repomask_ids = repos_mask.get(mask_repo_id) 7695 7696 if not isinstance(repomask_ids, set): 7697 repomask_ids = set() 7698 for atom in repomask: 7699 matches, r = self.atomMatch(atom, multiMatch = True, 7700 packagesFilter = False) 7701 if r != 0: 7702 continue 7703 repomask_ids |= set(matches) 7704 repos_mask[mask_repo_id] = repomask_ids 7705 7706 if idpackage in repomask_ids: 7707 7708 ref = self.SystemSettings['pkg_masking_reference'] 7709 myr = ref['repository_packages_db_mask'] 7710 7711 try: 7712 7713 plg_id = self.client_settings_plugin_id 7714 cl_data = self.SystemSettings[plg_id] 7715 validator_cache = cl_data['masking_validation']['cache'] 7716 validator_cache[(idpackage, reponame, live)] = -1, myr 7717 7718 except KeyError: # system settings client plugin not found 7719 pass 7720 7721 return -1, myr
7722
7723 - def _idpackageValidator_package_license_mask(self, idpackage, reponame, 7724 live):
7725 7726 if not self.SystemSettings['license_mask']: 7727 return 7728 7729 mylicenses = self.retrieveLicense(idpackage) 7730 mylicenses = mylicenses.strip().split() 7731 lic_mask = self.SystemSettings['license_mask'] 7732 for mylicense in mylicenses: 7733 7734 if mylicense not in lic_mask: 7735 continue 7736 7737 ref = self.SystemSettings['pkg_masking_reference'] 7738 myr = ref['user_license_mask'] 7739 try: 7740 7741 cl_data = self.SystemSettings[self.client_settings_plugin_id] 7742 validator_cache = cl_data['masking_validation']['cache'] 7743 validator_cache[(idpackage, reponame, live)] = -1, myr 7744 7745 except KeyError: # system settings client plugin not found 7746 pass 7747 7748 return -1, myr
7749
7750 - def _idpackageValidator_keyword_mask(self, idpackage, reponame, live):
7751 7752 # WORKAROUND for buggy entries 7753 # ** is fine then 7754 mykeywords = self.retrieveKeywords(idpackage) or set(['']) 7755 7756 mask_ref = self.SystemSettings['pkg_masking_reference'] 7757 7758 # firstly, check if package keywords are in etpConst['keywords'] 7759 # (universal keywords have been merged from package.keywords) 7760 same_keywords = etpConst['keywords'] & mykeywords 7761 if same_keywords: 7762 myr = mask_ref['system_keyword'] 7763 try: 7764 7765 cl_data = self.SystemSettings[self.client_settings_plugin_id] 7766 validator_cache = cl_data['masking_validation']['cache'] 7767 validator_cache[(idpackage, reponame, live)] = idpackage, myr 7768 7769 except KeyError: # system settings client plugin not found 7770 pass 7771 7772 return idpackage, myr 7773 7774 # if we get here, it means we didn't find mykeywords 7775 # in etpConst['keywords'] 7776 # we need to seek self.SystemSettings['keywords'] 7777 # seek in repository first 7778 keyword_repo = self.SystemSettings['keywords']['repositories'] 7779 7780 for keyword in list(keyword_repo.get(reponame, {}).keys()): 7781 7782 if keyword not in mykeywords: 7783 continue 7784 7785 keyword_data = keyword_repo[reponame].get(keyword) 7786 if not keyword_data: 7787 continue 7788 7789 if "*" in keyword_data: 7790 # all packages in this repo with keyword "keyword" are ok 7791 myr = mask_ref['user_repo_package_keywords_all'] 7792 try: 7793 7794 plg_id = self.client_settings_plugin_id 7795 cl_data = self.SystemSettings[plg_id] 7796 validator_cache = cl_data['masking_validation']['cache'] 7797 validator_cache[(idpackage, reponame, live)] = \ 7798 idpackage, myr 7799 7800 except KeyError: # system settings client plugin not found 7801 pass 7802 7803 return idpackage, myr 7804 7805 kwd_key = "%s_ids" % (keyword,) 7806 keyword_data_ids = keyword_repo[reponame].get(kwd_key) 7807 if not isinstance(keyword_data_ids, set): 7808 7809 keyword_data_ids = set() 7810 for atom in keyword_data: 7811 matches, r = self.atomMatch(atom, multiMatch = True, 7812 packagesFilter = False) 7813 if r != 0: 7814 continue 7815 keyword_data_ids |= matches 7816 7817 keyword_repo[reponame][kwd_key] = keyword_data_ids 7818 7819 if idpackage in keyword_data_ids: 7820 7821 myr = mask_ref['user_repo_package_keywords'] 7822 try: 7823 7824 plg_id = self.client_settings_plugin_id 7825 cl_data = self.SystemSettings[plg_id] 7826 validator_cache = cl_data['masking_validation']['cache'] 7827 validator_cache[(idpackage, reponame, live)] = \ 7828 idpackage, myr 7829 7830 except KeyError: # system settings client plugin not found 7831 pass 7832 return idpackage, myr 7833 7834 keyword_pkg = self.SystemSettings['keywords']['packages'] 7835 7836 # if we get here, it means we didn't find a match in repositories 7837 # so we scan packages, last chance 7838 for keyword in list(keyword_pkg.keys()): 7839 # use .keys() because keyword_pkg gets modified during iteration 7840 7841 # first of all check if keyword is in mykeywords 7842 if keyword not in mykeywords: 7843 continue 7844 7845 keyword_data = keyword_pkg.get(keyword) 7846 if not keyword_data: 7847 continue 7848 7849 kwd_key = "%s_ids" % (keyword,) 7850 keyword_data_ids = keyword_pkg.get(reponame+kwd_key) 7851 7852 if not isinstance(keyword_data_ids, (list, set)): 7853 keyword_data_ids = set() 7854 for atom in keyword_data: 7855 # match atom 7856 matches, r = self.atomMatch(atom, multiMatch = True, 7857 packagesFilter = False) 7858 if r != 0: 7859 continue 7860 keyword_data_ids |= matches 7861 7862 keyword_pkg[reponame+kwd_key] = keyword_data_ids 7863 7864 if idpackage in keyword_data_ids: 7865 7866 # valid! 7867 myr = mask_ref['user_package_keywords'] 7868 try: 7869 7870 plg_id = self.client_settings_plugin_id 7871 cl_data = self.SystemSettings[plg_id] 7872 validator_cache = cl_data['masking_validation']['cache'] 7873 validator_cache[(idpackage, reponame, live)] = \ 7874 idpackage, myr 7875 7876 except KeyError: # system settings client plugin not found 7877 pass 7878 7879 return idpackage, myr 7880 7881 7882 ## if we get here, it means that pkg it keyword masked 7883 ## and we should look at the very last resort, per-repository 7884 ## package keywords 7885 # check if repository contains keyword unmasking data 7886 7887 plg_id = self.client_settings_plugin_id 7888 cl_data = self.SystemSettings.get(plg_id) 7889 if cl_data is None: 7890 # SystemSettings Entropy Client plugin not available 7891 return 7892 # let's see if something is available in repository config 7893 repo_keywords = cl_data['repositories']['repos_keywords'].get(reponame) 7894 if repo_keywords is None: 7895 # nopers, sorry! 7896 return 7897 7898 # check universal keywords 7899 same_keywords = repo_keywords.get('universal') & mykeywords 7900 if same_keywords: 7901 # universal keyword matches! 7902 myr = mask_ref['repository_packages_db_keywords'] 7903 validator_cache = cl_data['masking_validation']['cache'] 7904 validator_cache[(idpackage, reponame, live)] = \ 7905 idpackage, myr 7906 return idpackage, myr 7907 7908 ## if we get here, it means that even universal masking failed 7909 ## and we need to look at per-package settings 7910 repo_settings = repo_keywords.get('packages') 7911 if not repo_settings: 7912 # it's empty, not worth checking 7913 return 7914 7915 cached_key = "packages_ids" 7916 keyword_data_ids = repo_keywords.get(cached_key) 7917 if not isinstance(keyword_data_ids, dict): 7918 # create cache 7919 7920 keyword_data_ids = {} 7921 for atom, values in list(repo_settings.items()): 7922 matches, r = self.atomMatch(atom, multiMatch = True, 7923 packagesFilter = False) 7924 if r != 0: 7925 continue 7926 for match in matches: 7927 obj = keyword_data_ids.setdefault(match, set()) 7928 obj.update(values) 7929 7930 repo_keywords[cached_key] = keyword_data_ids 7931 7932 same_keywords = keyword_data_ids.get(idpackage, set()) & \ 7933 etpConst['keywords'] 7934 if same_keywords: 7935 # found! this pkg is not masked, yay! 7936 myr = mask_ref['repository_packages_db_keywords'] 7937 validator_cache = cl_data['masking_validation']['cache'] 7938 validator_cache[(idpackage, reponame, live)] = \ 7939 idpackage, myr 7940 return idpackage, myr
7941 7942
7943 - def idpackageValidator(self, idpackage, live = True):
7944 """ 7945 Return whether given package identifier is available to user or not, 7946 reading package masking metadata stored in SystemSettings. 7947 7948 @param idpackage: package indentifier 7949 @type idpackage: int 7950 @keyword live: use live masking feature 7951 @type live: bool 7952 @return: tuple composed by idpackage and masking reason. If idpackage 7953 returned idpackage value == -1, it means that package is masked 7954 and a valid masking reason identifier is returned as second 7955 value of the tuple (see SystemSettings['pkg_masking_reasons']) 7956 @rtype: tuple 7957 """ 7958 7959 if self.dbname == etpConst['clientdbid']: 7960 return idpackage, 0 7961 7962 # FIXME: this is Entropy Client related but also part of the 7963 # currently implemented metaphor, so let's wait to have a Rule 7964 # Engine in place before removing the oddity of client_repo 7965 # metadatum. 7966 client_repo = self.get_plugins_metadata().get('client_repo') 7967 if not client_repo: 7968 # server-side repositories don't make any use of idpackage validator 7969 return idpackage, 0 7970 7971 reponame = self.dbname[len(etpConst['dbnamerepoprefix']):] 7972 try: 7973 cl_data = self.SystemSettings[self.client_settings_plugin_id] 7974 validator_cache = cl_data['masking_validation']['cache'] 7975 7976 cached = validator_cache.get((idpackage, reponame, live)) 7977 if cached is not None: 7978 return cached 7979 7980 # avoid memleaks 7981 if len(validator_cache) > 10000: 7982 validator_cache.clear() 7983 7984 except KeyError: # plugin does not exist 7985 pass 7986 7987 if live: 7988 data = self._idpackageValidator_live(idpackage, reponame) 7989 if data: 7990 return data 7991 7992 data = self._idpackageValidator_user_package_mask(idpackage, 7993 reponame, live) 7994 if data: 7995 return data 7996 7997 data = self._idpackageValidator_user_package_unmask(idpackage, 7998 reponame, live) 7999 if data: 8000 return data 8001 8002 data = self._idpackageValidator_packages_db_mask(idpackage, reponame, 8003 live) 8004 if data: 8005 return data 8006 8007 data = self._idpackageValidator_package_license_mask(idpackage, 8008 reponame, live) 8009 if data: 8010 return data 8011 8012 data = self._idpackageValidator_keyword_mask(idpackage, reponame, live) 8013 if data: 8014 return data 8015 8016 # holy crap, can't validate 8017 myr = self.SystemSettings['pkg_masking_reference']['completely_masked'] 8018 validator_cache[(idpackage, reponame, live)] = -1, myr 8019 return -1, myr
8020 8021
8022 - def _packagesFilter(self, results):
8023 """ 8024 Packages filter used by atomMatch, input must me foundIDs, 8025 a list like this: [608, 1867]. 8026 8027 """ 8028 8029 # keywordsFilter ONLY FILTERS results if 8030 # self.dbname.startswith(etpConst['dbnamerepoprefix']) 8031 # => repository database is open 8032 if not self.dbname.startswith(etpConst['dbnamerepoprefix']): 8033 return results 8034 8035 newresults = set() 8036 for idpackage in results: 8037 idpackage, reason = self.idpackageValidator(idpackage) 8038 if idpackage == -1: 8039 continue 8040 newresults.add(idpackage) 8041 return newresults
8042
8043 - def __filterSlot(self, idpackage, slot):
8044 if slot is None: 8045 return idpackage 8046 dbslot = self.retrieveSlot(idpackage) 8047 if dbslot == slot: 8048 return idpackage
8049
8050 - def __filterTag(self, idpackage, tag, operators):
8051 if tag is None: 8052 return idpackage 8053 dbtag = self.retrieveVersionTag(idpackage) 8054 compare = const_cmp(tag, dbtag) 8055 if not operators or operators == "=": 8056 if compare == 0: 8057 return idpackage 8058 else: 8059 return self.__do_operator_compare(idpackage, operators, compare)
8060
8061 - def __filterUse(self, idpackage, use):
8062 if not use: 8063 return idpackage 8064 pkguse = self.retrieveUseflags(idpackage) 8065 disabled = set([x[1:] for x in use if x.startswith("-")]) 8066 enabled = set([x for x in use if not x.startswith("-")]) 8067 enabled_not_satisfied = enabled - pkguse 8068 # check enabled 8069 if enabled_not_satisfied: 8070 return None 8071 # check disabled 8072 disabled_not_satisfied = disabled - pkguse 8073 if len(disabled_not_satisfied) != len(disabled): 8074 return None 8075 return idpackage
8076
8077 - def __do_operator_compare(self, token, operators, compare):
8078 if operators == ">" and compare == -1: 8079 return token 8080 elif operators == ">=" and compare < 1: 8081 return token 8082 elif operators == "<" and compare == 1: 8083 return token 8084 elif operators == "<=" and compare > -1: 8085 return token
8086
8087 - def __filterSlotTagUse(self, foundIDs, slot, tag, use, operators):
8088 8089 def myfilter(idpackage): 8090 8091 idpackage = self.__filterSlot(idpackage, slot) 8092 if not idpackage: 8093 return False 8094 8095 idpackage = self.__filterUse(idpackage, use) 8096 if not idpackage: 8097 return False 8098 8099 idpackage = self.__filterTag(idpackage, tag, operators) 8100 if not idpackage: 8101 return False 8102 8103 return True
8104 8105 return set(filter(myfilter, foundIDs)) 8106
8107 - def atomMatch(self, atom, caseSensitive = True, matchSlot = None, 8108 multiMatch = False, matchTag = None, matchUse = (), 8109 packagesFilter = True, matchRevision = None, extendedResults = False, 8110 useCache = True):
8111 8112 """ 8113 Match given atom (or dependency) in repository and return its package 8114 identifer and execution status. 8115 8116 @param atom: atom or dependency to match in repository 8117 @type atom: unicode string 8118 @keyword caseSensitive: match in case sensitive mode 8119 @type caseSensitive: bool 8120 @keyword matchSlot: match packages with given slot 8121 @type matchSlot: string 8122 @keyword multiMatch: match all the available packages, not just the 8123 best one 8124 @type multiMatch: bool 8125 @keyword matchTag: match packages with given tag 8126 @type matchTag: string 8127 @keyword matchUse: match packages with given use flags 8128 @type matchUse: list or tuple or set 8129 @keyword packagesFilter: enable package masking filter 8130 @type packagesFilter: bool 8131 @keyword matchRevision: match packages with given entropy revision 8132 @type matchRevision: int 8133 @keyword extendedResults: return extended results 8134 @type extendedResults: bool 8135 @keyword useCache: use on-disk cache 8136 @type useCache: bool 8137 @return: tuple of length 2 composed by (idpackage or -1, command status 8138 (0 means found, 1 means error)) or, if extendedResults is True, 8139 also add versioning information to tuple. 8140 If multiMatch is True, a tuple composed by a set (containing package 8141 identifiers) and command status is returned. 8142 @rtype: tuple or set 8143 @todo: improve documentation here 8144 """ 8145 8146 if not atom: 8147 return -1, 1 8148 8149 if useCache: 8150 cached = self.__atomMatchFetchCache( 8151 atom, caseSensitive, matchSlot, 8152 multiMatch, matchTag, 8153 matchUse, packagesFilter, matchRevision, 8154 extendedResults 8155 ) 8156 if isinstance(cached, tuple): 8157 8158 try: 8159 cached = self.__atomMatchValidateCache(cached, 8160 multiMatch, extendedResults) 8161 except (TypeError, ValueError, IndexError, KeyError,): 8162 cached = None 8163 8164 if isinstance(cached, tuple): 8165 return cached 8166 8167 atomTag = self.entropyTools.dep_gettag(atom) 8168 try: 8169 atomUse = self.entropyTools.dep_getusedeps(atom) 8170 except InvalidAtom: 8171 atomUse = () 8172 atomSlot = self.entropyTools.dep_getslot(atom) 8173 atomRev = self.entropyTools.dep_get_entropy_revision(atom) 8174 if isinstance(atomRev, int): 8175 if atomRev < 0: atomRev = None 8176 8177 # use match 8178 scan_atom = self.entropyTools.remove_usedeps(atom) 8179 if (not matchUse) and (atomUse): 8180 matchUse = atomUse 8181 8182 # tag match 8183 scan_atom = self.entropyTools.remove_tag(scan_atom) 8184 if (matchTag is None) and (atomTag is not None): 8185 matchTag = atomTag 8186 8187 # slot match 8188 scan_atom = self.entropyTools.remove_slot(scan_atom) 8189 if (matchSlot is None) and (atomSlot is not None): 8190 matchSlot = atomSlot 8191 8192 # revision match 8193 scan_atom = self.entropyTools.remove_entropy_revision(scan_atom) 8194 if (matchRevision is None) and (atomRev is not None): 8195 matchRevision = atomRev 8196 8197 direction = '' 8198 justname = True 8199 pkgkey = '' 8200 pkgname = '' 8201 pkgcat = '' 8202 pkgversion = '' 8203 strippedAtom = '' 8204 foundIDs = [] 8205 dbpkginfo = set() 8206 8207 if scan_atom: 8208 8209 while True: 8210 # check for direction 8211 strippedAtom = self.entropyTools.dep_getcpv(scan_atom) 8212 if scan_atom[-1] == "*": 8213 strippedAtom += "*" 8214 direction = scan_atom[0:-len(strippedAtom)] 8215 8216 justname = self.entropyTools.isjustname(strippedAtom) 8217 pkgkey = strippedAtom 8218 if justname == 0: 8219 # get version 8220 data = self.entropyTools.catpkgsplit(strippedAtom) 8221 if data is None: 8222 break # badly formatted 8223 pkgversion = data[2]+"-"+data[3] 8224 pkgkey = self.entropyTools.dep_getkey(strippedAtom) 8225 8226 splitkey = pkgkey.split("/") 8227 if (len(splitkey) == 2): 8228 pkgcat, pkgname = splitkey 8229 else: 8230 pkgcat, pkgname = "null", splitkey[0] 8231 8232 break 8233 8234 8235 # IDs found in the database that match our search 8236 foundIDs = self.__generate_found_ids_match(pkgkey, pkgname, pkgcat, 8237 caseSensitive, multiMatch) 8238 8239 ### FILTERING 8240 # filter slot and tag 8241 if foundIDs: 8242 foundIDs = self.__filterSlotTagUse(foundIDs, matchSlot, 8243 matchTag, matchUse, direction) 8244 if packagesFilter: 8245 foundIDs = self._packagesFilter(foundIDs) 8246 ### END FILTERING 8247 8248 if foundIDs: 8249 dbpkginfo = self.__handle_found_ids_match(foundIDs, direction, 8250 matchTag, matchRevision, justname, strippedAtom, pkgversion) 8251 8252 if not dbpkginfo: 8253 if extendedResults: 8254 if multiMatch: 8255 x = set() 8256 else: 8257 x = (-1, 1, None, None, None,) 8258 self.__atomMatchStoreCache( 8259 atom, caseSensitive, matchSlot, 8260 multiMatch, matchTag, 8261 matchUse, packagesFilter, matchRevision, 8262 extendedResults, result = (x, 1) 8263 ) 8264 return x, 1 8265 else: 8266 if multiMatch: 8267 x = set() 8268 else: 8269 x = -1 8270 self.__atomMatchStoreCache( 8271 atom, caseSensitive, matchSlot, 8272 multiMatch, matchTag, 8273 matchUse, packagesFilter, matchRevision, 8274 extendedResults, result = (x, 1) 8275 ) 8276 return x, 1 8277 8278 if multiMatch: 8279 if extendedResults: 8280 x = set([(x[0], 0, x[1], self.retrieveVersionTag(x[0]), \ 8281 self.retrieveRevision(x[0])) for x in dbpkginfo]) 8282 self.__atomMatchStoreCache( 8283 atom, caseSensitive, matchSlot, 8284 multiMatch, matchTag, 8285 matchUse, packagesFilter, matchRevision, 8286 extendedResults, result = (x, 0) 8287 ) 8288 return x, 0 8289 else: 8290 x = set([x[0] for x in dbpkginfo]) 8291 self.__atomMatchStoreCache( 8292 atom, caseSensitive, matchSlot, 8293 multiMatch, matchTag, 8294 matchUse, packagesFilter, matchRevision, 8295 extendedResults, result = (x, 0) 8296 ) 8297 return x, 0 8298 8299 if len(dbpkginfo) == 1: 8300 x = dbpkginfo.pop() 8301 if extendedResults: 8302 x = (x[0], 0, x[1], self.retrieveVersionTag(x[0]), 8303 self.retrieveRevision(x[0]),) 8304 8305 self.__atomMatchStoreCache( 8306 atom, caseSensitive, matchSlot, 8307 multiMatch, matchTag, 8308 matchUse, packagesFilter, matchRevision, 8309 extendedResults, result = (x, 0) 8310 ) 8311 return x, 0 8312 else: 8313 self.__atomMatchStoreCache( 8314 atom, caseSensitive, matchSlot, 8315 multiMatch, matchTag, 8316 matchUse, packagesFilter, matchRevision, 8317 extendedResults, result = (x[0], 0) 8318 ) 8319 return x[0], 0 8320 8321 dbpkginfo = list(dbpkginfo) 8322 pkgdata = {} 8323 versions = set() 8324 8325 for x in dbpkginfo: 8326 info_tuple = (x[1], self.retrieveVersionTag(x[0]), \ 8327 self.retrieveRevision(x[0])) 8328 versions.add(info_tuple) 8329 pkgdata[info_tuple] = x[0] 8330 8331 newer = self.entropyTools.get_entropy_newer_version(list(versions))[0] 8332 x = pkgdata[newer] 8333 if extendedResults: 8334 x = (x, 0, newer[0], newer[1], newer[2]) 8335 self.__atomMatchStoreCache( 8336 atom, caseSensitive, matchSlot, 8337 multiMatch, matchTag, 8338 matchUse, packagesFilter, matchRevision, 8339 extendedResults, result = (x, 0) 8340 ) 8341 return x, 0 8342 else: 8343 self.__atomMatchStoreCache( 8344 atom, caseSensitive, matchSlot, 8345 multiMatch, matchTag, 8346 matchUse, packagesFilter, matchRevision, 8347 extendedResults, result = (x, 0) 8348 ) 8349 return x, 0
8350
8351 - def __generate_found_ids_match(self, pkgkey, pkgname, pkgcat, caseSensitive, 8352 multiMatch):
8353 8354 if pkgcat == "null": 8355 results = self.searchPackagesByName(pkgname, 8356 sensitive = caseSensitive, justid = True) 8357 else: 8358 results = self.searchPackagesByNameAndCategory(name = pkgname, 8359 category = pkgcat, sensitive = caseSensitive, justid = True 8360 ) 8361 8362 mypkgcat = pkgcat 8363 mypkgname = pkgname 8364 virtual = False 8365 # if it's a PROVIDE, search with searchProvide 8366 # there's no package with that name 8367 if (not results) and (mypkgcat == "virtual"): 8368 8369 virtuals = self.searchProvide(pkgkey, justid = True, 8370 get_extended = True) 8371 if virtuals: 8372 virtual = True 8373 flat_virtuals = [] 8374 default_virtual = virtuals[0][0] 8375 # look for default old-style virtual 8376 for v_id, v_is_default in virtuals: 8377 if v_is_default == 1: 8378 default_virtual = v_id 8379 flat_virtuals.append(v_id) 8380 mypkgname = self.retrieveName(default_virtual) 8381 mypkgcat = self.retrieveCategory(default_virtual) 8382 results = flat_virtuals 8383 8384 8385 if not results: # nothing found 8386 return set() 8387 8388 if len(results) > 1: # need to choose 8389 8390 # if it's because category differs, it's a problem 8391 foundCat = None 8392 cats = set() 8393 for idpackage in results: 8394 cat = self.retrieveCategory(idpackage) 8395 cats.add(cat) 8396 if (cat == mypkgcat) or ((not virtual) and \ 8397 (mypkgcat == "virtual") and (cat == mypkgcat)): 8398 # in case of virtual packages only 8399 # (that they're not stored as provide) 8400 foundCat = cat 8401 8402 # if we found something at least... 8403 if (not foundCat) and (len(cats) == 1) and \ 8404 (mypkgcat in ("virtual", "null")): 8405 8406 foundCat = sorted(cats)[0] 8407 8408 if not foundCat: 8409 # got the issue 8410 return set() 8411 8412 # we can use foundCat 8413 mypkgcat = foundCat 8414 8415 # we need to search using the category 8416 if (not multiMatch) and (pkgcat == "null" or virtual): 8417 # we searched by name, we need to search using category 8418 results = self.searchPackagesByNameAndCategory( 8419 name = mypkgname, category = mypkgcat, 8420 sensitive = caseSensitive, justid = True 8421 ) 8422 8423 # if we get here, we have found the needed IDs 8424 return set(results) 8425 8426 ### 8427 ### just found one result 8428 ### 8429 8430 idpackage = results[0] 8431 # if mypkgcat is virtual, it can be forced 8432 if (mypkgcat == "virtual") and (not virtual): 8433 # in case of virtual packages only 8434 # (that they're not stored as provide) 8435 mypkgcat = self.retrieveCategory(idpackage) 8436 8437 # check if category matches 8438 if mypkgcat != "null": 8439 foundCat = self.retrieveCategory(idpackage) 8440 if mypkgcat == foundCat: 8441 return set([idpackage]) 8442 return set() # nope nope 8443 8444 # very good, here it is 8445 return set([idpackage])
8446 8447
8448 - def __handle_found_ids_match(self, foundIDs, direction, matchTag, 8449 matchRevision, justname, strippedAtom, pkgversion):
8450 8451 dbpkginfo = set() 8452 # now we have to handle direction 8453 if ((direction) or ((not direction) and (not justname)) or \ 8454 ((not direction) and (not justname) \ 8455 and strippedAtom.endswith("*"))) and foundIDs: 8456 8457 if (not justname) and \ 8458 ((direction == "~") or (direction == "=") or \ 8459 ((not direction) and (not justname)) or ((not direction) and \ 8460 not justname and strippedAtom.endswith("*"))): 8461 # any revision within the version specified 8462 # OR the specified version 8463 8464 if ((not direction) and (not justname)): 8465 direction = "=" 8466 8467 # remove gentoo revision (-r0 if none) 8468 if (direction == "="): 8469 if (pkgversion.split("-")[-1] == "r0"): 8470 pkgversion = self.entropyTools.remove_revision( 8471 pkgversion) 8472 8473 if (direction == "~"): 8474 pkgrevision = self.entropyTools.dep_get_spm_revision( 8475 pkgversion) 8476 pkgversion = self.entropyTools.remove_revision(pkgversion) 8477 8478 for idpackage in foundIDs: 8479 8480 dbver = self.retrieveVersion(idpackage) 8481 if (direction == "~"): 8482 myrev = self.entropyTools.dep_get_spm_revision( 8483 dbver) 8484 myver = self.entropyTools.remove_revision(dbver) 8485 if myver == pkgversion and pkgrevision <= myrev: 8486 # found 8487 dbpkginfo.add((idpackage, dbver)) 8488 else: 8489 # media-libs/test-1.2* support 8490 if pkgversion[-1] == "*": 8491 if dbver.startswith(pkgversion[:-1]): 8492 dbpkginfo.add((idpackage, dbver)) 8493 elif (matchRevision is not None) and (pkgversion == dbver): 8494 dbrev = self.retrieveRevision(idpackage) 8495 if dbrev == matchRevision: 8496 dbpkginfo.add((idpackage, dbver)) 8497 elif (pkgversion == dbver) and (matchRevision is None): 8498 dbpkginfo.add((idpackage, dbver)) 8499 8500 elif (direction.find(">") != -1) or (direction.find("<") != -1): 8501 8502 if not justname: 8503 8504 # remove revision (-r0 if none) 8505 if pkgversion.endswith("r0"): 8506 # remove 8507 self.entropyTools.remove_revision(pkgversion) 8508 8509 for idpackage in foundIDs: 8510 8511 revcmp = 0 8512 tagcmp = 0 8513 if matchRevision is not None: 8514 dbrev = self.retrieveRevision(idpackage) 8515 revcmp = const_cmp(matchRevision, dbrev) 8516 8517 if matchTag is not None: 8518 dbtag = self.retrieveVersionTag(idpackage) 8519 tagcmp = const_cmp(matchTag, dbtag) 8520 8521 dbver = self.retrieveVersion(idpackage) 8522 pkgcmp = self.entropyTools.compare_versions( 8523 pkgversion, dbver) 8524 8525 if pkgcmp is None: 8526 import warnings 8527 warnings.warn("WARNING, invalid version string " + \ 8528 "stored in %s: %s <-> %s" % ( 8529 self.dbname, pkgversion, dbver,) 8530 ) 8531 continue 8532 8533 if direction == ">": 8534 8535 if pkgcmp < 0: 8536 dbpkginfo.add((idpackage, dbver)) 8537 elif (matchRevision is not None) and pkgcmp <= 0 \ 8538 and revcmp < 0: 8539 dbpkginfo.add((idpackage, dbver)) 8540 8541 elif (matchTag is not None) and tagcmp < 0: 8542 dbpkginfo.add((idpackage, dbver)) 8543 8544 elif direction == "<": 8545 8546 if pkgcmp > 0: 8547 dbpkginfo.add((idpackage, dbver)) 8548 elif (matchRevision is not None) and pkgcmp >= 0 \ 8549 and revcmp > 0: 8550 dbpkginfo.add((idpackage, dbver)) 8551 8552 elif (matchTag is not None) and tagcmp > 0: 8553 dbpkginfo.add((idpackage, dbver)) 8554 8555 elif direction == ">=": 8556 8557 if (matchRevision is not None) and pkgcmp <= 0: 8558 if pkgcmp == 0: 8559 if revcmp <= 0: 8560 dbpkginfo.add((idpackage, dbver)) 8561 else: 8562 dbpkginfo.add((idpackage, dbver)) 8563 elif pkgcmp <= 0 and matchRevision is None: 8564 dbpkginfo.add((idpackage, dbver)) 8565 elif (matchTag is not None) and tagcmp <= 0: 8566 dbpkginfo.add((idpackage, dbver)) 8567 8568 elif direction == "<=": 8569 8570 if (matchRevision is not None) and pkgcmp >= 0: 8571 if pkgcmp == 0: 8572 if revcmp >= 0: 8573 dbpkginfo.add((idpackage, dbver)) 8574 else: 8575 dbpkginfo.add((idpackage, dbver)) 8576 elif pkgcmp >= 0 and matchRevision is None: 8577 dbpkginfo.add((idpackage, dbver)) 8578 elif (matchTag is not None) and tagcmp >= 0: 8579 dbpkginfo.add((idpackage, dbver)) 8580 8581 else: # just the key 8582 8583 dbpkginfo = set([(x, self.retrieveVersion(x),) for x in foundIDs]) 8584 8585 return dbpkginfo
8586