Package entropy :: Module db

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