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