Seth Vidal 09f86ec
diff --git a/cli.py b/cli.py
Seth Vidal 09f86ec
index 8f50541..f93a706 100644
Seth Vidal 09f86ec
--- a/cli.py
Seth Vidal 09f86ec
+++ b/cli.py
Seth Vidal 09f86ec
@@ -894,10 +894,12 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
Seth Vidal 09f86ec
             hdrcode, hdrresults = self.cleanHeaders()
Seth Vidal 09f86ec
             xmlcode, xmlresults = self.cleanMetadata()
Seth Vidal 09f86ec
             dbcode, dbresults = self.cleanSqlite()
Seth Vidal 09f86ec
+            rpmcode, rpmresults = self.cleanRpmDB()
Seth Vidal 09f86ec
             self.plugins.run('clean')
Seth Vidal 09f86ec
             
Seth Vidal 09f86ec
-            code = hdrcode + pkgcode + xmlcode + dbcode
Seth Vidal 09f86ec
-            results = hdrresults + pkgresults + xmlresults + dbresults
Seth Vidal 09f86ec
+            code = hdrcode + pkgcode + xmlcode + dbcode + rpmdb
Seth Vidal 09f86ec
+            results = (hdrresults + pkgresults + xmlresults + dbresults +
Seth Vidal 09f86ec
+                       rpmresults)
Seth Vidal 09f86ec
             for msg in results:
Seth Vidal 09f86ec
                 self.logger.debug(msg)
Seth Vidal 09f86ec
             return code, []
Seth Vidal 09f86ec
@@ -917,6 +919,9 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
Seth Vidal 09f86ec
         if 'expire-cache' in userlist or 'metadata' in userlist:
Seth Vidal 09f86ec
             self.logger.debug(_('Cleaning up expire-cache metadata'))
Seth Vidal 09f86ec
             expccode, expcresults = self.cleanExpireCache()
Seth Vidal 09f86ec
+        if 'rpmdb' in userlist:
Seth Vidal 09f86ec
+            self.logger.debug(_('Cleaning up cached rpmdb data'))
Seth Vidal 09f86ec
+            expccode, expcresults = self.cleanRpmDB()
Seth Vidal 09f86ec
         if 'plugins' in userlist:
Seth Vidal 09f86ec
             self.logger.debug(_('Cleaning up plugins'))
Seth Vidal 09f86ec
             self.plugins.run('clean')
Seth Vidal 09f86ec
diff --git a/docs/yum.8 b/docs/yum.8
Seth Vidal 09f86ec
index 4158453..9472a82 100644
Seth Vidal 09f86ec
--- a/docs/yum.8
Seth Vidal 09f86ec
+++ b/docs/yum.8
Seth Vidal 09f86ec
@@ -35,7 +35,7 @@ gnome\-packagekit application\&.
Seth Vidal 09f86ec
 .br 
Seth Vidal 09f86ec
 .I \fR * provides  | whatprovides feature1 [feature2] [\&.\&.\&.]
Seth Vidal 09f86ec
 .br  
Seth Vidal 09f86ec
-.I \fR * clean [ packages | headers | metadata | dbcache | all ]
Seth Vidal 09f86ec
+.I \fR * clean [ packages | metadata | expire-cache | rpmdb | plugins | all ]
Seth Vidal 09f86ec
 .br
Seth Vidal 09f86ec
 .I \fR * makecache
Seth Vidal 09f86ec
 .br
Seth Vidal 09f86ec
@@ -424,7 +424,8 @@ Eliminate the local data saying when the metadata and mirrorlists were downloade
Seth Vidal 09f86ec
 Eliminate any cached packages from the system.  Note that packages are not automatically deleted after they are downloaded.
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
 .IP "\fByum clean headers\fP"
Seth Vidal 09f86ec
-Eliminate all of the header files which yum uses for dependency resolution.
Seth Vidal 09f86ec
+Eliminate all of the header files, which old versions of yum used for
Seth Vidal 09f86ec
+dependency resolution.
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
 .IP "\fByum clean metadata\fP"
Seth Vidal 09f86ec
 Eliminate all of the files which yum uses to determine the remote
Seth Vidal 09f86ec
@@ -433,11 +434,22 @@ metadata the next time it is run.
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
 .IP "\fByum clean dbcache\fP"
Seth Vidal 09f86ec
 Eliminate the sqlite cache used for faster access to metadata.
Seth Vidal 09f86ec
-Using this option will force yum to recreate the cache the next time
Seth Vidal 09f86ec
-it is run.
Seth Vidal 09f86ec
+Using this option will force yum to download the sqlite metadata the next time
Seth Vidal 09f86ec
+it is run, or recreate the sqlite metadata if using an older repo.
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+.IP "\fByum clean dbcache\fP"
Seth Vidal 09f86ec
+Eliminate the sqlite cache used for faster access to metadata.
Seth Vidal 09f86ec
+Using this option will force yum to download the sqlite metadata the next time
Seth Vidal 09f86ec
+it is run, or recreate the sqlite metadata if using an older repo.
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+.IP "\fByum clean rpmdb\fP"
Seth Vidal 09f86ec
+Eliminate any cached data from the local rpmdb.
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+.IP "\fByum clean plugins\fP"
Seth Vidal 09f86ec
+Tell any enabled plugins to eliminate their cached data.
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
 .IP "\fByum clean all\fP"
Seth Vidal 09f86ec
-Runs \fByum clean packages\fP and \fByum clean headers\fP, \fByum clean metadata\fP and \fByum clean dbcache\fP as above.
Seth Vidal 09f86ec
+Does all of the above.
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
 .PP
Seth Vidal 09f86ec
 .SH "MISC"
