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, 426 matchRepo = None, server_repos = [], serverInstance = None, 427 search = False):
428 429 # support match in repository from shell 430 # set@repo1,repo2,repo3 431 package_set, repos = self.entropyTools.dep_get_match_in_repos( 432 package_set) 433 if (matchRepo == None) and (repos != None): 434 matchRepo = repos 435 436 if server_repos: 437 if not serverInstance: 438 t = _("server_repos needs serverInstance") 439 raise IncorrectParameter("IncorrectParameter: %s" % (t,)) 440 valid_repos = server_repos[:] 441 else: 442 valid_repos = self.validRepositories 443 444 if matchRepo and (type(matchRepo) in (list,tuple,set)): 445 valid_repos = list(matchRepo) 446 447 # if we search, we return all the matches available 448 if search: multiMatch = True 449 450 set_data = [] 451 452 while 1: 453 454 # check inside SystemSettings 455 if not server_repos: 456 sys_pkgsets = self.SystemSettings['system_package_sets'] 457 if search: 458 mysets = [x for x in sys_pkgsets.keys() if \ 459 (x.find(package_set) != -1)] 460 for myset in mysets: 461 mydata = sys_pkgsets.get(myset) 462 set_data.append((etpConst['userpackagesetsid'], 463 unicode(myset), mydata.copy(),)) 464 else: 465 mydata = sys_pkgsets.get(package_set) 466 if mydata is not None: 467 set_data.append((etpConst['userpackagesetsid'], 468 unicode(package_set), mydata,)) 469 if not multiMatch: 470 break 471 472 for repoid in valid_repos: 473 dbconn = self.__package_set_match_open_db(repoid, 474 serverInstance) 475 if search: 476 mysets = dbconn.searchSets(package_set) 477 for myset in mysets: 478 mydata = dbconn.retrievePackageSet(myset) 479 set_data.append((repoid, myset, mydata.copy(),)) 480 else: 481 mydata = dbconn.retrievePackageSet(package_set) 482 if mydata: 483 set_data.append((repoid, package_set, mydata,)) 484 if not multiMatch: 485 break 486 487 break 488 489 if not set_data: 490 return (),False 491 492 if multiMatch: 493 return set_data,True 494 495 return set_data.pop(0),True
496
497 - def get_unsatisfied_dependencies(self, dependencies, deep_deps = False, depcache = None):
498 499 if self.xcache: 500 c_data = sorted(dependencies) 501 client_checksum = self.clientDbconn.database_checksum() 502 c_hash = hash("%s|%s|%s" % (c_data,deep_deps,client_checksum,)) 503 c_hash = "%s%s" % (etpCache['filter_satisfied_deps'],c_hash,) 504 cached = self.Cacher.pop(c_hash) 505 if cached != None: return cached 506 507 const_debug_write(__name__, 508 "get_unsatisfied_dependencies (not cached, deep: %s) for => %s" % ( 509 deep_deps, dependencies,)) 510 511 if not isinstance(depcache,dict): 512 depcache = {} 513 514 # satisfied dependencies filter support 515 # package.satisfied file support 516 satisfied_kw = '__%s__satisfied_ids' % (__name__,) 517 satisfied_data = self.SystemSettings.get(satisfied_kw) 518 if satisfied_data is None: 519 satisfied_list = self.SystemSettings['satisfied'] 520 tmp_satisfied_data = set() 521 for atom in satisfied_list: 522 matches, m_res = self.atom_match(atom, multiMatch = True, 523 packagesFilter = False, multiRepo = True) 524 if m_res == 0: 525 tmp_satisfied_data |= matches 526 satisfied_data = tmp_satisfied_data 527 self.SystemSettings[satisfied_kw] = satisfied_data 528 529 cdb_am = self.clientDbconn.atomMatch 530 am = self.atom_match 531 open_repo = self.open_repository 532 intf_error = self.dbapi2.InterfaceError 533 cdb_getversioning = self.clientDbconn.getVersioningData 534 etp_cmp = self.entropyTools.entropy_compare_versions 535 etp_get_rev = self.entropyTools.dep_get_entropy_revision 536 537 def fm_dep(dependency): 538 539 cached = depcache.get(dependency) 540 if cached != None: 541 const_debug_write(__name__, 542 "get_unsatisfied_dependencies control cached for => %s" % ( 543 dependency,)) 544 const_debug_write(__name__, "...") 545 return cached 546 547 ### conflict 548 if dependency.startswith("!"): 549 idpackage,rc = cdb_am(dependency[1:]) 550 if idpackage != -1: 551 depcache[dependency] = dependency 552 const_debug_write(__name__, 553 "get_unsatisfied_dependencies conflict not found on system for => %s" % ( 554 dependency,)) 555 const_debug_write(__name__, "...") 556 return dependency 557 depcache[dependency] = 0 558 const_debug_write(__name__, "...") 559 return 0 560 561 c_ids, c_rc = cdb_am(dependency, multiMatch = True) 562 if c_rc != 0: 563 depcache[dependency] = dependency 564 const_debug_write(__name__, 565 "get_unsatisfied_dependencies not satisfied on system for => %s" % ( 566 dependency,)) 567 const_debug_write(__name__, "...") 568 return dependency 569 570 r_id, r_repo = am(dependency) 571 if r_id == -1: 572 depcache[dependency] = dependency 573 const_debug_write(__name__, 574 "get_unsatisfied_dependencies repository match not found for => %s" % ( 575 dependency,)) 576 const_debug_write(__name__, "...") 577 return dependency 578 579 # satisfied dependencies filter support 580 # package.satisfied file support 581 if (r_id, r_repo,) in satisfied_data: 582 return 0 # satisfied 583 584 dbconn = open_repo(r_repo) 585 try: 586 repo_pkgver, repo_pkgtag, repo_pkgrev = dbconn.getVersioningData(r_id) 587 except (intf_error,TypeError,): 588 # package entry is broken 589 const_debug_write(__name__, 590 "get_unsatisfied_dependencies repository entry broken for match => %s" % ( 591 (r_id, r_repo),)) 592 const_debug_write(__name__, "...") 593 return dependency 594 595 client_data = set() 596 for c_id in c_ids: 597 try: 598 installedVer, installedTag, installedRev = cdb_getversioning(c_id) 599 except TypeError: # corrupted entry? 600 installedVer = "0" 601 installedTag = '' 602 installedRev = 0 603 client_data.add((installedVer, installedTag, installedRev,)) 604 605 # support for app-foo/foo-123~-1 606 # -1 revision means, always pull the latest 607 do_deep = deep_deps 608 if not do_deep: 609 string_rev = etp_get_rev(dependency) 610 if string_rev == -1: 611 do_deep = True 612 613 # this is required for multi-slotted packages (like python) 614 # and when people mix Entropy and Portage 615 for installedVer, installedTag, installedRev in client_data: 616 vcmp = etp_cmp((repo_pkgver,repo_pkgtag,repo_pkgrev,), 617 (installedVer,installedTag,installedRev,)) 618 if vcmp == 0: 619 const_debug_write(__name__, 620 "get_unsatisfied_dependencies SATISFIED equals (not cached, deep: %s) => %s" % ( 621 deep_deps, dependency,)) 622 depcache[dependency] = 0 623 const_debug_write(__name__, "...") 624 return 0 625 ver_tag_repo = (repo_pkgver, repo_pkgtag,) 626 ver_tag_inst = (installedVer, installedTag,) 627 rev_match = repo_pkgrev != installedRev 628 629 if not do_deep and (ver_tag_repo == ver_tag_inst) and rev_match: 630 631 depcache[dependency] = 0 632 const_debug_write(__name__, 633 "get_unsatisfied_dependencies SATISFIED w/o rev (not cached, deep: %s) => %s" % ( 634 deep_deps, dependency,)) 635 const_debug_write(__name__, "...") 636 return 0 637 638 # if we get here it means that there are no matching packages 639 const_debug_write(__name__, 640 "get_unsatisfied_dependencies NOT SATISFIED (not cached, deep: %s) => %s" % ( 641 deep_deps, dependency,)) 642 643 depcache[dependency] = dependency 644 const_debug_write(__name__, "...") 645 return dependency
646 647 unsatisfied = map(fm_dep,dependencies) 648 unsatisfied = set([x for x in unsatisfied if x != 0]) 649 650 if self.xcache: 651 self.Cacher.push(c_hash,unsatisfied) 652 653 return unsatisfied 654
655 - def get_masked_packages_tree(self, match, atoms = False, flat = False, matchfilter = None):
656 657 if not isinstance(matchfilter,set): 658 matchfilter = set() 659 660 maskedtree = {} 661 mybuffer = Lifo() 662 depcache = set() 663 treelevel = -1 664 665 match_id, match_repo = match 666 667 mydbconn = self.open_repository(match_repo) 668 myatom = mydbconn.retrieveAtom(match_id) 669 idpackage, idreason = mydbconn.idpackageValidator(match_id) 670 if idpackage == -1: 671 treelevel += 1 672 if atoms: 673 mydict = {myatom: idreason,} 674 else: 675 mydict = {match: idreason,} 676 if flat: 677 maskedtree.update(mydict) 678 else: 679 maskedtree[treelevel] = mydict 680 681 mydeps = mydbconn.retrieveDependencies(match_id) 682 for mydep in mydeps: mybuffer.push(mydep) 683 try: 684 mydep = mybuffer.pop() 685 except ValueError: 686 mydep = None # stack empty 687 688 open_db = self.open_repository 689 am = self.atom_match 690 while mydep: 691 692 if mydep in depcache: 693 try: 694 mydep = mybuffer.pop() 695 except ValueError: 696 break # stack empty 697 continue 698 depcache.add(mydep) 699 700 idpackage, repoid = am(mydep) 701 if (idpackage, repoid) in matchfilter: 702 try: 703 mydep = mybuffer.pop() 704 except ValueError: 705 break # stack empty 706 continue 707 708 if idpackage != -1: 709 # doing even here because atomMatch with packagesFilter = False can pull 710 # something different 711 matchfilter.add((idpackage, repoid)) 712 713 # collect masked 714 if idpackage == -1: 715 idpackage, repoid = am(mydep, packagesFilter = False) 716 if idpackage != -1: 717 treelevel += 1 718 if not maskedtree.has_key(treelevel) and not flat: 719 maskedtree[treelevel] = {} 720 dbconn = open_db(repoid) 721 vidpackage, idreason = dbconn.idpackageValidator(idpackage) 722 if atoms: 723 mydict = {dbconn.retrieveAtom(idpackage): idreason} 724 else: 725 mydict = {(idpackage,repoid): idreason} 726 if flat: maskedtree.update(mydict) 727 else: maskedtree[treelevel].update(mydict) 728 729 # push its dep into the buffer 730 if idpackage != -1: 731 matchfilter.add((idpackage, repoid)) 732 dbconn = open_db(repoid) 733 owndeps = dbconn.retrieveDependencies(idpackage) 734 for owndep in owndeps: 735 mybuffer.push(owndep) 736 737 try: 738 mydep = mybuffer.pop() 739 except ValueError: 740 break # stack empty 741 742 return maskedtree
743 744
745 - def generate_dependency_tree(self, 746 matched_atom, empty_deps = False, deep_deps = False, matchfilter = None, 747 flat = False, filter_unsat_cache = None, treecache = None, keyslotcache = None):
748 749 if not isinstance(matchfilter,set): 750 matchfilter = set() 751 if not isinstance(filter_unsat_cache,dict): 752 filter_unsat_cache = {} 753 if not isinstance(treecache,set): 754 treecache = set() 755 if not isinstance(keyslotcache,set): 756 keyslotcache = set() 757 758 mydbconn = self.open_repository(matched_atom[1]) 759 myatom = mydbconn.retrieveAtom(matched_atom[0]) 760 761 # caches 762 # special events 763 deps_not_found = set() 764 conflicts = set() 765 766 mydep = (1,myatom) 767 mybuffer = Lifo() 768 deptree = set() 769 if matched_atom not in matchfilter: 770 deptree.add((1,matched_atom)) 771 772 virgin = True 773 open_repo = self.open_repository 774 atom_match = self.atom_match 775 cdb_atom_match = self.clientDbconn.atomMatch 776 lookup_conflict_replacement = self._lookup_conflict_replacement 777 lookup_library_breakages = self._lookup_library_breakages 778 lookup_inverse_dependencies = self._lookup_inverse_dependencies 779 get_unsatisfied_deps = self.get_unsatisfied_dependencies 780 781 def my_dep_filter(x): 782 if x in treecache: return False 783 if tuple(x.split(":")) in keyslotcache: return False 784 return True
785 786 while mydep: 787 788 const_debug_write(__name__, 789 "generate_dependency_tree analyzing => %s" % ( 790 mydep,)) 791 792 dep_level, dep_atom = mydep 793 794 # already analyzed in this call 795 if dep_atom in treecache: 796 const_debug_write(__name__, 797 "generate_dependency_tree already in treecache => %s" % ( 798 dep_atom,)) 799 try: 800 mydep = mybuffer.pop() 801 except ValueError: 802 const_debug_write(__name__, "---empty--") 803 break # stack empty 804 const_debug_write(__name__, "---") 805 continue 806 treecache.add(dep_atom) 807 808 if dep_atom is None: # corrupted entry 809 const_debug_write(__name__, 810 "generate_dependency_tree broken entry in DB => %s" % ( 811 mydep,)) 812 try: 813 mydep = mybuffer.pop() 814 except ValueError: 815 const_debug_write(__name__, "---empty2--") 816 break # stack empty 817 const_debug_write(__name__, "---") 818 continue 819 820 # conflicts 821 if dep_atom[0] == "!": 822 c_idpackage, xst = cdb_atom_match(dep_atom[1:]) 823 if c_idpackage != -1: 824 myreplacement = lookup_conflict_replacement(dep_atom[1:], 825 c_idpackage, deep_deps = deep_deps) 826 827 const_debug_write(__name__, 828 "generate_dependency_tree conflict replacement => %s" % ( 829 myreplacement,)) 830 831 if (myreplacement != None) and (myreplacement not in treecache): 832 mybuffer.push((dep_level+1,myreplacement)) 833 else: 834 conflicts.add(c_idpackage) 835 try: 836 mydep = mybuffer.pop() 837 except ValueError: 838 const_debug_write(__name__, "---empty3---") 839 break # stack empty 840 const_debug_write(__name__, "---") 841 continue 842 843 # atom found? 844 if virgin: 845 846 virgin = False 847 m_idpackage, m_repo = matched_atom 848 dbconn = open_repo(m_repo) 849 myidpackage, idreason = dbconn.idpackageValidator(m_idpackage) 850 851 const_debug_write(__name__, 852 "generate_dependency_tree virgin match masked? => %s - %s" % ( 853 myidpackage, idreason,)) 854 855 if myidpackage == -1: 856 m_idpackage = -1 857 858 else: 859 m_idpackage, m_repo = atom_match(dep_atom) 860 const_debug_write(__name__, 861 "generate_dependency_tree matching %s => (%s, %s)" % ( 862 dep_atom, m_idpackage, m_repo,)) 863 864 if m_idpackage == -1: 865 866 const_debug_write(__name__, 867 "generate_dependency_tree dep not found => %s" % ( 868 dep_atom,)) 869 870 deps_not_found.add(dep_atom) 871 try: 872 mydep = mybuffer.pop() 873 except ValueError: 874 const_debug_write(__name__, "---empty3---") 875 break # stack empty 876 const_debug_write(__name__, "---") 877 continue 878 879 # check if atom has been already pulled in 880 matchdb = open_repo(m_repo) 881 matchatom = matchdb.retrieveAtom(m_idpackage) 882 matchkey, matchslot = matchdb.retrieveKeySlot(m_idpackage) 883 884 const_debug_write(__name__, 885 "generate_dependency_tree idpackage %s => %s - %s:%s" % ( 886 m_idpackage, matchatom, matchkey, matchslot)) 887 888 if (dep_atom != matchatom) and (matchatom in treecache): 889 try: 890 mydep = mybuffer.pop() 891 except ValueError: 892 const_debug_write(__name__, "---empty4---") 893 break # stack empty 894 const_debug_write(__name__, 895 "generate_dependency_tree matchatom %s already in cache" % ( 896 matchatom,)) 897 const_debug_write(__name__, "---") 898 continue 899 900 treecache.add(matchatom) 901 902 const_debug_write(__name__, 903 "generate_dependency_tree check if key + slot cache => %s" % ( 904 (matchslot, matchkey),)) 905 906 # check if key + slot has been already pulled in 907 if (matchslot, matchkey) in keyslotcache: 908 try: 909 mydep = mybuffer.pop() 910 except ValueError: 911 const_debug_write(__name__, "---empty5---") 912 break # stack empty 913 const_debug_write(__name__, "---") 914 continue 915 else: 916 keyslotcache.add((matchslot, matchkey)) 917 918 const_debug_write(__name__, 919 "generate_dependency_tree not in key + slot cache => %s" % ( 920 (matchslot, matchkey),)) 921 922 match = (m_idpackage, m_repo,) 923 # result already analyzed? 924 if match in matchfilter: 925 try: 926 mydep = mybuffer.pop() 927 except ValueError: 928 const_debug_write(__name__, "---empty6---") 929 break # stack empty 930 const_debug_write(__name__, "---") 931 continue 932 933 const_debug_write(__name__, 934 "generate_dependency_tree match NOT already analyzed => %s" % ( 935 match,)) 936 937 # all checks passed, well done 938 matchfilter.add(match) 939 treedepth = dep_level+1 940 deptree.add((dep_level,match)) # add match 941 942 # extra hooks 943 cm_idpackage, cm_result = cdb_atom_match(matchkey, 944 matchSlot = matchslot) 945 if cm_idpackage != -1: 946 947 broken_atoms = lookup_library_breakages(match, 948 (cm_idpackage, cm_result,), deep_deps = deep_deps) 949 const_debug_write(__name__, 950 "generate_dependency_tree lib broken atoms for %s => %s" % ( 951 matchkey+":"+matchslot, broken_atoms,)) 952 953 inverse_deps = lookup_inverse_dependencies(match, 954 (cm_idpackage, cm_result,)) 955 const_debug_write(__name__, 956 "generate_dependency_tree inverse deps for %s => %s" % ( 957 matchkey+":"+matchslot, inverse_deps,)) 958 959 if inverse_deps: 960 deptree.remove((dep_level,match)) 961 for ikey,islot in inverse_deps: 962 iks_str = '%s:%s' % (ikey,islot,) 963 if ((ikey,islot) not in keyslotcache) and (iks_str not in treecache): 964 mybuffer.push((dep_level,iks_str)) 965 keyslotcache.add((ikey,islot)) 966 deptree.add((treedepth,match)) 967 treedepth += 1 968 969 for x in broken_atoms: 970 if (tuple(x.split(":")) not in keyslotcache) and (x not in treecache): 971 mybuffer.push((treedepth,x)) 972 973 m_deplist = matchdb.retrieveDependenciesList(m_idpackage) 974 975 const_debug_write(__name__, 976 "generate_dependency_tree dependency list for %s => %s" % ( 977 m_idpackage, m_deplist,)) 978 979 myundeps = filter(my_dep_filter, m_deplist) 980 981 const_debug_write(__name__, 982 "generate_dependency_tree filtered dependency list => %s" % ( 983 myundeps,)) 984 985 if not empty_deps: 986 987 m_unsat_deplist = get_unsatisfied_deps(myundeps, deep_deps, 988 depcache = filter_unsat_cache) 989 990 const_debug_write(__name__, 991 "generate_dependency_tree unsatisfied dependencies (deep: %s) => %s" % ( 992 deep_deps, m_unsat_deplist,)) 993 994 myundeps = filter(my_dep_filter, m_unsat_deplist) 995 996 const_debug_write(__name__, 997 "generate_dependency_tree filtered UNSATISFIED dependencies => %s" % ( 998 myundeps,)) 999 1000 # PDEPENDs support 1001 if myundeps: 1002 1003 post_deps = [x for x in \ 1004 matchdb.retrievePostDependencies(m_idpackage) if x \ 1005 in myundeps] 1006 1007 const_debug_write(__name__, 1008 "generate_dependency_tree POST dependencies => %s" % ( 1009 post_deps,)) 1010 1011 if post_deps: 1012 1013 # do some filtering 1014 # it is correct to not use my_dep_filter here 1015 myundeps = [x for x in myundeps if x not in post_deps] 1016 1017 const_debug_write(__name__, 1018 "generate_dependency_tree POST dependencies ADDED => %s" % ( 1019 myundeps,)) 1020 1021 for x in post_deps: 1022 mybuffer.push((-1, x)) # always after the package itself 1023 1024 for x in myundeps: 1025 mybuffer.push((treedepth, x)) 1026 1027 try: 1028 mydep = mybuffer.pop() 1029 except ValueError: 1030 const_debug_write(__name__, "---empty7---") 1031 break # stack empty 1032 const_debug_write(__name__, "---") 1033 1034 if deps_not_found: 1035 return list(deps_not_found), -2 1036 1037 if flat: 1038 return [x[1] for x in deptree], 0 1039 1040 newdeptree = {} 1041 for key, item in deptree: 1042 if key >= 0: 1043 # this makes sure that key is never = 0 1044 key += 1 1045 obj = newdeptree.setdefault(key, set()) 1046 obj.add(item) 1047 # conflicts 1048 newdeptree[0] = conflicts 1049 1050 return newdeptree,0 # note: newtree[0] contains possible conflicts 1051 1052
1053 - def _lookup_system_mask_repository_deps(self):
1054 1055 client_settings = self.SystemSettings[self.sys_settings_client_plugin_id] 1056 data = client_settings['repositories']['system_mask'] 1057 1058 if not data: 1059 return [] 1060 mydata = [] 1061 cached_items = set() 1062 for atom in data: 1063 mymatch = self.atom_match(atom) 1064 if mymatch[0] == -1: # ignore missing ones intentionally 1065 continue 1066 if mymatch in cached_items: 1067 continue 1068 if mymatch not in mydata: 1069 # check if not found 1070 myaction = self.get_package_action(mymatch) 1071 # only if the package is not installed 1072 if myaction == 1: mydata.append(mymatch) 1073 cached_items.add(mymatch) 1074 return mydata
1075
1076 - def _lookup_conflict_replacement(self, conflict_atom, client_idpackage, deep_deps):
1077 if self.entropyTools.isjustname(conflict_atom): 1078 return None 1079 conflict_match = self.atom_match(conflict_atom) 1080 mykey, myslot = self.clientDbconn.retrieveKeySlot(client_idpackage) 1081 new_match = self.atom_match(mykey, matchSlot = myslot) 1082 if (conflict_match == new_match) or (new_match[1] == 1): 1083 return None 1084 action = self.get_package_action(new_match) 1085 if (action == 0) and (not deep_deps): 1086 return None 1087 return "%s:%s" % (mykey,myslot,)
1088
1089 - def _lookup_inverse_dependencies(self, match, clientmatch):
1090 1091 cmpstat = self.get_package_action(match) 1092 if cmpstat == 0: return set() 1093 1094 keyslots = set() 1095 mydepends = self.clientDbconn.retrieveDepends(clientmatch[0]) 1096 am = self.atom_match 1097 cdb_rdeps = self.clientDbconn.retrieveDependencies 1098 cdb_rks = self.clientDbconn.retrieveKeySlot 1099 gpa = self.get_package_action 1100 keyslots_cache = set() 1101 match_cache = {} 1102 1103 for idpackage in mydepends: 1104 try: 1105 key, slot = cdb_rks(idpackage) 1106 except TypeError: 1107 continue 1108 if (key,slot) in keyslots_cache: continue 1109 keyslots_cache.add((key,slot)) 1110 if (key,slot) in keyslots: continue 1111 # grab its deps 1112 mydeps = cdb_rdeps(idpackage) 1113 found = False 1114 for mydep in mydeps: 1115 mymatch = match_cache.get(mydep, 0) 1116 if mymatch == 0: 1117 mymatch = am(mydep) 1118 match_cache[mydep] = mymatch 1119 if mymatch == match: 1120 found = True 1121 break 1122 if not found: 1123 mymatch = am(key, matchSlot = slot) 1124 if mymatch[0] == -1: continue 1125 cmpstat = gpa(mymatch) 1126 if cmpstat == 0: continue 1127 keyslots.add((key,slot)) 1128 1129 return keyslots
1130
1131 - def __get_lib_breaks_client_and_repo_side(self, match_db, match_idpackage, client_idpackage):
1132 repo_needed = match_db.retrieveNeeded(match_idpackage, extended = True, format = True) 1133 client_needed = self.clientDbconn.retrieveNeeded(client_idpackage, extended = True, format = True) 1134 repo_split = [x.split(".so")[0] for x in repo_needed] 1135 client_split = [x.split(".so")[0] for x in client_needed] 1136 client_side = [x for x in client_needed if (x not in repo_needed) and (x.split(".so")[0] in repo_split)] 1137 repo_side = [x for x in repo_needed if (x not in client_needed) and (x.split(".so")[0] in client_split)] 1138 return repo_needed, client_side, repo_side
1139
1140 - def _lookup_library_breakages(self, match, clientmatch, deep_deps = False):
1141 1142 # there is no need to update this cache when "match" 1143 # will be installed, because at that point 1144 # clientmatch[0] will differ. 1145 c_hash = "%s|%s|%s" % ( 1146 tuple(match), 1147 deep_deps, 1148 tuple(clientmatch), 1149 ) 1150 c_hash = "%s%s" % (etpCache['library_breakage'], hash(c_hash),) 1151 if self.xcache: 1152 cached = self.Cacher.pop(c_hash) 1153 if cached != None: return cached 1154 1155 # these should be pulled in before 1156 repo_atoms = set() 1157 # these can be pulled in after 1158 client_atoms = set() 1159 1160 matchdb = self.open_repository(match[1]) 1161 reponeeded, client_side, repo_side = self.__get_lib_breaks_client_and_repo_side(matchdb, 1162 match[0], clientmatch[0]) 1163 1164 # all the packages in client_side should be pulled in and updated 1165 client_idpackages = set() 1166 for needed in client_side: client_idpackages |= self.clientDbconn.searchNeeded(needed) 1167 1168 client_keyslots = set() 1169 def mymf(idpackage): 1170 if idpackage == clientmatch[0]: 1171 return 0 1172 ks = self.clientDbconn.retrieveKeySlot(idpackage) 1173 if ks is None: 1174 return 0 1175 return ks
1176 client_keyslots = set([x for x in map(mymf,client_idpackages) if x != 0]) 1177 1178 # all the packages in repo_side should be pulled in too 1179 repodata = {} 1180 for needed in repo_side: 1181 repodata[needed] = reponeeded[needed] 1182 del repo_side,reponeeded 1183 1184 repo_dependencies = matchdb.retrieveDependencies(match[0]) 1185 matched_deps = set() 1186 matched_repos = set() 1187 for dependency in repo_dependencies: 1188 depmatch = self.atom_match(dependency) 1189 if depmatch[0] == -1: 1190 continue 1191 matched_repos.add(depmatch[1]) 1192 matched_deps.add(depmatch) 1193 1194 matched_repos = [x for x in self.SystemSettings['repositories']['order'] \ 1195 if x in matched_repos] 1196 found_matches = set() 1197 for needed in repodata: 1198 for myrepo in matched_repos: 1199 mydbc = self.open_repository(myrepo) 1200 solved_needed = mydbc.resolveNeeded(needed, 1201 repodata[needed]) 1202 found = False 1203 for idpackage in solved_needed: 1204 x = (idpackage, myrepo) 1205 if x in matched_deps: 1206 found_matches.add(x) 1207 found = True 1208 break 1209 if found: 1210 break 1211 1212 for idpackage,repo in found_matches: 1213 if not deep_deps: 1214 cmpstat = self.get_package_action((idpackage,repo)) 1215 if cmpstat == 0: 1216 continue 1217 mydbc = self.open_repository(repo) 1218 repo_atoms.add(mydbc.retrieveAtom(idpackage)) 1219 1220 for key, slot in client_keyslots: 1221 idpackage, repo = self.atom_match(key, matchSlot = slot) 1222 if idpackage == -1: 1223 continue 1224 if not deep_deps: 1225 cmpstat = self.get_package_action((idpackage, repo)) 1226 if cmpstat == 0: 1227 continue 1228 mydbc = self.open_repository(repo) 1229 client_atoms.add(mydbc.retrieveAtom(idpackage)) 1230 1231 client_atoms |= repo_atoms 1232 1233 if self.xcache: 1234 self.Cacher.push(c_hash,client_atoms) 1235 1236 return client_atoms 1237 1238
1239 - def get_required_packages(self, matched_atoms, empty_deps = False, deep_deps = False, quiet = False):
1240 1241 c_hash = "%s%s" % ( 1242 etpCache['dep_tree'], 1243 hash("%s|%s|%s|%s|%s" % ( 1244 hash(frozenset(sorted(matched_atoms))), 1245 empty_deps, 1246 deep_deps, 1247 self.clientDbconn.database_checksum(), 1248 # needed when users do bogus things like editing config files 1249 # manually (branch setting) 1250 self.SystemSettings['repositories']['branch'], 1251 )),) 1252 if self.xcache: 1253 cached = self.Cacher.pop(c_hash) 1254 if cached != None: return cached 1255 1256 deptree = {} 1257 deptree[0] = set() 1258 1259 atomlen = len(matched_atoms); count = 0 1260 error_generated = 0 1261 error_tree = set() 1262 1263 # check if there are repositories needing some mandatory packages 1264 forced_matches = self._lookup_system_mask_repository_deps() 1265 if forced_matches: 1266 if isinstance(matched_atoms, list): 1267 matched_atoms = forced_matches + [x for x in matched_atoms if x not in forced_matches] 1268 elif isinstance(matched_atoms, set): # we cannot do anything about the order here 1269 matched_atoms |= set(forced_matches) 1270 1271 sort_dep_text = _("Sorting dependencies") 1272 filter_unsat_cache = {} 1273 treecache = set() 1274 keyslotcache = set() 1275 matchfilter = set() 1276 for matched_atom in matched_atoms: 1277 const_debug_write(__name__, 1278 "get_required_packages matched_atom => %s" % (matched_atom,)) 1279 1280 if not quiet: 1281 count += 1 1282 if (count%10 == 0) or (count == atomlen) or (count == 1): 1283 self.updateProgress(sort_dep_text, importance = 0, type = "info", 1284 back = True, header = ":: ", footer = " ::", 1285 percent = True, count = (count,atomlen)) 1286 1287 if matched_atom in matchfilter: continue 1288 newtree, result = self.generate_dependency_tree( 1289 matched_atom, empty_deps, deep_deps, 1290 matchfilter = matchfilter, filter_unsat_cache = filter_unsat_cache, treecache = treecache, 1291 keyslotcache = keyslotcache 1292 ) 1293 1294 const_debug_write(__name__, 1295 "get_required_packages deptree => %s -- %s" % ( 1296 newtree, result,)) 1297 1298 if result == -2: # deps not found 1299 error_generated = -2 1300 error_tree |= set(newtree) # it is a list, we convert it into set and update error_tree 1301 elif (result != 0): 1302 return newtree, result 1303 elif newtree: 1304 # add conflicts 1305 max_parent_key = max(deptree) 1306 deptree[0] |= newtree.pop(0) 1307 levelcount = 0 1308 for mylevel in sorted(newtree.keys(), reverse = True): 1309 levelcount += 1 1310 deptree[max_parent_key+levelcount] = newtree.get(mylevel) 1311 1312 if error_generated != 0: 1313 return error_tree,error_generated 1314 1315 if self.xcache: 1316 self.Cacher.push(c_hash,(deptree,0)) 1317 1318 return deptree,0
1319
1320 - def _filter_depends_multimatched_atoms(self, idpackage, depends, monotree):
1321 remove_depends = set() 1322 for d_idpackage in depends: 1323 mydeps = self.clientDbconn.retrieveDependencies(d_idpackage) 1324 for mydep in mydeps: 1325 matches, rslt = self.clientDbconn.atomMatch(mydep, multiMatch = True) 1326 if rslt == 1: continue 1327 if idpackage in matches and len(matches) > 1: 1328 # are all in depends? 1329 for mymatch in matches: 1330 if mymatch not in depends and mymatch not in monotree: 1331 remove_depends.add(d_idpackage) 1332 break 1333 depends -= remove_depends 1334 return depends
1335 1336
1337 - def generate_depends_tree(self, idpackages, deep = False):
1338 1339 c_hash = "%s%s" % ( 1340 etpCache['depends_tree'], 1341 hash("%s|%s" % ( 1342 tuple(sorted(idpackages)), 1343 deep, 1344 ), 1345 ), 1346 ) 1347 if self.xcache: 1348 cached = self.Cacher.pop(c_hash) 1349 if cached != None: return cached 1350 1351 dependscache = set() 1352 treeview = set(idpackages) 1353 treelevel = set(idpackages) 1354 tree = {} 1355 # I start from level 1 because level 0 is idpackages itself 1356 treedepth = 0 1357 tree[treedepth] = set(idpackages) 1358 monotree = set(idpackages) # monodimensional tree 1359 1360 # post-dependencies won't be pulled in 1361 pdepend_id = etpConst['spm']['pdepend_id'] 1362 # check if dependstable is sane before beginning 1363 self.clientDbconn.retrieveDepends(idpackages[0]) 1364 count = 0 1365 1366 rem_dep_text = _("Calculating inverse dependencies for") 1367 while 1: 1368 treedepth += 1 1369 tree[treedepth] = set() 1370 for idpackage in treelevel: 1371 1372 count += 1 1373 p_atom = self.clientDbconn.retrieveAtom(idpackage) 1374 self.updateProgress( 1375 blue(rem_dep_text + " %s" % (red(p_atom),)), 1376 importance = 0, 1377 type = "info", 1378 back = True, 1379 header = '|/-\\'[count%4]+" " 1380 ) 1381 1382 systempkg = not self.validate_package_removal(idpackage) 1383 if (idpackage in dependscache) or systempkg: 1384 if idpackage in treeview: 1385 treeview.remove(idpackage) 1386 continue 1387 1388 # obtain its inverse deps 1389 depends = self.clientDbconn.retrieveDepends(idpackage, 1390 exclude_deptypes = (pdepend_id,)) 1391 # filter already satisfied ones 1392 depends = set([x for x in depends if x not in monotree]) 1393 depends = set([x for x in depends if \ 1394 self.validate_package_removal(x)]) 1395 if depends: 1396 depends = self._filter_depends_multimatched_atoms( 1397 idpackage, depends, monotree) 1398 if depends: # something depends on idpackage 1399 tree[treedepth] |= depends 1400 monotree |= depends 1401 treeview |= depends 1402 elif deep: # if deep, grab its dependencies and check 1403 1404 mydeps = set() 1405 for x in self.clientDbconn.retrieveDependencies(idpackage): 1406 match = self.clientDbconn.atomMatch(x) 1407 if match[0] != -1: 1408 mydeps.add(match[0]) 1409 1410 # now filter them 1411 mydeps = [x for x in mydeps if x not in monotree and not \ 1412 (self.clientDbconn.isSystemPackage(x) or \ 1413 self.is_installed_idpackage_in_system_mask(x) )] 1414 for x in mydeps: 1415 mydepends = self.clientDbconn.retrieveDepends(x) 1416 mydepends -= set([y for y in mydepends if y \ 1417 not in monotree]) 1418 if not mydepends: 1419 tree[treedepth].add(x) 1420 monotree.add(x) 1421 treeview.add(x) 1422 1423 dependscache.add(idpackage) 1424 if idpackage in treeview: 1425 treeview.remove(idpackage) 1426 1427 treelevel = treeview.copy() 1428 if not treelevel: 1429 if not tree[treedepth]: 1430 del tree[treedepth] # probably the last one is empty then 1431 break 1432 1433 # now filter newtree 1434 for count in sorted(tree.keys(), reverse = True): 1435 x = 0 1436 while x < count: 1437 tree[x] -= tree[count] 1438 x += 1 1439 1440 if self.xcache: 1441 self.Cacher.push(c_hash,(tree,0)) 1442 # treeview is used to show deps while 1443 # tree is used to run the dependency code. 1444 return tree,0
1445
1446 - def calculate_available_packages(self, use_cache = True):
1447 1448 c_hash = self.get_available_packages_chash() 1449 if use_cache and self.xcache: 1450 cached = self.get_available_packages_cache(myhash = c_hash) 1451 if cached != None: 1452 return cached 1453 1454 available = [] 1455 self.setTotalCycles(len(self.validRepositories)) 1456 avail_dep_text = _("Calculating available packages for") 1457 for repo in self.validRepositories: 1458 try: 1459 dbconn = self.open_repository(repo) 1460 dbconn.validateDatabase() 1461 except (RepositoryError, SystemDatabaseError): 1462 self.cycleDone() 1463 continue 1464 try: 1465 # db may be corrupted, we cannot deal with it here 1466 idpackages = [x for x in dbconn.listAllIdpackages( 1467 order_by = 'atom') if dbconn.idpackageValidator(x)[0] != -1] 1468 except dbconn.dbapi2.OperationalError: 1469 self.cycleDone() 1470 continue 1471 count = 0 1472 maxlen = len(idpackages) 1473 myavailable = [] 1474 do_break = False 1475 for idpackage in idpackages: 1476 if do_break: 1477 break 1478 count += 1 1479 if (count % 10 == 0) or (count == 1) or (count == maxlen): 1480 self.updateProgress( 1481 avail_dep_text + " %s" % (repo,), 1482 importance = 0, 1483 type = "info", 1484 back = True, 1485 header = "::", 1486 count = (count,maxlen), 1487 percent = True, 1488 footer = " ::" 1489 ) 1490 # get key + slot 1491 try: 1492 key, slot = dbconn.retrieveKeySlot(idpackage) 1493 matches = self.clientDbconn.searchKeySlot(key, slot) 1494 except (self.dbapi2.DatabaseError,self.dbapi2.IntegrityError,self.dbapi2.OperationalError,): 1495 self.cycleDone() 1496 do_break = True 1497 continue 1498 if not matches: myavailable.append((idpackage,repo)) 1499 available += myavailable[:] 1500 self.cycleDone() 1501 1502 if self.xcache: 1503 self.Cacher.push("%s%s" % ( 1504 etpCache['world_available'], c_hash), available) 1505 return available
1506
1507 - def calculate_critical_updates(self, use_cache = True):
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 return update, remove, fine, spm_fine
1683
1684 - def check_package_update(self, atom, deep = False):
1685 1686 c_hash = "%s%s" % (etpCache['check_package_update'], 1687 hash("%s%s" % (atom, deep,) 1688 ), 1689 ) 1690 if self.xcache: 1691 cached = self.Cacher.pop(c_hash) 1692 if cached != None: 1693 return cached 1694 1695 found = False 1696 match = self.clientDbconn.atomMatch(atom) 1697 matched = None 1698 if match[0] != -1: 1699 myatom = self.clientDbconn.retrieveAtom(match[0]) 1700 mytag = self.entropyTools.dep_gettag(myatom) 1701 myatom = self.entropyTools.remove_tag(myatom) 1702 myrev = self.clientDbconn.retrieveRevision(match[0]) 1703 pkg_match = "="+myatom+"~"+str(myrev) 1704 if mytag != None: 1705 pkg_match += "#%s" % (mytag,) 1706 pkg_unsatisfied = self.get_unsatisfied_dependencies([pkg_match], deep_deps = deep) 1707 if pkg_unsatisfied: 1708 # does it really exist on current repos? 1709 pkg_key = self.entropyTools.dep_getkey(myatom) 1710 pkg_id, pkg_repo = self.atom_match(pkg_key) 1711 if pkg_id != -1: 1712 found = True 1713 del pkg_unsatisfied 1714 matched = self.atom_match(pkg_match) 1715 del match 1716 1717 if self.xcache: 1718 self.Cacher.push(c_hash,(found, matched)) 1719 return found, matched
1720
1721 - def validate_package_removal(self, idpackage):
1722 1723 pkgatom = self.clientDbconn.retrieveAtom(idpackage) 1724 pkgkey = self.entropyTools.dep_getkey(pkgatom) 1725 client_settings = self.SystemSettings[self.sys_settings_client_plugin_id] 1726 mask_installed_keys = client_settings['system_mask']['repos_installed_keys'] 1727 1728 if self.is_installed_idpackage_in_system_mask(idpackage): 1729 idpackages = mask_installed_keys.get(pkgkey) 1730 if not idpackages: return False 1731 if len(idpackages) > 1: 1732 return True 1733 return False # sorry! 1734 1735 # did we store the bastard in the db? 1736 system_pkg = self.clientDbconn.isSystemPackage(idpackage) 1737 if not system_pkg: return True 1738 # check if the package is slotted and exist more than one installed first 1739 matches, rc = self.clientDbconn.atomMatch(pkgkey, multiMatch = True) 1740 if len(matches) < 2: 1741 return False 1742 return True
1743 1744
1745 - def get_removal_queue(self, idpackages, deep = False):
1746 queue = [] 1747 if not idpackages: 1748 return queue 1749 treeview, status = self.generate_depends_tree(idpackages, deep = deep) 1750 if status == 0: 1751 for x in range(len(treeview))[::-1]: queue.extend(treeview[x]) 1752 return queue
1753
1754 - def get_install_queue(self, matched_atoms, empty_deps, deep_deps, quiet = False):
1755 1756 install = [] 1757 removal = [] 1758 treepackages, result = self.get_required_packages(matched_atoms, 1759 empty_deps, deep_deps, quiet = quiet) 1760 1761 if result == -2: 1762 return treepackages,removal,result 1763 1764 # format 1765 removal = treepackages.pop(0, set()) 1766 for dep_level in sorted(treepackages): 1767 install.extend(treepackages[dep_level]) 1768 1769 # filter out packages that are in actionQueue comparing key + slot 1770 if install and removal: 1771 myremmatch = {} 1772 for rm_idpackage in removal: 1773 keyslot = self.clientDbconn.retrieveKeySlot(rm_idpackage) 1774 # check if users removed idpackage while this 1775 # whole instance is running 1776 if keyslot is None: 1777 continue 1778 myremmatch[keyslot] = rm_idpackage 1779 1780 for pkg_id, pkg_repo in install: 1781 dbconn = self.open_repository(pkg_repo) 1782 testtuple = dbconn.retrieveKeySlot(pkg_id) 1783 removal.discard(myremmatch.get(testtuple)) 1784 1785 return install, sorted(removal), 0
1786