Package entropy :: Module spm

Source Code for Module entropy.spm

   1  # -*- coding: utf-8 -*- 
   2  ''' 
   3      # DESCRIPTION: 
   4      # Entropy Object Oriented Interface 
   5   
   6      Copyright (C) 2007-2009 Fabio Erculiani 
   7   
   8      This program is free software; you can redistribute it and/or modify 
   9      it under the terms of the GNU General Public License as published by 
  10      the Free Software Foundation; either version 2 of the License, or 
  11      (at your option) any later version. 
  12   
  13      This program is distributed in the hope that it will be useful, 
  14      but WITHOUT ANY WARRANTY; without even the implied warranty of 
  15      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  16      GNU General Public License for more details. 
  17   
  18      You should have received a copy of the GNU General Public License 
  19      along with this program; if not, write to the Free Software 
  20      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  21  ''' 
  22  import os 
  23  import stat 
  24  import sys 
  25  import shutil 
  26  import tempfile 
  27  from entropy.const import etpConst, etpUi 
  28  from entropy.exceptions import * 
  29  from entropy.output import darkred, darkgreen, brown, darkblue, purple, red, \ 
  30      bold 
  31  from entropy.i18n import _ 
  32  from entropy.core import SystemSettings, Singleton 
33 34 -class Spm:
35
36 - def __init__(self, OutputInterface):
37 38 if not hasattr(OutputInterface,'updateProgress'): 39 mytxt = _("OutputInterface does not have an updateProgress method") 40 raise IncorrectParameter("IncorrectParameter: %s, (! %s !)" % (OutputInterface,mytxt,)) 41 elif not callable(OutputInterface.updateProgress): 42 mytxt = _("OutputInterface does not have an updateProgress method") 43 raise IncorrectParameter("IncorrectParameter: %s, (! %s !)" % (OutputInterface,mytxt,)) 44 45 self.spm_backend = etpConst['spm']['backend'] 46 self.valid_backends = etpConst['spm']['available_backends'] 47 if self.spm_backend not in self.valid_backends: 48 mytxt = "%s: %s" % (_("Invalid backend"),self.spm_backend,) 49 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,)) 50 51 if self.spm_backend == "portage": 52 self.intf = PortagePlugin(OutputInterface)
53 54 @staticmethod
55 - def get_spm_interface():
56 backend = etpConst['spm']['backend'] 57 if backend == "portage": 58 return PortagePlugin
59
60 -class SpmPlugin(Singleton):
61 """Base class for Source Package Manager plugins""" 62
63 - class paren_normalize(list):
64 """Take a dependency structure as returned by paren_reduce or use_reduce 65 and generate an equivalent structure that has no redundant lists."""
66 - def __init__(self, src):
67 list.__init__(self) 68 self._zap_parens(src, self)
69
70 - def _zap_parens(self, src, dest, disjunction=False):
71 if not src: 72 return dest 73 i = iter(src) 74 for x in i: 75 if isinstance(x, basestring): 76 if x == '||': 77 x = self._zap_parens(i.next(), [], disjunction=True) 78 if len(x) == 1: 79 dest.append(x[0]) 80 else: 81 dest.append("||") 82 dest.append(x) 83 elif x.endswith("?"): 84 dest.append(x) 85 dest.append(self._zap_parens(i.next(), [])) 86 else: 87 dest.append(x) 88 else: 89 if disjunction: 90 x = self._zap_parens(x, []) 91 if len(x) == 1: 92 dest.append(x[0]) 93 else: 94 dest.append(x) 95 else: 96 self._zap_parens(x, dest) 97 return dest
98
99 - def init_singleton(self, output_interface):
100 """ 101 Source Package Manager Plugin singleton method. 102 This method must be reimplemented by subclasses. 103 104 @param output_interface: Entropy output interface 105 @type output_interface: entropy.output.TextInterface based instances 106 @raise NotImplementedError: when method is not reimplemented 107 """ 108 raise NotImplementedError
109
110 -def get_spm(output_interface):
111 """ 112 Service function that returns an Entropy SPM interface instance. 113 114 @param output_interface: Entropy Output Interface instance 115 @type output_interface: entropy.output.TextInterface based instance 116 @return: currently selected SPM interface 117 @rtype: entropy.spm.SpmPlugin instance 118 """ 119 spmintf = Spm.get_spm_interface() 120 return spmintf(output_interface)
121
122 -class PortagePlugin(SpmPlugin):
123 124 import entropy.tools as entropyTools
125 - def init_singleton(self, OutputInterface):
126 127 if not hasattr(OutputInterface,'updateProgress'): 128 mytxt = _("OutputInterface does not have an updateProgress method") 129 raise IncorrectParameter("IncorrectParameter: %s, (! %s !)" % (OutputInterface,mytxt,)) 130 elif not callable(OutputInterface.updateProgress): 131 mytxt = _("OutputInterface does not have an updateProgress method") 132 raise IncorrectParameter("IncorrectParameter: %s, (! %s !)" % (OutputInterface,mytxt,)) 133 134 # interface only needed OutputInterface functions 135 self.updateProgress = OutputInterface.updateProgress 136 self.askQuestion = OutputInterface.askQuestion 137 sys.path.append("/usr/lib/gentoolkit/pym") 138 139 from entropy.misc import LogFile 140 self.LogFile = LogFile 141 142 # importing portage stuff 143 import portage 144 self.portage = portage 145 self.EAPI = 1 146 try: 147 import portage.const as portage_const 148 except ImportError: 149 import portage_const 150 if hasattr(portage_const,"EAPI"): 151 self.EAPI = portage_const.EAPI 152 self.portage_const = portage_const 153 154 from portage.versions import best 155 self.portage_best = best 156 157 try: 158 import portage.util as portage_util 159 except ImportError: 160 import portage_util 161 self.portage_util = portage_util 162 163 try: 164 import portage.sets as portage_sets 165 self.portage_sets = portage_sets 166 except ImportError: 167 self.portage_sets = None 168 169 try: 170 import glsa 171 self.glsa = glsa 172 except ImportError: 173 self.glsa = None 174 175 if hasattr(self.portage,'exception'): 176 self.portage_exception = self.portage.exception 177 else: # portage <2.2 workaround 178 self.portage_exception = Exception 179 180 self.builtin_pkg_sets = [ 181 "system","world","installed","module-rebuild", 182 "security","preserved-rebuild","live-rebuild", 183 "downgrade","unavailable" 184 ]
185
186 - def write_to_log(self, message):
187 spmLog = self.LogFile( 188 level = etpConst['spmloglevel'], 189 filename = etpConst['spmlogfile'], 190 header = "[spm]" 191 ) 192 spmLog.write(message) 193 spmLog.flush() 194 spmLog.close()
195
196 - def write_traceback_to_log(self):
197 spmLog = self.LogFile( 198 level = etpConst['spmloglevel'], 199 filename = etpConst['spmlogfile'], 200 header = "[spm]" 201 ) 202 self.entropyTools.print_traceback(f = spmLog) 203 spmLog.flush() 204 spmLog.close()
205
206 - def list_glsa_packages(self, command = "affected"):
207 208 if not self.glsa: return 209 if command not in ['new','all','affected']: return 210 211 glsaconfig = self.glsa.checkconfig(self.portage.config(clone=self.portage.settings)) 212 completelist = self.glsa.get_glsa_list(glsaconfig["GLSA_DIR"], glsaconfig) 213 214 glsalist = [] 215 if command == "new": 216 checklist = [] 217 if os.access(glsaconfig["CHECKFILE"], os.R_OK): 218 checklist = [line.strip() for line in open(glsaconfig["CHECKFILE"], "r").readlines()] 219 glsalist = [e for e in completelist if e not in checklist] 220 elif command == "all": 221 glsalist = completelist 222 elif command == "affected": 223 # maybe this should be todolist instead 224 for x in completelist: 225 try: 226 myglsa = self.glsa.Glsa(x, glsaconfig) 227 except (self.glsa.GlsaTypeException, self.glsa.GlsaFormatException), e: 228 continue 229 if not myglsa.isVulnerable(): 230 continue 231 glsalist.append(x) 232 233 return glsalist
234
235 - def get_glsa_id_information(self, glsa_id):
236 if not self.glsa: return {} 237 238 glsaconfig = self.glsa.checkconfig(self.portage.config(clone=self.portage.settings)) 239 try: 240 myglsa = self.glsa.Glsa(glsa_id, glsaconfig) 241 except (self.glsa.GlsaTypeException, self.glsa.GlsaFormatException): 242 return {} 243 244 mydict = { 245 'glsa_id': glsa_id, 246 'number': myglsa.nr, 247 'access': myglsa.access, 248 'title': myglsa.title, 249 'synopsis': myglsa.synopsis, 250 'announced': myglsa.announced, 251 'revised': myglsa.revised, 252 'bugs': myglsa.bugs, 253 'description': myglsa.description, 254 'resolution': myglsa.resolution, 255 'impact': myglsa.impact_text, 256 'impacttype': myglsa.impact_type, 257 'affected': myglsa.affected, 258 'background': myglsa.background, 259 'glsatype': myglsa.glsatype, 260 'packages': myglsa.packages, 261 'services': myglsa.services, 262 'product': myglsa.product, 263 'references': myglsa.references, 264 'workaround': myglsa.workaround, 265 } 266 if myglsa.isApplied(): 267 status = "[A]" 268 elif myglsa.isVulnerable(): 269 status = "[N]" 270 else: 271 status = "[U]" 272 mydict['status'] = status 273 274 return mydict.copy()
275
276 - def run_fixpackages(self, myroot = None):
277 if myroot == None: 278 myroot = etpConst['systemroot']+"/" 279 mydb = {} 280 mydb[myroot] = {} 281 mydb[myroot]['vartree'] = self._get_portage_vartree(myroot) 282 mydb[myroot]['porttree'] = self._get_portage_portagetree(myroot) 283 mydb[myroot]['bintree'] = self._get_portage_binarytree(myroot) 284 mydb[myroot]['virtuals'] = self.portage.settings.getvirtuals(myroot) 285 if etpUi['mute']: 286 pid = os.fork() 287 if pid > 0: 288 os.waitpid(pid, 0) 289 else: 290 f = open("/dev/null","w") 291 old_stdout = sys.stdout 292 old_stderr = sys.stderr 293 sys.stdout = f 294 sys.stderr = f 295 self.portage._global_updates(mydb, {}) 296 sys.stdout = old_stdout 297 sys.stderr = old_stderr 298 f.close() 299 os._exit(0) 300 else: 301 self.portage._global_updates(mydb, {}) # always force
302
303 - def get_world_file(self):
304 return os.path.join(etpConst['systemroot'],"/",self.portage_const.WORLD_FILE)
305
306 - def get_third_party_mirrors(self, mirrorname):
307 x = [] 308 if self.portage.thirdpartymirrors.has_key(mirrorname): 309 x = self.portage.thirdpartymirrors[mirrorname] 310 return x
311
312 - def get_spm_setting(self, var):
313 return self.portage.settings[var]
314
316 config_protect = self.portage.settings['CONFIG_PROTECT'] 317 config_protect = config_protect.split() 318 config_protect_mask = self.portage.settings['CONFIG_PROTECT_MASK'] 319 config_protect_mask = config_protect_mask.split() 320 # explode 321 protect = [] 322 for x in config_protect: 323 x = os.path.expandvars(x) 324 protect.append(x) 325 mask = [] 326 for x in config_protect_mask: 327 x = os.path.expandvars(x) 328 mask.append(x) 329 return ' '.join(protect),' '.join(mask)
330
331 - def _get_portage_vartree(self, root):
332 333 if not etpConst['spm']['cache'].has_key('portage'): 334 etpConst['spm']['cache']['portage'] = {} 335 if not etpConst['spm']['cache']['portage'].has_key('vartree'): 336 etpConst['spm']['cache']['portage']['vartree'] = {} 337 338 cached = etpConst['spm']['cache']['portage']['vartree'].get(root) 339 if cached != None: 340 return cached 341 342 try: 343 mytree = self.portage.vartree(root=root) 344 except Exception, e: 345 raise SPMError("SPMError: %s: %s" % (Exception,e,)) 346 etpConst['spm']['cache']['portage']['vartree'][root] = mytree 347 return mytree
348
349 - def _get_portage_portagetree(self, root):
350 351 if not etpConst['spm']['cache'].has_key('portage'): 352 etpConst['spm']['cache']['portage'] = {} 353 if not etpConst['spm']['cache']['portage'].has_key('portagetree'): 354 etpConst['spm']['cache']['portage']['portagetree'] = {} 355 356 cached = etpConst['spm']['cache']['portage']['portagetree'].get(root) 357 if cached != None: 358 return cached 359 360 try: 361 mytree = self.portage.portagetree(root=root) 362 except Exception, e: 363 raise SPMError("SPMError: %s: %s" % (Exception,e,)) 364 etpConst['spm']['cache']['portage']['portagetree'][root] = mytree 365 return mytree
366
367 - def _get_portage_binarytree(self, root):
368 369 if not etpConst['spm']['cache'].has_key('portage'): 370 etpConst['spm']['cache']['portage'] = {} 371 if not etpConst['spm']['cache']['portage'].has_key('binarytree'): 372 etpConst['spm']['cache']['portage']['binarytree'] = {} 373 374 cached = etpConst['spm']['cache']['portage']['binarytree'].get(root) 375 if cached != None: 376 return cached 377 378 pkgdir = root+self.portage.settings['PKGDIR'] 379 try: 380 mytree = self.portage.binarytree(root,pkgdir) 381 except Exception, e: 382 raise SPMError("SPMError: %s: %s" % (Exception,e,)) 383 etpConst['spm']['cache']['portage']['binarytree'][root] = mytree 384 return mytree
385
386 - def _get_portage_config(self, config_root, root, use_cache = True):
387 388 if use_cache: 389 if not etpConst['spm']['cache'].has_key('portage'): 390 etpConst['spm']['cache']['portage'] = {} 391 if not etpConst['spm']['cache']['portage'].has_key('config'): 392 etpConst['spm']['cache']['portage']['config'] = {} 393 394 cached = etpConst['spm']['cache']['portage']['config'].get((config_root,root)) 395 if cached != None: 396 return cached 397 398 try: 399 mysettings = self.portage.config(config_root = config_root, target_root = root, config_incrementals = self.portage_const.INCREMENTALS) 400 except Exception, e: 401 raise SPMError("SPMError: %s: %s" % (Exception,e,)) 402 if use_cache: 403 etpConst['spm']['cache']['portage']['config'][(config_root,root)] = mysettings 404 return mysettings
405 406 # resolve atoms automagically (best, not current!) 407 # sys-libs/application --> sys-libs/application-1.2.3-r1
408 - def get_best_atom(self, atom, match = "bestmatch-visible"):
409 try: 410 return self.portage.portdb.xmatch(match,str(atom)) 411 except ValueError: 412 return None
413 414 # same as above but includes masked ebuilds
415 - def get_best_masked_atom(self, atom):
416 atoms = self.portage.portdb.xmatch("match-all",str(atom)) 417 return self.portage_best(atoms)
418
419 - def get_category_description_data(self, category):
420 from xml.dom import minidom 421 data = {} 422 portdir = self.portage.settings['PORTDIR'] 423 myfile = os.path.join(portdir,category,"metadata.xml") 424 if os.access(myfile,os.R_OK) and os.path.isfile(myfile): 425 doc = minidom.parse(myfile) 426 longdescs = doc.getElementsByTagName("longdescription") 427 for longdesc in longdescs: 428 data[longdesc.getAttribute("lang").strip()] = ' '.join([x.strip() for x in longdesc.firstChild.data.strip().split("\n")]) 429 return data
430
431 - def get_atom_category(self, atom):
432 try: 433 return self.portage.portdb.xmatch("match-all",str(atom))[0].split("/")[0] 434 except: 435 return None
436 437 # Packages in system (in the Portage language -> emerge system, remember?)
438 - def get_atoms_in_system(self):
439 system = self.portage.settings.packages 440 sysoutput = [] 441 for x in system: 442 y = self.get_installed_atoms(x) 443 if (y != None): 444 for z in y: 445 sysoutput.append(z) 446 sysoutput.extend(etpConst['spm']['system_packages']) # add our packages 447 return sysoutput
448
449 - def get_installed_atom(self, atom):
450 mypath = etpConst['systemroot']+"/" 451 mytree = self._get_portage_vartree(mypath) 452 rc = mytree.dep_match(str(atom)) 453 if rc: return rc[-1]
454
455 - def get_package_description(self, atom):
456 if atom.startswith("="): atom = atom[1:] 457 return self.portage.portdb.aux_get(atom,['DESCRIPTION'])[0]
458
459 - def get_package_ebuild_path(self, atom):
460 if atom.startswith("="): atom = atom[1:] 461 return self.portage.portdb.findname(atom)
462
463 - def get_package_changelog(self, atom):
464 if atom.startswith("="): atom = atom[1:] 465 ebuild_path = self.get_package_ebuild_path(atom) 466 if isinstance(ebuild_path,basestring): 467 cp = os.path.join(os.path.dirname(ebuild_path),"ChangeLog") 468 if os.path.isfile(cp) and os.access(cp,os.R_OK): 469 f = open(cp,"r") 470 txt = f.read() 471 f.close() 472 return txt
473
474 - def get_installed_package_description(self, atom):
475 mypath = etpConst['systemroot']+"/" 476 mytree = self._get_portage_vartree(mypath) 477 if atom.startswith("="): atom = atom[1:] 478 rc = mytree.dbapi.aux_get(atom, ["DESCRIPTION"])[0] 479 if rc: return rc
480
481 - def get_package_slot(self, atom):
482 if atom.startswith("="): atom = atom[1:] 483 return self.portage.portdb.aux_get(atom,['SLOT'])[0]
484
485 - def get_installed_package_slot(self, atom):
486 mypath = etpConst['systemroot']+"/" 487 mytree = self._get_portage_vartree(mypath) 488 if atom.startswith("="): atom = atom[1:] 489 rc = mytree.getslot(atom) 490 if rc: return rc
491
492 - def get_installed_atoms(self, atom):
493 mypath = etpConst['systemroot']+"/" 494 mytree = self._get_portage_vartree(mypath) 495 rc = mytree.dep_match(str(atom)) 496 if rc: return rc
497
498 - def search_keys(self, key):
499 key_split = key.split("/") 500 cat = key_split[0] 501 name = key_split[1] 502 cat_dir = os.path.join(self.get_vdb_path(),cat) 503 if not os.path.isdir(cat_dir): 504 return [] 505 return [os.path.join(cat,x) for x in os.listdir(cat_dir) if \ 506 x.startswith(name)]
507 508 # create a .tbz2 file in the specified path
509 - def quickpkg(self, atom, dirpath):
510 511 # getting package info 512 pkgname = atom.split("/")[1] 513 pkgcat = atom.split("/")[0] 514 #pkgfile = pkgname+".tbz2" 515 if not os.path.isdir(dirpath): 516 os.makedirs(dirpath) 517 dirpath += "/"+pkgname+etpConst['packagesext'] 518 dbdir = self.get_vdb_path()+"/"+pkgcat+"/"+pkgname+"/" 519 520 import tarfile 521 import stat 522 trees = self.portage.db["/"] 523 vartree = trees["vartree"] 524 dblnk = self.portage.dblink(pkgcat, pkgname, "/", vartree.settings, treetype="vartree", vartree=vartree) 525 dblnk.lockdb() 526 tar = tarfile.open(dirpath,"w:bz2") 527 528 contents = dblnk.getcontents() 529 paths = sorted(contents.keys()) 530 531 for path in paths: 532 try: 533 exist = os.lstat(path) 534 except OSError: 535 continue # skip file 536 ftype = contents[path][0] 537 lpath = path 538 arcname = path[1:] 539 if 'dir' == ftype and \ 540 not stat.S_ISDIR(exist.st_mode) and \ 541 os.path.isdir(lpath): 542 lpath = os.path.realpath(lpath) 543 tarinfo = tar.gettarinfo(lpath, arcname) 544 545 if stat.S_ISREG(exist.st_mode): 546 tarinfo.mode = stat.S_IMODE(exist.st_mode) 547 tarinfo.type = tarfile.REGTYPE 548 f = open(path) 549 try: 550 tar.addfile(tarinfo, f) 551 finally: 552 f.close() 553 else: 554 tar.addfile(tarinfo) 555 556 tar.close() 557 558 # appending xpak informations 559 import entropy.xpak as xpak 560 tbz2 = xpak.tbz2(dirpath) 561 tbz2.recompose(dbdir) 562 563 dblnk.unlockdb() 564 565 if os.path.isfile(dirpath): 566 return dirpath 567 else: 568 raise FileNotFound("FileNotFound: Spm:quickpkg %s: %s %s" % ( 569 _("error"), 570 dirpath, 571 _("not found"), 572 ) 573 )
574
575 - def get_package_use_file(self):
576 return os.path.join(self.portage_const.USER_CONFIG_PATH,'package.use')
577
578 - def enable_package_useflags(self, atom, useflags):
579 result = self.unset_package_useflags(atom, useflags) 580 if not result: return False 581 return self._handle_new_useflags(atom, useflags, "")
582
583 - def disable_package_useflags(self, atom, useflags):
584 result = self.unset_package_useflags(atom, useflags) 585 if not result: return False 586 return self._handle_new_useflags(atom, useflags, "-")
587
588 - def _handle_new_useflags(self, atom, useflags, mark):
589 matched_atom = self.get_best_atom(atom) 590 if not matched_atom: 591 return False 592 use_file = self.get_package_use_file() 593 594 if not (os.path.isfile(use_file) and os.access(use_file,os.W_OK)): 595 return False 596 f = open(use_file,"r") 597 content = [x.strip() for x in f.readlines()] 598 f.close() 599 600 def handle_line(line, useflags): 601 602 data = line.split() 603 if len(data) < 2: 604 return False, line 605 606 myatom = data[0] 607 if matched_atom != self.get_best_atom(myatom): 608 return False, line 609 610 flags = data[1:] 611 base_flags = [] 612 added_flags = [] 613 for flag in flags: 614 myflag = flag 615 if myflag.startswith("+"): 616 myflag = myflag[1:] 617 elif myflag.startswith("-"): 618 myflag = myflag[1:] 619 if not myflag: 620 continue 621 base_flags.append(myflag) 622 623 for useflag in useflags: 624 if mark+useflag in base_flags: 625 continue 626 added_flags.append(mark+useflag) 627 628 new_line = "%s %s" % (myatom, ' '.join(flags+added_flags)) 629 return True, new_line
630 631 632 atom_found = False 633 new_content = [] 634 for line in content: 635 636 changed, elaborated_line = handle_line(line, useflags) 637 if changed: atom_found = True 638 new_content.append(elaborated_line) 639 640 if not atom_found: 641 myline = "%s %s" % (atom, ' '.join([mark+x for x in useflags])) 642 new_content.append(myline) 643 644 645 f = open(use_file+".tmp","w") 646 for line in new_content: 647 f.write(line+"\n") 648 f.flush() 649 f.close() 650 os.rename(use_file+".tmp", use_file) 651 return True
652
653 - def unset_package_useflags(self, atom, useflags):
654 matched_atom = self.get_best_atom(atom) 655 if not matched_atom: 656 return False 657 658 use_file = self.get_package_use_file() 659 if not (os.path.isfile(use_file) and os.access(use_file,os.W_OK)): 660 return False 661 662 f = open(use_file,"r") 663 content = [x.strip() for x in f.readlines()] 664 f.close() 665 666 new_content = [] 667 for line in content: 668 669 data = line.split() 670 if len(data) < 2: 671 new_content.append(line) 672 continue 673 674 myatom = data[0] 675 if matched_atom != self.get_best_atom(myatom): 676 new_content.append(line) 677 continue 678 679 flags = data[1:] 680 new_flags = [] 681 for flag in flags: 682 myflag = flag 683 684 if myflag.startswith("+"): 685 myflag = myflag[1:] 686 elif myflag.startswith("-"): 687 myflag = myflag[1:] 688 689 if myflag in useflags: 690 continue 691 elif not flag: 692 continue 693 694 new_flags.append(flag) 695 696 if new_flags: 697 new_line = "%s %s" % (myatom, ' '.join(new_flags)) 698 new_content.append(new_line) 699 700 f = open(use_file+".tmp","w") 701 for line in new_content: 702 f.write(line+"\n") 703 f.flush() 704 f.close() 705 os.rename(use_file+".tmp", use_file) 706 return True
707
708 - def get_package_useflags(self, atom):
709 matched_atom = self.get_best_atom(atom) 710 if not matched_atom: 711 return {} 712 global_useflags = self.get_useflags() 713 use_force = self.get_useflags_force() 714 use_mask = self.get_useflags_mask() 715 package_use_useflags = self.get_package_use_useflags(atom) 716 717 data = {} 718 data['use_force'] = use_force.copy() 719 data['use_mask'] = use_mask.copy() 720 data['global_use'] = global_useflags.split() 721 722 iuse = self.get_package_setting(atom, "IUSE") 723 if not isinstance(iuse, basestring): 724 iuse = '' 725 data['iuse'] = iuse.split()[:] 726 iuse = set() 727 for myiuse in data['iuse']: 728 if myiuse.startswith("+"): 729 myiuse = myiuse[1:] 730 iuse.add(myiuse) 731 732 use = [f for f in data['global_use']+list(package_use_useflags['enabled']) if (f in iuse) and (f not in use_mask) and (f not in package_use_useflags['disabled'])] 733 use_disabled = [f for f in iuse if (f not in data['global_use']) and (f not in use_mask) and (f not in package_use_useflags['enabled'])] 734 data['use'] = use[:] 735 data['use_disabled'] = use_disabled[:] 736 737 matched_slot = self.get_package_slot(matched_atom) 738 try: 739 installed_atom = self.get_installed_atom("%s:%s" % (self.entropyTools.dep_getkey(atom),matched_slot,)) 740 except self.portage_exception: 741 installed_atom = None 742 743 if installed_atom: 744 745 # get its useflags 746 previous_iuse = self.get_installed_package_setting(installed_atom, "IUSE").split() 747 previous_use = self.get_installed_package_setting(installed_atom, "USE").split() 748 749 new_previous_iuse = set() 750 for myuse in previous_iuse: 751 if myuse.startswith("+"): 752 myuse = myuse[1:] 753 new_previous_iuse.add(myuse) 754 previous_iuse = list(new_previous_iuse) 755 756 inst_use = [f for f in previous_iuse if (f in previous_use) and (f not in use_mask)] 757 #inst_use_disabled = [f for f in previous_use if (f not in previous_iuse) and (f not in use_mask)] 758 759 # check removed use 760 use_removed = [] 761 for myuse in inst_use: 762 if myuse not in use: 763 use_removed.append(myuse) 764 765 # use not available 766 use_not_avail = [] 767 for myuse in previous_iuse: 768 if (myuse not in iuse) and (myuse not in use_removed): 769 use_not_avail.append(myuse) 770 771 # check new use 772 t_use = [] 773 for myuse in use: 774 if myuse not in inst_use: 775 myuse = "+%s*" % (myuse,) 776 t_use.append(myuse) 777 use = t_use 778 779 # check disabled use 780 t_use_disabled = [] 781 for myuse in use_disabled: 782 if myuse in inst_use: 783 if myuse in use_removed+use_not_avail: 784 continue 785 myuse = "-%s*" % (myuse,) 786 else: 787 myuse = "-%s" % (myuse,) 788 t_use_disabled.append(myuse) 789 use_disabled = t_use_disabled 790 791 for myuse in use_removed: 792 use_disabled.append("(-%s*)" % (myuse,)) 793 for myuse in use_not_avail: 794 use_disabled.append("(-%s)" % (myuse,)) 795 else: 796 use_disabled = ["-"+x for x in use_disabled] 797 798 data['use_string'] = ' '.join(sorted(use)+sorted([x for x in use_disabled])) 799 data['use_string_colored'] = ' '.join( 800 sorted([darkred(x) for x in use if not x.startswith("+")] + \ 801 [darkgreen(x) for x in use if x.startswith("+")]) + \ 802 sorted([darkblue(x) for x in use_disabled if x.startswith("-")] + \ 803 [brown(x) for x in use_disabled if x.startswith("(") and (x.find("*") == -1)] + \ 804 [purple(x) for x in use_disabled if x.startswith("(") and (x.find("*") != -1)] 805 ) 806 ) 807 return data
808
809 - def get_installed_package_useflags(self, atom):
810 811 matched_atom = self.get_installed_atom(atom) 812 if not matched_atom: 813 return {} 814 815 global_use = self.get_installed_package_setting(matched_atom, "USE") 816 use_mask = self.get_useflags_mask() 817 818 data = {} 819 data['use_mask'] = use_mask.copy() 820 data['global_use'] = global_use.split() 821 822 iuse = self.get_installed_package_setting(matched_atom, "IUSE") 823 if not isinstance(iuse,basestring): iuse = '' 824 data['iuse'] = iuse.split()[:] 825 iuse = set() 826 for myiuse in data['iuse']: 827 if myiuse.startswith("+"): 828 myiuse = myiuse[1:] 829 iuse.add(myiuse) 830 831 use = [f for f in data['global_use'] if (f in iuse) and (f not in use_mask)] 832 use_disabled = [f for f in iuse if (f not in data['global_use']) and (f not in use_mask)] 833 data['use'] = use[:] 834 data['use_disabled'] = use_disabled[:] 835 836 data['use_string'] = ' '.join(sorted(use)+sorted([x for x in use_disabled])) 837 data['use_string_colored'] = ' '.join( 838 sorted([darkred(x) for x in use if not x.startswith("+")] + \ 839 [darkgreen(x) for x in use if x.startswith("+")]) + \ 840 sorted([darkblue(x) for x in use_disabled if x.startswith("-")] + \ 841 [brown(x) for x in use_disabled if x.startswith("(") and (x.find("*") == -1)] + \ 842 [purple(x) for x in use_disabled if x.startswith("(") and (x.find("*") != -1)] 843 ) 844 ) 845 return data
846 847 # package.use
848 - def get_package_use_useflags(self, atom):
849 850 data = { 851 'enabled': set(), 852 'disabled': set(), 853 } 854 855 matched_atom = self.get_best_atom(atom) 856 if not matched_atom: 857 return data 858 859 use_file = self.get_package_use_file() 860 if not (os.path.isfile(use_file) and os.access(use_file,os.W_OK)): 861 return data 862 863 use_data = self.portage_util.grabdict(use_file) 864 for myatom in use_data: 865 mymatch = self.get_best_atom(myatom) 866 if mymatch != matched_atom: 867 continue 868 for flag in use_data[myatom]: 869 if flag.startswith("-"): 870 myflag = flag[1:] 871 data['enabled'].discard(myflag) 872 data['disabled'].add(myflag) 873 else: 874 myflag = flag 875 if myflag.startswith("+"): 876 myflag = myflag[1:] 877 data['disabled'].discard(myflag) 878 data['enabled'].add(myflag) 879 880 return data
881
882 - def get_useflags(self):
883 return self.portage.settings['USE']
884
885 - def get_useflags_force(self):
886 return self.portage.settings.useforce
887
888 - def get_useflags_mask(self):
889 return self.portage.settings.usemask
890
891 - def get_installed_package_setting(self, atom, setting):
892 mypath = etpConst['systemroot']+"/" 893 mytree = self._get_portage_vartree(mypath) 894 if atom.startswith("="): atom = atom[1:] 895 return mytree.dbapi.aux_get(atom, [setting])[0]
896
897 - def get_package_setting(self, atom, setting):
898 if atom.startswith("="): atom = atom[1:] 899 return self.portage.portdb.aux_get(atom,[setting])[0]
900
901 - def query_files(self, atom):
902 mypath = etpConst['systemroot']+"/" 903 mysplit = atom.split("/") 904 content = self.portage.dblink(mysplit[0], mysplit[1], mypath, self.portage.settings).getcontents() 905 return content.keys()
906
907 - def query_belongs(self, filename, like = False):
908 mypath = etpConst['systemroot']+"/" 909 mytree = self._get_portage_vartree(mypath) 910 packages = mytree.dbapi.cpv_all() 911 matches = set() 912 for package in packages: 913 mysplit = package.split("/") 914 content = self.portage.dblink(mysplit[0], mysplit[1], mypath, self.portage.settings).getcontents() 915 if not like: 916 if filename in content: 917 matches.add(package) 918 else: 919 for myfile in content: 920 if myfile.find(filename) != -1: 921 matches.add(package) 922 return matches
923
924 - def query_belongs_multiple(self, filenames, like = False):
925 mypath = etpConst['systemroot']+"/" 926 mytree = self._get_portage_vartree(mypath) 927 packages = mytree.dbapi.cpv_all() 928 matches = {} 929 filenames = filenames.copy() 930 for package in packages: 931 cat, pkgv = package.split("/") 932 content = self.portage.dblink(cat, pkgv, mypath, self.portage.settings).getcontents() 933 if not like: 934 for filename in filenames: 935 if filename in content: 936 myslot = self.get_installed_package_slot(package) 937 if not matches.has_key((package,myslot)): 938 matches[(package,myslot)] = set() 939 matches[(package,myslot)].add(filename) 940 else: 941 for filename in filenames: 942 for myfile in content: 943 if myfile.find(filename) != -1: 944 myslot = self.get_installed_package_slot(package) 945 if not matches.has_key((package,myslot)): 946 matches[(package,myslot)] = set() 947 matches[(package,myslot)].add(filename) 948 return matches
949
950 - def _resolve_enabled_useflags(self, iuse_list, use_list):
951 use = set() 952 use_mask = self.get_useflags_mask() 953 use_force = self.get_useflags_force() 954 for myiuse in iuse_list: 955 if myiuse[0] in ("+", "-",): 956 myiuse = myiuse[1:] 957 if ((myiuse in use_list) or (myiuse in use_force)) and \ 958 (myiuse not in use_mask): 959 use.add(myiuse) 960 return use
961
962 - def calculate_dependencies(self, my_iuse, my_use, my_license, my_depend, my_rdepend, my_pdepend, my_provide, my_src_uri):
963 964 metadata = { 965 'LICENSE': my_license, 966 'DEPEND': my_depend, 967 'PDEPEND': my_pdepend, 968 'RDEPEND': my_rdepend, 969 'PROVIDE': my_provide, 970 'SRC_URI': my_src_uri, 971 'USE_MASK': sorted(self.get_useflags_mask()), 972 'USE_FORCE': sorted(self.get_useflags_force()), 973 } 974 975 # generate USE flags metadata 976 raw_use = my_use.split() 977 enabled_use = sorted(self._resolve_enabled_useflags( 978 my_iuse.split(), raw_use)) 979 980 metadata['ENABLED_USE'] = enabled_use 981 use = raw_use + [x for x in metadata['USE_FORCE'] if x not in raw_use] 982 metadata['USE'] = sorted([unicode(x) for x in use if x not in \ 983 metadata['USE_MASK']]) 984 985 for k in "LICENSE", "RDEPEND", "DEPEND", "PDEPEND", "PROVIDE", "SRC_URI": 986 try: 987 if k == "SRC_URI": 988 deps = self.src_uri_paren_reduce(metadata[k]) 989 else: 990 deps = self.paren_reduce(metadata[k]) 991 deps = self.use_reduce(deps, uselist = raw_use) 992 deps = self.paren_normalize(deps) 993 if k == "LICENSE": 994 deps = self.paren_license_choose(deps) 995 else: 996 deps = self.paren_choose(deps) 997 if k.endswith("DEPEND"): 998 deps = self.usedeps_reduce(deps, enabled_use) 999 deps = ' '.join(deps) 1000 except Exception, e: 1001 self.entropyTools.print_traceback() 1002 self.updateProgress( 1003 darkred("%s: %s: %s :: %s") % ( 1004 _("Error calculating dependencies"), 1005 str(Exception), 1006 k, 1007 e, 1008 ), 1009 importance = 1, 1010 type = "error", 1011 header = red(" !!! ") 1012 ) 1013 deps = '' 1014 continue 1015 metadata[k] = deps 1016 return metadata
1017
1018 - def src_uri_paren_reduce(self, src_uris):
1019 src_uris = self.paren_reduce(src_uris) 1020 newlist = [] 1021 skip_next = False 1022 for src_uri in src_uris: 1023 if skip_next: 1024 skip_next = False 1025 continue 1026 if src_uri == "->": 1027 skip_next = True 1028 continue 1029 newlist.append(src_uri) 1030 return newlist
1031
1032 - def usedeps_reduce(self, dependencies, enabled_useflags):
1033 newlist = [] 1034 1035 def strip_use(xuse): 1036 myuse = xuse[:] 1037 if myuse[0] == "!": 1038 myuse = myuse[1:] 1039 if myuse[-1] in ("=","?",): 1040 myuse = myuse[:-1] 1041 return myuse
1042 1043 for dependency in dependencies: 1044 use_deps = self.entropyTools.dep_getusedeps(dependency) 1045 if use_deps: 1046 new_use_deps = [] 1047 for use in use_deps: 1048 """ 1049 explicitly support only specific types 1050 """ 1051 if (use[0] == "!") and (use[-1] not in ("=","?",)): 1052 # this does not exist atm 1053 continue 1054 elif use[-1] == "=": 1055 if use[0] == "!": 1056 # foo[!bar=] means bar? ( foo[-bar] ) !bar? ( foo[bar] ) 1057 s_use = strip_use(use) 1058 if s_use in enabled_useflags: 1059 new_use_deps.append("-%s" % (s_use,)) 1060 else: 1061 new_use_deps.append(s_use) 1062 continue 1063 else: 1064 # foo[bar=] means bar? ( foo[bar] ) !bar? ( foo[-bar] ) 1065 s_use = strip_use(use) 1066 if s_use in enabled_useflags: 1067 new_use_deps.append(s_use) 1068 else: 1069 new_use_deps.append("-%s" % (s_use,)) 1070 continue 1071 elif use[-1] == "?": 1072 if use[0] == "!": 1073 # foo[!bar?] means bar? ( foo ) !bar? ( foo[-bar] ) 1074 s_use = strip_use(use) 1075 if s_use not in enabled_useflags: 1076 new_use_deps.append("-%s" % (s_use,)) 1077 continue 1078 else: 1079 # foo[bar?] means bar? ( foo[bar] ) !bar? ( foo ) 1080 s_use = strip_use(use) 1081 if s_use in enabled_useflags: 1082 new_use_deps.append(s_use) 1083 continue 1084 new_use_deps.append(use) 1085 1086 if new_use_deps: 1087 dependency = "%s[%s]" % ( 1088 self.entropyTools.remove_usedeps(dependency), 1089 ','.join(new_use_deps), 1090 ) 1091 else: 1092 dependency = self.entropyTools.remove_usedeps(dependency) 1093 1094 newlist.append(dependency) 1095 return newlist 1096
1097 - def paren_reduce(self, mystr):
1098 """ 1099 1100 # deps.py -- Portage dependency resolution functions 1101 # Copyright 2003-2004 Gentoo Foundation 1102 # Distributed under the terms of the GNU General Public License v2 1103 # $Id: portage_dep.py 9174 2008-01-11 05:49:02Z zmedico $ 1104 1105 Take a string and convert all paren enclosed entities into sublists, optionally 1106 futher splitting the list elements by spaces. 1107 1108 Example usage: 1109 >>> paren_reduce('foobar foo ( bar baz )',1) 1110 ['foobar', 'foo', ['bar', 'baz']] 1111 >>> paren_reduce('foobar foo ( bar baz )',0) 1112 ['foobar foo ', [' bar baz ']] 1113 1114 @param mystr: The string to reduce 1115 @type mystr: String 1116 @rtype: Array 1117 @return: The reduced string in an array 1118 """ 1119 mylist = [] 1120 while mystr: 1121 left_paren = mystr.find("(") 1122 has_left_paren = left_paren != -1 1123 right_paren = mystr.find(")") 1124 has_right_paren = right_paren != -1 1125 if not has_left_paren and not has_right_paren: 1126 freesec = mystr 1127 subsec = None 1128 tail = "" 1129 elif mystr[0] == ")": 1130 return [mylist,mystr[1:]] 1131 elif has_left_paren and not has_right_paren: 1132 raise InvalidDependString( 1133 "InvalidDependString: %s: '%s'" % (_("missing right parenthesis"),mystr,)) 1134 elif has_left_paren and left_paren < right_paren: 1135 freesec,subsec = mystr.split("(",1) 1136 subsec,tail = self.paren_reduce(subsec) 1137 else: 1138 subsec,tail = mystr.split(")",1) 1139 subsec = self.strip_empty(subsec.split(" ")) 1140 return [mylist+subsec,tail] 1141 mystr = tail 1142 if freesec: 1143 mylist = mylist + self.strip_empty(freesec.split(" ")) 1144 if subsec is not None: 1145 mylist = mylist + [subsec] 1146 return mylist
1147
1148 - def strip_empty(self, myarr):
1149 """ 1150 1151 # deps.py -- Portage dependency resolution functions 1152 # Copyright 2003-2004 Gentoo Foundation 1153 # Distributed under the terms of the GNU General Public License v2 1154 # $Id: portage_dep.py 9174 2008-01-11 05:49:02Z zmedico $ 1155 1156 Strip all empty elements from an array 1157 1158 @param myarr: The list of elements 1159 @type myarr: List 1160 @rtype: Array 1161 @return: The array with empty elements removed 1162 """ 1163 for x in range(len(myarr)-1, -1, -1): 1164 if not myarr[x]: 1165 del myarr[x] 1166 return myarr
1167
1168 - def use_reduce(self, deparray, uselist=[], masklist=[], matchall=0, excludeall=[]):
1169 """ 1170 1171 # deps.py -- Portage dependency resolution functions 1172 # Copyright 2003-2004 Gentoo Foundation 1173 # Distributed under the terms of the GNU General Public License v2 1174 # $Id: portage_dep.py 9174 2008-01-11 05:49:02Z zmedico $ 1175 1176 Takes a paren_reduce'd array and reduces the use? conditionals out 1177 leaving an array with subarrays 1178 1179 @param deparray: paren_reduce'd list of deps 1180 @type deparray: List 1181 @param uselist: List of use flags 1182 @type uselist: List 1183 @param masklist: List of masked flags 1184 @type masklist: List 1185 @param matchall: Resolve all conditional deps unconditionally. Used by repoman 1186 @type matchall: Integer 1187 @rtype: List 1188 @return: The use reduced depend array 1189 """ 1190 # Quick validity checks 1191 for x in range(len(deparray)): 1192 if deparray[x] in ["||","&&"]: 1193 if len(deparray) - 1 == x or not isinstance(deparray[x+1], list): 1194 mytxt = _("missing atom list in") 1195 raise InvalidDependString(deparray[x]+" "+mytxt+" \""+str(deparray)+"\"") 1196 if deparray and deparray[-1] and deparray[-1][-1] == "?": 1197 mytxt = _("Conditional without target in") 1198 raise InvalidDependString("InvalidDependString: "+mytxt+" \""+str(deparray)+"\"") 1199 1200 # This is just for use by emerge so that it can enable a backward compatibility 1201 # mode in order to gracefully deal with installed packages that have invalid 1202 # atoms or dep syntax. For backward compatibility with api consumers, strict 1203 # behavior will be explicitly enabled as necessary. 1204 _dep_check_strict = False 1205 1206 mydeparray = deparray[:] 1207 rlist = [] 1208 while mydeparray: 1209 head = mydeparray.pop(0) 1210 1211 if isinstance(head,list): 1212 additions = self.use_reduce(head, uselist, masklist, matchall, excludeall) 1213 if additions: 1214 rlist.append(additions) 1215 elif rlist and rlist[-1] == "||": 1216 #XXX: Currently some DEPEND strings have || lists without default atoms. 1217 # raise portage_exception.InvalidDependString("No default atom(s) in \""+paren_enclose(deparray)+"\"") 1218 rlist.append([]) 1219 else: 1220 if head[-1] == "?": # Use reduce next group on fail. 1221 # Pull any other use conditions and the following atom or list into a separate array 1222 newdeparray = [head] 1223 while isinstance(newdeparray[-1], basestring) and newdeparray[-1][-1] == "?": 1224 if mydeparray: 1225 newdeparray.append(mydeparray.pop(0)) 1226 else: 1227 raise ValueError, _("Conditional with no target") 1228 1229 # Deprecation checks 1230 warned = 0 1231 if len(newdeparray[-1]) == 0: 1232 mytxt = "%s. (%s)" % (_("Empty target in string"),_("Deprecated"),) 1233 self.updateProgress( 1234 darkred("PortagePlugin.use_reduce(): %s" % (mytxt,)), 1235 importance = 0, 1236 type = "error", 1237 header = bold(" !!! ") 1238 ) 1239 warned = 1 1240 if len(newdeparray) != 2: 1241 mytxt = "%s. (%s)" % (_("Nested use flags without parenthesis"),_("Deprecated"),) 1242 self.updateProgress( 1243 darkred("PortagePlugin.use_reduce(): %s" % (mytxt,)), 1244 importance = 0, 1245 type = "error", 1246 header = bold(" !!! ") 1247 ) 1248 warned = 1 1249 if warned: 1250 self.updateProgress( 1251 darkred("PortagePlugin.use_reduce(): "+" ".join(map(str,[head]+newdeparray))), 1252 importance = 0, 1253 type = "error", 1254 header = bold(" !!! ") 1255 ) 1256 1257 # Check that each flag matches 1258 ismatch = True 1259 missing_flag = False 1260 for head in newdeparray[:-1]: 1261 head = head[:-1] 1262 if not head: 1263 missing_flag = True 1264 break 1265 if head.startswith("!"): 1266 head_key = head[1:] 1267 if not head_key: 1268 missing_flag = True 1269 break 1270 if not matchall and head_key in uselist or \ 1271 head_key in excludeall: 1272 ismatch = False 1273 break 1274 elif head not in masklist: 1275 if not matchall and head not in uselist: 1276 ismatch = False 1277 break 1278 else: 1279 ismatch = False 1280 if missing_flag: 1281 mytxt = _("Conditional without flag") 1282 raise InvalidDependString( 1283 "InvalidDependString: "+mytxt+": \"" + \ 1284 str([head+"?", newdeparray[-1]])+"\"") 1285 1286 # If they all match, process the target 1287 if ismatch: 1288 target = newdeparray[-1] 1289 if isinstance(target, list): 1290 additions = self.use_reduce(target, uselist, masklist, matchall, excludeall) 1291 if additions: 1292 rlist.append(additions) 1293 elif not _dep_check_strict: 1294 # The old deprecated behavior. 1295 rlist.append(target) 1296 else: 1297 mytxt = _("Conditional without parenthesis") 1298 raise InvalidDependString( 1299 "InvalidDependString: "+mytxt+": '%s?'" % head) 1300 1301 else: 1302 rlist += [head] 1303 return rlist
1304
1305 - def paren_choose(self, dep_list):
1306 newlist = [] 1307 do_skip = False 1308 for idx in range(len(dep_list)): 1309 1310 if do_skip: 1311 do_skip = False 1312 continue 1313 1314 item = dep_list[idx] 1315 if item == "||": # or 1316 next_item = dep_list[idx+1] 1317 if not next_item: # || ( asd? ( atom ) dsa? ( atom ) ) => [] if use asd and dsa are disabled 1318 do_skip = True 1319 continue 1320 item = self.dep_or_select(next_item) # must be a list 1321 if not item: 1322 # no matches, transform to string and append, so reagent will fail 1323 newlist.append(str(next_item)) 1324 else: 1325 newlist += item 1326 do_skip = True 1327 elif isinstance(item, list): # and 1328 item = self.dep_and_select(item) 1329 newlist += item 1330 else: 1331 newlist.append(item) 1332 1333 return newlist
1334
1335 - def dep_and_select(self, and_list):
1336 do_skip = False 1337 newlist = [] 1338 for idx in range(len(and_list)): 1339 1340 if do_skip: 1341 do_skip = False 1342 continue 1343 1344 x = and_list[idx] 1345 if x == "||": 1346 x = self.dep_or_select(and_list[idx+1]) 1347 do_skip = True 1348 if not x: 1349 x = str(and_list[idx+1]) 1350 else: 1351 newlist += x 1352 elif isinstance(x, list): 1353 x = self.dep_and_select(x) 1354 newlist += x 1355 else: 1356 newlist.append(x) 1357 1358 # now verify if all are satisfied 1359 for x in newlist: 1360 match = self.get_installed_atom(x) 1361 if match == None: 1362 return [] 1363 1364 return newlist
1365
1366 - def dep_or_select(self, or_list):
1367 do_skip = False 1368 for idx in range(len(or_list)): 1369 if do_skip: 1370 do_skip = False 1371 continue 1372 x = or_list[idx] 1373 if x == "||": # or 1374 x = self.dep_or_select(or_list[idx+1]) 1375 do_skip = True 1376 elif isinstance(x, list): # and 1377 x = self.dep_and_select(x) 1378 if not x: 1379 continue 1380 # found 1381 return x 1382 else: 1383 x = [x] 1384 1385 for y in x: 1386 match = self.get_installed_atom(y) 1387 if match != None: 1388 return [y] 1389 1390 return []
1391
1392 - def paren_license_choose(self, dep_list):
1393 1394 newlist = set() 1395 for item in dep_list: 1396 1397 if isinstance(item, list): 1398 # match the first 1399 data = set(self.paren_license_choose(item)) 1400 newlist.update(data) 1401 else: 1402 if item not in ["||"]: 1403 newlist.add(item) 1404 1405 return list(newlist)
1406
1407 - def get_vdb_path(self):
1408 rc = etpConst['systemroot']+"/"+self.portage_const.VDB_PATH 1409 if (not rc.endswith("/")): 1410 return rc+"/" 1411 return rc
1412
1413 - def get_available_packages(self, categories = [], filter_reinstalls = True):
1414 mypath = etpConst['systemroot']+"/" 1415 mysettings = self._get_portage_config("/",mypath) 1416 portdb = self.portage.portdbapi(mysettings["PORTDIR"], mysettings = mysettings) 1417 cps = portdb.cp_all() 1418 visibles = set() 1419 for cp in cps: 1420 if categories and cp.split("/")[0] not in categories: 1421 continue 1422 # get slots 1423 slots = set() 1424 atoms = self.get_best_atom(cp, "match-visible") 1425 if atoms: 1426 for atom in atoms: 1427 slots.add(portdb.aux_get(atom, ["SLOT"])[0]) 1428 for slot in slots: 1429 visibles.add(cp+":"+slot) 1430 del cps 1431 1432 # now match visibles 1433 available = set() 1434 for visible in visibles: 1435 match = self.get_best_atom(visible) 1436 if match == None: 1437 continue 1438 if filter_reinstalls: 1439 installed = self.get_installed_atom(visible) 1440 # if not installed, installed == None 1441 if installed != match: 1442 available.add(match) 1443 else: 1444 available.add(match) 1445 del visibles 1446 1447 return available
1448 1449 # Collect installed packages
1450 - def get_installed_packages(self, dbdir = None, categories = []):
1451 if not dbdir: 1452 appDbDir = self.get_vdb_path() 1453 else: 1454 appDbDir = dbdir 1455 dbDirs = os.listdir(appDbDir) 1456 installedAtoms = set() 1457 for pkgsdir in dbDirs: 1458 if os.path.isdir(appDbDir+pkgsdir): 1459 pkgdir = os.listdir(appDbDir+pkgsdir) 1460 for pdir in pkgdir: 1461 pkgcat = pkgsdir.split("/")[-1] 1462 if categories and (pkgcat not in categories): 1463 continue 1464 pkgatom = pkgcat+"/"+pdir 1465 if pkgatom.find("-MERGING-") == -1: 1466 installedAtoms.add(pkgatom) 1467 return sorted(list(installedAtoms)), len(installedAtoms)
1468
1469 - def get_installed_packages_counter(self, dbdir = None):
1470 if not dbdir: 1471 appDbDir = self.get_vdb_path() 1472 else: 1473 appDbDir = dbdir 1474 installedAtoms = set() 1475 1476 for current_dirpath, subdirs, files in os.walk(appDbDir): 1477 pvs = os.listdir(current_dirpath) 1478 for mypv in pvs: 1479 if mypv.startswith("-MERGING-"): 1480 continue 1481 mypvpath = current_dirpath+"/"+mypv 1482 if not os.path.isdir(mypvpath): 1483 continue 1484 mycounter_file = mypvpath+"/"+etpConst['spm']['xpak_entries']['counter'] 1485 if not os.access(mycounter_file,os.R_OK): 1486 continue 1487 f = open(mycounter_file) 1488 try: 1489 counter = int(f.readline().strip()) 1490 except (IOError, ValueError): 1491 f.close() 1492 continue 1493 installedAtoms.add((os.path.basename(current_dirpath)+"/"+mypv,counter)) 1494 return installedAtoms
1495
1496 - def _load_sets_config(self, settings, trees):
1497 1498 # from portage.const import USER_CONFIG_PATH, GLOBAL_CONFIG_PATH 1499 setconfigpaths = [os.path.join(self.portage_const.GLOBAL_CONFIG_PATH, etpConst['setsconffilename'])] 1500 setconfigpaths.append(os.path.join(settings["PORTDIR"], etpConst['setsconffilename'])) 1501 setconfigpaths += [os.path.join(x, etpConst['setsconffilename']) for x in settings["PORTDIR_OVERLAY"].split()] 1502 setconfigpaths.append(os.path.join(settings["PORTAGE_CONFIGROOT"], 1503 self.portage_const.USER_CONFIG_PATH.lstrip(os.path.sep), etpConst['setsconffilename'])) 1504 return self.portage_sets.SetConfig(setconfigpaths, settings, trees)
1505
1506 - def get_set_config(self):
1507 # old portage 1508 if self.portage_sets == None: return 1509 myroot = etpConst['systemroot']+"/" 1510 return self._load_sets_config( 1511 self.portage.settings, 1512 self.portage.db[myroot] 1513 )
1514
1515 - def get_sets(self, builtin_sets):
1516 config = self.get_set_config() 1517 if config == None: return {} 1518 mysets = config.getSets() 1519 if not builtin_sets: 1520 builtin_pkg_sets = [x for x in self.builtin_pkg_sets if x in mysets] 1521 for pkg_set in builtin_pkg_sets: mysets.pop(pkg_set) 1522 return mysets
1523
1524 - def get_set_atoms(self, pkgset_obj):
1525 config = self.get_set_config() 1526 if config == None: return [] 1527 return config.getSetAtoms(pkgset_obj).copy()
1528
1529 - def get_sets_expanded(self, builtin_sets = True):
1530 config = self.get_set_config() 1531 if config == None: return {} 1532 mysets = {} 1533 sets = config.getSets() 1534 if not builtin_sets: 1535 builtin_pkg_sets = [x for x in self.builtin_pkg_sets if x in sets] 1536 for pkg_set in builtin_pkg_sets: sets.pop(pkg_set) 1537 for myset in sorted(sets): 1538 try: atoms = config.getSetAtoms(myset).copy() 1539 except: continue 1540 mysets[myset] = atoms 1541 return mysets
1542
1543 - def refill_counter(self, dbdir = None):
1544 if not dbdir: 1545 appDbDir = self.get_vdb_path() 1546 else: 1547 appDbDir = dbdir 1548 counters = set() 1549 for catdir in os.listdir(appDbDir): 1550 catdir = appDbDir+catdir 1551 if not os.path.isdir(catdir): 1552 continue 1553 for pkgdir in os.listdir(catdir): 1554 pkgdir = catdir+"/"+pkgdir 1555 if not os.path.isdir(pkgdir): 1556 continue 1557 counterfile = pkgdir+"/"+etpConst['spm']['xpak_entries']['counter'] 1558 if not os.path.isfile(pkgdir+"/"+etpConst['spm']['xpak_entries']['counter']): 1559 continue 1560 try: 1561 f = open(counterfile,"r") 1562 counter = int(f.readline().strip()) 1563 counters.add(counter) 1564 f.close() 1565 except: 1566 continue 1567 if counters: 1568 newcounter = max(counters) 1569 else: 1570 newcounter = 0 1571 if not os.path.isdir(os.path.dirname(etpConst['edbcounter'])): 1572 os.makedirs(os.path.dirname(etpConst['edbcounter'])) 1573 try: 1574 f = open(etpConst['edbcounter'],"w") 1575 except IOError, e: 1576 if e[0] == 21: 1577 shutil.rmtree(etpConst['edbcounter'],True) 1578 try: 1579 os.rmdir(etpConst['edbcounter']) 1580 except: 1581 pass 1582 f = open(etpConst['edbcounter'],"w") 1583 f.write(str(newcounter)) 1584 f.flush() 1585 f.close() 1586 del counters 1587 return newcounter
1588 1589
1590 - def spm_doebuild(self, myebuild, mydo, tree, cpv, portage_tmpdir = None, licenses = [], fork = False):
1591 if fork: 1592 # memory leak: some versions of portage were memleaking here 1593 return self.entropyTools.spawn_function( 1594 self._portage_doebuild, myebuild, 1595 mydo, tree, cpv, 1596 portage_tmpdir, licenses 1597 ) 1598 return self._portage_doebuild(myebuild, mydo, tree, cpv, portage_tmpdir, licenses)
1599
1600 - def _portage_doebuild(self, myebuild, mydo, tree, cpv, portage_tmpdir = None, licenses = []):
1601 # myebuild = path/to/ebuild.ebuild with a valid unpacked xpak metadata 1602 # tree = "bintree" 1603 # cpv = atom 1604 # mydbapi = portage.fakedbapi(settings=portage.settings) 1605 # vartree = portage.vartree(root=myroot) 1606 1607 oldsystderr = sys.stderr 1608 f = open("/dev/null","w") 1609 if not etpUi['debug']: 1610 sys.stderr = f 1611 1612 ### SETUP ENVIRONMENT 1613 # if mute, supress portage output 1614 domute = False 1615 if etpUi['mute']: 1616 domute = True 1617 oldsysstdout = sys.stdout 1618 sys.stdout = f 1619 1620 mypath = etpConst['systemroot']+"/" 1621 1622 # old way to avoid loop of deaths for entropy portage hooks 1623 os.environ["SKIP_EQUO_SYNC"] = "1" 1624 1625 # load metadata 1626 myebuilddir = os.path.dirname(myebuild) 1627 keys = self.portage.auxdbkeys 1628 metadata = {} 1629 1630 for key in keys: 1631 mykeypath = os.path.join(myebuilddir,key) 1632 if os.path.isfile(mykeypath) and os.access(mykeypath,os.R_OK): 1633 f = open(mykeypath,"r") 1634 metadata[key] = f.readline().strip() 1635 f.close() 1636 1637 ### END SETUP ENVIRONMENT 1638 1639 # find config 1640 mysettings = self._get_portage_config("/",mypath) 1641 mysettings['EBUILD_PHASE'] = mydo 1642 1643 # crappy, broken, ebuilds, put accept_license eutils call 1644 # in pkg_setup, when environment variables are not setup yet 1645 # WARNING WARNING WARNING: 1646 # if some other hook fails for other reasons, it's because 1647 # it may miss env variable here. 1648 mysettings['LICENSE'] = str(' '.join(licenses)) 1649 if licenses: 1650 # we already do this early 1651 mysettings["ACCEPT_LICENSE"] = mysettings['LICENSE'] 1652 mysettings.backup_changes("ACCEPT_LICENSE") 1653 1654 mysettings['EAPI'] = "0" 1655 if metadata.has_key('EAPI'): 1656 mysettings['EAPI'] = metadata['EAPI'] 1657 1658 # workaround for scripts asking for user intervention 1659 mysettings['ROOT'] = mypath 1660 mysettings['CD_ROOT'] = "/tmp" 1661 1662 mysettings.backup_changes("EAPI") 1663 mysettings.backup_changes("LICENSE") 1664 mysettings.backup_changes("EBUILD_PHASE") 1665 mysettings.backup_changes("ROOT") 1666 mysettings.backup_changes("CD_ROOT") 1667 1668 try: # this is a >portage-2.1.4_rc11 feature 1669 mysettings._environ_whitelist = set(mysettings._environ_whitelist) 1670 # put our vars into whitelist 1671 mysettings._environ_whitelist.add("SKIP_EQUO_SYNC") 1672 mysettings._environ_whitelist.add("ACCEPT_LICENSE") 1673 mysettings._environ_whitelist.add("CD_ROOT") 1674 mysettings._environ_whitelist.add("ROOT") 1675 mysettings._environ_whitelist = frozenset(mysettings._environ_whitelist) 1676 except: 1677 self.write_traceback_to_log() 1678 1679 cpv = str(cpv) 1680 mysettings.setcpv(cpv) 1681 portage_tmpdir_created = False # for pkg_postrm, pkg_prerm 1682 if portage_tmpdir: 1683 if not os.path.isdir(portage_tmpdir): 1684 os.makedirs(portage_tmpdir) 1685 portage_tmpdir_created = True 1686 mysettings['PORTAGE_TMPDIR'] = str(portage_tmpdir) 1687 mysettings.backup_changes("PORTAGE_TMPDIR") 1688 1689 mydbapi = self.portage.fakedbapi(settings=mysettings) 1690 mydbapi.cpv_inject(cpv, metadata = metadata) 1691 1692 # cached vartree class 1693 vartree = self._get_portage_vartree(mypath) 1694 1695 try: 1696 rc = self.portage.doebuild( 1697 myebuild = str(myebuild), 1698 mydo = str(mydo), 1699 myroot = mypath, 1700 tree = tree, 1701 mysettings = mysettings, 1702 mydbapi = mydbapi, 1703 vartree = vartree, 1704 use_cache = 0 1705 ) 1706 except: 1707 self.write_traceback_to_log() 1708 raise 1709 1710 # if mute, restore old stdout/stderr 1711 if domute: 1712 sys.stdout = oldsysstdout 1713 1714 sys.stderr = oldsystderr 1715 f.close() 1716 1717 if portage_tmpdir_created: 1718 shutil.rmtree(portage_tmpdir,True) 1719 1720 del mydbapi 1721 del metadata 1722 del keys 1723 return rc
1724
1725 - def _extract_pkg_metadata_generate_extraction_dict(self):
1726 data = { 1727 'pf': { 1728 'path': etpConst['spm']['xpak_entries']['pf'], 1729 'critical': True, 1730 }, 1731 'chost': { 1732 'path': etpConst['spm']['xpak_entries']['chost'], 1733 'critical': True, 1734 }, 1735 'description': { 1736 'path': etpConst['spm']['xpak_entries']['description'], 1737 'critical': False, 1738 }, 1739 'homepage': { 1740 'path': etpConst['spm']['xpak_entries']['homepage'], 1741 'critical': False, 1742 }, 1743 'slot': { 1744 'path': etpConst['spm']['xpak_entries']['slot'], 1745 'critical': False, 1746 }, 1747 'cflags': { 1748 'path': etpConst['spm']['xpak_entries']['cflags'], 1749 'critical': False, 1750 }, 1751 'cxxflags': { 1752 'path': etpConst['spm']['xpak_entries']['cxxflags'], 1753 'critical': False, 1754 }, 1755 'category': { 1756 'path': etpConst['spm']['xpak_entries']['category'], 1757 'critical': True, 1758 }, 1759 'rdepend': { 1760 'path': etpConst['spm']['xpak_entries']['rdepend'], 1761 'critical': False, 1762 }, 1763 'pdepend': { 1764 'path': etpConst['spm']['xpak_entries']['pdepend'], 1765 'critical': False, 1766 }, 1767 'depend': { 1768 'path': etpConst['spm']['xpak_entries']['depend'], 1769 'critical': False, 1770 }, 1771 'use': { 1772 'path': etpConst['spm']['xpak_entries']['use'], 1773 'critical': False, 1774 }, 1775 'iuse': { 1776 'path': etpConst['spm']['xpak_entries']['iuse'], 1777 'critical': False, 1778 }, 1779 'license': { 1780 'path': etpConst['spm']['xpak_entries']['license'], 1781 'critical': False, 1782 }, 1783 'provide': { 1784 'path': etpConst['spm']['xpak_entries']['provide'], 1785 'critical': False, 1786 }, 1787 'sources': { 1788 'path': etpConst['spm']['xpak_entries']['src_uri'], 1789 'critical': False, 1790 }, 1791 'eclasses': { 1792 'path': etpConst['spm']['xpak_entries']['inherited'], 1793 'critical': False, 1794 }, 1795 'counter': { 1796 'path': etpConst['spm']['xpak_entries']['counter'], 1797 'critical': False, 1798 }, 1799 'keywords': { 1800 'path': etpConst['spm']['xpak_entries']['keywords'], 1801 'critical': False, 1802 }, 1803 'spm_phases': { 1804 'path': etpConst['spm']['xpak_entries']['defined_phases'], 1805 'critical': False, 1806 }, 1807 } 1808 return data
1809
1810 - def _extract_pkg_metadata_content(self, content_file, package_path):
1811 1812 pkg_content = {} 1813 1814 if os.path.isfile(content_file): 1815 1816 f = open(content_file,"r") 1817 content = [x.decode('raw_unicode_escape') for x in f.readlines()] 1818 f.close() 1819 outcontent = set() 1820 for line in content: 1821 line = line.strip().split() 1822 try: 1823 datatype = line[0] 1824 datafile = line[1:] 1825 if datatype == 'obj': 1826 datafile = datafile[:-2] 1827 datafile = ' '.join(datafile) 1828 elif datatype == 'dir': 1829 datafile = ' '.join(datafile) 1830 elif datatype == 'sym': 1831 datafile = datafile[:-3] 1832 datafile = ' '.join(datafile) 1833 else: 1834 myexc = "InvalidData: %s %s. %s." % ( 1835 datafile, 1836 _("not supported"), 1837 _("Probably Portage API has changed"), 1838 ) 1839 raise InvalidData(myexc) 1840 outcontent.add((datafile,datatype)) 1841 except: 1842 pass 1843 1844 outcontent = sorted(outcontent) 1845 for datafile, datatype in outcontent: 1846 pkg_content[datafile] = datatype 1847 1848 else: 1849 1850 # CONTENTS is not generated when a package is emerged with portage and the option -B 1851 # we have to unpack the tbz2 and generate content dict 1852 mytempdir = etpConst['packagestmpdir']+"/"+os.path.basename(package_path)+".inject" 1853 if os.path.isdir(mytempdir): 1854 shutil.rmtree(mytempdir) 1855 if not os.path.isdir(mytempdir): 1856 os.makedirs(mytempdir) 1857 1858 self.entropyTools.uncompress_tar_bz2(package_path, extractPath = mytempdir, catchEmpty = True) 1859 tmpdir_len = len(mytempdir) 1860 for currentdir, subdirs, files in os.walk(mytempdir): 1861 pkg_content[currentdir[tmpdir_len:]] = u"dir" 1862 for item in files: 1863 item = currentdir+"/"+item 1864 if os.path.islink(item): 1865 pkg_content[item[tmpdir_len:]] = u"sym" 1866 else: 1867 pkg_content[item[tmpdir_len:]] = u"obj" 1868 1869 # now remove 1870 shutil.rmtree(mytempdir,True) 1871 try: 1872 os.rmdir(mytempdir) 1873 except (OSError,): 1874 pass 1875 1876 return pkg_content
1877
1878 - def _extract_pkg_metadata_needed(self, needed_file):
1879 1880 pkg_needed = set() 1881 lines = [] 1882 1883 try: 1884 f = open(needed_file,"r") 1885 lines = [x.decode('raw_unicode_escape').strip() for x in f.readlines() if x.strip()] 1886 f.close() 1887 except IOError: 1888 return lines 1889 1890 for line in lines: 1891 needed = line.split() 1892 if len(needed) == 2: 1893 ownlib = needed[0] 1894 ownelf = -1 1895 if os.access(ownlib,os.R_OK): 1896 ownelf = self.entropyTools.read_elf_class(ownlib) 1897 for lib in needed[1].split(","): 1898 #if lib.find(".so") != -1: 1899 pkg_needed.add((lib,ownelf)) 1900 1901 return sorted(pkg_needed)
1902
1903 - def _extract_pkg_metadata_needed_paths(self, needed_libs):
1904 1905 data = {} 1906 ldpaths = self.entropyTools.collect_linker_paths() 1907 1908 for needed_lib, elf_class in needed_libs: 1909 for ldpath in ldpaths: 1910 my_lib = os.path.join(ldpath, needed_lib) 1911 if not os.access(my_lib, os.R_OK): 1912 continue 1913 myclass = self.entropyTools.read_elf_class(my_lib) 1914 if myclass != elf_class: 1915 continue 1916 obj = data.setdefault(needed_lib, set()) 1917 obj.add((my_lib, myclass,)) 1918 1919 return data
1920
1921 - def _extract_pkg_metadata_messages(self, log_dir, category, name, version, silent = False):
1922 1923 pkg_messages = [] 1924 1925 if os.path.isdir(log_dir): 1926 1927 elogfiles = os.listdir(log_dir) 1928 myelogfile = "%s:%s-%s" % (category, name, version,) 1929 foundfiles = [x for x in elogfiles if x.startswith(myelogfile)] 1930 if foundfiles: 1931 elogfile = foundfiles[0] 1932 if len(foundfiles) > 1: 1933 # get the latest 1934 mtimes = [] 1935 for item in foundfiles: mtimes.append((self.entropyTools.get_file_unix_mtime(os.path.join(log_dir,item)),item)) 1936 mtimes = sorted(mtimes) 1937 elogfile = mtimes[-1][1] 1938 messages = self.entropyTools.extract_elog(os.path.join(log_dir,elogfile)) 1939 for message in messages: 1940 message = message.replace("emerge","install") 1941 pkg_messages.append(message.decode('raw_unicode_escape')) 1942 1943 elif not silent: 1944 1945 mytxt = " %s, %s" % (_("not set"),_("have you configured make.conf properly?"),) 1946 self.updateProgress( 1947 red(log_dir)+mytxt, 1948 importance = 1, 1949 type = "warning", 1950 header = brown(" * ") 1951 ) 1952 1953 return pkg_messages
1954
1955 - def _extract_pkg_metadata_license_data(self, licenses_dir, license_string):
1956 1957 pkg_licensedata = {} 1958 if licenses_dir and os.path.isdir(licenses_dir): 1959 licdata = [x.strip() for x in license_string.split() if x.strip() and self.entropyTools.is_valid_string(x.strip())] 1960 for mylicense in licdata: 1961 licfile = os.path.join(licenses_dir,mylicense) 1962 if os.access(licfile,os.R_OK): 1963 if self.entropyTools.istextfile(licfile): 1964 f = open(licfile) 1965 content = '' 1966 line = f.readline() 1967 while line: 1968 content += line 1969 line = f.readline() 1970 try: 1971 try: 1972 pkg_licensedata[mylicense] = content.decode('raw_unicode_escape') 1973 except UnicodeDecodeError: 1974 pkg_licensedata[mylicense] = unicode(content,'utf-8') 1975 except (UnicodeDecodeError, UnicodeEncodeError,): 1976 continue # sorry! 1977 f.close() 1978 1979 return pkg_licensedata
1980 1994
1995 - def _extract_pkg_metadata_ebuild_entropy_tag(self, ebuild):
1996 search_tag = etpConst['spm']['ebuild_pkg_tag_var'] 1997 ebuild_tag = '' 1998 f = open(ebuild,"r") 1999 tags = [x.strip().decode('raw_unicode_escape') for x in f.readlines() if x.strip() and x.strip().startswith(search_tag)] 2000 f.close() 2001 if not tags: return ebuild_tag 2002 tag = tags[-1] 2003 tag = tag.split("=")[-1].strip('"').strip("'").strip() 2004 return tag
2005 2006 # This function extracts all the info from a .tbz2 file and returns them
2007 - def extract_pkg_metadata(self, package, silent = False, inject = False):
2008 2009 data = {} 2010 info_package = bold(os.path.basename(package))+": " 2011 system_settings = SystemSettings() 2012 2013 if not silent: 2014 self.updateProgress( 2015 red(info_package+_("Extracting package metadata")+" ..."), 2016 importance = 0, 2017 type = "info", 2018 header = brown(" * "), 2019 back = True 2020 ) 2021 2022 # fill package name and version 2023 data['digest'] = self.entropyTools.md5sum(package) 2024 data['signatures'] = { 2025 'sha1': self.entropyTools.sha1(package), 2026 'sha256': self.entropyTools.sha256(package), 2027 'sha512': self.entropyTools.sha512(package), 2028 } 2029 data['datecreation'] = str(self.entropyTools.get_file_unix_mtime(package)) 2030 data['size'] = str(self.entropyTools.get_file_size(package)) 2031 2032 tmp_dir = tempfile.mkdtemp() 2033 self.entropyTools.extract_xpak(package, tmp_dir) 2034 2035 data['injected'] = False 2036 if inject: data['injected'] = True 2037 data['branch'] = system_settings['repositories']['branch'] 2038 2039 portage_entries = self._extract_pkg_metadata_generate_extraction_dict() 2040 for item in portage_entries: 2041 value = '' 2042 try: 2043 f = open(os.path.join(tmp_dir, portage_entries[item]['path']),"r") 2044 value = f.readline().strip().decode('raw_unicode_escape') 2045 f.close() 2046 except IOError: 2047 if portage_entries[item]['critical']: 2048 raise 2049 data[item] = value 2050 2051 # workout pf 2052 pf_atom = os.path.join(data['category'], data['pf']) 2053 pkgcat, pkgname, pkgver, pkgrev = self.entropyTools.catpkgsplit( 2054 pf_atom) 2055 if pkgrev != "r0": 2056 pkgver += "-%s" % (pkgrev,) 2057 data['name'] = pkgname 2058 data['version'] = pkgver 2059 # bye bye pf 2060 del data['pf'] 2061 2062 # setup spm_phases properly 2063 spm_defined_phases_path = os.path.join(tmp_dir, 2064 portage_entries['spm_phases']['path']) 2065 if not os.path.isfile(spm_defined_phases_path): 2066 # force to None, because metadatum can be '', which is valid 2067 data['spm_phases'] = None 2068 2069 # setup vars 2070 # eclasses must be a set as returned by entropy.db.getPackageData 2071 data['eclasses'] = set(data['eclasses'].split()) 2072 try: 2073 data['counter'] = int(data['counter']) 2074 except ValueError: 2075 data['counter'] = -2 # -2 values will be insterted as incremental negative values into the database 2076 data['keywords'] = [x.strip() for x in data['keywords'].split() if x.strip()] 2077 if not data['keywords']: data['keywords'].insert(0,"") # support for packages with no keywords 2078 # keywords must be a set, as returned by 2079 # entropy.db.getPackageData 2080 data['keywords'] = set(data['keywords']) 2081 needed_file = os.path.join(tmp_dir, etpConst['spm']['xpak_entries']['needed']) 2082 data['needed'] = self._extract_pkg_metadata_needed(needed_file) 2083 data['needed_paths'] = self._extract_pkg_metadata_needed_paths(data['needed']) 2084 content_file = os.path.join(tmp_dir, etpConst['spm']['xpak_entries']['contents']) 2085 data['content'] = self._extract_pkg_metadata_content(content_file, package) 2086 data['disksize'] = self.entropyTools.sum_file_sizes(data['content']) 2087 2088 # [][][] Kernel dependent packages hook [][][] 2089 data['versiontag'] = '' 2090 kernelstuff = False 2091 kernelstuff_kernel = False 2092 for item in data['content']: 2093 if item.startswith("/lib/modules/"): 2094 kernelstuff = True 2095 # get the version of the modules 2096 kmodver = item.split("/lib/modules/")[1] 2097 kmodver = kmodver.split("/")[0] 2098 2099 lp = kmodver.split("-")[-1] 2100 if lp.startswith("r"): 2101 kname = kmodver.split("-")[-2] 2102 kver = kmodver.split("-")[0]+"-"+kmodver.split("-")[-1] 2103 else: 2104 kname = kmodver.split("-")[-1] 2105 kver = kmodver.split("-")[0] 2106 break 2107 # validate the results above 2108 if kernelstuff: 2109 matchatom = "linux-%s-%s" % (kname,kver,) 2110 if (matchatom == data['name']+"-"+data['version']): 2111 kernelstuff_kernel = True 2112 2113 data['versiontag'] = kmodver 2114 if not kernelstuff_kernel: 2115 data['slot'] = kmodver # if you change this behaviour, 2116 # you must change "reagent update" 2117 # and "equo database gentoosync" consequentially 2118 2119 file_ext = etpConst['spm']['ebuild_file_extension'] 2120 ebuilds_in_path = [x for x in os.listdir(tmp_dir) if x.endswith(".%s" % (file_ext,))] 2121 if not data['versiontag'] and ebuilds_in_path: 2122 # has the user specified a custom package tag inside the ebuild 2123 ebuild_path = os.path.join(tmp_dir, ebuilds_in_path[0]) 2124 data['versiontag'] = self._extract_pkg_metadata_ebuild_entropy_tag(ebuild_path) 2125 2126 2127 data['download'] = etpConst['packagesrelativepath'] + data['branch'] + "/" 2128 data['download'] += self.entropyTools.create_package_filename(data['category'], data['name'], data['version'], data['versiontag']) 2129 2130 2131 data['trigger'] = "" 2132 if os.path.isfile(etpConst['triggersdir']+"/"+data['category']+"/"+data['name']+"/"+etpConst['triggername']): 2133 f = open(etpConst['triggersdir']+"/"+data['category']+"/"+data['name']+"/"+etpConst['triggername'],"rb") 2134 data['trigger'] = f.read() 2135 f.close() 2136 2137 # Get Spm ChangeLog 2138 pkgatom = "%s/%s-%s" % (data['category'],data['name'],data['version'],) 2139 try: 2140 data['changelog'] = unicode(self.get_package_changelog(pkgatom), 2141 'raw_unicode_escape') 2142 except (UnicodeEncodeError, UnicodeDecodeError,), e: 2143 self.updateProgress( 2144 red(info_package) + _("changelog string conversion error") + \ 2145 " " + bold(str(e)), 2146 importance = 0, type = "warning", header = bold(" !!! ") 2147 ) 2148 data['changelog'] = None 2149 except: 2150 data['changelog'] = None 2151 2152 portage_metadata = self.calculate_dependencies( 2153 data['iuse'], data['use'], data['license'], data['depend'], 2154 data['rdepend'], data['pdepend'], data['provide'], data['sources'] 2155 ) 2156 2157 data['provide'] = set(portage_metadata['PROVIDE'].split()) 2158 data['license'] = portage_metadata['LICENSE'] 2159 data['useflags'] = [] 2160 for my_use in portage_metadata['USE']: 2161 if my_use in portage_metadata['USE_MASK']: 2162 continue 2163 if my_use in portage_metadata['USE_FORCE']: 2164 data['useflags'].append(my_use) 2165 continue 2166 if my_use in portage_metadata['ENABLED_USE']: 2167 data['useflags'].append(my_use) 2168 else: 2169 data['useflags'].append("-"+my_use) 2170 2171 # useflags must be a set, as returned by entropy.db.getPackageData 2172 data['useflags'] = set(data['useflags']) 2173 # sources must be a set, as returned by entropy.db.getPackageData 2174 data['sources'] = set(portage_metadata['SRC_URI'].split()) 2175 data['dependencies'] = {} 2176 for x in portage_metadata['RDEPEND'].split(): 2177 if x.startswith("!") or (x in ("(","||",")","")): 2178 continue 2179 data['dependencies'][x] = etpConst['spm']['(r)depend_id'] 2180 for x in portage_metadata['PDEPEND'].split(): 2181 if x.startswith("!") or (x in ("(","||",")","")): 2182 continue 2183 data['dependencies'][x] = etpConst['spm']['pdepend_id'] 2184 data['conflicts'] = [x.replace("!","") for x in \ 2185 portage_metadata['RDEPEND'].split() + \ 2186 portage_metadata['PDEPEND'].split() if \ 2187 x.startswith("!") and not x in ("(","||",")","")] 2188 2189 if (kernelstuff) and (not kernelstuff_kernel): 2190 # add kname to the dependency 2191 data['dependencies'][u"=sys-kernel/linux-"+kname+"-"+kver+"~-1"] = etpConst['spm']['(r)depend_id'] 2192 2193 # Conflicting tagged packages support 2194 # Needs Entropy Client System Settings Plugin, 2195 # but since entropy.server loads entropy.client, it's completely 2196 # fine as of now. 2197 key = data['category'] + "/" + data['name'] 2198 client_sysset_plg_id = etpConst['system_settings_plugins_ids']['client_plugin'] 2199 client_data = system_settings.get(client_sysset_plg_id, {}) 2200 confl_data = None 2201 if client_data: 2202 confl_data = client_data['repositories']['conflicting_tagged_packages'].get(key) 2203 if confl_data: 2204 for conflict in confl_data: 2205 data['conflicts'].append(conflict) 2206 2207 # conflicts must be a set, which is what is returned 2208 # by entropy.db.getPackageData 2209 data['conflicts'] = set(data['conflicts']) 2210 2211 # Get License text if possible 2212 licenses_dir = os.path.join(self.get_spm_setting('PORTDIR'),'licenses') 2213 data['licensedata'] = self._extract_pkg_metadata_license_data(licenses_dir, data['license']) 2214 data['mirrorlinks'] = self._extract_pkg_metadata_mirror_links(data['sources']) 2215 2216 # write only if it's a systempackage 2217 data['systempackage'] = False 2218 system_packages = [self.entropyTools.dep_getkey(x) for x in self.get_atoms_in_system()] 2219 if data['category']+"/"+data['name'] in system_packages: 2220 data['systempackage'] = True 2221 2222 # write only if it's a systempackage 2223 protect, mask = self.get_config_protect_and_mask() 2224 data['config_protect'] = protect 2225 data['config_protect_mask'] = mask 2226 2227 log_dir = etpConst['logdir']+"/elog" 2228 if not os.path.isdir(log_dir): os.makedirs(log_dir) 2229 data['messages'] = self._extract_pkg_metadata_messages(log_dir, data['category'], data['name'], data['version'], silent = silent) 2230 # etpapi must be int, as returned by entropy.db.getPackageData 2231 data['etpapi'] = int(etpConst['etpapi']) 2232 2233 # removing temporary directory 2234 shutil.rmtree(tmp_dir, True) 2235 if os.path.isdir(tmp_dir): 2236 try: 2237 os.remove(tmp_dir) 2238 except OSError: 2239 pass 2240 2241 if not silent: 2242 self.updateProgress( 2243 red(info_package+_("Package extraction complete")), importance = 0, 2244 type = "info", header = brown(" * "), back = True 2245 ) 2246 2247 # clear unused metadata 2248 del data['use'], data['iuse'], data['depend'], data['pdepend'], \ 2249 data['rdepend'] 2250 2251 return data
2252