Seth Vidal 09f86ec
diff --git a/test/rpmdb-cache.py b/test/rpmdb-cache.py
Seth Vidal 09f86ec
new file mode 100755
Seth Vidal 09f86ec
index 0000000..7768a93
Seth Vidal 09f86ec
--- /dev/null
Seth Vidal 09f86ec
+++ b/test/rpmdb-cache.py
Seth Vidal 09f86ec
@@ -0,0 +1,87 @@
Seth Vidal 09f86ec
+#! /usr/bin/python -tt
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+import sys
Seth Vidal 09f86ec
+import yum
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+__provides_of_requires_exact__ = False
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+yb1 = yum.YumBase()
Seth Vidal 09f86ec
+yb1.conf.cache = True
Seth Vidal 09f86ec
+yb2 = yum.YumBase()
Seth Vidal 09f86ec
+yb2.conf.cache = True
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+if len(sys.argv) > 1 and sys.argv[1].lower() == 'full':
Seth Vidal 09f86ec
+    print "Doing full test"
Seth Vidal 09f86ec
+    __provides_of_requires_exact__ = True
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+assert hasattr(yb1.rpmdb, '__cache_rpmdb__')
Seth Vidal 09f86ec
+yb1.rpmdb.__cache_rpmdb__ = False
Seth Vidal 09f86ec
+yb2.setCacheDir()
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+# Version
Seth Vidal 09f86ec
+ver1 = yb1.rpmdb.simpleVersion(main_only=True)[0]
Seth Vidal 09f86ec
+ver2 = yb2.rpmdb.simpleVersion(main_only=True)[0]
Seth Vidal 09f86ec
+if ver1 != ver2:
Seth Vidal 09f86ec
+    print >>sys.stderr, "Error: Version mismatch:", ver1, ver2
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+# Conflicts
Seth Vidal 09f86ec
+cpkgs1 = yb1.rpmdb.returnConflictPackages()
Seth Vidal 09f86ec
+cpkgs2 = yb2.rpmdb.returnConflictPackages()
Seth Vidal 09f86ec
+if len(cpkgs1) != len(cpkgs2):
Seth Vidal 09f86ec
+    print >>sys.stderr, "Error: Conflict len mismatch:", len(cpkgs1),len(cpkgs2)
Seth Vidal 09f86ec
+for pkg in cpkgs1:
Seth Vidal 09f86ec
+    if pkg not in cpkgs2:
Seth Vidal 09f86ec
+        print >>sys.stderr, "Error: Conflict cache missing", pkg
Seth Vidal 09f86ec
+for pkg in cpkgs2:
Seth Vidal 09f86ec
+    if pkg not in cpkgs1:
Seth Vidal 09f86ec
+        print >>sys.stderr, "Error: Conflict cache extra", pkg
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+# File Requires
Seth Vidal 09f86ec
+frd1, blah, fpd1 = yb1.rpmdb.fileRequiresData()
Seth Vidal 09f86ec
+frd2, blah, fpd2 = yb2.rpmdb.fileRequiresData()
Seth Vidal 09f86ec
+if len(frd1) != len(frd2):
Seth Vidal 09f86ec
+    print >>sys.stderr, "Error: FileReq len mismatch:", len(frd1), len(frd2)
Seth Vidal 09f86ec
+for pkgtup in frd1:
Seth Vidal 09f86ec
+    if pkgtup not in frd2:
Seth Vidal 09f86ec
+        print >>sys.stderr, "Error: FileReq cache missing", pkgtup
Seth Vidal 09f86ec
+        continue
Seth Vidal 09f86ec
+    if len(set(frd1[pkgtup])) != len(set(frd2[pkgtup])):
Seth Vidal 09f86ec
+        print >>sys.stderr, ("Error: FileReq[%s] len mismatch:" % (pkgtup,),
Seth Vidal 09f86ec
+                             len(frd1[pkgtup]), len(frd2[pkgtup]))
Seth Vidal 09f86ec
+    for name in frd1[pkgtup]:
Seth Vidal 09f86ec
+        if name not in frd2[pkgtup]:
Seth Vidal 09f86ec
+            print >>sys.stderr, ("Error: FileReq[%s] cache missing" % (pkgtup,),
Seth Vidal 09f86ec
+                                 name)
Seth Vidal 09f86ec
+for pkgtup in frd2:
Seth Vidal 09f86ec
+    if pkgtup not in frd1:
Seth Vidal 09f86ec
+        print >>sys.stderr, "Error: FileReq cache extra", pkgtup
Seth Vidal 09f86ec
+        continue
Seth Vidal 09f86ec
+    for name in frd2[pkgtup]:
Seth Vidal 09f86ec
+        if name not in frd1[pkgtup]:
Seth Vidal 09f86ec
+            print >>sys.stderr, ("Error: FileReq[%s] cache extra" % (pkgtup,),
Seth Vidal 09f86ec
+                                 name)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+# File Provides (of requires) -- not exact
Seth Vidal 09f86ec
+if len(fpd1) != len(fpd2):
Seth Vidal 09f86ec
+    print >>sys.stderr, "Error: FileProv len mismatch:", len(fpd1), len(fpd2)
Seth Vidal 09f86ec
+for name in fpd1:
Seth Vidal 09f86ec
+    if name not in fpd2:
Seth Vidal 09f86ec
+        print >>sys.stderr, "Error: FileProv cache missing", name
Seth Vidal 09f86ec
+        continue
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    if not __provides_of_requires_exact__:
Seth Vidal 09f86ec
+        continue # We might be missing some providers
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    if len(fpd1[name]) != len(fpd2[name]):
Seth Vidal 09f86ec
+        print >>sys.stderr, ("Error: FileProv[%s] len mismatch:" % (pkgtup,),
Seth Vidal 09f86ec
+                             len(fpd1[name]), len(fpd2[name]))
Seth Vidal 09f86ec
+    for pkgtup in fpd1[name]:
Seth Vidal 09f86ec
+        if pkgtup not in fpd2[name]:
Seth Vidal 09f86ec
+            print >>sys.stderr,"Error: FileProv[%s] cache missing" % name,pkgtup
Seth Vidal 09f86ec
+for name in fpd2:
Seth Vidal 09f86ec
+    if name not in fpd1:
Seth Vidal 09f86ec
+        print >>sys.stderr, "Error: FileProv cache extra", name
Seth Vidal 09f86ec
+        continue
Seth Vidal 09f86ec
+    for pkgtup in fpd2[name]:
Seth Vidal 09f86ec
+        if pkgtup not in fpd1[name]:
Seth Vidal 09f86ec
+            print >>sys.stderr,"Error: FileProv[%s] cache extra" % name,pkgtup
Seth Vidal 09f86ec
diff --git a/test/testbase.py b/test/testbase.py
Seth Vidal 09f86ec
index 3edfe57..c7a1ffe 100644
Seth Vidal 09f86ec
--- a/test/testbase.py
Seth Vidal 09f86ec
+++ b/test/testbase.py
Seth Vidal 09f86ec
@@ -14,6 +14,7 @@ from yum import packages
Seth Vidal 09f86ec
 from yum import packageSack
Seth Vidal 09f86ec
 from yum.constants import TS_INSTALL_STATES, TS_REMOVE_STATES
Seth Vidal 09f86ec
 from cli import YumBaseCli
Seth Vidal 09f86ec
+from yum.rpmsack import RPMDBPackageSack as _rpmdbsack
Seth Vidal 09f86ec
 import inspect
Seth Vidal 09f86ec
 from rpmUtils import arch
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
@@ -233,6 +234,50 @@ class FakeRpmDb(packageSack.PackageSack):
Seth Vidal 09f86ec
     def __init__(self):
Seth Vidal 09f86ec
         packageSack.PackageSack.__init__(self)
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
+    # Need to mock out rpmdb caching... copy&paste. Gack.
Seth Vidal 09f86ec
+    def returnConflictPackages(self):
Seth Vidal 09f86ec
+        ret = []
Seth Vidal 09f86ec
+        for pkg in self.returnPackages():
Seth Vidal 09f86ec
+            if len(pkg.conflicts):
Seth Vidal 09f86ec
+                ret.append(pkg)
Seth Vidal 09f86ec
+        return ret
Seth Vidal 09f86ec
+    def fileRequiresData(self):
Seth Vidal 09f86ec
+        installedFileRequires = {}
Seth Vidal 09f86ec
+        installedUnresolvedFileRequires = set()
Seth Vidal 09f86ec
+        resolved = set()
Seth Vidal 09f86ec
+        for pkg in self.returnPackages():
Seth Vidal 09f86ec
+            for name, flag, evr in pkg.requires:
Seth Vidal 09f86ec
+                if not name.startswith('/'):
Seth Vidal 09f86ec
+                    continue
Seth Vidal 09f86ec
+                installedFileRequires.setdefault(pkg.pkgtup, []).append(name)
Seth Vidal 09f86ec
+                if name not in resolved:
Seth Vidal 09f86ec
+                    dep = self.getProvides(name, flag, evr)
Seth Vidal 09f86ec
+                    resolved.add(name)
Seth Vidal 09f86ec
+                    if not dep:
Seth Vidal 09f86ec
+                        installedUnresolvedFileRequires.add(name)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        fileRequires = set()
Seth Vidal 09f86ec
+        for fnames in installedFileRequires.itervalues():
Seth Vidal 09f86ec
+            fileRequires.update(fnames)
Seth Vidal 09f86ec
+        installedFileProviders = {}
Seth Vidal 09f86ec
+        for fname in fileRequires:
Seth Vidal 09f86ec
+            pkgtups = [pkg.pkgtup for pkg in self.getProvides(fname)]
Seth Vidal 09f86ec
+            installedFileProviders[fname] = pkgtups
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        ret =  (installedFileRequires, installedUnresolvedFileRequires,
Seth Vidal 09f86ec
+                installedFileProviders)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        return ret
Seth Vidal 09f86ec
+    def transactionCacheFileRequires(self, installedFileRequires,
Seth Vidal 09f86ec
+                                     installedUnresolvedFileRequires,
Seth Vidal 09f86ec
+                                     installedFileProvides,
Seth Vidal 09f86ec
+                                     problems):
Seth Vidal 09f86ec
+        return
Seth Vidal 09f86ec
+    def transactionCacheConflictPackages(self, pkgs):
Seth Vidal 09f86ec
+        return
Seth Vidal 09f86ec
+    def transactionResultVersion(self, rpmdbv):
Seth Vidal 09f86ec
+        return
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
     def getProvides(self, name, flags=None, version=(None, None, None)):
Seth Vidal 09f86ec
         """return dict { packages -> list of matching provides }"""
Seth Vidal 09f86ec
         self._checkIndexes(failure='build')
