Package entropy :: Package db :: Module skel

Source Code for Module entropy.db.skel

   1  # -*- coding: utf-8 -*- 
   2  """ 
   3   
   4      @author: Fabio Erculiani <[email protected]> 
   5      @contact: [email protected] 
   6      @copyright: Fabio Erculiani 
   7      @license: GPL-2 
   8   
   9      B{Entropy Framework repository database prototype classes module}. 
  10  """ 
  11  import base64 
  12  import os 
  13  import shutil 
  14  import warnings 
  15  import hashlib 
  16  import codecs 
  17  import collections 
  18  import contextlib 
  19  import threading 
  20   
  21  from entropy.i18n import _ 
  22  from entropy.exceptions import InvalidAtom 
  23  from entropy.const import etpConst, const_cmp, const_debug_write, \ 
  24      const_convert_to_rawstring, const_mkstemp, const_is_python3 
  25  from entropy.output import TextInterface, brown, bold, red, blue, purple, \ 
  26      darkred, darkgreen 
  27  from entropy.cache import EntropyCacher 
  28  from entropy.core import EntropyPluginStore 
  29  from entropy.core.settings.base import SystemSettings 
  30  from entropy.exceptions import RepositoryPluginError 
  31  from entropy.spm.plugins.factory import get_default_instance as get_spm, \ 
  32      get_default_class as get_spm_class 
  33  from entropy.db.exceptions import OperationalError 
  34  from entropy.db.cache import EntropyRepositoryCachePolicies 
  35   
  36  import entropy.dep 
  37  import entropy.tools 
