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

Source Code for Module entropy.client.interfaces.dep

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