Seth Vidal 09f86ec
diff --git a/yum/__init__.py b/yum/__init__.py
Seth Vidal 09f86ec
index 2aaa66a..affa92b 100644
Seth Vidal 09f86ec
--- a/yum/__init__.py
Seth Vidal 09f86ec
+++ b/yum/__init__.py
Seth Vidal 09f86ec
@@ -469,7 +469,8 @@ class YumBase(depsolve.Depsolve):
Seth Vidal 09f86ec
             self.verbose_logger.log(logginglevels.DEBUG_4,
Seth Vidal 09f86ec
                                     _('Reading Local RPMDB'))
Seth Vidal 09f86ec
             self._rpmdb = rpmsack.RPMDBPackageSack(root=self.conf.installroot,
Seth Vidal 09f86ec
-                                                   releasever=self.yumvar['releasever'])
Seth Vidal 09f86ec
+                                                   releasever=self.yumvar['releasever'],
Seth Vidal 09f86ec
+                                                   cachedir=self.conf.cachedir)
Seth Vidal 09f86ec
             self.verbose_logger.debug('rpmdb time: %0.3f' % (time.time() - rpmdb_st))
Seth Vidal 09f86ec
         return self._rpmdb
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
@@ -1072,6 +1073,13 @@ class YumBase(depsolve.Depsolve):
Seth Vidal 09f86ec
         if self.conf.history_record:
Seth Vidal 09f86ec
             self.history.beg(rpmdbv, using_pkgs, list(self.tsInfo))
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
+        #  Just before we update the transaction, update what we think the
Seth Vidal 09f86ec
+        # rpmdb will look like. This needs to be done before the run, so that if
Seth Vidal 09f86ec
+        # "something" happens and the rpmdb is different from what we think it
Seth Vidal 09f86ec
+        # will be we store what we thought, not what happened (so it'll be an
Seth Vidal 09f86ec
+        # invalid cache).
Seth Vidal 09f86ec
+        self.rpmdb.transactionResultVersion(self.tsInfo.futureRpmDBVersion())
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
         errors = self.ts.run(cb.callback, '')
Seth Vidal 09f86ec
         # ts.run() exit codes are, hmm, "creative": None means all ok, empty 
Seth Vidal 09f86ec
         # list means some errors happened in the transaction and non-empty 
Seth Vidal 09f86ec
@@ -1699,6 +1707,11 @@ class YumBase(depsolve.Depsolve):
Seth Vidal 09f86ec
         exts = ['cachecookie', 'mirrorlist.txt']
Seth Vidal 09f86ec
         return self._cleanFiles(exts, 'cachedir', 'metadata')
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
+    def cleanRpmDB(self):
Seth Vidal 09f86ec
+        cachedir = self.conf.cachedir + "/rpmdb-cache/"
Seth Vidal 09f86ec
+        filelist = misc.getFileList(cachedir, '', [])
Seth Vidal 09f86ec
+        return self._cleanFilelist('rpmdb', filelist)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
     def _cleanFiles(self, exts, pathattr, filetype):
Seth Vidal 09f86ec
         filelist = []
Seth Vidal 09f86ec
         removed = 0
Seth Vidal 09f86ec
@@ -1707,7 +1720,9 @@ class YumBase(depsolve.Depsolve):
Seth Vidal 09f86ec
                 path = getattr(repo, pathattr)
Seth Vidal 09f86ec
                 if os.path.exists(path) and os.path.isdir(path):
Seth Vidal 09f86ec
                     filelist = misc.getFileList(path, ext, filelist)
Seth Vidal 09f86ec
+        self._cleanFilelist(filetype, filelist)
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
+    def _cleanFilelist(self, filetype, filelist):
Seth Vidal 09f86ec
         for item in filelist:
Seth Vidal 09f86ec
             try:
Seth Vidal 09f86ec
                 misc.unlink_f(item)
Seth Vidal 09f86ec
@@ -4163,7 +4178,9 @@ class YumBase(depsolve.Depsolve):
Seth Vidal 09f86ec
         if cachedir is None:
Seth Vidal 09f86ec
             return False # Tried, but failed, to get a "user" cachedir
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
-        self.repos.setCacheDir(cachedir + varReplace(suffix, self.yumvar))
Seth Vidal 09f86ec
+        cachedir += varReplace(suffix, self.yumvar)
Seth Vidal 09f86ec
+        self.repos.setCacheDir(cachedir)
Seth Vidal 09f86ec
+        self.rpmdb.setCacheDir(cachedir)
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
         return True # We got a new cache dir
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
diff --git a/yum/depsolve.py b/yum/depsolve.py
Seth Vidal 09f86ec
index 7871e98..b5953c2 100644
Seth Vidal 09f86ec
--- a/yum/depsolve.py
Seth Vidal 09f86ec
+++ b/yum/depsolve.py
Seth Vidal 09f86ec
@@ -918,31 +918,27 @@ class Depsolve(object):
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
     def _checkFileRequires(self):
Seth Vidal 09f86ec
         fileRequires = set()
Seth Vidal 09f86ec
+        nfileRequires = set() # These need to be looked up in the rpmdb.
Seth Vidal 09f86ec
         reverselookup = {}
Seth Vidal 09f86ec
         ret = []
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
         # generate list of file requirement in rpmdb
Seth Vidal 09f86ec
         if self.installedFileRequires is None:
Seth Vidal 09f86ec
-            self.installedFileRequires = {}
Seth Vidal 09f86ec
-            self.installedUnresolvedFileRequires = set()
Seth Vidal 09f86ec
-            resolved = set()
Seth Vidal 09f86ec
-            for pkg in self.rpmdb.returnPackages():
Seth Vidal 09f86ec
-                for name, flag, evr in pkg.requires:
Seth Vidal 09f86ec
-                    if not name.startswith('/'):
Seth Vidal 09f86ec
-                        continue
Seth Vidal 09f86ec
-                    self.installedFileRequires.setdefault(pkg, []).append(name)
Seth Vidal 09f86ec
-                    if name not in resolved:
Seth Vidal 09f86ec
-                        dep = self.rpmdb.getProvides(name, flag, evr)
Seth Vidal 09f86ec
-                        resolved.add(name)
Seth Vidal 09f86ec
-                        if not dep:
Seth Vidal 09f86ec
-                            self.installedUnresolvedFileRequires.add(name)
Seth Vidal 09f86ec
+            self.installedFileRequires, \
Seth Vidal 09f86ec
+              self.installedUnresolvedFileRequires, \
Seth Vidal 09f86ec
+              self.installedFileProviders = self.rpmdb.fileRequiresData()
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
         # get file requirements from packages not deleted
Seth Vidal 09f86ec
-        for po, files in self.installedFileRequires.iteritems():
Seth Vidal 09f86ec
-            if not self._tsInfo.getMembersWithState(po.pkgtup, output_states=TS_REMOVE_STATES):
Seth Vidal 09f86ec
+        todel = []
Seth Vidal 09f86ec
+        for pkgtup, files in self.installedFileRequires.iteritems():
Seth Vidal 09f86ec
+            if self._tsInfo.getMembersWithState(pkgtup, output_states=TS_REMOVE_STATES):
Seth Vidal 09f86ec
+                todel.append(pkgtup)
Seth Vidal 09f86ec
+            else:
Seth Vidal 09f86ec
                 fileRequires.update(files)
Seth Vidal 09f86ec
                 for filename in files:
Seth Vidal 09f86ec
-                    reverselookup.setdefault(filename, []).append(po)
Seth Vidal 09f86ec
+                    reverselookup.setdefault(filename, []).append(pkgtup)
Seth Vidal 09f86ec
+        for pkgtup in todel:
Seth Vidal 09f86ec
+            del self.installedFileRequires[pkgtup]
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
         fileRequires -= self.installedUnresolvedFileRequires
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
@@ -950,6 +946,8 @@ class Depsolve(object):
Seth Vidal 09f86ec
         for txmbr in self._tsInfo.getMembersWithState(output_states=TS_INSTALL_STATES):
Seth Vidal 09f86ec
             for name, flag, evr in txmbr.po.requires:
Seth Vidal 09f86ec
                 if name.startswith('/'):
Seth Vidal 09f86ec
+                    pt = txmbr.po.pkgtup
Seth Vidal 09f86ec
+                    self.installedFileRequires.setdefault(pt, []).append(name)
Seth Vidal 09f86ec
                     # check if file requires was already unresolved in update
Seth Vidal 09f86ec
                     if name in self.installedUnresolvedFileRequires:
Seth Vidal 09f86ec
                         already_broken = False