38 39 -class EntropyRepositoryPlugin(object):
40 """ 41 This is the base class for implementing EntropyRepository plugin hooks. 42 You have to subclass this, implement not implemented methods and provide 43 it to EntropyRepository class as described below. 44 45 Every plugin hook function features this signature: 46 int something_hook(entropy_repository_instance) 47 Where entropy_repository_instance is the calling EntropyRepository instance. 48 Every method should return a return status code which, when nonzero causes 49 a RepositoryPluginError exception to be thrown. 50 Every method returns 0 in the base class implementation. 51 """ 52
53 - def get_id(self):
54 """ 55 Return string identifier of myself. 56 57 @return: EntropyRepositoryPlugin identifier. 58 @rtype: string 59 """ 60 return str(self)
61
62 - def get_metadata(self):
63 """ 64 Developers reimplementing EntropyRepositoryPlugin can provide metadata 65 along with every instance. 66 If you want to provide read-only metadata, this method should really 67 return a copy of the metadata object, otherwise, return its direct 68 reference. 69 Metadata format is a map-like object (dictionary, dict()). 70 By default this method does return an empty dict. 71 Make sure that your metadata dictionaries around don't have keys in 72 common, otherwise those will be randomly overwritten eachothers. 73 74 @return: plugin metadata 75 @rtype: dict 76 """ 77 return {}
78
79 - def add_plugin_hook(self, entropy_repository_instance):
80 """ 81 Called during EntropyRepository plugin addition. 82 83 @param entropy_repository_instance: EntropyRepository instance 84 @type entropy_repository_instance: EntropyRepository 85 @return: execution status code, return nonzero for errors, this will 86 raise a RepositoryPluginError exception. 87 @rtype: int 88 """ 89 return 0
90
91 - def remove_plugin_hook(self, entropy_repository_instance):
92 """ 93 Called during EntropyRepository plugin removal. 94 95 @param entropy_repository_instance: EntropyRepository instance 96 @type entropy_repository_instance: EntropyRepository 97 @return: execution status code, return nonzero for errors, this will 98 raise a RepositoryPluginError exception. 99 @rtype: int 100 """ 101 return 0
102
103 - def commit_hook(self, entropy_repository_instance):
104 """ 105 Called during EntropyRepository data commit. 106 107 @param entropy_repository_instance: EntropyRepository instance 108 @type entropy_repository_instance: EntropyRepository 109 @return: execution status code, return nonzero for errors, this will 110 raise a RepositoryPluginError exception. 111 @rtype: int 112 """ 113 return 0
114
115 - def close_repo_hook(self, entropy_repository_instance):
116 """ 117 Called during EntropyRepository instance shutdown (close()). 118 119 @param entropy_repository_instance: EntropyRepository instance 120 @type entropy_repository_instance: EntropyRepository 121 @return: execution status code, return nonzero for errors, this will 122 raise a RepositoryPluginError exception. 123 @rtype: int 124 """ 125 return 0
126
127 - def add_package_hook(self, entropy_repository_instance, package_id, 128 package_data):
129 """ 130 Called after the addition of a package from EntropyRepository. 131 132 @param entropy_repository_instance: EntropyRepository instance 133 @type entropy_repository_instance: EntropyRepository 134 @param package_id: Entropy repository package identifier 135 @type package_id: int 136 @param package_data: package metadata used for insertion 137 (see addPackage) 138 @type package_data: dict 139 @return: execution status code, return nonzero for errors, this will 140 raise a RepositoryPluginError exception. 141 @rtype: int 142 """ 143 return 0
144
145 - def remove_package_hook(self, entropy_repository_instance, package_id, 146 from_add_package):
147 """ 148 Called after the removal of a package from EntropyRepository. 149 150 @param entropy_repository_instance: EntropyRepository instance 151 @type entropy_repository_instance: EntropyRepository 152 @param package_id: Entropy repository package identifier 153 @type package_id: int 154 @param from_add_package: inform whether removePackage() is called inside 155 addPackage() 156 @return: execution status code, return nonzero for errors, this will 157 raise a RepositoryPluginError exception. 158 @rtype: int 159 """ 160 return 0
161
162 - def clear_cache_hook(self, entropy_repository_instance):
163 """ 164 Called during EntropyRepository cache cleanup (clearCache). 165 166 @param entropy_repository_instance: EntropyRepository instance 167 @type entropy_repository_instance: EntropyRepository 168 @return: execution status code, return nonzero for errors, this will 169 raise a RepositoryPluginError exception. 170 @rtype: int 171 """ 172 return 0
173
174 - def initialize_repo_hook(self, entropy_repository_instance):
175 """ 176 Called during EntropyRepository data initialization (not instance init). 177 178 @param entropy_repository_instance: EntropyRepository instance 179 @type entropy_repository_instance: EntropyRepository 180 @return: execution status code, return nonzero for errors, this will 181 raise a RepositoryPluginError exception. 182 @rtype: int 183 """ 184 return 0
185
186 - def accept_license_hook(self, entropy_repository_instance):
187 """ 188 Called during EntropyRepository acceptLicense call. 189 190 @param entropy_repository_instance: EntropyRepository instance 191 @type entropy_repository_instance: EntropyRepository 192 @return: execution status code, return nonzero for errors, this will 193 raise a RepositoryPluginError exception. 194 @rtype: int 195 """ 196 return 0
197
198 - def treeupdates_move_action_hook(self, entropy_repository_instance, 199 package_id):
200 """ 201 Called after EntropyRepository treeupdates move action execution for 202 given package_id in given EntropyRepository instance. 203 204 @param entropy_repository_instance: EntropyRepository instance 205 @type entropy_repository_instance: EntropyRepository 206 @param package_id: Entropy repository package identifier 207 @type package_id: int 208 @return: execution status code, return nonzero for errors, this will 209 raise a RepositoryPluginError exception. 210 @rtype: int 211 """ 212 return 0
213
214 - def treeupdates_slot_move_action_hook(self, entropy_repository_instance, 215 package_id):
216 """ 217 Called after EntropyRepository treeupdates slot move action 218 execution for given package_id in given EntropyRepository instance. 219 220 @param entropy_repository_instance: EntropyRepository instance 221 @type entropy_repository_instance: EntropyRepository 222 @param package_id: Entropy repository package identifier 223 @type package_id: int 224 @return: execution status code, return nonzero for errors, this will 225 raise a RepositoryPluginError exception. 226 @rtype: int 227 """ 228 return 0
229
230 -class EntropyRepositoryPluginStore(EntropyPluginStore):
231 232 """ 233 EntropyRepository plugin interface. This is the EntropyRepository part 234 aimed to handle connected plugins. 235 """ 236 237 _PERMANENT_PLUGINS = {} 238
239 - def __init__(self):
240 EntropyPluginStore.__init__(self) 241 permanent_plugs = EntropyRepositoryPluginStore.get_permanent_plugins() 242 for plug in permanent_plugs.values(): 243 plug.add_plugin_hook(self)
244
245 - def add_plugin(self, entropy_repository_plugin):
246 """ 247 Overloaded from EntropyPluginStore, adds support for hooks execution. 248 """ 249 inst = entropy_repository_plugin 250 if not isinstance(inst, EntropyRepositoryPlugin): 251 raise AttributeError("EntropyRepositoryPluginStore: " + \ 252 "expected valid EntropyRepositoryPlugin instance") 253 EntropyPluginStore.add_plugin(self, inst.get_id(), inst) 254 inst.add_plugin_hook(self)
255
256 - def remove_plugin(self, plugin_id):
257 """ 258 Overloaded from EntropyPluginStore, adds support for hooks execution. 259 """ 260 plugins = self.get_plugins() 261 plug_inst = plugins.get(plugin_id) 262 if plug_inst is not None: 263 plug_inst.remove_plugin_hook(self) 264 return EntropyPluginStore.remove_plugin(self, plugin_id)
265 266 @staticmethod
267 - def add_permanent_plugin(entropy_repository_plugin):
268 """ 269 Add EntropyRepository permanent plugin. This plugin object will be 270 used across all the instantiated EntropyRepositoryPluginStore classes. 271 Each time a new instance is created, add_plugin_hook will be executed 272 for all the permanent plugins. 273 274 @param entropy_repository_plugin: EntropyRepositoryPlugin instance 275 @type entropy_repository_plugin: EntropyRepositoryPlugin instance 276 """ 277 inst = entropy_repository_plugin 278 if not isinstance(inst, EntropyRepositoryPlugin): 279 raise AttributeError("EntropyRepositoryPluginStore: " + \ 280 "expected valid EntropyRepositoryPlugin instance") 281 EntropyRepositoryPluginStore._PERMANENT_PLUGINS[inst.get_id()] = inst
282 283 @staticmethod
284 - def remove_permanent_plugin(plugin_id):
285 """ 286 Remove EntropyRepository permanent plugin. This plugin object will be 287 removed across all the EntropyRepository instances around. 288 Please note: due to the fact that there are no destructors around, 289 the "remove_plugin_hook" callback won't be executed when calling this 290 static method. 291 292 @param plugin_id: EntropyRepositoryPlugin identifier 293 @type plugin_id: string 294 @raise KeyError: in case of unavailable plugin identifier 295 """ 296 del EntropyRepositoryPluginStore._PERMANENT_PLUGINS[plugin_id]
297 298 @staticmethod
300 """ 301 Return EntropyRepositoryStore installed permanent plugins. 302 303 @return: copy of internal permanent plugins dict 304 @rtype: dict 305 """ 306 return EntropyRepositoryPluginStore._PERMANENT_PLUGINS.copy()
307
308 - def get_plugins(self):
309 """ 310 Overloaded from EntropyPluginStore, adds support for permanent plugins. 311 """ 312 plugins = EntropyPluginStore.get_plugins(self) 313 plugins.update(EntropyRepositoryPluginStore.get_permanent_plugins()) 314 return plugins
315
316 - def get_plugins_metadata(self):
317 """ 318 Return EntropyRepositoryPluginStore registered plugins metadata. 319 320 @return: plugins metadata 321 @rtype: dict 322 """ 323 plugins = self.get_plugins() 324 meta = {} 325 for plugin_id in plugins: 326 meta.update(plugins[plugin_id].get_metadata()) 327 return meta
328
329 - def get_plugin_metadata(self, plugin_id, key):
330 """ 331 Return EntropyRepositoryPlugin metadata value referenced by "key". 332 333 @param plugin_id. EntropyRepositoryPlugin identifier 334 @type plugin_id: string 335 @param key: EntropyRepositoryPlugin metadatum identifier 336 @type key: string 337 @return: metadatum value 338 @rtype: any Python object 339 @raise KeyError: if provided key or plugin_id is not available 340 """ 341 plugins = self.get_plugins() 342 return plugins[plugin_id][key]
343
344 - def set_plugin_metadata(self, plugin_id, key, value):
345 """ 346 Set EntropyRepositoryPlugin stored metadata. 347 348 @param plugin_id. EntropyRepositoryPlugin identifier 349 @type plugin_id: string 350 @param key: EntropyRepositoryPlugin metadatum identifier 351 @type key: string 352 @param value: value to set 353 @type value: any valid Python object 354 @raise KeyError: if plugin_id is not available 355 """ 356 plugins = self.get_plugins() 357 meta = plugins[plugin_id].get_metadata() 358 meta[key] = value
359
360 361 -class EntropyRepositoryBase(TextInterface, EntropyRepositoryPluginStore):
362 """ 363 EntropyRepository interface base class. 364 This is an abstact class containing abstract methods that 365 subclasses need to reimplement. 366 Every Entropy repository object has to inherit this class. 367 """ 368 369 VIRTUAL_META_PACKAGE_CATEGORY = "virtual" 370 # You can extend this with custom settings for your Repository 371 SETTING_KEYS = ("arch", "schema_revision") 372
373 - class ModuleProxy(object):
374 375 @staticmethod
376 - def get():
377 """ 378 Lazily load the Repository module. 379 """ 380 raise NotImplementedError()
381 382 @staticmethod
383 - def exceptions():
384 """ 385 Get the Repository exceptions module. 386 """ 387 raise NotImplementedError()
388 389 @staticmethod
390 - def errno():
391 """ 392 Get the Repository errno module. 393 """ 394 raise NotImplementedError()
395 396
397 - def __init__(self, readonly, xcache, temporary, name, direct=False, 398 cache_policy=None):
399 """ 400 EntropyRepositoryBase constructor. 401 402 @param readonly: readonly bit 403 @type readonly: bool 404 @param xcache: xcache bit (enable on-disk cache?) 405 @type xcache: bool 406 @param temporary: is this repo a temporary (non persistent) one? 407 @type temporary: bool 408 @param name: repository identifier (or name) 409 @type name: string 410 @keyword direct: True, if direct mode should be always enabled 411 @type direct: bool 412 """ 413 self._tls = threading.local() 414 self._direct_enabled = direct 415 if cache_policy is None: 416 cache_policy = EntropyRepositoryCachePolicies.DEFAULT_CACHE_POLICY 417 self._cache_policy = cache_policy 418 419 TextInterface.__init__(self) 420 self._readonly = readonly 421 self._caching = xcache 422 self._temporary = temporary 423 self.name = name 424 # backward compatibility 425 self.reponame = name 426 self._settings = SystemSettings() 427 self._cacher = EntropyCacher() 428 self.__db_match_cache_key = "match/db" 429 430 EntropyRepositoryPluginStore.__init__(self)
431
432 - def lock_path(self):
433 """ 434 Return the path of the file lock for this repository. 435 """ 436 return os.path.join( 437 etpConst['entropyrundir'], 438 "repository", self.name + ".lock")
439 440 @contextlib.contextmanager
441 - def direct(self):
442 """ 443 Avoid acquiring any kind of lock, disable caches and access directly 444 to the underlying repository data. 445 446 In latency sensitive code paths, acquiring locks (especially file locks) 447 and blocking may be impractical. This context manager makes possible to 448 avoid that, at the price of returning stale or null data. 449 450 This method uses Thread Local Storage. In order to determine if 451 direct mode is enabled, just call directed(). 452 memory cache is not cleared by this method, but both shared() and 453 exclusive() do that. 454 Nested calls are reference counted, so it's possible to enter the 455 direct() context more than once (in a nested way) without problems. 456 457 This method exists because some subclasses may have implemented their 458 own in-memory caches and if the locks aren't acquired, they may contain 459 stale data. However, keeping the cache clear may result in a big 460 performance penalty due to the fact that cold caches kill latency. 461 """ 462 counter = getattr(self._tls, "_EntropyRepositoryCacheCounter", 0) 463 self._tls._EntropyRepositoryCacheCounter = counter + 1 464 465 try: 466 yield 467 finally: 468 self._tls._EntropyRepositoryCacheCounter -= 1
469
470 - def cache_policy(self):
471 """ 472 Return the currently set in-RAM cache policy. 473 """ 474 return self._cache_policy
475
476 - def cache_policy_all(self):
477 """ 478 Return whether the cache policy is EntropyRepositoryCachePolicies.ALL. 479 """ 480 return self.cache_policy() == EntropyRepositoryCachePolicies.ALL
481
482 - def cache_policy_none(self):
483 """ 484 Return whether the cache policy is EntropyRepositoryCachePolicies.NONE. 485 """ 486 return self.cache_policy() == EntropyRepositoryCachePolicies.NONE
487
488 - def directed(self):
489 """ 490 Return whether direct mode is enabled or not for the current thread. 491 See direct() for more information. 492 """ 493 if self._direct_enabled: 494 return True 495 return getattr(self._tls, "_EntropyRepositoryCacheCounter", 0) != 0
496 497 @contextlib.contextmanager
498 - def shared(self):
499 """ 500 Acquire a shared file lock for this repository (context manager). 501 This is used for inter-process synchronization only. 502 503 This locking infrastructure assumes that resources initialized during 504 object instantiation are valid throughout the whole object lifecycle. 505 If this is not the case, please synchronize using the Entropy Resources 506 Lock. 507 508 If direct mode is enabled, this method is a no-op. 509 """ 510 opaque = None 511 try: 512 opaque = self.try_acquire_shared() 513 if opaque is None: 514 lock_path = self.lock_path() 515 516 self.output( 517 "%s %s ..." % ( 518 darkred(_("Acquiring shared lock on")), 519 darkgreen(lock_path), 520 ), 521 level = "warning", # use stderr, avoid breaking --quiet 522 back = True, 523 importance = 0) 524 525 opaque = self.acquire_shared() 526 527 self.output( 528 "%s %s" % ( 529 darkred(_("Acquired shared lock on")), 530 darkgreen(lock_path), 531 ), 532 level = "warning", # use stderr, avoid breaking --quiet 533 back = True, 534 importance = 0) 535 536 yield 537 538 finally: 539 if opaque is not None: 540 self.release_shared(opaque)
541 542 @contextlib.contextmanager
543 - def exclusive(self):
544 """ 545 Acquire an exclusive file lock for this repository (context manager). 546 This is used for inter-process synchronization only. 547 548 This locking infrastructure assumes that resources initialized during 549 object instantiation are valid throughout the whole object lifecycle. 550 If this is not the case, please synchronize using the Entropy Resources 551 Lock. 552 553 If direct mode is enabled, this method is a no-op. 554 """ 555 opaque = None 556 try: 557 opaque = self.try_acquire_exclusive() 558 if opaque is None: 559 lock_path = self.lock_path() 560 561 self.output( 562 "%s %s ..." % ( 563 darkred(_("Acquiring exclusive lock on")), 564 darkgreen(lock_path), 565 ), 566 level = "warning", # use stderr, avoid breaking --quiet 567 back = True, 568 importance = 0) 569 570 opaque = self.acquire_exclusive() 571 572 self.output( 573 "%s %s" % ( 574 darkred(_("Acquired exclusive lock on")), 575 darkgreen(lock_path), 576 ), 577 level = "warning", # use stderr, avoid breaking --quiet 578 back = True, 579 importance = 0) 580 581 yield 582 583 finally: 584 if opaque is not None: 585 self.release_exclusive(opaque)
586
587 - def acquire_shared(self):
588 """ 589 Acquire a shared file lock for this repository. 590 This is used for inter-process synchronization only. 591 592 This locking infrastructure assumes that resources initialized during 593 object instantiation are valid throughout the whole object lifecycle. 594 If this is not the case, please synchronize using the Entropy Resources 595 Lock. 596 597 The only effect of not using these synchronization methods is that 598 stale results, incomplete results, None (in case of using a no 599 longer valid package id, for instance) could be returned by methods. 600 If your code can deal with such conditions, it is perfectly fine to 601 avoid locking. 602 603 If direct mode is enabled, this method is a no-op. 604 605 This method can raise entropy.db.exceptions.LockAcquireError in 606 case of lock acquisition errors. 607 608 @return: an opaque that must be used to release the lock. 609 @rtype: object 610 """ 611 raise NotImplementedError()
612
613 - def acquire_exclusive(self):
614 """ 615 Acquire an exclusive file lock for this repository. 616 This is used for inter-process synchronization only. 617 618 This locking infrastructure assumes that resources initialized during 619 object instantiation are valid throughout the whole object lifecycle. 620 If this is not the case, please synchronize using the Entropy Resources 621 Lock. 622 623 The only effect of not using these synchronization methods is that 624 stale results, incomplete results, None (in case of using a no 625 longer valid package id, for instance) could be returned by methods. 626 If your code can deal with such conditions, it is perfectly fine to 627 avoid locking. 628 629 If direct mode is enabled, this method is a no-op. 630 631 This method can raise entropy.db.exceptions.LockAcquireError in 632 case of lock acquisition errors. 633 634 @return: an opaque that must be used to release the lock. 635 @rtype: object 636 """ 637 raise NotImplementedError()
638
639 - def try_acquire_shared(self):
640 """ 641 Try to acquire a shared file lock for this repository. 642 This is used for inter-process synchronization only. 643 644 This locking infrastructure assumes that resources initialized during 645 object instantiation are valid throughout the whole object lifecycle. 646 If this is not the case, please synchronize using the Entropy Resources 647 Lock. 648 649 The only effect of not using these synchronization methods is that 650 stale results, incomplete results, None (in case of using a no 651 longer valid package id, for instance) could be returned by methods. 652 If your code can deal with such conditions, it is perfectly fine to 653 avoid locking. 654 655 If direct mode is enabled, this method is a no-op. 656 657 This method can raise entropy.db.exceptions.LockAcquireError in 658 case of lock acquisition errors. 659 660 @return: an opaque object that must be used to release the lock, None 661 otherwise. 662 @rtype: object or None 663 """ 664 raise NotImplementedError()
665
666 - def try_acquire_exclusive(self):
667 """ 668 Try to acquire an exclusive file lock for this repository. 669 This is used for inter-process synchronization only. 670 671 This locking infrastructure assumes that resources initialized during 672 object instantiation are valid throughout the whole object lifecycle. 673 If this is not the case, please synchronize using the Entropy Resources 674 Lock. 675 676 The only effect of not using these synchronization methods is that 677 stale results, incomplete results, None (in case of using a no 678 longer valid package id, for instance) could be returned by methods. 679 If your code can deal with such conditions, it is perfectly fine to 680 avoid locking. 681 682 If direct mode is enabled, this method is a no-op. 683 684 This method can raise entropy.db.exceptions.LockAcquireError in 685 case of lock acquisition errors. 686 687 @return: an opaque object that must be used to release the lock, None 688 otherwise. 689 @rtype: object or None 690 """ 691 raise NotImplementedError()
692
693 - def release_shared(self, opaque):
694 """ 695 Release the previously acquired shared file lock for this repository. 696 This is used for inter-process synchronization only. 697 698 Make sure to commit any pending transaction before releasing the lock. 699 700 The only effect of not using these synchronization methods is that 701 stale results, incomplete results, None (in case of using a no 702 longer valid package id, for instance) could be returned by methods. 703 If your code can deal with such conditions, it is perfectly fine to 704 avoid locking. 705 706 If direct mode is enabled, this method is a no-op. 707 708 @param opaque: the opaque object returned by *acquire_shared methods. 709 @type opaque: object 710 """ 711 raise NotImplementedError()
712
713 - def release_exclusive(self, opaque):
714 """ 715 Release the previously acquired exclusive file lock for this repository. 716 This is used for inter-process synchronization only. 717 718 Make sure to commit any pending transaction before releasing the lock. 719 720 The only effect of not using these synchronization methods is that 721 stale results, incomplete results, None (in case of using a no 722 longer valid package id, for instance) could be returned by methods. 723 If your code can deal with such conditions, it is perfectly fine to 724 avoid locking. 725 726 If direct mode is enabled, this method is a no-op. 727 728 This method can raise entropy.db.exceptions.LockAcquireError in 729 case of lock acquisition errors. 730 731 @param opaque: the opaque object returned by *acquire_exclusive methods. 732 @type opaque: object 733 """ 734 raise NotImplementedError()
735
736 - def caching(self):
737 """ 738 Return whether caching is enabled in this repository. 739 740 @return: True, if caching is enabled 741 @rtype: bool 742 """ 743 return self._caching
744
745 - def temporary(self):
746 """ 747 Return wheter the repository is temporary (in-memory, for example). 748 749 @return: True, if repository is temporary 750 @rtype: bool 751 """ 752 return self._temporary
753
754 - def readonly(self):
755 """ 756 Return whether the repository is read-only. 757 This method shall always check real access 758 permissions. 759 760 @return: True, if repository is read-only 761 @rtype: bool 762 """ 763 return self._readonly
764
765 - def repository_id(self):
766 """ 767 Return the repository identifier assigned to this instance. 768 769 @return: the repository identifier 770 @rtype: string 771 """ 772 return self.name
773
774 - def close(self, safe=False):
775 """ 776 Close repository storage communication and open disk files. 777 You can still use this instance, but closed files will be reopened. 778 Attention: call this method from your subclass, otherwise 779 EntropyRepositoryPlugins won't be notified of a repo close. 780 781 @param safe: if True, the MainThread resources won't be 782 released. This is vital if both MainThread and a random 783 thread access the Repository concurrently. With safe=False 784 (original behaviour) MainThread cursors may become invalid 785 and cause random exceptions in a racey fashion. 786 But on the other hand, if closing all the resources is what 787 is really wanted, safe must be False, or the MainThread ones 788 will be never released. 789 @type safe: bool 790 """ 791 if not self._readonly: 792 self.commit() 793 794 plugins = self.get_plugins() 795 for plugin_id in sorted(plugins): 796 plug_inst = plugins[plugin_id] 797 exec_rc = plug_inst.close_repo_hook(self) 798 if exec_rc: 799 raise RepositoryPluginError( 800 "[close_repo_hook] %s: status: %s" % ( 801 plug_inst.get_id(), exec_rc,))
802
803 - def vacuum(self):
804 """ 805 Repository storage cleanup and optimization function. 806 """ 807 raise NotImplementedError()
808
809 - def commit(self, force = False, no_plugins = False):
810 """ 811 Commit actual changes and make them permanently stored. 812 Attention: call this method from your subclass, otherwise 813 EntropyRepositoryPlugins won't be notified. 814 815 @keyword force: force commit, despite read-only bit being set 816 @type force: bool 817 @keyword no_plugins: disable EntropyRepository plugins execution 818 @type no_plugins: bool 819 """ 820 if no_plugins: 821 return 822 823 plugins = self.get_plugins() 824 for plugin_id in sorted(plugins): 825 plug_inst = plugins[plugin_id] 826 exec_rc = plug_inst.commit_hook(self) 827 if exec_rc: 828 raise RepositoryPluginError("[commit_hook] %s: status: %s" % ( 829 plug_inst.get_id(), exec_rc,))
830
831 - def rollback(self):
832 """ 833 Rollback last transaction, if it hasn't been already committed. 834 """ 835 raise NotImplementedError()
836
837 - def initializeRepository(self):
838 """ 839 This method (re)initializes the repository, dropping all its content. 840 Attention: call this method from your subclass, otherwise 841 EntropyRepositoryPlugins won't be notified (AT THE END). 842 """ 843 plugins = self.get_plugins() 844 for plugin_id in sorted(plugins): 845 plug_inst = plugins[plugin_id] 846 exec_rc = plug_inst.initialize_repo_hook(self) 847 if exec_rc: 848 raise RepositoryPluginError( 849 "[initialize_repo_hook] %s: status: %s" % ( 850 plug_inst.get_id(), exec_rc,))
851
852 - def filterTreeUpdatesActions(self, actions):
853 """ 854 This method should be considered internal and not suited for general 855 audience. Given a raw package name/slot updates list, it returns 856 the action that should be really taken because not applied. 857 858 @param actions: list of raw treeupdates actions, for example: 859 ['move x11-foo/bar app-foo/bar', 'slotmove x11-foo/bar 2 3'] 860 @type actions: list 861 @return: list of raw treeupdates actions that should be really 862 worked out 863 @rtype: list 864 """ 865 866 # pre-filter: 867 # discard any f(a -> b) if f(b -> a) 868 filtered_actions = collections.OrderedDict() 869 filtered_cache = set() 870 for action in actions: 871 872 # filter duplicates 873 if action in filtered_cache: 874 continue 875 filtered_cache.add(action) 876 877 parts = action.split() 878 try: 879 cmd, args = parts[0], parts[1:] 880 except (IndexError, ValueError): 881 entropy.tools.print_traceback() 882 continue 883 884 action_key = (cmd, tuple(sorted(args))) 885 filtered_action = filtered_actions.get(action_key) 886 if filtered_action is None: 887 filtered_actions[action_key] = (action, cmd, args) 888 continue 889 890 # cases: 891 # a -> b and a -> b already stored: skip 892 # a -> b and b -> a already stored: replace 893 _ignore, _ignore, act_args = filtered_action 894 replace = False 895 if act_args == args: 896 # a -> b and a -> b already stored 897 # this is unlikely to happen, but better safe than sorry 898 pass 899 elif cmd == "move": 900 replace = args == list(reversed(act_args)) 901 elif cmd == "slotmove": 902 dep, from_slot, to_slot = args 903 replace = [dep, to_slot, from_slot] == act_args 904 905 if replace: 906 const_debug_write(__name__, "%s: replacing: %s with %s" % ( 907 self.name, act_args, args)) 908 # a -> b and b -> a already stored 909 del filtered_actions[action_key] # discard order 910 filtered_actions[action_key] = (action, cmd, args) 911 912 new_actions = [] 913 pkg_id_slotmove_actions = {} 914 for action_key in filtered_actions: 915 916 action, cmd, args = filtered_actions[action_key] 917 if action in new_actions: # skip dupies 918 continue 919 920 if cmd == "slotmove": 921 922 # slot move 923 atom, from_slot, to_slot = args 924 atom_key = entropy.dep.dep_getkey(atom) 925 category = atom_key.split("/")[0] 926 matches, sm_rc = self.atomMatch(atom, matchSlot = from_slot, 927 multiMatch = True, maskFilter = False) 928 929 if sm_rc == 1: 930 # before giving up, check if we scheduled another 931 # slotmove that undoes it, use to_slot. 932 # This is a PMS violation, but on 2013-12-18 it was found 933 # that somebody managed to commit this. 934 # 2Q-2013: profiles/updates/2Q-2013?r1=1.1&r2=1.2 935 # 4Q-2013: profiles/updates/4Q-2013?r1=1.1&r2=1.2 936 matches, sm_rc = self.atomMatch( 937 atom, matchSlot = to_slot, 938 multiMatch = True, maskFilter = False) 939 940 for package_id in matches: 941 pkg_slotmove = pkg_id_slotmove_actions.get(package_id) 942 if pkg_slotmove is None: 943 continue 944 (old_from_slot, old_to_slot, old_action) = pkg_slotmove 945 if (to_slot, from_slot) == (old_from_slot, old_to_slot): 946 # bingo, this is a PMS violation we need to deal 947 # with. 948 self.output( 949 "QA: '%s' overrides an old slotmove (%s)" % ( 950 action, old_action), 951 importance = 1, 952 level = "error", 953 header = darkred(" !!! ") 954 ) 955 try: 956 new_actions.remove(old_action) 957 except ValueError: 958 pass 959 960 continue 961 962 if sm_rc == 1: 963 # nothing found in repo that matches atom 964 # this means that no packages can effectively 965 # reference to it 966 continue 967 968 found = False 969 # found atoms, check category 970 for package_id in matches: 971 myslot = self.retrieveSlot(package_id) 972 mycategory = self.retrieveCategory(package_id) 973 if mycategory == category: 974 if (myslot != to_slot) and \ 975 (action not in new_actions): 976 pkg_id_slotmove_actions[package_id] = ( 977 from_slot, to_slot, action) 978 979 new_actions.append(action) 980 found = True 981 break 982 if found: 983 continue 984 # if we get here it means found == False 985 # search into dependencies 986 dep_atoms = self.searchDependency(atom_key, like = True, 987 multi = True, strings = True) 988 dep_atoms = [x for x in dep_atoms if x.endswith(":"+from_slot) \ 989 and entropy.dep.dep_getkey(x) == atom_key] 990 if dep_atoms: 991 new_actions.append(action) 992 993 elif cmd == "move": 994 995 atom = args[0] # usually a key 996 atom_key = entropy.dep.dep_getkey(atom) 997 category = atom_key.split("/")[0] 998 matches, m_rc = self.atomMatch(atom, multiMatch = True, 999 maskFilter = False) 1000 if m_rc == 1: 1001 # nothing found in repo that matches atom 1002 # this means that no packages can effectively 1003 # reference to it 1004 continue 1005 found = False 1006 for package_id in matches: 1007 mycategory = self.retrieveCategory(package_id) 1008 if (mycategory == category) and (action \ 1009 not in new_actions): 1010 new_actions.append(action) 1011 found = True 1012 break 1013 if found: 1014 continue 1015 # if we get here it means found == False 1016 # search into dependencies 1017 dep_atoms = self.searchDependency(atom_key, like = True, 1018 multi = True, strings = True) 1019 dep_atoms = [x for x in dep_atoms if \ 1020 entropy.dep.dep_getkey(x) == atom_key] 1021 if dep_atoms: 1022 new_actions.append(action) 1023 1024 return new_actions
1025
1026 - def handlePackage(self, pkg_data, revision = None, 1027 formattedContent = False):
1028 """ 1029 Update or add a package to repository automatically handling 1030 its scope and thus removal of previous versions if requested by 1031 the given metadata. 1032 pkg_data is a dict() containing all the information bound to 1033 a package: 1034 1035 { 1036 'signatures': 1037 { 1038 'sha256': 'zzz', 1039 'sha1': 'zzz', 1040 'sha512': 'zzz' 1041 }, 1042 'slot': '0', 1043 'datecreation': '1247681752.93', 1044 'description': 'Standard (de)compression library', 1045 'useflags': set(['kernel_linux']), 1046 'config_protect_mask': 'string string', 'etpapi': 3, 1047 'mirrorlinks': [], 1048 'cxxflags': '-Os -march=x86-64 -pipe', 1049 'injected': False, 1050 'licensedata': {'ZLIB': u"lictext"}, 1051 'pkg_dependencies': tuple(), 1052 'chost': 'x86_64-pc-linux-gn', 1053 'config_protect': 'string string', 1054 'download': 'packages/amd64/4/sys-libs:zlib-1.2.3-r1.tbz2', 1055 'conflicts': set([]), 1056 'digest': 'fd54248ae060c287b1ec939de3e55332', 1057 'size': '136302', 1058 'category': 'sys-libs', 1059 'license': 'ZLIB', 1060 'sources': set(), 1061 'name': 'zlib', 1062 'versiontag': '', 1063 'changelog': u"text", 1064 'provide_extended': set([]), 1065 'trigger': 'text', 1066 'counter': 22331, 1067 'branch': '4', 1068 'content': {}, 1069 'content_safety': {}, 1070 'needed_libs': [('/usr/bin/foo', 'foo', 'libc.so.6', 2, '')], 1071 'version': '1.2.3-r1', 1072 'keywords': set(), 1073 'cflags': '-Os -march=x86-64 -pipe', 1074 'disksize': 932206, 'spm_phases': None, 1075 'homepage': 'http://www.zlib.net/', 1076 'systempackage': True, 1077 'revision': 0 1078 } 1079 1080 @param pkg_data: Entropy package metadata dict 1081 @type pkg_data: dict 1082 @keyword revision: force a specific package revision 1083 @type revision: int 1084 @keyword formattedContent: tells whether content metadata is already 1085 formatted for insertion 1086 @type formattedContent: bool 1087 @return: package identifier 1088 @rtype: int 1089 """ 1090 raise NotImplementedError()
1091
1092 - def getPackagesToRemove(self, name, category, slot, injected):
1093 """ 1094 Return a list of packages that would be removed given name, category, 1095 slot and injection status. 1096 1097 @param name: package name 1098 @type name: string 1099 @param category: package category 1100 @type category: string 1101 @param slot: package slot 1102 @type slot: string 1103 @param injected: injection status (packages marked as injected are 1104 always considered not automatically removable) 1105 @type injected: bool 1106 1107 @return: list (set) of removable packages (package_ids) 1108 @rtype: set 1109 """ 1110 removelist = set() 1111 if injected: 1112 # read: if package has been injected, we'll skip 1113 # the removal of packages in the same slot, 1114 # usually used server side btw 1115 return removelist 1116 1117 searchsimilar = self.searchNameCategory(name, category) 1118 1119 # support for expiration-based packages handling, also internally 1120 # called Fat Scope. 1121 filter_similar = False 1122 srv_ss_plg = etpConst['system_settings_plugins_ids']['server_plugin'] 1123 srv_ss_fs_plg = \ 1124 etpConst['system_settings_plugins_ids']['server_plugin_fatscope'] 1125 1126 srv_plug_settings = self._settings.get(srv_ss_plg) 1127 if srv_plug_settings is not None: 1128 if srv_plug_settings['server']['exp_based_scope']: 1129 # in case support is enabled, return an empty set 1130 filter_similar = True 1131 1132 if filter_similar: 1133 # filter out packages in the same scope that are allowed to stay 1134 idpkgs = self._settings[srv_ss_fs_plg]['repos'].get( 1135 self.name) 1136 if idpkgs: 1137 if -1 in idpkgs: 1138 searchsimilar = [] 1139 else: 1140 searchsimilar = [x for x in searchsimilar if x[1] \ 1141 not in idpkgs] 1142 1143 for atom, package_id in searchsimilar: 1144 # get the package slot 1145 myslot = self.retrieveSlot(package_id) 1146 # we merely ignore packages with 1147 # negative counters, since they're the injected ones 1148 if self.isInjected(package_id): 1149 continue 1150 if slot == myslot: 1151 # remove! 1152 removelist.add(package_id) 1153 1154 return removelist
1155
1156 - def addPackage(self, pkg_data, revision = -1, package_id = None, 1157 formatted_content = False):
1158 """ 1159 Add package to this Entropy repository. The main difference between 1160 handlePackage and this is that from here, no packages are going to be 1161 removed, in any case. 1162 For more information about pkg_data layout, please see 1163 I{handlePackage()}. 1164 Attention: call this method from your subclass (AT THE END), otherwise 1165 EntropyRepositoryPlugins won't be notified. 1166 1167 @param pkg_data: Entropy package metadata 1168 @type pkg_data: dict 1169 @keyword revision: force a specific Entropy package revision 1170 @type revision: int 1171 @keyword package_id: add package to Entropy repository using the 1172 provided package identifier, this is very dangerous and could 1173 cause packages with the same identifier to be removed. 1174 @type package_id: int 1175 @keyword formatted_content: if True, determines whether the content 1176 metadata (usually the biggest part) in pkg_data is already 1177 prepared for insertion 1178 @type formatted_content: bool 1179 @return: new package identifier 1180 @rtype: int 1181 """ 1182 plugins = self.get_plugins() 1183 for plugin_id in sorted(plugins): 1184 plug_inst = plugins[plugin_id] 1185 exec_rc = plug_inst.add_package_hook(self, package_id, pkg_data) 1186 if exec_rc: 1187 raise RepositoryPluginError( 1188 "[add_package_hook] %s: status: %s" % ( 1189 plug_inst.get_id(), exec_rc,))
1190
1191 - def removePackage(self, package_id, from_add_package = False):
1192 """ 1193 Remove package from this Entropy repository using it's identifier 1194 (package_id). 1195 Attention: call this method from your subclass, otherwise 1196 EntropyRepositoryPlugins won't be notified. 1197 1198 @param package_id: Entropy repository package indentifier 1199 @type package_id: int 1200 @keyword from_add_package: inform function that it's being called from 1201 inside addPackage(). 1202 @type from_add_package: bool 1203 """ 1204 plugins = self.get_plugins() 1205 for plugin_id in sorted(plugins): 1206 plug_inst = plugins[plugin_id] 1207 exec_rc = plug_inst.remove_package_hook(self, package_id, 1208 from_add_package) 1209 if exec_rc: 1210 raise RepositoryPluginError( 1211 "[remove_package_hook] %s: status: %s" % ( 1212 plug_inst.get_id(), exec_rc,))
1213
1214 - def setInjected(self, package_id):
1215 """ 1216 Mark package as injected, injection is usually set for packages 1217 manually added to repository. Injected packages are not removed 1218 automatically even when featuring conflicting scope with other 1219 that are being added. If a package is injected, it means that 1220 maintainers have to handle it manually. 1221 1222 @param package_id: package indentifier 1223 @type package_id: int 1224 """ 1225 raise NotImplementedError()
1226
1227 - def setCreationDate(self, package_id, date):
1228 """ 1229 Update the creation date for package. Creation date is stored in 1230 string based unix time format. 1231 1232 @param package_id: package indentifier 1233 @type package_id: int 1234 @param date: unix time in string form 1235 @type date: string 1236 """ 1237 raise NotImplementedError()
1238
1239 - def setDigest(self, package_id, digest):
1240 """ 1241 Set package file md5sum for package. This information is used 1242 by entropy.client when downloading packages. 1243 1244 @param package_id: package indentifier 1245 @type package_id: int 1246 @param digest: md5 hash for package file 1247 @type digest: string 1248 """ 1249 raise NotImplementedError()
1250
1251 - def setSignatures(self, package_id, sha1, sha256, sha512, gpg = None):
1252 """ 1253 Set package file extra hashes (sha1, sha256, sha512) for package. 1254 1255 @param package_id: package indentifier 1256 @type package_id: int 1257 @param sha1: SHA1 hash for package file 1258 @type sha1: string 1259 @param sha256: SHA256 hash for package file 1260 @type sha256: string 1261 @param sha512: SHA512 hash for package file 1262 @type sha512: string 1263 @keyword gpg: GPG signature file content 1264 @type gpg: string 1265 """ 1266 raise NotImplementedError()
1267
1268 - def setDownloadURL(self, package_id, url):
1269 """ 1270 Set download URL prefix for package. 1271 1272 @param package_id: package indentifier 1273 @type package_id: int 1274 @param url: URL prefix to set 1275 @type url: string 1276 """ 1277 raise NotImplementedError()
1278
1279 - def setName(self, package_id, name):
1280 """ 1281 Set name for package. 1282 1283 @param package_id: package indentifier 1284 @type package_id: int 1285 @param name: package name 1286 @type name: string 1287 """ 1288 raise NotImplementedError()
1289
1290 - def setAtom(self, package_id, atom):
1291 """ 1292 Set atom string for package. "Atom" is the full, unique name of 1293 a package. 1294 1295 @param package_id: package indentifier 1296 @type package_id: int 1297 @param atom: atom string 1298 @type atom: string 1299 """ 1300 raise NotImplementedError()
1301
1302 - def setSlot(self, package_id, slot):
1303 """ 1304 Set slot string for package. Please refer to Portage SLOT documentation 1305 for more info. 1306 1307 @param package_id: package indentifier 1308 @type package_id: int 1309 @param slot: slot string 1310 @type slot: string 1311 """ 1312 raise NotImplementedError()
1313
1314 - def setDependency(self, iddependency, dependency):
1315 """ 1316 Set dependency string for iddependency (dependency identifier). 1317 1318 @param iddependency: dependency string identifier 1319 @type iddependency: int 1320 @param dependency: dependency string 1321 @type dependency: string 1322 """ 1323 raise NotImplementedError()
1324
1325 - def setCategory(self, package_id, category):
1326 """ 1327 Set category name for package. 1328 1329 @param package_id: package indentifier 1330 @type package_id: int 1331 @param category: category to set 1332 @type category: string 1333 """ 1334 raise NotImplementedError()
1335
1336 - def setCategoryDescription(self, category, description_data):
1337 """ 1338 Set description for given category name. 1339 1340 @param category: category name 1341 @type category: string 1342 @param description_data: category description for several locales. 1343 {'en': "This is blah", 'it': "Questo e' blah", ... } 1344 @type description_data: dict 1345 """ 1346 raise NotImplementedError()
1347
1348 - def setRevision(self, package_id, revision):
1349 """ 1350 Set Entropy revision for package. 1351 1352 @param package_id: package indentifier 1353 @type package_id: int 1354 @param revision: new revision 1355 @type revision: int 1356 """ 1357 raise NotImplementedError()
1358
1359 - def setContentSafety(self, package_id, content_safety):
1360 """ 1361 Set (overwriting previous entries) new content safety metadata. 1362 1363 @param package_id: package indentifier 1364 @type package_id: int 1365 @param content_safety: dictionary with the same data structure of the 1366 one returned by retrieveContentSafety() 1367 @type content_safety: dict 1368 """ 1369 raise NotImplementedError()
1370
1371 - def removeDependencies(self, package_id):
1372 """ 1373 Remove all the dependencies of package. 1374 1375 @param package_id: package indentifier 1376 @type package_id: int 1377 """ 1378 raise NotImplementedError()
1379
1380 - def insertDependencies(self, package_id, depdata):
1381 """ 1382 Insert dependencies for package. "depdata" is a dict() with dependency 1383 strings as keys and dependency type as values or a sequence of tuples 1384 composed by (dep, dep type). 1385 1386 @param package_id: package indentifier 1387 @type package_id: int 1388 @param depdata: dependency dictionary 1389 {'app-foo/foo': dep_type_integer, ...} 1390 @type depdata: dict 1391 """ 1392 raise NotImplementedError()
1393
1394 - def removeConflicts(self, package_id):
1395 """ 1396 Remove all the conflicts of package. 1397 1398 @param package_id: package indentifier 1399 @type package_id: int 1400 """ 1401 raise NotImplementedError()
1402
1403 - def insertConflicts(self, package_id, conflicts):
1404 """ 1405 Insert dependency conflicts for package. 1406 1407 @param package_id: package indentifier 1408 @type package_id: int 1409 @param conflicts: list of dep. conflicts 1410 @type conflicts: list 1411 """ 1412 raise NotImplementedError()
1413
1414 - def insertContent(self, package_id, content, already_formatted = False):
1415 """ 1416 Insert content metadata for package. "content" can either be a dict() 1417 or a list of triples (tuples of length 3, (package_id, path, type,)). 1418 This method expects Unicode strings. Passing 8-bit raw strings will 1419 cause unpredictable results. 1420 1421 @param package_id: package indentifier 1422 @type package_id: int 1423 @param content: content metadata to insert. 1424 {'/path/to/foo': 'obj(content type)',} 1425 or 1426 [(package_id, path, type,) ...] 1427 @type content: dict, list 1428 @keyword already_formatted: if True, "content" is expected to be 1429 already formatted for insertion, this means that "content" must be 1430 a list of tuples of length 3. 1431 @type already_formatted: bool 1432 """ 1433 raise NotImplementedError()
1434
1435 - def insertAutomergefiles(self, package_id, automerge_data):
1436 """ 1437 Insert configuration files automerge information for package. 1438 "automerge_data" contains configuration files paths and their belonging 1439 md5 hash. 1440 This features allows entropy.client to "auto-merge" or "auto-remove" 1441 configuration files never touched by user. 1442 This method expects Unicode strings. Passing 8-bit raw strings will 1443 cause unpredictable results. 1444 1445 @param package_id: package indentifier 1446 @type package_id: int 1447 @param automerge_data: list of tuples of length 2. 1448 [('/path/to/conf/file', 'md5_checksum_string',) ... ] 1449 @type automerge_data: list 1450 """ 1451 raise NotImplementedError()
1452
1453 - def insertPreservedLibrary(self, library, elfclass, path, atom):
1454 """ 1455 Mark a library as preserved. 1456 1457 @param library: the library name (SONAME) 1458 @type library: string 1459 @param elfclass: the ELF class of the library 1460 @type elfclass: int 1461 @param path: the path where the library is currently stored 1462 @param atom: the atom string of the package providing the library 1463 @type atom: string 1464 """ 1465 raise NotImplementedError()
1466
1467 - def removePreservedLibrary(self, library, elfclass, path):
1468 """ 1469 Remove a previously library marked as preserved. 1470 1471 @param library: the library name (SONAME) 1472 @type library: string 1473 @param elfclass: the ELF class of the library 1474 @type elfclass: int 1475 @param path: the path where the library is currently stored 1476 """ 1477 raise NotImplementedError()
1478
1479 - def listAllPreservedLibraries(self):
1480 """ 1481 Return a list of all the recorded preserved libraries. 1482 1483 @return: a list (tuple) of tuples composed by 1484 (library, elfclass, path, atom). 1485 @rtype: tuple 1486 """ 1487 raise NotImplementedError()
1488
1489 - def retrievePreservedLibraries(self, library, elfclass):
1490 """ 1491 Return a list of paths associated with the given preserved library, 1492 if any. 1493 1494 @return: the list (tuple) of paths associated with a SONAME 1495 and its ELF class. 1496 @rtype: frozenset 1497 """ 1498 raise NotImplementedError()
1499
1500 - def insertBranchMigration(self, repository, from_branch, to_branch, 1501 post_migration_md5sum, post_upgrade_md5sum):
1502 """ 1503 Insert Entropy Client "branch migration" scripts hash metadata. 1504 When upgrading from a branch to another, it can happen that repositories 1505 ship with scripts aiming to ease the upgrade. 1506 This method stores in the repository information on such scripts. 1507 1508 @param repository: repository identifier 1509 @type repository: string 1510 @param from_branch: original branch 1511 @type from_branch: string 1512 @param to_branch: destination branch 1513 @type to_branch: string 1514 @param post_migration_md5sum: md5 hash related to "post-migration" 1515 branch script file 1516 @type post_migration_md5sum: string 1517 @param post_upgrade_md5sum: md5 hash related to "post-upgrade on new 1518 branch" script file 1519 @type post_upgrade_md5sum: string 1520 """ 1521 raise NotImplementedError()
1522
1523 - def setBranchMigrationPostUpgradeMd5sum(self, repository, from_branch, 1524 to_branch, post_upgrade_md5sum):
1525 """ 1526 Update "post-upgrade on new branch" script file md5 hash. 1527 When upgrading from a branch to another, it can happen that repositories 1528 ship with scripts aiming to ease the upgrade. 1529 This method stores in the repository information on such scripts. 1530 1531 @param repository: repository identifier 1532 @type repository: string 1533 @param from_branch: original branch 1534 @type from_branch: string 1535 @param to_branch: destination branch 1536 @type to_branch: string 1537 @param post_upgrade_md5sum: md5 hash related to "post-upgrade on new 1538 branch" script file 1539 @type post_upgrade_md5sum: string 1540 """ 1541 raise NotImplementedError()
1542
1543 - def insertSpmUid(self, package_id, spm_package_uid):
1544 """ 1545 Insert Source Package Manager unique package identifier and bind it 1546 to Entropy package identifier given (package_id). This method is used 1547 by Entropy Client and differs from "_bindSpmPackageUid" because 1548 any other colliding package_id<->uid binding is overwritten by design. 1549 1550 @param package_id: package indentifier 1551 @type package_id: int 1552 @param spm_package_uid: Source package Manager unique package identifier 1553 @type spm_package_uid: int 1554 """ 1555 raise NotImplementedError()
1556
1557 - def setTrashedUid(self, spm_package_uid):
1558 """ 1559 Mark given Source Package Manager unique package identifier as 1560 "trashed". This is a trick to allow Entropy Server to support 1561 multiple repositories and parallel handling of them without 1562 make it messing with removed packages from the underlying system. 1563 1564 @param spm_package_uid: Source package Manager unique package identifier 1565 @type spm_package_uid: int 1566 """ 1567 raise NotImplementedError()
1568
1569 - def removeTrashedUids(self, spm_package_uids):
1570 """ 1571 Remove given Source Package Manager unique package identifiers from 1572 the "trashed" list. This is only used by Entropy Server. 1573 """ 1574 raise NotImplementedError()
1575
1576 - def setSpmUid(self, package_id, spm_package_uid, branch = None):
1577 """ 1578 Update Source Package Manager unique package identifier for given 1579 Entropy package identifier (package_id). 1580 This method *only* updates a currently available binding setting a new 1581 "spm_package_uid" 1582 1583 @param package_id: package indentifier 1584 @type package_id: int 1585 @param spm_package_uid: Source package Manager unique package identifier 1586 @type spm_package_uid: int 1587 @keyword branch: current Entropy repository branch 1588 @type branch: string 1589 """ 1590 raise NotImplementedError()
1591
1592 - def contentDiff(self, package_id, dbconn, dbconn_package_id, 1593 extended = False):
1594 """ 1595 Return content metadata difference between two packages. 1596 1597 @param package_id: package indentifier available in this repository 1598 @type package_id: int 1599 @param dbconn: other repository class instance 1600 @type dbconn: EntropyRepository 1601 @param dbconn_package_id: package identifier available in other 1602 repository 1603 @type dbconn_package_id: int 1604 @keyword extended: also return filetype (it is not considered in 1605 the comparison) 1606 @type extended: bool 1607 @return: content difference 1608 @rtype: frozenset 1609 @raise AttributeError: when self instance and dbconn are the same 1610 """ 1611 raise NotImplementedError()
1612
1613 - def clean(self):
1614 """ 1615 Run repository metadata cleanup over unused references. 1616 """ 1617 raise NotImplementedError()
1618
1619 - def getDependency(self, iddependency):
1620 """ 1621 Return dependency string for given dependency identifier. 1622 1623 @param iddependency: dependency identifier 1624 @type iddependency: int 1625 @return: dependency string 1626 @rtype: string or None 1627 """ 1628 raise NotImplementedError()
1629
1630 - def getFakeSpmUid(self):
1631 """ 1632 Obtain auto-generated available negative Source Package Manager 1633 package identifier. 1634 1635 @return: new negative spm uid 1636 @rtype: int 1637 """ 1638 raise NotImplementedError()
1639
1640 - def getApi(self):
1641 """ 1642 Get Entropy repository API. 1643 1644 @return: Entropy repository API 1645 @rtype: int 1646 """ 1647 raise NotImplementedError()
1648
1649 - def getPackageIds(self, atom):
1650 """ 1651 Obtain repository package identifiers from atom string. 1652 1653 @param atom: package atom 1654 @type atom: string 1655 @return: list of matching package_ids found 1656 @rtype: frozenset 1657 """ 1658 raise NotImplementedError()
1659
1660 - def getPackageIdFromDownload(self, download_relative_path, 1661 endswith = False):
1662 """ 1663 Obtain repository package identifier from its relative download path 1664 string. 1665 1666 @param download_relative_path: relative download path string returned 1667 by "retrieveDownloadURL" method 1668 @type download_relative_path: string 1669 @keyword endswith: search for package_id which download metadata ends 1670 with the one provided by download_relative_path 1671 @type endswith: bool 1672 @return: package_id in repository or -1 if not found 1673 @rtype: int 1674 """ 1675 raise NotImplementedError()
1676
1677 - def getVersioningData(self, package_id):
1678 """ 1679 Get package version information for provided package identifier. 1680 1681 @param package_id: package indentifier 1682 @type package_id: int 1683 @return: tuple of length 3 composed by (version, tag, revision,) 1684 belonging to package_id 1685 @rtype: tuple 1686 """ 1687 raise NotImplementedError()
1688
1689 - def getStrictData(self, package_id):
1690 """ 1691 Get a restricted (optimized) set of package metadata for provided 1692 package identifier. 1693 1694 @param package_id: package indentifier 1695 @type package_id: int 1696 @return: tuple of length 6 composed by 1697 (package key, slot, version, tag, revision, atom) 1698 belonging to package_id 1699 @rtype: tuple 1700 """ 1701 raise NotImplementedError()
1702
1703 - def getStrictScopeData(self, package_id):
1704 """ 1705 Get a restricted (optimized) set of package metadata for provided 1706 identifier that can be used to determine the scope of package. 1707 1708 @param package_id: package indentifier 1709 @type package_id: int 1710 @return: tuple of length 3 composed by (atom, slot, revision,) 1711 belonging to package_id 1712 @rtype: tuple 1713 """ 1714 raise NotImplementedError()
1715
1716 - def getScopeData(self, package_id):
1717 """ 1718 Get a set of package metadata for provided identifier that can be 1719 used to determine the scope of package. 1720 1721 @param package_id: package indentifier 1722 @type package_id: int 1723 @return: tuple of length 9 composed by 1724 (atom, category name, name, version, 1725 slot, tag, revision, branch, api,) 1726 belonging to package_id 1727 @rtype: tuple 1728 """ 1729 raise NotImplementedError()
1730
1731 - def getBaseData(self, package_id):
1732 """ 1733 Get a set of basic package metadata for provided package identifier. 1734 1735 @param package_id: package indentifier 1736 @type package_id: int 1737 @return: tuple of length 19 composed by 1738 (atom, name, version, tag, description, category name, CHOST, 1739 CFLAGS, CXXFLAGS, homepage, license, branch, download path, digest, 1740 slot, api, creation date, package size, revision,) 1741 belonging to package_id 1742 @rtype: tuple 1743 """ 1744 raise NotImplementedError()
1745
1746 - def getTriggerData(self, package_id, content = True):
1747 """ 1748 Get a set of basic package metadata for provided package identifier. 1749 This method is optimized to work with Entropy Client installation 1750 triggers returning only what is strictly needed. 1751 1752 @param package_id: package indentifier 1753 @type package_id: int 1754 @keyword content: if True, grabs the "content" metadata too, othewise 1755 such dict key value will be shown as empty set(). 1756 @type content: bool 1757 @return: dictionary containing package metadata 1758 1759 data = { 1760 'atom': atom, 1761 'category': category, 1762 'name': name, 1763 'version': version, 1764 'slot': slot, 1765 'versiontag': versiontag, 1766 'revision': revision, 1767 'branch': branch, 1768 'chost': chost, 1769 'cflags': cflags, 1770 'cxxflags': cxxflags, 1771 'etpapi': etpapi, 1772 'trigger': self.retrieveTrigger(package_id), 1773 'content': pkg_content, 1774 'spm_phases': self.retrieveSpmPhases(package_id), 1775 } 1776 1777 @rtype: dict or None 1778 """ 1779 scope_data = self.getScopeData(package_id) 1780 if scope_data is None: 1781 return 1782 atom, category, name, \ 1783 version, slot, versiontag, \ 1784 revision, branch, etpapi = scope_data 1785 chost, cflags, cxxflags = self.retrieveCompileFlags(package_id) 1786 1787 pkg_content = set() 1788 if content: 1789 pkg_content = self.retrieveContent(package_id) 1790 1791 data = { 1792 'atom': atom, 1793 'category': category, 1794 'name': name, 1795 'version': version, 1796 'slot': slot, 1797 'versiontag': versiontag, 1798 'revision': revision, 1799 'branch': branch, 1800 'chost': chost, 1801 'cflags': cflags, 1802 'cxxflags': cxxflags, 1803 'etpapi': etpapi, 1804 'trigger': self.retrieveTrigger(package_id), 1805 'content': pkg_content, 1806 'spm_phases': self.retrieveSpmPhases(package_id), 1807 } 1808 return data
1809
1810 - def getPackageData(self, package_id, get_content = True, 1811 content_insert_formatted = False, get_changelog = True, 1812 get_content_safety = True):
1813 """ 1814 Reconstruct all the package metadata belonging to provided package 1815 identifier into a dict object. 1816 1817 @param package_id: package indentifier 1818 @type package_id: int 1819 @keyword get_content: 1820 @type get_content: bool 1821 @keyword content_insert_formatted: 1822 @type content_insert_formatted: bool 1823 @keyword get_changelog: return ChangeLog text metadatum or None 1824 @type get_changelog: bool 1825 @keyword get_content_safety: return content_safety metadata or {} 1826 @type get_content_safety: bool 1827 @return: package metadata in dict() form 1828 1829 >>> data = { 1830 'atom': atom, 1831 'name': name, 1832 'version': version, 1833 'versiontag':versiontag, 1834 'description': description, 1835 'category': category, 1836 'chost': chost, 1837 'cflags': cflags, 1838 'cxxflags': cxxflags, 1839 'homepage': homepage, 1840 'license': mylicense, 1841 'branch': branch, 1842 'download': download, 1843 'digest': digest, 1844 'slot': slot, 1845 'etpapi': etpapi, 1846 'datecreation': datecreation, 1847 'size': size, 1848 'revision': revision, 1849 'counter': self.retrieveSpmUid(package_id), 1850 'trigger': self.retrieveTrigger(package_id), 1851 'disksize': self.retrieveOnDiskSize(package_id), 1852 'changelog': self.retrieveChangelog(package_id), 1853 'injected': self.isInjected(package_id), 1854 'systempackage': self.isSystemPackage(package_id), 1855 'config_protect': self.retrieveProtect(package_id), 1856 'config_protect_mask': self.retrieveProtectMask(package_id), 1857 'useflags': self.retrieveUseflags(package_id), 1858 'keywords': self.retrieveKeywords(package_id), 1859 'sources': sources, 1860 'needed_libs': self.retrieveNeededLibraries(package_id) 1861 'provided_libs': self.retrieveProvidedLibraries(package_id), 1862 'provide_extended': self.retrieveProvide(package_id), 1863 'conflicts': self.retrieveConflicts(package_id), 1864 'licensedata': self.retrieveLicenseData(package_id), 1865 'content': content, 1866 'content_safety': {}, 1867 'pkg_dependencies': self.retrieveDependencies(package_id, 1868 extended = True), 1869 'mirrorlinks': [[x,self.retrieveMirrorData(x)] for x in mirrornames], 1870 'signatures': signatures, 1871 'spm_phases': self.retrieveSpmPhases(package_id), 1872 'spm_repository': self.retrieveSpmRepository(package_id), 1873 'desktop_mime': [], 1874 'provided_mime': [], 1875 'original_repository': self.getInstalledPackageRepository(package_id), 1876 'extra_download': self.retrieveExtraDownload(package_id), 1877 } 1878 1879 @rtype: dict 1880 """ 1881 data = {} 1882 try: 1883 atom, name, version, versiontag, \ 1884 description, category, chost, \ 1885 cflags, cxxflags, homepage, \ 1886 mylicense, branch, download, \ 1887 digest, slot, etpapi, \ 1888 datecreation, size, revision = self.getBaseData(package_id) 1889 except TypeError: 1890 return None 1891 1892 content = {} 1893 if get_content: 1894 content = self.retrieveContent( 1895 package_id, extended = True, 1896 formatted = True, insert_formatted = content_insert_formatted 1897 ) 1898 1899 sources = self.retrieveSources(package_id) 1900 mirrornames = set() 1901 for x in sources: 1902 if x.startswith("mirror://"): 1903 mirrornames.add(x.split("/")[2]) 1904 1905 sha1, sha256, sha512, gpg = self.retrieveSignatures(package_id) 1906 signatures = { 1907 'sha1': sha1, 1908 'sha256': sha256, 1909 'sha512': sha512, 1910 'gpg': gpg, 1911 } 1912 1913 changelog = None 1914 if get_changelog: 1915 changelog = self.retrieveChangelog(package_id) 1916 content_safety = {} 1917 if get_content_safety: 1918 content_safety = self.retrieveContentSafety(package_id) 1919 1920 deps = self.retrieveDependencies( 1921 package_id, extended = True, 1922 resolve_conditional_deps = False) 1923 1924 needed_libs = self.retrieveNeededLibraries(package_id) 1925 compat_needed_libs = tuple( 1926 sorted((soname, elfclass) for _x, _x, soname, elfclass, _x 1927 in needed_libs) 1928 ) 1929 1930 data = { 1931 'atom': atom, 1932 'name': name, 1933 'version': version, 1934 'versiontag': versiontag, 1935 'description': description, 1936 'category': category, 1937 'chost': chost, 1938 'cflags': cflags, 1939 'cxxflags': cxxflags, 1940 'homepage': homepage, 1941 'license': mylicense, 1942 'branch': branch, 1943 'download': download, 1944 'digest': digest, 1945 'slot': slot, 1946 'etpapi': etpapi, 1947 'datecreation': datecreation, 1948 'size': size, 1949 'revision': revision, 1950 # risky to add to the sql above, still 1951 'counter': self.retrieveSpmUid(package_id), 1952 'trigger': self.retrieveTrigger(package_id), 1953 'disksize': self.retrieveOnDiskSize(package_id), 1954 'changelog': changelog, 1955 'injected': self.isInjected(package_id), 1956 'systempackage': self.isSystemPackage(package_id), 1957 'config_protect': self.retrieveProtect(package_id), 1958 'config_protect_mask': self.retrieveProtectMask(package_id), 1959 'useflags': self.retrieveUseflags(package_id), 1960 'keywords': self.retrieveKeywords(package_id), 1961 'sources': sources, 1962 'needed': compat_needed_libs, 1963 'needed_libs': needed_libs, 1964 'provided_libs': self.retrieveProvidedLibraries(package_id), 1965 'provide_extended': self.retrieveProvide(package_id), 1966 'conflicts': self.retrieveConflicts(package_id), 1967 'licensedata': self.retrieveLicenseData(package_id), 1968 'content': content, 1969 'content_safety': content_safety, 1970 'pkg_dependencies': deps, 1971 'mirrorlinks': [[x, self.retrieveMirrorData(x)] for x in mirrornames], 1972 'signatures': signatures, 1973 'spm_phases': self.retrieveSpmPhases(package_id), 1974 'spm_repository': self.retrieveSpmRepository(package_id), 1975 'desktop_mime': self.retrieveDesktopMime(package_id), 1976 'provided_mime': self.retrieveProvidedMime(package_id), 1977 'original_repository': self.getInstalledPackageRepository(package_id), 1978 'extra_download': self.retrieveExtraDownload(package_id), 1979 } 1980 1981 return data
1982
1983 - def getPackageXmlData(self, package_ids, get_content=True, 1984 get_changelog=True, get_content_safety=True):
1985 """ 1986 Generate the XML of the packages passed through package_ids. It is 1987 possible to validate the schema using either package.dtd or package.xsd. 1988 The returned string does not contain any xml header and the root tag is 1989 <packages>. 1990 Please note that the current implementation generates the 1991 XML tree in RAM and doesn't do any kind of "streaming". 1992 1993 @param package_ids: list of package identifiers 1994 @type package_ids: list 1995 @keyword get_content: include the package content in the XML 1996 @type get_content: bool 1997 @keyword get_changelog: include the package changelog in the XML 1998 @type get_changelog: bool 1999 @keyword get_content_safety: include the content safety metadata in the 2000 XML 2001 @type get_content_safety: bool 2002 @return: valid XML data 2003 @rtype: string 2004 """ 2005 from xml.dom import minidom 2006 doc = minidom.Document() 2007 packages = doc.createElement("packages") 2008 source_mirror_id = 1 2009 source_mirrors = {} 2010 package_changelogs_id = 1 2011 package_changelogs = {} 2012 2013 for package_id in package_ids: 2014 data = self.getPackageData( 2015 package_id, get_content = get_content, 2016 get_changelog = get_changelog, 2017 get_content_safety = get_content_safety) 2018 2019 package = doc.createElement("package") 2020 package.setAttribute("id", "id-%d" % (package_id,)) 2021 2022 is_system = "false" 2023 if data['systempackage']: 2024 is_system = "true" 2025 package.setAttribute("system", is_system) 2026 2027 is_injected = "false" 2028 if data['injected']: 2029 is_injected = "true" 2030 package.setAttribute("injected", is_injected) 2031 2032 package.setAttribute("creationdate", data['datecreation']) 2033 package.setAttribute("etpapi", "%d" % (data['etpapi'],)) 2034 package.setAttribute("spm-repository", data['spm_repository']) 2035 2036 atom = doc.createElement("atom") 2037 atom.appendChild(doc.createTextNode(data['atom'])) 2038 package.appendChild(atom) 2039 2040 category = doc.createElement("category") 2041 category.appendChild(doc.createTextNode(data['category'])) 2042 package.appendChild(category) 2043 2044 name = doc.createElement("name") 2045 name.appendChild(doc.createTextNode(data['name'])) 2046 name.setAttribute("natural-name", data['name'].capitalize()) 2047 package.appendChild(name) 2048 2049 version = doc.createElement("version") 2050 version.appendChild(doc.createTextNode(data['version'])) 2051 package.appendChild(version) 2052 2053 if data['versiontag']: 2054 versiontag = doc.createElement("versiontag") 2055 versiontag.appendChild(doc.createTextNode(data['versiontag'])) 2056 package.appendChild(versiontag) 2057 2058 revision = doc.createElement("revision") 2059 revision.appendChild(doc.createTextNode("%d" % (data['revision'],))) 2060 package.appendChild(revision) 2061 2062 branch = doc.createElement("branch") 2063 branch.appendChild(doc.createTextNode(data['branch'])) 2064 package.appendChild(branch) 2065 2066 slot = doc.createElement("slot") 2067 slot.appendChild(doc.createTextNode(data['slot'])) 2068 package.appendChild(slot) 2069 2070 lics = data['license'].split() 2071 lic_data = data['licensedata'] 2072 licenses = doc.createElement("licenses") 2073 for lic in lics: 2074 lic_el = doc.createElement("license") 2075 2076 lic_text = lic_data.get(lic, " ") 2077 if lic_text: 2078 lic_text = base64.b64encode( 2079 const_convert_to_rawstring( 2080 lic_text, from_enctype = "utf-8")) 2081 lic_el.appendChild(doc.createTextNode(lic_text)) 2082 lic_el.setAttribute("name", lic) 2083 lic_el.setAttribute("enc", "base64") 2084 licenses.appendChild(lic_el) 2085 if lics: 2086 package.appendChild(licenses) 2087 2088 if data['trigger']: 2089 trigger = doc.createElement("trigger") 2090 trigger.appendChild(doc.createTextNode( 2091 base64.b64encode(data['trigger']))) 2092 package.appendChild(trigger) 2093 2094 description = doc.createElement("description") 2095 description.appendChild(doc.createTextNode(data['description'])) 2096 package.appendChild(description) 2097 2098 homepage = doc.createElement("homepage") 2099 homepage.appendChild(doc.createTextNode(data['homepage'])) 2100 package.appendChild(homepage) 2101 2102 size = doc.createElement("size") 2103 size.appendChild(doc.createTextNode("%s" % (data['size'],))) 2104 package.appendChild(size) 2105 2106 chost = doc.createElement("chost") 2107 chost.appendChild(doc.createTextNode(data['chost'])) 2108 package.appendChild(chost) 2109 2110 cflags = doc.createElement("cflags") 2111 cflags.appendChild(doc.createTextNode(data['cflags'])) 2112 package.appendChild(cflags) 2113 2114 cxxflags = doc.createElement("cxxflags") 2115 cxxflags.appendChild(doc.createTextNode(data['cxxflags'])) 2116 package.appendChild(cxxflags) 2117 2118 content = doc.createElement("content") 2119 if data['content']: 2120 for path in sorted(data['content']): 2121 con_type = data['content'][path] 2122 path_el = doc.createElement("path") 2123 path_el.setAttribute("type", con_type) 2124 path_cs = data['content_safety'].get(path) 2125 if path_cs: 2126 path_el.setAttribute( 2127 "mtime", "%f" % (path_cs['mtime'],)) 2128 path_el.setAttribute("sha256", path_cs['sha256']) 2129 path_el.appendChild(doc.createTextNode(path)) 2130 content.appendChild(path_el) 2131 package.appendChild(content) 2132 2133 provides = doc.createElement("provides") 2134 if data['provide_extended']: 2135 for provide, is_default in sorted(data['provide_extended']): 2136 provide_el = doc.createElement("provide") 2137 default = "0" 2138 if is_default: 2139 default = "1" 2140 provide_el.setAttribute("default", default) 2141 provides.appendChild(provide_el) 2142 package.appendChild(provides) 2143 2144 dependencies = doc.createElement("dependencies") 2145 if data.get('pkg_dependencies'): 2146 dep_type_ids = etpConst['dependency_type_ids'] 2147 dep_type_map = { 2148 dep_type_ids['bdepend_id']: "buildtime", 2149 dep_type_ids['rdepend_id']: "runtime", 2150 dep_type_ids['pdepend_id']: "post-runtime", 2151 dep_type_ids['mdepend_id']: "manual", 2152 } 2153 for dep in sorted(data['conflicts']): 2154 dependency = doc.createElement("dependency") 2155 dependency.appendChild(doc.createTextNode(dep)) 2156 dependency.setAttribute("type", "runtime") 2157 dependency.setAttribute("conflict", "true") 2158 dependencies.appendChild(dependency) 2159 2160 for dep, dep_type in sorted(data['pkg_dependencies']): 2161 dependency = doc.createElement("dependency") 2162 dependency.appendChild(doc.createTextNode(dep)) 2163 dependency.setAttribute("type", dep_type) 2164 dependency.setAttribute("conflict", "false") 2165 dependencies.appendChild(dependency) 2166 2167 package.appendChild(dependencies) 2168 2169 for mirror_name, mirrors in data['mirrorlinks']: 2170 obj = source_mirrors.setdefault(mirror_name, {}) 2171 if not obj: 2172 obj.update({'id': source_mirror_id, 2173 'mirrors': set(mirrors),}) 2174 source_mirror_id += 1 2175 else: 2176 obj['mirrors'].update(mirrors) 2177 2178 sources = doc.createElement("sources") 2179 if data['sources']: 2180 for source in sorted(data['sources']): 2181 source_el = doc.createElement("source") 2182 source_el.appendChild(doc.createTextNode(source)) 2183 sources.appendChild(source_el) 2184 package.appendChild(sources) 2185 2186 useflags = doc.createElement("useflags") 2187 if data['useflags']: 2188 for useflag in sorted(data['useflags']): 2189 useflag_el = doc.createElement("useflag") 2190 useflag_el.setAttribute("name", useflag) 2191 useflags.appendChild(useflag_el) 2192 package.appendChild(useflags) 2193 2194 keywords = doc.createElement("keywords") 2195 if data['keywords']: 2196 for keyword in sorted(data['keywords']): 2197 keyword_el = doc.createElement("keyword") 2198 keyword_el.setAttribute("arch", keyword) 2199 keywords.appendChild(keyword_el) 2200 package.appendChild(keywords) 2201 2202 if data['config_protect']: 2203 config_protect = doc.createElement("config-protect") 2204 config_protect.appendChild( 2205 doc.createTextNode(data['config_protect'])) 2206 package.appendChild(config_protect) 2207 2208 if data['config_protect_mask']: 2209 config_protect_mask = doc.createElement("config-protect-mask") 2210 config_protect_mask.appendChild( 2211 doc.createTextNode(data['config_protect_mask'])) 2212 package.appendChild(config_protect_mask) 2213 2214 needed_libs = doc.createElement("needed-libs") 2215 if "needed_libs" in data: 2216 for _x, _x, needed, elf_class, _x in sorted( 2217 data['needed_libs']): 2218 needed_el = doc.createElement("needed-lib") 2219 needed_el.setAttribute("name", needed) 2220 needed_el.setAttribute("elfclass", "%d" % (elf_class,)) 2221 needed_libs.appendChild(needed_el) 2222 package.appendChild(needed_libs) 2223 else: # needed 2224 for needed, elf_class in sorted(data['needed']): 2225 needed_el = doc.createElement("needed-lib") 2226 needed_el.setAttribute("name", needed) 2227 needed_el.setAttribute("elfclass", "%d" % (elf_class,)) 2228 needed_libs.appendChild(needed_el) 2229 package.appendChild(needed_libs) 2230 2231 provided_libs = doc.createElement("provided-libs") 2232 if data['provided_libs']: 2233 for libname, path, elf_class in sorted(data['provided_libs']): 2234 provided_el = doc.createElement("provided-lib") 2235 provided_el.setAttribute("name", libname) 2236 provided_el.setAttribute("elfclass", "%d" % (elf_class,)) 2237 provided_el.appendChild(doc.createTextNode(path)) 2238 provided_libs.appendChild(provided_el) 2239 package.appendChild(provided_libs) 2240 2241 if data['changelog']: 2242 changelog_key = (data['category'], data['name']) 2243 obj = package_changelogs.setdefault(changelog_key, {}) 2244 if not obj: 2245 obj.update({ 2246 'id': package_changelogs_id, 2247 'changelog': data['changelog'], 2248 }) 2249 package_changelogs_id += 1 2250 2251 changelog = doc.createElement("changelog") 2252 changelog.setAttribute("pkg-changelog-id", "%d" % (obj['id'],)) 2253 package.appendChild(changelog) 2254 2255 desktop_mimes = doc.createElement("desktop-mimes") 2256 if data['desktop_mime']: 2257 for mime in data['desktop_mime']: 2258 mime_el = doc.createElement("desktop-mime") 2259 mime_el.setAttribute("name", mime['name']) 2260 mime_el.setAttribute("mimetype", mime['mimetype']) 2261 mime_el.setAttribute("icon", mime['icon']) 2262 mime_el.appendChild(doc.createTextNode(mime['executable'])) 2263 desktop_mimes.appendChild(mime_el) 2264 package.appendChild(desktop_mimes) 2265 2266 signature_id = 1 2267 signatures = {} 2268 download = doc.createElement("download") 2269 download.setAttribute("signature-id", "sign-%d-%d" % ( 2270 package_id, signature_id,)) 2271 package.appendChild(download) 2272 signatures[1] = { 2273 'url': data['download'], 2274 'md5': data['digest'], 2275 'sha1': data['signatures']['sha1'], 2276 'sha256': data['signatures']['sha256'], 2277 'sha512': data['signatures']['sha512'], 2278 'gpg': data['signatures']['gpg'], 2279 } 2280 signature_id += 1 2281 2282 extra_downloads = doc.createElement("extra-downloads") 2283 if data['extra_download']: 2284 for extra_download in data['extra_download']: 2285 extra_download_el = doc.createElement("extra-download") 2286 extra_download_el.setAttribute( 2287 "type", extra_download['type']) 2288 extra_download_el.setAttribute( 2289 "size", "%d" % (extra_download['size'],)) 2290 extra_download_el.setAttribute( 2291 "disksize", "%d" % (extra_download['disksize'],)) 2292 extra_download_el.setAttribute( 2293 "signature-id", 2294 "sign-%d-%d" % (package_id, signature_id,)) 2295 signatures[signature_id] = { 2296 'url': extra_download['download'], 2297 'md5': extra_download['md5'], 2298 'sha1': extra_download['sha1'], 2299 'sha256': extra_download['sha256'], 2300 'sha512': extra_download['sha512'], 2301 'gpg': extra_download['gpg'], 2302 } 2303 signature_id += 1 2304 extra_downloads.appendChild(extra_download_el) 2305 package.appendChild(extra_downloads) 2306 2307 signatures_el = doc.createElement("signatures") 2308 for signature_id in sorted(signatures): 2309 sign_data = signatures[signature_id] 2310 signature_el = doc.createElement("signature") 2311 signature_el.setAttribute("id", "sign-%d-%d" % ( 2312 package_id, signature_id,)) 2313 2314 sign_url = doc.createElement("url") 2315 sign_url.appendChild(doc.createTextNode(sign_data['url'])) 2316 signature_el.appendChild(sign_url) 2317 2318 sign_md5 = doc.createElement("md5") 2319 sign_md5.appendChild(doc.createTextNode(sign_data['md5'])) 2320 signature_el.appendChild(sign_md5) 2321 2322 sha1 = sign_data['sha1'] or "" 2323 sign_sha1 = doc.createElement("sha1") 2324 sign_sha1.appendChild(doc.createTextNode(sha1)) 2325 signature_el.appendChild(sign_sha1) 2326 2327 sha256 = sign_data['sha256'] or "" 2328 sign_sha256 = doc.createElement("sha256") 2329 sign_sha256.appendChild(doc.createTextNode(sha256)) 2330 signature_el.appendChild(sign_sha256) 2331 2332 sha512 = sign_data['sha256'] or "" 2333 sign_sha512 = doc.createElement("sha512") 2334 sign_sha512.appendChild(doc.createTextNode(sha512)) 2335 signature_el.appendChild(sign_sha512) 2336 2337 gpg = sign_data['gpg'] or "" 2338 sign_gpg = doc.createElement("gpg") 2339 sign_gpg.appendChild(doc.createTextNode(gpg)) 2340 signature_el.appendChild(sign_gpg) 2341 2342 signatures_el.appendChild(signature_el) 2343 2344 package.appendChild(signatures_el) 2345 2346 provided_mimes = doc.createElement("provided-mimes") 2347 if data['provided_mime']: 2348 for mime in sorted(data['provided_mime']): 2349 provided_mime = doc.createElement("provided-mime") 2350 provided_mime.setAttribute("mimetype", mime) 2351 provided_mimes.appendChild(provided_mime) 2352 package.appendChild(provided_mimes) 2353 2354 spm_phases = doc.createElement("spm-phases") 2355 if data['spm_phases']: 2356 for spm_phase in data['spm_phases'].split(): 2357 spm_phase_el = doc.createElement("spm-phase") 2358 spm_phase_el.appendChild(doc.createTextNode(spm_phase)) 2359 spm_phases.appendChild(spm_phase_el) 2360 package.appendChild(spm_phases) 2361 2362 spm_payload_el = doc.createElement("spm-payload") 2363 spm_payload = self.retrieveSpmMetadata(package_id) 2364 if spm_payload: 2365 spm_payload = base64.b64encode(spm_payload) 2366 spm_payload_el.appendChild(doc.createTextNode(spm_payload)) 2367 package.appendChild(spm_payload_el) 2368 2369 packages.appendChild(package) 2370 2371 source_mirrors_el = doc.createElement("source-mirrors") 2372 if source_mirrors: 2373 for mirror_name in sorted(source_mirrors): 2374 obj = source_mirrors[mirror_name] 2375 source_mirror = doc.createElement("source-mirror") 2376 source_mirror.setAttribute( 2377 "id", "source-mirror-%d" % (obj['id'],)) 2378 source_mirror.setAttribute("name", mirror_name) 2379 for mirror in sorted(obj['mirrors']): 2380 mirror_el = doc.createElement("mirror") 2381 mirror_el.appendChild(doc.createTextNode(mirror)) 2382 source_mirror.appendChild(mirror_el) 2383 source_mirrors_el.appendChild(source_mirror) 2384 packages.appendChild(source_mirrors_el) 2385 2386 pkg_changelogs_el = doc.createElement("pkg-changelogs") 2387 if package_changelogs: 2388 for changelog_key, cl in package_changelogs.items(): 2389 pkg_changelog = doc.createElement("pkg-changelog") 2390 pkg_changelog.appendChild(doc.createTextNode(cl['changelog'])) 2391 pkg_changelog.setAttribute("id", "%d" % (cl['id'],)) 2392 pkg_changelogs_el.appendChild(pkg_changelog) 2393 packages.appendChild(pkg_changelogs_el) 2394 2395 return packages.toprettyxml(indent=" ")
2396
2397 - def clearCache(self):
2398 """ 2399 Clear repository cache. 2400 Attention: call this method from your subclass, otherwise 2401 EntropyRepositoryPlugins won't be notified. 2402 """ 2403 plugins = self.get_plugins() 2404 for plugin_id in sorted(plugins): 2405 plug_inst = plugins[plugin_id] 2406 exec_rc = plug_inst.clear_cache_hook(self) 2407 if exec_rc: 2408 raise RepositoryPluginError( 2409 "[clear_cache_hook] %s: status: %s" % ( 2410 plug_inst.get_id(), exec_rc,))
2411
2412 - def retrieveRepositoryUpdatesDigest(self, repository):
2413 """ 2414 This method should be considered internal and not suited for general 2415 audience. Return digest (md5 hash) bound to repository package 2416 names/slots updates. 2417 2418 @param repository: repository identifier 2419 @type repository: string 2420 @return: digest string 2421 @rtype: string 2422 """ 2423 raise NotImplementedError()
2424
2425 - def _runConfigurationFilesUpdate(self, actions, files, 2426 protect_overwrite = True):
2427 """ 2428 Routine that takes all the executed actions and updates configuration 2429 files. 2430 """ 2431 spm_class = get_spm_class() 2432 updated_files = set() 2433 2434 actions_map = {} 2435 for action in actions: 2436 command = action.split() 2437 dep_key = entropy.dep.dep_getkey(command[1]) 2438 obj = actions_map.setdefault(dep_key, []) 2439 obj.append(tuple(command)) 2440 2441 def _workout_line(line): 2442 if not line.strip(): 2443 return line 2444 if line.lstrip().startswith("#"): 2445 return line 2446 2447 split_line = line.split() 2448 if not split_line: 2449 return line 2450 2451 pkg_dep = split_line[0] 2452 pkg_key = entropy.dep.dep_getkey(pkg_dep) 2453 2454 pkg_commands = actions_map.get(pkg_key) 2455 if pkg_commands is None: 2456 return line 2457 2458 for command in pkg_commands: 2459 if command[0] == "move": 2460 dep_from, key_to = command[1:] 2461 dep_from_key = entropy.dep.dep_getkey(dep_from) 2462 # NOTE: dep matching not supported, only using key 2463 if dep_from_key == pkg_key: 2464 # found, replace package name 2465 split_line[0] = pkg_dep.replace(dep_from_key, key_to) 2466 new_line = " ".join(split_line) + "\n" 2467 const_debug_write(__name__, 2468 "_runConfigurationFilesUpdate: replacing: " + \ 2469 "'%s' => '%s'" % (line, new_line,)) 2470 line = new_line 2471 # keep going, since updates are incremental 2472 # NOTE: slotmove not supported 2473 2474 return line
2475 2476 enc = etpConst['conf_encoding'] 2477 for file_path in files: 2478 tmp_fd, tmp_path = None, None 2479 try: 2480 with codecs.open(file_path, "r", encoding=enc) as source_f: 2481 tmp_fd, tmp_path = const_mkstemp( 2482 prefix="entropy.db._runConfigurationFilesUpdate", 2483 dir=os.path.dirname(file_path)) 2484 with entropy.tools.codecs_fdopen(tmp_fd, "w", enc) \ 2485 as dest_f: 2486 line = source_f.readline() 2487 while line: 2488 dest_f.write(_workout_line(line)) 2489 line = source_f.readline() 2490 2491 if protect_overwrite: 2492 new_file_path, prot_status = \ 2493 spm_class.allocate_protected_file( 2494 tmp_path, file_path) 2495 if prot_status: 2496 # it has been replaced 2497 os.rename(tmp_path, new_file_path) 2498 updated_files.add(new_file_path) 2499 else: 2500 os.remove(tmp_path) 2501 else: 2502 os.rename(tmp_path, file_path) 2503 2504 tmp_path = None 2505 tmp_fd = None 2506 2507 except (OSError, IOError,) as err: 2508 const_debug_write(__name__, "error: %s" % (err,)) 2509 continue 2510 finally: 2511 if tmp_fd is not None: 2512 try: 2513 os.close(tmp_fd) 2514 except (OSError, IOError): 2515 pass 2516 if tmp_path is not None: 2517 try: 2518 os.remove(tmp_path) 2519 except (OSError, IOError): 2520 pass 2521 2522 return updated_files
2523
2524 - def runTreeUpdatesActions(self, actions):
2525 """ 2526 Method not suited for general purpose usage. 2527 Executes package name/slot update actions passed. 2528 2529 @param actions: list of raw treeupdates actions, for example: 2530 ['move x11-foo/bar app-foo/bar', 'slotmove x11-foo/bar 2 3'] 2531 @type actions: list 2532 2533 @return: list (set) of packages that should be repackaged 2534 @rtype: set 2535 """ 2536 mytxt = "%s: %s, %s." % ( 2537 bold(_("SPM")), 2538 blue(_("Running packages metadata update")), 2539 red(_("it could take a while")), 2540 ) 2541 self.output( 2542 mytxt, 2543 importance = 1, 2544 level = "warning", 2545 header = darkred(" * ") 2546 ) 2547 try: 2548 spm = get_spm(self) 2549 spm.packages_repositories_metadata_update(actions) 2550 except Exception: 2551 entropy.tools.print_traceback() 2552 2553 quickpkg_atoms = set() 2554 executed_actions = [] 2555 for action in actions: 2556 command = action.split() 2557 mytxt = "%s: %s: %s." % ( 2558 bold(_("Entropy")), 2559 red(_("action")), 2560 blue(action), 2561 ) 2562 self.output( 2563 mytxt, 2564 importance = 1, 2565 level = "warning", 2566 header = darkred(" * ") 2567 ) 2568 if command[0] == "move": 2569 move_actions = self._runTreeUpdatesMoveAction(command[1:], 2570 quickpkg_atoms) 2571 if move_actions: 2572 executed_actions.append(action) 2573 quickpkg_atoms |= move_actions 2574 elif command[0] == "slotmove": 2575 slotmove_actions = self._runTreeUpdatesSlotmoveAction( 2576 command[1:], 2577 quickpkg_atoms) 2578 if slotmove_actions: 2579 executed_actions.append(action) 2580 quickpkg_atoms |= slotmove_actions 2581 2582 mytxt = "%s: %s." % ( 2583 bold(_("Entropy")), 2584 blue(_("package move actions complete")), 2585 ) 2586 self.output( 2587 mytxt, 2588 importance = 1, 2589 level = "info", 2590 header = purple(" @@ ") 2591 ) 2592 2593 mytxt = "%s: %s." % ( 2594 bold(_("Entropy")), 2595 blue(_("package moves completed successfully")), 2596 ) 2597 self.output( 2598 mytxt, 2599 importance = 1, 2600 level = "info", 2601 header = brown(" @@ ") 2602 ) 2603 2604 if executed_actions: 2605 # something actually happened, update configuration files 2606 files = self._settings.get_updatable_configuration_files( 2607 self.repository_id()) 2608 self._runConfigurationFilesUpdate(executed_actions, files) 2609 2610 # discard cache 2611 self.clearCache() 2612 2613 return quickpkg_atoms
2614 2615
2616 - def _runTreeUpdatesMoveAction(self, move_command, quickpkg_queue):
2617 """ 2618 Method not suited for general purpose usage. 2619 Executes package name move action passed. 2620 No need to override. 2621 2622 -- move action: 2623 1) move package key to the new name: category + name + atom 2624 2) update all the dependencies in dependenciesreference to the new key 2625 3) run fixpackages which will update /var/db/pkg files 2626 4) automatically run generate_package() to build the new binary and 2627 tainted binaries owning tainted iddependency and taint database 2628 2629 @param move_command: raw treeupdates move action, for example: 2630 'move x11-foo/bar app-foo/bar' 2631 @type move_command: string 2632 @param quickpkg_queue: current package regeneration queue 2633 @type quickpkg_queue: list 2634 @return: updated package regeneration queue 2635 @rtype: list 2636 """ 2637 dep_from = move_command[0] 2638 key_from = entropy.dep.dep_getkey(dep_from) 2639 key_to = entropy.dep.dep_getkey(move_command[1]) 2640 cat_to, name_to = key_to.split("/", 1) 2641 matches = self.atomMatch(dep_from, multiMatch = True, 2642 maskFilter = False) 2643 iddependencies = set() 2644 slot_pfx = etpConst['entropyslotprefix'] 2645 2646 matched_package_ids = matches[0] 2647 for package_id in matched_package_ids: 2648 2649 slot = self.retrieveSlot(package_id) 2650 old_atom = self.retrieveAtom(package_id) 2651 new_atom = old_atom.replace(key_from, key_to) 2652 2653 ### UPDATE DATABASE 2654 # update category 2655 self.setCategory(package_id, cat_to) 2656 # update name 2657 self.setName(package_id, name_to) 2658 # update atom 2659 self.setAtom(package_id, new_atom) 2660 2661 # look for packages we need to quickpkg again 2662 quickpkg_queue.add(key_to + slot_pfx + slot) 2663 2664 plugins = self.get_plugins() 2665 for plugin_id in sorted(plugins): 2666 plug_inst = plugins[plugin_id] 2667 exec_rc = plug_inst.treeupdates_move_action_hook(self, 2668 package_id) 2669 if exec_rc: 2670 raise RepositoryPluginError( 2671 "[treeupdates_move_action_hook] %s: status: %s" % ( 2672 plug_inst.get_id(), exec_rc,)) 2673 2674 iddeps = self.searchDependency(key_from, like = True, multi = True) 2675 for iddep in iddeps: 2676 2677 mydep = self.getDependency(iddep) 2678 # replace with new key and test 2679 mydep = mydep.replace(key_from, key_to) 2680 2681 pkg_ids, pkg_rc = self.atomMatch(mydep, multiMatch = True, 2682 maskFilter = False) 2683 2684 pointing_to_me = False 2685 for pkg_id in pkg_ids: 2686 if pkg_id not in matched_package_ids: 2687 # not my business 2688 continue 2689 # is this really pointing to me? 2690 mydep_key, _slot = self.retrieveKeySlot(pkg_id) 2691 if mydep_key != key_to: 2692 # not me! 2693 continue 2694 # yes, it's pointing to me 2695 pointing_to_me = True 2696 break 2697 2698 if not pointing_to_me: 2699 # meh ! 2700 continue 2701 2702 # now update 2703 # dependstable on server is always re-generated 2704 self.setDependency(iddep, mydep) 2705 # we have to repackage also package owning this iddep 2706 iddependencies |= self.searchPackageIdFromDependencyId(iddep) 2707 2708 self.commit() 2709 quickpkg_queue = list(quickpkg_queue) 2710 for x in range(len(quickpkg_queue)): 2711 myatom = quickpkg_queue[x] 2712 myatom = myatom.replace(key_from, key_to) 2713 quickpkg_queue[x] = myatom 2714 quickpkg_queue = set(quickpkg_queue) 2715 for package_id_owner in iddependencies: 2716 myatom = self.retrieveAtom(package_id_owner) 2717 if myatom is None: 2718 # reverse deps table out of sync 2719 continue 2720 myatom = myatom.replace(key_from, key_to) 2721 quickpkg_queue.add(myatom) 2722 return quickpkg_queue
2723 2724
2725 - def _runTreeUpdatesSlotmoveAction(self, slotmove_command, quickpkg_queue):
2726 """ 2727 Method not suited for general purpose usage. 2728 Executes package slot move action passed. 2729 No need to override. 2730 2731 -- slotmove action: 2732 1) move package slot 2733 2) update all the dependencies in dependenciesreference owning 2734 same matched atom + slot 2735 3) run fixpackages which will update /var/db/pkg files 2736 4) automatically run generate_package() to build the new 2737 binary and tainted binaries owning tainted iddependency 2738 and taint database 2739 2740 @param slotmove_command: raw treeupdates slot move action, for example: 2741 'slotmove x11-foo/bar 2 3' 2742 @type slotmove_command: string 2743 @param quickpkg_queue: current package regeneration queue 2744 @type quickpkg_queue: list 2745 @return: updated package regeneration queue 2746 @rtype: list 2747 """ 2748 atom = slotmove_command[0] 2749 atomkey = entropy.dep.dep_getkey(atom) 2750 slot_from = slotmove_command[1] 2751 slot_to = slotmove_command[2] 2752 matches = self.atomMatch(atom, multiMatch = True, maskFilter = False) 2753 iddependencies = set() 2754 slot_pfx = etpConst['entropyslotprefix'] 2755 2756 matched_package_ids = matches[0] 2757 for package_id in matched_package_ids: 2758 2759 # only if we've found VALID matches ! 2760 iddeps = self.searchDependency(atomkey, like = True, multi = True) 2761 for iddep in iddeps: 2762 # update string 2763 mydep = self.getDependency(iddep) 2764 2765 if mydep.find(slot_pfx + slot_from) == -1: 2766 # doesn't contain any trace of slot string, skipping 2767 continue 2768 2769 pkg_ids, pkg_rc = self.atomMatch(mydep, multiMatch = True, 2770 maskFilter = False) 2771 2772 pointing_to_me = False 2773 for pkg_id in pkg_ids: 2774 if pkg_id not in matched_package_ids: 2775 # not my business 2776 continue 2777 # is this really pointing to me? 2778 mydep_key, mydep_slot = self.retrieveKeySlot(pkg_id) 2779 if mydep_key != atomkey: 2780 # not me! 2781 continue 2782 if mydep_slot != slot_from: 2783 # not me! 2784 continue 2785 # yes, it's pointing to me 2786 pointing_to_me = True 2787 break 2788 2789 if not pointing_to_me: 2790 # meh ! 2791 continue 2792 2793 mydep = mydep.replace(slot_pfx + slot_from, slot_pfx + slot_to) 2794 # now update 2795 # dependstable on server is always re-generated 2796 self.setDependency(iddep, mydep) 2797 # we have to repackage also package owning this iddep 2798 iddependencies |= self.searchPackageIdFromDependencyId(iddep) 2799 2800 ### UPDATE DATABASE 2801 # update slot, do it here to avoid messing up with package match 2802 # code up here 2803 self.setSlot(package_id, slot_to) 2804 2805 # look for packages we need to quickpkg again 2806 # NOTE: quickpkg_queue is simply ignored if this is a client side 2807 # repository 2808 quickpkg_queue.add(atom + slot_pfx + slot_to) 2809 2810 plugins = self.get_plugins() 2811 for plugin_id in sorted(plugins): 2812 plug_inst = plugins[plugin_id] 2813 exec_rc = plug_inst.treeupdates_slot_move_action_hook(self, 2814 package_id) 2815 if exec_rc: 2816 raise RepositoryPluginError( 2817 "[treeupdates_slot_move_action_hook] %s: status: %s" % ( 2818 plug_inst.get_id(), exec_rc,)) 2819 2820 self.commit() 2821 for package_id_owner in iddependencies: 2822 myatom = self.retrieveAtom(package_id_owner) 2823 if myatom is None: 2824 # reverse deps table out of sync 2825 continue 2826 quickpkg_queue.add(myatom) 2827 return quickpkg_queue
2828
2829 - def listAllTreeUpdatesActions(self, no_ids_repos = False):
2830 """ 2831 This method should be considered internal and not suited for general 2832 audience. 2833 List all the available "treeupdates" (package names/slots changes 2834 directives) actions. 2835 Actions must be sorted by date (FLOAT). 2836 2837 @keyword no_ids_repos: if True, it will just return a tuple of 3-length 2838 tuples containing ((command, branch, unix_time,), ...) 2839 @type no_ids_repos: bool 2840 @return: tuple of tuples 2841 @rtype: tuple 2842 """ 2843 raise NotImplementedError()
2844
2845 - def retrieveTreeUpdatesActions(self, repository):
2846 """ 2847 This method should be considered internal and not suited for general 2848 audience. 2849 Return all the available "treeupdates (package names/slots changes 2850 directives) actions for provided repository. 2851 Actions must be sorted by date (FLOAT). 2852 2853 @param repository: repository identifier 2854 @type repository: string 2855 @return: tuple of raw-string commands to run 2856 @rtype: tuple 2857 """ 2858 raise NotImplementedError()
2859
2860 - def bumpTreeUpdatesActions(self, updates):
2861 # mainly used to restore a previous table, 2862 # used by reagent in --initialize 2863 """ 2864 This method should be considered internal and not suited for general 2865 audience. 2866 This method rewrites "treeupdates" metadata in repository. 2867 2868 @param updates: new treeupdates metadata 2869 @type updates: list 2870 """ 2871 raise NotImplementedError()
2872
2873 - def removeTreeUpdatesActions(self, repository):
2874 """ 2875 This method should be considered internal and not suited for general 2876 audience. 2877 This method removes "treeupdates" metadata in repository. 2878 2879 @param repository: remove treeupdates metadata for provided repository 2880 @type repository: string 2881 """ 2882 raise NotImplementedError()
2883
2884 - def insertTreeUpdatesActions(self, updates, repository):
2885 """ 2886 This method should be considered internal and not suited for general 2887 audience. 2888 This method insert "treeupdates" metadata in repository. 2889 2890 @param updates: new treeupdates metadata 2891 @type updates: list 2892 @param repository: insert treeupdates metadata for provided repository 2893 @type repository: string 2894 """ 2895 raise NotImplementedError()
2896
2897 - def setRepositoryUpdatesDigest(self, repository, digest):
2898 """ 2899 This method should be considered internal and not suited for general 2900 audience. 2901 Set "treeupdates" checksum (digest) for provided repository. 2902 2903 @param repository: repository identifier 2904 @type repository: string 2905 @param digest: treeupdates checksum string (md5) 2906 @type digest: string 2907 """ 2908 raise NotImplementedError()
2909
2910 - def addRepositoryUpdatesActions(self, repository, actions, branch):
2911 """ 2912 This method should be considered internal and not suited for general 2913 audience. 2914 Add "treeupdates" actions for repository and branch provided. 2915 2916 @param repository: repository identifier 2917 @type repository: string 2918 @param actions: list of raw treeupdates action strings 2919 @type actions: list 2920 @param branch: branch metadata to bind to the provided actions 2921 @type branch: string 2922 """ 2923 raise NotImplementedError()
2924
2925 - def clearPackageSets(self):
2926 """ 2927 Clear Package sets (group of packages) entries in repository. 2928 """ 2929 raise NotImplementedError()
2930
2931 - def insertPackageSets(self, sets_data):
2932 """ 2933 Insert Package sets metadata into repository. 2934 2935 @param sets_data: dictionary containing package set names as keys and 2936 list (set) of dependencies as value 2937 @type sets_data: dict 2938 """ 2939 raise NotImplementedError()
2940
2941 - def retrievePackageSets(self):
2942 """ 2943 Return Package sets metadata stored in repository. 2944 2945 @return: dictionary containing package set names as keys and 2946 list (set) of dependencies as value 2947 @rtype: dict 2948 """ 2949 raise NotImplementedError()
2950
2951 - def retrievePackageSet(self, setname):
2952 """ 2953 Return dependencies belonging to given package set name. 2954 This method does not check if the given package set name is 2955 available and returns an empty list (set) in these cases. 2956 2957 @param setname: Package set name 2958 @type setname: string 2959 @return: list (set) of dependencies belonging to given package set name 2960 @rtype: frozenset 2961 """ 2962 raise NotImplementedError()
2963
2964 - def retrieveAtom(self, package_id):
2965 """ 2966 Return "atom" metadatum for given package identifier. 2967 2968 @param package_id: package indentifier 2969 @type package_id: int 2970 @return: atom string 2971 @rtype: string or None 2972 """ 2973 raise NotImplementedError()
2974
2975 - def retrieveBranch(self, package_id):
2976 """ 2977 Return "branch" metadatum for given package identifier. 2978 2979 @param package_id: package indentifier 2980 @type package_id: int 2981 @return: branch metadatum 2982 @rtype: string or None 2983 """ 2984 raise NotImplementedError()
2985
2986 - def retrieveTrigger(self, package_id):
2987 """ 2988 Return "trigger" script content for given package identifier. 2989 2990 @param package_id: package indentifier 2991 @type package_id: int 2992 @return: trigger script content 2993 @rtype: string or None 2994 """ 2995 raise NotImplementedError()
2996
2997 - def retrieveDownloadURL(self, package_id):
2998 """ 2999 Return "download URL" metadatum for given package identifier. 3000 3001 @param package_id: package indentifier 3002 @type package_id: int 3003 @return: download url metadatum 3004 @rtype: string or None 3005 """ 3006 raise NotImplementedError()
3007
3008 - def retrieveDescription(self, package_id):
3009 """ 3010 Return "description" metadatum for given package identifier. 3011 3012 @param package_id: package indentifier 3013 @type package_id: int 3014 @return: package description 3015 @rtype: string or None 3016 """ 3017 raise NotImplementedError()
3018
3019 - def retrieveHomepage(self, package_id):
3020 """ 3021 Return "homepage" metadatum for given package identifier. 3022 3023 @param package_id: package indentifier 3024 @type package_id: int 3025 @return: package homepage 3026 @rtype: string or None 3027 """ 3028 raise NotImplementedError()
3029
3030 - def retrieveSpmUid(self, package_id):
3031 """ 3032 Return Source Package Manager unique identifier bound to Entropy 3033 package identifier. 3034 3035 @param package_id: package indentifier 3036 @type package_id: int 3037 @return: Spm UID or -1 (if not bound, valid for injected packages) 3038 @rtype: int 3039 """ 3040 raise NotImplementedError()
3041
3042 - def retrieveSize(self, package_id):
3043 """ 3044 Return "size" metadatum for given package identifier. 3045 "size" refers to Entropy package file size in bytes. 3046 3047 @param package_id: package indentifier 3048 @type package_id: int 3049 @return: size of Entropy package for given package identifier 3050 @rtype: int or None 3051 """ 3052 raise NotImplementedError()
3053
3054 - def retrieveOnDiskSize(self, package_id):
3055 """ 3056 Return "on disk size" metadatum for given package identifier. 3057 "on disk size" refers to unpacked Entropy package file size in bytes, 3058 which is in other words, the amount of space required on live system 3059 to have it installed (simplified explanation). 3060 3061 @param package_id: package indentifier 3062 @type package_id: int 3063 @return: on disk size metadatum 3064 @rtype: int 3065 """ 3066 raise NotImplementedError()
3067
3068 - def retrieveDigest(self, package_id):
3069 """ 3070 Return "digest" metadatum for given package identifier. 3071 "digest" refers to Entropy package file md5 checksum bound to given 3072 package identifier. 3073 3074 @param package_id: package indentifier 3075 @type package_id: int 3076 @return: md5 checksum for given package identifier 3077 @rtype: string or None 3078 """ 3079 raise NotImplementedError()
3080
3081 - def retrieveSignatures(self, package_id):
3082 """ 3083 Return package file extra hashes (sha1, sha256, sha512) for given 3084 package identifier. 3085 3086 @param package_id: package indentifier 3087 @type package_id: int 3088 @return: tuple of length 3, sha1, sha256, sha512 package extra 3089 hashes if available, otherwise the same but with None as values. 3090 @rtype: tuple 3091 """ 3092 raise NotImplementedError()
3093
3094 - def retrieveExtraDownload(self, package_id, down_type = None):
3095 """ 3096 Retrieve a list of extra package file URLs for package identifier. 3097 These URLs usually contain extra files that can be optionally installed 3098 by Entropy Client, for example: debug files. 3099 All the extra download file names must end with etpConst['packagesextraext'] 3100 extension. 3101 3102 @param package_id: package indentifier 3103 @type package_id: int 3104 @keyword down_type: retrieve data for a given entry type. 3105 Currently supported entry types are: "debug", "data". 3106 @type down_type: string 3107 @return: list (tuple) of dict containing "download", "type", "size", 3108 "disksize, "md5", "sha1","sha256", "sha512", "gpg" keys. "download" 3109 contains the relative URL (like the one returned by 3110 retrieveDownloadURL()) 3111 @rtype: tuple 3112 @raise AttributeError: if provided down_type value is invalid 3113 """ 3114 raise NotImplementedError()
3115
3116 - def retrieveName(self, package_id):
3117 """ 3118 Return "name" metadatum for given package identifier. 3119 Attention: package name != atom, the former is just a subset of the 3120 latter. 3121 3122 @param package_id: package indentifier 3123 @type package_id: int 3124 @return: "name" metadatum for given package identifier 3125 @rtype: string or None 3126 """ 3127 raise NotImplementedError()
3128
3129 - def retrieveKeySplit(self, package_id):
3130 """ 3131 Return a tuple composed by package category and package name for 3132 given package identifier. 3133 3134 @param package_id: package indentifier 3135 @type package_id: int 3136 @return: tuple of length 2 composed by (package_category, package_name,) 3137 @rtupe: tuple or None 3138 """ 3139 raise NotImplementedError()
3140
3141 - def retrieveKeySlot(self, package_id):
3142 """ 3143 Return a tuple composed by package key and slot for given package 3144 identifier. 3145 3146 @param package_id: package indentifier 3147 @type package_id: int 3148 @return: tuple of length 2 composed by (package_key, package_slot,) 3149 @rtupe: tuple or None 3150 """ 3151 raise NotImplementedError()
3152
3153 - def retrieveKeySlotAggregated(self, package_id):
3154 """ 3155 Return package key and package slot string (aggregated form through 3156 ":", for eg.: app-foo/foo:2). 3157 This method has been implemented for performance reasons. 3158 3159 @param package_id: package indentifier 3160 @type package_id: int 3161 @return: package key + ":" + slot string 3162 @rtype: string or None 3163 """ 3164 raise NotImplementedError()
3165
3166 - def retrieveKeySlotTag(self, package_id):
3167 """ 3168 Return package key, slot and tag tuple for given package identifier. 3169 3170 @param package_id: package indentifier 3171 @type package_id: int 3172 @return: tuple of length 3 providing (package_key, slot, package_tag,) 3173 @rtype: tuple 3174 """ 3175 raise NotImplementedError()
3176
3177 - def retrieveVersion(self, package_id):
3178 """ 3179 Return package version for given package identifier. 3180 3181 @param package_id: package indentifier 3182 @type package_id: int 3183 @return: package version 3184 @rtype: string or None 3185 """ 3186 raise NotImplementedError()
3187
3188 - def retrieveRevision(self, package_id):
3189 """ 3190 Return package Entropy-revision for given package identifier. 3191 3192 @param package_id: package indentifier 3193 @type package_id: int 3194 @return: Entropy-revision for given package indentifier 3195 @rtype: int or None 3196 """ 3197 raise NotImplementedError()
3198
3199 - def retrieveCreationDate(self, package_id):
3200 """ 3201 Return creation date for given package identifier. 3202 Creation date returned is a string representation of UNIX time format. 3203 3204 @param package_id: package indentifier 3205 @type package_id: int 3206 @return: creation date for given package identifier 3207 @rtype: string or None 3208 """ 3209 raise NotImplementedError()
3210
3211 - def retrieveApi(self, package_id):
3212 """ 3213 Return Entropy API in use when given package identifier was added. 3214 3215 @param package_id: package indentifier 3216 @type package_id: int 3217 @return: Entropy API for given package identifier 3218 @rtype: int or None 3219 """ 3220 raise NotImplementedError()
3221
3222 - def retrieveUseflags(self, package_id):
3223 """ 3224 Return "USE flags" metadatum for given package identifier. 3225 3226 @param package_id: package indentifier 3227 @type package_id: int 3228 @return: list (frozenset) of USE flags for given package identifier. 3229 @rtype: frozenset 3230 """ 3231 raise NotImplementedError()
3232
3233 - def retrieveSpmPhases(self, package_id):
3234 """ 3235 Return "Source Package Manager install phases" for given package 3236 identifier. 3237 3238 @param package_id: package indentifier 3239 @type package_id: int 3240 @return: "Source Package Manager available install phases" string 3241 @rtype: string or None 3242 """ 3243 raise NotImplementedError()
3244
3245 - def retrieveSpmRepository(self, package_id):
3246 """ 3247 Return Source Package Manager source repository used at compile time. 3248 3249 @param package_id: package indentifier 3250 @type package_id: int 3251 @return: Source Package Manager source repository 3252 @rtype: string or None 3253 """ 3254 raise NotImplementedError()
3255
3256 - def retrieveDesktopMime(self, package_id):
3257 """ 3258 Return file association metadata for package. 3259 3260 @param package_id: package indentifier 3261 @type package_id: int 3262 @return: list of dict() containing file association information 3263 @rtype: list 3264 """ 3265 raise NotImplementedError()
3266
3267 - def retrieveProvidedMime(self, package_id):
3268 """ 3269 Return mime types associated to package. Mimetypes whose package 3270 can handle. 3271 3272 @param package_id: package indentifier 3273 @type package_id: int 3274 @return: list (frozenset) of mimetypes 3275 @rtype: frozenset 3276 """ 3277 raise NotImplementedError()
3278
3279 - def retrieveNeeded(self, package_id, extended = False, formatted = False):
3280 """ 3281 Return "NEEDED" elf metadata for libraries contained in given package. 3282 Deprecated, use retrieveNeededLibraries. 3283 3284 @param package_id: package indentifier 3285 @type package_id: int 3286 @keyword extended: also return ELF class information for every 3287 library name 3288 @type extended: bool 3289 @keyword formatted: properly format output, returning a dictionary with 3290 library name as key and ELF class as value 3291 @type formatted: bool 3292 @return: "NEEDED" metadata for libraries contained in given package. 3293 @rtype: tuple or dict 3294 """ 3295 raise NotImplementedError()
3296
3297 - def retrieveNeededLibraries(self, package_id):
3298 """ 3299 Return the needed libraries for a given package. 3300 3301 @param package_id: package indentifier 3302 @type package_id: int 3303 @return: list (frozenset) of tuples composed by library user path, 3304 library user soname, soname, elf class, rpath. 3305 @rtype: frozenset 3306 """ 3307 raise NotImplementedError()
3308
3309 - def retrieveProvidedLibraries(self, package_id):
3310 """ 3311 Return list of library names (from NEEDED ELF metadata) provided by 3312 given package identifier. 3313 3314 @param package_id: package indentifier 3315 @type package_id: int 3316 @return: list (frozenset) of tuples of length 3 composed by library 3317 name, path and ELF class 3318 @rtype: frozenset 3319 """ 3320 raise NotImplementedError()
3321
3322 - def retrieveConflicts(self, package_id):
3323 """ 3324 Return list of conflicting dependencies for given package identifier. 3325 3326 @param package_id: package indentifier 3327 @type package_id: int 3328 @return: list (frozenset) of conflicting package dependencies 3329 @rtype: frozenset 3330 """ 3331 raise NotImplementedError()
3332
3333 - def retrieveProvide(self, package_id):
3334 """ 3335 Return list of dependencies/atoms are provided by the given package 3336 identifier (see Portage documentation about old-style PROVIDEs). 3337 3338 @param package_id: package indentifier 3339 @type package_id: int 3340 @return: list (frozenset) of atoms provided by package 3341 @rtype: frozenset 3342 """ 3343 raise NotImplementedError()
3344
3345 - def retrieveDependenciesList(self, package_id, exclude_deptypes = None, 3346 resolve_conditional_deps = True):
3347 """ 3348 Return list of dependencies, including conflicts for given package 3349 identifier. 3350 3351 @param package_id: package indentifier 3352 @type package_id: int 3353 @keyword exclude_deptypes: exclude given dependency types from returned 3354 data. Please see etpConst['dependency_type_ids'] for valid values. 3355 Anything != int will raise AttributeError 3356 @type exclude_deptypes: list 3357 @keyword resolve_conditional_deps: resolve conditional dependencies 3358 automatically by default, stuff like 3359 ( app-foo/foo | app-foo/bar ) & bar-baz/foo 3360 @type resolve_conditional_deps: bool 3361 @return: list (frozenset) of dependencies of package 3362 @rtype: frozenset 3363 @raise AttributeError: if exclude_deptypes contains illegal values 3364 """ 3365 raise NotImplementedError()
3366
3367 - def retrieveBuildDependencies(self, package_id, extended = False, 3368 resolve_conditional_deps = True):
3369 """ 3370 Return list of build time package dependencies for given package 3371 identifier. 3372 Note: this function is just a wrapper of retrieveDependencies() 3373 providing deptype (dependency type) = post-dependencies. 3374 3375 @param package_id: package indentifier 3376 @type package_id: int 3377 @keyword extended: return in extended format 3378 @type extended: bool 3379 @keyword resolve_conditional_deps: resolve conditional dependencies 3380 automatically by default, stuff like 3381 ( app-foo/foo | app-foo/bar ) & bar-baz/foo 3382 @type resolve_conditional_deps: bool 3383 @return: list (frozenset) of build dependencies of package 3384 @rtype: frozenset 3385 """ 3386 raise NotImplementedError()
3387
3388 - def retrieveRuntimeDependencies(self, package_id, extended = False, 3389 resolve_conditional_deps = True):
3390 """ 3391 Return list of runtime package dependencies for given package 3392 identifier. 3393 Note: this function is just a wrapper of retrieveDependencies() 3394 providing deptype (dependency type) = runtime-dependencies. 3395 3396 @param package_id: package indentifier 3397 @type package_id: int 3398 @keyword extended: return in extended format 3399 @type extended: bool 3400 @keyword resolve_conditional_deps: resolve conditional dependencies 3401 automatically by default, stuff like 3402 ( app-foo/foo | app-foo/bar ) & bar-baz/foo 3403 @type resolve_conditional_deps: bool 3404 @return: list (frozenset) of build dependencies of package 3405 @rtype: frozenset 3406 """ 3407 raise NotImplementedError()
3408
3409 - def retrievePostDependencies(self, package_id, extended = False, 3410 resolve_conditional_deps = True):
3411 """ 3412 Return list of post-merge package dependencies for given package 3413 identifier. 3414 Note: this function is just a wrapper of retrieveDependencies() 3415 providing deptype (dependency type) = post-dependencies. 3416 3417 @param package_id: package indentifier 3418 @type package_id: int 3419 @keyword extended: return in extended format 3420 @type extended: bool 3421 @keyword resolve_conditional_deps: resolve conditional dependencies 3422 automatically by default, stuff like 3423 ( app-foo/foo | app-foo/bar ) & bar-baz/foo 3424 @type resolve_conditional_deps: bool 3425 @return: list (frozenset) of post dependencies of package 3426 @rtype: frozenset 3427 """ 3428 raise NotImplementedError()
3429
3430 - def retrieveManualDependencies(self, package_id, extended = False, 3431 resolve_conditional_deps = True):
3432 """ 3433 Return manually added dependencies for given package identifier. 3434 Note: this function is just a wrapper of retrieveDependencies() 3435 providing deptype (dependency type) = manual-dependencies. 3436 3437 @param package_id: package indentifier 3438 @type package_id: int 3439 @keyword extended: return in extended format 3440 @type extended: bool 3441 @keyword resolve_conditional_deps: resolve conditional dependencies 3442 automatically by default, stuff like 3443 ( app-foo/foo | app-foo/bar ) & bar-baz/foo 3444 @type resolve_conditional_deps: bool 3445 @return: list (frozenset) of manual dependencies of package 3446 @rtype: frozenset 3447 """ 3448 raise NotImplementedError()
3449
3450 - def retrieveDependencies(self, package_id, extended = False, deptype = None, 3451 exclude_deptypes = None, resolve_conditional_deps = True):
3452 """ 3453 Return dependencies for given package identifier. 3454 3455 @param package_id: package indentifier 3456 @type package_id: int 3457 @keyword extended: return in extended format (list of tuples of length 2 3458 composed by dependency name and dependency type) 3459 @type extended: bool 3460 @keyword deptype: return only given type of dependencies 3461 see etpConst['dependency_type_ids']['*depend_id'] for dependency type 3462 identifiers 3463 @type deptype: bool 3464 @keyword exclude_deptypes: exclude given dependency types from returned 3465 data. Please see etpConst['dependency_type_ids'] for valid values. 3466 Anything != int will raise AttributeError 3467 @type exclude_deptypes: list 3468 @keyword resolve_conditional_deps: resolve conditional dependencies 3469 automatically by default, stuff like 3470 ( app-foo/foo | app-foo/bar ) & bar-baz/foo 3471 @type resolve_conditional_deps: bool 3472 @return: dependencies of given package 3473 @rtype: tuple or frozenset 3474 @raise AttributeError: if exclude_deptypes contains illegal values 3475 """ 3476 raise NotImplementedError()
3477
3478 - def retrieveKeywords(self, package_id):
3479 """ 3480 Return package SPM keyword list for given package identifier. 3481 3482 @param package_id: package indentifier 3483 @type package_id: int 3484 @return: list (frozenset) of keywords for given package identifier 3485 @rtype: frozenset 3486 """ 3487 raise NotImplementedError()
3488
3489 - def retrieveProtect(self, package_id):
3490 """ 3491 Return CONFIG_PROTECT (configuration file protection) string 3492 (containing a list of space reparated paths) metadata for given 3493 package identifier. 3494 3495 @param package_id: package indentifier 3496 @type package_id: int 3497 @return: CONFIG_PROTECT string 3498 @rtype: string 3499 """ 3500 raise NotImplementedError()
3501
3502 - def retrieveProtectMask(self, package_id):
3503 """ 3504 Return CONFIG_PROTECT_MASK (mask for configuration file protection) 3505 string (containing a list of space reparated paths) metadata for given 3506 package identifier. 3507 3508 @param package_id: package indentifier 3509 @type package_id: int 3510 @return: CONFIG_PROTECT_MASK string 3511 @rtype: string 3512 """ 3513 raise NotImplementedError()
3514
3515 - def retrieveSources(self, package_id, extended = False):
3516 """ 3517 Return source package URLs for given package identifier. 3518 "source" as in source code. 3519 3520 @param package_id: package indentifier 3521 @type package_id: int 3522 @keyword extended: 3523 @type extended: bool 3524 @return: if extended is True, dict composed by source URLs as key 3525 and list of mirrors as value, otherwise just a list (frozenset) of 3526 source package URLs. 3527 @rtype: dict or frozenset 3528 """ 3529 raise NotImplementedError()
3530
3531 - def retrieveAutomergefiles(self, package_id, get_dict = False):
3532 """ 3533 Return previously merged protected configuration files list and 3534 their md5 hashes for given package identifier. 3535 This is part of the "automerge" feature which uses file md5 checksum 3536 to determine if a protected configuration file can be merged auto- 3537 matically. 3538 3539 @param package_id: package indentifier 3540 @type package_id: int 3541 @keyword get_dict: return a dictionary with configuration file as key 3542 and md5 hash as value 3543 @type get_dict: bool 3544 @return: automerge metadata for given package identifier 3545 @rtype: frozenset or dict 3546 """ 3547 raise NotImplementedError()
3548
3549 - def retrieveContent(self, package_id, extended = False, 3550 formatted = False, insert_formatted = False, order_by = None):
3551 """ 3552 Return files contained in given package. 3553 3554 @param package_id: package indentifier 3555 @type package_id: int 3556 @keyword extended: return in extended format 3557 @type extended: bool 3558 @keyword formatted: return in dict() form 3559 @type formatted: bool 3560 @keyword insert_formatted: return in list of tuples form, ready to 3561 be added with insertContent() 3562 @keyword order_by: order by string, valid values are: 3563 "type" (if extended is True), "file" or "package_id" 3564 @type order_by: string 3565 @return: content metadata 3566 @rtype: dict or tuple or frozenset 3567 @raise AttributeError: if order_by value is invalid 3568 """ 3569 raise NotImplementedError()
3570
3571 - def retrieveContentIter(self, package_id, order_by = None, 3572 reverse = False):
3573 """ 3574 Return an iterator that makes possible to retrieve the files 3575 contained in given package. Please note that the iterator returned 3576 will fail if the EntropyRepository object is closed (call to close()). 3577 The iterator thus becomes invalid. 3578 Moreover, do not execute any other call that could invalidate 3579 the cursor object state before being done with it. 3580 3581 @param package_id: package indentifier 3582 @type package_id: int 3583 @keyword order_by: order by string, valid values are: 3584 "type" (if extended is True), "file" or "package_id" 3585 @type order_by: string 3586 @keyword reverse: return elements in reverse order 3587 @type reverse: bool 3588 @return: content metadata 3589 @rtype: iterator 3590 @raise AttributeError: if order_by value is invalid 3591 """ 3592 raise NotImplementedError()
3593
3594 - def retrieveContentSafety(self, package_id):
3595 """ 3596 Return supported content safety metadata for given package. 3597 Data returned is a dictionary, using package file path as key and 3598 dictionary as value. The latter, contains supported SPM content 3599 safety metadata, such as "sha256" (string) checksum, and "mtime" 3600 (float). The barely minimum is in fact, supporting sha256 and mtime 3601 of package files. 3602 3603 @param package_id: package indentifier 3604 @type package_id: int 3605 @return: content safety metadata 3606 @rtype: dict 3607 """ 3608 raise NotImplementedError()
3609
3610 - def retrieveContentSafetyIter(self, package_id):
3611 """ 3612 Return supported content safety metadata for given package in 3613 iterator form. 3614 Each iterator item is composed by a (path, sha256, mtime) tuple. 3615 Please note that the iterator returned will fail if the 3616 EntropyRepository object is closed (call to close()). 3617 The iterator thus becomes invalid. 3618 Moreover, do not execute any other call that could invalidate 3619 the cursor object state before being done with it. 3620 3621 @param package_id: package indentifier 3622 @type package_id: int 3623 @keyword order_by: order by string, valid values are: 3624 "type" (if extended is True), "file" or "package_id" 3625 @return: contentsafety metadata 3626 @rtype: iterator 3627 """ 3628 raise NotImplementedError()
3629
3630 - def retrieveChangelog(self, package_id):
3631 """ 3632 Return Source Package Manager ChangeLog for given package identifier. 3633 3634 @param package_id: package indentifier 3635 @type package_id: int 3636 @return: ChangeLog content 3637 @rtype: string or None 3638 """ 3639 raise NotImplementedError()
3640
3641 - def retrieveChangelogByKey(self, category, name):
3642 """ 3643 Return Source Package Manager ChangeLog content for given package 3644 category and name. 3645 3646 @param category: package category 3647 @type category: string 3648 @param name: package name 3649 @type name: string 3650 @return: ChangeLog content 3651 @rtype: string or None 3652 """ 3653 raise NotImplementedError()
3654
3655 - def retrieveSlot(self, package_id):
3656 """ 3657 Return "slot" metadatum for given package identifier. 3658 3659 @param package_id: package indentifier 3660 @type package_id: int 3661 @return: package slot 3662 @rtype: string or None 3663 """ 3664 raise NotImplementedError()
3665
3666 - def retrieveTag(self, package_id):
3667 """ 3668 Return "tag" metadatum for given package identifier. 3669 Tagging packages allows, for example, to support multiple 3670 different, colliding atoms in the same repository and still being 3671 able to exactly reference them. It's actually used to provide 3672 versions of external kernel modules for different kernels. 3673 3674 @param package_id: package indentifier 3675 @type package_id: int 3676 @return: tag string 3677 @rtype: string or None 3678 """ 3679 raise NotImplementedError()
3680
3681 - def retrieveMirrorData(self, mirrorname):
3682 """ 3683 Return available mirror URls for given mirror name. 3684 3685 @param mirrorname: mirror name (for eg. "openoffice") 3686 @type mirrorname: string 3687 @return: list (frozenset) of URLs providing the "openoffice" 3688 mirroring service 3689 @rtype: frozenset 3690 """ 3691 raise NotImplementedError()
3692
3693 - def retrieveCategory(self, package_id):
3694 """ 3695 Return category name for given package identifier. 3696 3697 @param package_id: package indentifier 3698 @type package_id: int 3699 @return: category where package is in 3700 @rtype: string or None 3701 """ 3702 raise NotImplementedError()
3703
3704 - def retrieveCategoryDescription(self, category):
3705 """ 3706 Return description text for given category. 3707 3708 @param category: category name 3709 @type category: string 3710 @return: category description dict, locale as key, description as value 3711 @rtype: dict 3712 """ 3713 raise NotImplementedError()
3714
3715 - def retrieveLicenseData(self, package_id):
3716 """ 3717 Return license metadata for given package identifier. 3718 3719 @param package_id: package indentifier 3720 @type package_id: int 3721 @return: dictionary composed by license name as key and license text 3722 as value 3723 @rtype: dict 3724 """ 3725 raise NotImplementedError()
3726
3727 - def retrieveLicenseDataKeys(self, package_id):
3728 """ 3729 Return license names available for given package identifier. 3730 3731 @param package_id: package indentifier 3732 @type package_id: int 3733 @return: list (frozenset) of license names which text is available in 3734 repository 3735 @rtype: frozenset 3736 """ 3737 raise NotImplementedError()
3738
3739 - def retrieveLicenseText(self, license_name):
3740 """ 3741 Return license text for given license name. 3742 3743 @param license_name: license name (for eg. GPL-2) 3744 @type license_name: string 3745 @return: license text 3746 @rtype: string (raw format) or None 3747 """ 3748 raise NotImplementedError()
3749
3750 - def retrieveLicense(self, package_id):
3751 """ 3752 Return "license" metadatum for given package identifier. 3753 3754 @param package_id: package indentifier 3755 @type package_id: int 3756 @return: license string 3757 @rtype: string or None 3758 """ 3759 raise NotImplementedError()
3760
3761 - def retrieveCompileFlags(self, package_id):
3762 """ 3763 Return Compiler flags during building of package. 3764 (CHOST, CXXFLAGS, LDFLAGS) 3765 3766 @param package_id: package indentifier 3767 @type package_id: int 3768 @return: tuple of length 3 composed by (CHOST, CFLAGS, CXXFLAGS) 3769 @rtype: tuple 3770 """ 3771 raise NotImplementedError()
3772
3773 - def retrieveReverseDependencies(self, package_id, atoms = False, 3774 key_slot = False, exclude_deptypes = None, extended = False):
3775 """ 3776 Return reverse (or inverse) dependencies for given package. 3777 3778 @param package_id: package indentifier 3779 @type package_id: int 3780 @keyword atoms: if True, method returns list of atoms 3781 @type atoms: bool 3782 @keyword key_slot: if True, method returns list of dependencies in 3783 key:slot form, example: (('app-foo/bar','2',), ...) 3784 @type key_slot: bool 3785 @keyword exclude_deptypes: exclude given dependency types from returned 3786 data. Please see etpConst['dependency_type_ids'] for valid values. 3787 Anything != int will raise AttributeError 3788 @type exclude_deptypes: iterable of ints 3789 @keyword extended: if True, the original dependency string will 3790 be returned along with the rest of information. So, if data 3791 returned would be a list of package identifiers (int), 3792 if extended = True this method will return a list of tuples 3793 composed by (package_id, dep_string). Same for atoms = True and 3794 key_slot = True. 3795 @type extended: bool 3796 @return: reverse dependency list (tuple) (or list of lists in case 3797 of extended = True) 3798 @rtype: tuple or frozenset 3799 @raise AttributeError: if exclude_deptypes contains illegal values 3800 """ 3801 raise NotImplementedError()
3802
3803 - def retrieveUnusedPackageIds(self):
3804 """ 3805 Return packages (through their identifiers) not referenced by any 3806 other as dependency (unused packages). 3807 3808 @return: unused package_ids ordered by atom 3809 @rtype: tuple 3810 """ 3811 raise NotImplementedError()
3812
3813 - def