Package entropy :: Package client :: Package interfaces :: Module dep

Source Code for Module entropy.client.interfaces.dep

   1  # -*- coding: utf-8 -*- 
   2  """ 
   3   
   4      @author: Fabio Erculiani <lxnay@sabayonlinux.org> 
   5      @contact: lxnay@sabayonlinux.org 
   6      @copyright: Fabio Erculiani 
   7      @license: GPL-2 
   8   
   9      B{Entropy Package Manager Client Dependency handling Interface}. 
  10   
  11  """ 
  12  from __future__ import with_statement 
  13  from entropy.misc import Lifo 
  14  from entropy.const import * 
  15  from entropy.exceptions import * 
  16  from entropy.output import bold, darkgreen, darkred, blue, red 
  17  from entropy.i18n import _ 
  18   
19 -class CalculatorsMixin:
20
21 - def dependencies_test(self, dbconn = None):
22 23 if dbconn == None: 24 dbconn = self.clientDbconn 25 # get all the installed packages 26 installed_packages = dbconn.listAllIdpackages() 27 28 pdepend_id = etpConst['spm']['pdepend_id'] 29 deps_not_matched = set() 30 # now look 31 length = len(installed_packages) 32 count = 0 33 for idpackage in installed_packages: 34 count += 1 35 36 if (count%150 == 0) or (count == length) or (count == 1): 37 atom = dbconn.retrieveAtom(idpackage) 38 self.updateProgress( 39 darkgreen(_("Checking %s") % (bold(atom),)), 40 importance = 0, 41 type = "info", 42 back = True, 43 count = (count,length), 44 header = darkred(" @@ ") 45 ) 46 47 xdeps = dbconn.retrieveDependencies(idpackage, 48 exclude_deptypes = (pdepend_id,)) 49 needed_deps = [(x,dbconn.atomMatch(x),) for x in xdeps] 50 deps_not_matched |= set([x for x,(y,z,) in needed_deps if y == -1]) 51 52 return deps_not_matched
53
54 - def find_belonging_dependency(self, matched_atoms):
55 crying_atoms = set() 56 for atom in matched_atoms: 57 for repo in self.validRepositories: 58 rdbconn = self.open_repository(repo) 59 riddep = rdbconn.searchDependency(atom) 60 if riddep != -1: 61 ridpackages = rdbconn.searchIdpackageFromIddependency(riddep) 62 for i in ridpackages: 63 i,r = rdbconn.idpackageValidator(i) 64 if i == -1: 65 continue 66 iatom = rdbconn.retrieveAtom(i) 67 crying_atoms.add((iatom,repo)) 68 return crying_atoms
69
70 - def __handle_multi_repo_matches(self, results, extended_results, valid_repos, server_inst):
71 72 packageInformation = {} 73 versionInformation = {} 74 # .tbz2 repos have always the precedence, so if we find them, 75 # we should second what user wants, installing his tbz2 76 tbz2repos = [x for x in results if x.endswith(etpConst['packagesext'])] 77 if tbz2repos: 78 del tbz2repos 79 newrepos = results.copy() 80 for x in newrepos: 81 if x.endswith(etpConst['packagesext']): 82 continue 83 del results[x] 84 85 version_duplicates = set() 86 versions = set() 87 for repo in results: 88 packageInformation[repo] = {} 89 if extended_results: 90 version = results[repo][1] 91 packageInformation[repo]['versiontag'] = results[repo][2] 92 packageInformation[repo]['revision'] = results[repo][3] 93 else: 94 dbconn = self.__atom_match_open_db(repo, server_inst) 95 packageInformation[repo]['versiontag'] = dbconn.retrieveVersionTag(results[repo]) 96 packageInformation[repo]['revision'] = dbconn.retrieveRevision(results[repo]) 97 version = dbconn.retrieveVersion(results[repo]) 98 packageInformation[repo]['version'] = version 99 versionInformation[version] = repo 100 if version in versions: 101 version_duplicates.add(version) 102 versions.add(version) 103 104 newerVersion = self.entropyTools.get_newer_version(list(versions))[0] 105 # if no duplicates are found or newer version is not in duplicates we're done 106 if (not version_duplicates) or (newerVersion not in version_duplicates): 107 reponame = versionInformation.get(newerVersion) 108 return (results[reponame],reponame) 109 110 # we have two repositories with >two packages with the same version 111 # check package tag 112 113 conflictingEntries = {} 114 tags_duplicates = set() 115 tags = set() 116 tagsInfo = {} 117 for repo in packageInformation: 118 if packageInformation[repo]['version'] != newerVersion: 119 continue 120 conflictingEntries[repo] = {} 121 versiontag = packageInformation[repo]['versiontag'] 122 if versiontag in tags: 123 tags_duplicates.add(versiontag) 124 tags.add(versiontag) 125 tagsInfo[versiontag] = repo 126 conflictingEntries[repo]['versiontag'] = versiontag 127 conflictingEntries[repo]['revision'] = packageInformation[repo]['revision'] 128 129 # tags will always be != [] 130 newerTag = sorted(list(tags), reverse = True)[0] 131 if newerTag not in tags_duplicates: 132 reponame = tagsInfo.get(newerTag) 133 return (results[reponame],reponame) 134 135 # in this case, we have >two packages with the same version and tag 136 # check package revision 137 138 conflictingRevisions = {} 139 revisions = set() 140 revisions_duplicates = set() 141 revisionInfo = {} 142 for repo in conflictingEntries: 143 if conflictingEntries[repo]['versiontag'] == newerTag: 144 conflictingRevisions[repo] = {} 145 versionrev = conflictingEntries[repo]['revision'] 146 if versionrev in revisions: 147 revisions_duplicates.add(versionrev) 148 revisions.add(versionrev) 149 revisionInfo[versionrev] = repo 150 conflictingRevisions[repo]['revision'] = versionrev 151 152 newerRevision = max(revisions) 153 if newerRevision not in revisions_duplicates: 154 reponame = revisionInfo.get(newerRevision) 155 return (results[reponame],reponame) 156 157 # final step, in this case we have >two packages with the same version, tag and revision 158 # get the repository with the biggest priority 159 160 for reponame in valid_repos: 161 if reponame in conflictingRevisions: 162 return (results[reponame],reponame)
163
164 - def __validate_atom_match_cache(self, cached_obj, multiMatch, extendedResults, multiRepo, server_inst):
165 166 data, rc = cached_obj 167 if rc == 1: return cached_obj 168 169 if multiRepo or multiMatch: 170 matches = data # set([(14789, 'sabayonlinux.org'), (14479, 'sabayonlinux.org')]) 171 if extendedResults: 172 # set([((14789, u'3.3.8b', u'', 0), 'sabayonlinux.org')]) 173 matches = [(x[0][0],x[1],) for x in data] 174 for m_id, m_repo in matches: 175 m_db = self.__atom_match_open_db(m_repo, server_inst) 176 if not m_db.isIdpackageAvailable(m_id): 177 return None 178 else: 179 m_id, m_repo = cached_obj # (14479, 'sabayonlinux.org') 180 if extendedResults: 181 # ((14479, u'4.4.2', u'', 0), 'sabayonlinux.org') 182 m_id, m_repo = cached_obj[0][0],cached_obj[1] 183 m_db = self.__atom_match_open_db(m_repo, server_inst) 184 if not m_db.isIdpackageAvailable(m_id): 185 return None 186 187 return cached_obj
188
189 - def __atom_match_open_db(self, repoid, server_inst):
190 if server_inst != None: 191 dbconn = server_inst.open_server_repository(just_reading = True, 192 repo = repoid, do_treeupdates = False) 193 else: 194 dbconn = self.open_repository(repoid) 195 return dbconn
196
197 - def atom_match(self, atom, caseSensitive = True, matchSlot = None, 198 matchTag = None, packagesFilter = True, 199 multiMatch = False, multiRepo = False, matchRevision = None, 200 matchRepo = None, server_repos = [], serverInstance = None, 201 extendedResults = False, useCache = True):
202 203 # support match in repository from shell 204 # atom@repo1,repo2,repo3 205 atom, repos = self.entropyTools.dep_get_match_in_repos(atom) 206 if (matchRepo == None) and (repos != None): 207 matchRepo = repos 208 209 u_hash = "" 210 k_ms = "//" 211 k_mt = "@#@" 212 k_mr = "-1" 213 if isinstance(matchRepo,(list,tuple,set,)): 214 u_hash = hash(frozenset(matchRepo)) 215 if isinstance(matchSlot,basestring): 216 k_ms = matchSlot 217 if isinstance(matchTag,basestring): 218 k_mt = matchTag 219 if isinstance(matchRevision,basestring): 220 k_mr = matchRevision 221 222 c_hash = "|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s" % ( 223 atom,k_ms,k_mt,hash(packagesFilter), 224 hash(frozenset(self.validRepositories)), 225 hash(frozenset(self.SystemSettings['repositories']['available'])), 226 hash(multiMatch),hash(multiRepo),hash(caseSensitive), 227 k_mr,hash(extendedResults), 228 u_hash, 229 ) 230 c_hash = "%s%s" % (self.atomMatchCacheKey,hash(c_hash),) 231 232 if self.xcache and useCache: 233 cached = self.Cacher.pop(c_hash) 234 if cached != None: 235 try: 236 cached = self.__validate_atom_match_cache(cached, multiMatch, extendedResults, multiRepo, serverInstance) 237 except (TypeError,ValueError,IndexError,KeyError,): 238 cached = None 239 if cached != None: 240 return cached 241 242 if server_repos: 243 if not serverInstance: 244 t = _("server_repos needs serverInstance") 245 raise IncorrectParameter("IncorrectParameter: %s" % (t,)) 246 valid_repos = server_repos[:] 247 else: 248 valid_repos = self.validRepositories 249 if matchRepo and (type(matchRepo) in (list,tuple,set)): 250 valid_repos = list(matchRepo) 251 252 repoResults = {} 253 for repo in valid_repos: 254 255 # search 256 dbconn = self.__atom_match_open_db(repo, serverInstance) 257 use_cache = useCache 258 while 1: 259 try: 260 query_data, query_rc = dbconn.atomMatch( 261 atom, 262 caseSensitive = caseSensitive, 263 matchSlot = matchSlot, 264 matchTag = matchTag, 265 packagesFilter = packagesFilter, 266 matchRevision = matchRevision, 267 extendedResults = extendedResults, 268 useCache = use_cache 269 ) 270 if query_rc == 0: 271 # package found, add to our dictionary 272 if extendedResults: 273 repoResults[repo] = (query_data[0],query_data[2],query_data[3],query_data[4]) 274 else: 275 repoResults[repo] = query_data 276 except TypeError: 277 if not use_cache: 278 raise 279 use_cache = False 280 continue 281 except dbconn.dbapi2.OperationalError: 282 # repository fooked, skip! 283 break 284 break 285 286 dbpkginfo = (-1,1) 287 if extendedResults: 288 dbpkginfo = ((-1,None,None,None),1) 289 290 if multiRepo and repoResults: 291 292 data = set() 293 for repoid in repoResults: 294 data.add((repoResults[repoid],repoid)) 295 dbpkginfo = (data,0) 296 297 elif len(repoResults) == 1: 298 # one result found 299 repo = repoResults.keys()[0] 300 dbpkginfo = (repoResults[repo],repo) 301 302 elif len(repoResults) > 1: 303 304 # we have to decide which version should be taken 305 mypkginfo = self.__handle_multi_repo_matches(repoResults, extendedResults, valid_repos, serverInstance) 306 if mypkginfo != None: dbpkginfo = mypkginfo 307 308 # multimatch support 309 if multiMatch: 310 311 if dbpkginfo[1] == 1: 312 dbpkginfo = (set(), 1) 313 else: # can be "0" or a string, but 1 means failure 314 if multiRepo: 315 data = set() 316 for q_id,q_repo in dbpkginfo[0]: 317 dbconn = self.__atom_match_open_db(q_repo, serverInstance) 318 query_data, query_rc = dbconn.atomMatch( 319 atom, 320 caseSensitive = caseSensitive, 321 matchSlot = matchSlot, 322 matchTag = matchTag, 323 packagesFilter = packagesFilter, 324 multiMatch = True, 325 extendedResults = extendedResults 326 ) 327 if extendedResults: 328 for item in query_data: 329 data.add(((item[0],item[2],item[3],item[4]),q_repo)) 330 else: 331 for x in query_data: data.add((x,q_repo)) 332 dbpkginfo = (data,0) 333 else: 334 dbconn = self.__atom_match_open_db(dbpkginfo[1], serverInstance) 335 query_data, query_rc = dbconn.atomMatch( 336 atom, 337 caseSensitive = caseSensitive, 338 matchSlot = matchSlot, 339 matchTag = matchTag, 340 packagesFilter = packagesFilter, 341 multiMatch = True, 342 extendedResults = extendedResults 343 ) 344 if extendedResults: 345 dbpkginfo = (set([((x[0],x[2],x[3],x[4]),dbpkginfo[1]) for x in query_data]),0) 346 else: 347 dbpkginfo = (set([(x,dbpkginfo[1]) for x in query_data]),0) 348 349 if self.xcache and useCache: 350 self.Cacher.push(c_hash,dbpkginfo) 351 352 return dbpkginfo
353 354 # expands package sets, and in future something more perhaps
355 - def packages_expand(self, packages):
356 new_packages = [] 357 358 for pkg_id in range(len(packages)): 359 package = packages[pkg_id] 360 361 # expand package sets 362 if package.startswith(etpConst['packagesetprefix']): 363 set_pkgs = sorted(list(self.package_set_expand(package, raise_exceptions = False))) 364 new_packages.extend([x for x in set_pkgs if x not in packages]) # atomMatch below will filter dupies 365 else: 366 new_packages.append(package) 367 368 return new_packages
369
370 - def package_set_expand(self, package_set, raise_exceptions = True):
371 372 max_recursion_level = 50 373 recursion_level = 0 374 375 def do_expand(myset, recursion_level, max_recursion_level): 376 recursion_level += 1 377 if recursion_level > max_recursion_level: 378 raise InvalidPackageSet('InvalidPackageSet: corrupted, too many recursions: %s' % (myset,)) 379 set_data, set_rc = self.package_set_match(myset[len(etpConst['packagesetprefix']):]) 380 if not set_rc: 381 raise InvalidPackageSet('InvalidPackageSet: not found: %s' % (myset,)) 382 (set_from, package_set, mydata,) = set_data 383 384 mypkgs = set() 385 for fset in mydata: # recursively 386 if fset.startswith(etpConst['packagesetprefix']): 387 mypkgs |= do_expand(fset, recursion_level, max_recursion_level) 388 else: 389 mypkgs.add(fset) 390 391 return mypkgs
392 393 if not package_set.startswith(etpConst['packagesetprefix']): 394 package_set = "%s%s" % (etpConst['packagesetprefix'],package_set,) 395 396 try: 397 mylist = do_expand(package_set, recursion_level, max_recursion_level) 398 except InvalidPackageSet: 399 if raise_exceptions: raise 400 mylist = set() 401 402 return mylist
403
404 - def package_set_list(self, server_repos = [], serverInstance = None, matchRepo = None):
405 return self.package_set_match('', matchRepo = matchRepo, server_repos = server_repos, serverInstance = serverInstance, search = True)[0]
406
407 - def package_set_search(self, package_set, server_repos = [], serverInstance = None, matchRepo = None):
408 # search support 409 if package_set == '*': package_set = '' 410 return self.package_set_match(package_set, matchRepo = matchRepo, server_repos = server_repos, serverInstance = serverInstance, search = True)[0]
411
412 - def __package_set_match_open_db(self, repoid, server_inst):
413 if server_inst != None: 414 dbconn = server_inst.open_server_repository(just_reading = True, repo = repoid) 415 else: 416 dbconn = self.open_repository(repoid) 417 return dbconn
418
419 - def package_set_match(self, package_set, multiMatch = False, 420 matchRepo = None, server_repos = [], serverInstance = None, 421 search = False):
422 423 # support match in repository from shell 424 # set@repo1,repo2,repo3 425 package_set, repos = self.entropyTools.dep_get_match_in_repos( 426 package_set) 427 if (matchRepo == None) and (repos != None): 428 matchRepo = repos 429 430 if server_repos: 431 if not serverInstance: 432 t = _("server_repos needs serverInstance") 433 raise IncorrectParameter("IncorrectParameter: %s" % (t,)) 434 valid_repos = server_repos[:] 435 else: 436 valid_repos = self.validRepositories 437 438 if matchRepo and (type(matchRepo) in (list,tuple,set)): 439 valid_repos = list(matchRepo) 440 441 # if we search, we return all the matches available 442 if search: multiMatch = True 443 444 set_data = [] 445 446 while 1: 447 448 # check inside SystemSettings 449 if not server_repos: 450 sys_pkgsets = self.SystemSettings['system_package_sets'] 451 if search: 452 mysets = [x for x in sys_pkgsets.keys() if \ 453 (x.find(package_set) != -1)] 454 for myset in mysets: 455 mydata = sys_pkgsets.get(myset) 456 set_data.append((etpConst['userpackagesetsid'], 457 unicode(myset), mydata.copy(),)) 458 else: 459 mydata = sys_pkgsets.get(package_set) 460 if mydata is not None: 461 set_data.append((etpConst['userpackagesetsid'], 462 unicode(package_set), mydata,)) 463 if not multiMatch: 464 break 465 466 for repoid in valid_repos: 467 dbconn = self.__package_set_match_open_db(repoid, 468 serverInstance) 469 if search: 470 mysets = dbconn.searchSets(package_set) 471 for myset in mysets: 472 mydata = dbconn.retrievePackageSet(myset) 473 set_data.append((repoid, myset, mydata.copy(),)) 474 else: 475 mydata = dbconn.retrievePackageSet(package_set) 476 if mydata: 477 set_data.append((repoid, package_set, mydata,)) 478 if not multiMatch: 479 break 480 481 break 482 483 if not set_data: 484 return (),False 485 486 if multiMatch: 487 return set_data,True 488 489 return set_data.pop(0),True
490
491 - def get_unsatisfied_dependencies(self, dependencies, deep_deps = False, depcache = None):
492 493 if self.xcache: 494 c_data = sorted(dependencies) 495 client_checksum = self.clientDbconn.checksum() 496 c_hash = hash("%s|%s|%s" % (c_data,deep_deps,client_checksum,)) 497 c_hash = "%s%s" % (etpCache['filter_satisfied_deps'],c_hash,) 498 cached = self.Cacher.pop(c_hash) 499 if cached != None: return cached 500 501 const_debug_write(__name__, 502 "get_unsatisfied_dependencies (not cached, deep: %s) for => %s" % ( 503 deep_deps, dependencies,)) 504 505 if not isinstance(depcache,dict): 506 depcache = {} 507 508 # satisfied dependencies filter support 509 # package.satisfied file support 510 satisfied_kw = '__%s__satisfied_ids' % (__name__,) 511 satisfied_data = self.SystemSettings.get(satisfied_kw) 512 if satisfied_data is None: 513 satisfied_list = self.SystemSettings['satisfied'] 514 tmp_satisfied_data = set() 515 for atom in satisfied_list: 516 matches, m_res = self.atom_match(atom, multiMatch = True, 517 packagesFilter = False, multiRepo = True) 518 if m_res == 0: 519 tmp_satisfied_data |= matches 520 satisfied_data = tmp_satisfied_data 521 self.SystemSettings[satisfied_kw] = satisfied_data 522 523 cdb_am = self.clientDbconn.atomMatch 524 am = self.atom_match 525 open_repo = self.open_repository 526 intf_error = self.dbapi2.InterfaceError 527 cdb_getversioning = self.clientDbconn.getVersioningData 528 etp_cmp = self.entropyTools.entropy_compare_versions 529 etp_get_rev = self.entropyTools.dep_get_entropy_revision 530 531 def fm_dep(dependency): 532 533 cached = depcache.get(dependency) 534 if cached != None: 535 const_debug_write(__name__, 536 "get_unsatisfied_dependencies control cached for => %s" % ( 537 dependency,)) 538 const_debug_write(__name__, "...") 539 return cached 540 541 ### conflict 542 if dependency.startswith("!"): 543 idpackage,rc = cdb_am(dependency[1:]) 544 if idpackage != -1: 545 depcache[dependency] = dependency 546 const_debug_write(__name__, 547 "get_unsatisfied_dependencies conflict not found on system for => %s" % ( 548 dependency,)) 549 const_debug_write(__name__, "...") 550 return dependency 551 depcache[dependency] = 0 552 const_debug_write(__name__, "...") 553 return 0 554 555 c_ids, c_rc = cdb_am(dependency, multiMatch = True) 556 if c_rc != 0: 557 depcache[dependency] = dependency 558 const_debug_write(__name__, 559 "get_unsatisfied_dependencies not satisfied on system for => %s" % ( 560 dependency,)) 561 const_debug_write(__name__, "...") 562 return dependency 563 564 r_id, r_repo = am(dependency) 565 if r_id == -1: 566 depcache[dependency] = dependency 567 const_debug_write(__name__, 568 "get_unsatisfied_dependencies repository match not found for => %s" % ( 569 dependency,)) 570 const_debug_write(__name__, "...") 571 return dependency 572 573 # satisfied dependencies filter support 574 # package.satisfied file support 575 if (r_id, r_repo,) in satisfied_data: 576 return 0 # satisfied 577 578 dbconn = open_repo(r_repo) 579 try: 580 repo_pkgver, repo_pkgtag, repo_pkgrev = dbconn.getVersioningData(r_id) 581 except (intf_error,TypeError,): 582 # package entry is broken 583 const_debug_write(__name__, 584 "get_unsatisfied_dependencies repository entry broken for match => %s" % ( 585 (r_id, r_repo),)) 586 const_debug_write(__name__, "...") 587 return dependency 588 589 client_data = set() 590 for c_id in c_ids: 591 try: 592 installedVer, installedTag, installedRev = cdb_getversioning(c_id) 593 except TypeError: # corrupted entry? 594 installedVer = "0" 595 installedTag = '' 596 installedRev = 0 597 client_data.add((installedVer, installedTag, installedRev,)) 598 599 # support for app-foo/foo-123~-1 600 # -1 revision means, always pull the latest 601 do_deep = deep_deps 602 if not do_deep: 603 string_rev = etp_get_rev(dependency) 604 if string_rev == -1: 605 do_deep = True 606 607 # this is required for multi-slotted packages (like python) 608 # and when people mix Entropy and Portage 609 for installedVer, installedTag, installedRev in client_data: 610 vcmp = etp_cmp((repo_pkgver,repo_pkgtag,repo_pkgrev,), 611 (installedVer,installedTag,installedRev,)) 612 if vcmp == 0: 613 const_debug_write(__name__, 614 "get_unsatisfied_dependencies SATISFIED equals (not cached, deep: %s) => %s" % ( 615 deep_deps, dependency,)) 616 depcache[dependency] = 0 617 const_debug_write(__name__, "...") 618 return 0 619 ver_tag_repo = (repo_pkgver, repo_pkgtag,) 620 ver_tag_inst = (installedVer, installedTag,) 621 rev_match = repo_pkgrev != installedRev 622 623 if not do_deep and (ver_tag_repo == ver_tag_inst) and rev_match: 624 625 depcache[dependency] = 0 626 const_debug_write(__name__, 627 "get_unsatisfied_dependencies SATISFIED w/o rev (not cached, deep: %s) => %s" % ( 628 deep_deps, dependency,)) 629 const_debug_write(__name__, "...") 630 return 0 631 632 # if we get here it means that there are no matching packages 633 const_debug_write(__name__, 634 "get_unsatisfied_dependencies NOT SATISFIED (not cached, deep: %s) => %s" % ( 635 deep_deps, dependency,)) 636 637 depcache[dependency] = dependency 638 const_debug_write(__name__, "...") 639 return dependency
640 641 unsatisfied = map(fm_dep,dependencies) 642 unsatisfied = set([x for x in unsatisfied if x != 0]) 643 644 if self.xcache: 645 self.Cacher.push(c_hash,unsatisfied) 646 647 return unsatisfied 648
649 - def get_masked_packages_tree(self, match, atoms = False, flat = False, matchfilter = None):
650 651 if not isinstance(matchfilter,set): 652 matchfilter = set() 653 654 maskedtree = {} 655 mybuffer = Lifo() 656 depcache = set() 657 treelevel = -1 658 659 match_id, match_repo = match 660 661 mydbconn = self.open_repository(match_repo) 662 myatom = mydbconn.retrieveAtom(match_id) 663 idpackage, idreason = mydbconn.idpackageValidator(match_id) 664 if idpackage == -1: 665 treelevel += 1 666 if atoms: 667 mydict = {myatom: idreason,} 668 else: 669 mydict = {match: idreason,} 670 if flat: 671 maskedtree.update(mydict) 672 else: 673 maskedtree[treelevel] = mydict 674 675 mydeps = mydbconn.retrieveDependencies(match_id) 676 for mydep in mydeps: mybuffer.push(mydep) 677 try: 678 mydep = mybuffer.pop() 679 except ValueError: 680 mydep = None # stack empty 681 682 open_db = self.open_repository 683 am = self.atom_match 684 while mydep: 685 686 if mydep in depcache: 687 try: 688 mydep = mybuffer.pop() 689 except ValueError: 690 break # stack empty 691 continue 692 depcache.add(mydep) 693 694 idpackage, repoid = am(mydep) 695 if (idpackage, repoid) in matchfilter: 696 try: 697 mydep = mybuffer.pop() 698 except ValueError: 699 break # stack empty 700 continue 701 702 if idpackage != -1: 703 # doing even here because atomMatch with packagesFilter = False can pull 704 # something different 705 matchfilter.add((idpackage, repoid)) 706 707 # collect masked 708 if idpackage == -1: 709 idpackage, repoid = am(mydep, packagesFilter = False) 710 if idpackage != -1: 711 treelevel += 1 712 if not maskedtree.has_key(treelevel) and not flat: 713 maskedtree[treelevel] = {} 714 dbconn = open_db(repoid) 715 vidpackage, idreason = dbconn.idpackageValidator(idpackage) 716 if atoms: 717 mydict = {dbconn.retrieveAtom(idpackage): idreason} 718 else: 719 mydict = {(idpackage,repoid): idreason} 720 if flat: maskedtree.update(mydict) 721 else: maskedtree[treelevel].update(mydict) 722 723 # push its dep into the buffer 724 if idpackage != -1: 725 matchfilter.add((idpackage, repoid)) 726 dbconn = open_db(repoid) 727 owndeps = dbconn.retrieveDependencies(idpackage) 728 for owndep in owndeps: 729 mybuffer.push(owndep) 730 731 try: 732 mydep = mybuffer.pop() 733 except ValueError: 734 break # stack empty 735 736 return maskedtree
737 738
739 - def generate_dependency_tree(self, 740 matched_atom, empty_deps = False, deep_deps = False, matchfilter = None, 741 flat = False, filter_unsat_cache = None, treecache = None, keyslotcache = None):
742 743 if not isinstance(matchfilter,set): 744 matchfilter = set() 745 if not isinstance(filter_unsat_cache,dict): 746 filter_unsat_cache = {} 747 if not isinstance(treecache,set): 748 treecache = set() 749 if not isinstance(keyslotcache,set): 750 keyslotcache = set() 751 752 mydbconn = self.open_repository(matched_atom[1]) 753 myatom = mydbconn.retrieveAtom(matched_atom[0]) 754 755 # caches 756 # special events 757 deps_not_found = set() 758 conflicts = set() 759 760 mydep = (1,myatom) 761 mybuffer = Lifo() 762 deptree = set() 763 if matched_atom not in matchfilter: 764 deptree.add((1,matched_atom)) 765 766 virgin = True 767 open_repo = self.open_repository 768 atom_match = self.atom_match 769 cdb_atom_match = self.clientDbconn.atomMatch 770 lookup_conflict_replacement = self._lookup_conflict_replacement 771 lookup_library_breakages = self._lookup_library_breakages 772 lookup_inverse_dependencies = self._lookup_inverse_dependencies 773 get_unsatisfied_deps = self.get_unsatisfied_dependencies 774 775 def my_dep_filter(x): 776 if x in treecache: return False 777 if tuple(x.split(":")) in keyslotcache: return False 778 return True
779 780 while mydep: 781 782 const_debug_write(__name__, 783 "generate_dependency_tree analyzing => %s" % ( 784 mydep,)) 785 786 dep_level, dep_atom = mydep 787 788 # already analyzed in this call 789 if dep_atom in treecache: 790 const_debug_write(__name__, 791 "generate_dependency_tree already in treecache => %s" % ( 792 dep_atom,)) 793 try: 794 mydep = mybuffer.pop() 795 except ValueError: 796 const_debug_write(__name__, "---empty--") 797 break # stack empty 798 const_debug_write(__name__, "---") 799 continue 800 treecache.add(dep_atom) 801 802 if dep_atom is None: # corrupted entry 803 const_debug_write(__name__, 804 "generate_dependency_tree broken entry in DB => %s" % ( 805 mydep,)) 806 try: 807 mydep = mybuffer.pop() 808 except ValueError: 809 const_debug_write(__name__, "---empty2--") 810 break # stack empty 811 const_debug_write(__name__, "---") 812 continue 813 814 # conflicts 815 if dep_atom[0] == "!": 816 c_idpackage, xst = cdb_atom_match(dep_atom[1:]) 817 if c_idpackage != -1: 818 myreplacement = lookup_conflict_replacement(dep_atom[1:], 819 c_idpackage, deep_deps = deep_deps) 820 821 const_debug_write(__name__, 822 "generate_dependency_tree conflict replacement => %s" % ( 823 myreplacement,)) 824 825 if (myreplacement != None) and (myreplacement not in treecache): 826 mybuffer.push((dep_level+1,myreplacement)) 827 else: 828 conflicts.add(c_idpackage) 829 try: 830 mydep = mybuffer.pop() 831 except ValueError: 832 const_debug_write(__name__, "---empty3---") 833 break # stack empty 834 const_debug_write(__name__, "---") 835 continue 836 837 # atom found? 838 if virgin: 839 840 virgin = False 841 m_idpackage, m_repo = matched_atom 842 dbconn = open_repo(m_repo) 843 myidpackage, idreason = dbconn.idpackageValidator(m_idpackage) 844 845 const_debug_write(__name__, 846 "generate_dependency_tree virgin match masked? => %s - %s" % ( 847 myidpackage, idreason,)) 848 849 if myidpackage == -1: 850 m_idpackage = -1 851 852 else: 853 m_idpackage, m_repo = atom_match(dep_atom) 854 const_debug_write(__name__, 855 "generate_dependency_tree matching %s => (%s, %s)" % ( 856 dep_atom, m_idpackage, m_repo,)) 857 858 if m_idpackage == -1: 859 860 const_debug_write(__name__, 861 "generate_dependency_tree dep not found => %s" % ( 862 dep_atom,)) 863 864 deps_not_found.add(dep_atom) 865 try: 866 mydep = mybuffer.pop() 867 except ValueError: 868 const_debug_write(__name__, "---empty3---") 869 break # stack empty 870 const_debug_write(__name__, "---") 871 continue 872 873 # check if atom has been already pulled in 874 matchdb = open_repo(m_repo) 875 matchatom = matchdb.retrieveAtom(m_idpackage) 876 matchkey, matchslot = matchdb.retrieveKeySlot(m_idpackage) 877 878 const_debug_write(__name__, 879 "generate_dependency_tree idpackage %s => %s - %s:%s" % ( 880 m_idpackage, matchatom, matchkey, matchslot)) 881 882 if (dep_atom != matchatom) and (matchatom in treecache): 883 try: 884 mydep = mybuffer.pop() 885 except ValueError: 886 const_debug_write(__name__, "---empty4---") 887 break # stack empty 888 const_debug_write(__name__, 889 "generate_dependency_tree matchatom %s already in cache" % ( 890 matchatom,)) 891 const_debug_write(__name__, "---") 892 continue 893 894 treecache.add(matchatom) 895 896 const_debug_write(__name__, 897 "generate_dependency_tree check if key + slot cache => %s" % ( 898 (matchslot, matchkey),)) 899 900 # check if key + slot has been already pulled in 901 if (matchslot, matchkey) in keyslotcache: 902 try: 903 mydep = mybuffer.pop() 904 except ValueError: 905 const_debug_write(__name__, "---empty5---") 906 break # stack empty 907 const_debug_write(__name__, "---") 908 continue 909 else: 910 keyslotcache.add((matchslot, matchkey)) 911 912 const_debug_write(__name__, 913 "generate_dependency_tree not in key + slot cache => %s" % ( 914 (matchslot, matchkey),)) 915 916 match = (m_idpackage, m_repo,) 917 # result already analyzed? 918 if match in matchfilter: 919 try: 920 mydep = mybuffer.pop() 921 except ValueError: 922 const_debug_write(__name__, "---empty6---") 923 break # stack empty 924 const_debug_write(__name__, "---") 925 continue 926 927 const_debug_write(__name__, 928 "generate_dependency_tree match NOT already analyzed => %s" % ( 929 match,)) 930 931 # all checks passed, well done 932 matchfilter.add(match) 933 treedepth = dep_level+1 934 deptree.add((dep_level,match)) # add match 935 936 # extra hooks 937 cm_idpackage, cm_result = cdb_atom_match(matchkey, 938 matchSlot = matchslot) 939 if cm_idpackage != -1: 940 941 broken_atoms = lookup_library_breakages(match, 942 (cm_idpackage, cm_result,), deep_deps = deep_deps) 943 const_debug_write(__name__, 944 "generate_dependency_tree lib broken atoms for %s => %s" % ( 945 matchkey+":"+matchslot, broken_atoms,)) 946 947 inverse_deps = lookup_inverse_dependencies(match, 948 (cm_idpackage, cm_result,)) 949 const_debug_write(__name__, 950 "generate_dependency_tree inverse deps for %s => %s" % ( 951 matchkey+":"+matchslot, inverse_deps,)) 952 953 if inverse_deps: 954 deptree.remove((dep_level,match)) 955 for ikey,islot in inverse_deps: 956 iks_str = '%s:%s' % (ikey,islot,) 957 if ((ikey,islot) not in keyslotcache) and (iks_str not in treecache): 958 mybuffer.push((dep_level,iks_str)) 959 keyslotcache.add((ikey,islot)) 960 deptree.add((treedepth,match)) 961 treedepth += 1 962 963 for x in broken_atoms: 964 if (tuple(x.split(":")) not in keyslotcache) and (x not in treecache): 965 mybuffer.push((treedepth,x)) 966 967 m_deplist = matchdb.retrieveDependenciesList(m_idpackage) 968 969 const_debug_write(__name__, 970 "generate_dependency_tree dependency list for %s => %s" % ( 971 m_idpackage, m_deplist,)) 972 973 myundeps = filter(my_dep_filter, m_deplist) 974 975 const_debug_write(__name__, 976 "generate_dependency_tree filtered dependency list => %s" % ( 977 myundeps,)) 978 979 if not empty_deps: 980 981 m_unsat_deplist = get_unsatisfied_deps(myundeps, deep_deps, 982 depcache = filter_unsat_cache) 983 984 const_debug_write(__name__, 985 "generate_dependency_tree unsatisfied dependencies (deep: %s) => %s" % ( 986 deep_deps, m_unsat_deplist,)) 987 988 myundeps = filter(my_dep_filter, m_unsat_deplist) 989 990 const_debug_write(__name__, 991 "generate_dependency_tree filtered UNSATISFIED dependencies => %s" % ( 992 myundeps,)) 993 994 # PDEPENDs support 995 if myundeps: 996 997 post_deps = [x for x in \ 998 matchdb.retrievePostDependencies(m_idpackage) if x \ 999 in myundeps] 1000 1001 const_debug_write(__name__, 1002 "generate_dependency_tree POST dependencies => %s" % ( 1003 post_deps,)) 1004 1005 if post_deps: 1006 1007 # do some filtering 1008 # it is correct to not use my_dep_filter here 1009 myundeps = [x for x in myundeps if x not in post_deps] 1010 1011 const_debug_write(__name__, 1012 "generate_dependency_tree POST dependencies ADDED => %s" % ( 1013 myundeps,)) 1014 1015 for x in post_deps: 1016 mybuffer.push((-1, x)) # always after the package itself 1017 1018 for x in myundeps: 1019 mybuffer.push((treedepth, x)) 1020 1021 try: 1022 mydep = mybuffer.pop() 1023 except ValueError: 1024 const_debug_write(__name__, "---empty7---") 1025 break # stack empty 1026 const_debug_write(__name__, "---") 1027 1028 if deps_not_found: 1029 return list(deps_not_found), -2 1030 1031 if flat: 1032 return [x[1] for x in deptree], 0 1033 1034 newdeptree = {} 1035 for key, item in deptree: 1036 if key >= 0: 1037 # this makes sure that key is never = 0 1038 key += 1 1039 obj = newdeptree.setdefault(key, set()) 1040 obj.add(item) 1041 # conflicts 1042 newdeptree[0] = conflicts 1043 1044 return newdeptree,0 # note: newtree[0] contains possible conflicts 1045 1046
1047 - def _lookup_system_mask_repository_deps(self):
1048 1049 client_settings = self.SystemSettings[self.sys_settings_client_plugin_id] 1050 data = client_settings['repositories']['system_mask'] 1051 1052 if not data: 1053 return [] 1054 mydata = [] 1055 cached_items = set() 1056 for atom in data: 1057 mymatch = self.atom_match(atom) 1058 if mymatch[0] == -1: # ignore missing ones intentionally 1059 continue 1060 if mymatch in cached_items: 1061 continue 1062 if mymatch not in mydata: 1063 # check if not found 1064 myaction = self.get_package_action(mymatch) 1065 # only if the package is not installed 1066 if myaction == 1: mydata.append(mymatch) 1067 cached_items.add(mymatch) 1068 return mydata
1069
1070 - def _lookup_conflict_replacement(self, conflict_atom, client_idpackage, deep_deps):
1071 if self.entropyTools.isjustname(conflict_atom): 1072 return None 1073 conflict_match = self.atom_match(conflict_atom) 1074 mykey, myslot = self.clientDbconn.retrieveKeySlot(client_idpackage) 1075 new_match = self.atom_match(mykey, matchSlot = myslot) 1076 if (conflict_match == new_match) or (new_match[1] == 1): 1077 return None 1078 action = self.get_package_action(new_match) 1079 if (action == 0) and (not deep_deps): 1080 return None 1081 return "%s:%s" % (mykey,myslot,)
1082
1083 - def _lookup_inverse_dependencies(self, match, clientmatch):
1084 1085 cmpstat = self.get_package_action(match) 1086 if cmpstat == 0: return set() 1087 1088 keyslots = set() 1089 mydepends = self.clientDbconn.retrieveReverseDependencies(clientmatch[0]) 1090 am = self.atom_match 1091 cdb_rdeps = self.clientDbconn.retrieveDependencies 1092 cdb_rks = self.clientDbconn.retrieveKeySlot 1093 gpa = self.get_package_action 1094 keyslots_cache = set() 1095 match_cache = {} 1096 1097 for idpackage in mydepends: 1098 try: 1099 key, slot = cdb_rks(idpackage) 1100 except TypeError: 1101 continue 1102 if (key,slot) in keyslots_cache: continue 1103 keyslots_cache.add((key,slot)) 1104 if (key,slot) in keyslots: continue 1105 # grab its deps 1106 mydeps = cdb_rdeps(idpackage) 1107 found = False 1108 for mydep in mydeps: 1109 mymatch = match_cache.get(mydep, 0) 1110 if mymatch == 0: 1111 mymatch = am(mydep) 1112 match_cache[mydep] = mymatch 1113 if mymatch == match: 1114 found = True 1115 break 1116 if not found: 1117 mymatch = am(key, matchSlot = slot) 1118 if mymatch[0] == -1: continue 1119 cmpstat = gpa(mymatch) 1120 if cmpstat == 0: continue 1121 keyslots.add((key,slot)) 1122 1123 return keyslots
1124
1125 - def __get_lib_breaks_client_and_repo_side(self, match_db, match_idpackage, client_idpackage):
1126 repo_needed = match_db.retrieveNeeded(match_idpackage, extended = True, format = True) 1127 client_needed = self.clientDbconn.retrieveNeeded(client_idpackage, extended = True, format = True) 1128 repo_split = [x.split(".so")[0] for x in repo_needed] 1129 client_split = [x.split(".so")[0] for x in client_needed] 1130 client_side = [x for x in client_needed if (x not in repo_needed) and (x.split(".so")[0] in repo_split)] 1131 repo_side = [x for x in repo_needed if (x not in client_needed) and (x.split(".so")[0] in client_split)] 1132 return repo_needed, client_side, repo_side
1133
1134 - def _lookup_library_breakages(self, match, clientmatch, deep_deps = False):
1135 1136 # there is no need to update this cache when "match" 1137 # will be installed, because at that point 1138 # clientmatch[0] will differ. 1139 c_hash = "%s|%s|%s" % ( 1140 tuple(match), 1141 deep_deps, 1142 tuple(clientmatch), 1143 ) 1144 c_hash = "%s%s" % (etpCache['library_breakage'], hash(c_hash),) 1145 if self.xcache: 1146 cached = self.Cacher.pop(c_hash) 1147 if cached != None: return cached 1148 1149 # these should be pulled in before 1150 repo_atoms = set() 1151 # these can be pulled in after 1152 client_atoms = set() 1153 1154 matchdb = self.open_repository(match[1]) 1155 reponeeded, client_side, repo_side = self.__get_lib_breaks_client_and_repo_side(matchdb, 1156 match[0], clientmatch[0]) 1157 1158 # all the packages in client_side should be pulled in and updated 1159 client_idpackages = set() 1160 for needed in client_side: client_idpackages |= self.clientDbconn.searchNeeded(needed) 1161 1162 client_keyslots = set() 1163 def mymf(idpackage): 1164 if idpackage == clientmatch[0]: 1165 return 0 1166 ks = self.clientDbconn.retrieveKeySlot(idpackage) 1167 if ks is None: 1168 return 0 1169 return ks
1170 client_keyslots = set([x for x in map(mymf,client_idpackages) if x != 0]) 1171 1172 # all the packages in repo_side should be pulled in too 1173 repodata = {} 1174 for needed in repo_side: 1175 repodata[needed] = reponeeded[needed] 1176 del repo_side,reponeeded 1177 1178 repo_dependencies = matchdb.retrieveDependencies(match[0]) 1179 matched_deps = set() 1180 matched_repos = set() 1181 for dependency in repo_dependencies: 1182 depmatch = self.atom_match(dependency) 1183 if depmatch[0] == -1: 1184 continue 1185 matched_repos.add(depmatch[1]) 1186 matched_deps.add(depmatch) 1187 1188 matched_repos = [x for x in self.SystemSettings['repositories']['order'] \ 1189 if x in matched_repos] 1190 found_matches = set() 1191 for needed in repodata: 1192 for myrepo in matched_repos: 1193 mydbc = self.open_repository(myrepo) 1194 solved_needed = mydbc.resolveNeeded(needed, 1195 repodata[needed]) 1196 found = False 1197 for idpackage in solved_needed: 1198 x = (idpackage, myrepo) 1199 if x in matched_deps: 1200 found_matches.add(x) 1201 found = True 1202 break 1203 if found: 1204 break 1205 1206 for idpackage,repo in found_matches: 1207 if not deep_deps: 1208 cmpstat = self.get_package_action((idpackage,repo)) 1209 if cmpstat == 0: 1210 continue 1211 mydbc = self.open_repository(repo) 1212 repo_atoms.add(mydbc.retrieveAtom(idpackage)) 1213 1214 for key, slot in client_keyslots: 1215 idpackage, repo = self.atom_match(key, matchSlot = slot) 1216 if idpackage == -1: 1217 continue 1218 if not deep_deps: 1219 cmpstat = self.get_package_action((idpackage, repo)) 1220 if cmpstat == 0: 1221 continue 1222 mydbc = self.open_repository(repo) 1223 client_atoms.add(mydbc.retrieveAtom(idpackage)) 1224 1225 client_atoms |= repo_atoms 1226 1227 if self.xcache: 1228 self.Cacher.push(c_hash,client_atoms) 1229 1230 return client_atoms 1231 1232
1233 - def get_required_packages(self, matched_atoms, empty_deps = False, deep_deps = False, quiet = False):
1234 1235 c_hash = "%s%s" % ( 1236 etpCache['dep_tree'], 1237 hash("%s|%s|%s|%s|%s" % ( 1238 hash(frozenset(sorted(matched_atoms))), 1239 empty_deps, 1240 deep_deps, 1241 self.clientDbconn.checksum(), 1242 # needed when users do bogus things like editing config files 1243 # manually (branch setting) 1244 self.SystemSettings['repositories']['branch'], 1245 )),) 1246 if self.xcache: 1247 cached = self.Cacher.pop(c_hash) 1248 if cached != None: return cached 1249 1250 deptree = {} 1251 deptree[0] = set() 1252 1253 atomlen = len(matched_atoms); count = 0 1254 error_generated = 0 1255 error_tree = set() 1256 1257 # check if there are repositories needing some mandatory packages 1258 forced_matches = self._lookup_system_mask_repository_deps() 1259 if forced_matches: 1260 if isinstance(matched_atoms, list): 1261 matched_atoms = forced_matches + [x for x in matched_atoms if x not in forced_matches] 1262 elif isinstance(matched_atoms, set): # we cannot do anything about the order here 1263 matched_atoms |= set(forced_matches) 1264 1265 sort_dep_text = _("Sorting dependencies") 1266 filter_unsat_cache = {} 1267 treecache = set() 1268 keyslotcache = set() 1269 matchfilter = set() 1270 for matched_atom in matched_atoms: 1271 const_debug_write(__name__, 1272 "get_required_packages matched_atom => %s" % (matched_atom,)) 1273 1274 if not quiet: 1275 count += 1 1276 if (count%10 == 0) or (count == atomlen) or (count == 1): 1277 self.updateProgress(sort_dep_text, importance = 0, type = "info", 1278 back = True, header = ":: ", footer = " ::", 1279 percent = True, count = (count,atomlen)) 1280 1281 if matched_atom in matchfilter: continue 1282 newtree, result = self.generate_dependency_tree( 1283 matched_atom, empty_deps, deep_deps, 1284 matchfilter = matchfilter, filter_unsat_cache = filter_unsat_cache, treecache = treecache, 1285 keyslotcache = keyslotcache 1286 ) 1287 1288 const_debug_write(__name__, 1289 "get_required_packages deptree => %s -- %s" % ( 1290 newtree, result,)) 1291 1292 if result == -2: # deps not found 1293 error_generated = -2 1294 error_tree |= set(newtree) # it is a list, we convert it into set and update error_tree 1295 elif (result != 0): 1296 return newtree, result 1297 elif newtree: 1298 # add conflicts 1299 max_parent_key = max(deptree) 1300 deptree[0] |= newtree.pop(0) 1301 levelcount = 0 1302 for mylevel in sorted(newtree.keys(), reverse = True): 1303 levelcount += 1 1304 deptree[max_parent_key+levelcount] = newtree.get(mylevel) 1305 1306 if error_generated != 0: 1307 return error_tree,error_generated 1308 1309 if self.xcache: 1310 self.Cacher.push(c_hash,(deptree,0)) 1311 1312 return deptree,0
1313
1314 - def _filter_depends_multimatched_atoms(self, idpackage, depends, monotree):
1315 remove_depends = set() 1316 for d_idpackage in depends: 1317 mydeps = self.clientDbconn.retrieveDependencies(d_idpackage) 1318 for mydep in mydeps: 1319 matches, rslt = self.clientDbconn.atomMatch(mydep, multiMatch = True) 1320 if rslt == 1: continue 1321 if idpackage in matches and len(matches) > 1: 1322 # are all in depends? 1323 for mymatch in matches: 1324 if mymatch not in depends and mymatch not in monotree: 1325 remove_depends.add(d_idpackage) 1326 break 1327 depends -= remove_depends 1328 return depends
1329 1330
1331 - def generate_depends_tree(self, idpackages, deep = False):
1332 1333 c_hash = "%s%s" % ( 1334 etpCache['depends_tree'], 1335 hash("%s|%s" % ( 1336 tuple(sorted(idpackages)), 1337 deep, 1338 ), 1339 ), 1340 ) 1341 if self.xcache: 1342 cached = self.Cacher.pop(c_hash) 1343 if cached != None: return cached 1344 1345 dependscache = set() 1346 treeview = set(idpackages) 1347 treelevel = set(idpackages) 1348 tree = {} 1349 # I start from level 1 because level 0 is idpackages itself 1350 treedepth = 0 1351 tree[treedepth] = set(idpackages) 1352 monotree = set(idpackages) # monodimensional tree 1353 1354 # post-dependencies won't be pulled in 1355 pdepend_id = etpConst['spm']['pdepend_id'] 1356 # check if dependstable is sane before beginning 1357 self.clientDbconn.retrieveReverseDependencies(idpackages[0]) 1358 count = 0 1359 1360 rem_dep_text = _("Calculating inverse dependencies for") 1361 while 1: 1362 treedepth += 1 1363 tree[treedepth] = set() 1364 for idpackage in treelevel: 1365 1366 count += 1 1367 p_atom = self.clientDbconn.retrieveAtom(idpackage) 1368 self.updateProgress( 1369 blue(rem_dep_text + " %s" % (red(p_atom),)), 1370 importance = 0, 1371 type = "info", 1372 back = True, 1373 header = '|/-\\'[count%4]+" " 1374 ) 1375 1376 systempkg = not self.validate_package_removal(idpackage) 1377 if (idpackage in dependscache) or systempkg: 1378 if idpackage in treeview: 1379 treeview.remove(idpackage) 1380 continue 1381 1382 # obtain its inverse deps 1383 depends = self.clientDbconn.retrieveReverseDependencies(idpackage, 1384 exclude_deptypes = (pdepend_id,)) 1385 # filter already satisfied ones 1386 depends = set([x for x in depends if x not in monotree]) 1387 depends = set([x for x in depends if \ 1388 self.validate_package_removal(x)]) 1389 if depends: 1390 depends = self._filter_depends_multimatched_atoms( 1391 idpackage, depends, monotree) 1392 if depends: # something depends on idpackage 1393 tree[treedepth] |= depends 1394 monotree |= depends 1395 treeview |= depends 1396 elif deep: # if deep, grab its dependencies and check 1397 1398 mydeps = set() 1399 for x in self.clientDbconn.retrieveDependencies(idpackage): 1400 match = self.clientDbconn.atomMatch(x) 1401 if match[0] != -1: 1402 mydeps.add(match[0]) 1403 1404 # now filter them 1405 mydeps = [x for x in mydeps if x not in monotree and not \ 1406 (self.clientDbconn.isSystemPackage(x) or \ 1407 self.is_installed_idpackage_in_system_mask(x) )] 1408 for x in mydeps: 1409 mydepends = self.clientDbconn.retrieveReverseDependencies(x) 1410 mydepends -= set([y for y in mydepends if y \ 1411 not in monotree]) 1412 if not mydepends: 1413 tree[treedepth].add(x) 1414 monotree.add(x) 1415 treeview.add(x) 1416 1417 dependscache.add(idpackage) 1418 if idpackage in treeview: 1419 treeview.remove(idpackage) 1420 1421 treelevel = treeview.copy() 1422 if not treelevel: 1423 if not tree[treedepth]: 1424 del tree[treedepth] # probably the last one is empty then 1425 break 1426 1427 # now filter newtree 1428 for count in sorted(tree.keys(), reverse = True): 1429 x = 0 1430 while x < count: 1431 tree[x] -= tree[count] 1432 x += 1 1433 1434 if self.xcache: 1435 self.Cacher.push(c_hash,(tree,0)) 1436 # treeview is used to show deps while 1437 # tree is used to run the dependency code. 1438 return tree,0
1439
1440 - def calculate_available_packages(self, use_cache = True):
1441 1442 c_hash = self.get_available_packages_chash() 1443 if use_cache and self.xcache: 1444 cached = self.get_available_packages_cache(myhash = c_hash) 1445 if cached != None: 1446 return cached 1447 1448 available = [] 1449 self.setTotalCycles(len(self.validRepositories)) 1450 avail_dep_text = _("Calculating available packages for") 1451 for repo in self.validRepositories: 1452 try: 1453 dbconn = self.open_repository(repo) 1454 dbconn.validateDatabase() 1455 except (RepositoryError, SystemDatabaseError): 1456 self.cycleDone() 1457 continue 1458 try: 1459 # db may be corrupted, we cannot deal with it here 1460 idpackages = [x for x in dbconn.listAllIdpackages( 1461 order_by = 'atom') if dbconn.idpackageValidator(x)[0] != -1] 1462 except dbconn.dbapi2.OperationalError: 1463 self.cycleDone() 1464 continue 1465 count = 0 1466 maxlen = len(idpackages) 1467 myavailable = [] 1468 do_break = False 1469 for idpackage in idpackages: 1470 if do_break: 1471 break 1472 count += 1 1473 if (count % 10 == 0) or (count == 1) or (count == maxlen): 1474 self.updateProgress( 1475 avail_dep_text + " %s" % (repo,), 1476 importance = 0, 1477 type = "info", 1478 back = True, 1479 header = "::", 1480 count = (count,maxlen), 1481 percent = True, 1482 footer = " ::" 1483 ) 1484 # get key + slot 1485 try: 1486 key, slot = dbconn.retrieveKeySlot(idpackage) 1487 matches = self.clientDbconn.searchKeySlot(key, slot) 1488 except (self.dbapi2.DatabaseError,self.dbapi2.IntegrityError,self.dbapi2.OperationalError,): 1489 self.cycleDone() 1490 do_break = True 1491 continue 1492 if not matches: myavailable.append((idpackage,repo)) 1493 available += myavailable[:] 1494 self.cycleDone() 1495 1496 if self.xcache: 1497 self.Cacher.push("%s%s" % ( 1498 etpCache['world_available'], c_hash), available) 1499 return available
1500
1501 - def calculate_critical_updates(self, use_cache = True):
1502 1503 # check if we are branch migrating 1504 # in this case, critical pkgs feature is disabled 1505 in_branch_upgrade = etpConst['etp_in_branch_upgrade_file'] 1506 if os.access(in_branch_upgrade, os.R_OK | os.F_OK): 1507 return set(), [] 1508 1509 db_digest = self.all_repositories_checksum() 1510 if use_cache and self.xcache: 1511 cached = self.get_critical_updates_cache(db_digest = db_digest) 1512 if cached != None: 1513 return cached 1514 1515 client_settings = self.SystemSettings[self.sys_settings_client_plugin_id] 1516 critical_data = client_settings['repositories']['critical_updates'] 1517 1518 atoms = set() 1519 atom_matches = {} 1520 for repoid in critical_data: 1521 for atom in critical_data[repoid]: 1522 match_id, match_repo = self.atom_match(atom) 1523 if match_repo == 1: 1524 continue 1525 atom_matches[atom] = (match_id, match_repo,) 1526 atoms.add(atom) 1527 1528 atoms = self.get_unsatisfied_dependencies(atoms) 1529 matches = [atom_matches.get(atom) for atom in atoms] 1530 data = (atoms, matches) 1531 1532 if self.xcache: 1533 c_hash = self.get_critical_update_cache_hash(db_digest) 1534 self.Cacher.push("%s%s" % (etpCache['critical_update'], c_hash,), 1535 data, async = False) 1536 1537 return data
1538 1539
1540 - def calculate_world_updates(self, empty_deps = False, use_cache = True, 1541 critical_updates = True):
1542 1543 cl_settings = self.SystemSettings[self.sys_settings_client_plugin_id] 1544 misc_settings = cl_settings['misc'] 1545 update = [] 1546 remove = [] 1547 fine = [] 1548 spm_fine = [] 1549 1550 # critical updates hook, if enabled 1551 # this will force callers to receive only critical updates 1552 if misc_settings.get('forcedupdates') and critical_updates: 1553 upd_atoms, upd_matches = self.calculate_critical_updates( 1554 use_cache = use_cache) 1555 if upd_atoms: 1556 return upd_matches, remove, fine, spm_fine 1557 1558 db_digest = self.all_repositories_checksum() 1559 if use_cache and self.xcache: 1560 cached = self.get_world_update_cache(empty_deps = empty_deps, 1561 db_digest = db_digest) 1562 if cached != None: 1563 return cached 1564 1565 1566 ignore_spm_downgrades = misc_settings['ignore_spm_downgrades'] 1567 1568 # get all the installed packages 1569 try: 1570 idpackages = self.clientDbconn.listAllIdpackages(order_by = 'atom') 1571 except self.dbapi2.OperationalError: 1572 # client db is broken! 1573 raise SystemDatabaseError("installed packages database is broken") 1574 1575 maxlen = len(idpackages) 1576 count = 0 1577 mytxt = _("Calculating world packages") 1578 for idpackage in idpackages: 1579 1580 count += 1 1581 if (count%10 == 0) or (count == maxlen) or (count == 1): 1582 self.updateProgress( 1583 mytxt, 1584 importance = 0, 1585 type = "info", 1586 back = True, 1587 header = ":: ", 1588 count = (count,maxlen), 1589 percent = True, 1590 footer = " ::" 1591 ) 1592 1593 try: 1594 cl_pkgkey, cl_slot, cl_version, \ 1595 cl_tag, cl_revision, \ 1596 cl_atom = self.clientDbconn.getStrictData(idpackage) 1597 except TypeError: 1598 # check against broken entries, or removed during iteration 1599 continue 1600 use_match_cache = True 1601 do_continue = False 1602 while 1: 1603 try: 1604 match = self.atom_match( 1605 cl_pkgkey, 1606 matchSlot = cl_slot, 1607 extendedResults = True, 1608 useCache = use_match_cache 1609 ) 1610 except self.dbapi2.OperationalError: 1611 # ouch, but don't crash here 1612 do_continue = True 1613 break 1614 try: 1615 m_idpackage = match[0][0] 1616 except TypeError: 1617 if not use_match_cache: raise 1618 use_match_cache = False 1619 continue 1620 break 1621 if do_continue: continue 1622 # now compare 1623 # version: cl_version 1624 # tag: cl_tag 1625 # revision: cl_revision 1626 if (m_idpackage != -1): 1627 repoid = match[1] 1628 version = match[0][1] 1629 tag = match[0][2] 1630 revision = match[0][3] 1631 if empty_deps: 1632 if (m_idpackage,repoid) not in update: 1633 update.append((m_idpackage,repoid)) 1634 continue 1635 elif (cl_revision != revision): 1636 # different revision 1637 if cl_revision == 9999 and ignore_spm_downgrades: 1638 # no difference, we're ignoring revision 9999 1639 fine.append(cl_atom) 1640 if (m_idpackage,repoid) not in update: 1641 spm_fine.append((m_idpackage,repoid)) 1642 continue 1643 else: 1644 if (m_idpackage,repoid) not in update: 1645 update.append((m_idpackage,repoid)) 1646 continue 1647 elif (cl_version != version): 1648 # different versions 1649 if (m_idpackage,repoid) not in update: 1650 update.append((m_idpackage,repoid)) 1651 continue 1652 elif (cl_tag != tag): 1653 # different tags 1654 if (m_idpackage,repoid) not in update: 1655 update.append((m_idpackage,repoid)) 1656 continue 1657 else: 1658 # no difference 1659 fine.append(cl_atom) 1660 continue 1661 1662 # don't take action if it's just masked 1663 maskedresults = self.atom_match(cl_pkgkey, matchSlot = cl_slot, 1664 packagesFilter = False) 1665 if maskedresults[0] == -1: 1666 remove.append(idpackage) 1667 # look for packages that would match key 1668 # with any slot (for eg: gcc, kernel updates) 1669 matchresults = self.atom_match(cl_pkgkey) 1670 if matchresults[0] != -1: 1671 m_action = self.get_package_action(matchresults) 1672 if m_action > 0 and (matchresults not in update): 1673 update.append(matchresults) 1674 1675 if self.xcache: 1676 c_hash = self.get_world_update_cache_hash(db_digest, empty_deps, 1677 ignore_spm_downgrades) 1678 data = (update, remove, fine, spm_fine,) 1679 self.Cacher.push("%s%s" % (etpCache['world_update'],c_hash,), 1680 data, async = False) 1681 1682 if not update: 1683 # delete branch upgrade file if exists, since there are 1684 # no updates, this file does not deserve to be saved anyway 1685 br_path = etpConst['etp_in_branch_upgrade_file'] 1686 if os.access(br_path, os.W_OK | os.F_OK): 1687 os.remove(br_path) 1688 1689 return update, remove, fine, spm_fine
1690
1691 - def check_package_update(self, atom, deep = False):
1692 1693 c_hash = "%s%s" % (etpCache['check_package_update'], 1694 hash("%s%s" % (atom, deep,) 1695 ), 1696 ) 1697 if self.xcache: 1698 cached = self.Cacher.pop(c_hash) 1699 if cached != None: 1700 return cached 1701 1702 found = False 1703 match = self.clientDbconn.atomMatch(atom) 1704 matched = None 1705 if match[0] != -1: 1706 myatom = self.clientDbconn.retrieveAtom(match[0]) 1707 mytag = self.entropyTools.dep_gettag(myatom) 1708 myatom = self.entropyTools.remove_tag(myatom) 1709 myrev = self.clientDbconn.retrieveRevision(match[0]) 1710 pkg_match = "="+myatom+"~"+str(myrev) 1711 if mytag != None: 1712 pkg_match += "#%s" % (mytag,) 1713 pkg_unsatisfied = self.get_unsatisfied_dependencies([pkg_match], deep_deps = deep) 1714 if pkg_unsatisfied: 1715 # does it really exist on current repos? 1716 pkg_key = self.entropyTools.dep_getkey(myatom) 1717 pkg_id, pkg_repo = self.atom_match(pkg_key) 1718 if pkg_id != -1: 1719 found = True 1720 del pkg_unsatisfied 1721 matched = self.atom_match(pkg_match) 1722 del match 1723 1724 if self.xcache: 1725 self.Cacher.push(c_hash,(found, matched)) 1726 return found, matched
1727
1728 - def validate_package_removal(self, idpackage):
1729 1730 pkgatom = self.clientDbconn.retrieveAtom(idpackage) 1731 pkgkey = self.entropyTools.dep_getkey(pkgatom) 1732 client_settings = self.SystemSettings[self.sys_settings_client_plugin_id] 1733 mask_installed_keys = client_settings['system_mask']['repos_installed_keys'] 1734 1735 if self.is_installed_idpackage_in_system_mask(idpackage): 1736 idpackages = mask_installed_keys.get(pkgkey) 1737 if not idpackages: return False 1738 if len(idpackages) > 1: 1739 return True 1740 return False # sorry! 1741 1742 # did we store the bastard in the db? 1743 system_pkg = self.clientDbconn.isSystemPackage(idpackage) 1744 if not system_pkg: return True 1745 # check if the package is slotted and exist more than one installed first 1746 matches, rc = self.clientDbconn.atomMatch(pkgkey, multiMatch = True) 1747 if len(matches) < 2: 1748 return False 1749 return True
1750 1751
1752 - def get_removal_queue(self, idpackages, deep = False):
1753 queue = [] 1754 if not idpackages: 1755 return queue 1756 treeview, status = self.generate_depends_tree(idpackages, deep = deep) 1757 if status == 0: 1758 for x in range(len(treeview))[::-1]: queue.extend(treeview[x]) 1759 return queue
1760
1761 - def get_install_queue(self, matched_atoms, empty_deps, deep_deps, quiet = False):
1762 1763 install = [] 1764 removal = [] 1765 treepackages, result = self.get_required_packages(matched_atoms, 1766 empty_deps, deep_deps, quiet = quiet) 1767 1768 if result == -2: 1769 return treepackages,removal,result 1770 1771 # format 1772 removal = treepackages.pop(0, set()) 1773 for dep_level in sorted(treepackages): 1774 install.extend(treepackages[dep_level]) 1775 1776 # filter out packages that are in actionQueue comparing key + slot 1777 if install and removal: 1778 myremmatch = {} 1779 for rm_idpackage in removal: 1780 keyslot = self.clientDbconn.retrieveKeySlot(rm_idpackage) 1781 # check if users removed idpackage while this 1782 # whole instance is running 1783 if keyslot is None: 1784 continue 1785 myremmatch[keyslot] = rm_idpackage 1786 1787 for pkg_id, pkg_repo in install: 1788 dbconn = self.open_repository(pkg_repo) 1789 testtuple = dbconn.retrieveKeySlot(pkg_id) 1790 removal.discard(myremmatch.get(testtuple)) 1791 1792 return install, sorted(removal), 0
1793