Seth Vidal 09f86ec
@@ -959,23 +957,75 @@ class Depsolve(object):
Seth Vidal 09f86ec
                                 break
Seth Vidal 09f86ec
                         if already_broken:
Seth Vidal 09f86ec
                             continue
Seth Vidal 09f86ec
+                    if name not in fileRequires:
Seth Vidal 09f86ec
+                        nfileRequires.add(name)
Seth Vidal 09f86ec
                     fileRequires.add(name)
Seth Vidal 09f86ec
-                    reverselookup.setdefault(name, []).append(txmbr.po)
Seth Vidal 09f86ec
+                    reverselookup.setdefault(name, []).append(txmbr.po.pkgtup)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        todel = []
Seth Vidal 09f86ec
+        for fname in self.installedFileProviders:
Seth Vidal 09f86ec
+            niFP_fname = []
Seth Vidal 09f86ec
+            for pkgtup in self.installedFileProviders[fname]:
Seth Vidal 09f86ec
+                if self._tsInfo.getMembersWithState(pkgtup, output_states=TS_REMOVE_STATES):
Seth Vidal 09f86ec
+                    continue
Seth Vidal 09f86ec
+                niFP_fname.append(pkgtup)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+            if not niFP_fname:
Seth Vidal 09f86ec
+                todel.append(fname)
Seth Vidal 09f86ec
+                continue
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+            self.installedFileProviders[fname] = niFP_fname
Seth Vidal 09f86ec
+        for fname in todel:
Seth Vidal 09f86ec
+            del self.installedFileProviders[fname]
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
         # check the file requires
Seth Vidal 09f86ec
+        iFP = self.installedFileProviders
Seth Vidal 09f86ec
         for filename in fileRequires:
Seth Vidal 09f86ec
-            if not self.tsInfo.getOldProvides(filename) and not self.tsInfo.getNewProvides(filename):
Seth Vidal 09f86ec
-                for po in reverselookup[filename]:
Seth Vidal 09f86ec
-                    ret.append( (po, (filename, 0, '')) )
Seth Vidal 09f86ec
+            # In theory we need this to be:
Seth Vidal 09f86ec
+            #
Seth Vidal 09f86ec
+            # nprov, filename in iFP (or new), oprov
Seth Vidal 09f86ec
+            #
Seth Vidal 09f86ec
+            # ...this keeps the cache exactly the same as the non-cached data.
Seth Vidal 09f86ec
+            # However that also means that we'll always need the filelists, so
Seth Vidal 09f86ec
+            # we do:
Seth Vidal 09f86ec
+            #
Seth Vidal 09f86ec
+            # filename in iFP (if found return), oprov (if found return),
Seth Vidal 09f86ec
+            # nprov
Seth Vidal 09f86ec
+            #
Seth Vidal 09f86ec
+            # ...this means we'll always get the same _result_ (as we only need
Seth Vidal 09f86ec
+            # to know if _something_ provides), but our cache will be off on
Seth Vidal 09f86ec
+            # what does/doesn't provide the file.
Seth Vidal 09f86ec
+            if filename in self.installedFileProviders:
Seth Vidal 09f86ec
+                continue
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
-        return ret
Seth Vidal 09f86ec
+            oprov = self.tsInfo.getOldProvides(filename)
Seth Vidal 09f86ec
+            if oprov:
Seth Vidal 09f86ec
+                iFP.setdefault(filename, []).extend([po.pkgtup for po in oprov])
Seth Vidal 09f86ec
+                continue
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+            nprov = self.tsInfo.getNewProvides(filename)
Seth Vidal 09f86ec
+            if nprov:
Seth Vidal 09f86ec
+                iFP.setdefault(filename, []).extend([po.pkgtup for po in nprov])
Seth Vidal 09f86ec
+                continue 
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+            for pkgtup in reverselookup[filename]:
Seth Vidal 09f86ec
+                po = self.getInstalledPackageObject(pkgtup)
Seth Vidal 09f86ec
+                ret.append( (po, (filename, 0, '')) )
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
+        self.rpmdb.transactionCacheFileRequires(self.installedFileRequires, 
Seth Vidal 09f86ec
+                                        self.installedUnresolvedFileRequires,
Seth Vidal 09f86ec
+                                        self.installedFileProviders,
Seth Vidal 09f86ec
+                                        ret)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        return ret
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
     def _checkConflicts(self):
Seth Vidal 09f86ec
         ret = [ ]
Seth Vidal 09f86ec
-        for po in self.rpmdb.returnPackages():
Seth Vidal 09f86ec
+        cpkgs = []
Seth Vidal 09f86ec
+        for po in self.rpmdb.returnConflictPackages():
Seth Vidal 09f86ec
             if self.tsInfo.getMembersWithState(po.pkgtup, output_states=TS_REMOVE_STATES):
Seth Vidal 09f86ec
                 continue
Seth Vidal 09f86ec
+            cpkgs.append(po)
Seth Vidal 09f86ec
             for conflict in po.returnPrco('conflicts'):
Seth Vidal 09f86ec
                 (r, f, v) = conflict
Seth Vidal 09f86ec
                 for conflicting_po in self.tsInfo.getNewProvides(r, f, v):
Seth Vidal 09f86ec
@@ -985,16 +1035,20 @@ class Depsolve(object):
Seth Vidal 09f86ec
                                  conflicting_po) )
Seth Vidal 09f86ec
         for txmbr in self.tsInfo.getMembersWithState(output_states=TS_INSTALL_STATES):
Seth Vidal 09f86ec
             po = txmbr.po
Seth Vidal 09f86ec
+            done = False
Seth Vidal 09f86ec
             for conflict in txmbr.po.returnPrco('conflicts'):
Seth Vidal 09f86ec
+                if not done:
Seth Vidal 09f86ec
+                    cpkgs.append(txmbr.po)
Seth Vidal 09f86ec
+                    done = True
Seth Vidal 09f86ec
                 (r, f, v) = conflict
Seth Vidal 09f86ec
                 for conflicting_po in self.tsInfo.getProvides(r, f, v):
Seth Vidal 09f86ec
                     if conflicting_po.pkgtup[0] == po.pkgtup[0] and conflicting_po.pkgtup[2:] == po.pkgtup[2:]:
Seth Vidal 09f86ec
                         continue
Seth Vidal 09f86ec
                     ret.append( (po, self._prco_req_nfv2req(r, f, v),
Seth Vidal 09f86ec
                                  conflicting_po) )
Seth Vidal 09f86ec
+        self.rpmdb.transactionCacheConflictPackages(cpkgs)
Seth Vidal 09f86ec
         return ret
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
-
Seth Vidal 09f86ec
     def isPackageInstalled(self, pkgname):
Seth Vidal 09f86ec
         lst = self.tsInfo.matchNaevr(name = pkgname)
Seth Vidal 09f86ec
         for txmbr in lst:
Seth Vidal 09f86ec
diff --git a/yum/rpmsack.py b/yum/rpmsack.py
Seth Vidal 09f86ec
index 151e33e..a5f4042 100644
Seth Vidal 09f86ec
--- a/yum/rpmsack.py
Seth Vidal 09f86ec
+++ b/yum/rpmsack.py
Seth Vidal 09f86ec
@@ -97,7 +97,10 @@ class RPMDBPackageSack(PackageSackBase):
Seth Vidal 09f86ec
                            rpm.RPMTAG_OBSOLETEFLAGS)
Seth Vidal 09f86ec
             }
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
-    def __init__(self, root='/', releasever=None):
Seth Vidal 09f86ec
+    # Do we want to cache rpmdb data in a file, for later use?
Seth Vidal 09f86ec
+    __cache_rpmdb__ = True
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    def __init__(self, root='/', releasever=None, cachedir=None):
Seth Vidal 09f86ec
         self.root = root
Seth Vidal 09f86ec
         self._idx2pkg = {}
Seth Vidal 09f86ec
         self._name2pkg = {}
Seth Vidal 09f86ec
@@ -107,6 +110,13 @@ class RPMDBPackageSack(PackageSackBase):
Seth Vidal 09f86ec
         self._get_pro_cache = {}
Seth Vidal 09f86ec
         self._get_req_cache  = {}
Seth Vidal 09f86ec
         self._loaded_gpg_keys = False
