1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
32
34 return "%u:%s" % (self._num, self._chksum.hexdigest())
35
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
44 return not (self == other)
45
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
55 """Base class that provides the interface for PackageSacks."""
58
61
63 ret = self.returnPackages()
64 if hasattr(ret, '__iter__'):
65 return ret.__iter__()
66 else:
67 return iter(ret)
68
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
84 raise NotImplementedError()
85
86 - def populate(self, repo, mdtype, callback, cacheOnly):
87 raise NotImplementedError()
88
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
102 raise NotImplementedError()
103
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
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):
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
136 """return list of package requiring the name (any evr and flag)"""
137 raise NotImplementedError()
138
140 """return list of package providing the name (any evr and flag)"""
141 raise NotImplementedError()
142
144 """return list of package conflicting with the name (any evr and flag)"""
145 raise NotImplementedError()
146
148 """return list of package obsoleting the name (any evr and flag)"""
149 raise NotImplementedError()
150
152 """returns a dict of obsoletes dict[obsoleting pkgtuple] = [list of obs]"""
153 raise NotImplementedError()
154
156 """return list of packages by filename"""
157 raise NotImplementedError()
158
160 """add a pkgobject to the packageSack"""
161 raise NotImplementedError()
162
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
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
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
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
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
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
242 """returns a list of pkg tuples (n, a, e, v, r)"""
243 raise NotImplementedError()
244
246 raise NotImplementedError()
247
249 """exclude incompatible arches. archlist is a list of compatible arches"""
250 raise NotImplementedError()
251
253 raise NotImplementedError()
254
256 raise NotImplementedError()
257
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
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
285
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
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
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
328
329 req = {}
330 orphans = []
331
332
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:
340 continue
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
348
349
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
601
602
603
605 """represents sets (sacks) of Package Objects"""
607 self.nevra = {}
608 self.obsoletes = {}
609
610 self.requires = {}
611
612 self.provides = {}
613 self.conflicts = {}
614 self.filenames = {}
615 self.pkgsByRepo = {}
616 self.pkgsByID = {}
617
618 self.compatarchs = None
619 self.indexesBuilt = 0
620
621
623 ret = 0
624 for repo in self.pkgsByRepo:
625 ret += len(self.pkgsByRepo[repo])
626 return ret
627
628
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
640 """ Do nothing, mainly for the testing code. """
641 pass
642
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
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)):
704
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
730 """return list of package requiring the item requested"""
731
732 return self.searchPrco(name, 'requires')
733
735 """return list of package providing the item requested"""
736
737 return self.searchPrco(name, 'provides')
738
740 """return list of package conflicting with item requested"""
741
742 return self.searchPrco(name, 'conflicts')
743
745 """return list of package obsoleting the item requested"""
746
747 return self.searchPrco(name, 'obsoletes')
748
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
761
762 newest_tups = set((pkg.pkgtup for pkg in self.returnNewestByName()))
763
764
765
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
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
786 if not dict.has_key(key):
787 dict[key] = []
788
789
790 dict[key].append(data)
791
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:
801 del dict[key]
802
803
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
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
839
841
842
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
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
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
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
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
909
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
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
962 returnlist = []
963 for polst in highdict.values():
964 for po in polst:
965 returnlist.append(po)
966
967 return returnlist
968
970 """returns a list of pkg tuples (n, a, e, v, r) optionally from a single repoid"""
971
972
973 return [pkg.pkgtup for pkg in self.returnPackages(patterns=patterns,
974 ignore_case=False)]
975
979
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
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
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
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
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
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
1042
1044 for pkgobj in ObjList:
1045 self.addPackage(pkgobj)
1046