Package entropy :: Package spm :: Package plugins :: Package interfaces :: Package portage_plugin

Source Code for Package entropy.spm.plugins.interfaces.portage_plugin

   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 Source Package Manager "Portage" Plugin}. 
  10   
  11  """ 
  12  import os 
  13  import io 
  14  import errno 
  15  import bz2 
  16  import hashlib 
  17  import shlex 
  18  import stat 
  19  import sys 
  20  import shutil 
  21  import stat 
  22  import subprocess 
  23  import tarfile 
  24  import time 
  25  import codecs 
  26  import warnings 
  27  import gc 
  28   
  29  from entropy.const import etpConst, const_get_stringtype, \ 
  30      const_convert_to_unicode, const_convert_to_rawstring, \ 
  31      const_setup_perms, const_setup_file, const_is_python3, \ 
  32      const_debug_enabled, const_mkdtemp, const_mkstemp, \ 
  33      const_file_readable, const_dir_readable 
  34  from entropy.exceptions import FileNotFound, InvalidDependString, \ 
  35      InvalidAtom, EntropyException 
  36  from entropy.output import darkred, darkgreen, brown, darkblue, teal, \ 
  37      purple, red, bold, blue, getcolor, decolorize, is_mute, is_interactive 
  38  from entropy.i18n import _ 
  39  from entropy.core.settings.base import SystemSettings 
  40  from entropy.misc import LogFile, ParallelTask 
  41  from entropy.spm.plugins.skel import SpmPlugin 
  42  import entropy.dep 
  43  import entropy.tools 
  44  from entropy.spm.plugins.interfaces.portage_plugin import xpak 
  45  from entropy.spm.plugins.interfaces.portage_plugin import xpaktools 
46 47 48 -class StdoutSplitter(object):
49
50 - def __init__(self, phase, logger, std):
51 self._phase = phase 52 self._logger = logger 53 self._std = std 54 self._closed = False 55 self._rfd, self._wfd = os.pipe() 56 57 self._task = ParallelTask(self._pusher) 58 self._task.name = "StdoutSplitterPusher" 59 self._task.daemon = True 60 self._task.start() 61 62 if const_is_python3(): 63 64 class Writer(object): 65 66 def __init__(self, parent, buf): 67 self._buf = buf 68 self._parent = parent
69 70 def write(self, b): 71 self._buf.write(b) 72 self._parent.write(const_convert_to_unicode(b))
73 74 def flush(self): 75 self._buf.flush() 76 self._parent.flush() 77 78 if isinstance(self._std, io.TextIOWrapper): 79 self.buffer = Writer(self, self._std.buffer) 80
81 - def __iter__(self):
82 return self._std
83
84 - def __hash__(self):
85 return hash(self._std)
86
87 - def _pusher(self):
88 while True: 89 try: 90 chunk = os.read(self._rfd, 512) # BLOCKS 91 except (IOError, OSError) as err: 92 # both can raise EINTR 93 if err.errno == errno.EINTR: 94 continue 95 if err.errno == errno.EBADF: 96 # fd has been closed 97 break 98 raise 99 try: 100 if const_is_python3() and isinstance(self._std, io.TextIOWrapper): 101 self._std.buffer.write(chunk) 102 else: 103 self._std.write(chunk) 104 except (OSError, IOError) as err: 105 sys.__stderr__.write( 106 "_pusher thread: " 107 "cannot write to stdout: " 108 "%s" % (repr(err),)) 109 try: 110 # write directly without mangling 111 os.write(self._logger.fileno(), chunk) 112 except (OSError, IOError) as err: 113 sys.__stderr__.write( 114 "_pusher thread: " 115 "cannot write to logger: " 116 "%s" % (repr(err),)) 117 if self._closed: 118 break
119 120 @property
121 - def softspace(self):
122 return self._std.softspace
123 124 @property
125 - def name(self):
126 return self._std.name
127 128 @property
129 - def newlines(self):
130 return self._std.newlines
131 132 @property
133 - def mode(self):
134 return self._std.mode
135 136 @property
137 - def errors(self):
138 return self._std.errors
139 140 @property
141 - def encoding(self):
142 return self._std.encoding
143 144 @property
145 - def closed(self):
146 return self._closed
147
148 - def fileno(self):
149 # redirect Portage to our pipe 150 return self._wfd
151
152 - def flush(self):
153 self._logger.flush() 154 return self._std.flush()
155
156 - def close(self):
157 self._closed = True 158 err = None 159 try: 160 os.close(self._wfd) 161 except OSError as _err: 162 err = _err 163 try: 164 os.close(self._rfd) 165 except OSError as _err: 166 err = _err 167 168 self._task.join() 169 if err is not None: 170 raise err
171
172 - def isatty(self):
173 return self._std.isatty()
174
175 - def next(self):
176 return self._std.next()
177
178 - def __next__(self):
179 return next(self._std)
180
181 - def read(self, *args, **kwargs):
182 return self._std.read(*args, **kwargs)
183
184 - def readline(self, *args, **kwargs):
185 return self._std.readline(*args, **kwargs)
186
187 - def readlines(self, *args, **kwargs):
188 return self._std.readlines(*args, **kwargs)
189
190 - def seek(self, *args, **kwargs):
191 return self._std.seek(*args, **kwargs)
192
193 - def tell(self):
194 return self._std.tell()
195
196 - def truncate(self, *args, **kwargs):
197 return self._std.truncate(*args, **kwargs)
198
199 - def write(self, mystr):
200 try: 201 raw_string = const_convert_to_rawstring(mystr) 202 except UnicodeEncodeError: 203 raw_string = const_convert_to_rawstring( 204 mystr, etpConst['conf_encoding']) 205 206 to_write = len(raw_string) 207 count = 0 208 while to_write < count: 209 try: 210 count += os.write(self._wfd, raw_string[count:]) 211 except (IOError, OSError) as err: 212 # both can raise EINTR 213 if err.errno == errno.EINTR: 214 continue 215 raise
216
217 - def writelines(self, lst):
218 for line in lst: 219 self.write(line)
220 221 if const_is_python3(): 222 223 # line_buffering readable seekable writable
224 - def readable(self):
225 return self._std.readable()
226
227 - def seekable(self):
228 return self._std.seekable()
229
230 - def writable(self):
231 return self._std.writable()
232 233 @property
234 - def line_buffering(self):
235 return self._std.line_buffering
236 237 else:
238 - def xreadlines(self):
239 return self._std.xreadlines()
240
241 242 -class PortagePackageGroups(dict):
243 """ 244 Entropy Package categories group representation 245 """
246 - def __init__(self):
247 dict.__init__(self) 248 249 data = { 250 'accessibility': { 251 'name': _("Accessibility"), 252 'description': \ 253 _("Accessibility applications"), 254 'categories': ['app-accessibility'], 255 }, 256 'office': { 257 'name': _("Office"), 258 'description': _("Applications used in office environments"), 259 'categories': ['app-office', 'app-pda', 'app-mobilephone', 260 'app-cdr', 'app-antivirus', 'app-laptop', 'mail-', 261 ], 262 }, 263 'development': { 264 'name': _("Development"), 265 'description': _("Applications or system libraries"), 266 'categories': ['dev-', 'sys-devel'], 267 }, 268 'system': { 269 'name': _("System"), 270 'description': _("System applications or libraries"), 271 'categories': ['sys-'], 272 }, 273 'games': { 274 'name': _("Games"), 275 'description': _("Games, enjoy your spare time"), 276 'categories': ['games-'], 277 }, 278 'gnome': { 279 'name': _("GNOME Desktop"), 280 'description': \ 281 _("Applications and libraries for the GNOME Desktop"), 282 'categories': ['gnome-'], 283 }, 284 'kde': { 285 'name': _("KDE Desktop"), 286 'description': \ 287 _("Applications and libraries for the KDE Desktop"), 288 'categories': ['kde-'], 289 }, 290 'xfce': { 291 'name': _("XFCE Desktop"), 292 'description': \ 293 _("Applications and libraries for the XFCE Desktop"), 294 'categories': ['xfce-'], 295 }, 296 'lxde': { 297 'name': _("LXDE Desktop"), 298 'description': \ 299 _("Applications and libraries for the LXDE Desktop"), 300 'categories': ['lxde-'], 301 }, 302 'multimedia': { 303 'name': _("Multimedia"), 304 'description': \ 305 _("Applications and libraries for Multimedia"), 306 'categories': ['media-'], 307 }, 308 'networking': { 309 'name': _("Networking"), 310 'description': \ 311 _("Applications and libraries for Networking"), 312 'categories': ['net-', 'www-'], 313 }, 314 'science': { 315 'name': _("Science"), 316 'description': \ 317 _("Scientific applications and libraries"), 318 'categories': ['sci-'], 319 }, 320 'security': { 321 'name': _("Security"), 322 'description': \ 323 _("Security oriented applications"), 324 'categories': ['app-antivirus', 'net-analyzer', 'net-firewall'], 325 }, 326 'x11': { 327 'name': _("X11"), 328 'description': \ 329 _("Applications and libraries for X11"), 330 'categories': ['x11-'], 331 }, 332 } 333 self.update(data)
334
335 336 -class PortageMetaphor:
337 338 """ 339 This class (will) contains Portage packages metaphor related functions. 340 It is intended for internal (plugin) use only. So, go away from here ;) 341 """ 342 343 # used to properly sort /usr/portage/profiles/updates files 344 @staticmethod
345 - def sort_update_files(update_list):
346 """ 347 docstring_title 348 349 @param update_list: 350 @type update_list: 351 @return: 352 @rtype: 353 """ 354 sort_dict = {} 355 # sort per year 356 for item in update_list: 357 # get year 358 year = item.split("-")[1] 359 if year in sort_dict: 360 sort_dict[year].append(item) 361 else: 362 sort_dict[year] = [] 363 sort_dict[year].append(item) 364 new_list = [] 365 keys = sorted(sort_dict.keys()) 366 for key in keys: 367 sort_dict[key].sort() 368 new_list += sort_dict[key] 369 del sort_dict 370 return new_list
371
372 373 -class PortageEntropyDepTranslator(object):
374 """ 375 Conditional dependency string translator from Portage to Entropy. 376 377 Example usage: 378 >>> translator = PortageEntropyDepTranslator(portage_string) 379 >>> entropy_string = translator.translate() 380 entropy_string 381 382 """ 383
384 - class ParseError(EntropyException):
385 """ 386 Parse error. 387 """
388
389 - def __init__(self, portage_dependency):
390 """ 391 PortageEntropyDepTranslator constructor. 392 393 @param portage_dependency: Portage dependency string 394 @type portage_dependency: string 395 """ 396 self.__dep = portage_dependency
397
398 - def __produce_entropy_dep(self, split_dep):
399 """ 400 Digest Portage raw dependency data produced by __extract_scope() 401 """ 402 dep_str_list = [] 403 operator, sub_split = split_dep[0], split_dep[1:] 404 405 for dep in sub_split: 406 if isinstance(dep, list): 407 _str = self.__produce_entropy_dep(dep) 408 else: 409 _str = dep 410 dep_str_list.append(_str) 411 412 return "( " + (" " + operator + " ").join(dep_str_list) + " )"
413
414 - def __extract_scope(self, split_sub):
415 """ 416 Prepare split Portage dependency string for complete digestion. 417 """ 418 scope_list = [] 419 nest_level = 0 420 skip_count = 0 421 sub_count = 0 422 423 for sub_idx in range(len(split_sub)): 424 425 sub_count += 1 426 if skip_count: 427 skip_count -= 1 428 continue 429 430 sub = split_sub[sub_idx] 431 if sub == "||": # or 432 try: 433 next_sub = split_sub[sub_idx+1] 434 except IndexError as err: 435 raise PortageEntropyDepTranslator.ParseError( 436 "Index Error") 437 if next_sub != "(": 438 raise PortageEntropyDepTranslator.ParseError( 439 "Syntax Error") 440 441 local_sub_count, sub_scope = self.__extract_scope( 442 split_sub[sub_idx+2:]) 443 skip_count += local_sub_count 444 scope_list.append( 445 [entropy.dep.DependencyStringParser.LOGIC_OR] + sub_scope) 446 447 elif sub == "(": 448 local_sub_count, sub_scope = self.__extract_scope( 449 split_sub[sub_idx+1:]) 450 skip_count += local_sub_count 451 scope_list.append( 452 [entropy.dep.DependencyStringParser.LOGIC_AND] + sub_scope) 453 nest_level += 1 454 455 elif sub == ")": 456 if nest_level == 0: 457 break # end of scope 458 nest_level -= 1 459 460 else: 461 scope_list.append(sub) 462 463 return sub_count, scope_list
464
465 - def translate(self):
466 """ 467 Effectively translate Portage dependency string returning Entropy one. 468 469 @return: Entropy dependency string 470 @rtype: string 471 @raise PortageEntropyDepTranslator.ParseError: in case of malformed 472 Portage dependency. 473 """ 474 split_sub = [x.strip() for x in self.__dep.split() if x.strip()] 475 count, split_dep = self.__extract_scope(split_sub) 476 return self.__produce_entropy_dep(split_dep[0])
477
478 479 -class PortagePlugin(SpmPlugin):
480 481 xpak_entries = { 482 'description': "DESCRIPTION", 483 'homepage': "HOMEPAGE", 484 'chost': "CHOST", 485 'category': "CATEGORY", 486 'cflags': "CFLAGS", 487 'cxxflags': "CXXFLAGS", 488 'license': "LICENSE", 489 'src_uri': "SRC_URI", 490 'use': "USE", 491 'iuse': "IUSE", 492 'slot': "SLOT", 493 'provide': "PROVIDE", 494 'depend': "DEPEND", 495 'rdepend': "RDEPEND", 496 'pdepend': "PDEPEND", 497 'bdepend': "BDEPEND", # since EAPI 7 498 'needed': "NEEDED", 499 'needed.elf.2': "NEEDED.ELF.2", 500 'inherited': "INHERITED", 501 'keywords': "KEYWORDS", 502 'contents': "CONTENTS", 503 'counter': "COUNTER", 504 'defined_phases': "DEFINED_PHASES", 505 'repository': "repository", 506 'pf': "PF", 507 'eapi': "EAPI", 508 'features': "FEATURES", 509 } 510 511 _xpak_const = { 512 # xpak temp directory path 513 'entropyxpakrelativepath': "xpak", 514 # xpak metadata directory path 515 'entropyxpakdatarelativepath': "data", 516 # xpak metadata file name 517 'entropyxpakfilename': "metadata.xpak", 518 } 519 520 _ebuild_entries = { 521 'ebuild_pkg_tag_var': "ENTROPY_PROJECT_TAG", 522 } 523 524 _cmd_map = { 525 'env_update_cmd': "/usr/sbin/env-update", 526 'ask_cmd': "--ask", 527 'info_cmd': "--info", 528 'remove_cmd': "-C", 529 'nodeps_cmd': "--nodeps", 530 'fetchonly_cmd': "--fetchonly", 531 'buildonly_cmd': "--buildonly", 532 'oneshot_cmd': "--oneshot", 533 'pretend_cmd': "--pretend", 534 'verbose_cmd': "--verbose", 535 'nocolor_cmd': "--color=n", 536 'source_profile_cmd': "source /etc/profile", 537 'exec_cmd': "/usr/bin/emerge", 538 } 539 540 _package_phases_map = { 541 'setup': 'setup', 542 'preinstall': 'preinst', 543 'postinstall': 'postinst', 544 'preremove': 'prerm', 545 'postremove': 'postrm', 546 'configure': 'config', 547 } 548 549 _config_files_map = { 550 'global_make_conf': "/etc/make.conf", 551 'global_make_conf_new': "/etc/portage/make.conf", 552 'global_package_keywords': "/etc/portage/package.keywords", 553 'global_package_use': "/etc/portage/package.use", 554 'global_package_mask': "/etc/portage/package.mask", 555 'global_package_unmask': "/etc/portage/package.unmask", 556 'global_make_profile': "/etc/make.profile", 557 } 558 559 PLUGIN_API_VERSION = 12 560 561 SUPPORTED_MATCH_TYPES = [ 562 "bestmatch-visible", "cp-list", "list-visible", "match-all", 563 "match-visible", "minimum-all", "minimum-visible" 564 ] 565 566 CACHE = { 567 'vartree': {}, 568 'binarytree': {}, 569 'config': {}, 570 'portagetree': {}, 571 } 572 573 IS_DEFAULT = True 574 PLUGIN_NAME = 'portage' 575 ENV_FILE_COMP = "environment.bz2" 576 EBUILD_EXT = ".ebuild" 577 KERNEL_CATEGORY = "sys-kernel" 578 _PORTAGE_ENTROPY_PACKAGE_NAME = "sys-apps/portage" 579 _ACCEPT_PROPERTIES = const_convert_to_unicode("* -interactive") 580 581 ENV_DIRS = set(["/etc/env.d"]) 582 583 if "/usr/lib/gentoolkit/pym" not in sys.path: 584 sys.path.append("/usr/lib/gentoolkit/pym") 585 586 # Portage now installs its modules into site-packages. 587 # However, if it's compiled only for py2.7, running 588 # this code with py3.3 won't work. So, add the real 589 # portage/pym path. 590 if "/usr/lib/portage/pym" not in sys.path: 591 sys.path.append("/usr/lib/portage/pym") 592
593 - def init_singleton(self, output_interface):
594 595 self.__output = output_interface 596 self.__entropy_repository_treeupdate_digests = {} 597 598 # setup licenses according to Gentoo bug #234300 comment 9. 599 # EAPI < 3. 600 os.environ["ACCEPT_PROPERTIES"] = self._ACCEPT_PROPERTIES 601 602 # setup color status 603 if not getcolor(): 604 # Entropy color output is disable, disable Portage 605 os.environ['NOCOLOR'] = "yes" 606 elif "NOCOLOR" in os.environ: 607 del os.environ['NOCOLOR'] 608 609 # importing portage stuff 610 import portage.const 611 # Portage 2.1.9x, enable package sets for overlay. 612 portage.const._ENABLE_SET_CONFIG = True 613 import portage 614 import portage.util 615 self._portage = portage
616
617 - def _reload_modules(self):
618 619 """ 620 WARNING: this function reloads Portage modules in RAM 621 it brutally kills the current instance by removing 622 it from sys.modules and calling a new import. 623 There may be resource leaks but since this can only be run 624 once per "session", that's nothing to worry about. 625 """ 626 mytxt = "%s..." % ( 627 brown(_("Reloading Portage modules")), 628 ) 629 self.__output.output( 630 mytxt, 631 importance = 0, 632 header = red(" ## ") 633 ) 634 635 self.clear() 636 637 for obj in tuple(PortagePlugin.CACHE.values()): 638 obj.clear() 639 640 port_key = "portage" 641 emerge_key = "_emerge" 642 # we have a portage module instance in here too 643 # need to kill it 644 current_module_name = __name__ + "." + port_key 645 if current_module_name in sys.modules: 646 del sys.modules[current_module_name] 647 648 for key in tuple(sys.modules.keys()): 649 if key.startswith(port_key): 650 del sys.modules[key] 651 elif key.startswith(emerge_key): 652 del sys.modules[key] 653 # now reimport everything 654 655 # Portage 2.1.9x, enable package sets for overlay. 656 import portage.const 657 portage.const._ENABLE_SET_CONFIG = True 658 import portage 659 import portage.util 660 # reassign portage variable, pointing to a fresh object 661 self._portage = portage
662
663 - def clear(self):
664 """ 665 Reimplemented from SpmPlugin class. 666 """ 667 for root, tree in list(PortagePlugin.CACHE['portagetree'].items()): 668 dbapi = tree.dbapi 669 670 dbapi.melt() 671 dbapi._aux_cache.clear() 672 dbapi.clear_caches() 673 tree.dbapi = portage.dbapi.porttree.portdbapi( 674 mysettings=dbapi.settings) 675 676 for root, tree in list(PortagePlugin.CACHE['vartree'].items()): 677 dbapi = tree.dbapi 678 if hasattr(dbapi, "_clear_cache"): 679 dbapi._clear_cache() 680 681 gc.collect()
682 683 @staticmethod
684 - def get_package_groups():
685 """ 686 Return package groups available metadata (Spm categories are grouped 687 into macro categories called "groups"). 688 """ 689 return PortagePackageGroups()
690 691 @staticmethod
693 """ 694 Reimplemented from SpmPlugin class. 695 """ 696 return ["tbz2"]
697
698 - def package_metadata_keys(self):
699 """ 700 Reimplemented from SpmPlugin class. 701 """ 702 # return what's inside vartree because it's more complete 703 dbapi = self._get_portage_vartree().dbapi 704 if hasattr(dbapi, '_aux_cache_keys'): 705 return list(dbapi._aux_cache_keys) 706 707 sys.stderr.write("PortagePlugin: missing vardb._aux_cache_keys !\n") 708 return ["CHOST", "COUNTER", "DEPEND", "DESCRIPTION", 709 "EAPI", "HOMEPAGE", "IUSE", "KEYWORDS", 710 "LICENSE", "PDEPEND", "PROPERTIES", "PROVIDE", "RDEPEND", 711 "BDEPEND", "repository", "RESTRICT", "SLOT", "USE" 712 ]
713
714 - def get_cache_directory(self, root = None):
715 """ 716 Reimplemented from SpmPlugin class. 717 """ 718 if root is None: 719 root = etpConst['systemroot'] + os.path.sep 720 cache_path = self._portage.const.CACHE_PATH.lstrip(os.path.sep) 721 return os.path.join(root, cache_path)
722
723 - def get_package_metadata(self, package, key):
724 """ 725 Reimplemented from SpmPlugin class. 726 """ 727 return self._portage.portdb.aux_get(package, [key])[0]
728
729 - def get_package_changelog(self, package):
730 """ 731 Reimplemented from SpmPlugin class. 732 """ 733 ebuild_path = self.get_package_build_script_path(package) 734 if isinstance(ebuild_path, const_get_stringtype()): 735 clog_path = os.path.join(os.path.dirname(ebuild_path), "ChangeLog") 736 try: 737 with open(clog_path, "rb") as clog_f: 738 return clog_f.read() 739 except (OSError, IOError) as err: 740 if err.errno != errno.ENOENT: 741 raise
742
743 - def get_package_build_script_path(self, package):
744 """ 745 Reimplemented from SpmPlugin class. 746 """ 747 return self._portage.portdb.findname(package)
748
749 - def get_installed_package_build_script_path(self, package, root = None):
750 """ 751 Reimplemented from SpmPlugin class. 752 """ 753 return os.path.join(self._get_vdb_path(root = root), package, 754 package.split("/")[-1] + PortagePlugin.EBUILD_EXT)
755
756 - def get_installed_package_metadata(self, package, key, root = None):
757 """ 758 Reimplemented from SpmPlugin class. 759 """ 760 data = self._get_installed_package_metadata( 761 package, key, root = root) 762 if key == "SLOT" and data: 763 # EAPI5, strip /* from SLOT 764 data = self._strip_slash_from_slot(data) 765 return data
766
767 - def _get_installed_package_metadata(self, package, key, root = None):
768 """ 769 Internal version of get_installed_package_metadata(). 770 This method doesn't do any automagic mangling to returned 771 data. 772 """ 773 if root is None: 774 root = etpConst['systemroot'] + os.path.sep 775 vartree = self._get_portage_vartree(root = root) 776 try: 777 return vartree.dbapi.aux_get(package, [key])[0] 778 except KeyError: # make clear that we raise KeyError 779 raise 780 except OSError as err: 781 raise KeyError("Original OSError: %s" % (err,))
782
783 - def get_system_packages(self):
784 """ 785 Reimplemented from SpmPlugin class. 786 """ 787 system = [] 788 for package in self._portage.settings.packages: 789 pkgs = self.match_installed_package(package, match_all = True) 790 system.extend(pkgs) 791 return system
792
793 - def get_package_categories(self):
794 """ 795 Reimplemented from SpmPlugin class. 796 """ 797 return self._get_portage_config(os.path.sep, os.path.sep).categories
798
799 - def get_package_category_description_metadata(self, category):
800 """ 801 Reimplemented from SpmPlugin class. 802 """ 803 from xml.dom import minidom 804 data = {} 805 portdir = self._portage.settings['PORTDIR'] 806 myfile = os.path.join(portdir, category, "metadata.xml") 807 if const_file_readable(myfile): 808 doc = minidom.parse(myfile) 809 longdescs = doc.getElementsByTagName("longdescription") 810 for longdesc in longdescs: 811 data[longdesc.getAttribute("lang").strip()] = \ 812 ' '.join([x.strip() for x in \ 813 longdesc.firstChild.data.strip().split("\n")]) 814 return data
815
816 - def _get_glsa(self):
817 try: 818 import glsa 819 glsa_mod = glsa 820 except ImportError: 821 glsa_mod = None 822 return glsa_mod
823
824 - def get_security_packages(self, security_property):
825 """ 826 Reimplemented from SpmPlugin class. 827 """ 828 _glsa = self._get_glsa() 829 if _glsa is None: 830 return [] 831 if security_property not in ['new', 'all', 'affected']: 832 return [] 833 834 glsaconfig = _glsa.checkconfig( 835 self._portage.config(clone=self._portage.settings)) 836 completelist = _glsa.get_glsa_list( 837 glsaconfig["GLSA_DIR"], glsaconfig) 838 839 glsalist = [] 840 if security_property == "new": 841 842 checklist = [] 843 try: 844 enc = etpConst['conf_encoding'] 845 with codecs.open(glsaconfig["CHECKFILE"], "r", encoding=enc) \ 846 as check_f: 847 checklist.extend([x.strip() for x in check_f.readlines()]) 848 except (OSError, IOError) as err: 849 if err.errno != errno.ENOENT: 850 raise 851 glsalist = [x for x in completelist if x not in checklist] 852 853 elif security_property == "all": 854 glsalist = completelist 855 856 elif security_property == "affected": 857 858 # maybe this should be todolist instead 859 for glsa_item in completelist: 860 try: 861 myglsa = _glsa.Glsa(glsa_item, glsaconfig) 862 except (_glsa.GlsaTypeException, _glsa.GlsaFormatException,): 863 continue 864 865 if not myglsa.isVulnerable(): 866 continue 867 868 glsalist.append(glsa_item) 869 870 return glsalist
871
872 - def get_security_advisory_metadata(self, advisory_id):
873 """ 874 Reimplemented from SpmPlugin class. 875 """ 876 _glsa = self._get_glsa() 877 if _glsa is None: 878 return {} 879 880 glsaconfig = _glsa.checkconfig( 881 self._portage.config(clone=self._portage.settings)) 882 try: 883 myglsa = _glsa.Glsa(advisory_id, glsaconfig) 884 except (_glsa.GlsaTypeException, _glsa.GlsaFormatException): 885 return {} 886 887 mydict = { 888 'glsa_id': advisory_id, 889 'number': myglsa.nr, 890 'access': myglsa.access, 891 'title': myglsa.title, 892 'synopsis': myglsa.synopsis, 893 'announced': myglsa.announced, 894 'revised': myglsa.revised, 895 'bugs': myglsa.bugs, 896 'description': myglsa.description, 897 'resolution': myglsa.resolution, 898 'impact': myglsa.impact_text, 899 'impacttype': myglsa.impact_type, 900 'affected': myglsa.affected, 901 'background': myglsa.background, 902 'glsatype': myglsa.glsatype, 903 'packages': myglsa.packages, 904 'services': myglsa.services, 905 'product': myglsa.product, 906 'references': myglsa.references, 907 'workaround': myglsa.workaround, 908 } 909 910 status = "[U]" 911 if myglsa.isApplied(): 912 status = "[A]" 913 elif myglsa.isVulnerable(): 914 status = "[N]" 915 mydict['status'] = status 916 917 return mydict
918
919 - def get_setting(self, key):
920 """ 921 Reimplemented from SpmPlugin class. 922 """ 923 return self._portage.settings[key]
924
925 - def get_user_installed_packages_file(self, root = None):
926 """ 927 Reimplemented from SpmPlugin class. 928 """ 929 world_file = self._portage.const.WORLD_FILE 930 if root is None: 931 root = etpConst['systemroot'] + os.path.sep 932 return os.path.join(root, world_file)
933
934 - def get_merge_protected_paths(self):
935 """ 936 Reimplemented from SpmPlugin class. 937 """ 938 config_protect = self._portage.settings['CONFIG_PROTECT'] 939 return [os.path.expandvars(x) for x in config_protect.split()]
940
942 """ 943 Reimplemented from SpmPlugin class. 944 """ 945 config_protect = self._portage.settings['CONFIG_PROTECT_MASK'] 946 return [os.path.expandvars(x) for x in config_protect.split()]
947
948 - def get_download_mirrors(self, mirror_name):
949 """ 950 Reimplemented from SpmPlugin class. 951 """ 952 mirrors = [] 953 if mirror_name in self._portage.thirdpartymirrors: 954 mirrors.extend(self._portage.thirdpartymirrors[mirror_name]) 955 return mirrors
956
957 - def packages_repositories_metadata_update(self, actions):
958 """ 959 Reimplemented from SpmPlugin class. 960 """ 961 root = etpConst['systemroot'] + os.path.sep 962 vartree = self._get_portage_vartree(root = root) 963 move = vartree.dbapi.move_ent 964 slotmove = vartree.dbapi.move_slot_ent 965 966 def prepare_move(command): 967 cmd, old, new = command 968 try: 969 return [ 970 cmd, 971 self._portage.dep.Atom(old), 972 self._portage.dep.Atom(new)] 973 except self._portage.exception.InvalidAtom: 974 return None
975 976 def prepare_slotmove(command): 977 cmd, atom, old, new = command 978 try: 979 return [ 980 cmd, 981 self._portage.dep.Atom(atom), 982 old, 983 new] 984 except self._portage.exception.InvalidAtom: 985 return None
986 987 commands = [] 988 for action in actions: 989 mytxt = "%s: %s: %s." % ( 990 brown(_("SPM")), 991 purple(_("action")), 992 blue(action), 993 ) 994 self.__output.output( 995 mytxt, 996 importance = 1, 997 level = "warning", 998 header = darkred(" * ") 999 ) 1000 1001 command = action.split() 1002 if command[0] == "move": 1003 command = prepare_move(command) 1004 if command is None: 1005 continue 1006 move(command) 1007 commands.append(command) 1008 elif command[0] == "slotmove": 1009 command = prepare_slotmove(command) 1010 if command is None: 1011 continue 1012 slotmove(command) 1013 commands.append(command) 1014 1015 mytxt = "%s: %s." % ( 1016 brown(_("SPM")), 1017 purple(_("updating metadata")), 1018 ) 1019 self.__output.output( 1020 mytxt, 1021 importance = 1, 1022 level = "warning", 1023 header = darkred(" * ") 1024 ) 1025 vartree.dbapi.update_ents(commands) 1026
1027 - def match_package(self, package, match_type = None):
1028 """ 1029 Reimplemented from SpmPlugin class. 1030 """ 1031 if match_type is None: 1032 match_type = "bestmatch-visible" 1033 elif match_type not in PortagePlugin.SUPPORTED_MATCH_TYPES: 1034 raise KeyError() 1035 try: 1036 return self._portage.portdb.xmatch(match_type, package) 1037 except self._portage.exception.PortageException: 1038 raise KeyError()
1039
1040 - def match_installed_package(self, package, match_all = False, root = None):
1041 """ 1042 Reimplemented from SpmPlugin class. 1043 """ 1044 if root is None: 1045 root = etpConst['systemroot'] + os.path.sep 1046 1047 # Portage >=2.2_alpha50 returns AmbiguousPackageName 1048 # if the package dependency passed is too ambiguous 1049 # By contract, we have to raise KeyError. 1050 ambiguous_pkg_name_exception = getattr(self._portage.exception, 1051 "AmbiguousPackageName", self._portage.exception.PortageException) 1052 vartree = self._get_portage_vartree(root = root) 1053 try: 1054 matches = vartree.dep_match(package) or [] 1055 except self._portage.exception.InvalidAtom as err: 1056 raise KeyError(err) 1057 except ambiguous_pkg_name_exception as err: 1058 raise KeyError(err) 1059 1060 if match_all: 1061 return matches 1062 elif matches: 1063 return matches[-1] 1064 return ''
1065
1066 - def generate_package(self, package, file_save_dir, builtin_debug = False):
1067 """ 1068 Reimplemented from SpmPlugin class. 1069 """ 1070 pkgcat, pkgname = package.split("/", 1) 1071 file_save_name = file_save_dir + os.path.sep + pkgcat + ":" + \ 1072 pkgname 1073 file_save_path = file_save_name + etpConst['packagesext'] 1074 1075 dbdir = os.path.join(self._get_vdb_path(), pkgcat, pkgname) 1076 1077 trees = self._portage.db["/"] 1078 vartree = trees["vartree"] 1079 dblnk = self._portage.dblink(pkgcat, pkgname, "/", vartree.settings, 1080 treetype="vartree", vartree=vartree) 1081 locked = False 1082 if etpConst['uid'] == 0: 1083 dblnk.lockdb() 1084 locked = True 1085 1086 generated_package_files = [] 1087 # store package file in temporary directory, then move 1088 # atomicity ftw 1089 1090 tmp_fd, tmp_file = None, None 1091 debug_tmp_fd, debug_tmp_file = None, None 1092 try: 1093 tmp_fd, tmp_file = const_mkstemp(dir = file_save_dir, 1094 prefix = "entropy.spm.Portage.generate_package._tar") 1095 os.close(tmp_fd) 1096 tmp_fd = None 1097 # cannot use fdopen with tarfile 1098 tar = tarfile.open(tmp_file, mode = "w:bz2") 1099 debug_tar = None 1100 debug_tmp_file = None 1101 debug_file_save_path = None 1102 if not builtin_debug: 1103 # since we cannot add entropy revision yet, we at least use 1104 # the timestamp (md5 hashed) as part of the filename 1105 cur_t = time.time() 1106 m = hashlib.md5() 1107 m.update(const_convert_to_rawstring(cur_t)) 1108 m.update(const_convert_to_rawstring(package)) 1109 debug_file_save_path = file_save_name + "." + m.hexdigest() + \ 1110 etpConst['packagesdebugext'] 1111 debug_tmp_fd, debug_tmp_file = const_mkstemp( 1112 dir = file_save_dir, 1113 prefix = "entropy.spm.Portage.generate_package._debug_tar") 1114 os.close(debug_tmp_fd) 1115 debug_tmp_fd = None 1116 debug_tar = tarfile.open(debug_tmp_file, mode = "w:bz2") 1117 1118 contents = dblnk.getcontents() 1119 paths = sorted(contents) 1120 1121 def _is_debug_path(obj): 1122 for debug_path in etpConst['splitdebug_dirs']: 1123 if obj.startswith(debug_path): 1124 return True 1125 return False
1126 1127 debug_empty = True 1128 for path in paths: 1129 try: 1130 exist = os.lstat(path) 1131 except OSError: 1132 continue # skip file 1133 ftype = contents[path][0] 1134 lpath = path 1135 arcname = path[1:] 1136 if 'dir' == ftype and \ 1137 not stat.S_ISDIR(exist.st_mode) and \ 1138 os.path.isdir(lpath): 1139 lpath = os.path.realpath(lpath) 1140 tarinfo = tar.gettarinfo(lpath, arcname) 1141 1142 tar_obj = None 1143 if debug_tar is not None: 1144 if _is_debug_path(path): 1145 tar_obj = debug_tar 1146 if not tarinfo.isdir(): 1147 debug_empty = False 1148 if tar_obj is None: 1149 tar_obj = tar 1150 1151 if stat.S_ISREG(exist.st_mode): 1152 with open(path, "rb") as f: 1153 tar_obj.addfile(tarinfo, f) 1154 else: 1155 tar_obj.addfile(tarinfo) 1156 1157 tar.close() 1158 if debug_tar is not None: 1159 debug_tar.close() 1160 # appending xpak informations 1161 tbz2 = xpak.tbz2(tmp_file) 1162 tbz2.recompose(dbdir) 1163 if locked: 1164 dblnk.unlockdb() 1165 # now do atomic move 1166 const_setup_file(tmp_file, etpConst['entropygid'], 0o664) 1167 os.rename(tmp_file, file_save_path) 1168 generated_package_files.append(file_save_path) 1169 1170 if debug_tar is not None: 1171 if debug_empty: 1172 os.remove(debug_tmp_file) 1173 else: 1174 const_setup_file( 1175 debug_tmp_file, etpConst['entropygid'], 0o664) 1176 os.rename(debug_tmp_file, debug_file_save_path) 1177 generated_package_files.append(debug_file_save_path) 1178 1179 for package_file in generated_package_files: 1180 if not const_file_readable(package_file): 1181 raise self.Error( 1182 "Spm:generate_package %s: %s %s" % ( 1183 _("error"), 1184 package_file, 1185 _("not readable"), 1186 ) 1187 ) 1188 1189 return generated_package_files 1190 1191 finally: 1192 for fd in (tmp_fd, debug_tmp_fd): 1193 if fd is not None: 1194 try: 1195 os.close(fd) 1196 except OSError: 1197 pass 1198 for path in (tmp_file, debug_tmp_file): 1199 if path is not None: 1200 try: 1201 os.remove(path) 1202 except OSError as err: 1203 if err.errno != errno.ENOENT: 1204 raise 1205
1206 - def _add_kernel_dependency_to_pkg(self, pkg_data, pkg_dir_prefix):
1207 1208 # NOTE: i hate hardcoded shit, but our SPM doesn't support 1209 # kernel dependencies. 1210 kmod_pfx = "/lib/modules" 1211 kmox_sfx = ".ko" 1212 1213 # these have to be kept in sync with kswitch 1214 kernels_dir = "/etc/kernels" 1215 release_level = "RELEASE_LEVEL" 1216 1217 content = [x for x in pkg_data['content'] if x.startswith(kmod_pfx)] 1218 content = [x for x in content if x.endswith(kmox_sfx)] 1219 enc = etpConst['conf_encoding'] 1220 1221 # filter out hidden files 1222 if not content: 1223 return 1224 1225 def read_kern_vermagic(ko_path): 1226 1227 # apparently upstream is idiot 100% tested 1228 modinfo_path = None 1229 for _path in ("/sbin", "/usr/bin", "/bin"): 1230 modinfo_path = os.path.join(_path, "modinfo") 1231 if os.path.lexists(modinfo_path): 1232 break 1233 if modinfo_path is None: 1234 warnings.warn("Something is wrong, no modinfo on the system") 1235 return 1236 1237 tmp_fd, tmp_file = const_mkstemp( 1238 prefix="entropy.spm.portage._add_kernel_dependency_to_pkg") 1239 try: 1240 with os.fdopen(tmp_fd, "w") as tmp_fw: 1241 rc = subprocess.call((modinfo_path, "-F", "vermagic", 1242 ko_path), stdout = tmp_fw, stderr = tmp_fw) 1243 1244 with codecs.open(tmp_file, "r", encoding=enc) as tmp_r: 1245 modinfo_output = tmp_r.read().strip() 1246 finally: 1247 try: 1248 os.close(tmp_fd) 1249 except OSError: 1250 pass 1251 os.remove(tmp_file) 1252 1253 if rc != 0: 1254 warnings.warn( 1255 "Cannot properly guess kernel module vermagic, error" + \ 1256 modinfo_output) 1257 return 1258 1259 return modinfo_output.split()[0]
1260 1261 def find_kernel(vermagic): 1262 k_dirs = [] 1263 try: 1264 k_dirs += os.listdir(kernels_dir) 1265 except (OSError, IOError): 1266 pass 1267 1268 k_dirs = [os.path.join(kernels_dir, x) for x in k_dirs] 1269 k_dirs = [x for x in k_dirs if os.path.isdir(x)] 1270 1271 for k_dir in k_dirs: 1272 rl_path = os.path.join(k_dir, release_level) 1273 if not os.path.lexists(rl_path): 1274 # skip without trying to open() it. 1275 continue 1276 1277 level = None 1278 try: 1279 with codecs.open(rl_path, "r", encoding = enc) as rl_f: 1280 level = rl_f.read(512).strip() 1281 except (OSError, IOError): 1282 continue 1283 1284 if level != vermagic: 1285 # not the vermagic we're looking for. 1286 continue 1287 1288 owners = self.search_paths_owners([rl_path]) 1289 if not owners: 1290 # wtf? ignore dependency then 1291 continue 1292 atom_slot = sorted(owners.keys())[0] # deterministic 1293 return atom_slot # (atom, slot) tuple 1294 1295 vermagic_cache = set() 1296 for item in content: 1297 1298 # read vermagic 1299 item_pkg_path = os.path.join(pkg_dir_prefix, item[1:]) 1300 kern_vermagic = read_kern_vermagic(item_pkg_path) 1301 if kern_vermagic is None: 1302 continue 1303 1304 if kern_vermagic in vermagic_cache: 1305 # skip, already processed 1306 continue 1307 vermagic_cache.add(kern_vermagic) 1308 1309 if not entropy.dep.is_valid_package_tag(kern_vermagic): 1310 # argh! wtf, this is invalid! 1311 continue 1312 1313 # properly set package tag and slot 1314 pkg_data['versiontag'] = kern_vermagic 1315 # tweak slot, yeah 1316 pkg_data['slot'] = "%s,%s" % (pkg_data['slot'], kern_vermagic,) 1317 1318 # now try to guess package providing that vermagic 1319 k_atom_slot = find_kernel(kern_vermagic) 1320 if k_atom_slot is None: 1321 # cannot bind a kernel package to this vermagic 1322 continue 1323 1324 k_atom, _k_slot = k_atom_slot 1325 # yippie, kernel dep installed also for SPM 1326 return "=%s~-1" % (k_atom,) 1327
1328 - def _get_default_virtual_pkg(self, virtual_key):
1329 defaults = self._portage.settings.getvirtuals()[virtual_key] 1330 if defaults: 1331 return defaults[0]
1332
1333 - def __source_env_get_var(self, env_file, env_var):
1334 current_mod = sys.modules[__name__].__file__ 1335 dirname = os.path.dirname(current_mod) 1336 exec_path = os.path.join(dirname, "env_sourcer.sh") 1337 args = [exec_path, env_file, env_var] 1338 tmp_fd, tmp_path = None, None 1339 tmp_err_fd, tmp_err_path = None, None 1340 raw_enc = etpConst['conf_raw_encoding'] 1341 1342 try: 1343 tmp_fd, tmp_path = const_mkstemp( 1344 prefix="entropy.spm.__source_env_get_var") 1345 tmp_err_fd, tmp_err_path = const_mkstemp( 1346 prefix="entropy.spm.__source_env_get_var_err") 1347 1348 sts = subprocess.call(args, stdout = tmp_fd, stderr = tmp_err_fd) 1349 if sts != 0: 1350 raise IOError("cannot source %s and get %s" % ( 1351 env_file, env_var,)) 1352 1353 # this way buffers are flushed out 1354 os.close(tmp_fd) 1355 tmp_fd = None 1356 with codecs.open(tmp_path, "r", encoding = raw_enc) as tmp_r: 1357 # cut down to 1M... anything longer is just insane 1358 output = tmp_r.read(1024000).rstrip() 1359 1360 return const_convert_to_unicode(output, enctype = raw_enc) 1361 1362 finally: 1363 for fd in (tmp_fd, tmp_err_fd): 1364 if fd is not None: 1365 try: 1366 os.close(fd) 1367 except OSError: 1368 pass 1369 for path in (tmp_path, tmp_err_path): 1370 if path is not None: 1371 try: 1372 os.remove(path) 1373 except OSError as err: 1374 if err.errno != errno.ENOENT: 1375 raise
1376
1377 - def __pkg_sources_filtering(self, sources):
1378 sources.discard("->") 1379 sources = set((x for x in sources if "/" in x)) 1380 return sources
1381 1382 @staticmethod
1383 - def dump_package_metadata(entropy_package_path, metadata_path):
1384 """ 1385 Reimplemented from SpmPlugin class. 1386 """ 1387 return xpaktools.suck_xpak(entropy_package_path, metadata_path)
1388 1389 @staticmethod
1390 - def aggregate_package_metadata(entropy_package_path, metadata_path):
1391 """ 1392 Reimplemented from SpmPlugin class. 1393 """ 1394 return xpaktools.aggregate_xpak(entropy_package_path, metadata_path)
1395
1396 - def extract_package_metadata(self, package_file, license_callback = None, 1397 restricted_callback = None):
1398 """ 1399 Reimplemented from SpmPlugin class. 1400 """ 1401 data = {} 1402 system_settings = SystemSettings() 1403 1404 # fill package name and version 1405 data['digest'] = entropy.tools.md5sum(package_file) 1406 data['signatures'] = { 1407 'sha1': entropy.tools.sha1(package_file), 1408 'sha256': entropy.tools.sha256(package_file), 1409 'sha512': entropy.tools.sha512(package_file), 1410 'gpg': None, # GPG signature will be filled later on, if enabled 1411 } 1412 data['datecreation'] = str(os.path.getmtime(package_file)) 1413 data['size'] = str(entropy.tools.get_file_size(package_file)) 1414 1415 # This allows os.* functions on Python2 to use unicode, correctly. 1416 # See the issues with puppet-agent (unit tests in db.py). 1417 tmp_dir = const_convert_to_unicode( 1418 const_mkdtemp(prefix="entropy.spm._extract"), 1419 enctype = sys.getfilesystemencoding()) 1420 meta_dir = os.path.join(tmp_dir, "portage") 1421 pkg_dir = os.path.join(tmp_dir, "pkg") 1422 os.mkdir(meta_dir) 1423 os.mkdir(pkg_dir) 1424 1425 # extract stuff 1426 xpaktools.extract_xpak(package_file, meta_dir) 1427 empty_content = False 1428 try: 1429 entropy.tools.uncompress_tarball(package_file, 1430 extract_path = pkg_dir, catch_empty = False) 1431 except tarfile.ReadError: 1432 empty_content = True 1433 1434 env_bz2 = os.path.join(meta_dir, PortagePlugin.ENV_FILE_COMP) 1435 uncompressed_env_file = None 1436 if const_file_readable(env_bz2): 1437 # when extracting fake metadata, env_bz2 can be unavailable 1438 uncompressed_env_file = entropy.tools.unpack_bzip2(env_bz2) 1439 1440 # package injection status always false by default 1441 # developer can change metadatum after this function 1442 data['injected'] = False 1443 data['branch'] = system_settings['repositories']['branch'] 1444 1445 portage_entries = self._extract_pkg_metadata_generate_extraction_dict() 1446 enc = etpConst['conf_encoding'] 1447 for item in portage_entries: 1448 1449 value = '' 1450 try: 1451 item_path = os.path.join(meta_dir, 1452 portage_entries[item]['path']) 1453 with codecs.open(item_path, "r", encoding=enc) as item_f: 1454 value = item_f.readline().strip() 1455 except IOError: 1456 if portage_entries[item]['critical']: 1457 if uncompressed_env_file is None: 1458 raise 1459 env_var = portage_entries[item].get('env') 1460 if env_var is None: 1461 raise 1462 value = self.__source_env_get_var( 1463 uncompressed_env_file, env_var) 1464 data[item] = value 1465 1466 # EAPI5 support 1467 data['slot'] = self._strip_slash_from_slot(data['slot']) 1468 1469 #if not data['chost']: 1470 # # stupid portage devs and virtual pkgs! 1471 # # try to cope 1472 # # WARNING: this can be erroneously set to currently running 1473 # # system CHOST that could not match the CHOST the package was 1474 # # built with 1475 # data['chost'] = self._portage.settings['CHOST'] 1476 1477 # Entropy PMS support inside Portage. 1478 # This way it is possible to append Entropy-related 1479 # dependencies to packages, supported variables: 1480 # ENTROPY_RDEPEND, ENTROPY_PDEPEND, ENTROPY_DEPEND 1481 e_dep_lst = [ 1482 ("ENTROPY_RDEPEND", "rdepend"), 1483 ("ENTROPY_PDEPEND", "pdepend"), 1484 ("ENTROPY_DEPEND", "depend"), 1485 ] 1486 if uncompressed_env_file is not None: 1487 for e_dep, dkey in e_dep_lst: 1488 e_xdepend = self.__source_env_get_var( 1489 uncompressed_env_file, e_dep) 1490 if e_xdepend: 1491 data[dkey] += " " 1492 data[dkey] += e_xdepend 1493 1494 if not data['spm_repository']: # make sure it's set to None 1495 data['spm_repository'] = None 1496 1497 if not data['sources'] and (uncompressed_env_file is not None): 1498 # when extracting fake metadata, env_bz2 can be unavailable 1499 uncompressed_env_file = entropy.tools.unpack_bzip2(env_bz2) 1500 # unfortunately upstream dropped SRC_URI file support 1501 data['sources'] = self.__source_env_get_var( 1502 uncompressed_env_file, "SRC_URI") 1503 1504 # workout pf 1505 pf_atom = os.path.join(data['category'], data['pf']) 1506 pkgcat, pkgname, pkgver, pkgrev = entropy.dep.catpkgsplit( 1507 pf_atom) 1508 if pkgrev != "r0": 1509 pkgver += "-%s" % (pkgrev,) 1510 data['name'] = pkgname 1511 data['version'] = pkgver 1512 # bye bye pf 1513 del data['pf'] 1514 1515 # setup spm_phases properly 1516 spm_defined_phases_path = os.path.join(meta_dir, 1517 portage_entries['spm_phases']['path']) 1518 if not os.path.isfile(spm_defined_phases_path): 1519 # force to None, because metadatum can be '', which is valid 1520 data['spm_phases'] = None 1521 1522 try: 1523 data['counter'] = int(data['counter']) 1524 except ValueError: 1525 # -2 values will be insterted as incremental 1526 # negative values into the database 1527 data['counter'] = -2 1528 1529 data['keywords'] = [x.strip() for x in data['keywords'].split() \ 1530 if x.strip()] 1531 if not data['keywords']: 1532 # support for packages with no keywords 1533 data['keywords'].insert(0, "**") 1534 1535 data['keywords'] = set(data['keywords']) 1536 1537 content_file = os.path.join(meta_dir, 1538 PortagePlugin.xpak_entries['contents']) 1539 # even if pkg_dir is tweaked after this, it's fine anyway for 1540 # packages emerge with -B, because for those, we also get the 1541 # full package_file (not a fake one). 1542 data['content'] = self._extract_pkg_metadata_content(content_file, 1543 package_file, pkg_dir) 1544 # There are packages providing no files, even if given package_file 1545 # is complete (meaning, it contains real file. Not a fake one, like 1546 # it can happen with "equo rescue spmsync", to make things quicker). 1547 # So, to differentiate between "complete package file with no content" 1548 # and "fake package file, with arbitrary content", we check 1549 # data['content']. If empty_content is True but data['content'] is 1550 # contains something, then we have a fake package_file. 1551 if data['content'] and empty_content: 1552 # fake package_file, need to tweak pkg_dir to systemroot 1553 pkg_dir = etpConst['systemroot'] + os.path.sep 1554 1555 # at this point, pkg_dir must point to a valid "root" directory 1556 # because checksums have to be calculated against files being available 1557 # in the package. The case above (when using equo rescue spmsync) is 1558 # fine too. 1559 data['content_safety'] = self._extract_pkg_metadata_content_safety( 1560 data['content'], pkg_dir) 1561 data['disksize'] = entropy.tools.sum_file_sizes_hardlinks([ 1562 os.path.join(pkg_dir, x) for x, y in data['content'].items() \ 1563 if y == "obj"]) 1564 data['provided_libs'] = self._extract_pkg_metadata_provided_libs( 1565 pkg_dir, data['content']) 1566 1567 needed_elf_file = os.path.join(meta_dir, 1568 PortagePlugin.xpak_entries['needed.elf.2']) 1569 needed_file = os.path.join(meta_dir, 1570 PortagePlugin.xpak_entries['needed']) 1571 1572 if os.path.isfile(needed_elf_file): 1573 needed_libs = self._extract_pkg_metadata_needed_libs_elf_2( 1574 needed_elf_file) 1575 # deprecated, kept for backward compatibility 1576 data['needed'] = tuple( 1577 sorted((soname, elfc) for _x, _x, soname, elfc, _x 1578 in needed_libs) 1579 ) 1580 data['needed_libs'] = needed_libs 1581 elif os.path.isfile(needed_file): 1582 needed_libs = self._extract_pkg_metadata_needed_libs( 1583 needed_elf_file) 1584 # deprecated, kept for backward compatibility 1585 # fallback to old NEEDED file 1586 data['needed'] = tuple( 1587 sorted((soname, elfc) for _x, _x, soname, elfc, _x 1588 in needed_libs) 1589 ) 1590 data['needed_libs'] = needed_libs 1591 else: 1592 needed_libs = self._generate_needed_libs_elf_2( 1593 pkg_dir, data['content']) 1594 # deprecated, kept for backward compatibility 1595 # some PMS like pkgcore don't generate NEEDED.ELF.2 1596 # generate one ourselves if possible. May generate 1597 # a slighly different (more complete?) content. 1598 data['needed'] = tuple( 1599 sorted((soname, elfc) for _x, _x, soname, elfc, _x 1600 in needed_libs) 1601 ) 1602 data['needed_libs'] = needed_libs 1603 1604 # [][][] Kernel dependent packages hook [][][] 1605 data['versiontag'] = '' 1606 kern_dep_key = None 1607 1608 if data['category'] != PortagePlugin.KERNEL_CATEGORY: 1609 kern_dep_key = self._add_kernel_dependency_to_pkg(data, pkg_dir) 1610 elif uncompressed_env_file is not None: 1611 # we may have packages in sys-kernel category holding 1612 # kernel modules without being kernels 1613 # ETYPE is a typical environment variable used by kernel 1614 # sources and binaries (and firmwares). 1615 # If it's set, it means that this is a kernel ebuild. 1616 etype = self.__source_env_get_var( 1617 uncompressed_env_file, "ETYPE") 1618 if not etype: 1619 kern_dep_key = self._add_kernel_dependency_to_pkg(data, pkg_dir) 1620 1621 file_ext = PortagePlugin.EBUILD_EXT 1622 ebuilds_in_path = [x for x in os.listdir(meta_dir) if \ 1623 x.endswith(file_ext)] 1624 1625 if not data['versiontag'] and ebuilds_in_path: 1626 # has the user specified a custom package tag inside the ebuild 1627 ebuild_path = os.path.join(meta_dir, ebuilds_in_path[0]) 1628 data['versiontag'] = self._extract_pkg_metadata_ebuild_entropy_tag( 1629 ebuild_path) 1630 1631 data['trigger'] = const_convert_to_rawstring("") 1632 triggers_dir = SpmPlugin.external_triggers_dir() 1633 trigger_file = os.path.join(triggers_dir, data['category'], 1634 data['name'], etpConst['triggername']) 1635 1636 try: 1637 with open(trigger_file, "rb") as trig_f: 1638 data['trigger'] = trig_f.read() 1639 except (OSError, IOError) as err: 1640 if err.errno != errno.ENOENT: 1641 raise 1642 1643 # Get Spm ChangeLog 1644 pkgatom = "%s/%s-%s" % (data['category'], data['name'], 1645 data['version'],) 1646 try: 1647 changelog = self.get_package_changelog(pkgatom) 1648 if changelog is not None: 1649 data['changelog'] = const_convert_to_unicode(changelog) 1650 else: 1651 data['changelog'] = None 1652 except (UnicodeEncodeError, UnicodeDecodeError,) as e: 1653 sys.stderr.write("%s: %s, %s\n" % ( 1654 "changelog string conversion error", e, 1655 package_file,) 1656 ) 1657 data['changelog'] = None 1658 except: 1659 data['changelog'] = None 1660 1661 if not data['eapi']: 1662 data['eapi'] = None 1663 portage_metadata = self._calculate_dependencies( 1664 data['iuse'], data['use'], data['license'], data['depend'], 1665 data['rdepend'], data['pdepend'], data['bdepend'], 1666 data['provide'], data['sources'], data['eapi'] 1667 ) 1668 1669 data['license'] = " ".join(portage_metadata['LICENSE']) 1670 data['useflags'] = [] 1671 data['useflags'].extend(portage_metadata['ENABLED_USE']) 1672 # consider forced use flags always on 1673 data['useflags'].extend(portage_metadata['USE_FORCE']) 1674 for my_use in portage_metadata['DISABLED_USE']: 1675 data['useflags'].append("-"+my_use) 1676 1677 # useflags must be a set, as returned by entropy.db.getPackageData 1678 data['useflags'] = set(data['useflags']) 1679 # sources must be a set, as returned by entropy.db.getPackageData 1680 data['sources'] = set(portage_metadata['SRC_URI']) 1681 data['sources'] = self.__pkg_sources_filtering(data['sources']) 1682 1683 data['pkg_dependencies'] = set() 1684 1685 dep_keys = { 1686 "RDEPEND": etpConst['dependency_type_ids']['rdepend_id'], 1687 "PDEPEND": etpConst['dependency_type_ids']['pdepend_id'], 1688 "DEPEND": etpConst['dependency_type_ids']['bdepend_id'], 1689 "BDEPEND": etpConst['dependency_type_ids']['bdepend_id'], 1690 } 1691 dep_duplicates = set() 1692 for dep_key, dep_val in dep_keys.items(): 1693 for x in portage_metadata[dep_key]: 1694 if x.startswith("!") or (x in ("(", "||", ")", "")): 1695 continue 1696 1697 if (x, dep_val) in dep_duplicates: 1698 continue 1699 dep_duplicates.add((x, dep_val)) 1700 1701 data['pkg_dependencies'].add((x, dep_val)) 1702 1703 dep_duplicates.clear() 1704 1705 data['conflicts'] = [x.replace("!", "") for x in \ 1706 portage_metadata['RDEPEND'] + \ 1707 portage_metadata['PDEPEND'] if \ 1708 x.startswith("!") and not x in ("(", "||", ")", "")] 1709 1710 if kern_dep_key is not None: 1711 kern_dep_id = etpConst['dependency_type_ids']['rdepend_id'] 1712 data['pkg_dependencies'].add((kern_dep_key, kern_dep_id)) 1713 1714 # force a tuple object 1715 data['pkg_dependencies'] = tuple(data['pkg_dependencies']) 1716 1717 # conflicts must be a set, which is what is returned 1718 # by entropy.db.getPackageData 1719 data['conflicts'] = set(data['conflicts']) 1720 1721 # old-style virtual support, we need to check if this pkg provides 1722 # PROVIDE metadatum which points to itself, if so, this is the 1723 # default 1724 del data['provide'] 1725 provide_extended = set() 1726 myself_provide_key = data['category'] + "/" + data['name'] 1727 for provide_key in set(portage_metadata['PROVIDE']): 1728 is_provide_default = 0 1729 try: 1730 profile_default_provide = self._get_default_virtual_pkg( 1731 provide_key) 1732 except KeyError: 1733 profile_default_provide = 1 # cant be this 1734 1735 if profile_default_provide == myself_provide_key: 1736 is_provide_default = 1 1737 1738 provide_extended.add((provide_key, is_provide_default,)) 1739 1740 # this actually changes provide format 1741 data['provide_extended'] = provide_extended 1742 1743 # Get License text if possible 1744 # NOTE: this is sucky, because Portage XPAK metadata doesn't contain 1745 # license text, and we need to rely on PORTDIR, which is very bad 1746 data['licensedata'] = self._extract_pkg_metadata_license_data( 1747 data['spm_repository'], data['license']) 1748 1749 data['desktop_mime'], data['provided_mime'] = \ 1750 self._extract_pkg_metadata_desktop_mime( 1751 pkg_dir, data['content']) 1752 1753 data['mirrorlinks'] = self._extract_pkg_metadata_mirror_links( 1754 data['sources']) 1755 1756 # write only if it's a systempackage 1757 data['systempackage'] = False 1758 system_packages = [entropy.dep.dep_getkey(x) for x in \ 1759 self.get_system_packages()] 1760 if data['category'] + "/" + data['name'] in system_packages: 1761 data['systempackage'] = True 1762 1763 # write only if it's a systempackage 1764 data['config_protect'] = ' '.join(self.get_merge_protected_paths()) 1765 data['config_protect_mask'] = ' '.join( 1766 self.get_merge_protected_paths_mask()) 1767 1768 # etpapi must be int, as returned by entropy.db.getPackageData 1769 data['etpapi'] = int(etpConst['etpapi']) 1770 1771 # prepare download URL string, check licenses 1772 nonfree = False 1773 restricted = False 1774 if license_callback is not None: 1775 nonfree = not license_callback(data) 1776 if restricted_callback is not None: 1777 restricted = restricted_callback(data) 1778 data['download'] = entropy.tools.create_package_dirpath(data['branch'], 1779 nonfree = nonfree, restricted = restricted) 1780 data['download'] = os.path.join(data['download'], 1781 entropy.dep.create_package_relative_path( 1782 data['category'], data['name'], data['version'], 1783 data['versiontag'], 1784 sha1=data['signatures']['sha1'])) 1785 1786 # removing temporary directory 1787 shutil.rmtree(tmp_dir, True) 1788 1789 # clear unused metadata 1790 del data['use'], data['iuse'], data['depend'], data['pdepend'], \ 1791 data['rdepend'], data['bdepend'], data['eapi'] 1792 1793 return data
1794
1795 - def get_installed_package_content(self, package, root = None):
1796 """ 1797 Reimplemented from SpmPlugin class. 1798 """ 1799 if root is None: 1800 root = etpConst['systemroot'] + os.path.sep 1801 1802 cat, pkgv = package.split("/") 1803 return sorted(self._portage.dblink(cat, pkgv, root, 1804 self._portage.settings).getcontents())
1805
1806 - def get_packages(self, categories = None, filter_reinstalls = True):
1807 """ 1808 Reimplemented from SpmPlugin class. 1809 """ 1810 if categories is None: 1811 categories = [] 1812 1813 root = etpConst['systemroot'] + os.path.sep 1814 mysettings = self._get_portage_config(os.path.sep, root) 1815 portdb = self._get_portage_portagetree(root).dbapi 1816 1817 cps = portdb.cp_all() 1818 visibles = set() 1819 for cp in cps: 1820 if categories: 1821 if cp.split("/")[0] not in categories: 1822 continue 1823 1824 # get slots 1825 slots = set() 1826 atoms = self.match_package(cp, match_type = "match-visible") 1827 if atoms: 1828 for atom in atoms: 1829 slot = portdb.aux_get(atom, ["SLOT"])[0] 1830 slot = self._strip_slash_from_slot(slot) 1831 slots.add(slot) 1832 for slot in slots: 1833 visibles.add(cp + ":" + slot) 1834 1835 # now match visibles 1836 available = set() 1837 for visible in visibles: 1838 1839 match = self.match_package(visible) 1840 if not match: 1841 continue 1842 1843 if filter_reinstalls: 1844 installed = self.match_installed_package(visible) 1845 if installed != match: 1846 available.add(match) 1847 else: 1848 available.add(match) 1849 1850 return available
1851
1852 - def compile_packages(self, packages, stdin = None, stdout = None, 1853 stderr = None, environ = None, pid_write_func = None, 1854 pretend = False, verbose = False, fetch_only = False, 1855 build_only = False, no_dependencies = False, 1856 ask = False, coloured_output = False, oneshot = False):
1857 1858 cmd = [PortagePlugin._cmd_map['exec_cmd']] 1859 if pretend: 1860 cmd.append(PortagePlugin._cmd_map['pretend_cmd']) 1861 if verbose: 1862 cmd.append(PortagePlugin._cmd_map['verbose_cmd']) 1863 if ask: 1864 cmd.append(PortagePlugin._cmd_map['ask_cmd']) 1865 if oneshot: 1866 cmd.append(PortagePlugin._cmd_map['oneshot_cmd']) 1867 if not coloured_output: 1868 cmd.append(PortagePlugin._cmd_map['nocolor_cmd']) 1869 if fetch_only: 1870 cmd.append(PortagePlugin._cmd_map['fetchonly_cmd']) 1871 if build_only: 1872 cmd.append(PortagePlugin._cmd_map['buildonly_cmd']) 1873 if no_dependencies: 1874 cmd.append(PortagePlugin._cmd_map['nodeps_cmd']) 1875 1876 cmd.extend(packages) 1877 cmd_string = """\ 1878 %s && %s && %s 1879 """ % (PortagePlugin._cmd_map['env_update_cmd'], 1880 PortagePlugin._cmd_map['source_profile_cmd'], 1881 ' '.join(cmd) 1882 ) 1883 1884 env = os.environ.copy() 1885 if environ is not None: 1886 env.update(environ) 1887 1888 proc = subprocess.Popen(cmd_string, stdout = stdout, stderr = stderr, 1889 stdin = stdin, env = env, shell = True) 1890 if pid_write_func is not None: 1891 pid_write_func(proc.pid) 1892 return proc.wait()
1893
1894 - def environment_update(self):
1895 args = (PortagePlugin._cmd_map['env_update_cmd'],) 1896 try: 1897 # inherit stdin, stderr, stdout from parent 1898 proc = subprocess.Popen(args, stdout = sys.stdout, 1899 stderr = sys.stderr, stdin = sys.stdin) 1900 except OSError as err: 1901 if err.errno != errno.ENOENT: 1902 raise 1903 return 1904 return proc.wait()
1905
1906 - def print_build_environment_info(self, stdin = None, stdout = None, 1907 stderr = None, environ = None, pid_write_func = None, 1908 coloured_output = False):
1909 1910 cmd = [PortagePlugin._cmd_map['exec_cmd'], 1911 PortagePlugin._cmd_map['info_cmd']] 1912 if not coloured_output: 1913 cmd.append(PortagePlugin._cmd_map['nocolor_cmd']) 1914 1915 cmd_string = """\ 1916 %s && %s && %s 1917 """ % (PortagePlugin._cmd_map['env_update_cmd'], 1918 PortagePlugin._cmd_map['source_profile_cmd'], 1919 ' '.join(cmd) 1920 ) 1921 1922 env = os.environ.copy() 1923 if environ is not None: 1924 env.update(environ) 1925 1926 proc = subprocess.Popen(cmd_string, stdout = stdout, stderr = stderr, 1927 stdin = stdin, env = env, shell = True) 1928 if pid_write_func is not None: 1929 pid_write_func(proc.pid) 1930 return proc.wait()
1931
1932 - def get_installed_packages(self, categories = None, root = None):
1933 """ 1934 Reimplemented from SpmPlugin class. 1935 """ 1936 vartree = self._get_portage_vartree(root = root) 1937 packages = vartree.dbapi.cpv_all() 1938 if not categories: 1939 return packages 1940 1941 def catfilter(pkg): 1942 if pkg.split("/", 1)[0] in categories: 1943 return True 1944 return False
1945 1946 return list(filter(catfilter, packages)) 1947
1948 - def get_user_selected_packages(self, root = None):
1949 """ 1950 Reimplemented from SpmPlugin class. 1951 """ 1952 world_atoms = set() 1953 1954 with self._PortageWorldSetLocker(self, root = root): 1955 world_file = self.get_user_installed_packages_file(root = root) 1956 enc = etpConst['conf_encoding'] 1957 1958 try: 1959 with codecs.open(world_file, "r", encoding=enc) \ 1960 as world_f: 1961 world_atoms |= set((x.strip() for x in \ 1962 world_f.readlines() if x.strip())) 1963 except (OSError, IOError) as err: 1964 if err.errno != errno.ENOENT: 1965 raise self.Error(err) 1966 except UnicodeDecodeError as err: 1967 raise self.Error("Portage world file is malformed") 1968 1969 return frozenset(world_atoms)
1970
1971 - def get_package_sets(self, builtin_sets):
1972 """ 1973 Reimplemented from SpmPlugin class. 1974 """ 1975 config = self._get_set_config() 1976 if config == None: 1977 return {} 1978 1979 mysets = config.getSets() 1980 if not builtin_sets: 1981 # attention, this is sensible to Portage API changes 1982 files = self._get_portage_sets_files_object() 1983 if files is not None: 1984 static_file_class = files.StaticFileSet 1985 # filter out Portage-generated sets object, those not being 1986 # an instance of portage._sets.files.StaticFileSet 1987 for key, obj in tuple(mysets.items()): 1988 if not isinstance(obj, static_file_class): 1989 mysets.pop(key) 1990 1991 set_data = {} 1992 for k, obj in mysets.items(): 1993 pset = obj.getAtoms() 1994 pset |= obj.getNonAtoms() 1995 set_data[k] = pset 1996 return set_data
1997
1998 - def convert_from_entropy_package_name(self, entropy_package_name):
1999 """ 2000 Reimplemented from SpmPlugin class. 2001 """ 2002 spm_name = entropy.dep.remove_tag(entropy_package_name) 2003 spm_name = entropy.dep.remove_entropy_revision(spm_name) 2004 return spm_name
2005
2006 - def assign_uid_to_installed_package(self, package, root = None):
2007 """ 2008 Reimplemented from SpmPlugin class. 2009 """ 2010 if root is None: 2011 root = etpConst['systemroot'] + os.path.sep 2012 2013 with self._PortageVdbLocker(self, root = root): 2014 2015 vartree = self._get_portage_vartree(root) 2016 dbbuild = self.get_installed_package_build_script_path(package, 2017 root = root) 2018 2019 counter_dir = os.path.dirname(dbbuild) 2020 counter_name = PortagePlugin.xpak_entries['counter'] 2021 counter_path = os.path.join(counter_dir, counter_name) 2022 2023 if not const_dir_readable(counter_dir): 2024 raise self.Error("SPM package directory not found") 2025 2026 enc = etpConst['conf_encoding'] 2027 try: 2028 with codecs.open(counter_path, "w", encoding=enc) as count_f: 2029 new_counter = vartree.dbapi.counter_tick( 2030 root, mycpv = package) 2031 count_f.write(const_convert_to_unicode(new_counter)) 2032 finally: 2033 self._bump_vartree_mtime(package, root = root) 2034 2035 return new_counter
2036
2037 - def resolve_package_uid(self, entropy_repository, 2038 entropy_repository_package_id):
2039 """ 2040 Reimplemented from SpmPlugin class. 2041 """ 2042 counter_path = PortagePlugin.xpak_entries['counter'] 2043 entropy_atom = entropy_repository.retrieveAtom( 2044 entropy_repository_package_id) 2045 2046 spm_name = self.convert_from_entropy_package_name(entropy_atom) 2047 build_path = self.get_installed_package_build_script_path(spm_name) 2048 atom_counter_path = os.path.join(os.path.dirname(build_path), 2049 counter_path) 2050 2051 enc = etpConst['conf_encoding'] 2052 try: 2053 with codecs.open(atom_counter_path, "r", encoding=enc) as f: 2054 counter = int(f.readline().strip()) 2055 except (OSError, IOError) as err: 2056 if err.errno == errno.ENOENT: 2057 return None 2058 raise 2059 except ValueError: 2060 raise self.Error("invalid Unique Identifier found") 2061 except Exception as e: 2062 raise self.Error("General SPM Error: %s" % (repr(e),)) 2063 2064 return counter
2065
2066 - def resolve_spm_package_uid(self, package):
2067 """ 2068 Reimplemented from SpmPlugin class. 2069 """ 2070 try: 2071 return int(self.get_installed_package_metadata(package, "COUNTER")) 2072 except ValueError: 2073 raise KeyError("invalid counter")
2074
2075 - def search_paths_owners(self, paths, exact_match = True):
2076 """ 2077 Reimplemented from SpmPlugin class. 2078 """ 2079 if not isinstance(paths, (list, set, frozenset, dict, tuple)): 2080 raise AttributeError("iterable needed") 2081 2082 matches = {} 2083 root = etpConst['systemroot'] + os.path.sep 2084 2085 # if qfile is avail, it's much faster than using Portage API 2086 qfile_exec = "/usr/bin/qfile" 2087 if os.path.lexists(qfile_exec): 2088 2089 qfile_args = (qfile_exec, "-q", "-C", "--skip-plibreg", "-R", root,) 2090 if exact_match: 2091 qfile_args += ("-v",) 2092 2093 rc = 0 2094 for filename in paths: 2095 2096 proc = subprocess.Popen(qfile_args + (filename,), 2097 stdout = subprocess.PIPE) 2098 rc = proc.wait() 2099 if rc != 0: 2100 # wtf?, fallback to old way 2101 proc.stdout.close() 2102 matches.clear() 2103 break 2104 2105 out = proc.stdout.read() 2106 if const_is_python3(): 2107 out = const_convert_to_unicode(out) 2108 2109 proc.stdout.close() 2110 pkgs = set([x.strip() for x in out.splitlines()]) 2111 for pkg in pkgs: 2112 slot = self.get_installed_package_metadata(pkg, "SLOT") 2113 obj = matches.setdefault((pkg, slot,), set()) 2114 obj.add(filename) 2115 2116 if rc == 0: 2117 return matches 2118 2119 mytree = self._get_portage_vartree(root) 2120 packages = mytree.dbapi.cpv_all() 2121 2122 for package in packages: 2123 cat, pkgv = package.split("/") 2124 content = self._portage.dblink(cat, pkgv, root, 2125 self._portage.settings).getcontents() 2126 2127 if exact_match: 2128 for filename in paths: 2129 if filename in content: 2130 myslot = self.get_installed_package_metadata(package, 2131 "SLOT") 2132 obj = matches.setdefault((package, myslot,), set()) 2133 obj.add(filename) 2134 else: 2135 for filename in paths: 2136 for myfile in content: 2137 if myfile.find(filename) == -1: 2138 continue 2139 myslot = self.get_installed_package_metadata(package, 2140 "SLOT") 2141 obj = matches.setdefault((package, myslot,), set()) 2142 obj.add(filename) 2143 2144 return matches
2145
2146 - def _reload_portage_if_required(self, phase, package_metadata):
2147 # filter out unwanted phases 2148 if phase not in ("postrm", "postinst"): 2149 return 2150 category, name = package_metadata['category'], package_metadata['name'] 2151 key = category + "/" + name 2152 # reload portage modules only if we're dealing with sys-apps/portage 2153 if key == PortagePlugin._PORTAGE_ENTROPY_PACKAGE_NAME: 2154 self._reload_modules()
2155
2156 - def _portage_doebuild(self, myebuild, action, action_metadata, mydo, 2157 tree, cpv, portage_tmpdir = None, licenses = None):
2158 2159 if licenses is None: 2160 licenses = [] 2161 2162 root = etpConst['systemroot'] + os.path.sep 2163 2164 # old way to avoid loop of deaths for entropy portage hooks 2165 os.environ["SKIP_EQUO_SYNC"] = "1" 2166 2167 # load metadata 2168 myebuilddir = os.path.dirname(myebuild) 2169 keys = sorted(self._portage.auxdbkeys) + ["repository"] 2170 metadata = {} 2171 enc = etpConst['conf_encoding'] 2172 2173 for key in keys: 2174 mykeypath = os.path.join(myebuilddir, key) 2175 try: 2176 with codecs.open(mykeypath, "r", encoding=enc) as f: 2177 metadata[key] = f.readline().strip() 2178 except (OSError, IOError) as err: 2179 if err.errno != errno.ENOENT: 2180 raise 2181 2182 ### END SETUP ENVIRONMENT 2183 2184 # find config 2185 mysettings = self._get_portage_config(os.path.sep, root) 2186 mysettings['EBUILD_PHASE'] = mydo 2187 mysettings['EMERGE_FROM'] = "binary" 2188 2189 # Always turn off FEATURES=noauto as it breaks the phase 2190 # execution. This has been also fixed in Portage in 2191 # commit 10017a62b227558ed446419a2133c1584676c01c 2192 mysettings.features.discard("noauto") 2193 2194 # Turn off ccache if it's set, pointless and might 2195 # generate warnings 2196 mysettings.features.discard("ccache") 2197 2198 # EAPI >=3 2199 mysettings["ACCEPT_LICENSE"] = const_convert_to_unicode( 2200 " ".join(licenses)) 2201 mysettings.backup_changes("ACCEPT_LICENSE") 2202 mysettings.regenerate() 2203 2204 mysettings['EAPI'] = "0" 2205 if 'EAPI' in metadata: 2206 mysettings['EAPI'] = metadata['EAPI'] 2207 2208 # workaround for scripts asking for user intervention 2209 mysettings['ROOT'] = root 2210 mysettings['CD_ROOT'] = "/tmp" 2211 2212 mysettings.backup_changes("EAPI") 2213 mysettings.backup_changes("EBUILD_PHASE") 2214 mysettings.backup_changes("EMERGE_FROM") 2215 mysettings.backup_changes("ROOT") 2216 mysettings.backup_changes("CD_ROOT") 2217 2218 try: # this is a >portage-2.1.4_rc11 feature 2219 env_wl = set(mysettings._environ_whitelist) 2220 # put our vars into whitelist 2221 env_wl.add("SKIP_EQUO_SYNC") 2222 env_wl.add("ACCEPT_LICENSE") 2223 env_wl.add("CD_ROOT") 2224 env_wl.add("ROOT") 2225 mysettings._environ_whitelist = frozenset(env_wl) 2226 except (AttributeError,): 2227 self.log_message(entropy.tools.get_traceback()) 2228 2229 portage_tmpdir_created = False # for pkg_postrm, pkg_prerm 2230 2231 if portage_tmpdir is None: 2232 # /tmp might be mounted using tmpfs, noexec, etc 2233 portage_tmpdir = const_mkdtemp(prefix="tmpdir_doebuild") 2234 portage_tmpdir_created = True 2235 elif not os.path.isdir(portage_tmpdir): 2236 os.makedirs(portage_tmpdir, 0o744) 2237 const_setup_perms(portage_tmpdir, etpConst['entropygid'], 2238 recursion = False) 2239 2240 if portage_tmpdir: 2241 mysettings['PORTAGE_TMPDIR'] = str(portage_tmpdir) 2242 mysettings.backup_changes("PORTAGE_TMPDIR") 2243 2244 # make sure that PORTDIR exists 2245 portdir = mysettings["PORTDIR"] 2246 try: 2247 os.makedirs(os.path.join(portdir, "licenses"), 0o755) 2248 except OSError: 2249 # best effort 2250 pass 2251 2252 cpv = str(cpv) 2253 mydbapi = self._portage.fakedbapi(settings=mysettings) 2254 2255 mydbapi.cpv_inject(cpv, metadata = metadata) 2256 mysettings.setcpv(cpv, mydb = mydbapi) 2257 2258 # This is part of EAPI=4, but Portage doesn't set REPLACED_BY_VERSION 2259 # if not inside dblink.treewalk(). So, we must set it here 2260 if (action == "install") and (action_metadata is not None) and \ 2261 (mydo in ("prerm", "postrm")): 2262 # NOTE: this is done AFTER setcpv to avoid having it to reset 2263 # this setting. It is better to NOT backup this variable 2264 mysettings["REPLACED_BY_VERSION"] = action_metadata['version'] 2265 2266 # cached vartree class 2267 vartree = self._get_portage_vartree(root = root) 2268 2269 if const_debug_enabled(): 2270 self.__output.output( 2271 "PortagePlugin<_portage_doebuild>, env: %s" % ( 2272 locals(),), 2273 importance = 0, 2274 header = "" 2275 ) 2276 2277 with LogFile(level = SystemSettings()['system']['log_level'], 2278 filename = etpConst['entropylogfile'], header = "[spm]") as logger: 2279 2280 oldsysstdout = sys.stdout 2281 oldsysstderr = sys.stderr 2282 splitter_out = None 2283 splitter_err = None 2284 try: 2285 if is_mute(): 2286 tmp_fd, tmp_file = const_mkstemp( 2287 prefix="entropy.spm.portage._portage_doebuild") 2288 tmp_fw = os.fdopen(tmp_fd, "w") 2289 fd_pipes = { 2290 0: sys.stdin.fileno(), 2291 1: tmp_fw.fileno(), 2292 2: tmp_fw.fileno(), 2293 } 2294 else: 2295 splitter_out = StdoutSplitter( 2296 mydo, logger, sys.stdout) 2297 splitter_err = StdoutSplitter( 2298 mydo, logger, sys.stderr) 2299 fd_pipes = { 2300 0: sys.stdin.fileno(), 2301 1: splitter_out.fileno(), 2302 2: splitter_err.fileno(), 2303 } 2304 2305 rc = self._portage.doebuild( 2306 str(myebuild), 2307 str(mydo), 2308 settings = mysettings, 2309 tree = tree, 2310 mydbapi = mydbapi, 2311 vartree = vartree, 2312 debug = const_debug_enabled(), 2313 fd_pipes = fd_pipes, 2314 use_cache = 0 2315 ) 2316 2317 except self._portage.exception.UnsupportedAPIException as err: 2318 logger.write(entropy.tools.get_traceback()) 2319 raise self.OutdatedPhaseError(err) 2320 2321 except Exception as err: 2322 logger.write(entropy.tools.get_traceback()) 2323 raise self.PhaseError(err) 2324 2325 finally: 2326 sys.stdout = oldsysstdout 2327 sys.stderr = oldsysstderr 2328 if splitter_out is not None: 2329 try: 2330 splitter_out.close() 2331 except OSError: 2332 pass 2333 if splitter_err is not None: 2334 try: 2335 splitter_err.close() 2336 except OSError: 2337 pass 2338 if is_mute(): 2339 tmp_fw.flush() 2340 tmp_fw.close() 2341 try: 2342 os.remove(tmp_file) 2343 except OSError: 2344 pass 2345 2346 if portage_tmpdir_created: 2347 shutil.rmtree(portage_tmpdir, True) 2348 2349 del mydbapi 2350 del metadata 2351 del keys 2352 2353 if rc != 0: 2354 raise self.PhaseFailure( 2355 "Phase terminated with exit status: %d" % (rc,), 2356 rc)
2357 2358 @staticmethod
2359 - def _pkg_compose_atom(package_metadata):
2360 return package_metadata['category'] + "/" + \ 2361 package_metadata['name'] + "-" + package_metadata['version']
2362 2363 @staticmethod
2364 - def _pkg_compose_xpak_ebuild(package_metadata):
2365 package = PortagePlugin._pkg_compose_atom(package_metadata) 2366 return os.path.join(package_metadata['xpakdir'], 2367 os.path.basename(package) + PortagePlugin.EBUILD_EXT)
2368
2369 - def _pkg_remove_overlayed_ebuild(self, moved_ebuild):
2370 2371 mydir = os.path.dirname(moved_ebuild) 2372 shutil.rmtree(mydir, True) 2373 mydir = os.path.dirname(mydir) 2374 content = os.listdir(mydir) 2375 while not content: 2376 try: 2377 os.rmdir(mydir) 2378 except OSError: 2379 # cannot remove further 2380 break 2381 mydir = os.path.dirname(mydir) 2382 content = os.listdir(mydir)
2383
2384 - def _pkg_remove_ebuild_env_setup_hook(self, ebuild):
2385 2386 ebuild_path = os.path.dirname(ebuild) 2387 2388 myroot = os.path.sep 2389 if etpConst['systemroot']: 2390 myroot = etpConst['systemroot'] + os.path.sep 2391 2392 # we need to fix ROOT= if it's set inside environment 2393 bz2envfile = os.path.join(ebuild_path, PortagePlugin.ENV_FILE_COMP) 2394 if os.path.isfile(bz2envfile) and os.path.isdir(myroot): 2395 envfile = entropy.tools.unpack_bzip2(bz2envfile) 2396 bzf = bz2.BZ2File(bz2envfile, "w") 2397 with open(envfile, "rb") as f: 2398 line = f.readline() 2399 root_tag = const_convert_to_rawstring("ROOT=") 2400 while line: 2401 if line.startswith(root_tag): 2402 line = const_convert_to_rawstring( 2403 "ROOT=%s\n" % (myroot,)) 2404 bzf.write(line) 2405 line = f.readline() 2406 bzf.close() 2407 os.remove(envfile)
2408
2409 - def _pkg_remove_setup_ebuild_env(self, myebuild, portage_atom):
2410 2411 ebuild_dir = os.path.dirname(myebuild) 2412 ebuild_file = os.path.basename(myebuild) 2413 moved_ebuild = None 2414 2415 # copy the whole directory in a safe place 2416 dest_dir = os.path.join(etpConst['entropyunpackdir'], 2417 "vardb/" + portage_atom) 2418 if os.path.exists(dest_dir): 2419 if os.path.isdir(dest_dir): 2420 shutil.rmtree(dest_dir, True) 2421 elif os.path.isfile(dest_dir) or os.path.islink(dest_dir): 2422 os.remove(dest_dir) 2423 2424 os.makedirs(dest_dir) 2425 items = os.listdir(ebuild_dir) 2426 for item in items: 2427 myfrom = os.path.join(ebuild_dir, item) 2428 myto = os.path.join(dest_dir, item) 2429 if const_file_readable(myfrom): 2430 # make sure it is readable before copying 2431 shutil.copy2(myfrom, myto) 2432 2433 newmyebuild = os.path.join(dest_dir, ebuild_file) 2434 if os.path.isfile(newmyebuild): 2435 myebuild = newmyebuild 2436 moved_ebuild = myebuild 2437 self._pkg_remove_ebuild_env_setup_hook(myebuild) 2438 2439 return myebuild, moved_ebuild
2440
2441 - def _pkg_setup(self, action_name, action_metadata, package_metadata):
2442 2443 package = PortagePlugin._pkg_compose_atom(package_metadata) 2444 env_file = os.path.join(package_metadata['unpackdir'], "portage", 2445 package, "temp/environment") 2446 2447 if os.path.isfile(env_file): 2448 # setup phase already called 2449 return 2450 2451 ebuild = PortagePlugin._pkg_compose_xpak_ebuild(package_metadata) 2452 # is ebuild available ? 2453 if not const_file_readable(ebuild): 2454 self.log_message( 2455 "[SETUP] ATTENTION Cannot properly run SPM setup" 2456 " phase for %s. Ebuild path: %s not found." % ( 2457 package, ebuild,) 2458 ) 2459 raise self.PhaseFailure( 2460 "Ebuild not found at path: %s" % ( 2461 ebuild,), 1) 2462 2463 try: 2464 self._portage_doebuild( 2465 ebuild, action_name, action_metadata, 2466 "setup", "bintree", package, 2467 portage_tmpdir = package_metadata['unpackdir'], 2468 licenses = package_metadata.get('accept_license')) 2469 2470 except self.PhaseError: 2471 # by contract, this exception must be raised. 2472 raise 2473 2474 except self.PhaseFailure: 2475 # and this as well must be raised. 2476 raise 2477 2478 except Exception as err: 2479 entropy.tools.print_traceback() 2480 raise self.PhaseFailure("%s" % (err,), 1)
2481
2482 - def _pkg_fooinst(self, action_metadata, package_metadata, action_name, 2483 phase):
2484 2485 package = PortagePlugin._pkg_compose_atom(package_metadata) 2486 ebuild = PortagePlugin._pkg_compose_xpak_ebuild(package_metadata) 2487 2488 # is ebuild available ? 2489 if not const_file_readable(ebuild): 2490 self.log_message( 2491 "[PRE] ATTENTION Cannot properly run SPM %s" 2492 " phase for %s. Ebuild path: %s not found." % ( 2493 phase, package, ebuild,) 2494 ) 2495 raise self.PhaseFailure( 2496 "Ebuild not found at path: %s" % ( 2497 ebuild,), 1) 2498 2499 self._pkg_setup(action_name, action_metadata, package_metadata) 2500 2501 try: 2502 self._portage_doebuild( 2503 ebuild, action_name, action_metadata, 2504 phase, "bintree", package, 2505 portage_tmpdir = package_metadata['unpackdir'], 2506 licenses = package_metadata.get('accept_license')) 2507 2508 except self.PhaseError as err: 2509 # by contract, this exception must be raised. 2510 raise 2511 2512 except self.PhaseFailure: 2513 # and this as well must be raised. 2514 raise 2515 2516 except Exception as err: 2517 entropy.tools.print_traceback() 2518 raise self.PhaseFailure("%s" % (err,), 1) 2519 2520 finally: 2521 self._reload_portage_if_required(phase, package_metadata)
2522
2523 - def _pkg_foorm(self, action_metadata, package_metadata, action_name, phase):
2524 2525 rc = 0 2526 moved_ebuild = None 2527 package = PortagePlugin._pkg_compose_atom(package_metadata) 2528 ebuild = self.get_installed_package_build_script_path(package) 2529 2530 if not os.path.isfile(ebuild): 2531 return 2532 2533 try: 2534 ebuild, moved_ebuild = self._pkg_remove_setup_ebuild_env( 2535 ebuild, package) 2536 2537 except EOFError as err: 2538 # stuff on system is broken, ignore it 2539 entropy.tools.print_traceback() 2540 err_msg = "Ebuild: pkg_%s() failed, EOFError: %s - ignoring" % ( 2541 phase, err) 2542 self.__output.output( 2543 err_msg, 2544 importance = 1, 2545 level = "warning", 2546 header = red(" ## ") 2547 ) 2548 raise self.PhaseFailure( 2549 "Phase failed with EOFError", 1) 2550 2551 except OSError as err: 2552 # this means something really bad 2553 # but for now we just push out a warning 2554 entropy.tools.print_traceback() 2555 err_msg = "Ebuild: pkg_%s() failed, OSError: %s - ignoring" % ( 2556 phase, err) 2557 self.__output.output( 2558 err_msg, 2559 importance = 1, 2560 level = "warning", 2561 header = red(" ## ") 2562 ) 2563 raise self.PhaseFailure( 2564 "Phase failed with OSError", 1) 2565 2566 except ImportError as err: 2567 # stuff on system is broken, ignore it 2568 entropy.tools.print_traceback() 2569 err_msg = "Ebuild: pkg_%s() failed, ImportError: %s - ignoring" % ( 2570 phase, err) 2571 self.__output.output( 2572 err_msg, 2573 importance = 1, 2574 level = "warning", 2575 header = red(" ## ") 2576 ) 2577 raise self.PhaseFailure( 2578 "Phase failed with ImportError", 1) 2579 2580 work_dir = os.path.join(etpConst['entropyunpackdir'], 2581 package.replace("/", "_")) 2582 2583 try: 2584 self._reload_portage_if_required(phase, package_metadata) 2585 2586 self._portage_doebuild( 2587 ebuild, action_name, action_metadata, 2588 phase, "bintree", package, portage_tmpdir = work_dir, 2589 licenses = package_metadata.get('accept_license')) 2590 2591 except self.PhaseError as err: 2592 # by contract, this exception must be raised. 2593 raise 2594 2595 except self.PhaseFailure: 2596 # and this as well must be raised. 2597 raise 2598 2599 except Exception as err: 2600 entropy.tools.print_traceback() 2601 raise self.PhaseFailure("%s" % (err,), 1) 2602 2603 finally: 2604 if os.path.isdir(work_dir): 2605 shutil.rmtree(work_dir, True) 2606 2607 if moved_ebuild is not None: 2608 if os.path.isfile(moved_ebuild): 2609 self._pkg_remove_overlayed_ebuild(moved_ebuild)
2610
2611 - def _pkg_preinst(self, action_name, action_metadata, package_metadata):
2612 return self._pkg_fooinst(action_metadata, package_metadata, 2613 action_name, "preinst")
2614
2615 - def _pkg_postinst(self, action_name, action_metadata, package_metadata):
2616 return self._pkg_fooinst(action_metadata, package_metadata, 2617 action_name, "postinst")
2618
2619 - def _pkg_prerm(self, action_name, action_metadata, package_metadata):
2620 return self._pkg_foorm(action_metadata, package_metadata, action_name, 2621 "prerm")
2622
2623 - def _pkg_postrm(self, action_name, action_metadata, package_metadata):
2624 return self._pkg_foorm(action_metadata, package_metadata, action_name, 2625 "postrm")
2626
2627 - def _pkg_config(self, action_name, action_metadata, package_metadata):
2628 2629 package = PortagePlugin._pkg_compose_atom(package_metadata) 2630 ebuild = self.get_installed_package_build_script_path(package) 2631 if not os.path.isfile(ebuild): 2632 raise self.PhaseFailure("No ebuild found: %s" % (ebuild,), 2) 2633 2634 try: 2635 self._portage_doebuild( 2636 ebuild, action_name, action_metadata, 2637 "config", "bintree", package, 2638 licenses = package_metadata.get('accept_license')) 2639 2640 except self.PhaseError as err: 2641 # by contract, this exception must be raised. 2642 raise 2643 2644 except self.PhaseFailure: 2645 # and this as well must be raised. 2646 raise 2647 2648 except Exception as err: 2649 entropy.tools.print_traceback() 2650 raise self.PhaseFailure("%s" % (err,), 1)
2651
2652 - def append_metadata_to_package(self, entropy_package_name, package_path):
2653 """ 2654 Reimplemented from SpmPlugin class. 2655 """ 2656 spm_name = self.convert_from_entropy_package_name(entropy_package_name) 2657 dbbuild = self.get_installed_package_build_script_path(spm_name) 2658 dbdir = os.path.dirname(dbbuild) 2659 2660 if os.path.isdir(dbdir): 2661 tbz2 = xpak.tbz2(package_path) 2662 tbz2.recompose(dbdir) 2663 return True 2664 return False
2665
2666 - def __run_pkg_sync_quickpkg(self, entropy_server, atoms, repo_db, repo):
2667 """ 2668 Executes packages regeneration for given atoms. 2669 """ 2670 package_paths = [] 2671 runatoms = set() 2672 for myatom in atoms: 2673 mymatch = repo_db.atomMatch(myatom) 2674 if mymatch[0] == -1: 2675 continue 2676 myatom = repo_db.retrieveAtom(mymatch[0]) 2677 myatom = entropy.dep.remove_tag(myatom) 2678 runatoms.add(myatom) 2679 2680 for myatom in runatoms: 2681 2682 # check if atom is available 2683 try: 2684 inst_match = self.match_installed_package(myatom) 2685 except KeyError: 2686 inst_match = None 2687 if not inst_match: 2688 self.__output.output( 2689 red("%s: " % (_("package not available on system"),) ) + \ 2690 blue(myatom), 2691 importance = 1, 2692 level = "warning", 2693 header = purple(" # ") 2694 ) 2695 continue 2696 else: 2697 self.__output.output( 2698 red("%s: " % (_("repackaging"),) )+blue(myatom), 2699 importance = 1, 2700 level = "warning", 2701 header = blue(" # ") 2702 ) 2703 2704 mydest = entropy_server._get_local_store_directory(repo) 2705 try: 2706 pkg_list = self.generate_package(myatom, mydest) 2707 except Exception: 2708 entropy.tools.print_traceback() 2709 mytxt = "%s: %s: %s, %s." % ( 2710 bold(_("WARNING")), 2711 red(_("Cannot complete quickpkg for atom")), 2712 blue(myatom), 2713 _("do it manually"), 2714 ) 2715 self.__output.output( 2716 mytxt, 2717 importance = 1, 2718 level = "warning", 2719 header = darkred(" * ") 2720 ) 2721 continue 2722 package_paths.append(pkg_list) 2723 packages_data = [(pkg_list, False,) for pkg_list in package_paths] 2724 idpackages = entropy_server.add_packages_to_repository(repo, 2725 packages_data, ask = is_interactive()) 2726 2727 if not idpackages: 2728 2729 mytxt = "%s: %s. %s." % ( 2730 bold(_("ATTENTION")), 2731 red(_("package files rebuild did not run properly")), 2732 red(_("Please update packages manually")), 2733 ) 2734 self.__output.output( 2735 mytxt, 2736 importance = 1, 2737 level = "warning", 2738 header = darkred(" * ") 2739 )
2740
2741 - def __portage_updates_md5(self, repo_updates_file):
2742 2743 root = etpConst['systemroot'] + os.path.sep 2744 2745 portdb = self._get_portage_portagetree(root).dbapi 2746 mdigest = hashlib.md5() 2747 # this way, if no matches are found, the same value is returned 2748 if const_is_python3(): 2749 mdigest.update(const_convert_to_rawstring("begin")) 2750 else: 2751 mdigest.update("begin") 2752 2753 for repo_name in portdb.getRepositories(): 2754 repo_path = portdb.getRepositoryPath(repo_name) 2755 updates_dir = os.path.join(repo_path, "profiles", "updates") 2756 if not os.path.isdir(updates_dir): 2757 continue 2758 2759 # get checksum 2760 # update 2761 ndigest = entropy.tools.md5obj_directory(updates_dir) 2762 mdigest.update(ndigest.digest()) 2763 2764 # also checksum etpConst['etpdatabaseupdatefile'] 2765 if os.path.isfile(repo_updates_file): 2766 with open(repo_updates_file, "rb") as f: 2767 block = f.read(1024) 2768 while block: 2769 mdigest.update(block) 2770 block = f.read(1024) 2771 2772 return mdigest
2773
2774 - def _get_portage_update_actions(self, repo_updates_file):
2775 2776 root = etpConst['systemroot'] + os.path.sep 2777 2778 updates_map = {} 2779 portdb = self._get_portage_portagetree(root).dbapi 2780 2781 for repo_name in portdb.getRepositories(): 2782 repo_path = portdb.getRepositoryPath(repo_name) 2783 updates_dir = os.path.join(repo_path, "profiles", "updates") 2784 if not os.path.isdir(updates_dir): 2785 continue 2786 2787 update_files_repo = [x for x in os.listdir(updates_dir) if x \ 2788 not in ("CVS", ".svn")] 2789 for update_id in update_files_repo: 2790 obj = updates_map.setdefault(update_id, []) 2791 obj.append(os.path.join(updates_dir, update_id)) 2792 2793 update_actions = [] 2794 sorted_ids = PortageMetaphor.sort_update_files(list(updates_map.keys())) 2795 enc = etpConst['conf_encoding'] 2796 for update_id in sorted_ids: 2797 update_files = updates_map[update_id] 2798 2799 # now load actions from files 2800 for update_file in update_files: 2801 with codecs.open(update_file, "r", encoding=enc) as f: 2802 mycontent = f.readlines() 2803 lines = [x.strip() for x in mycontent if x.strip()] 2804 update_actions.extend(lines) 2805 2806 # add entropy packages.db.repo_updates content 2807 if os.path.isfile(repo_updates_file): 2808 with codecs.open(repo_updates_file, "r", encoding=enc) as f: 2809 mycontent = f.readlines() 2810 lines = [x.strip() for x in mycontent if x.strip() and \ 2811 not x.strip().startswith("#")] 2812 update_actions.extend(lines) 2813 2814 return update_actions
2815
2816 - def package_names_update(self, entropy_repository, entropy_repository_id, 2817 entropy_server, entropy_branch):
2818 2819 repo_updates_file = \ 2820 entropy_server._get_local_repository_treeupdates_file( 2821 entropy_repository_id) 2822 do_rescan = False 2823 2824 stored_digest = entropy_repository.retrieveRepositoryUpdatesDigest( 2825 entropy_repository_id) 2826 if stored_digest == -1: 2827 do_rescan = True 2828 2829 # check portage files for changes if do_rescan is still false 2830 portage_dirs_digest = "0" 2831 if not do_rescan: 2832 2833 if entropy_repository_id in \ 2834 self.__entropy_repository_treeupdate_digests: 2835 2836 portage_dirs_digest = \ 2837 self.__entropy_repository_treeupdate_digests.get( 2838 entropy_repository_id) 2839 else: 2840 mdigest = self.__portage_updates_md5(repo_updates_file) 2841 portage_dirs_digest = mdigest.hexdigest() 2842 self.__entropy_repository_treeupdate_digests[entropy_repository_id] = \ 2843 portage_dirs_digest 2844 2845 if do_rescan or (str(stored_digest) != str(portage_dirs_digest)): 2846 2847 # force parameters, only ServerEntropyRepository exposes 2848 # the setReadonly method 2849 entropy_repository.setReadonly(False) 2850 # disable upload trigger 2851