Seth Vidal 09f86ec
+        if cachedir is None:
Seth Vidal 09f86ec
+            cachedir = misc.getCacheDir()
Seth Vidal 09f86ec
+        self.setCacheDir(cachedir)
Seth Vidal 09f86ec
+        self._have_cached_rpmdbv_data = None
Seth Vidal 09f86ec
+        self._cached_conflicts_data = None
Seth Vidal 09f86ec
+        # Store the result of what happens, if a transaction completes.
Seth Vidal 09f86ec
+        self._trans_cache_store = {}
Seth Vidal 09f86ec
         self.ts = None
Seth Vidal 09f86ec
         self.releasever = releasever
Seth Vidal 09f86ec
         self.auto_close = False # this forces a self.ts.close() after
Seth Vidal 09f86ec
@@ -153,6 +163,13 @@ class RPMDBPackageSack(PackageSackBase):
Seth Vidal 09f86ec
             'conflicts' : { },
Seth Vidal 09f86ec
             'obsoletes' : { },
Seth Vidal 09f86ec
             }
Seth Vidal 09f86ec
+        self._have_cached_rpmdbv_data = None
Seth Vidal 09f86ec
+        self._cached_conflicts_data = None
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    def setCacheDir(self, cachedir):
Seth Vidal 09f86ec
+        """ Sets the internal cachedir value for the rpmdb, to be the
Seth Vidal 09f86ec
+            "rpmdb-cache" directory from this parent. """
Seth Vidal 09f86ec
+        self._cachedir = cachedir + "/rpmdb-cache/"
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
     def readOnlyTS(self):
Seth Vidal 09f86ec
         if not self.ts:
Seth Vidal 09f86ec
@@ -367,6 +384,103 @@ class RPMDBPackageSack(PackageSackBase):
Seth Vidal 09f86ec
             pkgobjlist = pkgobjlist[0] + pkgobjlist[1]
Seth Vidal 09f86ec
         return pkgobjlist
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
+    def _uncached_returnConflictPackages(self):
Seth Vidal 09f86ec
+        if self._cached_conflicts_data is None:
Seth Vidal 09f86ec
+            ret = []
Seth Vidal 09f86ec
+            for pkg in self.returnPackages():
Seth Vidal 09f86ec
+                if len(pkg.conflicts):
Seth Vidal 09f86ec
+                    ret.append(pkg)
Seth Vidal 09f86ec
+            self._cached_conflicts_data = ret
Seth Vidal 09f86ec
+        return self._cached_conflicts_data
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    def _write_conflicts_new(self, pkgs, rpmdbv):
Seth Vidal 09f86ec
+        if not os.access(self._cachedir, os.W_OK):
Seth Vidal 09f86ec
+            return
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        conflicts_fname = self._cachedir + '/conflicts'
Seth Vidal 09f86ec
+        fo = open(conflicts_fname + '.tmp', 'w')
Seth Vidal 09f86ec
+        fo.write("%s\n" % rpmdbv)
Seth Vidal 09f86ec
+        fo.write("%u\n" % len(pkgs))
Seth Vidal 09f86ec
+        for pkg in sorted(pkgs):
Seth Vidal 09f86ec
+            for var in pkg.pkgtup:
Seth Vidal 09f86ec
+                fo.write("%s\n" % var)
Seth Vidal 09f86ec
+        fo.close()
Seth Vidal 09f86ec
+        os.rename(conflicts_fname + '.tmp', conflicts_fname)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    def _write_conflicts(self, pkgs):
Seth Vidal 09f86ec
+        rpmdbv = self.simpleVersion(main_only=True)[0]
Seth Vidal 09f86ec
+        self._write_conflicts_new(pkgs, rpmdbv)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    def _read_conflicts(self):
Seth Vidal 09f86ec
+        if not self.__cache_rpmdb__:
Seth Vidal 09f86ec
+            return None
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        def _read_str(fo):
Seth Vidal 09f86ec
+            return fo.readline()[:-1]
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        conflict_fname = self._cachedir + '/conflicts'
Seth Vidal 09f86ec
+        if not os.path.exists(conflict_fname):
Seth Vidal 09f86ec
+            return None
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        fo = open(conflict_fname)
Seth Vidal 09f86ec
+        frpmdbv = fo.readline()
Seth Vidal 09f86ec
+        rpmdbv = self.simpleVersion(main_only=True)[0]
Seth Vidal 09f86ec
+        if not frpmdbv or rpmdbv != frpmdbv[:-1]:
Seth Vidal 09f86ec
+            return None
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        ret = []
Seth Vidal 09f86ec
+        try:
Seth Vidal 09f86ec
+            # Read the conflicts...
Seth Vidal 09f86ec
+            pkgtups_num = int(_read_str(fo))
Seth Vidal 09f86ec
+            while pkgtups_num > 0:
Seth Vidal 09f86ec
+                pkgtups_num -= 1
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+                # n, a, e, v, r
Seth Vidal 09f86ec
+                pkgtup = (_read_str(fo), _read_str(fo),
Seth Vidal 09f86ec
+                          _read_str(fo), _read_str(fo), _read_str(fo))
Seth Vidal 09f86ec
+                int(pkgtup[2]) # Check epoch is valid
Seth Vidal 09f86ec
+                ret.extend(self.searchPkgTuple(pkgtup))
Seth Vidal 09f86ec
+            if fo.readline() != '': # Should be EOF
Seth Vidal 09f86ec
+                return None
Seth Vidal 09f86ec
+        except ValueError:
Seth Vidal 09f86ec
+            return None
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        self._cached_conflicts_data = ret
Seth Vidal 09f86ec
+        return self._cached_conflicts_data
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    def transactionCacheConflictPackages(self, pkgs):
Seth Vidal 09f86ec
+        if self.__cache_rpmdb__:
Seth Vidal 09f86ec
+            self._trans_cache_store['conflicts'] = pkgs
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    def returnConflictPackages(self):
Seth Vidal 09f86ec
+        """ Return a list of packages that have conflicts. """
Seth Vidal 09f86ec
+        pkgs = self._read_conflicts()
Seth Vidal 09f86ec
+        if pkgs is None:
Seth Vidal 09f86ec
+            pkgs = self._uncached_returnConflictPackages()
Seth Vidal 09f86ec
+            if self.__cache_rpmdb__:
Seth Vidal 09f86ec
+                self._write_conflicts(pkgs)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        return pkgs
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    def transactionResultVersion(self, rpmdbv):
Seth Vidal 09f86ec
+        """ We are going to do a transaction, and the parameter will be the
Seth Vidal 09f86ec
+            rpmdb version when we finish. The idea being we can update all
Seth Vidal 09f86ec
+            our rpmdb caches for that rpmdb version. """
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        if not self.__cache_rpmdb__:
Seth Vidal 09f86ec
+            self._trans_cache_store = {}
Seth Vidal 09f86ec
+            return
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        if 'conflicts' in self._trans_cache_store:
Seth Vidal 09f86ec
+            pkgs = self._trans_cache_store['conflicts']
Seth Vidal 09f86ec
+            self._write_conflicts_new(pkgs, rpmdbv)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        if 'file-requires' in self._trans_cache_store:
Seth Vidal 09f86ec
+            data = self._trans_cache_store['file-requires']
Seth Vidal 09f86ec
+            self._write_file_requires(rpmdbv, data)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        self._trans_cache_store = {}
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
     def returnGPGPubkeyPackages(self):
Seth Vidal 09f86ec
         """ Return packages of the gpg-pubkeys ... hacky. """
Seth Vidal 09f86ec
         ts = self.readOnlyTS()
Seth Vidal 09f86ec
@@ -377,6 +491,198 @@ class RPMDBPackageSack(PackageSackBase):
Seth Vidal 09f86ec
             ret.append(self._makePackageObject(hdr, mi.instance()))
