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

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

   1  # -*- coding: utf-8 -*- 
   2  """ 
   3   
   4      @author: Fabio Erculiani <lxnay@sabayonlinux.org> 
   5      @contact: lxnay@sabayonlinux.org 
   6      @copyright: Fabio Erculiani 
   7      @license: GPL-2 
   8   
   9      B{Entropy Source Package Manager "Portage" Plugin}. 
  10   
  11  """ 
  12  from __future__ import with_statement 
  13  import os 
  14  import sys 
  15  import shutil 
  16  import tempfile 
  17  from entropy.const import etpConst, etpUi 
  18  from entropy.exceptions import FileNotFound, SPMError, InvalidDependString, \ 
  19      InvalidData 
  20  from entropy.output import darkred, darkgreen, brown, darkblue, purple, red, \ 
  21      bold 
  22  from entropy.i18n import _ 
  23  from entropy.core.settings.base import SystemSettings 
  24  from entropy.misc import LogFile 
  25  from entropy.spm.plugins.skel import SpmPlugin 
  26  import entropy.tools 
27 28 -class PortagePackageGroups(dict):
29 """ 30 Entropy Package categories group representation 31 """
32 - def __init__(self):
33 dict.__init__(self) 34 35 data = { 36 'office': { 37 'name': _("Office"), 38 'description': _("Applications used in office environments"), 39 'categories': [u'app-office', u'app-pda', u'app-mobilephone', 40 u'app-cdr', u'app-antivirus', u'app-laptop', u'mail-', 41 ], 42 }, 43 'development': { 44 'name': _("Development"), 45 'description': _("Applications or system libraries"), 46 'categories': [u'dev-', u'sys-devel'], 47 }, 48 'system': { 49 'name': _("System"), 50 'description': _("System applications or libraries"), 51 'categories': [u'sys-'], 52 }, 53 'games': { 54 'name': _("Games"), 55 'description': _("Games, enjoy your spare time"), 56 'categories': [u'games-'], 57 }, 58 'gnome': { 59 'name': _("GNOME Desktop"), 60 'description': \ 61 _("Applications and libraries for the GNOME Desktop"), 62 'categories': [u'gnome-'], 63 }, 64 'kde': { 65 'name': _("KDE Desktop"), 66 'description': \ 67 _("Applications and libraries for the KDE Desktop"), 68 'categories': [u'kde-'], 69 }, 70 'xfce': { 71 'name': _("XFCE Desktop"), 72 'description': \ 73 _("Applications and libraries for the XFCE Desktop"), 74 'categories': [u'xfce-'], 75 }, 76 'lxde': { 77 'name': _("LXDE Desktop"), 78 'description': \ 79 _("Applications and libraries for the LXDE Desktop"), 80 'categories': [u'lxde-'], 81 }, 82 'multimedia': { 83 'name': _("Multimedia"), 84 'description': \ 85 _("Applications and libraries for Multimedia"), 86 'categories': [u'media-'], 87 }, 88 'networking': { 89 'name': _("Networking"), 90 'description': \ 91 _("Applications and libraries for Networking"), 92 'categories': [u'net-', u'www-'], 93 }, 94 'science': { 95 'name': _("Science"), 96 'description': \ 97 _("Scientific applications and libraries"), 98 'categories': [u'sci-'], 99 }, 100 'x11': { 101 'name': _("X11"), 102 'description': \ 103 _("Applications and libraries for X11"), 104 'categories': [u'x11-'], 105 }, 106 } 107 self.update(data)
108
109 -class PortagePlugin(SpmPlugin):
110 111 builtin_pkg_sets = [ 112 "system","world","installed","module-rebuild", 113 "security","preserved-rebuild","live-rebuild", 114 "downgrade","unavailable" 115 ] 116 117 package_phases_map = { 118 'setup': 'setup', 119 'preinstall': 'preinst', 120 'postinstall': 'postinst', 121 'preremove': 'prerm', 122 'postremove': 'postrm', 123 'configure': 'config', 124 } 125 126 PLUGIN_API_VERSION = 0 127 128 SUPPORTED_MATCH_TYPES = [ 129 "bestmatch-visible", "cp-list", "list-visible", "match-all", 130 "match-visible", "minimum-all", "minimum-visible" 131 ] 132
133 - class paren_normalize(list):
134 """Take a dependency structure as returned by paren_reduce or use_reduce 135 and generate an equivalent structure that has no redundant lists."""
136 - def __init__(self, src):
137 list.__init__(self) 138 self._zap_parens(src, self)
139
140 - def _zap_parens(self, src, dest, disjunction=False):
141 if not src: 142 return dest 143 i = iter(src) 144 for x in i: 145 if isinstance(x, basestring): 146 if x == '||': 147 x = self._zap_parens(i.next(), [], disjunction=True) 148 if len(x) == 1: 149 dest.append(x[0]) 150 else: 151 dest.append("||") 152 dest.append(x) 153 elif x.endswith("?"): 154 dest.append(x) 155 dest.append(self._zap_parens(i.next(), [])) 156 else: 157 dest.append(x) 158 else: 159 if disjunction: 160 x = self._zap_parens(x, []) 161 if len(x) == 1: 162 dest.append(x[0]) 163 else: 164 dest.append(x) 165 else: 166 self._zap_parens(x, dest) 167 return dest
168
169 - def init_singleton(self, OutputInterface):
170 171 mytxt = _("OutputInterface does not have an updateProgress method") 172 if not hasattr(OutputInterface,'updateProgress'): 173 raise AttributeError(mytxt) 174 elif not callable(OutputInterface.updateProgress): 175 raise AttributeError(mytxt) 176 177 # interface only needed OutputInterface functions 178 self.updateProgress = OutputInterface.updateProgress 179 self.askQuestion = OutputInterface.askQuestion 180 sys.path.append("/usr/lib/gentoolkit/pym") 181 182 # importing portage stuff 183 import portage 184 self.portage = portage 185 self.EAPI = 1 186 try: 187 import portage.const as portage_const 188 except ImportError: 189 import portage_const 190 if hasattr(portage_const, "EAPI"): 191 self.EAPI = portage_const.EAPI 192 self.portage_const = portage_const 193 194 from portage.versions import best 195 self._portage_best = best 196 197 try: 198 import portage.util as portage_util 199 except ImportError: 200 import portage_util 201 self.portage_util = portage_util 202 203 try: 204 import portage.sets as portage_sets 205 self.portage_sets = portage_sets 206 except ImportError: 207 self.portage_sets = None 208 209 try: 210 import glsa 211 self.glsa = glsa 212 except ImportError: 213 self.glsa = None 214 215 if hasattr(self.portage,'exception'): 216 self.portage_exception = self.portage.exception 217 else: # portage <2.2 workaround 218 self.portage_exception = Exception
219 220 @staticmethod
221 - def get_package_groups():
222 """ 223 Return package groups available metadata (Spm categories are grouped 224 into macro categories called "groups"). 225 """ 226 return PortagePackageGroups()
227
228 - def package_metadata_keys(self):
229 """ 230 Reimplemented from SpmPlugin class. 231 """ 232 # return what's inside vartree because it's more complete 233 dbapi = self._get_portage_vartree().dbapi 234 if hasattr(dbapi, '_aux_cache_keys'): 235 return list(dbapi._aux_cache_keys) 236 237 sys.stderr.write("PortagePlugin: missing vardb._aux_cache_keys !\n") 238 return ["CHOST", "COUNTER", "DEPEND", "DESCRIPTION", 239 "EAPI", "HOMEPAGE", "IUSE", "KEYWORDS", 240 "LICENSE", "PDEPEND", "PROPERTIES", "PROVIDE", "RDEPEND", 241 "repository", "RESTRICT" , "SLOT", "USE" 242 ]
243
244 - def get_cache_directory(self, root = None):
245 """ 246 Reimplemented from SpmPlugin class. 247 """ 248 if root is None: 249 root = etpConst['systemroot'] + os.path.sep 250 cache_path = self.portage_const.CACHE_PATH.lstrip(os.path.sep) 251 return os.path.join(root, cache_path)
252
253 - def get_package_metadata(self, package, key):
254 """ 255 Reimplemented from SpmPlugin class. 256 """ 257 return self.portage.portdb.aux_get(package, [key])[0]
258
259 - def get_package_changelog(self, package):
260 """ 261 Reimplemented from SpmPlugin class. 262 """ 263 ebuild_path = self.get_package_build_script_path(package) 264 if isinstance(ebuild_path, basestring): 265 266 clog_path = os.path.join(os.path.dirname(ebuild_path), "ChangeLog") 267 if os.access(clog_path, os.R_OK | os.F_OK): 268 with open(clog_path, "r") as clog_f: 269 return clog_f.read()
270
271 - def get_package_build_script_path(self, package):
272 """ 273 Reimplemented from SpmPlugin class. 274 """ 275 return self.portage.portdb.findname(package)
276
277 - def get_installed_package_build_script_path(self, package, root = None):
278 """ 279 Reimplemented from SpmPlugin class. 280 """ 281 return os.path.join(self._get_vdb_path(root = root), package, 282 package.split("/")[-1] + etpConst['spm']['source_build_ext'])
283
284 - def get_installed_package_metadata(self, package, key, root = None):
285 """ 286 Reimplemented from SpmPlugin class. 287 """ 288 if root is None: 289 root = etpConst['systemroot'] + os.path.sep 290 vartree = self._get_portage_vartree(root = root) 291 return vartree.dbapi.aux_get(package, [key])[0]
292
293 - def get_system_packages(self):
294 """ 295 Reimplemented from SpmPlugin class. 296 """ 297 system = [] 298 for package in self.portage.settings.packages: 299 pkgs = self.match_installed_package(package, match_all = True) 300 system.extend(pkgs) 301 system.extend(etpConst['spm']['system_packages']) 302 return system
303
304 - def get_package_categories(self):
305 """ 306 Reimplemented from SpmPlugin class. 307 """ 308 return self._get_portage_config(os.path.sep, os.path.sep).categories
309
310 - def get_package_category_description_metadata(self, category):
311 """ 312 Reimplemented from SpmPlugin class. 313 """ 314 from xml.dom import minidom 315 data = {} 316 portdir = self.portage.settings['PORTDIR'] 317 myfile = os.path.join(portdir,category,"metadata.xml") 318 if os.access(myfile,os.R_OK) and os.path.isfile(myfile): 319 doc = minidom.parse(myfile) 320 longdescs = doc.getElementsByTagName("longdescription") 321 for longdesc in longdescs: 322 data[longdesc.getAttribute("lang").strip()] = \ 323 ' '.join([x.strip() for x in \ 324 longdesc.firstChild.data.strip().split("\n")]) 325 return data
326
327 - def get_security_packages(self, security_property):
328 """ 329 Reimplemented from SpmPlugin class. 330 """ 331 if not self.glsa: 332 return [] 333 if security_property not in ['new','all','affected']: 334 return [] 335 336 glsaconfig = self.glsa.checkconfig( 337 self.portage.config(clone=self.portage.settings)) 338 completelist = self.glsa.get_glsa_list( 339 glsaconfig["GLSA_DIR"], glsaconfig) 340 341 glsalist = [] 342 if security_property == "new": 343 344 checklist = [] 345 if os.access(glsaconfig["CHECKFILE"], os.R_OK | os.F_OK): 346 with open(glsaconfig["CHECKFILE"], "r") as check_f: 347 checklist.extend([x.strip() for x in check_f.readlines()]) 348 glsalist = [x for x in completelist if x not in checklist] 349 350 elif security_property == "all": 351 glsalist = completelist 352 353 elif security_property == "affected": 354 355 # maybe this should be todolist instead 356 for glsa_item in completelist: 357 try: 358 myglsa = self.glsa.Glsa(glsa_item, glsaconfig) 359 except (self.glsa.GlsaTypeException, 360 self.glsa.GlsaFormatException,): 361 continue 362 363 if not myglsa.isVulnerable(): 364 continue 365 366 glsalist.append(glsa_item) 367 368 return glsalist
369
370 - def get_security_advisory_metadata(self, advisory_id):
371 """ 372 Reimplemented from SpmPlugin class. 373 """ 374 if not self.glsa: 375 return {} 376 377 glsaconfig = self.glsa.checkconfig( 378 self.portage.config(clone=self.portage.settings)) 379 try: 380 myglsa = self.glsa.Glsa(advisory_id, glsaconfig) 381 except (self.glsa.GlsaTypeException, self.glsa.GlsaFormatException): 382 return {} 383 384 mydict = { 385 'glsa_id': advisory_id, 386 'number': myglsa.nr, 387 'access': myglsa.access, 388 'title': myglsa.title, 389 'synopsis': myglsa.synopsis, 390 'announced': myglsa.announced, 391 'revised': myglsa.revised, 392 'bugs': myglsa.bugs, 393 'description': myglsa.description, 394 'resolution': myglsa.resolution, 395 'impact': myglsa.impact_text, 396 'impacttype': myglsa.impact_type, 397 'affected': myglsa.affected, 398 'background': myglsa.background, 399 'glsatype': myglsa.glsatype, 400 'packages': myglsa.packages, 401 'services': myglsa.services, 402 'product': myglsa.product, 403 'references': myglsa.references, 404 'workaround': myglsa.workaround, 405 } 406 407 status = "[U]" 408 if myglsa.isApplied(): 409 status = "[A]" 410 elif myglsa.isVulnerable(): 411 status = "[N]" 412 mydict['status'] = status 413 414 return mydict
415
416 - def get_setting(self, key):
417 """ 418 Reimplemented from SpmPlugin class. 419 """ 420 return self.portage.settings[key]
421
422 - def get_user_installed_packages_file(self, root = None):
423 """ 424 Reimplemented from SpmPlugin class. 425 """ 426 world_file = self.portage_const.WORLD_FILE 427 if root is None: 428 root = etpConst['systemroot'] + os.path.sep 429 return os.path.join(root, world_file)
430
431 - def get_merge_protected_paths(self):
432 """ 433 Reimplemented from SpmPlugin class. 434 """ 435 config_protect = self.portage.settings['CONFIG_PROTECT'] 436 return [os.path.expandvars(x) for x in config_protect.split()]
437
439 """ 440 Reimplemented from SpmPlugin class. 441 """ 442 config_protect = self.portage.settings['CONFIG_PROTECT_MASK'] 443 return [os.path.expandvars(x) for x in config_protect.split()]
444
445 - def get_download_mirrors(self, mirror_name):
446 """ 447 Reimplemented from SpmPlugin class. 448 """ 449 mirrors = [] 450 if self.portage.thirdpartymirrors.has_key(mirror_name): 451 mirrors.extend(self.portage.thirdpartymirrors[mirror_name]) 452 return mirrors
453
455 """ 456 Reimplemented from SpmPlugin class. 457 """ 458 root = etpConst['systemroot'] + os.path.sep 459 mydb = {} 460 mydb[root] = {} 461 mydb[root]['vartree'] = self._get_portage_vartree(root) 462 mydb[root]['porttree'] = self._get_portage_portagetree(root) 463 mydb[root]['bintree'] = self._get_portage_binarytree(root) 464 mydb[root]['virtuals'] = self.portage.settings.getvirtuals(root) 465 466 if etpUi['mute']: 467 pid = os.fork() 468 if pid > 0: 469 os.waitpid(pid, 0) 470 else: 471 log = LogFile( 472 level = etpConst['spmloglevel'], 473 filename = etpConst['spmlogfile'], 474 header = "[spm]" 475 ) 476 old_stdout = sys.stdout 477 old_stderr = sys.stderr 478 sys.stdout = log 479 sys.stderr = log 480 481 self.portage._global_updates(mydb, {}) 482 483 sys.stdout = old_stdout 484 sys.stderr = old_stderr 485 log.flush() 486 log.close() 487 os._exit(0) 488 else: 489 self.portage._global_updates(mydb, {}) # always force
490
491 - def match_package(self, package, match_type = None):
492 """ 493 Reimplemented from SpmPlugin class. 494 """ 495 if match_type is None: 496 match_type = "bestmatch-visible" 497 elif match_type not in PortagePlugin.SUPPORTED_MATCH_TYPES: 498 raise KeyError 499 500 return self.portage.portdb.xmatch(match_type, package)
501
502 - def match_installed_package(self, package, match_all = False, root = None):
503 """ 504 Reimplemented from SpmPlugin class. 505 """ 506 if root is None: 507 root = etpConst['systemroot'] + os.path.sep 508 509 vartree = self._get_portage_vartree(root = root) 510 matches = vartree.dep_match(package) or [] 511 512 if match_all: 513 return matches 514 elif matches: 515 return matches[-1] 516 return ''
517
518 - def generate_package(self, package, file_save_path):
519 """ 520 Reimplemented from SpmPlugin class. 521 """ 522 pkgcat, pkgname = package.split("/", 1) 523 if not os.path.isdir(file_save_path): 524 os.makedirs(file_save_path) 525 file_save_path += "/" + pkgname + etpConst['packagesext'] 526 dbdir = os.path.join(self._get_vdb_path(), pkgcat, pkgname) 527 528 import tarfile 529 import stat 530 trees = self.portage.db["/"] 531 vartree = trees["vartree"] 532 dblnk = self.portage.dblink(pkgcat, pkgname, "/", vartree.settings, 533 treetype="vartree", vartree=vartree) 534 dblnk.lockdb() 535 tar = tarfile.open(file_save_path, "w:bz2") 536 537 contents = dblnk.getcontents() 538 paths = sorted(contents.keys()) 539 540 for path in paths: 541 try: 542 exist = os.lstat(path) 543 except OSError: 544 continue # skip file 545 ftype = contents[path][0] 546 lpath = path 547 arcname = path[1:] 548 if 'dir' == ftype and \ 549 not stat.S_ISDIR(exist.st_mode) and \ 550 os.path.isdir(lpath): 551 lpath = os.path.realpath(lpath) 552 tarinfo = tar.gettarinfo(lpath, arcname) 553 554 if stat.S_ISREG(exist.st_mode): 555 tarinfo.mode = stat.S_IMODE(exist.st_mode) 556 tarinfo.type = tarfile.REGTYPE 557 f = open(path) 558 try: 559 tar.addfile(tarinfo, f) 560 finally: 561 f.close() 562 else: 563 tar.addfile(tarinfo) 564 565 tar.close() 566 567 # appending xpak informations 568 import entropy.xpak as xpak 569 tbz2 = xpak.tbz2(file_save_path) 570 tbz2.recompose(dbdir) 571 572 dblnk.unlockdb() 573 574 if os.access(file_save_path, os.F_OK): 575 return file_save_path 576 577 raise SPMError("SPMError: Spm:generate_package %s: %s %s" % ( 578 _("error"), 579 file_save_path, 580 _("not found"), 581 ) 582 )
583
584 - def extract_package_metadata(self, package_file):
585 """ 586 Reimplemented from SpmPlugin class. 587 """ 588 data = {} 589 system_settings = SystemSettings() 590 591 # fill package name and version 592 data['digest'] = entropy.tools.md5sum(package_file) 593 data['signatures'] = { 594 'sha1': entropy.tools.sha1(package_file), 595 'sha256': entropy.tools.sha256(package_file), 596 'sha512': entropy.tools.sha512(package_file), 597 } 598 data['datecreation'] = str(entropy.tools.get_file_unix_mtime( 599 package_file)) 600 data['size'] = str(entropy.tools.get_file_size(package_file)) 601 602 tmp_dir = tempfile.mkdtemp() 603 entropy.tools.extract_xpak(package_file, tmp_dir) 604 605 # package injection status always false by default 606 # developer can change metadatum after this function 607 data['injected'] = False 608 data['branch'] = system_settings['repositories']['branch'] 609 610 portage_entries = self._extract_pkg_metadata_generate_extraction_dict() 611 for item in portage_entries: 612 613 value = '' 614 try: 615 616 item_path = os.path.join(tmp_dir, portage_entries[item]['path']) 617 with open(item_path, "r") as item_f: 618 value = item_f.readline().strip().decode( 619 'raw_unicode_escape') 620 621 except IOError: 622 if portage_entries[item]['critical']: 623 raise 624 data[item] = value 625 626 627 # workout pf 628 pf_atom = os.path.join(data['category'], data['pf']) 629 pkgcat, pkgname, pkgver, pkgrev = entropy.tools.catpkgsplit( 630 pf_atom) 631 if pkgrev != "r0": 632 pkgver += "-%s" % (pkgrev,) 633 data['name'] = pkgname 634 data['version'] = pkgver 635 # bye bye pf 636 del data['pf'] 637 638 # setup spm_phases properly 639 spm_defined_phases_path = os.path.join(tmp_dir, 640 portage_entries['spm_phases']['path']) 641 if not os.path.isfile(spm_defined_phases_path): 642 # force to None, because metadatum can be '', which is valid 643 data['spm_phases'] = None 644 645 data['eclasses'] = set(data['eclasses'].split()) 646 try: 647 data['counter'] = int(data['counter']) 648 except ValueError: 649 # -2 values will be insterted as incremental 650 # negative values into the database 651 data['counter'] = -2 652 653 data['keywords'] = [x.strip() for x in data['keywords'].split() \ 654 if x.strip()] 655 if not data['keywords']: 656 # support for packages with no keywords 657 data['keywords'].insert(0, "") 658 659 data['keywords'] = set(data['keywords']) 660 needed_file = os.path.join(tmp_dir, 661 etpConst['spm']['xpak_entries']['needed']) 662 663 data['needed'] = self._extract_pkg_metadata_needed(needed_file) 664 data['needed_paths'] = self._extract_pkg_metadata_needed_paths( 665 data['needed']) 666 667 content_file = os.path.join(tmp_dir, 668 etpConst['spm']['xpak_entries']['contents']) 669 data['content'] = self._extract_pkg_metadata_content(content_file, 670 package_file) 671 data['disksize'] = entropy.tools.sum_file_sizes(data['content']) 672 673 # [][][] Kernel dependent packages hook [][][] 674 data['versiontag'] = '' 675 kernelstuff = False 676 kernelstuff_kernel = False 677 for item in data['content']: 678 if item.startswith("/lib/modules/"): 679 kernelstuff = True 680 # get the version of the modules 681 kmodver = item.split("/lib/modules/")[1] 682 kmodver = kmodver.split("/")[0] 683 684 lp = kmodver.split("-")[-1] 685 if lp.startswith("r"): 686 kname = kmodver.split("-")[-2] 687 kver = kmodver.split("-")[0]+"-"+kmodver.split("-")[-1] 688 else: 689 kname = kmodver.split("-")[-1] 690 kver = kmodver.split("-")[0] 691 break 692 693 # validate the results above 694 if kernelstuff: 695 matchatom = "linux-%s-%s" % (kname,kver,) 696 if (matchatom == data['name']+"-"+data['version']): 697 kernelstuff_kernel = True 698 699 data['versiontag'] = kmodver 700 if not kernelstuff_kernel: 701 data['slot'] = kmodver # if you change this behaviour, 702 # you must change "reagent update" 703 # and "equo database gentoosync" consequentially 704 705 file_ext = etpConst['spm']['ebuild_file_extension'] 706 ebuilds_in_path = [x for x in os.listdir(tmp_dir) if \ 707 x.endswith(".%s" % (file_ext,))] 708 709 if not data['versiontag'] and ebuilds_in_path: 710 # has the user specified a custom package tag inside the ebuild 711 ebuild_path = os.path.join(tmp_dir, ebuilds_in_path[0]) 712 data['versiontag'] = self._extract_pkg_metadata_ebuild_entropy_tag( 713 ebuild_path) 714 715 data['download'] = etpConst['packagesrelativepath'] + data['branch'] \ 716 + "/" 717 data['download'] += entropy.tools.create_package_filename( 718 data['category'], data['name'], data['version'], data['versiontag']) 719 720 data['trigger'] = "" 721 trigger_file = os.path.join(etpConst['triggersdir'], data['category'], 722 data['name'], etpConst['triggername']) 723 if os.access(trigger_file, os.F_OK | os.R_OK): 724 with open(trigger_file,"rb") as trig_f: 725 data['trigger'] = trig_f.read() 726 727 # Get Spm ChangeLog 728 pkgatom = "%s/%s-%s" % (data['category'], data['name'], 729 data['version'],) 730 try: 731 data['changelog'] = unicode(self.get_package_changelog(pkgatom), 732 'raw_unicode_escape') 733 except (UnicodeEncodeError, UnicodeDecodeError,), e: 734 sys.stderr.write("%s: %s, %s\n" % ( 735 "changelog string conversion error", e, 736 package_file,) 737 ) 738 data['changelog'] = None 739 except: 740 data['changelog'] = None 741 742 portage_metadata = self._calculate_dependencies( 743 data['iuse'], data['use'], data['license'], data['depend'], 744 data['rdepend'], data['pdepend'], data['provide'], data['sources'] 745 ) 746 747 data['provide'] = set(portage_metadata['PROVIDE'].split()) 748 data['license'] = portage_metadata['LICENSE'] 749 data['useflags'] = [] 750 for my_use in portage_metadata['USE']: 751 if my_use in portage_metadata['USE_MASK']: 752 continue 753 if my_use in portage_metadata['USE_FORCE']: 754 data['useflags'].append(my_use) 755 continue 756 if my_use in portage_metadata['ENABLED_USE']: 757 data['useflags'].append(my_use) 758 else: 759 data['useflags'].append("-"+my_use) 760 761 # useflags must be a set, as returned by entropy.db.getPackageData 762 data['useflags'] = set(data['useflags']) 763 # sources must be a set, as returned by entropy.db.getPackageData 764 data['sources'] = set(portage_metadata['SRC_URI'].split()) 765 data['dependencies'] = {} 766 767 for x in portage_metadata['RDEPEND'].split(): 768 if x.startswith("!") or (x in ("(","||",")","")): 769 continue 770 data['dependencies'][x] = etpConst['spm']['(r)depend_id'] 771 772 for x in portage_metadata['PDEPEND'].split(): 773 if x.startswith("!") or (x in ("(","||",")","")): 774 continue 775 data['dependencies'][x] = etpConst['spm']['pdepend_id'] 776 777 data['conflicts'] = [x.replace("!","") for x in \ 778 portage_metadata['RDEPEND'].split() + \ 779 portage_metadata['PDEPEND'].split() if \ 780 x.startswith("!") and not x in ("(","||",")","")] 781 782 if (kernelstuff) and (not kernelstuff_kernel): 783 # add kname to the dependency 784 kern_dep_key = u"=sys-kernel/linux-"+kname+"-"+kver+"~-1" 785 data['dependencies'][kern_dep_key] = etpConst['spm']['(r)depend_id'] 786 787 # Conflicting tagged packages support 788 # Needs Entropy Client System Settings Plugin, 789 # but since entropy.server loads entropy.client, it's completely 790 # fine as of now. 791 key = data['category'] + "/" + data['name'] 792 plug_data = etpConst['system_settings_plugins_ids'] 793 client_sysset_plg_id = plug_data['client_plugin'] 794 client_data = system_settings.get(client_sysset_plg_id, {}) 795 confl_data = None 796 797 if client_data: 798 repo_data = client_data['repositories'] 799 confl_data = repo_data['conflicting_tagged_packages'].get(key) 800 801 if confl_data: 802 for conflict in confl_data: 803 data['conflicts'].append(conflict) 804 805 # conflicts must be a set, which is what is returned 806 # by entropy.db.getPackageData 807 data['conflicts'] = set(data['conflicts']) 808 809 # Get License text if possible 810 licenses_dir = os.path.join(self.get_setting('PORTDIR'), 'licenses') 811 data['licensedata'] = self._extract_pkg_metadata_license_data( 812 licenses_dir, data['license']) 813 814 data['mirrorlinks'] = self._extract_pkg_metadata_mirror_links( 815 data['sources']) 816 817 # write only if it's a systempackage 818 data['systempackage'] = False 819 system_packages = [entropy.tools.dep_getkey(x) for x in \ 820 self.get_system_packages()] 821 if data['category'] + "/" + data['name'] in system_packages: 822 data['systempackage'] = True 823 824 # write only if it's a systempackage 825 data['config_protect'] = ' '.join(self.get_merge_protected_paths()) 826 data['config_protect_mask'] = ' '.join( 827 self.get_merge_protected_paths_mask()) 828 829 log_dir = etpConst['logdir']+"/elog" 830 if not os.path.isdir(log_dir): os.makedirs(log_dir) 831 data['messages'] = self._extract_pkg_metadata_messages(log_dir, 832 data['category'], data['name'], data['version']) 833 834 # etpapi must be int, as returned by entropy.db.getPackageData 835 data['etpapi'] = int(etpConst['etpapi']) 836 837 # removing temporary directory 838 shutil.rmtree(tmp_dir, True) 839 if os.path.isdir(tmp_dir): 840 try: 841 os.remove(tmp_dir) 842 except OSError: 843 pass 844 845 # clear unused metadata 846 del data['use'], data['iuse'], data['depend'], data['pdepend'], \ 847 data['rdepend'] 848 849 return data
850
851 - def enable_package_compile_options(self, package, options):
852 """ 853 Reimplemented from SpmPlugin class. 854 """ 855 result = self._unset_package_useflags(package, options) 856 if not result: 857 return False 858 return self._handle_new_useflags(package, options, "")
859
860 - def disable_package_compile_options(self, package, options):
861 """ 862 Reimplemented from SpmPlugin class. 863 """ 864 result = self._unset_package_useflags(package, options) 865 if not result: 866 return False 867 return self._handle_new_useflags(package, options, "-")
868
869 - def get_package_compile_options(self, package):
870 """ 871 Reimplemented from SpmPlugin class. 872 """ 873 matched_atom = self.match_package(package) 874 if not matched_atom: 875 return {} 876 global_useflags = self._get_useflags() 877 use_force = self._get_useflags_force() 878 use_mask = self._get_useflags_mask() 879 package_use_useflags = self._get_package_use_useflags(package) 880 881 data = {} 882 data['use_force'] = use_force.copy() 883 data['use_mask'] = use_mask.copy() 884 data['global_use'] = global_useflags.split() 885 886 iuse = self.get_package_metadata(package, "IUSE") 887 if not isinstance(iuse, basestring): 888 iuse = '' 889 data['iuse'] = iuse.split()[:] 890 iuse = set() 891 for myiuse in data['iuse']: 892 if myiuse.startswith("+"): 893 myiuse = myiuse[1:] 894 iuse.add(myiuse) 895 896 use = [f for f in data['global_use'] + \ 897 list(package_use_useflags['enabled']) if (f in iuse) \ 898 and (f not in use_mask) and \ 899 (f not in package_use_useflags['disabled'])] 900 901 use_disabled = [f for f in iuse if (f not in data['global_use']) \ 902 and (f not in use_mask) and \ 903 (f not in package_use_useflags['enabled'])] 904 905 data['use'] = use[:] 906 data['use_disabled'] = use_disabled[:] 907 908 matched_slot = self.get_package_metadata(matched_atom, "SLOT") 909 try: 910 inst_key = "%s:%s" % ( 911 entropy.tools.dep_getkey(package), 912 matched_slot, 913 ) 914 installed_atom = self.match_installed_package(inst_key) 915 except self.portage_exception: 916 installed_atom = '' 917 918 if installed_atom: 919 920 # get its useflags 921 previous_iuse = self.get_installed_package_metadata(installed_atom, 922 "IUSE").split() 923 previous_use = self.get_installed_package_metadata(installed_atom, 924 "USE").split() 925 926 new_previous_iuse = set() 927 for myuse in previous_iuse: 928 if myuse.startswith("+"): 929 myuse = myuse[1:] 930 new_previous_iuse.add(myuse) 931 previous_iuse = list(new_previous_iuse) 932 933 inst_use = [f for f in previous_iuse if (f in previous_use) and \ 934 (f not in use_mask)] 935 #inst_use_disabled = [f for f in previous_use if \ 936 # (f not in previous_iuse) and (f not in use_mask)] 937 938 # check removed use 939 use_removed = [] 940 for myuse in inst_use: 941 if myuse not in use: 942 use_removed.append(myuse) 943 944 # use not available 945 use_not_avail = [] 946 for myuse in previous_iuse: 947 if (myuse not in iuse) and (myuse not in use_removed): 948 use_not_avail.append(myuse) 949 950 # check new use 951 t_use = [] 952 for myuse in use: 953 if myuse not in inst_use: 954 myuse = "+%s*" % (myuse,) 955 t_use.append(myuse) 956 use = t_use 957 958 # check disabled use 959 t_use_disabled = [] 960 for myuse in use_disabled: 961 if myuse in inst_use: 962 if myuse in use_removed+use_not_avail: 963 continue 964 myuse = "-%s*" % (myuse,) 965 else: 966 myuse = "-%s" % (myuse,) 967 t_use_disabled.append(myuse) 968 use_disabled = t_use_disabled 969 970 for myuse in use_removed: 971 use_disabled.append("(-%s*)" % (myuse,)) 972 for myuse in use_not_avail: 973 use_disabled.append("(-%s)" % (myuse,)) 974 else: 975 use_disabled = ["-"+x for x in use_disabled] 976 977 data['use_string'] = ' '.join(sorted(use)+sorted([x for x in \ 978 use_disabled])) 979 data['use_string_colored'] = ' '.join( 980 sorted([darkred(x) for x in use if not x.startswith("+")] + \ 981 [darkgreen(x) for x in use if x.startswith("+")]) + \ 982 sorted([darkblue(x) for x in use_disabled if x.startswith("-")] + \ 983 [brown(x) for x in use_disabled if x.startswith("(") and \ 984 (x.find("*") == -1)] + \ 985 [purple(x) for x in use_disabled if x.startswith("(") and \ 986 (x.find("*") != -1)] 987 ) 988 ) 989 990 return data
991
992 - def get_installed_package_compile_options(self, package, root = None):
993 """ 994 Reimplemented from SpmPlugin class. 995 """ 996 matched_atom = self.match_installed_package(package, root = root) 997 if not matched_atom: 998 return {} 999 1000 global_use = self.get_installed_package_metadata(matched_atom, "USE", 1001 root = root) 1002 use_mask = self._get_useflags_mask() 1003 1004 data = {} 1005 data['use_mask'] = use_mask.copy() 1006 data['global_use'] = global_use.split() 1007 1008 iuse = self.get_installed_package_metadata(matched_atom, "IUSE", 1009 root = root) 1010 if not isinstance(iuse, basestring): 1011 iuse = '' 1012 data['iuse'] = iuse.split()[:] 1013 iuse = set() 1014 for myiuse in data['iuse']: 1015 if myiuse.startswith("+"): 1016 myiuse = myiuse[1:] 1017 iuse.add(myiuse) 1018 1019 use = [f for f in data['global_use'] if (f in iuse) and \ 1020 (f not in use_mask)] 1021 use_disabled = [f for f in iuse if (f not in data['global_use']) and \ 1022 (f not in use_mask)] 1023 data['use'] = use[:] 1024 data['use_disabled'] = use_disabled[:] 1025 1026 data['use_string'] = ' '.join(sorted(use)+sorted([x for x in \ 1027 use_disabled])) 1028 data['use_string_colored'] = ' '.join( 1029 sorted([darkred(x) for x in use if not x.startswith("+")] + \ 1030 [darkgreen(x) for x in use if x.startswith("+")]) + \ 1031 sorted([darkblue(x) for x in use_disabled if x.startswith("-")] + \ 1032 [brown(x) for x in use_disabled if x.startswith("(") and \ 1033 (x.find("*") == -1)] + \ 1034 [purple(x) for x in use_disabled if x.startswith("(") and \ 1035 (x.find("*") != -1)] 1036 ) 1037 ) 1038 return data
1039
1040 - def get_installed_package_content(self, package, root = None):
1041 """ 1042 Reimplemented from SpmPlugin class. 1043 """ 1044 if root is None: 1045 root = etpConst['systemroot'] + os.path.sep 1046 mytree = self._get_portage_vartree(root) 1047 1048 cat, pkgv = package.split("/") 1049 return sorted(self.portage.dblink(cat, pkgv, root, 1050 self.portage.settings).getcontents())
1051
1052 - def get_packages(self, categories = None, filter_reinstalls = True):
1053 """ 1054 Reimplemented from SpmPlugin class. 1055 """ 1056 if categories is None: 1057 categories = [] 1058 1059 root = etpConst['systemroot'] + os.path.sep 1060 mysettings = self._get_portage_config(os.path.sep, root) 1061 portdb = self.portage.portdbapi(mysettings["PORTDIR"], 1062 mysettings = mysettings) 1063 1064 cps = portdb.cp_all() 1065 visibles = set() 1066 for cp in cps: 1067 if categories and cp.split("/")[0] not in categories: 1068 continue 1069 1070 # get slots 1071 slots = set() 1072 atoms = self.match_package(cp, match_type = "match-visible") 1073 if atoms: 1074 for atom in atoms: 1075 slots.add(portdb.aux_get(atom, ["SLOT"])[0]) 1076 for slot in slots: 1077 visibles.add(cp+":"+slot) 1078 1079 # now match visibles 1080 available = set() 1081 for visible in visibles: 1082 1083 match = self.match_package(visible) 1084 if not match: 1085 continue 1086 1087 if filter_reinstalls: 1088 installed = self.match_installed_package(visible) 1089 if installed != match: 1090 available.add(match) 1091 else: 1092 available.add(match) 1093 1094 return available
1095
1096 - def get_installed_packages(self, categories = None, root = None):
1097 """ 1098 Reimplemented from SpmPlugin class. 1099 """ 1100 vartree = self._get_portage_vartree(root = root) 1101 packages = vartree.dbapi.cpv_all() 1102 if not categories: 1103 return packages 1104 1105 def catfilter(pkg): 1106 if pkg.split("/", 1)[0] in categories: 1107 return True 1108 return False
1109 1110 return filter(catfilter, packages)
1111
1112 - def get_package_sets(self, builtin_sets):
1113 """ 1114 Reimplemented from SpmPlugin class. 1115 """ 1116 config = self._get_set_config() 1117 if config == None: 1118 return {} 1119 1120 mysets = config.getSets() 1121 if not builtin_sets: 1122 builtin_pkg_sets = [x for x in PortagePlugin.builtin_pkg_sets if \ 1123 x in mysets] 1124 for pkg_set in builtin_pkg_sets: 1125 mysets.pop(pkg_set) 1126 1127 return dict((x, y.getAtoms(),) for x, y in mysets.items())
1128
1129 - def assign_uid_to_installed_package(self, package, root = None):
1130 """ 1131 Reimplemented from SpmPlugin class. 1132 """ 1133 if root is None: 1134 root = etpConst['systemroot'] + os.path.sep 1135 1136 vartree = self._get_portage_vartree(root) 1137 dbbuild = self.get_installed_package_build_script_path(package, 1138 root = root) 1139 1140 counter_dir = os.path.dirname(dbbuild) 1141 counter_name = etpConst['spm']['xpak_entries']['counter'] 1142 counter_path = os.path.join(counter_dir, counter_name) 1143 1144 if not os.access(counter_dir, os.W_OK): 1145 raise SPMError("SPM package directory not found") 1146 1147 with open(counter_path, "w") as count_f: 1148 new_counter = vartree.dbapi.counter_tick(root, mycpv = package) 1149 count_f.write(str(new_counter)) 1150 count_f.flush() 1151 1152 return new_counter
1153
1154 - def search_paths_owners(self, paths, exact_match = True):
1155 """ 1156 Reimplemented from SpmPlugin class. 1157 """ 1158 if not isinstance(paths, (list, set, frozenset, dict, tuple,)): 1159 raise AttributeError("iterable needed") 1160 root = etpConst['systemroot'] + os.path.sep 1161 mytree = self._get_portage_vartree(root) 1162 packages = mytree.dbapi.cpv_all() 1163 matches = {} 1164 1165 for package in packages: 1166 cat, pkgv = package.split("/") 1167 content = self.portage.dblink(cat, pkgv, root, 1168 self.portage.settings).getcontents() 1169 1170 if exact_match: 1171 for filename in paths: 1172 if filename in content: 1173 myslot = self.get_installed_package_metadata(package, 1174 "SLOT") 1175 obj = matches.setdefault((package, myslot,), set()) 1176 obj.add(filename) 1177 else: 1178 for filename in paths: 1179 for myfile in content: 1180 if myfile.find(filename) == -1: 1181 continue 1182 myslot = self.get_installed_package_metadata(package, 1183 "SLOT") 1184 obj = matches.setdefault((package, myslot,), set()) 1185 obj.add(filename) 1186 1187 return matches
1188
1189 - def _portage_doebuild(self, myebuild, mydo, tree, cpv, 1190 portage_tmpdir = None, licenses = None):
1191 # myebuild = path/to/ebuild.ebuild with a valid unpacked xpak metadata 1192 # tree = "bintree" 1193 # cpv = atom 1194 # mydbapi = portage.fakedbapi(settings=portage.settings) 1195 # vartree = portage.vartree(root=myroot) 1196 1197 if licenses is None: 1198 licenses = [] 1199 1200 oldsystderr = sys.stderr 1201 dev_null = open("/dev/null","w") 1202 if not etpUi['debug']: 1203 sys.stderr = dev_null 1204 1205 ### SETUP ENVIRONMENT 1206 # if mute, supress portage output 1207 domute = False 1208 if etpUi['mute']: 1209 domute = True 1210 oldsysstdout = sys.stdout 1211 sys.stdout = dev_null 1212 1213 root = etpConst['systemroot'] + os.path.sep 1214 1215 # old way to avoid loop of deaths for entropy portage hooks 1216 os.environ["SKIP_EQUO_SYNC"] = "1" 1217 1218 # load metadata 1219 myebuilddir = os.path.dirname(myebuild) 1220 keys = self.portage.auxdbkeys 1221 metadata = {} 1222 1223 for key in keys: 1224 mykeypath = os.path.join(myebuilddir,key) 1225 if os.path.isfile(mykeypath) and os.access(mykeypath,os.R_OK): 1226 f = open(mykeypath,"r") 1227 metadata[key] = f.readline().strip() 1228 f.close() 1229 1230 ### END SETUP ENVIRONMENT 1231 1232 # find config 1233 mysettings = self._get_portage_config(os.path.sep, root) 1234 mysettings['EBUILD_PHASE'] = mydo 1235 1236 # crappy, broken, ebuilds, put accept_license eutils call 1237 # in pkg_setup, when environment variables are not setup yet 1238 # WARNING WARNING WARNING: 1239 # if some other hook fails for other reasons, it's because 1240 # it may miss env variable here. 1241 mysettings['LICENSE'] = str(' '.join(licenses)) 1242 if licenses: 1243 # we already do this early 1244 mysettings["ACCEPT_LICENSE"] = mysettings['LICENSE'] 1245 mysettings.backup_changes("ACCEPT_LICENSE") 1246 1247 mysettings['EAPI'] = "0" 1248 if metadata.has_key('EAPI'): 1249 mysettings['EAPI'] = metadata['EAPI'] 1250 1251 # workaround for scripts asking for user intervention 1252 mysettings['ROOT'] = root 1253 mysettings['CD_ROOT'] = "/tmp" 1254 1255 mysettings.backup_changes("EAPI") 1256 mysettings.backup_changes("LICENSE") 1257 mysettings.backup_changes("EBUILD_PHASE") 1258 mysettings.backup_changes("ROOT") 1259 mysettings.backup_changes("CD_ROOT") 1260 1261 try: # this is a >portage-2.1.4_rc11 feature 1262 mysettings._environ_whitelist = set(mysettings._environ_whitelist) 1263 # put our vars into whitelist 1264 mysettings._environ_whitelist.add("SKIP_EQUO_SYNC") 1265 mysettings._environ_whitelist.add("ACCEPT_LICENSE") 1266 mysettings._environ_whitelist.add("CD_ROOT") 1267 mysettings._environ_whitelist.add("ROOT") 1268 mysettings._environ_whitelist = frozenset(mysettings._environ_whitelist) 1269 except (AttributeError,): 1270 self.log_message(entropy.tools.get_traceback()) 1271 1272 cpv = str(cpv) 1273 mysettings.setcpv(cpv) 1274 portage_tmpdir_created = False # for pkg_postrm, pkg_prerm 1275 1276 if portage_tmpdir is None: 1277 portage_tmpdir = entropy.tools.get_random_temp_file() 1278 1279 if portage_tmpdir: 1280 if not os.path.isdir(portage_tmpdir): 1281 os.makedirs(portage_tmpdir) 1282 portage_tmpdir_created = True 1283 mysettings['PORTAGE_TMPDIR'] = str(portage_tmpdir) 1284 mysettings.backup_changes("PORTAGE_TMPDIR") 1285 1286 # create FAKE ${PORTDIR} directory and licenses subdir 1287 portdir = os.path.join(portage_tmpdir, "portdir") 1288 portdir_lic = os.path.join(portdir, "licenses") 1289 if not os.path.isdir(portdir): 1290 os.mkdir(portdir) # portage_tmpdir must be available! 1291 # create licenses subdir 1292 if not os.path.isdir(portdir_lic): 1293 os.mkdir(portdir_lic) 1294 1295 # set fake PORTDIR 1296 old_portdir = mysettings["PORTDIR"][:] 1297 mysettings["PORTDIR"] = portdir 1298 mysettings.backup_changes("PORTDIR") 1299 1300 ### WORKAROUND for buggy check_license() in eutils.eclass 1301 ### that looks for file availability before considering 1302 ### ACCEPT_LICENSE 1303 for lic in licenses: 1304 lic_path = os.path.join(portdir_lic, lic) 1305 if not os.access(lic_path, os.F_OK): 1306 lic_f = open(lic_path, "w") 1307 lic_f.close() 1308 1309 mydbapi = self.portage.fakedbapi(settings=mysettings) 1310 mydbapi.cpv_inject(cpv, metadata = metadata) 1311 1312 # cached vartree class 1313 vartree = self._get_portage_vartree(root = root) 1314 1315 try: 1316 rc = self.portage.doebuild( 1317 myebuild = str(myebuild), 1318 mydo = str(mydo), 1319 myroot = root, 1320 tree = tree, 1321 mysettings = mysettings, 1322 mydbapi = mydbapi, 1323 vartree = vartree, 1324 use_cache = 0 1325 ) 1326 except: 1327 self.log_message(entropy.tools.get_traceback()) 1328 raise 1329 1330 # if mute, restore old stdout/stderr 1331 if domute: 1332 sys.stdout = oldsysstdout 1333 1334 sys.stderr = oldsystderr 1335 dev_null.close() 1336 1337 if portage_tmpdir_created: 1338 shutil.rmtree(portage_tmpdir, True) 1339 1340 # reset PORTDIR back to its old path 1341 # for security ! 1342 mysettings["PORTDIR"] = old_portdir 1343 mysettings.backup_changes("PORTDIR") 1344 1345 del mydbapi 1346 del metadata 1347 del keys 1348 return rc
1349
1350 - def execute_package_phase(self, package, build_script_path, phase_name, 1351 work_dir = None, licenses_accepted = None):
1352 """ 1353 Reimplemented from SpmPlugin class. 1354 """ 1355 if licenses_accepted is None: 1356 licenses_accepted = [] 1357 1358 portage_phase = PortagePlugin.package_phases_map[phase_name] 1359 return self._portage_doebuild(build_script_path, portage_phase, 1360 "bintree", package, work_dir, licenses_accepted)
1361
1362 - def add_installed_package(self, package_metadata):
1363 """ 1364 Reimplemented from SpmPlugin class. 1365 """ 1366 atomsfound = set() 1367 category = package_metadata['category'] 1368 key = category + "/" + package_metadata['name'] 1369 spm_package = key + "-" + package_metadata['version'] 1370 1371 build = self.get_installed_package_build_script_path(spm_package) 1372 pkg_dir = os.path.dirname(build) 1373 cat_dir = os.path.dirname(pkg_dir) 1374 1375 if os.path.isdir(cat_dir): 1376 my_findings = [os.path.join(category, x) for x in \ 1377 os.listdir(cat_dir)] 1378 # filter by key 1379 real_findings = [x for x in my_findings if \ 1380 key == entropy.tools.dep_getkey(x)] 1381 atomsfound.update(real_findings) 1382 1383 myslot = package_metadata['slot'] 1384 for xatom in atomsfound: 1385 1386 if self.get_installed_package_metadata(xatom, "SLOT") != myslot: 1387 continue 1388 1389 mybuild = self.get_installed_package_build_script_path(xatom) 1390 remove_path = os.path.dirname(mybuild) 1391 shutil.rmtree(remove_path, True) 1392 1393 # we now install it 1394 xpak_rel_path = etpConst['entropyxpakdatarelativepath'] 1395 proposed_xpak_dir = os.path.join(package_metadata['xpakpath'], 1396 xpak_rel_path) 1397 1398 counter = -1 1399 if (package_metadata['xpakstatus'] != None) and \ 1400 os.path.isdir(proposed_xpak_dir) or package_metadata['merge_from']: 1401 1402 copypath = proposed_xpak_dir 1403 if package_metadata['merge_from']: 1404 copypath = package_metadata['xpakdir'] 1405 if not os.path.isdir(copypath): 1406 return 0 1407 1408 if not os.path.isdir(cat_dir): 1409 os.makedirs(cat_dir, 0755) 1410 if os.path.isdir(pkg_dir): 1411 shutil.rmtree(pkg_dir) 1412 1413 try: 1414 shutil.copytree(copypath, pkg_dir) 1415 except (IOError,), e: 1416 mytxt = "%s: %s: %s: %s" % (red(_("QA")), 1417 brown(_("Cannot update Portage database to destination")), 1418 purple(pkg_dir),e,) 1419 self.updateProgress( 1420 mytxt, 1421 importance = 1, 1422 type = "warning", 1423 header = darkred(" ## ") 1424 ) 1425 1426 try: 1427 counter = self.assign_uid_to_installed_package(spm_package) 1428 except SPMError, err: 1429 mytxt = "%s: %s [%s]" % ( 1430 brown(_("SPM uid update error")), pkg_dir, err, 1431 ) 1432 self.updateProgress( 1433 red("QA: ") + mytxt, 1434 importance = 1, 1435 type = "warning", 1436 header = darkred(" ## ") 1437 ) 1438 counter = -1 1439 1440 user_inst_source = etpConst['install_sources']['user'] 1441 if package_metadata['install_source'] != user_inst_source: 1442 # only user selected packages in Portage world file 1443 return counter 1444 1445 myslot = package_metadata['slot'][:] 1446 if (package_metadata['versiontag'] == package_metadata['slot']) \ 1447 and package_metadata['versiontag']: 1448 # usually kernel packages 1449 myslot = "0" 1450 1451 keyslot = key+":"+myslot 1452 world_file = self.get_user_installed_packages_file() 1453 world_dir = os.path.dirname(world_file) 1454 world_atoms = set() 1455 1456 if os.access(world_file, os.R_OK | os.F_OK): 1457 with open(world_file, "r") as world_f: 1458 world_atoms |= set((x.strip() for x in world_f.readlines() if \ 1459 x.strip())) 1460 1461 try: 1462 1463 if keyslot not in world_atoms and \ 1464 os.access(world_dir, os.W_OK) and \ 1465 entropy.tools.istextfile(world_file): 1466 1467 world_atoms.discard(key) 1468 world_atoms.add(keyslot) 1469 world_file_tmp = world_file+".entropy_inst" 1470 1471 with open(world_file_tmp, "w") as world_f: 1472 for item in sorted(world_atoms): 1473 world_f.write(item + "\n") 1474 world_f.flush() 1475 1476 os.rename(world_file_tmp, world_file) 1477 1478 except (UnicodeDecodeError, UnicodeEncodeError,), e: 1479 1480 mytxt = "%s: %s" % ( 1481 brown(_("Cannot update SPM installed pkgs file")), world_file, 1482 ) 1483 self.updateProgress( 1484 red("QA: ") + mytxt + ": " + unicode(e), 1485 importance = 1, 1486 type = "warning", 1487 header = darkred(" ## ") 1488 ) 1489 1490 return counter
1491
1492 - def remove_installed_package(self, package_metadata):
1493 """ 1494 Reimplemented from SpmPlugin class. 1495 """ 1496 atom = entropy.tools.remove_tag(package_metadata['removeatom']) 1497 remove_build = self.get_installed_package_build_script_path(atom) 1498 remove_path = os.path.dirname(remove_build) 1499 key = entropy.tools.dep_getkey(atom) 1500 1501 others_installed = self.match_installed_package(key, match_all = True) 1502 if atom in others_installed: 1503 others_installed.remove(atom) 1504 1505 # Support for tagged packages 1506 slot = package_metadata['slot'] 1507 tag = package_metadata['versiontag'] 1508 if (tag == slot) and tag: 1509 slot = "0" 1510 1511 def do_rm_path_atomic(xpath): 1512 for my_el in os.listdir(xpath): 1513 my_el = os.path.join(xpath, my_el) 1514 try: 1515 os.remove(my_el) 1516 except OSError: 1517 pass 1518 try: 1519 os.rmdir(xpath) 1520 except OSError: 1521 pass
1522 1523 if os.path.isdir(remove_path): 1524 do_rm_path_atomic(remove_path) 1525 1526 # also remove parent directory if empty 1527 category_path = os.path.dirname(remove_path) 1528 if os.path.isdir(category_path): 1529 if not os.listdir(category_path): 1530 try: 1531 os.rmdir(category_path) 1532 except OSError: 1533 pass 1534 1535 if others_installed: 1536 1537 for myatom in others_installed: 1538 myslot = self.get_installed_package_metadata(myatom, "SLOT") 1539 if myslot != slot: 1540 continue 1541 mybuild = self.get_installed_package_build_script_path(myatom) 1542 mydir = os.path.dirname(mybuild) 1543 if not os.path.isdir(mydir): 1544 continue 1545 do_rm_path_atomic(mydir) 1546 1547 return 0 1548 1549 # otherwise update Portage world file 1550 world_file = self.get_user_installed_packages_file() 1551 world_file_tmp = world_file + ".entropy.tmp" 1552 if os.access(world_file, os.W_OK | os.F_OK): 1553 1554 new = open(world_file_tmp,"w") 1555 old = open(world_file,"r") 1556 line = old.readline() 1557 1558 while line: 1559 1560 if line.find(key) != -1: 1561 line = old.readline() 1562 continue 1563 if line.find(key+":"+slot) != -1: 1564 line = old.readline() 1565 continue 1566 new.write(line) 1567 line = old.readline() 1568 1569 new.flush() 1570 new.close() 1571 old.close() 1572 os.rename(world_file_tmp, world_file) 1573 1574 return 0 1575
1576 - def configure_installed_package(self, package_metadata):
1577 """ 1578 Reimplemented from SpmPlugin class. 1579 """ 1580 atom = package_metadata['key'] + "-" + package_metadata['version'] 1581 myebuild = self.get_installed_package_build_script_path(atom) 1582 1583 if not os.access(myebuild, os.R_OK | os.F_OK): 1584 # cannot find ebuild ! ouch! 1585 return 2 1586 1587 try: 1588 rc = self.execute_package_phase(atom, myebuild, 1589 "configure", 1590 licenses_accepted = package_metadata['accept_license'] 1591 ) 1592 if rc == 1: 1593 return 3 1594 1595 except Exception, err: 1596 1597 entropy.tools.print_traceback() 1598 mytxt = "%s: %s %s." % ( 1599 bold(_("QA")), 1600 brown(_("Cannot run SPM configure phase for")), 1601 bold(str(atom)), 1602 ) 1603 mytxt2 = "%s: %s, %s" % ( 1604 bold(_("Error")), 1605 type(Exception), 1606 err, 1607 ) 1608 for txt in (mytxt, mytxt2,): 1609 self.updateProgress( 1610 txt, 1611 importance = 0, 1612 header = red(" ## ") 1613 ) 1614 return 1 1615 1616 return 0
1617 1618 @staticmethod
1619 - def entropy_install_setup_hook(entropy_client, package_metadata):
1620 """ 1621 Reimplemented from SpmPlugin class. 1622 """ 1623 package_metadata['xpakpath'] = etpConst['entropyunpackdir'] + \ 1624 os.path.sep + package_metadata['download'] + os.path.sep + \ 1625 etpConst['entropyxpakrelativepath'] 1626 1627 if not package_metadata['merge_from']: 1628 1629 package_metadata['xpakstatus'] = None 1630 package_metadata['xpakdir'] = package_metadata['xpakpath'] + \ 1631 os.path.sep + etpConst['entropyxpakdatarelativepath'] 1632 1633 else: 1634 1635 package_metadata['xpakstatus'] = True 1636 1637 try: 1638 try: 1639 import portage.const as portage_const 1640 except ImportError: 1641 import portage_const 1642 portdbdir = portage_const.VDB_PATH 1643 except ImportError: 1644 portdbdir = 'var/db/pkg' 1645 1646 portdbdir = os.path.join(package_metadata['merge_from'], portdbdir) 1647 portdbdir = os.path.join(portdbdir, package_metadata['category']) 1648 portdbdir = os.path.join(portdbdir, package_metadata['name'] + \ 1649 "-" + package_metadata['version']) 1650 1651 package_metadata['xpakdir'] = portdbdir 1652 1653 package_metadata['triggers']['install']['xpakdir'] = \ 1654 package_metadata['xpakdir'] 1655 1656 return 0
1657 1658 @staticmethod
1659 - def entropy_install_unpack_hook(entropy_client, package_metadata):
1660 """ 1661 Reimplemented from SpmPlugin class. 1662 """ 1663 # unpack xpak ? 1664 if os.path.isdir(package_metadata['xpakpath']): 1665 shutil.rmtree(package_metadata['xpakpath'], True) 1666 1667 # create data dir where we'll unpack the xpak 1668 xpak_dir = package_metadata['xpakpath'] + os.path.sep + \ 1669 etpConst['entropyxpakdatarelativepath'] 1670 1671 os.makedirs(xpak_dir, 0755) 1672 1673 xpak_path = package_metadata['xpakpath'] + os.path.sep + \ 1674 etpConst['entropyxpakfilename'] 1675 1676 if not package_metadata['merge_from']: 1677 1678 if package_metadata['smartpackage']: 1679 1680 # we need to get the .xpak from database 1681 xdbconn = entropy_client.open_repository( 1682 package_metadata['repository']) 1683 xpakdata = xdbconn.retrieveXpakMetadata( 1684 package_metadata['idpackage']) 1685 if xpakdata: 1686 # save into a file 1687 with open(xpak_path, "wb") as xpak_f: 1688 xpak_f.write(xpakdata) 1689 xpak_f.flush() 1690 package_metadata['xpakstatus'] = \ 1691 entropy.tools.unpack_xpak( 1692 xpak_path, 1693 xpak_dir 1694 ) 1695 else: 1696 package_metadata['xpakstatus'] = None 1697 del xpakdata 1698 1699 else: 1700 package_metadata['xpakstatus'] = entropy.tools.extract_xpak( 1701 package_metadata['pkgpath'], 1702 xpak_dir 1703 ) 1704 1705 else: # merge_from 1706 1707 tolink_dir = xpak_dir 1708 if os.path.isdir(tolink_dir): 1709 shutil.rmtree(tolink_dir, True) 1710 # now link 1711 os.symlink(package_metadata['xpakdir'], tolink_dir) 1712 1713 # create fake portage ${D} linking it to imagedir 1714 portage_cpv = package_metadata['category'] + "/" + \ 1715 package_metadata['name'] + "-" + package_metadata['version'] 1716 1717 portage_db_fakedir = os.path.join( 1718 package_metadata['unpackdir'], 1719 "portage/" + portage_cpv 1720 ) 1721 1722 os.makedirs(portage_db_fakedir, 0755) 1723 # now link it to package_metadata['imagedir'] 1724 os.symlink(package_metadata['imagedir'], 1725 os.path.join(portage_db_fakedir, "image")) 1726 1727 return 0
1728
1729 - def _get_portage_vartree(self, root = None):
1730 1731 if root is None: 1732 root = etpConst['systemroot'] + os.path.sep 1733 1734 if not etpConst['spm']['cache'].has_key('portage'): 1735 etpConst['spm']['cache']['portage'] = {} 1736 if not etpConst['spm']['cache']['portage'].has_key('vartree'): 1737 etpConst['spm']['cache']['portage']['vartree'] = {} 1738 1739 cached = etpConst['spm']['cache']['portage']['vartree'].get(root) 1740 if cached != None: 1741 return cached 1742 1743 try: 1744 mytree = self.portage.vartree(root=root) 1745 except Exception, e: 1746 raise SPMError("SPMError: %s: %s" % (Exception,e,)) 1747 etpConst['spm']['cache']['portage']['vartree'][root] = mytree 1748 return mytree
1749
1750 - def _get_portage_portagetree(self, root):
1751 1752 if not etpConst['spm']['cache'].has_key('portage'): 1753 etpConst['spm']['cache']['portage'] = {} 1754 if not etpConst['spm']['cache']['portage'].has_key('portagetree'): 1755 etpConst['spm']['cache']['portage']['portagetree'] = {} 1756 1757 cached = etpConst['spm']['cache']['portage']['portagetree'].get(root) 1758 if cached != None: 1759 return cached 1760 1761 try: 1762 mytree = self.portage.portagetree(root=root) 1763 except Exception, e: 1764 raise SPMError("SPMError: %s: %s" % (Exception,e,)) 1765 etpConst['spm']['cache']['portage']['portagetree'][root] = mytree 1766 return mytree
1767
1768 - def _get_portage_binarytree(self, root):
1769 1770 if not etpConst['spm']['cache'].has_key('portage'): 1771 etpConst['spm']['cache']['portage'] = {} 1772 if not etpConst['spm']['cache']['portage'].has_key('binarytree'): 1773 etpConst['spm']['cache']['portage']['binarytree'] = {} 1774 1775 cached = etpConst['spm']['cache']['portage']['binarytree'].get(root) 1776 if cached != None: 1777 return cached 1778 1779 pkgdir = root+self.portage.settings['PKGDIR'] 1780 try: 1781 mytree = self.portage.binarytree(root,pkgdir) 1782 except Exception, e: 1783 raise SPMError("SPMError: %s: %s" % (Exception,e,)) 1784 etpConst['spm']['cache']['portage']['binarytree'][root] = mytree 1785 return mytree
1786
1787 - def _get_portage_config(self, config_root, root, use_cache = True):
1788 1789 if use_cache: 1790 if not etpConst['spm']['cache'].has_key('portage'): 1791 etpConst['spm']['cache']['portage'] = {} 1792 if not etpConst['spm']['cache']['portage'].has_key('config'): 1793 etpConst['spm']['cache']['portage']['config'] = {} 1794 1795 cached = etpConst['spm']['cache']['portage']['config'].get((config_root,root)) 1796 if cached != None: 1797 return cached 1798 1799 try: 1800 mysettings = self.portage.config(config_root = config_root, target_root = root, config_incrementals = self.portage_const.INCREMENTALS) 1801 except Exception, e: 1802 raise SPMError("SPMError: %s: %s" % (Exception,e,)) 1803 if use_cache: 1804 etpConst['spm']['cache']['portage']['config'][(config_root,root)] = mysettings 1805 return mysettings
1806
1807 - def _get_package_use_file(self):
1808 return os.path.join(self.portage_const.USER_CONFIG_PATH,'package.use')
1809
1810 - def _handle_new_useflags(self, atom, useflags, mark):
1811 matched_atom = self.match_package(atom) 1812 if not matched_atom: 1813 return False 1814 use_file = self._get_package_use_file() 1815 1816 if not (os.path.isfile(use_file) and os.access(use_file,os.W_OK)): 1817 return False 1818 f = open(use_file,"r") 1819 content = [x.strip() for x in f.readlines()] 1820 f.close() 1821 1822 def handle_line(line, useflags): 1823 1824 data = line.split() 1825 if len(data) < 2: 1826 return False, line 1827 1828 myatom = data[0] 1829 if matched_atom != self.match_package(myatom): 1830 return False, line 1831 1832 flags = data[1:] 1833 base_flags = [] 1834 added_flags = [] 1835 for flag in flags: 1836 myflag = flag 1837 if myflag.startswith("+"): 1838 myflag = myflag[1:] 1839 elif myflag.startswith("-"): 1840 myflag = myflag[1:] 1841 if not myflag: 1842 continue 1843 base_flags.append(myflag) 1844 1845 for useflag in useflags: 1846 if mark+useflag in base_flags: 1847 continue 1848 added_flags.append(mark+useflag) 1849 1850 new_line = "%s %s" % (myatom, ' '.join(flags+added_flags)) 1851 return True, new_line
1852 1853 1854 atom_found = False 1855 new_content = [] 1856 for line in content: 1857 1858 changed, elaborated_line = handle_line(line, useflags) 1859 if changed: atom_found = True 1860 new_content.append(elaborated_line) 1861 1862 if not atom_found: 1863 myline = "%s %s" % (atom, ' '.join([mark+x for x in useflags])) 1864 new_content.append(myline) 1865 1866 1867 f = open(use_file+".tmp","w") 1868 for line in new_content: 1869 f.write(line+"\n") 1870 f.flush() 1871 f.close() 1872 os.rename(use_file+".tmp", use_file) 1873 return True 1874
1875 - def _unset_package_useflags(self, atom, useflags):
1876 matched_atom = self.match_package(atom) 1877 if not matched_atom: 1878 return False 1879 1880 use_file = self._get_package_use_file() 1881 if not (os.path.isfile(use_file) and os.access(use_file,os.W_OK)): 1882 return False 1883 1884 with open(use_file, "r") as f: 1885 content = [x.strip() for x in f.readlines()] 1886 1887 new_content = [] 1888 for line in content: 1889 1890 data = line.split() 1891 if len(data) < 2: 1892 new_content.append(line) 1893 continue 1894 1895 myatom = data[0] 1896 if matched_atom != self.match_package(myatom): 1897 new_content.append(line) 1898 continue 1899 1900 flags = data[1:] 1901 new_flags = [] 1902 for flag in flags: 1903 myflag = flag 1904 1905 if myflag.startswith("+"): 1906 myflag = myflag[1:] 1907 elif myflag.startswith("-"): 1908 myflag = myflag[1:] 1909 1910 if myflag in useflags: 1911 continue 1912 elif not flag: 1913 continue 1914 1915 new_flags.append(flag) 1916 1917 if new_flags: 1918 new_line = "%s %s" % (myatom, ' '.join(new_flags)) 1919 new_content.append(new_line) 1920 1921 with open(use_file+".tmp", "w") as f: 1922 for line in new_content: 1923 f.write(line+"\n") 1924 f.flush() 1925 1926 os.rename(use_file+".tmp", use_file) 1927 return True
1928
1929 - def _get_package_use_useflags(self, atom):
1930 1931 data = { 1932 'enabled': set(), 1933 'disabled': set(), 1934 } 1935 1936 matched_atom = self.match_package(atom) 1937 if not matched_atom: 1938 return data 1939 1940 use_file = self._get_package_use_file() 1941 if not (os.path.isfile(use_file) and os.access(use_file,os.W_OK)): 1942 return data 1943 1944 use_data = self.portage_util.grabdict(use_file) 1945 for myatom in use_data: 1946 mymatch = self.match_package(myatom) 1947 if mymatch != matched_atom: 1948 continue 1949 for flag in use_data[myatom]: 1950 if flag.startswith("-"): 1951 myflag = flag[1:] 1952 data['enabled'].discard(myflag) 1953 data['disabled'].add(myflag) 1954 else: 1955 myflag = flag 1956 if myflag.startswith("+"): 1957 myflag = myflag[1:] 1958 data['disabled'].discard(myflag) 1959 data['enabled'].add(myflag) 1960 1961 return data
1962
1963 - def _get_useflags(self):
1964 return self.portage.settings['USE']
1965
1966 - def _get_useflags_force(self):
1967 return self.portage.settings.useforce
1968
1969 - def _get_useflags_mask(self):
1970 return self.portage.settings.usemask
1971
1972 - def _resolve_enabled_useflags(self, iuse_list, use_list):
1973 use = set() 1974 use_mask = self._get_useflags_mask() 1975 use_force = self._get_useflags_force() 1976 for myiuse in iuse_list: 1977 if myiuse[0] in ("+", "-",): 1978 myiuse = myiuse[1:] 1979 if ((myiuse in use_list) or (myiuse in use_force)) and \ 1980 (myiuse not in use_mask): 1981 use.add(myiuse) 1982 return use
1983
1984 - def _calculate_dependencies(self, my_iuse, my_use, my_license, my_depend, 1985 my_rdepend, my_pdepend, my_provide, my_src_uri):
1986 1987 metadata = { 1988 'LICENSE': my_license, 1989 'DEPEND': my_depend, 1990 'PDEPEND': my_pdepend, 1991 'RDEPEND': my_rdepend, 1992 'PROVIDE': my_provide, 1993 'SRC_URI': my_src_uri, 1994 'USE_MASK': sorted(self._get_useflags_mask()), 1995 'USE_FORCE': sorted(self._get_useflags_force()), 1996 } 1997 1998 # generate USE flags metadata 1999 raw_use = my_use.split() 2000 enabled_use = sorted(self._resolve_enabled_useflags( 2001 my_iuse.split(), raw_use)) 2002 2003 metadata['ENABLED_USE'] = enabled_use 2004 use = raw_use + [x for x in metadata['USE_FORCE'] if x not in raw_use] 2005 metadata['USE'] = sorted([unicode(x) for x in use if x not in \ 2006 metadata['USE_MASK']]) 2007 2008 for k in "LICENSE", "RDEPEND", "DEPEND", "PDEPEND", "PROVIDE", "SRC_URI": 2009 try: 2010 if k == "SRC_URI": 2011 deps = self._src_uri_paren_reduce(metadata[k]) 2012 else: 2013 deps = self._paren_reduce(metadata[k]) 2014 deps = self._use_reduce(deps, uselist = raw_use) 2015 deps = self.paren_normalize(deps) 2016 if k == "LICENSE": 2017 deps = self._paren_license_choose(deps) 2018 else: 2019 deps = self._paren_choose(deps) 2020 if k.endswith("DEPEND"): 2021 deps = self._usedeps_reduce(deps, enabled_use) 2022 deps = ' '.join(deps) 2023 except Exception, e: 2024 entropy.tools.print_traceback() 2025 self.updateProgress( 2026 darkred("%s: %s: %s :: %s") % ( 2027 _("Error calculating dependencies"), 2028 str(Exception), 2029 k, 2030 e, 2031 ), 2032 importance = 1, 2033 type = "error", 2034 header = red(" !!! ") 2035 ) 2036 deps = '' 2037 continue 2038 metadata[k] = deps 2039 return metadata
2040
2041 - def _src_uri_paren_reduce(self, src_uris):
2042 src_uris = self._paren_reduce(src_uris) 2043 newlist = [] 2044 skip_next = False 2045 for src_uri in src_uris: 2046 if skip_next: 2047 skip_next = False 2048 continue 2049 if src_uri == "->": 2050 skip_next = True 2051 continue 2052 newlist.append(src_uri) 2053 return newlist
2054
2055 - def _usedeps_reduce(self, dependencies, enabled_useflags):
2056 newlist = [] 2057 2058 def strip_use(xuse): 2059 myuse = xuse[:] 2060 if myuse[0] == "!": 2061 myuse = myuse[1:] 2062 if myuse[-1] in ("=","?",): 2063 myuse = myuse[:-1] 2064 return myuse
2065 2066 for dependency in dependencies: 2067 use_deps = entropy.tools.dep_getusedeps(dependency) 2068 if use_deps: 2069 new_use_deps = [] 2070 for use in use_deps: 2071 """ 2072 explicitly support only specific types 2073 """ 2074 if (use[0] == "!") and (use[-1] not in ("=","?",)): 2075 # this does not exist atm 2076 continue 2077 elif use[-1] == "=": 2078 if use[0] == "!": 2079 # foo[!bar=] means bar? ( foo[-bar] ) !bar? ( foo[bar] ) 2080 s_use = strip_use(use) 2081 if s_use in enabled_useflags: 2082 new_use_deps.append("-%s" % (s_use,)) 2083 else: 2084 new_use_deps.append(s_use) 2085 continue 2086 else: 2087 # foo[bar=] means bar? ( foo[bar] ) !bar? ( foo[-bar] ) 2088 s_use = strip_use(use) 2089 if s_use in enabled_useflags: 2090 new_use_deps.append(s_use) 2091 else: 2092 new_use_deps.append("-%s" % (s_use,)) 2093 continue 2094 elif use[-1] == "?": 2095 if use[0] == "!": 2096 # foo[!bar?] means bar? ( foo ) !bar? ( foo[-bar] ) 2097 s_use = strip_use(use) 2098 if s_use not in enabled_useflags: 2099 new_use_deps.append("-%s" % (s_use,)) 2100 continue 2101 else: 2102 # foo[bar?] means bar? ( foo[bar] ) !bar? ( foo ) 2103 s_use = strip_use(use) 2104 if s_use in enabled_useflags: 2105 new_use_deps.append(s_use) 2106 continue 2107 new_use_deps.append(use) 2108 2109 if new_use_deps: 2110 dependency = "%s[%s]" % ( 2111 entropy.tools.remove_usedeps(dependency), 2112 ','.join(new_use_deps), 2113 ) 2114 else: 2115 dependency = entropy.tools.remove_usedeps(dependency) 2116 2117 newlist.append(dependency) 2118 return newlist 2119
2120 - def _paren_reduce(self, mystr):
2121 """ 2122 2123 # deps.py -- Portage dependency resolution functions 2124 # Copyright 2003-2004 Gentoo Foundation 2125 # Distributed under the terms of the GNU General Public License v2 2126 # $Id: portage_dep.py 9174 2008-01-11 05:49:02Z zmedico $ 2127 2128 Take a string and convert all paren enclosed entities into sublists, optionally 2129 futher splitting the list elements by spaces. 2130 2131 Example usage: 2132 >>> paren_reduce('foobar foo ( bar baz )',1) 2133 ['foobar', 'foo', ['bar', 'baz']] 2134 >>> paren_reduce('foobar foo ( bar baz )',0) 2135 ['foobar foo ', [' bar baz ']] 2136 2137 @param mystr: The string to reduce 2138 @type mystr: String 2139 @rtype: Array 2140 @return: The reduced string in an array 2141 """ 2142 mylist = [] 2143 while mystr: 2144 left_paren = mystr.find("(") 2145 has_left_paren = left_paren != -1 2146 right_paren = mystr.find(")") 2147 has_right_paren = right_paren != -1 2148 if not has_left_paren and not has_right_paren: 2149 freesec = mystr 2150 subsec = None 2151 tail = "" 2152 elif mystr[0] == ")": 2153 return [mylist,mystr[1:]] 2154 elif has_left_paren and not has_right_paren: 2155 raise InvalidDependString( 2156 "InvalidDependString: %s: '%s'" % (_("missing right parenthesis"),mystr,)) 2157 elif has_left_paren and left_paren < right_paren: 2158 freesec,subsec = mystr.split("(",1) 2159 subsec,tail = self._paren_reduce(subsec) 2160 else: 2161 subsec,tail = mystr.split(")",1) 2162 subsec = self._strip_empty(subsec.split(" ")) 2163 return [mylist+subsec,tail] 2164 mystr = tail 2165 if freesec: 2166 mylist = mylist + self._strip_empty(freesec.split(" ")) 2167 if subsec is not None: 2168 mylist = mylist + [subsec] 2169 return mylist
2170
2171 - def _strip_empty(self, myarr):
2172 """ 2173 2174 # deps.py -- Portage dependency resolution functions 2175 # Copyright 2003-2004 Gentoo Foundation 2176 # Distributed under the terms of the GNU General Public License v2 2177 # $Id: portage_dep.py 9174 2008-01-11 05:49:02Z zmedico $ 2178 2179 Strip all empty elements from an array 2180 2181 @param myarr: The list of elements 2182 @type myarr: List 2183 @rtype: Array 2184 @return: The array with empty elements removed 2185 """ 2186 for x in range(len(myarr)-1, -1, -1): 2187 if not myarr[x]: 2188 del myarr[x] 2189 return myarr
2190
2191 - def _use_reduce(self, deparray, uselist = None, masklist = None, 2192 matchall = 0, excludeall = None):
2193 """ 2194 2195 # deps.py -- Portage dependency resolution functions 2196 # Copyright 2003-2004 Gentoo Foundation 2197 # Distributed under the terms of the GNU General Public License v2 2198 # $Id: portage_dep.py 9174 2008-01-11 05:49:02Z zmedico $ 2199 2200 Takes a paren_reduce'd array and reduces the use? conditionals out 2201 leaving an array with subarrays 2202 2203 @param deparray: paren_reduce'd list of deps 2204 @type deparray: List 2205 @param uselist: List of use flags 2206 @type uselist: List 2207 @param masklist: List of masked flags 2208 @type masklist: List 2209 @param matchall: Resolve all conditional deps unconditionally. Used by repoman 2210 @type matchall: Integer 2211 @rtype: List 2212 @return: The use reduced depend array 2213 """ 2214 2215 if uselist is None: 2216 uselist = [] 2217 if masklist is None: 2218 masklist = [] 2219 if excludeall is None: 2220 excludeall = [] 2221 2222 # Quick validity checks 2223 for x in range(len(deparray)): 2224 if deparray[x] in ["||","&&"]: 2225 if len(deparray) - 1 == x or not isinstance(deparray[x+1], list): 2226 mytxt = _("missing atom list in") 2227 raise InvalidDependString(deparray[x]+" "+mytxt+" \""+str(deparray)+"\"") 2228 if deparray and deparray[-1] and deparray[-1][-1] == "?": 2229 mytxt = _("Conditional without target in") 2230 raise InvalidDependString("InvalidDependString: "+mytxt+" \""+str(deparray)+"\"") 2231 2232 # This is just for use by emerge so that it can enable a backward compatibility 2233 # mode in order to gracefully deal with installed packages that have invalid 2234 # atoms or dep syntax. For backward compatibility with api consumers, strict 2235 # behavior will be explicitly enabled as necessary. 2236 _dep_check_strict = False 2237 2238 mydeparray = deparray[:] 2239 rlist = [] 2240 while mydeparray: 2241 head = mydeparray.pop(0) 2242 2243 if isinstance(head,list): 2244 additions = self._use_reduce(head, uselist, masklist, matchall, excludeall) 2245 if additions: 2246 rlist.append(additions) 2247 elif rlist and rlist[-1] == "||": 2248 #XXX: Currently some DEPEND strings have || lists without default atoms. 2249 # raise portage_exception.InvalidDependString("No default atom(s) in \""+paren_enclose(deparray)+"\"") 2250 rlist.append([]) 2251 else: 2252 if head[-1] == "?": # Use reduce next group on fail. 2253 # Pull any other use conditions and the following atom or list into a separate array 2254 newdeparray = [head] 2255 while isinstance(newdeparray[-1], basestring) and newdeparray[-1][-1] == "?": 2256 if mydeparray: 2257 newdeparray.append(mydeparray.pop(0)) 2258 else: 2259 raise ValueError, _("Conditional with no target") 2260 2261 # Deprecation checks 2262 warned = 0 2263 if len(newdeparray[-1]) == 0: 2264 mytxt = "%s. (%s)" % (_("Empty target in string"),_("Deprecated"),) 2265 self.updateProgress( 2266 darkred("PortagePlugin._use_reduce(): %s" % (mytxt,)), 2267 importance = 0, 2268 type = "error", 2269 header = bold(" !!! ") 2270 ) 2271 warned = 1 2272 if len(newdeparray) != 2: 2273 mytxt = "%s. (%s)" % (_("Nested use flags without parenthesis"),_("Deprecated"),) 2274 self.updateProgress( 2275 darkred("PortagePlugin._use_reduce(): %s" % (mytxt,)), 2276 importance = 0, 2277 type = "error", 2278 header = bold(" !!! ") 2279 ) 2280 warned = 1 2281 if warned: 2282 self.updateProgress( 2283 darkred("PortagePlugin._use_reduce(): "+" ".join(map(str,[head]+newdeparray))), 2284 importance = 0, 2285 type = "error", 2286 header = bold(" !!! ") 2287 ) 2288 2289 # Check that each flag matches 2290 ismatch = True 2291 missing_flag = False 2292 for head in newdeparray[:-1]: 2293 head = head[:-1] 2294 if not head: 2295 missing_flag = True 2296 break 2297 if head.startswith("!"): 2298 head_key = head[1:] 2299 if not head_key: 2300 missing_flag = True 2301 break 2302 if not matchall and head_key in uselist or \ 2303 head_key in excludeall: 2304 ismatch = False 2305 break 2306 elif head not in masklist: 2307 if not matchall and head not in uselist: 2308 ismatch = False 2309 break 2310 else: 2311 ismatch = False 2312 if missing_flag: 2313 mytxt = _("Conditional without flag") 2314 raise InvalidDependString( 2315 "InvalidDependString: "+mytxt+": \"" + \ 2316 str([head+"?", newdeparray[-1]])+"\"") 2317 2318 # If they all match, process the target 2319 if ismatch: 2320 target = newdeparray[-1] 2321 if isinstance(target, list): 2322 additions = self._use_reduce(target, uselist, masklist, matchall, excludeall) 2323 if additions: 2324 rlist.append(additions) 2325 elif not _dep_check_strict: 2326 # The old deprecated behavior. 2327 rlist.append(target) 2328 else: 2329 mytxt = _("Conditional without parenthesis") 2330 raise InvalidDependString( 2331 "InvalidDependString: "+mytxt+": '%s?'" % head) 2332 2333 else: 2334 rlist += [head] 2335 return rlist
2336
2337 - def _paren_choose(self, dep_list):
2338 newlist = [] 2339 do_skip = False 2340 for idx in range(len(dep_list)): 2341 2342 if do_skip: 2343 do_skip = False 2344 continue 2345 2346 item = dep_list[idx] 2347 if item == "||": # or 2348 next_item = dep_list[idx+1] 2349 if not next_item: # || ( asd? ( atom ) dsa? ( atom ) ) => [] if use asd and dsa are disabled 2350 do_skip = True 2351 continue 2352 item = self._dep_or_select(next_item) # must be a list 2353 if not item: 2354 # no matches, transform to string and append, so reagent will fail 2355 newlist.append(str(next_item)) 2356 else: 2357 newlist += item 2358 do_skip = True 2359 elif isinstance(item, list): # and 2360 item = self._dep_and_select(item) 2361 newlist += item 2362 else: 2363 newlist.append(item) 2364 2365 return newlist
2366
2367 - def _dep_and_select(self, and_list):
2368 do_skip = False 2369 newlist = [] 2370 for idx in range(len(and_list)): 2371 2372 if do_skip: 2373 do_skip = False 2374 continue 2375 2376 x = and_list[idx] 2377 if x == "||": 2378 x = self._dep_or_select(and_list[idx+1]) 2379 do_skip = True 2380 if not x: 2381 x = str(and_list[idx+1]) 2382 else: 2383 newlist += x 2384 elif isinstance(x, list): 2385 x = self._dep_and_select(x) 2386 newlist += x 2387 else: 2388 newlist.append(x) 2389 2390 # now verify if all are satisfied 2391 for x in newlist: 2392 match = self.match_installed_package(x) 2393 if not match: 2394 return [] 2395 2396 return newlist
2397
2398 - def _dep_or_select(self, or_list):
2399 do_skip = False 2400 for idx in range(len(or_list)): 2401 if do_skip: 2402 do_skip = False 2403 continue 2404 x = or_list[idx] 2405 if x == "||": # or 2406 x = self._dep_or_select(or_list[idx+1]) 2407 do_skip = True 2408 elif isinstance(x, list): # and 2409 x = self._dep_and_select(x) 2410 if not x: 2411 continue 2412 # found 2413 return x 2414 else: 2415 x = [x] 2416 2417 for y in x: 2418 match = self.match_installed_package(y) 2419 if match: 2420 return [y] 2421 2422 return []
2423
2424 - def _paren_license_choose(self, dep_list):
2425 2426 newlist = set() 2427 for item in dep_list: 2428 2429 if isinstance(item, list): 2430 # match the first 2431 data = set(self._paren_license_choose(item)) 2432 newlist.update(data) 2433 else: 2434 if item not in ["||"]: 2435 newlist.add(item) 2436 2437 return list(newlist)
2438
2439 - def _get_vdb_path(self, root = None):
2440 if root is None: 2441 root = etpConst['systemroot'] + os.path.sep 2442 return os.path.join(root, self.portage_const.VDB_PATH)
2443
2444 - def _load_sets_config(self, settings, trees):
2445 2446 # from portage.const import USER_CONFIG_PATH, GLOBAL_CONFIG_PATH 2447 setconfigpaths = [os.path.join(self.portage_const.GLOBAL_CONFIG_PATH, etpConst['setsconffilename'])] 2448 setconfigpaths.append(os.path.join(settings["PORTDIR"], etpConst['setsconffilename'])) 2449 setconfigpaths += [os.path.join(x, etpConst['setsconffilename']) for x in settings["PORTDIR_OVERLAY"].split()] 2450 setconfigpaths.append(os.path.join(settings["PORTAGE_CONFIGROOT"], 2451 self.portage_const.USER_CONFIG_PATH.lstrip(os.path.sep), etpConst['setsconffilename'])) 2452 return self.portage_sets.SetConfig(setconfigpaths, settings, trees)
2453
2454 - def _get_set_config(self):
2455 # old portage 2456 if self.portage_sets == None: 2457 return 2458 myroot = etpConst['systemroot'] + os.path.sep 2459 return self._load_sets_config( 2460 self.portage.settings, 2461 self.portage.db[myroot] 2462 )
2463
2464 - def _extract_pkg_metadata_generate_extraction_dict(self):
2465 data = { 2466 'pf': { 2467 'path': etpConst['spm']['xpak_entries']['pf'], 2468 'critical': True, 2469 }, 2470 'chost': { 2471 'path': etpConst['spm']['xpak_entries']['chost'], 2472 'critical': True, 2473 }, 2474 'description': { 2475 'path': etpConst['spm']['xpak_entries']['description'], 2476 'critical': False, 2477 }, 2478 'homepage': { 2479 'path': etpConst['spm']['xpak_entries']['homepage'], 2480 'critical': False, 2481 }, 2482 'slot': { 2483 'path': etpConst['spm']['xpak_entries']['slot'], 2484 'critical': False, 2485 }, 2486 'cflags': { 2487 'path': etpConst['spm']['xpak_entries']['cflags'], 2488 'critical': False, 2489 }, 2490 'cxxflags': { 2491 'path': etpConst['spm']['xpak_entries']['cxxflags'], 2492 'critical': False, 2493 }, 2494 'category': { 2495 'path': etpConst['spm']['xpak_entries']['category'], 2496 'critical': True, 2497 }, 2498 'rdepend': { 2499 'path': etpConst['spm']['xpak_entries']['rdepend'], 2500 'critical': False, 2501 }, 2502 'pdepend': { 2503 'path': etpConst['spm']['xpak_entries']['pdepend'], 2504 'critical': False, 2505 }, 2506 'depend': { 2507 'path': etpConst['spm']['xpak_entries']['depend'], 2508 'critical': False, 2509 }, 2510 'use': { 2511 'path': etpConst['spm']['xpak_entries']['use'], 2512 'critical': False, 2513 }, 2514 'iuse': { 2515 'path': etpConst['spm']['xpak_entries']['iuse'], 2516 'critical': False, 2517 }, 2518 'license': { 2519 'path': etpConst['spm']['xpak_entries']['license'], 2520 'critical': False, 2521 }, 2522 'provide': { 2523 'path': etpConst['spm']['xpak_entries']['provide'], 2524 'critical': False, 2525 }, 2526 'sources': { 2527 'path': etpConst['spm']['xpak_entries']['src_uri'], 2528 'critical': False, 2529 }, 2530 'eclasses': { 2531 'path': etpConst['spm']['xpak_entries']['inherited'], 2532 'critical': False, 2533 }, 2534 'counter': { 2535 'path': etpConst['spm']['xpak_entries']['counter'], 2536 'critical': False, 2537 }, 2538 'keywords': { 2539 'path': etpConst['spm']['xpak_entries']['keywords'], 2540 'critical': False, 2541 }, 2542 'spm_phases': { 2543 'path': etpConst['spm']['xpak_entries']['defined_phases'], 2544 'critical': False, 2545 }, 2546 } 2547 return data
2548
2549 - def _extract_pkg_metadata_content(self, content_file, package_path):
2550 2551 pkg_content = {} 2552 2553 if os.path.isfile(content_file): 2554 2555 f = open(content_file,"r") 2556 content = [x.decode('raw_unicode_escape') for x in f.readlines()] 2557 f.close() 2558 outcontent = set() 2559 for line in content: 2560 line = line.strip().split() 2561 try: 2562 datatype = line[0] 2563 datafile = line[1:] 2564 if datatype == 'obj': 2565 datafile = datafile[:-2] 2566 datafile = ' '.join(datafile) 2567 elif datatype == 'dir': 2568 datafile = ' '.join(datafile) 2569 elif datatype == 'sym': 2570 datafile = datafile[:-3] 2571 datafile = ' '.join(datafile) 2572 else: 2573 myexc = "InvalidData: %s %s. %s." % ( 2574 datafile, 2575 _("not supported"), 2576 _("Probably Portage API has changed"), 2577 ) 2578 raise InvalidData(myexc) 2579 outcontent.add((datafile,datatype)) 2580 except: 2581 pass 2582 2583 outcontent = sorted(outcontent) 2584 for datafile, datatype in outcontent: 2585 pkg_content[datafile] = datatype 2586 2587 else: 2588 2589 # CONTENTS is not generated when a package is emerged with portage and the option -B 2590 # we have to unpack the tbz2 and generate content dict 2591 mytempdir = etpConst['packagestmpdir']+"/"+os.path.basename(package_path)+".inject" 2592 if os.path.isdir(mytempdir): 2593 shutil.rmtree(mytempdir) 2594 if not os.path.isdir(mytempdir): 2595 os.makedirs(mytempdir) 2596 2597 entropy.tools.uncompress_tar_bz2(package_path, extractPath = mytempdir, catchEmpty = True) 2598 tmpdir_len = len(mytempdir) 2599 for currentdir, subdirs, files in os.walk(mytempdir): 2600 pkg_content[currentdir[tmpdir_len:]] = u"dir" 2601 for item in files: 2602 item = currentdir+"/"+item 2603 if os.path.islink(item): 2604 pkg_content[item[tmpdir_len:]] = u"sym" 2605 else: 2606 pkg_content[item[tmpdir_len:]] = u"obj" 2607 2608 # now remove 2609 shutil.rmtree(mytempdir,True) 2610 try: 2611 os.rmdir(mytempdir) 2612 except (OSError,): 2613 pass 2614 2615 return pkg_content
2616
2617 - def _extract_pkg_metadata_needed(self, needed_file):
2618 2619 pkg_needed = set() 2620 lines = [] 2621 2622 try: 2623 f = open(needed_file,"r") 2624 lines = [x.decode('raw_unicode_escape').strip() for x in f.readlines() if x.strip()] 2625 f.close() 2626 except IOError: 2627 return lines 2628 2629 for line in lines: 2630 needed = line.split() 2631 if len(needed) == 2: 2632 ownlib = needed[0] 2633 ownelf = -1 2634 if os.access(ownlib,os.R_OK): 2635 ownelf = entropy.tools.read_elf_class(ownlib) 2636 for lib in needed[1].split(","): 2637 #if lib.find(".so") != -1: 2638 pkg_needed.add((lib,ownelf)) 2639 2640 return sorted(pkg_needed)
2641
2642 - def _extract_pkg_metadata_needed_paths(self, needed_libs):
2643 2644 data = {} 2645 ldpaths = entropy.tools.collect_linker_paths() 2646 2647 for needed_lib, elf_class in needed_libs: 2648 for ldpath in ldpaths: 2649 my_lib = os.path.join(ldpath, needed_lib) 2650 if not os.access(my_lib, os.R_OK): 2651 continue 2652 myclass = entropy.tools.read_elf_class(my_lib) 2653 if myclass != elf_class: 2654 continue 2655 obj = data.setdefault(needed_lib, set()) 2656 obj.add((my_lib, myclass,)) 2657 2658 return data
2659
2660 - def _extract_pkg_metadata_messages(self, log_dir, category, name, version):
2661 2662 pkg_messages = [] 2663 if not os.path.isdir(log_dir): 2664 return pkg_messages 2665 2666 elogfiles = os.listdir(log_dir) 2667 myelogfile = "%s:%s-%s" % (category, name, version,) 2668 foundfiles = [x for x in elogfiles if x.startswith(myelogfile)] 2669 if foundfiles: 2670 elogfile = foundfiles[0] 2671 if len(foundfiles) > 1: 2672 # get the latest 2673 mtimes = [] 2674 for item in foundfiles: mtimes.append((entropy.tools.get_file_unix_mtime(os.path.join(log_dir,item)),item)) 2675 mtimes = sorted(mtimes) 2676 elogfile = mtimes[-1][1] 2677 messages = entropy.tools.extract_elog(os.path.join(log_dir,elogfile)) 2678 for message in messages: 2679 message = message.replace("emerge","install") 2680 pkg_messages.append(message.decode('raw_unicode_escape')) 2681 2682 return pkg_messages
2683
2684 - def _extract_pkg_metadata_license_data(self, licenses_dir, license_string):
2685 2686 pkg_licensedata = {} 2687 if licenses_dir and os.path.isdir(licenses_dir): 2688 licdata = [x.strip() for x in license_string.split() if x.strip() and entropy.tools.is_valid_string(x.strip())] 2689 for mylicense in licdata: 2690 licfile = os.path.join(licenses_dir,mylicense) 2691 if os.access(licfile,os.R_OK): 2692 if entropy.tools.istextfile(licfile): 2693 f = open(licfile) 2694 content = '' 2695 line = f.readline() 2696 while line: 2697 content += line 2698 line = f.readline() 2699 try: 2700 try: 2701 pkg_licensedata[mylicense] = content.decode('raw_unicode_escape') 2702 except UnicodeDecodeError: 2703 pkg_licensedata[mylicense] = unicode(content,'utf-8') 2704 except (UnicodeDecodeError, UnicodeEncodeError,): 2705 continue # sorry! 2706 f.close() 2707 2708 return pkg_licensedata
2709 2723
2724 - def _extract_pkg_metadata_ebuild_entropy_tag(self, ebuild):
2725 search_tag = etpConst['spm']['ebuild_pkg_tag_var'] 2726 ebuild_tag = '' 2727 f = open(ebuild,"r") 2728 tags = [x.strip().decode('raw_unicode_escape') for x in f.readlines() if x.strip() and x.strip().startswith(search_tag)] 2729 f.close() 2730 if not tags: return ebuild_tag 2731 tag = tags[-1] 2732 tag = tag.split("=")[-1].strip('"').strip("'").strip() 2733 return tag
2734