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, repo = repoid) 200 else: 201 dbconn = self.open_repository(repoid) 202 return dbconn
203
204 - def atom_match(self, atom, caseSensitive = True, matchSlot = None, 205 matchBranches = (), matchTag = None, packagesFilter = True, 206 multiMatch = False, multiRepo = False, matchRevision = None, 207 matchRepo = None, server_repos = [], serverInstance = None, 208 extendedResults = False, useCache = True):
209 210 # support match in repository from shell 211 # atom@repo1,repo2,repo3 212 atom, repos = self.entropyTools.dep_get_match_in_repos(atom) 213 if (matchRepo == None) and (repos != None): 214 matchRepo = repos 215 216 u_hash = "" 217 m_hash = "" 218 k_ms = "//" 219 k_mt = "@#@" 220 k_mr = "-1" 221 if isinstance(matchRepo,(list,tuple,set,)): u_hash = hash(frozenset(matchRepo)) 222 if isinstance(matchBranches,(list,tuple,set,)): m_hash = hash(frozenset(matchBranches)) 223 if isinstance(matchSlot,basestring): k_ms = matchSlot 224 if isinstance(matchTag,basestring): k_mt = matchTag 225 if isinstance(matchRevision,basestring): k_mr = matchRevision 226 227 c_hash = "|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s" % ( 228 atom,k_ms,k_mt,hash(packagesFilter), 229 hash(frozenset(self.validRepositories)), 230 hash(frozenset(self.SystemSettings['repositories']['available'])), 231 hash(multiMatch),hash(multiRepo),hash(caseSensitive), 232 k_mr,hash(extendedResults), 233 u_hash, m_hash 234 ) 235 c_hash = "%s%s" % (self.atomMatchCacheKey,hash(c_hash),) 236 237 if self.xcache and useCache: 238 cached = self.Cacher.pop(c_hash) 239 if cached != None: 240 try: 241 cached = self.__validate_atom_match_cache(cached, multiMatch, extendedResults, multiRepo, serverInstance) 242 except (TypeError,ValueError,IndexError,KeyError,): 243 cached = None 244 if cached != None: 245 return cached 246 247 if server_repos: 248 if not serverInstance: 249 t = _("server_repos needs serverInstance") 250 raise IncorrectParameter("IncorrectParameter: %s" % (t,)) 251 valid_repos = server_repos[:] 252 else: 253 valid_repos = self.validRepositories 254 if matchRepo and (type(matchRepo) in (list,tuple,set)): 255 valid_repos = list(matchRepo) 256 257 repoResults = {} 258 for repo in valid_repos: 259 260 # search 261 dbconn = self.__atom_match_open_db(repo, serverInstance) 262 use_cache = useCache 263 while 1: 264 try: 265 query_data, query_rc = dbconn.atomMatch( 266 atom, 267 caseSensitive = caseSensitive, 268 matchSlot = matchSlot, 269 matchBranches = matchBranches, 270 matchTag = matchTag, 271 packagesFilter = packagesFilter, 272 matchRevision = matchRevision, 273 extendedResults = extendedResults, 274 useCache = use_cache 275 ) 276 if query_rc == 0: 277 # package found, add to our dictionary 278 if extendedResults: 279 repoResults[repo] = (query_data[0],query_data[2],query_data[3],query_data[4]) 280 else: 281 repoResults[repo] = query_data 282 except TypeError: 283 if not use_cache: 284 raise 285 use_cache = False 286 continue 287 break 288 289 dbpkginfo = (-1,1) 290 if extendedResults: 291 dbpkginfo = ((-1,None,None,None),1) 292 293 if multiRepo and repoResults: 294 295 data = set() 296 for repoid in repoResults: 297 data.add((repoResults[repoid],repoid)) 298 dbpkginfo = (data,0) 299 300 elif len(repoResults) == 1: 301 # one result found 302 repo = repoResults.keys()[0] 303 dbpkginfo = (repoResults[repo],repo) 304 305 elif len(repoResults) > 1: 306 307 # we have to decide which version should be taken 308 mypkginfo = self.__handle_multi_repo_matches(repoResults, extendedResults, valid_repos, serverInstance) 309 if mypkginfo != None: dbpkginfo = mypkginfo 310 311 # multimatch support 312 if multiMatch: 313 314 if dbpkginfo[1] == 1: 315 dbpkginfo = (set(), 1) 316 else: # can be "0" or a string, but 1 means failure 317 if multiRepo: 318 data = set() 319 for q_id,q_repo in dbpkginfo[0]: 320 dbconn = self.__atom_match_open_db(q_repo, serverInstance) 321 query_data, query_rc = dbconn.atomMatch( 322 atom, 323 caseSensitive = caseSensitive, 324 matchSlot = matchSlot, 325 matchBranches = matchBranches, 326 matchTag = matchTag, 327 packagesFilter = packagesFilter, 328 multiMatch = True, 329 extendedResults = extendedResults 330 ) 331 if extendedResults: 332 for item in query_data: 333 data.add(((item[0],item[2],item[3],item[4]),q_repo)) 334 else: 335 for x in query_data: data.add((x,q_repo)) 336 dbpkginfo = (data,0) 337 else: 338 dbconn = self.__atom_match_open_db(dbpkginfo[1], serverInstance) 339 query_data, query_rc = dbconn.atomMatch( 340 atom, 341 caseSensitive = caseSensitive, 342 matchSlot = matchSlot, 343 matchBranches = matchBranches, 344 matchTag = matchTag, 345 packagesFilter = packagesFilter, 346 multiMatch = True, 347 extendedResults = extendedResults 348 ) 349 if extendedResults: 350 dbpkginfo = (set([((x[0],x[2],x[3],x[4]),dbpkginfo[1]) for x in query_data]),0) 351 else: 352 dbpkginfo = (set([(x,dbpkginfo[1]) for x in query_data]),0) 353 354 if self.xcache and useCache: 355 self.Cacher.push(c_hash,dbpkginfo) 356 357 return dbpkginfo
358 359 # expands package sets, and in future something more perhaps
360 - def packages_expand(self, packages):
361 new_packages = [] 362 363 for pkg_id in range(len(packages)): 364 package = packages[pkg_id] 365 366 # expand package sets 367 if package.startswith(etpConst['packagesetprefix']): 368 set_pkgs = sorted(list(self.package_set_expand(package, raise_exceptions = False))) 369 new_packages.extend([x for x in set_pkgs if x not in packages]) # atomMatch below will filter dupies 370 else: 371 new_packages.append(package) 372 373 return new_packages
374
375 - def package_set_expand(self, package_set, raise_exceptions = True):
376 377 max_recursion_level = 50 378 recursion_level = 0 379 380 def do_expand(myset, recursion_level, max_recursion_level): 381 recursion_level += 1 382 if recursion_level > max_recursion_level: 383 raise InvalidPackageSet('InvalidPackageSet: corrupted, too many recursions: %s' % (myset,)) 384 set_data, set_rc = self.package_set_match(myset[len(etpConst['packagesetprefix']):]) 385 if not set_rc: 386 raise InvalidPackageSet('InvalidPackageSet: not found: %s' % (myset,)) 387 (set_from, package_set, mydata,) = set_data 388 389 mypkgs = set() 390 for fset in mydata: # recursively 391 if fset.startswith(etpConst['packagesetprefix']): 392 mypkgs |= do_expand(fset, recursion_level, max_recursion_level) 393 else: 394 mypkgs.add(fset) 395 396 return mypkgs
397 398 if not package_set.startswith(etpConst['packagesetprefix']): 399 package_set = "%s%s" % (etpConst['packagesetprefix'],package_set,) 400 401 try: 402 mylist = do_expand(package_set, recursion_level, max_recursion_level) 403 except InvalidPackageSet: 404 if raise_exceptions: raise 405 mylist = set() 406 407 return mylist
408
409 - def package_set_list(self, server_repos = [], serverInstance = None, matchRepo = None):
410 return self.package_set_match('', matchRepo = matchRepo, server_repos = server_repos, serverInstance = serverInstance, search = True)[0]
411
412 - def package_set_search(self, package_set, server_repos = [], serverInstance = None, matchRepo = None):
413 # search support 414 if package_set == '*': package_set = '' 415 return self.package_set_match(package_set, matchRepo = matchRepo, server_repos = server_repos, serverInstance = serverInstance, search = True)[0]
416
417 - def __package_set_match_open_db(self, repoid, server_inst):
418 if server_inst != None: 419 dbconn = server_inst.open_server_repository(just_reading = True, repo = repoid) 420 else: 421 dbconn = self.open_repository(repoid) 422 return dbconn
423
424 - def package_set_match(self, package_set, multiMatch = False, matchRepo = None, server_repos = [], serverInstance = None, search = False):
425 426 # support match in repository from shell 427 # set@repo1,repo2,repo3 428 package_set, repos = self.entropyTools.dep_get_match_in_repos(package_set) 429 if (matchRepo == None) and (repos != None): 430 matchRepo = repos 431 432 if server_repos: 433 if not serverInstance: 434 t = _("server_repos needs serverInstance") 435 raise IncorrectParameter("IncorrectParameter: %s" % (t,)) 436 valid_repos = server_repos[:] 437 else: 438 valid_repos = self.validRepositories 439 440 if matchRepo and (type(matchRepo) in (list,tuple,set)): 441 valid_repos = list(matchRepo) 442 443 # if we search, we return all the matches available 444 if search: multiMatch = True 445 446 set_data = [] 447 448 while 1: 449 450 # check inside SystemSettings 451 if not server_repos: 452 if search: 453 mysets = [x for x in self.SystemSettings['system_package_sets'].keys() if (x.find(package_set) != -1)] 454 for myset in mysets: 455 mydata = self.SystemSettings['system_package_sets'].get(myset) 456 set_data.append((etpConst['userpackagesetsid'], unicode(myset), mydata.copy(),)) 457 else: 458 mydata = self.SystemSettings['system_package_sets'].get(package_set) 459 if mydata != None: 460 set_data.append((etpConst['userpackagesetsid'], unicode(package_set), mydata,)) 461 if not multiMatch: break 462 463 for repoid in valid_repos: 464 dbconn = self.__package_set_match_open_db(repoid, serverInstance) 465 if search: 466 mysets = dbconn.searchSets(package_set) 467 for myset in mysets: 468 mydata = dbconn.retrievePackageSet(myset) 469 set_data.append((repoid, myset, mydata.copy(),)) 470 else: 471 mydata = dbconn.retrievePackageSet(package_set) 472 if mydata: set_data.append((repoid, package_set, mydata,)) 473 if not multiMatch: break 474 475 break 476 477 if not set_data: return (),False 478 if multiMatch: return set_data,True 479 return set_data.pop(0),True
480
481 - def get_unsatisfied_dependencies(self, dependencies, deep_deps = False, depcache = None):
482 483 if self.xcache: 484 c_data = sorted(dependencies) 485 client_checksum = self.clientDbconn.database_checksum() 486 c_hash = hash("%s|%s|%s" % (c_data,deep_deps,client_checksum,)) 487 c_hash = "%s%s" % (etpCache['filter_satisfied_deps'],c_hash,) 488 cached = self.Cacher.pop(c_hash) 489 if cached != None: return cached 490 491 if not isinstance(depcache,dict): 492 depcache = {} 493 494 cdb_am = self.clientDbconn.atomMatch 495 am = self.atom_match 496 open_repo = self.open_repository 497 intf_error = self.dbapi2.InterfaceError 498 cdb_getversioning = self.clientDbconn.getVersioningData 499 etp_cmp = self.entropyTools.entropy_compare_versions 500 etp_get_rev = self.entropyTools.dep_get_entropy_revision 501 #do_needed_check = False 502 503 def fm_dep(dependency): 504 505 cached = depcache.get(dependency) 506 if cached != None: return cached 507 508 ### conflict 509 if dependency.startswith("!"): 510 idpackage,rc = cdb_am(dependency[1:]) 511 if idpackage != -1: 512 depcache[dependency] = dependency 513 return dependency 514 depcache[dependency] = 0 515 return 0 516 517 c_id,c_rc = cdb_am(dependency) 518 if c_id == -1: 519 depcache[dependency] = dependency 520 return dependency 521 522 #if not deep_deps and not do_needed_check: 523 # depcache[dependency] = 0 524 # return 0 525 526 r_id,r_repo = am(dependency) 527 if r_id == -1: 528 depcache[dependency] = dependency 529 return dependency 530 531 #if do_needed_check: 532 # dbconn = open_repo(r_repo) 533 # installed_needed = cdb_retrieveneededraw(c_id) 534 # repo_needed = dbconn.retrieveNeededRaw(r_id) 535 # if installed_needed != repo_needed: 536 # return dependency 537 # #elif not deep_deps: 538 # # return 0 539 540 dbconn = open_repo(r_repo) 541 try: 542 repo_pkgver, repo_pkgtag, repo_pkgrev = dbconn.getVersioningData(r_id) 543 except (intf_error,TypeError,): 544 # package entry is broken 545 return dependency 546 547 try: 548 installedVer, installedTag, installedRev = cdb_getversioning(c_id) 549 except TypeError: # corrupted entry? 550 installedVer = "0" 551 installedTag = '' 552 installedRev = 0 553 554 # support for app-foo/foo-123~-1 555 # -1 revision means, always pull the latest 556 do_deep = deep_deps 557 if not do_deep: 558 string_rev = etp_get_rev(dependency) 559 if string_rev == -1: 560 do_deep = True 561 562 vcmp = etp_cmp((repo_pkgver,repo_pkgtag,repo_pkgrev,), (installedVer,installedTag,installedRev,)) 563 if vcmp != 0: 564 if not do_deep and ((repo_pkgver,repo_pkgtag,) == (installedVer,installedTag,)) and (repo_pkgrev != installedRev): 565 depcache[dependency] = 0 566 return 0 567 depcache[dependency] = dependency 568 return dependency 569 depcache[dependency] = 0 570 return 0
571 572 unsatisfied = map(fm_dep,dependencies) 573 unsatisfied = set([x for x in unsatisfied if x != 0]) 574 575 if self.xcache: 576 self.Cacher.push(c_hash,unsatisfied) 577 578 return unsatisfied 579
580 - def get_masked_packages_tree(self, match, atoms = False, flat = False, matchfilter = None):
581 582 if not isinstance(matchfilter,set): 583 matchfilter = set() 584 585 maskedtree = {} 586 mybuffer = Lifo() 587 depcache = set() 588 treelevel = -1 589 590 match_id, match_repo = match 591 592 mydbconn = self.open_repository(match_repo) 593 myatom = mydbconn.retrieveAtom(match_id) 594 idpackage, idreason = mydbconn.idpackageValidator(match_id) 595 if idpackage == -1: 596 treelevel += 1 597 if atoms: 598 mydict = {myatom: idreason,} 599 else: 600 mydict = {match: idreason,} 601 if flat: 602 maskedtree.update(mydict) 603 else: 604 maskedtree[treelevel] = mydict 605 606 mydeps = mydbconn.retrieveDependencies(match_id) 607 for mydep in mydeps: mybuffer.push(mydep) 608 mydep = mybuffer.pop() 609 610 open_db = self.open_repository 611 am = self.atom_match 612 while mydep: 613 614 if mydep in depcache: 615 mydep = mybuffer.pop() 616 continue 617 depcache.add(mydep) 618 619 idpackage, repoid = am(mydep) 620 if (idpackage, repoid) in matchfilter: 621 mydep = mybuffer.pop() 622 continue 623 624 if idpackage != -1: 625 # doing even here because atomMatch with packagesFilter = False can pull 626 # something different 627 matchfilter.add((idpackage, repoid)) 628 629 # collect masked 630 if idpackage == -1: 631 idpackage, repoid = am(mydep, packagesFilter = False) 632 if idpackage != -1: 633 treelevel += 1 634 if not maskedtree.has_key(treelevel) and not flat: 635 maskedtree[treelevel] = {} 636 dbconn = open_db(repoid) 637 vidpackage, idreason = dbconn.idpackageValidator(idpackage) 638 if atoms: 639 mydict = {dbconn.retrieveAtom(idpackage): idreason} 640 else: 641 mydict = {(idpackage,repoid): idreason} 642 if flat: maskedtree.update(mydict) 643 else: maskedtree[treelevel].update(mydict) 644 645 # push its dep into the buffer 646 if idpackage != -1: 647 matchfilter.add((idpackage, repoid)) 648 dbconn = open_db(repoid) 649 owndeps = dbconn.retrieveDependencies(idpackage) 650 for owndep in owndeps: 651 mybuffer.push(owndep) 652 653 mydep = mybuffer.pop() 654 655 return maskedtree
656 657
658 - def generate_dependency_tree(self, 659 matched_atom, empty_deps = False, deep_deps = False, matchfilter = None, 660 flat = False, filter_unsat_cache = None, treecache = None, keyslotcache = None):
661 662 if not isinstance(matchfilter,set): 663 matchfilter = set() 664 if not isinstance(filter_unsat_cache,dict): 665 filter_unsat_cache = {} 666 if not isinstance(treecache,set): 667 treecache = set() 668 if not isinstance(keyslotcache,set): 669 keyslotcache = set() 670 671 mydbconn = self.open_repository(matched_atom[1]) 672 myatom = mydbconn.retrieveAtom(matched_atom[0]) 673 674 # caches 675 # special events 676 deps_not_found = set() 677 conflicts = set() 678 679 mydep = (1,myatom) 680 mybuffer = Lifo() 681 deptree = set() 682 if matched_atom not in matchfilter: 683 deptree.add((1,matched_atom)) 684 685 virgin = True 686 open_repo = self.open_repository 687 atom_match = self.atom_match 688 cdb_atom_match = self.clientDbconn.atomMatch 689 lookup_conflict_replacement = self._lookup_conflict_replacement 690 lookup_library_breakages = self._lookup_library_breakages 691 lookup_inverse_dependencies = self._lookup_inverse_dependencies 692 get_unsatisfied_deps = self.get_unsatisfied_dependencies 693 694 def my_dep_filter(x): 695 if x in treecache: return False 696 if tuple(x.split(":")) in keyslotcache: return False 697 return True
698 699 while mydep: 700 701 dep_level, dep_atom = mydep 702 703 # already analyzed in this call 704 if dep_atom in treecache: 705 mydep = mybuffer.pop() 706 continue 707 treecache.add(dep_atom) 708 709 if dep_atom == None: # corrupted entry 710 mydep = mybuffer.pop() 711 continue 712 713 # conflicts 714 if dep_atom[0] == "!": 715 c_idpackage, xst = cdb_atom_match(dep_atom[1:]) 716 if c_idpackage != -1: 717 myreplacement = lookup_conflict_replacement(dep_atom[1:], c_idpackage, deep_deps = deep_deps) 718 if (myreplacement != None) and (myreplacement not in treecache): 719 mybuffer.push((dep_level+1,myreplacement)) 720 else: 721 conflicts.add(c_idpackage) 722 mydep = mybuffer.pop() 723 continue 724 725 # atom found? 726 if virgin: 727 virgin = False 728 m_idpackage, m_repo = matched_atom 729 dbconn = open_repo(m_repo) 730 myidpackage, idreason = dbconn.idpackageValidator(m_idpackage) 731 if myidpackage == -1: m_idpackage = -1 732 else: 733 m_idpackage, m_repo = atom_match(dep_atom) 734 if m_idpackage == -1: 735 deps_not_found.add(dep_atom) 736 mydep = mybuffer.pop() 737 continue 738 739 # check if atom has been already pulled in 740 matchdb = open_repo(m_repo) 741 matchatom = matchdb.retrieveAtom(m_idpackage) 742 matchkey, matchslot = matchdb.retrieveKeySlot(m_idpackage) 743 if (dep_atom != matchatom) and (matchatom in treecache): 744 mydep = mybuffer.pop() 745 continue 746 747 treecache.add(matchatom) 748 749 # check if key + slot has been already pulled in 750 if (matchslot,matchkey) in keyslotcache: 751 mydep = mybuffer.pop() 752 continue 753 else: 754 keyslotcache.add((matchslot,matchkey)) 755 756 match = (m_idpackage, m_repo,) 757 # result already analyzed? 758 if match in matchfilter: 759 mydep = mybuffer.pop() 760 continue 761 762 # all checks passed, well done 763 matchfilter.add(match) 764 treedepth = dep_level+1 765 deptree.add((dep_level,match)) # add match 766 767 # extra hooks 768 cm_idpackage, cm_result = cdb_atom_match(matchkey, matchSlot = matchslot) 769 if cm_idpackage != -1: 770 broken_atoms = lookup_library_breakages(match, (cm_idpackage, cm_result,), deep_deps = deep_deps) 771 inverse_deps = lookup_inverse_dependencies(match, (cm_idpackage, cm_result,)) 772 if inverse_deps: 773 deptree.remove((dep_level,match)) 774 for ikey,islot in inverse_deps: 775 iks_str = '%s:%s' % (ikey,islot,) 776 if ((ikey,islot) not in keyslotcache) and (iks_str not in treecache): 777 mybuffer.push((dep_level,iks_str)) 778 keyslotcache.add((ikey,islot)) 779 deptree.add((treedepth,match)) 780 treedepth += 1 781 for x in broken_atoms: 782 if (tuple(x.split(":")) not in keyslotcache) and (x not in treecache): 783 mybuffer.push((treedepth,x)) 784 785 myundeps = filter(my_dep_filter,matchdb.retrieveDependenciesList(m_idpackage)) 786 if not empty_deps: 787 myundeps = filter(my_dep_filter,get_unsatisfied_deps(myundeps, deep_deps, depcache = filter_unsat_cache)) 788 789 # PDEPENDs support 790 if myundeps: 791 post_deps = [x for x in matchdb.retrievePostDependencies(m_idpackage) if x in myundeps] 792 if post_deps: 793 # only filter if post_deps contains something 794 myundeps = [x for x in myundeps if x not in post_deps] 795 for x in post_deps: mybuffer.push((-1,x)) # always after the package itself 796 797 for x in myundeps: mybuffer.push((treedepth,x)) 798 mydep = mybuffer.pop() 799 800 if deps_not_found: 801 return list(deps_not_found),-2 802 803 if flat: return [x[1] for x in deptree],0 804 805 newdeptree = {} 806 for key, item in deptree: 807 if key >= 0: 808 # this makes sure that key is never = 0 809 key += 1 810 obj = newdeptree.setdefault(key, set()) 811 obj.add(item) 812 # conflicts 813 newdeptree[0] = conflicts 814 815 return newdeptree,0 # note: newtree[0] contains possible conflicts 816 817
818 - def _lookup_system_mask_repository_deps(self):
819 820 data = self.SystemSettings['repos_system_mask'] 821 if not data: return [] 822 mydata = [] 823 cached_items = set() 824 for atom in data: 825 mymatch = self.atom_match(atom) 826 if mymatch[0] == -1: # ignore missing ones intentionally 827 continue 828 if mymatch in cached_items: 829 continue 830 if mymatch not in mydata: 831 # check if not found 832 myaction = self.get_package_action(mymatch) 833 # only if the package is not installed 834 if myaction == 1: mydata.append(mymatch) 835 cached_items.add(mymatch) 836 return mydata
837
838 - def _lookup_conflict_replacement(self, conflict_atom, client_idpackage, deep_deps):
839 if self.entropyTools.isjustname(conflict_atom): 840 return None 841 conflict_match = self.atom_match(conflict_atom) 842 mykey, myslot = self.clientDbconn.retrieveKeySlot(client_idpackage) 843 new_match = self.atom_match(mykey, matchSlot = myslot) 844 if (conflict_match == new_match) or (new_match[1] == 1): 845 return None 846 action = self.get_package_action(new_match) 847 if (action == 0) and (not deep_deps): 848 return None 849 return "%s:%s" % (mykey,myslot,)
850
851 - def _lookup_inverse_dependencies(self, match, clientmatch):
852 853 cmpstat = self.get_package_action(match) 854 if cmpstat == 0: return set() 855 856 keyslots = set() 857 mydepends = self.clientDbconn.retrieveDepends(clientmatch[0]) 858 am = self.atom_match 859 cdb_rdeps = self.clientDbconn.retrieveDependencies 860 cdb_rks = self.clientDbconn.retrieveKeySlot 861 gpa = self.get_package_action 862 keyslots_cache = set() 863 match_cache = {} 864 865 for idpackage in mydepends: 866 try: 867 key, slot = cdb_rks(idpackage) 868 except TypeError: 869 continue 870 if (key,slot) in keyslots_cache: continue 871 keyslots_cache.add((key,slot)) 872 if (key,slot) in keyslots: continue 873 # grab its deps 874 mydeps = cdb_rdeps(idpackage) 875 found = False 876 for mydep in mydeps: 877 mymatch = match_cache.get(mydep, 0) 878 if mymatch == 0: 879 mymatch = am(mydep) 880 match_cache[mydep] = mymatch 881 if mymatch == match: 882 found = True 883 break 884 if not found: 885 mymatch = am(key, matchSlot = slot) 886 if mymatch[0] == -1: continue 887 cmpstat = gpa(mymatch) 888 if cmpstat == 0: continue 889 keyslots.add((key,slot)) 890 891 return keyslots
892
893 - def __get_lib_breaks_client_and_repo_side(self, match_db, match_idpackage, client_idpackage):
894 repo_needed = match_db.retrieveNeeded(match_idpackage, extended = True, format = True) 895 client_needed = self.clientDbconn.retrieveNeeded(client_idpackage, extended = True, format = True) 896 repo_split = [x.split(".so")[0] for x in repo_needed] 897 client_split = [x.split(".so")[0] for x in client_needed] 898 client_side = [x for x in client_needed if (x not in repo_needed) and (x.split(".so")[0] in repo_split)] 899 repo_side = [x for x in repo_needed if (x not in client_needed) and (x.split(".so")[0] in client_split)] 900 return repo_needed, client_side, repo_side
901
902 - def _lookup_library_breakages(self, match, clientmatch, deep_deps = False):
903 904 # there is no need to update this cache when "match" will be installed, because at that point 905 # clientmatch[0] will differ. 906 c_hash = "%s|%s|%s" % (hash(tuple(match)),hash(deep_deps),hash(tuple(clientmatch)),) 907 c_hash = "%s%s" % (etpCache['library_breakage'],hash(c_hash),) 908 if self.xcache: 909 cached = self.Cacher.pop(c_hash) 910 if cached != None: return cached 911 912 # these should be pulled in before 913 repo_atoms = set() 914 # these can be pulled in after 915 client_atoms = set() 916 917 matchdb = self.open_repository(match[1]) 918 reponeeded, client_side, repo_side = self.__get_lib_breaks_client_and_repo_side(matchdb, 919 match[0], clientmatch[0]) 920 921 # all the packages in client_side should be pulled in and updated 922 client_idpackages = set() 923 for needed in client_side: client_idpackages |= self.clientDbconn.searchNeeded(needed) 924 925 client_keyslots = set() 926 def mymf(idpackage): 927 if idpackage == clientmatch[0]: 928 return 0 929 ks = self.clientDbconn.retrieveKeySlot(idpackage) 930 if ks is None: 931 return 0 932 return ks
933 client_keyslots = set([x for x in map(mymf,client_idpackages) if x != 0]) 934 935 # all the packages in repo_side should be pulled in too 936 repodata = {} 937 for needed in repo_side: 938 repodata[needed] = reponeeded[needed] 939 del repo_side,reponeeded 940 941 repo_dependencies = matchdb.retrieveDependencies(match[0]) 942 matched_deps = set() 943 matched_repos = set() 944 for dependency in repo_dependencies: 945 depmatch = self.atom_match(dependency) 946 if depmatch[0] == -1: 947 continue 948 matched_repos.add(depmatch[1]) 949 matched_deps.add(depmatch) 950 951 matched_repos = [x for x in self.SystemSettings['repositories']['order'] \ 952 if x in matched_repos] 953 found_matches = set() 954 for needed in repodata: 955 for myrepo in matched_repos: 956 mydbc = self.open_repository(myrepo) 957 solved_needed = mydbc.resolveNeeded(needed, 958 repodata[needed]) 959 found = False 960 for idpackage in solved_needed: 961 x = (idpackage, myrepo) 962 if x in matched_deps: 963 found_matches.add(x) 964 found = True 965 break 966 if found: 967 break 968 969 for idpackage,repo in found_matches: 970 if not deep_deps: 971 cmpstat = self.get_package_action((idpackage,repo)) 972 if cmpstat == 0: 973 continue 974 mydbc = self.open_repository(repo) 975 repo_atoms.add(mydbc.retrieveAtom(idpackage)) 976 977 for key, slot in client_keyslots: 978 idpackage, repo = self.atom_match(key, matchSlot = slot) 979 if idpackage == -1: 980 continue 981 if not deep_deps: 982 cmpstat = self.get_package_action((idpackage, repo)) 983 if cmpstat == 0: 984 continue 985 mydbc = self.open_repository(repo) 986 client_atoms.add(mydbc.retrieveAtom(idpackage)) 987 988 client_atoms |= repo_atoms 989 990 if self.xcache: 991 self.Cacher.push(c_hash,client_atoms) 992 993 return client_atoms 994 995
996 - def get_required_packages(self, matched_atoms, empty_deps = False, deep_deps = False, quiet = False):
997 998 c_hash = "%s%s" % (etpCache['dep_tree'],hash("%s|%s|%s|%s" % ( 999 hash(frozenset(sorted(matched_atoms))),hash(empty_deps), 1000 hash(deep_deps),self.clientDbconn.database_checksum(), 1001 )),) 1002 if self.xcache: 1003 cached = self.Cacher.pop(c_hash) 1004 if cached != None: return cached 1005 1006 deptree = {} 1007 deptree[0] = set() 1008 1009 atomlen = len(matched_atoms); count = 0 1010 error_generated = 0 1011 error_tree = set() 1012 1013 # check if there are repositories needing some mandatory packages 1014 forced_matches = self._lookup_system_mask_repository_deps() 1015 if forced_matches: 1016 if isinstance(matched_atoms, list): 1017 matched_atoms = forced_matches + [x for x in matched_atoms if x not in forced_matches] 1018 elif isinstance(matched_atoms, set): # we cannot do anything about the order here 1019 matched_atoms |= set(forced_matches) 1020 1021 sort_dep_text = _("Sorting dependencies") 1022 filter_unsat_cache = {} 1023 treecache = set() 1024 keyslotcache = set() 1025 matchfilter = set() 1026 for matched_atom in matched_atoms: 1027 1028 if not quiet: 1029 count += 1 1030 if (count%10 == 0) or (count == atomlen) or (count == 1): 1031 self.updateProgress(sort_dep_text, importance = 0, type = "info", 1032 back = True, header = ":: ", footer = " ::", 1033 percent = True, count = (count,atomlen)) 1034 1035 if matched_atom in matchfilter: continue 1036 newtree, result = self.generate_dependency_tree( 1037 matched_atom, empty_deps, deep_deps, 1038 matchfilter = matchfilter, filter_unsat_cache = filter_unsat_cache, treecache = treecache, 1039 keyslotcache = keyslotcache 1040 ) 1041 1042 if result == -2: # deps not found 1043 error_generated = -2 1044 error_tree |= set(newtree) # it is a list, we convert it into set and update error_tree 1045 elif (result != 0): 1046 return newtree, result 1047 elif newtree: 1048 # add conflicts 1049 max_parent_key = max(deptree) 1050 deptree[0] |= newtree.pop(0) 1051 levelcount = 0 1052 for mylevel in sorted(newtree.keys(), reverse = True): 1053 levelcount += 1 1054 deptree[max_parent_key+levelcount] = newtree.get(mylevel) 1055 1056 if error_generated != 0: 1057 return error_tree,error_generated 1058 1059 if self.xcache: 1060 self.Cacher.push(c_hash,(deptree,0)) 1061 1062 return deptree,0
1063
1064 - def _filter_depends_multimatched_atoms(self, idpackage, depends, monotree):
1065 remove_depends = set() 1066 for d_idpackage in depends: 1067 mydeps = self.clientDbconn.retrieveDependencies(d_idpackage) 1068 for mydep in mydeps: 1069 matches, rslt = self.clientDbconn.atomMatch(mydep, multiMatch = True) 1070 if rslt == 1: continue 1071 if idpackage in matches and len(matches) > 1: 1072 # are all in depends? 1073 for mymatch in matches: 1074 if mymatch not in depends and mymatch not in monotree: 1075 remove_depends.add(d_idpackage) 1076 break 1077 depends -= remove_depends 1078 return depends
1079 1080
1081 - def generate_depends_tree(self, idpackages, deep = False):
1082 1083 c_hash = "%s%s" % (etpCache['depends_tree'],hash("%s|%s" % ( 1084 hash(tuple(sorted(idpackages))),hash(deep),),),) 1085 if self.xcache: 1086 cached = self.Cacher.pop(c_hash) 1087 if cached != None: return cached 1088 1089 dependscache = set() 1090 treeview = set(idpackages) 1091 treelevel = set(idpackages) 1092 tree = {} 1093 # I start from level 1 because level 0 is idpackages itself 1094 treedepth = 0 1095 tree[treedepth] = set(idpackages) 1096 monotree = set(idpackages) # monodimensional tree 1097 1098 # post-dependencies won't be pulled in 1099 pdepend_id = etpConst['spm']['pdepend_id'] 1100 # check if dependstable is sane before beginning 1101 self.clientDbconn.retrieveDepends(idpackages[0]) 1102 count = 0 1103 1104 rem_dep_text = _("Calculating inverse dependencies for") 1105 while 1: 1106 treedepth += 1 1107 tree[treedepth] = set() 1108 for idpackage in treelevel: 1109 1110 count += 1 1111 p_atom = self.clientDbconn.retrieveAtom(idpackage) 1112 self.updateProgress( 1113 blue(rem_dep_text + " %s" % (red(p_atom),)), 1114 importance = 0, 1115 type = "info", 1116 back = True, 1117 header = '|/-\\'[count%4]+" " 1118 ) 1119 1120 systempkg = not self.validate_package_removal(idpackage) 1121 if (idpackage in dependscache) or systempkg: 1122 if idpackage in treeview: 1123 treeview.remove(idpackage) 1124 continue 1125 1126 # obtain its inverse deps 1127 depends = self.clientDbconn.retrieveDepends(idpackage, 1128 exclude_deptypes = (pdepend_id,)) 1129 # filter already satisfied ones 1130 depends = set([x for x in depends if x not in monotree]) 1131 depends = set([x for x in depends if \ 1132 self.validate_package_removal(x)]) 1133 if depends: 1134 depends = self._filter_depends_multimatched_atoms( 1135 idpackage, depends, monotree) 1136 if depends: # something depends on idpackage 1137 tree[treedepth] |= depends 1138 monotree |= depends 1139 treeview |= depends 1140 elif deep: # if deep, grab its dependencies and check 1141 1142 mydeps = set() 1143 for x in self.clientDbconn.retrieveDependencies(idpackage): 1144 match = self.clientDbconn.atomMatch(x) 1145 if match[0] != -1: 1146 mydeps.add(match[0]) 1147 1148 # now filter them 1149 mydeps = [x for x in mydeps if x not in monotree and not \ 1150 (self.clientDbconn.isSystemPackage(x) or \ 1151 self.is_installed_idpackage_in_system_mask(x) )] 1152 for x in mydeps: 1153 mydepends = self.clientDbconn.retrieveDepends(x) 1154 mydepends -= set([y for y in mydepends if y \ 1155 not in monotree]) 1156 if not mydepends: 1157 tree[treedepth].add(x) 1158 monotree.add(x) 1159 treeview.add(x) 1160 1161 dependscache.add(idpackage) 1162 if idpackage in treeview: 1163 treeview.remove(idpackage) 1164 1165 treelevel = treeview.copy() 1166 if not treelevel: 1167 if not tree[treedepth]: 1168 del tree[treedepth] # probably the last one is empty then 1169 break 1170 1171 # now filter newtree 1172 for count in sorted(tree.keys(), reverse = True): 1173 x = 0 1174 while x < count: 1175 tree[x] -= tree[count] 1176 x += 1 1177 1178 if self.xcache: 1179 self.Cacher.push(c_hash,(tree,0)) 1180 # treeview is used to show deps while 1181 # tree is used to run the dependency code. 1182 return tree,0
1183
1184 - def calculate_available_packages(self, use_cache = True):
1185 1186 branch = self.SystemSettings['repositories']['branch'] 1187 c_hash = self.get_available_packages_chash(branch) 1188 1189 if use_cache and self.xcache: 1190 cached = self.get_available_packages_cache(myhash = c_hash) 1191 if cached != None: 1192 return cached 1193 1194 available = [] 1195 self.setTotalCycles(len(self.validRepositories)) 1196 avail_dep_text = _("Calculating available packages for") 1197 for repo in self.validRepositories: 1198 try: 1199 dbconn = self.open_repository(repo) 1200 dbconn.validateDatabase() 1201 except (RepositoryError,SystemDatabaseError): 1202 self.cycleDone() 1203 continue 1204 idpackages = [x for x in dbconn.listAllIdpackages( 1205 order_by = 'atom') if dbconn.idpackageValidator(x)[0] != -1] 1206 count = 0 1207 maxlen = len(idpackages) 1208 myavailable = [] 1209 do_break = False 1210 for idpackage in idpackages: 1211 if do_break: 1212 break 1213 count += 1 1214 if (count % 10 == 0) or (count == 1) or (count == maxlen): 1215 self.updateProgress( 1216 avail_dep_text + " %s" % (repo,), 1217 importance = 0, 1218 type = "info", 1219 back = True, 1220 header = "::", 1221 count = (count,maxlen), 1222 percent = True, 1223 footer = " ::" 1224 ) 1225 # get key + slot 1226 try: 1227 key, slot = dbconn.retrieveKeySlot(idpackage) 1228 matches = self.clientDbconn.searchKeySlot(key, slot) 1229 except (self.dbapi2.DatabaseError,self.dbapi2.IntegrityError,self.dbapi2.OperationalError,): 1230 self.cycleDone() 1231 do_break = True 1232 continue 1233 if not matches: myavailable.append((idpackage,repo)) 1234 available += myavailable[:] 1235 self.cycleDone() 1236 1237 if self.xcache: 1238 self.Cacher.push("%s%s" % (etpCache['world_available'],c_hash),available) 1239 return available
1240
1241 - def calculate_world_updates(self, empty_deps = False, branch = None, 1242 use_cache = True):
1243 1244 if branch == None: 1245 branch = self.SystemSettings['repositories']['branch'] 1246 1247 db_digest = self.all_repositories_checksum() 1248 if use_cache and self.xcache: 1249 cached = self.get_world_update_cache(empty_deps = empty_deps, 1250 branch = branch, db_digest = db_digest) 1251 if cached != None: return cached 1252 1253 misc_settings = self.SystemSettings[self.sys_settings_client_plugin_id]['misc'] 1254 ignore_spm_downgrades = misc_settings['ignore_spm_downgrades'] 1255 update = [] 1256 remove = [] 1257 fine = [] 1258 spm_fine = [] 1259 1260 # get all the installed packages 1261 idpackages = self.clientDbconn.listAllIdpackages(order_by = 'atom') 1262 maxlen = len(idpackages) 1263 count = 0 1264 mytxt = _("Calculating world packages") 1265 for idpackage in idpackages: 1266 1267 count += 1 1268 if (count%10 == 0) or (count == maxlen) or (count == 1): 1269 self.updateProgress( 1270 mytxt, 1271 importance = 0, 1272 type = "info", 1273 back = True, 1274 header = ":: ", 1275 count = (count,maxlen), 1276 percent = True, 1277 footer = " ::" 1278 ) 1279 1280 try: 1281 cl_pkgkey, cl_slot, cl_version, \ 1282 cl_tag, cl_revision, \ 1283 cl_atom = self.clientDbconn.getStrictData(idpackage) 1284 except TypeError: 1285 # check against broken entries, or removed during iteration 1286 continue 1287 use_match_cache = True 1288 do_continue = False 1289 while 1: 1290 try: 1291 match = self.atom_match( 1292 cl_pkgkey, 1293 matchSlot = cl_slot, 1294 matchBranches = (branch,), 1295 extendedResults = True, 1296 useCache = use_match_cache 1297 ) 1298 except self.dbapi2.OperationalError: 1299 # ouch, but don't crash here 1300 do_continue = True 1301 break 1302 try: 1303 m_idpackage = match[0][0] 1304 except TypeError: 1305 if not use_match_cache: raise 1306 use_match_cache = False 1307 continue 1308 break 1309 if do_continue: continue 1310 # now compare 1311 # version: cl_version 1312 # tag: cl_tag 1313 # revision: cl_revision 1314 if (m_idpackage != -1): 1315 repoid = match[1] 1316 version = match[0][1] 1317 tag = match[0][2] 1318 revision = match[0][3] 1319 if empty_deps: 1320 if (m_idpackage,repoid) not in update: 1321 update.append((m_idpackage,repoid)) 1322 continue 1323 elif (cl_revision != revision): 1324 # different revision 1325 if cl_revision == 9999 and ignore_spm_downgrades: 1326 # no difference, we're ignoring revision 9999 1327 fine.append(cl_atom) 1328 if (m_idpackage,repoid) not in update: 1329 spm_fine.append((m_idpackage,repoid)) 1330 continue 1331 else: 1332 if (m_idpackage,repoid) not in update: 1333 update.append((m_idpackage,repoid)) 1334 continue 1335 elif (cl_version != version): 1336 # different versions 1337 if (m_idpackage,repoid) not in update: 1338 update.append((m_idpackage,repoid)) 1339 continue 1340 elif (cl_tag != tag): 1341 # different tags 1342 if (m_idpackage,repoid) not in update: 1343 update.append((m_idpackage,repoid)) 1344 continue 1345 else: 1346 # no difference 1347 fine.append(cl_atom) 1348 continue 1349 1350 # don't take action if it's just masked 1351 maskedresults = self.atom_match(cl_pkgkey, matchSlot = cl_slot, 1352 matchBranches = (branch,), packagesFilter = False) 1353 if maskedresults[0] == -1: 1354 remove.append(idpackage) 1355 # look for packages that would match key 1356 # with any slot (for eg: gcc, kernel updates) 1357 matchresults = self.atom_match(cl_pkgkey, 1358 matchBranches = (branch,)) 1359 if matchresults[0] != -1: 1360 m_action = self.get_package_action(matchresults) 1361 if m_action > 0 and (matchresults not in update): 1362 update.append(matchresults) 1363 1364 if self.xcache: 1365 c_hash = self.get_world_update_cache_hash(db_digest, empty_deps, 1366 branch, ignore_spm_downgrades) 1367 data = { 1368 'r': (update, remove, fine, spm_fine,), 1369 'empty_deps': empty_deps, 1370 } 1371 self.Cacher.push("%s%s" % (etpCache['world_update'],c_hash,), 1372 data, async = False) 1373 1374 return update, remove, fine, spm_fine
1375
1376 - def check_package_update(self, atom, deep = False):
1377 1378 c_hash = "%s%s" % (etpCache['check_package_update'],hash("%s%s" % (atom,hash(deep),)),) 1379 if self.xcache: 1380 cached = self.Cacher.pop(c_hash) 1381 if cached != None: 1382 return cached 1383 1384 found = False 1385 match = self.clientDbconn.atomMatch(atom) 1386 matched = None 1387 if match[0] != -1: 1388 myatom = self.clientDbconn.retrieveAtom(match[0]) 1389 mytag = self.entropyTools.dep_gettag(myatom) 1390 myatom = self.entropyTools.remove_tag(myatom) 1391 myrev = self.clientDbconn.retrieveRevision(match[0]) 1392 pkg_match = "="+myatom+"~"+str(myrev) 1393 if mytag != None: 1394 pkg_match += "#%s" % (mytag,) 1395 pkg_unsatisfied = self.get_unsatisfied_dependencies([pkg_match], deep_deps = deep) 1396 if pkg_unsatisfied: 1397 # does it really exist on current repos? 1398 pkg_key = self.entropyTools.dep_getkey(myatom) 1399 pkg_id, pkg_repo = self.atom_match(pkg_key) 1400 if pkg_id != -1: 1401 found = True 1402 del pkg_unsatisfied 1403 matched = self.atom_match(pkg_match) 1404 del match 1405 1406 if self.xcache: 1407 self.Cacher.push(c_hash,(found, matched)) 1408 return found, matched
1409 1410 # This is the function that should be used by third party applications 1411 # to retrieve a list of available updates, along with conflicts (removalQueue) and obsoletes 1412 # (removed)
1413 - def get_world_queue(self, empty_deps = False, branch = None):
1414 if branch == None: 1415 branch = self.SystemSettings['repositories']['branch'] 1416 update, remove, fine, spm_fine = self.calculate_world_updates( 1417 empty_deps = empty_deps, branch = branch) 1418 del fine 1419 data = {} 1420 data['removed'] = list(remove) 1421 data['runQueue'] = [] 1422 data['removalQueue'] = [] 1423 status = -1 1424 if update: 1425 # calculate install+removal queues 1426 install, removal, status = self.get_install_queue( 1427 update, empty_deps, deep_deps = False) 1428 # update data['removed'] 1429 data['removed'] = [x for x in data['removed'] if x not in removal] 1430 data['runQueue'] += install 1431 data['removalQueue'] += removal 1432 return data,status
1433
1434 - def validate_package_removal(self, idpackage):
1435 1436 pkgatom = self.clientDbconn.retrieveAtom(idpackage) 1437 pkgkey = self.entropyTools.dep_getkey(pkgatom) 1438 client_plugin_id = etpConst['system_settings_plugins_ids']['client_plugin'] 1439 mask_installed_keys = self.SystemSettings[client_plugin_id]['system_mask']['repos_installed_keys'] 1440 1441 if self.is_installed_idpackage_in_system_mask(idpackage): 1442 idpackages = mask_installed_keys.get(pkgkey) 1443 if not idpackages: return False 1444 if len(idpackages) > 1: 1445 return True 1446 return False # sorry! 1447 1448 # did we store the bastard in the db? 1449 system_pkg = self.clientDbconn.isSystemPackage(idpackage) 1450 if not system_pkg: return True 1451 # check if the package is slotted and exist more than one installed first 1452 matches, rc = self.clientDbconn.atomMatch(pkgkey, multiMatch = True) 1453 if len(matches) < 2: 1454 return False 1455 return True
1456 1457
1458 - def get_removal_queue(self, idpackages, deep = False):
1459 queue = [] 1460 if not idpackages: 1461 return queue 1462 treeview, status = self.generate_depends_tree(idpackages, deep = deep) 1463 if status == 0: 1464 for x in range(len(treeview))[::-1]: queue.extend(treeview[x]) 1465 return queue
1466
1467 - def get_install_queue(self, matched_atoms, empty_deps, deep_deps, quiet = False):
1468 1469 install = [] 1470 removal = [] 1471 treepackages, result = self.get_required_packages(matched_atoms, empty_deps, deep_deps, quiet = quiet) 1472 1473 if result == -2: 1474 return treepackages,removal,result 1475 1476 # format 1477 removal = treepackages.pop(0, set()) 1478 for x in sorted(treepackages.keys()): install.extend(treepackages[x]) 1479 1480 # filter out packages that are in actionQueue comparing key + slot 1481 if install and removal: 1482 myremmatch = {} 1483 for x in removal: 1484 atom = self.clientDbconn.retrieveAtom(x) 1485 # XXX check if users removed idpackage while this whole instance is running 1486 if atom == None: continue 1487 myremmatch[(self.entropyTools.dep_getkey(atom),self.clientDbconn.retrieveSlot(x),)] = x 1488 for pkg_id, pkg_repo in install: 1489 dbconn = self.open_repository(pkg_repo) 1490 testtuple = (self.entropyTools.dep_getkey(dbconn.retrieveAtom(pkg_id)),dbconn.retrieveSlot(pkg_id)) 1491 removal.discard(myremmatch.get(testtuple)) 1492 1493 return install, sorted(removal), 0
1494