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 mydep = mybuffer.pop() 669 670 open_db = self.open_repository 671 am = self.atom_match 672 while mydep: 673 674 if mydep in depcache: 675 mydep = mybuffer.pop() 676 continue 677 depcache.add(mydep) 678 679 idpackage, repoid = am(mydep) 680 if (idpackage, repoid) in matchfilter: 681 mydep = mybuffer.pop() 682 continue 683 684 if idpackage != -1: 685 # doing even here because atomMatch with packagesFilter = False can pull 686 # something different 687 matchfilter.add((idpackage, repoid)) 688 689 # collect masked 690 if idpackage == -1: 691 idpackage, repoid = am(mydep, packagesFilter = False) 692 if idpackage != -1: 693 treelevel += 1 694 if not maskedtree.has_key(treelevel) and not flat: 695 maskedtree[treelevel] = {} 696 dbconn = open_db(repoid) 697 vidpackage, idreason = dbconn.idpackageValidator(idpackage) 698 if atoms: 699 mydict = {dbconn.retrieveAtom(idpackage): idreason} 700 else: 701 mydict = {(idpackage,repoid): idreason} 702 if flat: maskedtree.update(mydict) 703 else: maskedtree[treelevel].update(mydict) 704 705 # push its dep into the buffer 706 if idpackage != -1: 707 matchfilter.add((idpackage, repoid)) 708 dbconn = open_db(repoid) 709 owndeps = dbconn.retrieveDependencies(idpackage) 710 for owndep in owndeps: 711 mybuffer.push(owndep) 712 713 mydep = mybuffer.pop() 714 715 return maskedtree
716 717
718 - def generate_dependency_tree(self, 719 matched_atom, empty_deps = False, deep_deps = False, matchfilter = None, 720 flat = False, filter_unsat_cache = None, treecache = None, keyslotcache = None):
721 722 if not isinstance(matchfilter,set): 723 matchfilter = set() 724 if not isinstance(filter_unsat_cache,dict): 725 filter_unsat_cache = {} 726 if not isinstance(treecache,set): 727 treecache = set() 728 if not isinstance(keyslotcache,set): 729 keyslotcache = set() 730 731 mydbconn = self.open_repository(matched_atom[1]) 732 myatom = mydbconn.retrieveAtom(matched_atom[0]) 733 734 # caches 735 # special events 736 deps_not_found = set() 737 conflicts = set() 738 739 mydep = (1,myatom) 740 mybuffer = Lifo() 741 deptree = set() 742 if matched_atom not in matchfilter: 743 deptree.add((1,matched_atom)) 744 745 virgin = True 746 open_repo = self.open_repository 747 atom_match = self.atom_match 748 cdb_atom_match = self.clientDbconn.atomMatch 749 lookup_conflict_replacement = self._lookup_conflict_replacement 750 lookup_library_breakages = self._lookup_library_breakages 751 lookup_inverse_dependencies = self._lookup_inverse_dependencies 752 get_unsatisfied_deps = self.get_unsatisfied_dependencies 753 754 def my_dep_filter(x): 755 if x in treecache: return False 756 if tuple(x.split(":")) in keyslotcache: return False 757 return True
758 759 while mydep: 760 761 const_debug_write(__name__, 762 "generate_dependency_tree analyzing => %s" % ( 763 mydep,)) 764 765 dep_level, dep_atom = mydep 766 767 # already analyzed in this call 768 if dep_atom in treecache: 769 const_debug_write(__name__, 770 "generate_dependency_tree already in treecache => %s" % ( 771 dep_atom,)) 772 mydep = mybuffer.pop() 773 const_debug_write(__name__, "---") 774 continue 775 treecache.add(dep_atom) 776 777 if dep_atom is None: # corrupted entry 778 const_debug_write(__name__, 779 "generate_dependency_tree broken entry in DB => %s" % ( 780 mydep,)) 781 mydep = mybuffer.pop() 782 const_debug_write(__name__, "---") 783 continue 784 785 # conflicts 786 if dep_atom[0] == "!": 787 c_idpackage, xst = cdb_atom_match(dep_atom[1:]) 788 if c_idpackage != -1: 789 myreplacement = lookup_conflict_replacement(dep_atom[1:], 790 c_idpackage, deep_deps = deep_deps) 791 792 const_debug_write(__name__, 793 "generate_dependency_tree conflict replacement => %s" % ( 794 myreplacement,)) 795 796 if (myreplacement != None) and (myreplacement not in treecache): 797 mybuffer.push((dep_level+1,myreplacement)) 798 else: 799 conflicts.add(c_idpackage) 800 mydep = mybuffer.pop() 801 const_debug_write(__name__, "---") 802 continue 803 804 # atom found? 805 if virgin: 806 807 virgin = False 808 m_idpackage, m_repo = matched_atom 809 dbconn = open_repo(m_repo) 810 myidpackage, idreason = dbconn.idpackageValidator(m_idpackage) 811 812 const_debug_write(__name__, 813 "generate_dependency_tree virgin match masked? => %s - %s" % ( 814 myidpackage, idreason,)) 815 816 if myidpackage == -1: 817 m_idpackage = -1 818 819 else: 820 m_idpackage, m_repo = atom_match(dep_atom) 821 const_debug_write(__name__, 822 "generate_dependency_tree matching %s => (%s, %s)" % ( 823 dep_atom, m_idpackage, m_repo,)) 824 825 if m_idpackage == -1: 826 827 const_debug_write(__name__, 828 "generate_dependency_tree dep not found => %s" % ( 829 dep_atom,)) 830 831 deps_not_found.add(dep_atom) 832 mydep = mybuffer.pop() 833 const_debug_write(__name__, "---") 834 continue 835 836 # check if atom has been already pulled in 837 matchdb = open_repo(m_repo) 838 matchatom = matchdb.retrieveAtom(m_idpackage) 839 matchkey, matchslot = matchdb.retrieveKeySlot(m_idpackage) 840 841 const_debug_write(__name__, 842 "generate_dependency_tree idpackage %s => %s - %s:%s" % ( 843 m_idpackage, matchatom, matchkey, matchslot)) 844 845 if (dep_atom != matchatom) and (matchatom in treecache): 846 mydep = mybuffer.pop() 847 const_debug_write(__name__, 848 "generate_dependency_tree matchatom %s already in cache" % ( 849 matchatom,)) 850 const_debug_write(__name__, "---") 851 continue 852 853 treecache.add(matchatom) 854 855 const_debug_write(__name__, 856 "generate_dependency_tree check if key + slot cache => %s" % ( 857 (matchslot, matchkey),)) 858 859 # check if key + slot has been already pulled in 860 if (matchslot, matchkey) in keyslotcache: 861 mydep = mybuffer.pop() 862 const_debug_write(__name__, "---") 863 continue 864 else: 865 keyslotcache.add((matchslot, matchkey)) 866 867 const_debug_write(__name__, 868 "generate_dependency_tree not in key + slot cache => %s" % ( 869 (matchslot, matchkey),)) 870 871 match = (m_idpackage, m_repo,) 872 # result already analyzed? 873 if match in matchfilter: 874 mydep = mybuffer.pop() 875 const_debug_write(__name__, "---") 876 continue 877 878 const_debug_write(__name__, 879 "generate_dependency_tree match NOT already analyzed => %s" % ( 880 match,)) 881 882 # all checks passed, well done 883 matchfilter.add(match) 884 treedepth = dep_level+1 885 deptree.add((dep_level,match)) # add match 886 887 # extra hooks 888 cm_idpackage, cm_result = cdb_atom_match(matchkey, 889 matchSlot = matchslot) 890 if cm_idpackage != -1: 891 892 broken_atoms = lookup_library_breakages(match, 893 (cm_idpackage, cm_result,), deep_deps = deep_deps) 894 const_debug_write(__name__, 895 "generate_dependency_tree lib broken atoms for %s => %s" % ( 896 matchkey+":"+matchslot, broken_atoms,)) 897 898 inverse_deps = lookup_inverse_dependencies(match, 899 (cm_idpackage, cm_result,)) 900 const_debug_write(__name__, 901 "generate_dependency_tree inverse deps for %s => %s" % ( 902 matchkey+":"+matchslot, inverse_deps,)) 903 904 if inverse_deps: 905 deptree.remove((dep_level,match)) 906 for ikey,islot in inverse_deps: 907 iks_str = '%s:%s' % (ikey,islot,) 908 if ((ikey,islot) not in keyslotcache) and (iks_str not in treecache): 909 mybuffer.push((dep_level,iks_str)) 910 keyslotcache.add((ikey,islot)) 911 deptree.add((treedepth,match)) 912 treedepth += 1 913 914 for x in broken_atoms: 915 if (tuple(x.split(":")) not in keyslotcache) and (x not in treecache): 916 mybuffer.push((treedepth,x)) 917 918 m_deplist = matchdb.retrieveDependenciesList(m_idpackage) 919 920 const_debug_write(__name__, 921 "generate_dependency_tree dependency list for %s => %s" % ( 922 m_idpackage, m_deplist,)) 923 924 myundeps = filter(my_dep_filter, m_deplist) 925 926 const_debug_write(__name__, 927 "generate_dependency_tree filtered dependency list => %s" % ( 928 myundeps,)) 929 930 if not empty_deps: 931 932 m_unsat_deplist = get_unsatisfied_deps(myundeps, deep_deps, 933 depcache = filter_unsat_cache) 934 935 const_debug_write(__name__, 936 "generate_dependency_tree unsatisfied dependencies (deep: %s) => %s" % ( 937 deep_deps, m_unsat_deplist,)) 938 939 myundeps = filter(my_dep_filter, m_unsat_deplist) 940 941 const_debug_write(__name__, 942 "generate_dependency_tree filtered UNSATISFIED dependencies => %s" % ( 943 myundeps,)) 944 945 # PDEPENDs support 946 if myundeps: 947 948 post_deps = [x for x in \ 949 matchdb.retrievePostDependencies(m_idpackage) if x \ 950 in myundeps] 951 952 const_debug_write(__name__, 953 "generate_dependency_tree POST dependencies => %s" % ( 954 post_deps,)) 955 956 if post_deps: 957 958 # do some filtering 959 # it is correct to not use my_dep_filter here 960 myundeps = [x for x in myundeps if x not in post_deps] 961 962 const_debug_write(__name__, 963 "generate_dependency_tree POST dependencies ADDED => %s" % ( 964 myundeps,)) 965 966 for x in post_deps: 967 mybuffer.push((-1, x)) # always after the package itself 968 969 for x in myundeps: 970 mybuffer.push((treedepth, x)) 971 972 mydep = mybuffer.pop() 973 const_debug_write(__name__, "---") 974 975 if deps_not_found: 976 return list(deps_not_found),-2 977 978 if flat: return [x[1] for x in deptree],0 979 980 newdeptree = {} 981 for key, item in deptree: 982 if key >= 0: 983 # this makes sure that key is never = 0 984 key += 1 985 obj = newdeptree.setdefault(key, set()) 986 obj.add(item) 987 # conflicts 988 newdeptree[0] = conflicts 989 990 return newdeptree,0 # note: newtree[0] contains possible conflicts 991 992
993 - def _lookup_system_mask_repository_deps(self):
994 995 client_settings = self.SystemSettings[self.sys_settings_client_plugin_id] 996 data = client_settings['repositories']['system_mask'] 997 998 if not data: 999 return [] 1000 mydata = [] 1001 cached_items = set() 1002 for atom in data: 1003 mymatch = self.atom_match(atom) 1004 if mymatch[0] == -1: # ignore missing ones intentionally 1005 continue 1006 if mymatch in cached_items: 1007 continue 1008 if mymatch not in mydata: 1009 # check if not found 1010 myaction = self.get_package_action(mymatch) 1011 # only if the package is not installed 1012 if myaction == 1: mydata.append(mymatch) 1013 cached_items.add(mymatch) 1014 return mydata
1015
1016 - def _lookup_conflict_replacement(self, conflict_atom, client_idpackage, deep_deps):
1017 if self.entropyTools.isjustname(conflict_atom): 1018 return None 1019 conflict_match = self.atom_match(conflict_atom) 1020 mykey, myslot = self.clientDbconn.retrieveKeySlot(client_idpackage) 1021 new_match = self.atom_match(mykey, matchSlot = myslot) 1022 if (conflict_match == new_match) or (new_match[1] == 1): 1023 return None 1024 action = self.get_package_action(new_match) 1025 if (action == 0) and (not deep_deps): 1026 return None 1027 return "%s:%s" % (mykey,myslot,)
1028
1029 - def _lookup_inverse_dependencies(self, match, clientmatch):
1030 1031 cmpstat = self.get_package_action(match) 1032 if cmpstat == 0: return set() 1033 1034 keyslots = set() 1035 mydepends = self.clientDbconn.retrieveDepends(clientmatch[0]) 1036 am = self.atom_match 1037 cdb_rdeps = self.clientDbconn.retrieveDependencies 1038 cdb_rks = self.clientDbconn.retrieveKeySlot 1039 gpa = self.get_package_action 1040 keyslots_cache = set() 1041 match_cache = {} 1042 1043 for idpackage in mydepends: 1044 try: 1045 key, slot = cdb_rks(idpackage) 1046 except TypeError: 1047 continue 1048 if (key,slot) in keyslots_cache: continue 1049 keyslots_cache.add((key,slot)) 1050 if (key,slot) in keyslots: continue 1051 # grab its deps 1052 mydeps = cdb_rdeps(idpackage) 1053 found = False 1054 for mydep in mydeps: 1055 mymatch = match_cache.get(mydep, 0) 1056 if mymatch == 0: 1057 mymatch = am(mydep) 1058 match_cache[mydep] = mymatch 1059 if mymatch == match: 1060 found = True 1061 break 1062 if not found: 1063 mymatch = am(key, matchSlot = slot) 1064 if mymatch[0] == -1: continue 1065 cmpstat = gpa(mymatch) 1066 if cmpstat == 0: continue 1067 keyslots.add((key,slot)) 1068 1069 return keyslots
1070
1071 - def __get_lib_breaks_client_and_repo_side(self, match_db, match_idpackage, client_idpackage):
1072 repo_needed = match_db.retrieveNeeded(match_idpackage, extended = True, format = True) 1073 client_needed = self.clientDbconn.retrieveNeeded(client_idpackage, extended = True, format = True) 1074 repo_split = [x.split(".so")[0] for x in repo_needed] 1075 client_split = [x.split(".so")[0] for x in client_needed] 1076 client_side = [x for x in client_needed if (x not in repo_needed) and (x.split(".so")[0] in repo_split)] 1077 repo_side = [x for x in repo_needed if (x not in client_needed) and (x.split(".so")[0] in client_split)] 1078 return repo_needed, client_side, repo_side
1079
1080 - def _lookup_library_breakages(self, match, clientmatch, deep_deps = False):
1081 1082 # there is no need to update this cache when "match" 1083 # will be installed, because at that point 1084 # clientmatch[0] will differ. 1085 c_hash = "%s|%s|%s" % ( 1086 tuple(match), 1087 deep_deps, 1088 tuple(clientmatch), 1089 ) 1090 c_hash = "%s%s" % (etpCache['library_breakage'], hash(c_hash),) 1091 if self.xcache: 1092 cached = self.Cacher.pop(c_hash) 1093 if cached != None: return cached 1094 1095 # these should be pulled in before 1096 repo_atoms = set() 1097 # these can be pulled in after 1098 client_atoms = set() 1099 1100 matchdb = self.open_repository(match[1]) 1101 reponeeded, client_side, repo_side = self.__get_lib_breaks_client_and_repo_side(matchdb, 1102 match[0], clientmatch[0]) 1103 1104 # all the packages in client_side should be pulled in and updated 1105 client_idpackages = set() 1106 for needed in client_side: client_idpackages |= self.clientDbconn.searchNeeded(needed) 1107 1108 client_keyslots = set() 1109 def mymf(idpackage): 1110 if idpackage == clientmatch[0]: 1111 return 0 1112 ks = self.clientDbconn.retrieveKeySlot(idpackage) 1113 if ks is None: 1114 return 0 1115 return ks
1116 client_keyslots = set([x for x in map(mymf,client_idpackages) if x != 0]) 1117 1118 # all the packages in repo_side should be pulled in too 1119 repodata = {} 1120 for needed in repo_side: 1121 repodata[needed] = reponeeded[needed] 1122 del repo_side,reponeeded 1123 1124 repo_dependencies = matchdb.retrieveDependencies(match[0]) 1125 matched_deps = set() 1126 matched_repos = set() 1127 for dependency in repo_dependencies: 1128 depmatch = self.atom_match(dependency) 1129 if depmatch[0] == -1: 1130 continue 1131 matched_repos.add(depmatch[1]) 1132 matched_deps.add(depmatch) 1133 1134 matched_repos = [x for x in self.SystemSettings['repositories']['order'] \ 1135 if x in matched_repos] 1136 found_matches = set() 1137 for needed in repodata: 1138 for myrepo in matched_repos: 1139 mydbc = self.open_repository(myrepo) 1140 solved_needed = mydbc.resolveNeeded(needed, 1141 repodata[needed]) 1142 found = False 1143 for idpackage in solved_needed: 1144 x = (idpackage, myrepo) 1145 if x in matched_deps: 1146 found_matches.add(x) 1147 found = True 1148 break 1149 if found: 1150 break 1151 1152 for idpackage,repo in found_matches: 1153 if not deep_deps: 1154 cmpstat = self.get_package_action((idpackage,repo)) 1155 if cmpstat == 0: 1156 continue 1157 mydbc = self.open_repository(repo) 1158 repo_atoms.add(mydbc.retrieveAtom(idpackage)) 1159 1160 for key, slot in client_keyslots: 1161 idpackage, repo = self.atom_match(key, matchSlot = slot) 1162 if idpackage == -1: 1163 continue 1164 if not deep_deps: 1165 cmpstat = self.get_package_action((idpackage, repo)) 1166 if cmpstat == 0: 1167 continue 1168 mydbc = self.open_repository(repo) 1169 client_atoms.add(mydbc.retrieveAtom(idpackage)) 1170 1171 client_atoms |= repo_atoms 1172 1173 if self.xcache: 1174 self.Cacher.push(c_hash,client_atoms) 1175 1176 return client_atoms 1177 1178
1179 - def get_required_packages(self, matched_atoms, empty_deps = False, deep_deps = False, quiet = False):
1180 1181 c_hash = "%s%s" % ( 1182 etpCache['dep_tree'], 1183 hash("%s|%s|%s|%s|%s" % ( 1184 hash(frozenset(sorted(matched_atoms))), 1185 empty_deps, 1186 deep_deps, 1187 self.clientDbconn.database_checksum(), 1188 # needed when users do bogus things like editing config files 1189 # manually (branch setting) 1190 self.SystemSettings['repositories']['branch'], 1191 )),) 1192 if self.xcache: 1193 cached = self.Cacher.pop(c_hash) 1194 if cached != None: return cached 1195 1196 deptree = {} 1197 deptree[0] = set() 1198 1199 atomlen = len(matched_atoms); count = 0 1200 error_generated = 0 1201 error_tree = set() 1202 1203 # check if there are repositories needing some mandatory packages 1204 forced_matches = self._lookup_system_mask_repository_deps() 1205 if forced_matches: 1206 if isinstance(matched_atoms, list): 1207 matched_atoms = forced_matches + [x for x in matched_atoms if x not in forced_matches] 1208 elif isinstance(matched_atoms, set): # we cannot do anything about the order here 1209 matched_atoms |= set(forced_matches) 1210 1211 sort_dep_text = _("Sorting dependencies") 1212 filter_unsat_cache = {} 1213 treecache = set() 1214 keyslotcache = set() 1215 matchfilter = set() 1216 for matched_atom in matched_atoms: 1217 const_debug_write(__name__, 1218 "get_required_packages matched_atom => %s" % (matched_atom,)) 1219 1220 if not quiet: 1221 count += 1 1222 if (count%10 == 0) or (count == atomlen) or (count == 1): 1223 self.updateProgress(sort_dep_text, importance = 0, type = "info", 1224 back = True, header = ":: ", footer = " ::", 1225 percent = True, count = (count,atomlen)) 1226 1227 if matched_atom in matchfilter: continue 1228 newtree, result = self.generate_dependency_tree( 1229 matched_atom, empty_deps, deep_deps, 1230 matchfilter = matchfilter, filter_unsat_cache = filter_unsat_cache, treecache = treecache, 1231 keyslotcache = keyslotcache 1232 ) 1233 1234 const_debug_write(__name__, 1235 "get_required_packages deptree => %s -- %s" % ( 1236 newtree, result,)) 1237 1238 if result == -2: # deps not found 1239 error_generated = -2 1240 error_tree |= set(newtree) # it is a list, we convert it into set and update error_tree 1241 elif (result != 0): 1242 return newtree, result 1243 elif newtree: 1244 # add conflicts 1245 max_parent_key = max(deptree) 1246 deptree[0] |= newtree.pop(0) 1247 levelcount = 0 1248 for mylevel in sorted(newtree.keys(), reverse = True): 1249 levelcount += 1 1250 deptree[max_parent_key+levelcount] = newtree.get(mylevel) 1251 1252 if error_generated != 0: 1253 return error_tree,error_generated 1254 1255 if self.xcache: 1256 self.Cacher.push(c_hash,(deptree,0)) 1257 1258 return deptree,0
1259
1260 - def _filter_depends_multimatched_atoms(self, idpackage, depends, monotree):
1261 remove_depends = set() 1262 for d_idpackage in depends: 1263 mydeps = self.clientDbconn.retrieveDependencies(d_idpackage) 1264 for mydep in mydeps: 1265 matches, rslt = self.clientDbconn.atomMatch(mydep, multiMatch = True) 1266 if rslt == 1: continue 1267 if idpackage in matches and len(matches) > 1: 1268 # are all in depends? 1269 for mymatch in matches: 1270 if mymatch not in depends and mymatch not in monotree: 1271 remove_depends.add(d_idpackage) 1272 break 1273 depends -= remove_depends 1274 return depends
1275 1276
1277 - def generate_depends_tree(self, idpackages, deep = False):
1278 1279 c_hash = "%s%s" % ( 1280 etpCache['depends_tree'], 1281 hash("%s|%s" % ( 1282 tuple(sorted(idpackages)), 1283 deep, 1284 ), 1285 ), 1286 ) 1287 if self.xcache: 1288 cached = self.Cacher.pop(c_hash) 1289 if cached != None: return cached 1290 1291 dependscache = set() 1292 treeview = set(idpackages) 1293 treelevel = set(idpackages) 1294 tree = {} 1295 # I start from level 1 because level 0 is idpackages itself 1296 treedepth = 0 1297 tree[treedepth] = set(idpackages) 1298 monotree = set(idpackages) # monodimensional tree 1299 1300 # post-dependencies won't be pulled in 1301 pdepend_id = etpConst['spm']['pdepend_id'] 1302 # check if dependstable is sane before beginning 1303 self.clientDbconn.retrieveDepends(idpackages[0]) 1304 count = 0 1305 1306 rem_dep_text = _("Calculating inverse dependencies for") 1307 while 1: 1308 treedepth += 1 1309 tree[treedepth] = set() 1310 for idpackage in treelevel: 1311 1312 count += 1 1313 p_atom = self.clientDbconn.retrieveAtom(idpackage) 1314 self.updateProgress( 1315 blue(rem_dep_text + " %s" % (red(p_atom),)), 1316 importance = 0, 1317 type = "info", 1318 back = True, 1319 header = '|/-\\'[count%4]+" " 1320 ) 1321 1322 systempkg = not self.validate_package_removal(idpackage) 1323 if (idpackage in dependscache) or systempkg: 1324 if idpackage in treeview: 1325 treeview.remove(idpackage) 1326 continue 1327 1328 # obtain its inverse deps 1329 depends = self.clientDbconn.retrieveDepends(idpackage, 1330 exclude_deptypes = (pdepend_id,)) 1331 # filter already satisfied ones 1332 depends = set([x for x in depends if x not in monotree]) 1333 depends = set([x for x in depends if \ 1334 self.validate_package_removal(x)]) 1335 if depends: 1336 depends = self._filter_depends_multimatched_atoms( 1337 idpackage, depends, monotree) 1338 if depends: # something depends on idpackage 1339 tree[treedepth] |= depends 1340 monotree |= depends 1341 treeview |= depends 1342 elif deep: # if deep, grab its dependencies and check 1343 1344 mydeps = set() 1345 for x in self.clientDbconn.retrieveDependencies(idpackage): 1346 match = self.clientDbconn.atomMatch(x) 1347 if match[0] != -1: 1348 mydeps.add(match[0]) 1349 1350 # now filter them 1351 mydeps = [x for x in mydeps if x not in monotree and not \ 1352 (self.clientDbconn.isSystemPackage(x) or \ 1353 self.is_installed_idpackage_in_system_mask(x) )] 1354 for x in mydeps: 1355 mydepends = self.clientDbconn.retrieveDepends(x) 1356 mydepends -= set([y for y in mydepends if y \ 1357 not in monotree]) 1358 if not mydepends: 1359 tree[treedepth].add(x) 1360 monotree.add(x) 1361 treeview.add(x) 1362 1363 dependscache.add(idpackage) 1364 if idpackage in treeview: 1365 treeview.remove(idpackage) 1366 1367 treelevel = treeview.copy() 1368 if not treelevel: 1369 if not tree[treedepth]: 1370 del tree[treedepth] # probably the last one is empty then 1371 break 1372 1373 # now filter newtree 1374 for count in sorted(tree.keys(), reverse = True): 1375 x = 0 1376 while x < count: 1377 tree[x] -= tree[count] 1378 x += 1 1379 1380 if self.xcache: 1381 self.Cacher.push(c_hash,(tree,0)) 1382 # treeview is used to show deps while 1383 # tree is used to run the dependency code. 1384 return tree,0
1385
1386 - def calculate_available_packages(self, use_cache = True):
1387 1388 c_hash = self.get_available_packages_chash() 1389 if use_cache and self.xcache: 1390 cached = self.get_available_packages_cache(myhash = c_hash) 1391 if cached != None: 1392 return cached 1393 1394 available = [] 1395 self.setTotalCycles(len(self.validRepositories)) 1396 avail_dep_text = _("Calculating available packages for") 1397 for repo in self.validRepositories: 1398 try: 1399 dbconn = self.open_repository(repo) 1400 dbconn.validateDatabase() 1401 except (RepositoryError,SystemDatabaseError): 1402 self.cycleDone() 1403 continue 1404 idpackages = [x for x in dbconn.listAllIdpackages( 1405 order_by = 'atom') if dbconn.idpackageValidator(x)[0] != -1] 1406 count = 0 1407 maxlen = len(idpackages) 1408 myavailable = [] 1409 do_break = False 1410 for idpackage in idpackages: 1411 if do_break: 1412 break 1413 count += 1 1414 if (count % 10 == 0) or (count == 1) or (count == maxlen): 1415 self.updateProgress( 1416 avail_dep_text + " %s" % (repo,), 1417 importance = 0, 1418 type = "info", 1419 back = True, 1420 header = "::", 1421 count = (count,maxlen), 1422 percent = True, 1423 footer = " ::" 1424 ) 1425 # get key + slot 1426 try: 1427 key, slot = dbconn.retrieveKeySlot(idpackage) 1428 matches = self.clientDbconn.searchKeySlot(key, slot) 1429 except (self.dbapi2.DatabaseError,self.dbapi2.IntegrityError,self.dbapi2.OperationalError,): 1430 self.cycleDone() 1431 do_break = True 1432 continue 1433 if not matches: myavailable.append((idpackage,repo)) 1434 available += myavailable[:] 1435 self.cycleDone() 1436 1437 if self.xcache: 1438 self.Cacher.push("%s%s" % ( 1439 etpCache['world_available'], c_hash), available) 1440 return available
1441
1442 - def calculate_critical_updates(self, use_cache = True):
1443 1444 db_digest = self.all_repositories_checksum() 1445 if use_cache and self.xcache: 1446 cached = self.get_critical_updates_cache(db_digest = db_digest) 1447 if cached != None: 1448 return cached 1449 1450 client_settings = self.SystemSettings[self.sys_settings_client_plugin_id] 1451 critical_data = client_settings['repositories']['critical_updates'] 1452 1453 atoms = set() 1454 atom_matches = {} 1455 for repoid in critical_data: 1456 for atom in critical_data[repoid]: 1457 match_id, match_repo = self.atom_match(atom) 1458 if match_repo == 1: 1459 continue 1460 atom_matches[atom] = (match_id, match_repo,) 1461 atoms.add(atom) 1462 1463 atoms = self.get_unsatisfied_dependencies(atoms) 1464 matches = [atom_matches.get(atom) for atom in atoms] 1465 data = (atoms, matches) 1466 1467 if self.xcache: 1468 c_hash = self.get_critical_update_cache_hash(db_digest) 1469 self.Cacher.push("%s%s" % (etpCache['critical_update'], c_hash,), 1470 data, async = False) 1471 1472 return data
1473 1474
1475 - def calculate_world_updates(self, empty_deps = False, use_cache = True, 1476 critical_updates = True):
1477 1478 cl_settings = self.SystemSettings[self.sys_settings_client_plugin_id] 1479 misc_settings = cl_settings['misc'] 1480 update = [] 1481 remove = [] 1482 fine = [] 1483 spm_fine = [] 1484 1485 # critical updates hook, if enabled 1486 # this will force callers to receive only critical updates 1487 if misc_settings.get('forcedupdates') and critical_updates: 1488 upd_atoms, upd_matches = self.calculate_critical_updates( 1489 use_cache = use_cache) 1490 if upd_atoms: 1491 return upd_matches, remove, fine, spm_fine 1492 1493 db_digest = self.all_repositories_checksum() 1494 if use_cache and self.xcache: 1495 cached = self.get_world_update_cache(empty_deps = empty_deps, 1496 db_digest = db_digest) 1497 if cached != None: 1498 return cached 1499 1500 1501 ignore_spm_downgrades = misc_settings['ignore_spm_downgrades'] 1502 1503 # get all the installed packages 1504 idpackages = self.clientDbconn.listAllIdpackages(order_by = 'atom') 1505 maxlen = len(idpackages) 1506 count = 0 1507 mytxt = _("Calculating world packages") 1508 for idpackage in idpackages: 1509 1510 count += 1 1511 if (count%10 == 0) or (count == maxlen) or (count == 1): 1512 self.updateProgress( 1513 mytxt, 1514 importance = 0, 1515 type = "info", 1516 back = True, 1517 header = ":: ", 1518 count = (count,maxlen), 1519 percent = True, 1520 footer = " ::" 1521 ) 1522 1523 try: 1524 cl_pkgkey, cl_slot, cl_version, \ 1525 cl_tag, cl_revision, \ 1526 cl_atom = self.clientDbconn.getStrictData(idpackage) 1527 except TypeError: 1528 # check against broken entries, or removed during iteration 1529 continue 1530 use_match_cache = True 1531 do_continue = False 1532 while 1: 1533 try: 1534 match = self.atom_match( 1535 cl_pkgkey, 1536 matchSlot = cl_slot, 1537 extendedResults = True, 1538 useCache = use_match_cache 1539 ) 1540 except self.dbapi2.OperationalError: 1541 # ouch, but don't crash here 1542 do_continue = True 1543 break 1544 try: 1545 m_idpackage = match[0][0] 1546 except TypeError: 1547 if not use_match_cache: raise 1548 use_match_cache = False 1549 continue 1550 break 1551 if do_continue: continue 1552 # now compare 1553 # version: cl_version 1554 # tag: cl_tag 1555 # revision: cl_revision 1556 if (m_idpackage != -1): 1557 repoid = match[1] 1558 version = match[0][1] 1559 tag = match[0][2] 1560 revision = match[0][3] 1561 if empty_deps: 1562 if (m_idpackage,repoid) not in update: 1563 update.append((m_idpackage,repoid)) 1564 continue 1565 elif (cl_revision != revision): 1566 # different revision 1567 if cl_revision == 9999 and ignore_spm_downgrades: 1568 # no difference, we're ignoring revision 9999 1569 fine.append(cl_atom) 1570 if (m_idpackage,repoid) not in update: 1571 spm_fine.append((m_idpackage,repoid)) 1572 continue 1573 else: 1574 if (m_idpackage,repoid) not in update: 1575 update.append((m_idpackage,repoid)) 1576 continue 1577 elif (cl_version != version): 1578 # different versions 1579 if (m_idpackage,repoid) not in update: 1580 update.append((m_idpackage,repoid)) 1581 continue 1582 elif (cl_tag != tag): 1583 # different tags 1584 if (m_idpackage,repoid) not in update: 1585 update.append((m_idpackage,repoid)) 1586 continue 1587 else: 1588 # no difference 1589 fine.append(cl_atom) 1590 continue 1591 1592 # don't take action if it's just masked 1593 maskedresults = self.atom_match(cl_pkgkey, matchSlot = cl_slot, 1594 packagesFilter = False) 1595 if maskedresults[0] == -1: 1596 remove.append(idpackage) 1597 # look for packages that would match key 1598 # with any slot (for eg: gcc, kernel updates) 1599 matchresults = self.atom_match(cl_pkgkey) 1600 if matchresults[0] != -1: 1601 m_action = self.get_package_action(matchresults) 1602 if m_action > 0 and (matchresults not in update): 1603 update.append(matchresults) 1604 1605 if self.xcache: 1606 c_hash = self.get_world_update_cache_hash(db_digest, empty_deps, 1607 ignore_spm_downgrades) 1608 data = { 1609 'r': (update, remove, fine, spm_fine,), 1610 'empty_deps': empty_deps, 1611 } 1612 self.Cacher.push("%s%s" % (etpCache['world_update'],c_hash,), 1613 data, async = False) 1614 1615 return update, remove, fine, spm_fine
1616
1617 - def check_package_update(self, atom, deep = False):
1618 1619 c_hash = "%s%s" % (etpCache['check_package_update'], 1620 hash("%s%s" % (atom, deep,) 1621 ), 1622 ) 1623 if self.xcache: 1624 cached = self.Cacher.pop(c_hash) 1625 if cached != None: 1626 return cached 1627 1628 found = False 1629 match = self.clientDbconn.atomMatch(atom) 1630 matched = None 1631 if match[0] != -1: 1632 myatom = self.clientDbconn.retrieveAtom(match[0]) 1633 mytag = self.entropyTools.dep_gettag(myatom) 1634 myatom = self.entropyTools.remove_tag(myatom) 1635 myrev = self.clientDbconn.retrieveRevision(match[0]) 1636 pkg_match = "="+myatom+"~"+str(myrev) 1637 if mytag != None: 1638 pkg_match += "#%s" % (mytag,) 1639 pkg_unsatisfied = self.get_unsatisfied_dependencies([pkg_match], deep_deps = deep) 1640 if pkg_unsatisfied: 1641 # does it really exist on current repos? 1642 pkg_key = self.entropyTools.dep_getkey(myatom) 1643 pkg_id, pkg_repo = self.atom_match(pkg_key) 1644 if pkg_id != -1: 1645 found = True 1646 del pkg_unsatisfied 1647 matched = self.atom_match(pkg_match) 1648 del match 1649 1650 if self.xcache: 1651 self.Cacher.push(c_hash,(found, matched)) 1652 return found, matched
1653
1654 - def validate_package_removal(self, idpackage):
1655 1656 pkgatom = self.clientDbconn.retrieveAtom(idpackage) 1657 pkgkey = self.entropyTools.dep_getkey(pkgatom) 1658 client_settings = self.SystemSettings[self.sys_settings_client_plugin_id] 1659 mask_installed_keys = client_settings['system_mask']['repos_installed_keys'] 1660 1661 if self.is_installed_idpackage_in_system_mask(idpackage): 1662 idpackages = mask_installed_keys.get(pkgkey) 1663 if not idpackages: return False 1664 if len(idpackages) > 1: 1665 return True 1666 return False # sorry! 1667 1668 # did we store the bastard in the db? 1669 system_pkg = self.clientDbconn.isSystemPackage(idpackage) 1670 if not system_pkg: return True 1671 # check if the package is slotted and exist more than one installed first 1672 matches, rc = self.clientDbconn.atomMatch(pkgkey, multiMatch = True) 1673 if len(matches) < 2: 1674 return False 1675 return True
1676 1677
1678 - def get_removal_queue(self, idpackages, deep = False):
1679 queue = [] 1680 if not idpackages: 1681 return queue 1682 treeview, status = self.generate_depends_tree(idpackages, deep = deep) 1683 if status == 0: 1684 for x in range(len(treeview))[::-1]: queue.extend(treeview[x]) 1685 return queue
1686
1687 - def get_install_queue(self, matched_atoms, empty_deps, deep_deps, quiet = False):
1688 1689 install = [] 1690 removal = [] 1691 treepackages, result = self.get_required_packages(matched_atoms, 1692 empty_deps, deep_deps, quiet = quiet) 1693 1694 if result == -2: 1695 return treepackages,removal,result 1696 1697 # format 1698 removal = treepackages.pop(0, set()) 1699 for dep_level in sorted(treepackages): 1700 install.extend(treepackages[dep_level]) 1701 1702 # filter out packages that are in actionQueue comparing key + slot 1703 if install and removal: 1704 myremmatch = {} 1705 for rm_idpackage in removal: 1706 keyslot = self.clientDbconn.retrieveKeySlot(rm_idpackage) 1707 # check if users removed idpackage while this 1708 # whole instance is running 1709 if keyslot is None: 1710 continue 1711 myremmatch[keyslot] = rm_idpackage 1712 1713 for pkg_id, pkg_repo in install: 1714 dbconn = self.open_repository(pkg_repo) 1715 testtuple = dbconn.retrieveKeySlot(pkg_id) 1716 removal.discard(myremmatch.get(testtuple)) 1717 1718 return install, sorted(removal), 0
1719