Seth Vidal 09f86ec
         return ret
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
+    def _read_file_requires(self):
Seth Vidal 09f86ec
+        def _read_str(fo):
Seth Vidal 09f86ec
+            return fo.readline()[:-1]
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        assert self.__cache_rpmdb__
Seth Vidal 09f86ec
+        if not os.path.exists(self._cachedir + '/file-requires'):
Seth Vidal 09f86ec
+            return None, None
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        rpmdbv = self.simpleVersion(main_only=True)[0]
Seth Vidal 09f86ec
+        fo = open(self._cachedir + '/file-requires')
Seth Vidal 09f86ec
+        frpmdbv = fo.readline()
Seth Vidal 09f86ec
+        if not frpmdbv or rpmdbv != frpmdbv[:-1]:
Seth Vidal 09f86ec
+            return None, None
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        iFR = {}
Seth Vidal 09f86ec
+        iFP = {}
Seth Vidal 09f86ec
+        try:
Seth Vidal 09f86ec
+            # Read the requires...
Seth Vidal 09f86ec
+            pkgtups_num = int(_read_str(fo))
Seth Vidal 09f86ec
+            while pkgtups_num > 0:
Seth Vidal 09f86ec
+                pkgtups_num -= 1
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+                # n, a, e, v, r
Seth Vidal 09f86ec
+                pkgtup = (_read_str(fo), _read_str(fo),
Seth Vidal 09f86ec
+                          _read_str(fo), _read_str(fo), _read_str(fo))
Seth Vidal 09f86ec
+                int(pkgtup[2]) # Check epoch is valid
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+                files_num = int(_read_str(fo))
Seth Vidal 09f86ec
+                while files_num > 0:
Seth Vidal 09f86ec
+                    files_num -= 1
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+                    fname = _read_str(fo)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+                    iFR.setdefault(pkgtup, []).append(fname)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+            # Read the provides...
Seth Vidal 09f86ec
+            files_num = int(_read_str(fo))
Seth Vidal 09f86ec
+            while files_num > 0:
Seth Vidal 09f86ec
+                files_num -= 1
Seth Vidal 09f86ec
+                fname = _read_str(fo)
Seth Vidal 09f86ec
+                pkgtups_num = int(_read_str(fo))
Seth Vidal 09f86ec
+                while pkgtups_num > 0:
Seth Vidal 09f86ec
+                    pkgtups_num -= 1
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+                    # n, a, e, v, r
Seth Vidal 09f86ec
+                    pkgtup = (_read_str(fo), _read_str(fo),
Seth Vidal 09f86ec
+                              _read_str(fo), _read_str(fo), _read_str(fo))
Seth Vidal 09f86ec
+                    int(pkgtup[2]) # Check epoch is valid
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+                    iFP.setdefault(fname, []).append(pkgtup)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+            if fo.readline() != '': # Should be EOF
Seth Vidal 09f86ec
+                return None, None
Seth Vidal 09f86ec
+        except ValueError:
Seth Vidal 09f86ec
+            return None, None
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        return iFR, iFP
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    def fileRequiresData(self):
Seth Vidal 09f86ec
+        """ Get a cached copy of the fileRequiresData for
Seth Vidal 09f86ec
+            depsolving/checkFileRequires, note the giant comment in that
Seth Vidal 09f86ec
+            function about how we don't keep this perfect for the providers of
Seth Vidal 09f86ec
+            the requires. """
Seth Vidal 09f86ec
+        if self.__cache_rpmdb__:
Seth Vidal 09f86ec
+            iFR, iFP = self._read_file_requires()
Seth Vidal 09f86ec
+            if iFR is not None:
Seth Vidal 09f86ec
+                return iFR, set(), iFP
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        installedFileRequires = {}
Seth Vidal 09f86ec
+        installedUnresolvedFileRequires = set()
Seth Vidal 09f86ec
+        resolved = set()
Seth Vidal 09f86ec
+        for pkg in self.returnPackages():
Seth Vidal 09f86ec
+            for name, flag, evr in pkg.requires:
Seth Vidal 09f86ec
+                if not name.startswith('/'):
Seth Vidal 09f86ec
+                    continue
Seth Vidal 09f86ec
+                installedFileRequires.setdefault(pkg.pkgtup, []).append(name)
Seth Vidal 09f86ec
+                if name not in resolved:
Seth Vidal 09f86ec
+                    dep = self.getProvides(name, flag, evr)
Seth Vidal 09f86ec
+                    resolved.add(name)
Seth Vidal 09f86ec
+                    if not dep:
Seth Vidal 09f86ec
+                        installedUnresolvedFileRequires.add(name)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        fileRequires = set()
Seth Vidal 09f86ec
+        for fnames in installedFileRequires.itervalues():
Seth Vidal 09f86ec
+            fileRequires.update(fnames)
Seth Vidal 09f86ec
+        installedFileProviders = {}
Seth Vidal 09f86ec
+        for fname in fileRequires:
Seth Vidal 09f86ec
+            pkgtups = [pkg.pkgtup for pkg in self.getProvides(fname)]
Seth Vidal 09f86ec
+            installedFileProviders[fname] = pkgtups
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        ret =  (installedFileRequires, installedUnresolvedFileRequires,
Seth Vidal 09f86ec
+                installedFileProviders)
Seth Vidal 09f86ec
+        if self.__cache_rpmdb__:
Seth Vidal 09f86ec
+            rpmdbv = self.simpleVersion(main_only=True)[0]
Seth Vidal 09f86ec
+            self._write_file_requires(rpmdbv, ret)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        return ret
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    def transactionCacheFileRequires(self, installedFileRequires,
Seth Vidal 09f86ec
+                                     installedUnresolvedFileRequires,
Seth Vidal 09f86ec
+                                     installedFileProvides,
Seth Vidal 09f86ec
+                                     problems):
Seth Vidal 09f86ec
+        if not self.__cache_rpmdb__:
Seth Vidal 09f86ec
+            return
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        if installedUnresolvedFileRequires or problems:
Seth Vidal 09f86ec
+            return
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        data = (installedFileRequires,
Seth Vidal 09f86ec
+                installedUnresolvedFileRequires,
Seth Vidal 09f86ec
+                installedFileProvides)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        self._trans_cache_store['file-requires'] = data
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    def _write_file_requires(self, rpmdbversion, data):
Seth Vidal 09f86ec
+        if not os.access(self._cachedir, os.W_OK):
Seth Vidal 09f86ec
+            return
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        (installedFileRequires,
Seth Vidal 09f86ec
+         installedUnresolvedFileRequires,
Seth Vidal 09f86ec
+         installedFileProvides) = data
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        fo = open(self._cachedir + '/file-requires.tmp', 'w')
Seth Vidal 09f86ec
+        fo.write("%s\n" % rpmdbversion)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        fo.write("%u\n" % len(installedFileRequires))
Seth Vidal 09f86ec
+        for pkgtup in sorted(installedFileRequires):
Seth Vidal 09f86ec
+            for var in pkgtup:
Seth Vidal 09f86ec
+                fo.write("%s\n" % var)
Seth Vidal 09f86ec
+            filenames = set(installedFileRequires[pkgtup])
Seth Vidal 09f86ec
+            fo.write("%u\n" % len(filenames))
Seth Vidal 09f86ec
+            for fname in sorted(filenames):
Seth Vidal 09f86ec
+                fo.write("%s\n" % fname)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        fo.write("%u\n" % len(installedFileProvides))
Seth Vidal 09f86ec
+        for fname in sorted(installedFileProvides):
Seth Vidal 09f86ec
+            fo.write("%s\n" % fname)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+            pkgtups = set(installedFileProvides[fname])
Seth Vidal 09f86ec
+            fo.write("%u\n" % len(pkgtups))
Seth Vidal 09f86ec
+            for pkgtup in sorted(pkgtups):
Seth Vidal 09f86ec
+                for var in pkgtup:
Seth Vidal 09f86ec
+                    fo.write("%s\n" % var)
Seth Vidal 09f86ec
+        fo.close()
Seth Vidal 09f86ec
+        os.rename(self._cachedir + '/file-requires.tmp',
Seth Vidal 09f86ec
+                  self._cachedir + '/file-requires')
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    def _get_cached_simpleVersion_main(self):
Seth Vidal 09f86ec
+        """ Return the cached string of the main rpmdbv. """
Seth Vidal 09f86ec
+        if self._have_cached_rpmdbv_data is not None:
Seth Vidal 09f86ec
+            return self._have_cached_rpmdbv_data
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        if not self.__cache_rpmdb__:
Seth Vidal 09f86ec
+            return None
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        #  This test is "obvious" and the only thing to come out of:
Seth Vidal 09f86ec
+        # http://lists.rpm.org/pipermail/rpm-maint/2007-November/001719.html
Seth Vidal 09f86ec
+        # ...if anything gets implemented, we should change.
Seth Vidal 09f86ec
+        rpmdbvfname = self._cachedir + "/version"
Seth Vidal 09f86ec
+        rpmdbfname  = "/var/lib/rpm/Packages"
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        if os.path.exists(rpmdbvfname) and os.path.exists(rpmdbfname):
Seth Vidal 09f86ec
+            # See if rpmdb has "changed" ...
Seth Vidal 09f86ec
+            nmtime = os.path.getmtime(rpmdbvfname)
Seth Vidal 09f86ec
+            omtime = os.path.getmtime(rpmdbfname)
Seth Vidal 09f86ec
+            if omtime <= nmtime:
Seth Vidal 09f86ec
+                rpmdbv = open(rpmdbvfname).readline()[:-1]
Seth Vidal 09f86ec
+                self._have_cached_rpmdbv_data  = rpmdbv
Seth Vidal 09f86ec
+        return self._have_cached_rpmdbv_data
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+    def _put_cached_simpleVersion_main(self, rpmdbv):
Seth Vidal 09f86ec
+        self._have_cached_rpmdbv_data  = str(rpmdbv)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        if not self.__cache_rpmdb__:
Seth Vidal 09f86ec
+            return
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        rpmdbvfname = self._cachedir + "/version"
Seth Vidal 09f86ec
+        if not os.access(self._cachedir, os.W_OK):
Seth Vidal 09f86ec
+            if os.path.exists(self._cachedir):
Seth Vidal 09f86ec
+                return
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+            try:
Seth Vidal 09f86ec
+                os.makedirs(self._cachedir)
Seth Vidal 09f86ec
+            except (IOError, OSError), e:
Seth Vidal 09f86ec
+                return
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        fo = open(rpmdbvfname + ".tmp", "w")
Seth Vidal 09f86ec
+        fo.write(self._have_cached_rpmdbv_data)
Seth Vidal 09f86ec
+        fo.write('\n')
Seth Vidal 09f86ec
+        fo.close()
Seth Vidal 09f86ec
+        os.rename(rpmdbvfname + ".tmp", rpmdbvfname)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
     def simpleVersion(self, main_only=False, groups={}):
