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