1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import rpm
17 import types
18 import warnings
19 import glob
20 import os
21 import os.path
22
23 from rpmUtils import miscutils
24 from rpmUtils import arch
25 from rpmUtils.transaction import initReadOnlyTransaction
26 import misc
27 import Errors
28 from packages import YumInstalledPackage, parsePackages
29 from packageSack import PackageSackBase, PackageSackVersion
30
31
32 import fnmatch
33 import re
34
35 from yum.i18n import to_unicode, _
36 import constants
37
38 import yum.depsolve
41
42 - def __init__(self, rpmhdr, index, rpmdb):
43 YumInstalledPackage.__init__(self, rpmhdr, yumdb=rpmdb.yumdb)
44
45
46 self.url = rpmhdr['url']
47
48 self.sourcerpm = rpmhdr['sourcerpm']
49
50 self.idx = index
51 self.rpmdb = rpmdb
52
53 self._has_hdr = False
54 del self.hdr
55
57
58 if self._has_hdr:
59 return self.hdr
60
61 ts = self.rpmdb.readOnlyTS()
62 mi = ts.dbMatch(0, self.idx)
63 try:
64 return mi.next()
65 except StopIteration:
66 raise Errors.PackageSackError, 'Rpmdb changed underneath us'
67
69 self.hdr = val = self._get_hdr()
70 self._has_hdr = True
71
72
73 if varname.startswith('__') and varname.endswith('__'):
74 raise AttributeError, "%s has no attribute %s" % (self, varname)
75
76 if varname != 'hdr':
77 val = val[varname]
78
79
80 return val
81
84 '''
85 Represents a problem in the rpmdb, from the check_*() functions.
86 '''
87 - def __init__(self, pkg, problem, **kwargs):
88 self.pkg = pkg
89 self.problem = problem
90 for kwarg in kwargs:
91 setattr(self, kwarg, kwargs[kwarg])
92
94 if other is None:
95 return 1
96 return cmp(self.pkg, other.pkg) or cmp(self.problem, other.problem)
97
101 if self.problem == 'requires':
102 return "%s %s %s" % (self.pkg, _('has missing requires of'),
103 self.missing)
104
105 return "%s %s %s: %s" % (self.pkg, _('has installed conflicts'),
106 self.found,', '.join(map(str, self.conflicts)))
107
112
114 return _("%s is a duplicate with %s") % (self.pkg, self.duplicate)
115
118 '''
119 Represent rpmdb as a packagesack
120 '''
121
122 DEP_TABLE = {
123 'requires' : (rpm.RPMTAG_REQUIRENAME,
124 rpm.RPMTAG_REQUIREVERSION,
125 rpm.RPMTAG_REQUIREFLAGS),
126 'provides' : (rpm.RPMTAG_PROVIDENAME,
127 rpm.RPMTAG_PROVIDEVERSION,
128 rpm.RPMTAG_PROVIDEFLAGS),
129 'conflicts' : (rpm.RPMTAG_CONFLICTNAME,
130 rpm.RPMTAG_CONFLICTVERSION,
131 rpm.RPMTAG_CONFLICTFLAGS),
132 'obsoletes' : (rpm.RPMTAG_OBSOLETENAME,
133 rpm.RPMTAG_OBSOLETEVERSION,
134 rpm.RPMTAG_OBSOLETEFLAGS)
135 }
136
137
138 __cache_rpmdb__ = True
139
140 - def __init__(self, root='/', releasever=None, cachedir=None,
141 persistdir='/var/lib/yum'):
142 self.root = root
143 self._idx2pkg = {}
144 self._name2pkg = {}
145 self._tup2pkg = {}
146 self._completely_loaded = False
147 self._simple_pkgtup_list = []
148 self._get_pro_cache = {}
149 self._get_req_cache = {}
150 self._loaded_gpg_keys = False
151 if cachedir is None:
152 cachedir = misc.getCacheDir()
153 self.setCacheDir(cachedir)
154 self._persistdir = root + '/' + persistdir
155 self._have_cached_rpmdbv_data = None
156 self._cached_conflicts_data = None
157
158 self._trans_cache_store = {}
159 self.ts = None
160 self.releasever = releasever
161 self.auto_close = False
162
163
164
165 self._cache = {
166 'provides' : { },
167 'requires' : { },
168 'conflicts' : { },
169 'obsoletes' : { },
170 }
171
172 addldb_path = os.path.normpath(self._persistdir + '/yumdb')
173 self.yumdb = RPMDBAdditionalData(db_path=addldb_path)
174
176 '''Getter for the pkglist property.
177 Returns a list of package tuples.
178 '''
179 if not self._simple_pkgtup_list:
180 for (hdr, mi) in self._all_packages():
181 self._simple_pkgtup_list.append(self._hdr2pkgTuple(hdr))
182
183 return self._simple_pkgtup_list
184
185 pkglist = property(_get_pkglist, None)
186
188 self._idx2pkg = {}
189 self._name2pkg = {}
190 self._tup2pkg = {}
191 self._completely_loaded = False
192 self._simple_pkgtup_list = []
193 self._get_pro_cache = {}
194 self._get_req_cache = {}
195
196
197 if misc is not None:
198 misc.unshare_data()
199 self._cache = {
200 'provides' : { },
201 'requires' : { },
202 'conflicts' : { },
203 'obsoletes' : { },
204 }
205 self._have_cached_rpmdbv_data = None
206 self._cached_conflicts_data = None
207
209 """ Sets the internal cachedir value for the rpmdb, to be the
210 "installed" directory from this parent. """
211 self._cachedir = self.root + '/' + cachedir + "/installed/"
212
219
223
227
231
232 - def searchAll(self, name, query_type='like'):
233 ts = self.readOnlyTS()
234 result = {}
235
236
237 tag = self.DEP_TABLE['provides'][0]
238 mi = ts.dbMatch()
239 mi.pattern(tag, rpm.RPMMIRE_GLOB, name)
240 for hdr in mi:
241 if hdr['name'] == 'gpg-pubkey':
242 continue
243 pkg = self._makePackageObject(hdr, mi.instance())
244 if not result.has_key(pkg.pkgid):
245 result[pkg.pkgid] = pkg
246 del mi
247
248 fileresults = self.searchFiles(name)
249 for pkg in fileresults:
250 if not result.has_key(pkg.pkgid):
251 result[pkg.pkgid] = pkg
252
253 if self.auto_close:
254 self.ts.close()
255
256 return result.values()
257
259 """search the filelists in the rpms for anything matching name"""
260
261 ts = self.readOnlyTS()
262 result = {}
263
264 mi = ts.dbMatch('basenames', name)
265 for hdr in mi:
266 if hdr['name'] == 'gpg-pubkey':
267 continue
268 pkg = self._makePackageObject(hdr, mi.instance())
269 if not result.has_key(pkg.pkgid):
270 result[pkg.pkgid] = pkg
271 del mi
272
273 result = result.values()
274
275 if self.auto_close:
276 self.ts.close()
277
278 return result
279
281
282 result = self._cache[prcotype].get(name)
283 if result is not None:
284 return result
285 (n,f,(e,v,r)) = misc.string_to_prco_tuple(name)
286 glob = False
287
288 if misc.re_glob(n):
289 glob = True
290
291 ts = self.readOnlyTS()
292 result = {}
293 tag = self.DEP_TABLE[prcotype][0]
294 mi = ts.dbMatch(tag, misc.to_utf8(n))
295 for hdr in mi:
296 if hdr['name'] == 'gpg-pubkey':
297 continue
298 po = self._makePackageObject(hdr, mi.instance())
299 if not glob:
300 if po.checkPrco(prcotype, (n, f, (e,v,r))):
301 result[po.pkgid] = po
302 else:
303 result[po.pkgid] = po
304 del mi
305
306
307
308 if prcotype == 'provides' and name[0] == '/':
309 fileresults = self.searchFiles(name)
310 for pkg in fileresults:
311 result[pkg.pkgid] = pkg
312
313 result = result.values()
314 self._cache[prcotype][name] = result
315
316 if self.auto_close:
317 self.ts.close()
318
319 return result
320
323
326
329
332
335
336 installed = PackageSackBase.contains
337
352
363
364 @staticmethod
366 if not patterns or len(patterns) > constants.PATTERNS_MAX:
367 return None
368 ret = []
369 for pat in patterns:
370 if not pat:
371 continue
372 qpat = pat[0]
373 if qpat in ('?', '*'):
374 qpat = None
375 if ignore_case:
376 if qpat is not None:
377 qpat = qpat.lower()
378 ret.append((qpat, re.compile(fnmatch.translate(pat), re.I)))
379 else:
380 ret.append((qpat, re.compile(fnmatch.translate(pat))))
381 return ret
382 @staticmethod
384 if repatterns is None:
385 return True
386
387 for qpat, repat in repatterns:
388 epoch = hdr['epoch']
389 if epoch is None:
390 epoch = '0'
391 else:
392 epoch = str(epoch)
393 qname = hdr['name'][0]
394 if ignore_case:
395 qname = qname.lower()
396 if qpat is not None and qpat != qname and qpat != epoch[0]:
397 continue
398 if repat.match(hdr['name']):
399 return True
400 if repat.match("%(name)s-%(version)s-%(release)s.%(arch)s" % hdr):
401 return True
402 if repat.match("%(name)s.%(arch)s" % hdr):
403 return True
404 if repat.match("%(name)s-%(version)s" % hdr):
405 return True
406 if repat.match("%(name)s-%(version)s-%(release)s" % hdr):
407 return True
408 if repat.match(epoch + ":%(name)s-%(version)s-%(release)s.%(arch)s"
409 % hdr):
410 return True
411 if repat.match("%(name)s-%(epoch)s:%(version)s-%(release)s.%(arch)s"
412 % hdr):
413 return True
414 return False
415
416 - def returnPackages(self, repoid=None, patterns=None, ignore_case=False):
417 """Returns a list of packages. Note that the packages are
418 always filtered to those matching the patterns/case. repoid is
419 ignored, and is just here for compatibility with non-rpmdb sacks. """
420 if not self._completely_loaded:
421 rpats = self._compile_patterns(patterns, ignore_case)
422 for hdr, idx in self._all_packages():
423 if self._match_repattern(rpats, hdr, ignore_case):
424 self._makePackageObject(hdr, idx)
425 self._completely_loaded = patterns is None
426
427 pkgobjlist = self._idx2pkg.values()
428
429 if self._loaded_gpg_keys:
430 pkgobjlist = [pkg for pkg in pkgobjlist if pkg.name != 'gpg-pubkey']
431 if patterns:
432 pkgobjlist = parsePackages(pkgobjlist, patterns, not ignore_case)
433 pkgobjlist = pkgobjlist[0] + pkgobjlist[1]
434 return pkgobjlist
435
437 if self._cached_conflicts_data is None:
438 ret = []
439 for pkg in self.returnPackages():
440 if len(pkg.conflicts):
441 ret.append(pkg)
442 self._cached_conflicts_data = ret
443 return self._cached_conflicts_data
444
446 if not os.access(self._cachedir, os.W_OK):
447 return
448
449 conflicts_fname = self._cachedir + '/conflicts'
450 fo = open(conflicts_fname + '.tmp', 'w')
451 fo.write("%s\n" % rpmdbv)
452 fo.write("%u\n" % len(pkgs))
453 for pkg in sorted(pkgs):
454 for var in pkg.pkgtup:
455 fo.write("%s\n" % var)
456 fo.close()
457 os.rename(conflicts_fname + '.tmp', conflicts_fname)
458
462
469
470 conflict_fname = self._cachedir + '/conflicts'
471 if not os.path.exists(conflict_fname):
472 return None
473
474 fo = open(conflict_fname)
475 frpmdbv = fo.readline()
476 rpmdbv = self.simpleVersion(main_only=True)[0]
477 if not frpmdbv or rpmdbv != frpmdbv[:-1]:
478 return None
479
480 ret = []
481 try:
482
483 pkgtups_num = int(_read_str(fo))
484 while pkgtups_num > 0:
485 pkgtups_num -= 1
486
487
488 pkgtup = (_read_str(fo), _read_str(fo),
489 _read_str(fo), _read_str(fo), _read_str(fo))
490 int(pkgtup[2])
491 ret.extend(self.searchPkgTuple(pkgtup))
492 if fo.readline() != '':
493 return None
494 except ValueError:
495 return None
496
497 self._cached_conflicts_data = ret
498 return self._cached_conflicts_data
499
501 if self.__cache_rpmdb__:
502 self._trans_cache_store['conflicts'] = pkgs
503
513
515 """ We are going to do a transaction, and the parameter will be the
516 rpmdb version when we finish. The idea being we can update all
517 our rpmdb caches for that rpmdb version. """
518
519 if not self.__cache_rpmdb__:
520 self._trans_cache_store = {}
521 return
522
523 if 'conflicts' in self._trans_cache_store:
524 pkgs = self._trans_cache_store['conflicts']
525 self._write_conflicts_new(pkgs, rpmdbv)
526
527 if 'file-requires' in self._trans_cache_store:
528 data = self._trans_cache_store['file-requires']
529 self._write_file_requires(rpmdbv, data)
530
531 if 'yumdb-package-checksums' in self._trans_cache_store:
532 data = self._trans_cache_store['yumdb-package-checksums']
533 self._write_package_checksums(rpmdbv, data)
534
535 self._trans_cache_store = {}
536
538 """ We are going to reset the transaction, because the data we've added
539 already might now be invalid (Eg. skip-broken, or splitting a
540 transaction). """
541
542 self._trans_cache_store = {}
543
545 """ Return packages of the gpg-pubkeys ... hacky. """
546 ts = self.readOnlyTS()
547 mi = ts.dbMatch('name', 'gpg-pubkey')
548 ret = []
549 for hdr in mi:
550 self._loaded_gpg_keys = True
551 ret.append(self._makePackageObject(hdr, mi.instance()))
552 return ret
553
555 def _read_str(fo):
556 return fo.readline()[:-1]
557
558 assert self.__cache_rpmdb__
559 if not os.path.exists(self._cachedir + '/file-requires'):
560 return None, None
561
562 rpmdbv = self.simpleVersion(main_only=True)[0]
563 fo = open(self._cachedir + '/file-requires')
564 frpmdbv = fo.readline()
565 if not frpmdbv or rpmdbv != frpmdbv[:-1]:
566 return None, None
567
568 iFR = {}
569 iFP = {}
570 try:
571
572 pkgtups_num = int(_read_str(fo))
573 while pkgtups_num > 0:
574 pkgtups_num -= 1
575
576
577 pkgtup = (_read_str(fo), _read_str(fo),
578 _read_str(fo), _read_str(fo), _read_str(fo))
579 int(pkgtup[2])
580
581 files_num = int(_read_str(fo))
582 while files_num > 0:
583 files_num -= 1
584
585 fname = _read_str(fo)
586
587 iFR.setdefault(pkgtup, []).append(fname)
588
589
590 files_num = int(_read_str(fo))
591 while files_num > 0:
592 files_num -= 1
593 fname = _read_str(fo)
594 pkgtups_num = int(_read_str(fo))
595 while pkgtups_num > 0:
596 pkgtups_num -= 1
597
598
599 pkgtup = (_read_str(fo), _read_str(fo),
600 _read_str(fo), _read_str(fo), _read_str(fo))
601 int(pkgtup[2])
602
603 iFP.setdefault(fname, []).append(pkgtup)
604
605 if fo.readline() != '':
606 return None, None
607 except ValueError:
608 return None, None
609
610 return iFR, iFP
611
613 """ Get a cached copy of the fileRequiresData for
614 depsolving/checkFileRequires, note the giant comment in that
615 function about how we don't keep this perfect for the providers of
616 the requires. """
617 if self.__cache_rpmdb__:
618 iFR, iFP = self._read_file_requires()
619 if iFR is not None:
620 return iFR, set(), iFP
621
622 installedFileRequires = {}
623 installedUnresolvedFileRequires = set()
624 resolved = set()
625 for pkg in self.returnPackages():
626 for name, flag, evr in pkg.requires:
627 if not name.startswith('/'):
628 continue
629 installedFileRequires.setdefault(pkg.pkgtup, []).append(name)
630 if name not in resolved:
631 dep = self.getProvides(name, flag, evr)
632 resolved.add(name)
633 if not dep:
634 installedUnresolvedFileRequires.add(name)
635
636 fileRequires = set()
637 for fnames in installedFileRequires.itervalues():
638 fileRequires.update(fnames)
639 installedFileProviders = {}
640 for fname in fileRequires:
641 pkgtups = [pkg.pkgtup for pkg in self.getProvides(fname)]
642 installedFileProviders[fname] = pkgtups
643
644 ret = (installedFileRequires, installedUnresolvedFileRequires,
645 installedFileProviders)
646 if self.__cache_rpmdb__:
647 rpmdbv = self.simpleVersion(main_only=True)[0]
648 self._write_file_requires(rpmdbv, ret)
649
650 return ret
651
652 - def transactionCacheFileRequires(self, installedFileRequires,
653 installedUnresolvedFileRequires,
654 installedFileProvides,
655 problems):
656 if not self.__cache_rpmdb__:
657 return
658
659 if installedUnresolvedFileRequires or problems:
660 return
661
662 data = (installedFileRequires,
663 installedUnresolvedFileRequires,
664 installedFileProvides)
665
666 self._trans_cache_store['file-requires'] = data
667
669 if not os.access(self._cachedir, os.W_OK):
670 return
671
672 (installedFileRequires,
673 installedUnresolvedFileRequires,
674 installedFileProvides) = data
675
676
677
678 if installedUnresolvedFileRequires:
679 return
680
681 fo = open(self._cachedir + '/file-requires.tmp', 'w')
682 fo.write("%s\n" % rpmdbversion)
683
684 fo.write("%u\n" % len(installedFileRequires))
685 for pkgtup in sorted(installedFileRequires):
686 for var in pkgtup:
687 fo.write("%s\n" % var)
688 filenames = set(installedFileRequires[pkgtup])
689 fo.write("%u\n" % len(filenames))
690 for fname in sorted(filenames):
691 fo.write("%s\n" % fname)
692
693 fo.write("%u\n" % len(installedFileProvides))
694 for fname in sorted(installedFileProvides):
695 fo.write("%s\n" % fname)
696
697 pkgtups = set(installedFileProvides[fname])
698 fo.write("%u\n" % len(pkgtups))
699 for pkgtup in sorted(pkgtups):
700 for var in pkgtup:
701 fo.write("%s\n" % var)
702 fo.close()
703 os.rename(self._cachedir + '/file-requires.tmp',
704 self._cachedir + '/file-requires')
705
707 """ As simpleVersion() et. al. requires it, we "cache" this yumdb data
708 as part of our rpmdb cache. We cache it with rpmdb data, even
709 though someone _could_ use yumdb to alter it without changing the
710 rpmdb ... don't do that. """
711 if not self.__cache_rpmdb__:
712 return
713
714 if not os.path.exists(self._cachedir + '/yumdb-package-checksums'):
715 return
716
717 def _read_str(fo):
718 return fo.readline()[:-1]
719
720 rpmdbv = self.simpleVersion(main_only=True)[0]
721 fo = open(self._cachedir + '/yumdb-package-checksums')
722 frpmdbv = fo.readline()
723 if not frpmdbv or rpmdbv != frpmdbv[:-1]:
724 return
725
726 checksum_data = {}
727 try:
728
729 pkgtups_num = int(_read_str(fo))
730 while pkgtups_num > 0:
731 pkgtups_num -= 1
732
733
734 pkgtup = (_read_str(fo), _read_str(fo),
735 _read_str(fo), _read_str(fo), _read_str(fo))
736 int(pkgtup[2])
737
738 T = _read_str(fo)
739 D = _read_str(fo)
740 checksum_data[pkgtup] = (T, D)
741
742 if fo.readline() != '':
743 return
744 except ValueError:
745 return
746
747 for pkgtup in checksum_data:
748 (n, a, e, v, r) = pkgtup
749 pkg = self.searchNevra(n, e, v, r, a)[0]
750 (T, D) = checksum_data[pkgtup]
751 if ('checksum_type' in pkg.yumdb_info._read_cached_data or
752 'checksum_data' in pkg.yumdb_info._read_cached_data):
753 continue
754 pkg.yumdb_info._read_cached_data['checksum_type'] = T
755 pkg.yumdb_info._read_cached_data['checksum_data'] = D
756
758 if not self.__cache_rpmdb__:
759 return
760
761 self._trans_cache_store['yumdb-package-checksums'] = pkg_checksum_tups
762
764 if not os.access(self._cachedir, os.W_OK):
765 return
766
767 pkg_checksum_tups = data
768 fo = open(self._cachedir + '/yumdb-package-checksums.tmp', 'w')
769 fo.write("%s\n" % rpmdbversion)
770 fo.write("%u\n" % len(pkg_checksum_tups))
771 for pkgtup, TD in sorted(pkg_checksum_tups):
772 for var in pkgtup:
773 fo.write("%s\n" % var)
774 for var in TD:
775 fo.write("%s\n" % var)
776 fo.close()
777 os.rename(self._cachedir + '/yumdb-package-checksums.tmp',
778 self._cachedir + '/yumdb-package-checksums')
779
781 """ Return the cached string of the main rpmdbv. """
782 if self._have_cached_rpmdbv_data is not None:
783 return self._have_cached_rpmdbv_data
784
785 if not self.__cache_rpmdb__:
786 return None
787
788
789
790
791 rpmdbvfname = self._cachedir + "/version"
792 rpmdbfname = self.root + "/var/lib/rpm/Packages"
793
794 if os.path.exists(rpmdbvfname) and os.path.exists(rpmdbfname):
795
796 nmtime = os.path.getmtime(rpmdbvfname)
797 omtime = os.path.getmtime(rpmdbfname)
798 if omtime <= nmtime:
799 rpmdbv = open(rpmdbvfname).readline()[:-1]
800 self._have_cached_rpmdbv_data = rpmdbv
801 return self._have_cached_rpmdbv_data
802
804 self._have_cached_rpmdbv_data = str(rpmdbv)
805
806 if not self.__cache_rpmdb__:
807 return
808
809 rpmdbvfname = self._cachedir + "/version"
810 if not os.access(self._cachedir, os.W_OK):
811 if os.path.exists(self._cachedir):
812 return
813
814 try:
815 os.makedirs(self._cachedir)
816 except (IOError, OSError), e:
817 return
818
819 fo = open(rpmdbvfname + ".tmp", "w")
820 fo.write(self._have_cached_rpmdbv_data)
821 fo.write('\n')
822 fo.close()
823 os.rename(rpmdbvfname + ".tmp", rpmdbvfname)
824
826 """ Return a simple version for all installed packages. """
827 def _up_revs(irepos, repoid, rev, pkg, csum):
828 irevs = irepos.setdefault(repoid, {})
829 rpsv = irevs.setdefault(None, PackageSackVersion())
830 rpsv.update(pkg, csum)
831 if rev is not None:
832 rpsv = irevs.setdefault(rev, PackageSackVersion())
833 rpsv.update(pkg, csum)
834
835 if main_only and not groups:
836 rpmdbv = self._get_cached_simpleVersion_main()
837 if rpmdbv is not None:
838 return [rpmdbv, {}]
839
840 main = PackageSackVersion()
841 irepos = {}
842 main_grps = {}
843 irepos_grps = {}
844 for pkg in sorted(self.returnPackages()):
845 ydbi = pkg.yumdb_info
846 csum = None
847 if 'checksum_type' in ydbi and 'checksum_data' in ydbi:
848 csum = (ydbi.checksum_type, ydbi.checksum_data)
849 main.update(pkg, csum)
850
851 for group in groups:
852 if pkg.name in groups[group]:
853 if group not in main_grps:
854 main_grps[group] = PackageSackVersion()
855 irepos_grps[group] = {}
856 main_grps[group].update(pkg, csum)
857
858 if main_only:
859 continue
860
861 repoid = 'installed'
862 rev = None
863 if 'from_repo' in pkg.yumdb_info:
864 repoid = '@' + pkg.yumdb_info.from_repo
865 if 'from_repo_revision' in pkg.yumdb_info:
866 rev = pkg.yumdb_info.from_repo_revision
867
868 _up_revs(irepos, repoid, rev, pkg, csum)
869 for group in groups:
870 if pkg.name in groups[group]:
871 _up_revs(irepos_grps[group], repoid, rev, pkg, csum)
872
873 if self._have_cached_rpmdbv_data is None:
874 self._put_cached_simpleVersion_main(main)
875
876 if groups:
877 return [main, irepos, main_grps, irepos_grps]
878 return [main, irepos]
879
880 @staticmethod
882 count = 0
883 for s in searchstrings:
884 for field in fields:
885 value = to_unicode(hdr[field])
886 if value and value.lower().find(s) != -1:
887 count += 1
888 break
889 return count
890
893 if not lowered:
894 searchstrings = map(lambda x: x.lower(), searchstrings)
895 ret = []
896 for hdr, idx in self._all_packages():
897 n = self._find_search_fields(fields, searchstrings, hdr)
898 if n > 0:
899 ret.append((self._makePackageObject(hdr, idx), n))
900 return ret
902 returnList = []
903 for name in names:
904 returnList.extend(self._search(name=name))
905 return returnList
906
907 - def searchNevra(self, name=None, epoch=None, ver=None, rel=None, arch=None):
909
912
916
917
919 '''Generator that yield (header, index) for all packages
920 '''
921 ts = self.readOnlyTS()
922 mi = ts.dbMatch()
923
924 for hdr in mi:
925 if hdr['name'] != 'gpg-pubkey':
926 yield (hdr, mi.instance())
927 del mi
928 if self.auto_close:
929 self.ts.close()
930
931
933 """returns a package header having been given an index"""
934 warnings.warn('_header_from_index() will go away in a future version of Yum.\n',
935 Errors.YumFutureDeprecationWarning, stacklevel=2)
936
937 ts = self.readOnlyTS()
938 try:
939 mi = ts.dbMatch(0, idx)
940 except (TypeError, StopIteration), e:
941
942 print 'No index matching %s found in rpmdb, this is bad' % idx
943 yield None
944 else:
945 hdr = mi.next()
946 yield hdr
947 del hdr
948
949 del mi
950 if self.auto_close:
951 self.ts.close()
952
953
954 - def _search(self, name=None, epoch=None, ver=None, rel=None, arch=None):
955 '''List of matching packages, to zero or more of NEVRA.'''
956 pkgtup = (name, arch, epoch, ver, rel)
957 if pkgtup in self._tup2pkg:
958 return [self._tup2pkg[pkgtup]]
959
960 loc = locals()
961 ret = []
962
963 if self._completely_loaded:
964 if name is not None:
965 pkgs = self._name2pkg.get(name, [])
966 else:
967 pkgs = self.returnPkgs()
968 for po in pkgs:
969 for tag in ('arch', 'rel', 'ver', 'epoch'):
970 if loc[tag] is not None and loc[tag] != getattr(po, tag):
971 break
972 else:
973 ret.append(po)
974 return ret
975
976 ts = self.readOnlyTS()
977 if name is not None:
978 mi = ts.dbMatch('name', name)
979 elif arch is not None:
980 mi = ts.dbMatch('arch', arch)
981 else:
982 mi = ts.dbMatch()
983 self._completely_loaded = True
984
985 for hdr in mi:
986 if hdr['name'] == 'gpg-pubkey':
987 continue
988 po = self._makePackageObject(hdr, mi.instance())
989 for tag in ('arch', 'rel', 'ver', 'epoch'):
990 if loc[tag] is not None and loc[tag] != getattr(po, tag):
991 break
992 else:
993 ret.append(po)
994
995 if self.auto_close:
996 self.ts.close()
997
998 return ret
999
1001 if index in self._idx2pkg:
1002 return self._idx2pkg[index]
1003 po = RPMInstalledPackage(hdr, index, self)
1004 self._idx2pkg[index] = po
1005 self._name2pkg.setdefault(po.name, []).append(po)
1006 self._tup2pkg[po.pkgtup] = po
1007 return po
1008
1022
1023
1025 warnings.warn('getPkgList() will go away in a future version of Yum.\n'
1026 'Please access this via the pkglist attribute.',
1027 DeprecationWarning, stacklevel=2)
1028
1029 return self.pkglist
1030
1032 warnings.warn('getHdrList() will go away in a future version of Yum.\n',
1033 DeprecationWarning, stacklevel=2)
1034 return [ hdr for hdr, idx in self._all_packages() ]
1035
1037 warnings.warn('getNameArchPkgList() will go away in a future version of Yum.\n',
1038 DeprecationWarning, stacklevel=2)
1039
1040 lst = []
1041 for (name, arch, epoch, ver, rel) in self.pkglist:
1042 lst.append((name, arch))
1043
1044 return miscutils.unique(lst)
1045
1047 warnings.warn('getNamePkgList() will go away in a future version of Yum.\n',
1048 DeprecationWarning, stacklevel=2)
1049
1050 lst = []
1051 for (name, arch, epoch, ver, rel) in self.pkglist:
1052 lst.append(name)
1053
1054 return miscutils.unique(lst)
1055
1057 warnings.warn('returnTuplebyKeyword() will go away in a future version of Yum.\n',
1058 DeprecationWarning, stacklevel=2)
1059 return [po.pkgtup for po in self._search(name=name, arch=arch, epoch=epoch, ver=ver, rel=rel)]
1060
1062 warnings.warn('returnHeaderByTuple() will go away in a future version of Yum.\n',
1063 DeprecationWarning, stacklevel=2)
1064 """returns a list of header(s) based on the pkgtuple provided"""
1065
1066 (n, a, e, v, r) = pkgtuple
1067
1068 lst = self.searchNevra(name=n, arch=a, epoch=e, ver=v, rel=r)
1069 if len(lst) > 0:
1070 item = lst[0]
1071 return [item.hdr]
1072 else:
1073 return []
1074
1076 """returns a list of header indexes based on the pkgtuple provided"""
1077
1078 warnings.warn('returnIndexbyTuple() will go away in a future version of Yum.\n',
1079 DeprecationWarning, stacklevel=2)
1080
1081 name, arch, epoch, version, release = pkgtuple
1082
1083
1084 if epoch in (None, 0, '(none)', ''):
1085 epoch = '0'
1086
1087 return [po.idx for po in self._search(name, epoch, version, release, arch)]
1088
1090
1091 raise NotImplementedError
1092
1093 @staticmethod
1095 """ Given random stuff, generate a usable dep tuple. """
1096
1097 if flags == 0:
1098 flags = None
1099
1100 if type(version) is types.StringType:
1101 (r_e, r_v, r_r) = miscutils.stringToVersion(version)
1102
1103 elif type(version) in (types.TupleType, types.ListType):
1104 (r_e, r_v, r_r) = version
1105 else:
1106
1107
1108 r_e = r_v = r_r = None
1109
1110 deptup = (name, misc.share_data(flags),
1111 (misc.share_data(r_e), misc.share_data(r_v),
1112 misc.share_data(r_r)))
1113 return misc.share_data(deptup)
1114
1115 - def getProvides(self, name, flags=None, version=(None, None, None)):
1116 """searches the rpmdb for what provides the arguments
1117 returns a list of pkg objects of providing packages, possibly empty"""
1118
1119 name = misc.share_data(name)
1120 deptup = self._genDeptup(name, flags, version)
1121 if deptup in self._get_pro_cache:
1122 return self._get_pro_cache[deptup]
1123 r_v = deptup[2][1]
1124
1125 pkgs = self.searchProvides(name)
1126
1127 result = { }
1128
1129 for po in pkgs:
1130 if name[0] == '/' and r_v is None:
1131 result[po] = [(name, None, (None, None, None))]
1132 continue
1133 hits = po.matchingPrcos('provides', deptup)
1134 if hits:
1135 result[po] = hits
1136 self._get_pro_cache[deptup] = result
1137 return result
1138
1142
1143 - def getRequires(self, name, flags=None, version=(None, None, None)):
1144 """searches the rpmdb for what provides the arguments
1145 returns a list of pkgtuples of providing packages, possibly empty"""
1146
1147 name = misc.share_data(name)
1148 deptup = self._genDeptup(name, flags, version)
1149 if deptup in self._get_req_cache:
1150 return self._get_req_cache[deptup]
1151 r_v = deptup[2][1]
1152
1153 pkgs = self.searchRequires(name)
1154
1155 result = { }
1156
1157 for po in pkgs:
1158 if name[0] == '/' and r_v is None:
1159
1160 result[po] = [(name, None, (None, None, None))]
1161 continue
1162 hits = po.matchingPrcos('requires', deptup)
1163 if hits:
1164 result[po] = hits
1165 self._get_req_cache[deptup] = result
1166 return result
1167
1171
1173 """returns a list of yum installed package objects which own a file
1174 that are currently running or in use."""
1175 pkgs = {}
1176 for pid in misc.return_running_pids():
1177 for fn in misc.get_open_files(pid):
1178 for pkg in self.searchFiles(fn):
1179 pkgs[pkg] = 1
1180
1181 return sorted(pkgs.keys())
1182
1184 """ Checks for any missing dependencies. """
1185
1186 if pkgs is None:
1187 pkgs = self.returnPackages()
1188
1189 providers = set()
1190 problems = []
1191 for pkg in sorted(pkgs):
1192 for rreq in pkg.requires:
1193 if rreq[0].startswith('rpmlib'): continue
1194 if rreq in providers: continue
1195
1196 (req, flags, ver) = rreq
1197 if self.getProvides(req, flags, ver):
1198 providers.add(rreq)
1199 continue
1200 flags = yum.depsolve.flags.get(flags, flags)
1201 missing = miscutils.formatRequire(req, ver, flags)
1202 prob = RPMDBProblemDependency(pkg, "requires", missing=missing)
1203 problems.append(prob)
1204
1205 for creq in pkg.conflicts:
1206 if creq[0].startswith('rpmlib'): continue
1207
1208 (req, flags, ver) = creq
1209 res = self.getProvides(req, flags, ver)
1210 if not res:
1211 continue
1212 flags = yum.depsolve.flags.get(flags, flags)
1213 found = miscutils.formatRequire(req, ver, flags)
1214 prob = RPMDBProblemDependency(pkg, "conflicts", found=found,
1215 conflicts=res)
1216 problems.append(prob)
1217 return problems
1218
1220 last = None
1221 for pkg in sorted(self.returnPackages()):
1222 if pkg.name in ignore_provides:
1223 continue
1224 if ignore_provides.intersection(set(pkg.provides_names)):
1225 continue
1226
1227 if last is None:
1228 last = pkg
1229 continue
1230 yield last, pkg
1231 last = pkg
1232
1234 """ Checks for any "duplicate packages" (those with multiple versions
1235 installed), we ignore any packages with a provide in the passed
1236 provide list (this is how installonlyworks, so we do the same). """
1237 ignore_provides = set(ignore_provides)
1238 problems = []
1239 for last, pkg in self._iter_two_pkgs(ignore_provides):
1240 if pkg.name != last.name:
1241 continue
1242 if pkg.verEQ(last) and pkg != last:
1243 if arch.isMultiLibArch(pkg.arch) and last.arch != 'noarch':
1244 continue
1245 if arch.isMultiLibArch(last.arch) and pkg.arch != 'noarch':
1246 continue
1247
1248
1249 problems.append(RPMDBProblemDuplicate(pkg, duplicate=last))
1250 return problems
1251
1254 return path.replace('/', '').replace('~', '')
1255
1258 """class for access to the additional data not able to be stored in the
1259 rpmdb"""
1260
1261
1262
1263
1264
1265 - def __init__(self, db_path='/var/lib/yum/yumdb'):
1266 self.conf = misc.GenericHolder()
1267 self.conf.db_path = db_path
1268 self.conf.writable = False
1269
1270 self._packages = {}
1271 if not os.path.exists(self.conf.db_path):
1272 try:
1273 os.makedirs(self.conf.db_path)
1274 except (IOError, OSError), e:
1275
1276 return
1277 self.conf.writable = True
1278 else:
1279 if os.access(self.conf.db_path, os.W_OK):
1280 self.conf.writable = True
1281
1282
1283
1285
1286 glb = '%s/*/*/' % self.conf.db_path
1287 pkgdirs = glob.glob(glb)
1288 for d in pkgdirs:
1289 pkgid = os.path.basename(d).split('-')[0]
1290 self._packages[pkgid] = d
1291
1293 if pkgid in self._packages:
1294 return self._packages[pkgid]
1295 (n, a, e, v,r) = pkgtup
1296 n = _sanitize(n)
1297 thisdir = '%s/%s/%s-%s-%s-%s-%s' % (self.conf.db_path,
1298 n[0], pkgid, n, v, r, a)
1299 self._packages[pkgid] = thisdir
1300 return thisdir
1301
1302 - def get_package(self, po=None, pkgtup=None, pkgid=None):
1303 """Return an RPMDBAdditionalDataPackage Object for this package"""
1304 if po:
1305 thisdir = self._get_dir_name(po.pkgtup, po.pkgid)
1306 elif pkgtup and pkgid:
1307 thisdir = self._get_dir_name(pkgtup, pkgid)
1308 else:
1309 raise ValueError,"Pass something to RPMDBAdditionalData.get_package"
1310
1311 return RPMDBAdditionalDataPackage(self.conf, thisdir)
1312
1314 """populate out the dirs and remove all the items no longer in the rpmd
1315 and/or populate various bits to the currently installed version"""
1316
1317
1318
1319
1320
1321
1322 pass
1323
1326 self._conf = conf
1327 self._mydir = pkgdir
1328
1329 self._read_cached_data = {}
1330
1331 - def _write(self, attr, value):
1332
1333 if not os.path.exists(self._mydir):
1334 os.makedirs(self._mydir)
1335
1336 attr = _sanitize(attr)
1337 if attr in self._read_cached_data:
1338 del self._read_cached_data[attr]
1339 fn = self._mydir + '/' + attr
1340 fn = os.path.normpath(fn)
1341 fo = open(fn + '.tmp', 'w')
1342 try:
1343 fo.write(value)
1344 except (OSError, IOError), e:
1345 raise AttributeError, "Cannot set attribute %s on %s" % (attr, self)
1346
1347 fo.flush()
1348 fo.close()
1349 del fo
1350 os.rename(fn + '.tmp', fn)
1351 self._read_cached_data[attr] = value
1352
1354 attr = _sanitize(attr)
1355
1356 if attr.endswith('.tmp'):
1357 raise AttributeError, "%s has no attribute %s" % (self, attr)
1358
1359 if attr in self._read_cached_data:
1360 return self._read_cached_data[attr]
1361
1362 fn = self._mydir + '/' + attr
1363 if not os.path.exists(fn):
1364 raise AttributeError, "%s has no attribute %s" % (self, attr)
1365
1366 fo = open(fn, 'r')
1367 self._read_cached_data[attr] = fo.read()
1368 fo.close()
1369 del fo
1370 return self._read_cached_data[attr]
1371
1373 """remove the attribute file"""
1374
1375 attr = _sanitize(attr)
1376 fn = self._mydir + '/' + attr
1377 if attr in self._read_cached_data:
1378 del self._read_cached_data[attr]
1379 if os.path.exists(fn):
1380 try:
1381 os.unlink(fn)
1382 except (IOError, OSError):
1383 raise AttributeError, "Cannot delete attribute %s on " % (attr, self)
1384
1386 return self._read(attr)
1387
1389 if not attr.startswith('_'):
1390 self._write(attr, value)
1391 else:
1392 object.__setattr__(self, attr, value)
1393
1395 if not attr.startswith('_'):
1396 self._delete(attr)
1397 else:
1398 object.__delattr__(self, attr)
1399
1400 - def __iter__(self, show_hidden=False):
1401 for item in self._read_cached_data:
1402 yield item
1403 for item in glob.glob(self._mydir + '/*'):
1404 item = item[(len(self._mydir) + 1):]
1405 if item in self._read_cached_data:
1406 continue
1407 if not show_hidden and item.endswith('.tmp'):
1408 continue
1409 yield item
1410
1412
1413 for item in self.__iter__(show_hidden=True):
1414 self._delete(item)
1415 try:
1416 os.rmdir(self._mydir)
1417 except OSError:
1418 pass
1419
1420
1421
1422
1423 - def get(self, attr, default=None):
1424 """retrieve an add'l data obj"""
1425
1426 try:
1427 res = self._read(attr)
1428 except AttributeError:
1429 return default
1430 return res
1431
1434 sack = RPMDBPackageSack('/')
1435 for p in sack.simplePkgList():
1436 print p
1437
1438 if __name__ == '__main__':
1439 main()
1440