Seth Vidal 09f86ec
         """ Return a simple version for all installed packages. """
Seth Vidal 09f86ec
         def _up_revs(irepos, repoid, rev, pkg, csum):
Seth Vidal 09f86ec
@@ -387,6 +693,11 @@ class RPMDBPackageSack(PackageSackBase):
Seth Vidal 09f86ec
                 rpsv = irevs.setdefault(rev, PackageSackVersion())
Seth Vidal 09f86ec
                 rpsv.update(pkg, csum)
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
+        if main_only and not groups:
Seth Vidal 09f86ec
+            rpmdbv = self._get_cached_simpleVersion_main()
Seth Vidal 09f86ec
+            if rpmdbv is not None:
Seth Vidal 09f86ec
+                return [rpmdbv, {}]
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
         main = PackageSackVersion()
Seth Vidal 09f86ec
         irepos = {}
Seth Vidal 09f86ec
         main_grps = {}
Seth Vidal 09f86ec
@@ -420,6 +731,9 @@ class RPMDBPackageSack(PackageSackBase):
Seth Vidal 09f86ec
                 if pkg.name in groups[group]:
Seth Vidal 09f86ec
                     _up_revs(irepos_grps[group], repoid, rev, pkg, csum)
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
+        if self._have_cached_rpmdbv_data is None:
Seth Vidal 09f86ec
+            self._put_cached_simpleVersion_main(main)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
         if groups:
Seth Vidal 09f86ec
             return [main, irepos, main_grps, irepos_grps]
Seth Vidal 09f86ec
         return [main, irepos]
