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 os.environ["SKIP_EQUO_SYNC"] = "1" 1596 os.environ["CD_ROOT"] = "/tmp" # workaround for scripts asking for user intervention 1597 os.environ["ROOT"] = mypath 1598 1599 if licenses: 1600 os.environ["ACCEPT_LICENSE"] = str(' '.join(licenses)) # we already do this early 1601 1602 # load metadata 1603 myebuilddir = os.path.dirname(myebuild) 1604 keys = self.portage.auxdbkeys 1605 metadata = {} 1606 1607 for key in keys: 1608 mykeypath = os.path.join(myebuilddir,key) 1609 if os.path.isfile(mykeypath) and os.access(mykeypath,os.R_OK): 1610 f = open(mykeypath,"r") 1611 metadata[key] = f.readline().strip() 1612 f.close() 1613 1614 ### END SETUP ENVIRONMENT 1615 1616 # find config 1617 mysettings = self._get_portage_config("/",mypath) 1618 mysettings['EBUILD_PHASE'] = mydo 1619 mysettings['EAPI'] = "0" 1620 if metadata.has_key('EAPI'): 1621 mysettings['EAPI'] = metadata['EAPI'] 1622 mysettings.backup_changes("EAPI") 1623 1624 try: # this is a >portage-2.1.4_rc11 feature 1625 mysettings._environ_whitelist = set(mysettings._environ_whitelist) 1626 # put our vars into whitelist 1627 mysettings._environ_whitelist.add("SKIP_EQUO_SYNC") 1628 mysettings._environ_whitelist.add("ACCEPT_LICENSE") 1629 mysettings._environ_whitelist.add("CD_ROOT") 1630 mysettings._environ_whitelist.add("ROOT") 1631 mysettings._environ_whitelist = frozenset(mysettings._environ_whitelist) 1632 except: 1633 self.write_traceback_to_log() 1634 1635 cpv = str(cpv) 1636 mysettings.setcpv(cpv) 1637 portage_tmpdir_created = False # for pkg_postrm, pkg_prerm 1638 if portage_tmpdir: 1639 if not os.path.isdir(portage_tmpdir): 1640 os.makedirs(portage_tmpdir) 1641 portage_tmpdir_created = True 1642 mysettings['PORTAGE_TMPDIR'] = str(portage_tmpdir) 1643 mysettings.backup_changes("PORTAGE_TMPDIR") 1644 1645 mydbapi = self.portage.fakedbapi(settings=mysettings) 1646 mydbapi.cpv_inject(cpv, metadata = metadata) 1647 1648 # cached vartree class 1649 vartree = self._get_portage_vartree(mypath) 1650 1651 try: 1652 rc = self.portage.doebuild( 1653 myebuild = str(myebuild), 1654 mydo = str(mydo), 1655 myroot = mypath, 1656 tree = tree, 1657 mysettings = mysettings, 1658 mydbapi = mydbapi, 1659 vartree = vartree, 1660 use_cache = 0 1661 ) 1662 except: 1663 self.write_traceback_to_log() 1664 raise 1665 1666 # if mute, restore old stdout/stderr 1667 if domute: 1668 sys.stdout = oldsysstdout 1669 1670 sys.stderr = oldsystderr 1671 f.close() 1672 1673 if portage_tmpdir_created: 1674 shutil.rmtree(portage_tmpdir,True) 1675 1676 del mydbapi 1677 del metadata 1678 del keys 1679 return rc
1680
1681 - def _extract_pkg_metadata_generate_extraction_dict(self):
1682 data = { 1683 'pf': { 1684 'path': etpConst['spm']['xpak_entries']['pf'], 1685 'critical': True, 1686 }, 1687 'chost': { 1688 'path': etpConst['spm']['xpak_entries']['chost'], 1689 'critical': True, 1690 }, 1691 'description': { 1692 'path': etpConst['spm']['xpak_entries']['description'], 1693 'critical': False, 1694 }, 1695 'homepage': { 1696 'path': etpConst['spm']['xpak_entries']['homepage'], 1697 'critical': False, 1698 }, 1699 'slot': { 1700 'path': etpConst['spm']['xpak_entries']['slot'], 1701 'critical': False, 1702 }, 1703 'cflags': { 1704 'path': etpConst['spm']['xpak_entries']['cflags'], 1705 'critical': False, 1706 }, 1707 'cxxflags': { 1708 'path': etpConst['spm']['xpak_entries']['cxxflags'], 1709 'critical': False, 1710 }, 1711 'category': { 1712 'path': etpConst['spm']['xpak_entries']['category'], 1713 'critical': True, 1714 }, 1715 'rdepend': { 1716 'path': etpConst['spm']['xpak_entries']['rdepend'], 1717 'critical': False, 1718 }, 1719 'pdepend': { 1720 'path': etpConst['spm']['xpak_entries']['pdepend'], 1721 'critical': False, 1722 }, 1723 'depend': { 1724 'path': etpConst['spm']['xpak_entries']['depend'], 1725 'critical': False, 1726 }, 1727 'use': { 1728 'path': etpConst['spm']['xpak_entries']['use'], 1729 'critical': False, 1730 }, 1731 'iuse': { 1732 'path': etpConst['spm']['xpak_entries']['iuse'], 1733 'critical': False, 1734 }, 1735 'license': { 1736 'path': etpConst['spm']['xpak_entries']['license'], 1737 'critical': False, 1738 }, 1739 'provide': { 1740 'path': etpConst['spm']['xpak_entries']['provide'], 1741 'critical': False, 1742 }, 1743 'sources': { 1744 'path': etpConst['spm']['xpak_entries']['src_uri'], 1745 'critical': False, 1746 }, 1747 'eclasses': { 1748 'path': etpConst['spm']['xpak_entries']['inherited'], 1749 'critical': False, 1750 }, 1751 'counter': { 1752 'path': etpConst['spm']['xpak_entries']['counter'], 1753 'critical': False, 1754 }, 1755 'keywords': { 1756 'path': etpConst['spm']['xpak_entries']['keywords'], 1757 'critical': False, 1758 }, 1759 'spm_phases': { 1760 'path': etpConst['spm']['xpak_entries']['defined_phases'], 1761 'critical': False, 1762 }, 1763 } 1764 return data
1765
1766 - def _extract_pkg_metadata_content(self, content_file, package_path):
1767 1768 pkg_content = {} 1769 1770 if os.path.isfile(content_file): 1771 1772 f = open(content_file,"r") 1773 content = [x.decode('raw_unicode_escape') for x in f.readlines()] 1774 f.close() 1775 outcontent = set() 1776 for line in content: 1777 line = line.strip().split() 1778 try: 1779 datatype = line[0] 1780 datafile = line[1:] 1781 if datatype == 'obj': 1782 datafile = datafile[:-2] 1783 datafile = ' '.join(datafile) 1784 elif datatype == 'dir': 1785 datafile = ' '.join(datafile) 1786 elif datatype == 'sym': 1787 datafile = datafile[:-3] 1788 datafile = ' '.join(datafile) 1789 else: 1790 myexc = "InvalidData: %s %s. %s." % ( 1791 datafile, 1792 _("not supported"), 1793 _("Probably Portage API has changed"), 1794 ) 1795 raise InvalidData(myexc) 1796 outcontent.add((datafile,datatype)) 1797 except: 1798 pass 1799 1800 outcontent = sorted(outcontent) 1801 for datafile, datatype in outcontent: 1802 pkg_content[datafile] = datatype 1803 1804 else: 1805 1806 # CONTENTS is not generated when a package is emerged with portage and the option -B 1807 # we have to unpack the tbz2 and generate content dict 1808 mytempdir = etpConst['packagestmpdir']+"/"+os.path.basename(package_path)+".inject" 1809 if os.path.isdir(mytempdir): 1810 shutil.rmtree(mytempdir) 1811 if not os.path.isdir(mytempdir): 1812 os.makedirs(mytempdir) 1813 1814 self.entropyTools.uncompress_tar_bz2(package_path, extractPath = mytempdir, catchEmpty = True) 1815 tmpdir_len = len(mytempdir) 1816 for currentdir, subdirs, files in os.walk(mytempdir): 1817 pkg_content[currentdir[tmpdir_len:]] = u"dir" 1818 for item in files: 1819 item = currentdir+"/"+item 1820 if os.path.islink(item): 1821 pkg_content[item[tmpdir_len:]] = u"sym" 1822 else: 1823 pkg_content[item[tmpdir_len:]] = u"obj" 1824 1825 # now remove 1826 shutil.rmtree(mytempdir,True) 1827 try: 1828 os.rmdir(mytempdir) 1829 except (OSError,): 1830 pass 1831 1832 return pkg_content
1833
1834 - def _extract_pkg_metadata_needed(self, needed_file):
1835 1836 pkg_needed = set() 1837 lines = [] 1838 1839 try: 1840 f = open(needed_file,"r") 1841 lines = [x.decode('raw_unicode_escape').strip() for x in f.readlines() if x.strip()] 1842 f.close() 1843 except IOError: 1844 return lines 1845 1846 for line in lines: 1847 needed = line.split() 1848 if len(needed) == 2: 1849 ownlib = needed[0] 1850 ownelf = -1 1851 if os.access(ownlib,os.R_OK): 1852 ownelf = self.entropyTools.read_elf_class(ownlib) 1853 for lib in needed[1].split(","): 1854 #if lib.find(".so") != -1: 1855 pkg_needed.add((lib,ownelf)) 1856 1857 return sorted(pkg_needed)
1858
1859 - def _extract_pkg_metadata_needed_paths(self, needed_libs):
1860 1861 data = {} 1862 ldpaths = self.entropyTools.collect_linker_paths() 1863 1864 for needed_lib, elf_class in needed_libs: 1865 for ldpath in ldpaths: 1866 my_lib = os.path.join(ldpath, needed_lib) 1867 if not os.access(my_lib, os.R_OK): 1868 continue 1869 myclass = self.entropyTools.read_elf_class(my_lib) 1870 if myclass != elf_class: 1871 continue 1872 obj = data.setdefault(needed_lib, set()) 1873 obj.add((my_lib, myclass,)) 1874 1875 return data
1876
1877 - def _extract_pkg_metadata_messages(self, log_dir, category, name, version, silent = False):
1878 1879 pkg_messages = [] 1880 1881 if os.path.isdir(log_dir): 1882 1883 elogfiles = os.listdir(log_dir) 1884 myelogfile = "%s:%s-%s" % (category, name, version,) 1885 foundfiles = [x for x in elogfiles if x.startswith(myelogfile)] 1886 if foundfiles: 1887 elogfile = foundfiles[0] 1888 if len(foundfiles) > 1: 1889 # get the latest 1890 mtimes = [] 1891 for item in foundfiles: mtimes.append((self.entropyTools.get_file_unix_mtime(os.path.join(log_dir,item)),item)) 1892 mtimes = sorted(mtimes) 1893 elogfile = mtimes[-1][1] 1894 messages = self.entropyTools.extract_elog(os.path.join(log_dir,elogfile)) 1895 for message in messages: 1896 message = message.replace("emerge","install") 1897 pkg_messages.append(message.decode('raw_unicode_escape')) 1898 1899 elif not silent: 1900 1901 mytxt = " %s, %s" % (_("not set"),_("have you configured make.conf properly?"),) 1902 self.updateProgress( 1903 red(log_dir)+mytxt, 1904 importance = 1, 1905 type = "warning", 1906 header = brown(" * ") 1907 ) 1908 1909 return pkg_messages
1910
1911 - def _extract_pkg_metadata_license_data(self, licenses_dir, license_string):
1912 1913 pkg_licensedata = {} 1914 if licenses_dir and os.path.isdir(licenses_dir): 1915 licdata = [x.strip() for x in license_string.split() if x.strip() and self.entropyTools.is_valid_string(x.strip())] 1916 for mylicense in licdata: 1917 licfile = os.path.join(licenses_dir,mylicense) 1918 if os.access(licfile,os.R_OK): 1919 if self.entropyTools.istextfile(licfile): 1920 f = open(licfile) 1921 content = '' 1922 line = f.readline() 1923 while line: 1924 content += line 1925 line = f.readline() 1926 try: 1927 try: 1928 pkg_licensedata[mylicense] = content.decode('raw_unicode_escape') 1929 except UnicodeDecodeError: 1930 pkg_licensedata[mylicense] = unicode(content,'utf-8') 1931 except (UnicodeDecodeError, UnicodeEncodeError,): 1932 continue # sorry! 1933 f.close() 1934 1935 return pkg_licensedata
1936 1950
1951 - def _extract_pkg_metadata_ebuild_entropy_tag(self, ebuild):
1952 search_tag = etpConst['spm']['ebuild_pkg_tag_var'] 1953 ebuild_tag = '' 1954 f = open(ebuild,"r") 1955 tags = [x.strip().decode('raw_unicode_escape') for x in f.readlines() if x.strip() and x.strip().startswith(search_tag)] 1956 f.close() 1957 if not tags: return ebuild_tag 1958 tag = tags[-1] 1959 tag = tag.split("=")[-1].strip('"').strip("'").strip() 1960 return tag
1961 1962 # This function extracts all the info from a .tbz2 file and returns them
1963 - def extract_pkg_metadata(self, package, silent = False, inject = False):
1964 1965 data = {} 1966 info_package = bold(os.path.basename(package))+": " 1967 system_settings = SystemSettings() 1968 1969 if not silent: 1970 self.updateProgress( 1971 red(info_package+_("Extracting package metadata")+" ..."), 1972 importance = 0, 1973 type = "info", 1974 header = brown(" * "), 1975 back = True 1976 ) 1977 1978 # fill package name and version 1979 data['digest'] = self.entropyTools.md5sum(package) 1980 data['signatures'] = { 1981 'sha1': self.entropyTools.sha1(package), 1982 'sha256': self.entropyTools.sha256(package), 1983 'sha512': self.entropyTools.sha512(package), 1984 } 1985 data['datecreation'] = str(self.entropyTools.get_file_unix_mtime(package)) 1986 data['size'] = str(self.entropyTools.get_file_size(package)) 1987 1988 tmp_dir = tempfile.mkdtemp() 1989 self.entropyTools.extract_xpak(package, tmp_dir) 1990 1991 data['injected'] = False 1992 if inject: data['injected'] = True 1993 data['branch'] = system_settings['repositories']['branch'] 1994 1995 portage_entries = self._extract_pkg_metadata_generate_extraction_dict() 1996 for item in portage_entries: 1997 value = '' 1998 try: 1999 f = open(os.path.join(tmp_dir, portage_entries[item]['path']),"r") 2000 value = f.readline().strip().decode('raw_unicode_escape') 2001 f.close() 2002 except IOError: 2003 if portage_entries[item]['critical']: 2004 raise 2005 data[item] = value 2006 2007 # workout pf 2008 pf_atom = os.path.join(data['category'], data['pf']) 2009 pkgcat, pkgname, pkgver, pkgrev = self.entropyTools.catpkgsplit( 2010 pf_atom) 2011 if pkgrev != "r0": 2012 pkgver += "-%s" % (pkgrev,) 2013 data['name'] = pkgname 2014 data['version'] = pkgver 2015 # bye bye pf 2016 del data['pf'] 2017 2018 # setup spm_phases properly 2019 spm_defined_phases_path = os.path.join(tmp_dir, 2020 portage_entries['spm_phases']['path']) 2021 if not os.path.isfile(spm_defined_phases_path): 2022 # force to None, because metadatum can be '', which is valid 2023 data['spm_phases'] = None 2024 2025 # setup vars 2026 # eclasses must be a set as returned by entropy.db.getPackageData 2027 data['eclasses'] = set(data['eclasses'].split()) 2028 try: 2029 data['counter'] = int(data['counter']) 2030 except ValueError: 2031 data['counter'] = -2 # -2 values will be insterted as incremental negative values into the database 2032 data['keywords'] = [x.strip() for x in data['keywords'].split() if x.strip()] 2033 if not data['keywords']: data['keywords'].insert(0,"") # support for packages with no keywords 2034 # keywords must be a set, as returned by 2035 # entropy.db.getPackageData 2036 data['keywords'] = set(data['keywords']) 2037 needed_file = os.path.join(tmp_dir, etpConst['spm']['xpak_entries']['needed']) 2038 data['needed'] = self._extract_pkg_metadata_needed(needed_file) 2039 data['needed_paths'] = self._extract_pkg_metadata_needed_paths(data['needed']) 2040 content_file = os.path.join(tmp_dir, etpConst['spm']['xpak_entries']['contents']) 2041 data['content'] = self._extract_pkg_metadata_content(content_file, package) 2042 data['disksize'] = self.entropyTools.sum_file_sizes(data['content']) 2043 2044 # [][][] Kernel dependent packages hook [][][] 2045 data['versiontag'] = '' 2046 kernelstuff = False 2047 kernelstuff_kernel = False 2048 for item in data['content']: 2049 if item.startswith("/lib/modules/"): 2050 kernelstuff = True 2051 # get the version of the modules 2052 kmodver = item.split("/lib/modules/")[1] 2053 kmodver = kmodver.split("/")[0] 2054 2055 lp = kmodver.split("-")[-1] 2056 if lp.startswith("r"): 2057 kname = kmodver.split("-")[-2] 2058 kver = kmodver.split("-")[0]+"-"+kmodver.split("-")[-1] 2059 else: 2060 kname = kmodver.split("-")[-1] 2061 kver = kmodver.split("-")[0] 2062 break 2063 # validate the results above 2064 if kernelstuff: 2065 matchatom = "linux-%s-%s" % (kname,kver,) 2066 if (matchatom == data['name']+"-"+data['version']): 2067 kernelstuff_kernel = True 2068 2069 data['versiontag'] = kmodver 2070 if not kernelstuff_kernel: 2071 data['slot'] = kmodver # if you change this behaviour, 2072 # you must change "reagent update" 2073 # and "equo database gentoosync" consequentially 2074 2075 file_ext = etpConst['spm']['ebuild_file_extension'] 2076 ebuilds_in_path = [x for x in os.listdir(tmp_dir) if x.endswith(".%s" % (file_ext,))] 2077 if not data['versiontag'] and ebuilds_in_path: 2078 # has the user specified a custom package tag inside the ebuild 2079 ebuild_path = os.path.join(tmp_dir, ebuilds_in_path[0]) 2080 data['versiontag'] = self._extract_pkg_metadata_ebuild_entropy_tag(ebuild_path) 2081 2082 2083 data['download'] = etpConst['packagesrelativepath'] + data['branch'] + "/" 2084 data['download'] += self.entropyTools.create_package_filename(data['category'], data['name'], data['version'], data['versiontag']) 2085 2086 2087 data['trigger'] = "" 2088 if os.path.isfile(etpConst['triggersdir']+"/"+data['category']+"/"+data['name']+"/"+etpConst['triggername']): 2089 f = open(etpConst['triggersdir']+"/"+data['category']+"/"+data['name']+"/"+etpConst['triggername'],"rb") 2090 data['trigger'] = f.read() 2091 f.close() 2092 2093 # Get Spm ChangeLog 2094 pkgatom = "%s/%s-%s" % (data['category'],data['name'],data['version'],) 2095 try: 2096 data['changelog'] = unicode(self.get_package_changelog(pkgatom), 2097 'raw_unicode_escape') 2098 except (UnicodeEncodeError, UnicodeDecodeError,), e: 2099 self.updateProgress( 2100 red(info_package) + _("changelog string conversion error") + \ 2101 " " + bold(str(e)), 2102 importance = 0, type = "warning", header = bold(" !!! ") 2103 ) 2104 data['changelog'] = None 2105 except: 2106 data['changelog'] = None 2107 2108 portage_metadata = self.calculate_dependencies( 2109 data['iuse'], data['use'], data['license'], data['depend'], 2110 data['rdepend'], data['pdepend'], data['provide'], data['sources'] 2111 ) 2112 2113 data['provide'] = set(portage_metadata['PROVIDE'].split()) 2114 data['license'] = portage_metadata['LICENSE'] 2115 data['useflags'] = [] 2116 for my_use in portage_metadata['USE']: 2117 if my_use in portage_metadata['USE_MASK']: 2118 continue 2119 if my_use in portage_metadata['USE_FORCE']: 2120 data['useflags'].append(my_use) 2121 continue 2122 if my_use in portage_metadata['ENABLED_USE']: 2123 data['useflags'].append(my_use) 2124 else: 2125 data['useflags'].append("-"+my_use) 2126 2127 # useflags must be a set, as returned by entropy.db.getPackageData 2128 data['useflags'] = set(data['useflags']) 2129 # sources must be a set, as returned by entropy.db.getPackageData 2130 data['sources'] = set(portage_metadata['SRC_URI'].split()) 2131 data['dependencies'] = {} 2132 for x in portage_metadata['RDEPEND'].split(): 2133 if x.startswith("!") or (x in ("(","||",")","")): 2134 continue 2135 data['dependencies'][x] = etpConst['spm']['(r)depend_id'] 2136 for x in portage_metadata['PDEPEND'].split(): 2137 if x.startswith("!") or (x in ("(","||",")","")): 2138 continue 2139 data['dependencies'][x] = etpConst['spm']['pdepend_id'] 2140 data['conflicts'] = [x.replace("!","") for x in \ 2141 portage_metadata['RDEPEND'].split() + \ 2142 portage_metadata['PDEPEND'].split() if \ 2143 x.startswith("!") and not x in ("(","||",")","")] 2144 2145 if (kernelstuff) and (not kernelstuff_kernel): 2146 # add kname to the dependency 2147 data['dependencies'][u"=sys-kernel/linux-"+kname+"-"+kver+"~-1"] = etpConst['spm']['(r)depend_id'] 2148 2149 # Conflicting tagged packages support 2150 # Needs Entropy Client System Settings Plugin, 2151 # but since entropy.server loads entropy.client, it's completely 2152 # fine as of now. 2153 key = data['category'] + "/" + data['name'] 2154 client_sysset_plg_id = etpConst['system_settings_plugins_ids']['client_plugin'] 2155 client_data = system_settings.get(client_sysset_plg_id, {}) 2156 confl_data = None 2157 if client_data: 2158 confl_data = client_data['repositories']['conflicting_tagged_packages'].get(key) 2159 if confl_data: 2160 for conflict in confl_data: 2161 data['conflicts'].append(conflict) 2162 2163 # conflicts must be a set, which is what is returned 2164 # by entropy.db.getPackageData 2165 data['conflicts'] = set(data['conflicts']) 2166 2167 # Get License text if possible 2168 licenses_dir = os.path.join(self.get_spm_setting('PORTDIR'),'licenses') 2169 data['licensedata'] = self._extract_pkg_metadata_license_data(licenses_dir, data['license']) 2170 data['mirrorlinks'] = self._extract_pkg_metadata_mirror_links(data['sources']) 2171 2172 # write only if it's a systempackage 2173 data['systempackage'] = False 2174 system_packages = [self.entropyTools.dep_getkey(x) for x in self.get_atoms_in_system()] 2175 if data['category']+"/"+data['name'] in system_packages: 2176 data['systempackage'] = True 2177 2178 # write only if it's a systempackage 2179 protect, mask = self.get_config_protect_and_mask() 2180 data['config_protect'] = protect 2181 data['config_protect_mask'] = mask 2182 2183 log_dir = etpConst['logdir']+"/elog" 2184 if not os.path.isdir(log_dir): os.makedirs(log_dir) 2185 data['messages'] = self._extract_pkg_metadata_messages(log_dir, data['category'], data['name'], data['version'], silent = silent) 2186 # etpapi must be int, as returned by entropy.db.getPackageData 2187 data['etpapi'] = int(etpConst['etpapi']) 2188 2189 # removing temporary directory 2190 shutil.rmtree(tmp_dir, True) 2191 if os.path.isdir(tmp_dir): 2192 try: 2193 os.remove(tmp_dir) 2194 except OSError: 2195 pass 2196 2197 if not silent: 2198 self.updateProgress( 2199 red(info_package+_("Package extraction complete")), importance = 0, 2200 type = "info", header = brown(" * "), back = True 2201 ) 2202 2203 # clear unused metadata 2204 del data['use'], data['iuse'], data['depend'], data['pdepend'], \ 2205 data['rdepend'] 2206 2207 return data
2208