Package yum :: Module packageSack
[hide private]
[frames] | no frames]

Source Code for Module yum.packageSack

   1  #!/usr/bin/python -tt 
   2  # This program is free software; you can redistribute it and/or modify 
   3  # it under the terms of the GNU General Public License as published by 
   4  # the Free Software Foundation; either version 2 of the License, or 
   5  # (at your option) any later version. 
   6  # 
   7  # This program is distributed in the hope that it will be useful, 
   8  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
   9  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  10  # GNU Library General Public License for more details. 
  11  # 
  12  # You should have received a copy of the GNU General Public License 
  13  # along with this program; if not, write to the Free Software 
  14  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
  15  # Copyright 2006 Duke University 
  16   
  17  """ 
  18  Classes for manipulating and querying groups of packages. 
  19  """ 
  20   
  21  from Errors import PackageSackError 
  22  import warnings 
  23  import re 
  24  import fnmatch 
  25  import misc 
  26  from packages import parsePackages 
  27   
28 -class PackageSackVersion:
29 - def __init__(self):
30 self._num = 0 31 self._chksum = misc.Checksums(['sha1'])
32
33 - def __str__(self):
34 return "%u:%s" % (self._num, self._chksum.hexdigest())
35
36 - def __eq__(self, other):
37 if other is None: return False 38 if type(other) in (type(''), type(u'')): 39 return str(self) == other 40 if self._num != other._num: return False 41 if self._chksum.digest() != other._chksum.digest(): return False 42 return True
43 - def __ne__(self, other):
44 return not (self == other)
45
46 - def update(self, pkg, csum):
47 self._num += 1 48 self._chksum.update(str(pkg)) 49 if csum is not None: 50 self._chksum.update(csum[0]) 51 self._chksum.update(csum[1])
52 53
54 -class PackageSackBase(object):
55 """Base class that provides the interface for PackageSacks."""
56 - def __init__(self):
57 self.added = {}
58
59 - def __len__(self):
60 return len(self.returnPackages())
61
62 - def __iter__(self):
63 ret = self.returnPackages() 64 if hasattr(ret, '__iter__'): 65 return ret.__iter__() 66 else: 67 return iter(ret)
68
69 - def __cmp__(self, other):
70 if other is None: 71 return 1 72 73 s_repos = list(self.added) 74 o_repos = list(other.added) 75 if len(s_repos) != len(o_repos): 76 return len(s_repos) - len(o_repos) 77 for (s_repo, o_repo) in zip(sorted(s_repos), sorted(o_repos)): 78 ret = cmp(s_repo, o_repo) 79 if ret: 80 return ret 81 return 0
82
83 - def setCompatArchs(self, compatArchs):
84 raise NotImplementedError()
85
86 - def populate(self, repo, mdtype, callback, cacheOnly):
87 raise NotImplementedError()
88
89 - def packagesByTuple(self, pkgtup):
90 """return a list of package objects by (n,a,e,v,r) tuple""" 91 warnings.warn('packagesByTuple() will go away in a future version of Yum.\n', 92 DeprecationWarning, stacklevel=2) 93 94 return self.searchPkgTuple(pkgtup)
95 96
97 - def searchNevra(self, name=None, epoch=None, ver=None, rel=None, arch=None):
98 """return list of pkgobjects matching the nevra requested""" 99 raise NotImplementedError()
100
101 - def searchNames(self, names=[]):
102 raise NotImplementedError()
103
104 - def searchPO(self, po):
105 """return list of package objects matching the name, epoch, ver, rel, 106 arch of the package object passed in""" 107 108 return self.searchNevra(name=po.name, epoch=po.epoch, ver=po.ver, 109 rel=po.rel, arch=po.arch)
110
111 - def searchPkgTuple(self, pkgtup):
112 """return list of pkgobject matching the (n,a,e,v,r) tuple""" 113 (n,a,e,v,r) = pkgtup 114 return self.searchNevra(name=n, arch=a, epoch=e, ver=v, rel=r)
115
116 - def contains(self, name=None, arch=None, epoch=None, ver=None, rel=None, po=None):
117 """return if there are any packages in the sack that match the given NAEVR 118 or the NAEVR of the given po""" 119 if po: 120 name = po.name 121 arch = po.arch 122 epoch = po.epoch 123 ver = po.version 124 rel = po.release 125 return bool(self.searchNevra(name=name, arch=arch, epoch=epoch, ver=ver, rel=rel))
126
127 - def getProvides(self, name, flags=None, version=(None, None, None)):
128 """return dict { packages -> list of matching provides }""" 129 raise NotImplementedError()
130
131 - def getRequires(self, name, flags=None, version=(None, None, None)):
132 """return dict { packages -> list of matching requires }""" 133 raise NotImplementedError()
134
135 - def searchRequires(self, name):
136 """return list of package requiring the name (any evr and flag)""" 137 raise NotImplementedError()
138
139 - def searchProvides(self, name):
140 """return list of package providing the name (any evr and flag)""" 141 raise NotImplementedError()
142
143 - def searchConflicts(self, name):
144 """return list of package conflicting with the name (any evr and flag)""" 145 raise NotImplementedError()
146
147 - def searchObsoletes(self, name):
148 """return list of package obsoleting the name (any evr and flag)""" 149 raise NotImplementedError()
150
151 - def returnObsoletes(self, newest=False):
152 """returns a dict of obsoletes dict[obsoleting pkgtuple] = [list of obs]""" 153 raise NotImplementedError()
154
155 - def searchFiles(self, name):
156 """return list of packages by filename""" 157 raise NotImplementedError()
158
159 - def addPackage(self, obj):
160 """add a pkgobject to the packageSack""" 161 raise NotImplementedError()
162
163 - def buildIndexes(self):
164 """builds the useful indexes for searching/querying the packageSack 165 This should be called after all the necessary packages have been 166 added/deleted""" 167 raise NotImplementedError()
168
169 - def delPackage(self, obj):
170 """delete a pkgobject""" 171 raise NotImplementedError()
172
173 - def returnPackages(self, repoid=None, patterns=None, ignore_case=False):
174 """return list of all packages""" 175 raise NotImplementedError()
176
177 - def addPackageExcluder(self, repoid, excluderid, excluder, *args):
178 """ Add an "excluder" for all packages in the repo/sack. Can basically 179 do anything based on nevra, changes lots of exclude decisions from 180 "preload package; test; delPackage" into "load excluder". 181 Excluderid is used so the caller doesn't have to track 182 "have I loaded the excluder for this repo.", it's probably only 183 useful when repoid is None ... if it turns out utterly worthless 184 then it's still not a huge wart. """ 185 raise NotImplementedError()
186
187 - def simpleVersion(self, main_only=False, groups={}):
188 """ Return a simple version for all available packages. """ 189 def _up_revs(arepos, repoid, rev, pkg, csum): 190 arevs = arepos.setdefault(repoid, {}) 191 rpsv = arevs.setdefault(None, PackageSackVersion()) 192 rpsv.update(pkg, csum) 193 if rev is not None: 194 rpsv = arevs.setdefault(rev, PackageSackVersion()) 195 rpsv.update(pkg, csum)
196 197 main = PackageSackVersion() 198 arepos = {} 199 main_grps = {} 200 arepos_grps = {} 201 for pkg in sorted(self.returnPackages()): 202 csum = pkg.returnIdSum() 203 main.update(pkg, csum) 204 205 for group in groups: 206 if pkg.name in groups[group]: 207 if group not in main_grps: 208 main_grps[group] = PackageSackVersion() 209 arepos_grps[group] = {} 210 main_grps[group].update(pkg, csum) 211 212 if main_only: 213 continue 214 215 rev = pkg.repo.repoXML.revision 216 _up_revs(arepos, pkg.repoid, rev, pkg, csum) 217 for group in groups: 218 if pkg.name in groups[group]: 219 _up_revs(arepos_grps[group], pkg.repoid, rev, pkg, csum) 220 221 if groups: 222 return [main, arepos, main_grps, arepos_grps] 223 return [main, arepos]
224
225 - def returnNewestByNameArch(self, naTup=None, 226 patterns=None, ignore_case=False):
227 """return list of newest packages based on name, arch matching 228 this means(in name.arch form): foo.i386 and foo.noarch are not 229 compared to each other for highest version only foo.i386 and 230 foo.i386 will be compared""" 231 raise NotImplementedError()
232
233 - def returnNewestByName(self, name=None, patterns=None, ignore_case=False):
234 """return list of newest packages based on name matching 235 this means(in name.arch form): foo.i386 and foo.noarch will 236 be compared to each other for highest version. 237 Note that given: foo-1.i386; foo-2.i386 and foo-3.x86_64 238 The last _two_ pkgs will be returned, not just one of them. """ 239 raise NotImplementedError()
240
241 - def simplePkgList(self, patterns=None, ignore_case=False):
242 """returns a list of pkg tuples (n, a, e, v, r)""" 243 raise NotImplementedError()
244
245 - def printPackages(self):
246 raise NotImplementedError()
247
248 - def excludeArchs(self, archlist):
249 """exclude incompatible arches. archlist is a list of compatible arches""" 250 raise NotImplementedError()
251
252 - def searchPackages(self, fields, criteria_re, callback):
253 raise NotImplementedError()
254
255 - def searchAll(self, arg, query_type):
256 raise NotImplementedError()
257
258 - def matchPackageNames(self, pkgspecs):
259 """take a list strings and match the packages in the sack against it 260 this will match against: 261 name 262 name.arch 263 name-ver-rel.arch 264 name-ver 265 name-ver-rel 266 epoch:name-ver-rel.arch 267 name-epoch:ver-rel.arch 268 269 return [exact matches], [glob matches], [unmatch search terms] 270 """ 271 # Setup match() for the search we're doing 272 matched = [] 273 exactmatch = [] 274 unmatched = set(pkgspecs) 275 276 specs = {} 277 for p in pkgspecs: 278 if misc.re_glob(p): 279 restring = fnmatch.translate(p) 280 specs[p] = re.compile(restring) 281 else: 282 specs[p] = p 283 284 # We don't use simplePkgList() here because that loads all of the 285 # rpmdb, if we are Eg. doing a "remove PackageKit". 286 pkgs = self.returnPackages(patterns=unmatched) 287 for pkgtup in [pkg.pkgtup for pkg in pkgs]: 288 (n,a,e,v,r) = pkgtup 289 names = set(( 290 n, 291 '%s.%s' % (n, a), 292 '%s-%s-%s.%s' % (n, v, r, a), 293 '%s-%s' % (n, v), 294 '%s-%s-%s' % (n, v, r), 295 '%s:%s-%s-%s.%s' % (e, n, v, r, a), 296 '%s-%s:%s-%s.%s' % (n, e, v, r, a), 297 )) 298 299 for (term,query) in specs.items(): 300 if term == query: 301 if query in names: 302 exactmatch.append(self.searchPkgTuple(pkgtup)[0]) 303 unmatched.discard(term) 304 else: 305 for n in names: 306 if query.match(n): 307 matched.append(self.searchPkgTuple(pkgtup)[0]) 308 unmatched.discard(term) 309 return misc.unique(exactmatch), misc.unique(matched), list(unmatched)
310
311 - def returnLeafNodes(self, repoid=None):
312 """returns a list of package objects that are not required by 313 any other package in this repository""" 314 315 def _return_all_provides(po): 316 """ Return all the provides, via. yield. """ 317 # These are done one by one, so that we get lazy loading 318 for prov in po.provides_names: 319 yield prov 320 for prov in po.filelist: 321 yield prov 322 for prov in po.dirlist: 323 yield prov 324 for prov in po.ghostlist: 325 yield prov
326 327 # fixme - maybe cache this list? 328 329 req = {} 330 orphans = [] 331 332 # prebuild the req dict 333 for po in self.returnPackages(repoid=repoid): 334 if not po.requires_names: 335 continue 336 for r in po.requires_names: 337 if r not in req: 338 req[r] = set() 339 if len(req[r]) > 1: # We only need to know if another pkg. 340 continue # reqs. the provide. So 2 pkgs. is enough. 341 req[r].add(po.name) 342 343 for po in self.returnPackages(repoid=repoid): 344 preq = 0 345 for p in _return_all_provides(po): 346 if req.has_key(p): 347 # If this pkg provides something that is required by 348 # anything but itself (or another version of itself) it 349 # isn't an orphan. 350 if len(req[p]) > 1 or po.name not in req[p]: 351 preq += 1 352 break 353 354 if preq == 0: 355 orphans.append(po) 356 357 return orphans 358
359 -class MetaSack(PackageSackBase):
360 """Represents the aggregate of multiple package sacks, such that they can 361 all be treated as one unified sack.""" 362
363 - def __init__(self):
364 PackageSackBase.__init__(self) 365 self.sacks = {} 366 self.compatarchs = None
367
368 - def __len__(self):
369 ret = 0 370 for sack in sorted(self.sacks.values()): 371 ret += len(sack) 372 return ret
373
374 - def dropCachedData(self):
375 for sack in self.sacks.values(): 376 if hasattr(sack, 'dropCachedData'): 377 sack.dropCachedData()
378
379 - def addSack(self, repoid, sack):
380 """Adds a repository's packageSack to this MetaSack.""" 381 self.sacks[repoid] = sack 382 383 # Make sure the new sack follows the same rules we have been given. 384 sack.setCompatArchs(self.compatarchs)
385
386 - def populate(self, repo, mdtype, callback, cacheOnly):
387 self.sacks[repo.id].populate(repo, mdtype, callback, cacheOnly)
388
389 - def setCompatArchs(self, compatArchs):
390 for sack in self.sacks.values(): 391 sack.setCompatArchs(compatArchs)
392
393 - def packagesByTuple(self, pkgtup):
394 """return a list of package objects by (n,a,e,v,r) tuple""" 395 warnings.warn('packagesByTuple() will go away in a future version of Yum.\n', 396 DeprecationWarning, stacklevel=2) 397 return self._computeAggregateListResult("packagesByTuple", pkgtup)
398
399 - def searchNevra(self, name=None, epoch=None, ver=None, rel=None, arch=None):
400 """return list of pkgobjects matching the nevra requested""" 401 return self._computeAggregateListResult("searchNevra", name, epoch, ver, rel, arch)
402
403 - def searchNames(self, names=[]):
404 return self._computeAggregateListResult("searchNames", names)
405
406 - def getProvides(self, name, flags=None, version=(None, None, None)):
407 """return dict { packages -> list of matching provides }""" 408 return self._computeAggregateDictResult("getProvides", name, flags, version)
409
410 - def getRequires(self, name, flags=None, version=(None, None, None)):
411 """return dict { packages -> list of matching requires }""" 412 return self._computeAggregateDictResult("getRequires", name, flags, version)
413
414 - def searchRequires(self, name):
415 """return list of package requiring the name (any evr and flag)""" 416 return self._computeAggregateListResult("searchRequires", name)
417
418 - def searchProvides(self, name):
419 """return list of package providing the name (any evr and flag)""" 420 return self._computeAggregateListResult("searchProvides", name)
421
422 - def searchConflicts(self, name):
423 """return list of package conflicting with the name (any evr and flag)""" 424 return self._computeAggregateListResult("searchConflicts", name)
425
426 - def searchObsoletes(self, name):
427 """return list of package obsoleting the name (any evr and flag)""" 428 return self._computeAggregateListResult("searchObsoletes", name)
429
430 - def returnObsoletes(self, newest=False):
431 """returns a dict of obsoletes dict[obsoleting pkgtuple] = [list of obs]""" 432 if not newest: 433 return self._computeAggregateDictResult("returnObsoletes") 434 435 obsdict = self._computeAggregateDictResult("returnObsoletes") 436 437 names = set((obstup[0] for obstup in obsdict)) 438 nobsdict = {} 439 last_name = '' 440 last_pkg = None 441 for pkg in reversed(sorted(self.searchNames(names))): 442 if last_name == pkg.name and not pkg.verEQ(last_pkg): 443 continue 444 last_name = pkg.name 445 last_pkg = pkg 446 if pkg.pkgtup in obsdict: 447 nobsdict[pkg.pkgtup] = obsdict[pkg.pkgtup] 448 return nobsdict
449
450 - def searchFiles(self, name):
451 """return list of packages by filename""" 452 return self._computeAggregateListResult("searchFiles", name)
453
454 - def addPackage(self, obj):
455 """Add a pkgobject to the packageSack. This is a meaningless operation 456 for the MetaSack.""" 457 pass
458
459 - def buildIndexes(self):
460 """builds the useful indexes for searching/querying the packageSack 461 This should be called after all the necessary packages have been 462 added/deleted""" 463 for sack in self.sacks.values(): 464 sack.buildIndexes()
465
466 - def delPackage(self, obj):
467 """Delete a pkgobject if it exists in every sub-sack.""" 468 obj.repo.sack.delPackage(obj)
469 470
471 - def returnPackages(self, repoid=None, patterns=None, ignore_case=False):
472 """Returns a list of packages. Note that the packages are 473 always filtered to those matching the patterns/case. An optional 474 repoid allows you to easily get data for a specific repo. """ 475 if not repoid: 476 return self._computeAggregateListResult("returnPackages", 477 None, patterns, ignore_case) 478 return self.sacks[repoid].returnPackages(patterns=patterns, 479 ignore_case=ignore_case)
480
481 - def addPackageExcluder(self, repoid, excluderid, excluder, *args):
482 """ Add an "excluder" for all packages in the repo/sack. Can basically 483 do anything based on nevra, changes lots of exclude decisions from 484 "preload package; test; delPackage" into "load excluder". 485 Excluderid is used so the caller doesn't have to track 486 "have I loaded the excluder for this repo.", it's probably only 487 useful when repoid is None ... if it turns out utterly worthless 488 then it's still not a huge wart. """ 489 if not repoid: 490 calr = self._computeAggregateListResult 491 return calr("addPackageExcluder", None, excluderid, excluder, *args) 492 return self.sacks[repoid].addPackageExcluder(None, 493 excluderid,excluder, *args)
494
495 - def returnNewestByNameArch(self, naTup=None, 496 patterns=None, ignore_case=False):
497 """return list of newest packages based on name, arch matching 498 this means(in name.arch form): foo.i386 and foo.noarch are not 499 compared to each other for highest version only foo.i386 and 500 foo.i386 will be compared""" 501 calr = self._computeAggregateListResult 502 pkgs = calr("returnNewestByNameArch", naTup, patterns, ignore_case) 503 pkgs = packagesNewestByNameArch(pkgs) 504 if not pkgs and (naTup or patterns): 505 ui_pats = ", ".join(patterns or []) 506 raise PackageSackError, 'No Package Matching %s' % ui_pats 507 return pkgs
508
509 - def returnNewestByName(self, name=None, patterns=None, ignore_case=False):
510 """return list of newest packages based on name matching 511 this means(in name.arch form): foo.i386 and foo.noarch will 512 be compared to each other for highest version. 513 Note that given: foo-1.i386; foo-2.i386 and foo-3.x86_64 514 The last _two_ pkgs will be returned, not just one of them. """ 515 pkgs = self._computeAggregateListResult("returnNewestByName", name, 516 patterns, ignore_case) 517 pkgs = packagesNewestByName(pkgs) 518 if not pkgs and (name or patterns): 519 if name: 520 ui_pats = name 521 else: 522 ui_pats = ", ".join(patterns or []) 523 raise PackageSackError, 'No Package Matching %s' % ui_pats 524 return pkgs
525
526 - def simplePkgList(self, patterns=None, ignore_case=False):
527 """returns a list of pkg tuples (n, a, e, v, r)""" 528 return self._computeAggregateListResult("simplePkgList", 529 patterns, ignore_case)
530
531 - def printPackages(self):
532 for sack in self.sacks.values(): 533 sack.printPackages()
534
535 - def excludeArchs(self, archlist):
536 """exclude incompatible arches. archlist is a list of compatible arches""" 537 for sack in self.sacks.values(): 538 sack.excludeArchs(archlist)
539
540 - def searchPackages(self, fields, criteria_re, callback):
541 return self._computeAggregateDictResult("searchPackages", fields, criteria_re, callback)
542
543 - def searchAll(self, arg, query_type):
544 return self._computeAggregateListResult("searchAll", arg, query_type)
545
546 - def matchPackageNames(self, pkgspecs):
547 matched = [] 548 exactmatch = [] 549 unmatched = None 550 for sack in self.sacks.values(): 551 if hasattr(sack, "matchPackageNames"): 552 e, m, u = [], [], [] 553 try: 554 e, m, u = sack.matchPackageNames(pkgspecs) 555 except PackageSackError: 556 continue 557 558 exactmatch.extend(e) 559 matched.extend(m) 560 if unmatched is None: 561 unmatched = set(u) 562 else: 563 unmatched = unmatched.intersection(set(u)) 564 565 matched = misc.unique(matched) 566 exactmatch = misc.unique(exactmatch) 567 if unmatched is None: 568 unmatched = [] 569 else: 570 unmatched = list(unmatched) 571 return exactmatch, matched, unmatched
572
573 - def _computeAggregateListResult(self, methodName, *args):
574 result = [] 575 for sack in sorted(self.sacks.values()): 576 if hasattr(sack, methodName): 577 method = getattr(sack, methodName) 578 try: 579 sackResult = apply(method, args) 580 except PackageSackError: 581 continue 582 583 if sackResult: 584 result.extend(sackResult) 585 586 return result
587
588 - def _computeAggregateDictResult(self, methodName, *args):
589 result = {} 590 for sack in sorted(self.sacks.values()): 591 if hasattr(sack, methodName): 592 method = getattr(sack, methodName) 593 try: 594 sackResult = apply(method, args) 595 except PackageSackError: 596 continue 597 598 if sackResult: 599 result.update(sackResult) 600 return result
601 602 603
604 -class PackageSack(PackageSackBase):
605 """represents sets (sacks) of Package Objects"""
606 - def __init__(self):
607 self.nevra = {} #nevra[(Name, Epoch, Version, Release, Arch)] = [] 608 self.obsoletes = {} #obs[obsoletename] = [pkg1, pkg2, pkg3] 609 #the package lists are packages that obsolete the key name 610 self.requires = {} #req[reqname] = [pkg1, pkg2, pkg3] 611 #the package lists are packages that require the key name 612 self.provides = {} #ditto of above but for provides 613 self.conflicts = {} #ditto of above but for conflicts 614 self.filenames = {} # duh 615 self.pkgsByRepo = {} #pkgsByRepo['repoid']= [pkg1, pkg2, pkg3] 616 self.pkgsByID = {} #pkgsById[pkgid] = [pkg1, pkg2] (should really only ever be one value but 617 #you might have repos with the same package in them 618 self.compatarchs = None # dict of compatible archs for addPackage 619 self.indexesBuilt = 0
620 621
622 - def __len__(self):
623 ret = 0 624 for repo in self.pkgsByRepo: 625 ret += len(self.pkgsByRepo[repo]) 626 return ret
627 628
629 - def _checkIndexes(self, failure='error'):
630 """check to see if the indexes are built, if not do what failure demands 631 either error out or build the indexes, default is to error out""" 632 633 if not self.indexesBuilt: 634 if failure == 'error': 635 raise PackageSackError, 'Indexes not yet built, cannot search' 636 elif failure == 'build': 637 self.buildIndexes()
638
639 - def dropCachedData(self):
640 """ Do nothing, mainly for the testing code. """ 641 pass
642
643 - def setCompatArchs(self, compatarchs):
644 self.compatarchs = compatarchs
645
646 - def searchNevra(self, name=None, epoch=None, ver=None, rel=None, arch=None):
647 """return list of pkgobjects matching the nevra requested""" 648 self._checkIndexes(failure='build') 649 if (name, epoch, ver, rel, arch) in self.nevra: 650 return self.nevra[(name, epoch, ver, rel, arch)] 651 elif name is not None: 652 pkgs = self.nevra.get((name, None, None, None, None), []) 653 else: 654 pkgs = [] 655 for pkgsbyRepo in self.pkgsByRepo.itervalues(): 656 pkgs.extend(pkgsbyRepo) 657 658 result = [ ] 659 for po in pkgs: 660 if ((name and name!=po.name) or 661 (epoch and epoch!=po.epoch) or 662 (ver and ver!=po.ver) or 663 (rel and rel!=po.rel) or 664 (arch and arch!=po.arch)): 665 continue 666 result.append(po) 667 return result
668
669 - def searchNames(self, names=[]):
670 """return list of pkgobjects matching the names requested""" 671 self._checkIndexes(failure='build') 672 result = [] 673 done = set() 674 for name in names: 675 if name in done: 676 continue 677 done.add(name) 678 result.extend(self.nevra.get((name, None, None, None, None), [])) 679 return result
680
681 - def getProvides(self, name, flags=None, version=(None, None, None)):
682 """return dict { packages -> list of matching provides }""" 683 self._checkIndexes(failure='build') 684 result = { } 685 for po in self.provides.get(name, []): 686 hits = po.matchingPrcos('provides', (name, flags, version)) 687 if hits: 688 result[po] = hits 689 if name[0] == '/': 690 hit = (name, None, (None, None, None)) 691 for po in self.searchFiles(name): 692 result.setdefault(po, []).append(hit) 693 return result
694
695 - def getRequires(self, name, flags=None, version=(None, None, None)):
696 """return dict { packages -> list of matching requires }""" 697 self._checkIndexes(failure='build') 698 result = { } 699 for po in self.requires.get(name, []): 700 hits = po.matchingPrcos('requires', (name, flags, version)) 701 if hits: 702 result[po] = hits 703 return result
704
705 - def searchPrco(self, name, prcotype):
706 self._checkIndexes(failure='build') 707 prcodict = getattr(self, prcotype) 708 (n,f,(e,v,r)) = misc.string_to_prco_tuple(name) 709 710 basic_results = [] 711 results = [] 712 if n in prcodict: 713 basic_results.extend(prcodict[n]) 714 715 for po in basic_results: 716 if po.checkPrco(prcotype, (n, f, (e,v,r))): 717 results.append(po) 718 719 if prcotype != "provides": 720 return results 721 722 if not misc.re_filename(n): 723 return results 724 725 results.extend(self.searchFiles(n)) 726 return misc.unique(results)
727 728
729 - def searchRequires(self, name):
730 """return list of package requiring the item requested""" 731 732 return self.searchPrco(name, 'requires')
733
734 - def searchProvides(self, name):
735 """return list of package providing the item requested""" 736 737 return self.searchPrco(name, 'provides')
738
739 - def searchConflicts(self, name):
740 """return list of package conflicting with item requested""" 741 742 return self.searchPrco(name, 'conflicts')
743
744 - def searchObsoletes(self, name):
745 """return list of package obsoleting the item requested""" 746 747 return self.searchPrco(name, 'obsoletes')
748
749 - def returnObsoletes(self, newest=False):
750 """returns a dict of obsoletes dict[obsoleting pkgtuple] = [list of obs]""" 751 obs = {} 752 for po in self.returnPackages(): 753 if len(po.obsoletes) == 0: 754 continue 755 obs.setdefault(po.pkgtup, []).extend(po.obsoletes) 756 757 if not newest: 758 return obs 759 760 # FIXME - this is slooooooooooooooooooooooooooooooow 761 # get the dict back 762 newest_tups = set((pkg.pkgtup for pkg in self.returnNewestByName())) 763 764 # go through each of the keys of the obs dict and see if it is in the 765 # sack of newest pkgs - if it is not - remove the entry 766 togo = [] 767 for obstup in obs: 768 if obstup not in newest_tups: 769 togo.append(obstup) 770 for obstup in togo: 771 del obs[obstup] 772 773 return obs
774
775 - def searchFiles(self, name):
776 """return list of packages by filename 777 FIXME - need to add regex match against keys in file list 778 """ 779 self._checkIndexes(failure='build') 780 if self.filenames.has_key(name): 781 return self.filenames[name] 782 else: 783 return []
784
785 - def _addToDictAsList(self, dict, key, data):
786 if not dict.has_key(key): 787 dict[key] = [] 788 #if data not in dict[key]: - if I enable this the whole world grinds to a halt 789 # need a faster way of looking for the object in any particular list 790 dict[key].append(data)
791
792 - def _delFromListOfDict(self, dict, key, data):
793 if key not in dict: 794 return 795 try: 796 dict[key].remove(data) 797 except ValueError: 798 pass 799 800 if len(dict[key]) == 0: # if it's an empty list of the dict, then kill it 801 del dict[key]
802 803
804 - def addPackage(self, obj):
805 """add a pkgobject to the packageSack""" 806 807 repoid = obj.repoid 808 (name, arch, epoch, ver, rel) = obj.pkgtup 809 810 if not self.compatarchs or arch in self.compatarchs: 811 self._addToDictAsList(self.pkgsByRepo, repoid, obj) 812 if self.indexesBuilt: 813 self._addPackageToIndex(obj)
814
815 - def buildIndexes(self):
816 """builds the useful indexes for searching/querying the packageSack 817 This should be called after all the necessary packages have been 818 added/deleted""" 819 820 self.clearIndexes() 821 822 for repoid in self.pkgsByRepo: 823 for obj in self.pkgsByRepo[repoid]: 824 self._addPackageToIndex(obj) 825 self.indexesBuilt = 1
826 827
828 - def clearIndexes(self):
829 # blank out the indexes 830 self.obsoletes = {} 831 self.requires = {} 832 self.provides = {} 833 self.conflicts = {} 834 self.filenames = {} 835 self.nevra = {} 836 self.pkgsByID = {} 837 838 self.indexesBuilt = 0
839
840 - def _addPackageToIndex(self, obj):
841 # store the things provided just on name, not the whole require+version 842 # this lets us reduce the set of pkgs to search when we're trying to depSolve 843 for (n, fl, (e,v,r)) in obj.returnPrco('obsoletes'): 844 self._addToDictAsList(self.obsoletes, n, obj) 845 for (n, fl, (e,v,r)) in obj.returnPrco('requires'): 846 self._addToDictAsList(self.requires, n, obj) 847 for (n, fl, (e,v,r)) in obj.returnPrco('provides'): 848 self._addToDictAsList(self.provides, n, obj) 849 for (n, fl, (e,v,r)) in obj.returnPrco('conflicts'): 850 self._addToDictAsList(self.conflicts, n, obj) 851 for ftype in obj.returnFileTypes(): 852 for file in obj.returnFileEntries(ftype): 853 self._addToDictAsList(self.filenames, file, obj) 854 self._addToDictAsList(self.pkgsByID, obj.id, obj) 855 (name, arch, epoch, ver, rel) = obj.pkgtup 856 self._addToDictAsList(self.nevra, (name, epoch, ver, rel, arch), obj) 857 self._addToDictAsList(self.nevra, (name, None, None, None, None), obj)
858
859 - def _delPackageFromIndex(self, obj):
860 for (n, fl, (e,v,r)) in obj.returnPrco('obsoletes'): 861 self._delFromListOfDict(self.obsoletes, n, obj) 862 for (n, fl, (e,v,r)) in obj.returnPrco('requires'): 863 self._delFromListOfDict(self.requires, n, obj) 864 for (n, fl, (e,v,r)) in obj.returnPrco('provides'): 865 self._delFromListOfDict(self.provides, n, obj) 866 for (n, fl, (e,v,r)) in obj.returnPrco('conflicts'): 867 self._delFromListOfDict(self.conflicts, n, obj) 868 for ftype in obj.returnFileTypes(): 869 for file in obj.returnFileEntries(ftype): 870 self._delFromListOfDict(self.filenames, file, obj) 871 self._delFromListOfDict(self.pkgsByID, obj.id, obj) 872 (name, arch, epoch, ver, rel) = obj.pkgtup 873 self._delFromListOfDict(self.nevra, (name, epoch, ver, rel, arch), obj) 874 self._delFromListOfDict(self.nevra, (name, None, None, None, None), obj)
875
876 - def delPackage(self, obj):
877 """delete a pkgobject""" 878 self._delFromListOfDict(self.pkgsByRepo, obj.repoid, obj) 879 if self.indexesBuilt: 880 self._delPackageFromIndex(obj)
881
882 - def returnPackages(self, repoid=None, patterns=None, ignore_case=False):
883 """return list of all packages, takes optional repoid""" 884 returnList = [] 885 if repoid is None: 886 for repo in self.pkgsByRepo: 887 returnList.extend(self.pkgsByRepo[repo]) 888 else: 889 try: 890 returnList = self.pkgsByRepo[repoid] 891 except KeyError: 892 # nothing to return 893 pass 894 895 if patterns: 896 returnList = parsePackages(returnList, patterns, not ignore_case, 897 unique='repo-pkgkey') 898 returnList = returnList[0] + returnList[1] 899 return returnList
900
901 - def returnNewestByNameArch(self, naTup=None, 902 patterns=None, ignore_case=False):
903 """return list of newest packages based on name, arch matching 904 this means(in name.arch form): foo.i386 and foo.noarch are not 905 compared to each other for highest version only foo.i386 and 906 foo.i386 will be compared""" 907 highdict = {} 908 # If naTup is set, only iterate through packages that match that 909 # name 910 if (naTup): 911 self._checkIndexes(failure='build') 912 where = self.nevra.get((naTup[0],None,None,None,None)) 913 if (not where): 914 raise PackageSackError, 'No Package Matching %s.%s' % naTup 915 else: 916 where = self.returnPackages(patterns=patterns, 917 ignore_case=ignore_case) 918 919 for pkg in where: 920 if not highdict.has_key((pkg.name, pkg.arch)): 921 highdict[(pkg.name, pkg.arch)] = pkg 922 else: 923 pkg2 = highdict[(pkg.name, pkg.arch)] 924 if pkg.verGT(pkg2): 925 highdict[(pkg.name, pkg.arch)] = pkg 926 927 if naTup: 928 if naTup in highdict: 929 return [highdict[naTup]] 930 else: 931 raise PackageSackError, 'No Package Matching %s.%s' % naTup 932 933 return highdict.values()
934
935 - def returnNewestByName(self, name=None, patterns=None, ignore_case=False):
936 """return list of newest packages based on name matching 937 this means(in name.arch form): foo.i386 and foo.noarch will 938 be compared to each other for highest version. 939 Note that given: foo-1.i386; foo-2.i386 and foo-3.x86_64 940 The last _two_ pkgs will be returned, not just one of them. """ 941 942 highdict = {} 943 for pkg in self.returnPackages(patterns=patterns, 944 ignore_case=ignore_case): 945 if not highdict.has_key(pkg.name): 946 highdict[pkg.name] = [] 947 highdict[pkg.name].append(pkg) 948 else: 949 pkg2 = highdict[pkg.name][0] 950 if pkg.verGT(pkg2): 951 highdict[pkg.name] = [pkg] 952 if pkg.verEQ(pkg2): 953 highdict[pkg.name].append(pkg) 954 955 if name: 956 if name in highdict: 957 return highdict[name] 958 else: 959 raise PackageSackError, 'No Package Matching %s' % name 960 961 #this is a list of lists - break it back out into a single list 962 returnlist = [] 963 for polst in highdict.values(): 964 for po in polst: 965 returnlist.append(po) 966 967 return returnlist
968
969 - def simplePkgList(self, patterns=None, ignore_case=False):
970 """returns a list of pkg tuples (n, a, e, v, r) optionally from a single repoid""" 971 972 # Don't cache due to excludes 973 return [pkg.pkgtup for pkg in self.returnPackages(patterns=patterns, 974 ignore_case=False)]
975
976 - def printPackages(self):
977 for pkg in self.returnPackages(): 978 print pkg
979
980 - def excludeArchs(self, archlist):
981 """exclude incompatible arches. archlist is a list of compatible arches""" 982 983 for pkg in self.returnPackages(): 984 if pkg.arch not in archlist: 985 self.delPackage(pkg)
986
987 - def searchPackages(self, fields, criteria_re, callback):
988 matches = {} 989 990 for po in self.returnPackages(): 991 tmpvalues = [] 992 for field in fields: 993 value = getattr(po, field) 994 if value and criteria_re.search(value): 995 tmpvalues.append(value) 996 if len(tmpvalues) > 0: 997 if callback: 998 callback(po, tmpvalues) 999 matches[po] = tmpvalues 1000 1001 return matches
1002
1003 -def packagesNewestByName(pkgs):
1004 """ Does the same as PackageSack.returnNewestByName(). 1005 Note that given: foo-1.i386; foo-2.i386 and foo-3.x86_64 1006 The last _two_ pkgs will be returned, not just one of them. """ 1007 newest = {} 1008 for pkg in pkgs: 1009 key = pkg.name 1010 1011 # Can't use pkg.__cmp__ because it takes .arch into account 1012 cval = 1 1013 if key in newest: 1014 cval = pkg.verCMP(newest[key][0]) 1015 if cval > 0: 1016 newest[key] = [pkg] 1017 elif cval == 0: 1018 newest[key].append(pkg) 1019 ret = [] 1020 for vals in newest.itervalues(): 1021 ret.extend(vals) 1022 return ret
1023 -def packagesNewestByNameArch(pkgs):
1024 """ Does the same as PackageSack.returnNewestByNameArch() """ 1025 newest = {} 1026 for pkg in pkgs: 1027 key = (pkg.name, pkg.arch) 1028 if key in newest and pkg.verLE(newest[key]): 1029 continue 1030 newest[key] = pkg 1031 return newest.values()
1032
1033 -class ListPackageSack(PackageSack):
1034 """Derived class from PackageSack to build new Sack from list of 1035 pkgObjects - like one returned from self.returnNewestByNameArch() 1036 or self.returnNewestByName()""" 1037
1038 - def __init__(self, Objlist=None):
1039 PackageSack.__init__(self) 1040 if Objlist is not None: 1041 self.addList(Objlist)
1042
1043 - def addList(self, ObjList):
1044 for pkgobj in ObjList: 1045 self.addPackage(pkgobj)
1046