Seth Vidal 09f86ec
diff --git a/yum/transactioninfo.py b/yum/transactioninfo.py
Seth Vidal 09f86ec
index c2fc804..c7d5b8c 100644
Seth Vidal 09f86ec
--- a/yum/transactioninfo.py
Seth Vidal 09f86ec
+++ b/yum/transactioninfo.py
Seth Vidal 09f86ec
@@ -26,7 +26,7 @@ to rpm.
Seth Vidal 09f86ec
 """
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
 from constants import *
Seth Vidal 09f86ec
-from packageSack import PackageSack
Seth Vidal 09f86ec
+from packageSack import PackageSack, PackageSackVersion
Seth Vidal 09f86ec
 from packages import YumInstalledPackage
Seth Vidal 09f86ec
 from sqlitesack import YumAvailablePackageSqlite
Seth Vidal 09f86ec
 import Errors
Seth Vidal 09f86ec
@@ -558,6 +558,42 @@ class TransactionData:
Seth Vidal 09f86ec
         result.update(self.getNewRequires(name, flag, version))
Seth Vidal 09f86ec
         return result
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
+    def futureRpmDBVersion(self):
Seth Vidal 09f86ec
+        """ Return a simple version for the future rpmdb. Works like
Seth Vidal 09f86ec
+            rpmdb.simpleVersion(main_only=True)[0], but for the state the rpmdb
Seth Vidal 09f86ec
+            will be in after the transaction. """
Seth Vidal 09f86ec
+        pkgs = self.rpmdb.returnPackages()
Seth Vidal 09f86ec
+        _reinstalled_pkgtups = {}
Seth Vidal 09f86ec
+        for txmbr in self.getMembersWithState(None, TS_INSTALL_STATES):
Seth Vidal 09f86ec
+            # reinstalls have to use their "new" checksum data, in case it's
Seth Vidal 09f86ec
+            # different.
Seth Vidal 09f86ec
+            if hasattr(txmbr, 'reinstall') and txmbr.reinstall:
Seth Vidal 09f86ec
+                _reinstalled_pkgtups[txmbr.po.pkgtup] = txmbr.po
Seth Vidal 09f86ec
+            pkgs.append(txmbr.po)
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+        main = PackageSackVersion()
Seth Vidal 09f86ec
+        for pkg in sorted(pkgs):
Seth Vidal 09f86ec
+            if pkg.repoid != 'installed':
Seth Vidal 09f86ec
+                # Paste from PackageSackBase.simpleVersion()
Seth Vidal 09f86ec
+                csum = pkg.returnIdSum()
Seth Vidal 09f86ec
+                main.update(pkg, csum)
Seth Vidal 09f86ec
+                continue
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+            # Installed pkg, see if it's about to die
Seth Vidal 09f86ec
+            if self.getMembersWithState(pkg.pkgtup, TS_REMOVE_STATES):
Seth Vidal 09f86ec
+                continue
Seth Vidal 09f86ec
+            # ...or die and be risen again (Zombie!)
Seth Vidal 09f86ec
+            if pkg.pkgtup in _reinstalled_pkgtups:
Seth Vidal 09f86ec
+                continue
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
+            # Paste from rpmdb.simpleVersion()
Seth Vidal 09f86ec
+            ydbi = pkg.yumdb_info
Seth Vidal 09f86ec
+            csum = None
Seth Vidal 09f86ec
+            if 'checksum_type' in ydbi and 'checksum_data' in ydbi:
Seth Vidal 09f86ec
+                csum = (ydbi.checksum_type, ydbi.checksum_data)
Seth Vidal 09f86ec
+            main.update(pkg, csum)
Seth Vidal 09f86ec
+        return main
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
 class ConditionalTransactionData(TransactionData):
Seth Vidal 09f86ec
     """A transaction data implementing conditional package addition"""
Seth Vidal 09f86ec
     def __init__(self):
Seth Vidal 09f86ec
@@ -615,6 +651,7 @@ class SortableTransactionData(TransactionData):
Seth Vidal 09f86ec
         self._sorted.reverse()
Seth Vidal 09f86ec
         return self._sorted
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
 class TransactionMember:
Seth Vidal 09f86ec
     """Class to describe a Transaction Member (a pkg to be installed/
Seth Vidal 09f86ec
        updated/erased)."""
Seth Vidal 09f86ec
diff --git a/yumcommands.py b/yumcommands.py
Seth Vidal 09f86ec
index b809216..f123c16 100644
Seth Vidal 09f86ec
--- a/yumcommands.py
Seth Vidal 09f86ec
+++ b/yumcommands.py
Seth Vidal 09f86ec
@@ -1099,20 +1099,29 @@ class VersionCommand(YumCommand):
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
         verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
Seth Vidal 09f86ec
         groups = {}
Seth Vidal 09f86ec
-        gconf = yum.config.readVersionGroupsConfig()
Seth Vidal 09f86ec
+        if vcmd in ('nogroups', 'nogroups-installed', 'nogroups-available',
Seth Vidal 09f86ec
+                    'nogroups-all'):
Seth Vidal 09f86ec
+            gconf = []
Seth Vidal 09f86ec
+            if vcmd == 'nogroups':
Seth Vidal 09f86ec
+                vcmd = 'installed'
Seth Vidal 09f86ec
+            else:
Seth Vidal 09f86ec
+                vcmd = vcmd[len('nogroups-'):]
Seth Vidal 09f86ec
+        else:
Seth Vidal 09f86ec
+            gconf = yum.config.readVersionGroupsConfig()
Seth Vidal 09f86ec
+
Seth Vidal 09f86ec
         for group in gconf:
Seth Vidal 09f86ec
             groups[group] = set(gconf[group].pkglist)
Seth Vidal 09f86ec
             if gconf[group].run_with_packages:
Seth Vidal 09f86ec
                 groups[group].update(base.run_with_package_names)
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
-        if vcmd in ('grouplist'):
Seth Vidal 09f86ec
+        if vcmd == 'grouplist':
Seth Vidal 09f86ec
             print _(" Yum version groups:")
Seth Vidal 09f86ec
             for group in sorted(groups):
Seth Vidal 09f86ec
                 print "   ", group
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
             return 0, ['version grouplist']
Seth Vidal 09f86ec
 
Seth Vidal 09f86ec
-        if vcmd in ('groupinfo'):
Seth Vidal 09f86ec
+        if vcmd == 'groupinfo':
Seth Vidal 09f86ec
             for group in groups:
Seth Vidal 09f86ec
                 if group not in extcmds[1:]:
Seth Vidal 09f86ec
                     continue
3427e23
commit 366c3e6bb9ebd7ad3f121bdf2c089b0132d51604
da4f145
Author: James Antill <james@and.org>
da4f145
Date:   Fri Dec 4 08:27:01 2009 -0500
da4f145
da4f145
     Fixes for clean functions, BZ 544173
da4f145
    
da4f145
     When nothing to be done, set removed.
da4f145
     When doing "clean all" fix the var. name.
da4f145
     When doing anything but clean rpmdb, fix the return.
3427e23
     Allow rpmdb as a valid arg.
3427e23
     Fix getFileList() with ext == ''
da4f145
da4f145
diff --git a/cli.py b/cli.py
da4f145
index f93a706..2c6c9a4 100644
da4f145
--- a/cli.py
da4f145
+++ b/cli.py
da4f145
@@ -897,7 +897,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
da4f145
             rpmcode, rpmresults = self.cleanRpmDB()
da4f145
             self.plugins.run('clean')
da4f145
             
da4f145
-            code = hdrcode + pkgcode + xmlcode + dbcode + rpmdb
da4f145
+            code = hdrcode + pkgcode + xmlcode + dbcode + rpmcode
da4f145
             results = (hdrresults + pkgresults + xmlresults + dbresults +
da4f145
                        rpmresults)
da4f145
             for msg in results:
da4f145
diff --git a/yum/__init__.py b/yum/__init__.py
da4f145
index affa92b..1c82144 100644
da4f145
--- a/yum/__init__.py
da4f145
+++ b/yum/__init__.py
da4f145
@@ -1714,15 +1714,15 @@ class YumBase(depsolve.Depsolve):
da4f145
 
da4f145
     def _cleanFiles(self, exts, pathattr, filetype):
da4f145
         filelist = []
da4f145
-        removed = 0
da4f145
         for ext in exts:
da4f145
             for repo in self.repos.listEnabled():
da4f145
                 path = getattr(repo, pathattr)
da4f145
                 if os.path.exists(path) and os.path.isdir(path):
da4f145
                     filelist = misc.getFileList(path, ext, filelist)
da4f145
-        self._cleanFilelist(filetype, filelist)
da4f145
+        return self._cleanFilelist(filetype, filelist)
da4f145
 
da4f145
     def _cleanFilelist(self, filetype, filelist):
da4f145
+        removed = 0
da4f145
         for item in filelist:
da4f145
             try:
da4f145
                 misc.unlink_f(item)
3427e23
diff --git a/yum/misc.py b/yum/misc.py
3427e23
index 642f9a2..f221f1d 100644
3427e23
--- a/yum/misc.py
3427e23
+++ b/yum/misc.py
3427e23
@@ -336,7 +336,7 @@ def getFileList(path, ext, filelist):
3427e23
         if os.path.isdir(path + '/' + d):
3427e23
             filelist = getFileList(path + '/' + d, ext, filelist)
3427e23
         else:
3427e23
-            if d[-extlen:].lower() == '%s' % (ext):
3427e23
+            if not ext or d[-extlen:].lower() == '%s' % (ext):
3427e23
                 newpath = os.path.normpath(path + '/' + d)
3427e23
                 filelist.append(newpath)
3427e23
                     
3427e23
diff --git a/yumcommands.py b/yumcommands.py
3427e23
index 83d9d00..4fe2fe1 100644
3427e23
--- a/yumcommands.py
3427e23
+++ b/yumcommands.py
3427e23
@@ -85,7 +85,7 @@ def checkGroupArg(base, basecmd, extcmds):
3427e23
 
3427e23
 def checkCleanArg(base, basecmd, extcmds):
3427e23
     VALID_ARGS = ('headers', 'packages', 'metadata', 'dbcache', 'plugins',
3427e23
-                  'expire-cache', 'all')
3427e23
+                  'expire-cache', 'rpmdb', 'all')
3427e23
 
3427e23
     if len(extcmds) == 0:
3427e23
         base.logger.critical(_('Error: clean requires an option: %s') % (
0d64cf3
commit dbcdcd605d233c555f3ce3861152a2378bf9e622
0d64cf3
Author: James Antill <james@and.org>
0d64cf3
Date:   Thu Dec 10 09:46:00 2009 -0500
0d64cf3
0d64cf3
    Fix when we have file require(s) from just to be installed pkgs. The mash bug
0d64cf3
0d64cf3
diff --git a/yum/depsolve.py b/yum/depsolve.py
0d64cf3
index b5953c2..d46452c 100644
0d64cf3
--- a/yum/depsolve.py
0d64cf3
+++ b/yum/depsolve.py
0d64cf3
@@ -1009,7 +1009,11 @@ class Depsolve(object):
0d64cf3
                 continue 
0d64cf3
 
0d64cf3
             for pkgtup in reverselookup[filename]:
0d64cf3
-                po = self.getInstalledPackageObject(pkgtup)
0d64cf3
+                po = self.tsInfo.getMembersWithState(pkgtup, TS_INSTALL_STATES)
0d64cf3
+                if po:
0d64cf3
+                    po = po[0] # Should only have one
0d64cf3
+                else:
0d64cf3
+                    po = self.getInstalledPackageObject(pkgtup)
0d64cf3
                 ret.append( (po, (filename, 0, '')) )
0d64cf3
 
0d64cf3
         self.rpmdb.transactionCacheFileRequires(self.installedFileRequires, 
36e4acc
commit 67882783e6add4c5c9b717872554c23fc0ade913
36e4acc
Author: James Antill <james@and.org>
36e4acc
Date:   Thu Dec 10 18:28:28 2009 -0500
36e4acc
36e4acc
    getMembers returns txmbrs not POs ... *sigh*
36e4acc
36e4acc
diff --git a/yum/depsolve.py b/yum/depsolve.py
36e4acc
index d46452c..a09bd4b 100644
36e4acc
--- a/yum/depsolve.py
36e4acc
+++ b/yum/depsolve.py
36e4acc
@@ -1011,7 +1011,7 @@ class Depsolve(object):
36e4acc
             for pkgtup in reverselookup[filename]:
36e4acc
                 po = self.tsInfo.getMembersWithState(pkgtup, TS_INSTALL_STATES)
36e4acc
                 if po:
36e4acc
-                    po = po[0] # Should only have one
36e4acc
+                    po = po[0].po # Should only have one
36e4acc
                 else:
36e4acc
                     po = self.getInstalledPackageObject(pkgtup)
36e4acc
                 ret.append( (po, (filename, 0, '')) )