[yum-cvs] 22 commits - rpmUtils/miscutils.py test/packagetests.py yum/depsolve.py yum/packageSack.py yum/packages.py yum/rpmsack.py yum/sqlitesack.py yum/transactioninfo.py

Seth Vidal skvidal at linux.duke.edu
Wed Aug 1 19:09:22 UTC 2007


 rpmUtils/miscutils.py  |   63 ++++++-
 test/packagetests.py   |   15 +
 yum/depsolve.py        |  396 +++++++++++++++++--------------------------------
 yum/packageSack.py     |  175 +++++++++++++--------
 yum/packages.py        |  100 +++---------
 yum/rpmsack.py         |   49 ++----
 yum/sqlitesack.py      |  103 +++++++++++-
 yum/transactioninfo.py |   94 +++++++++++
 8 files changed, 556 insertions(+), 439 deletions(-)

New commits:
commit 543497c3cc8009bb8d812014db89335d0ff64610
Merge: 643039c... c63662d...
Author: Seth Vidal <skvidal at fedoraproject.org>
Date:   Wed Aug 1 15:08:26 2007 -0400

    Merge branch 'ffesti' of git://www.jur-linux.org/git-data/yum-ffesti
    
    * 'ffesti' of git://www.jur-linux.org/git-data/yum-ffesti: (21 commits)
      remove merge artifact
      move creation of sqlite idices to sqlitesack to create them even if the metadataparser is used
      only search in sqlite db if there are any sqlitedb pkgs in the transaction
      fix copy/paste error: match new conflicts against whole transaction
      Add some test cases for rangeCompare
      Don't treat installed obsoletes as conflicts
      load PRCO only once from the sqlitedb - even if it is empty
      Make PackageSack.matchPackageNames() match all other implementations of this method, needed to use PackageSack as a part of a MetaSack
      keep PackageSack indexes up2date
      remove code obsoleted by new search API
      trigger file requires check when install members got removed from transaction
      Check removed transaction members to avoid missing dependencies
      Use new search API in checkRemove
      New conflict check implementation using new search API, fixes rh#245707
      use new search API in checkInstall
      ajust to new tsInfo interface
      add .get(Old|New)?Provides(), .get(Old|New)?Requires() to TransactionData (ak tsInfo)
      add .getProvides(), .getRequires() to PackageSack, MetaSack
      add .getProvides(), .getRequires() to SqliteSack
      move PRCO compare code out of package
      ...

commit c63662df10d16eafefbc6cb1527e31226b61ca72
Author: Florian Festi <ffesti at redhat.com>
Date:   Wed Jul 25 13:05:43 2007 +0200

    remove merge artifact

diff --git a/yum/depsolve.py b/yum/depsolve.py
index 93e40f6..dfc0e49 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
@@ -780,7 +780,6 @@ class Depsolve(object):
             if len(thisneeds) == 0:
                 self._dcobj.already_seen[txmbr] = 1
             ret.extend(thisneeds)
-            self._dcobj.already_seen[txmbr] = 1
 
         # check transaction members that got removed from the transaction again
         for txmbr in self.tsInfo.getRemovedMembers():
commit 42283902f929ac131cda7b3497ae047b497e02bc
Author: Florian Festi <ffesti at redhat.com>
Date:   Tue Jul 24 16:21:28 2007 +0200

    move creation of sqlite idices to sqlitesack to create them even if the metadataparser is used

diff --git a/yum/sqlitesack.py b/yum/sqlitesack.py
index 113fd0a..8dc2c6c 100644
--- a/yum/sqlitesack.py
+++ b/yum/sqlitesack.py
@@ -262,8 +262,19 @@ class YumSqlitePackageSack(yumRepo.YumPackageSack):
 
         if datatype == 'metadata':
             self.primarydb[repo] = dataobj
+            # temporary hack to create indexes that are not (yet)
+            # created by the metadata parser
+            cur = dataobj.cursor()
+            cur.execute("CREATE INDEX IF NOT EXISTS pkgprovides ON provides (pkgKey)")
+            cur.execute("CREATE INDEX IF NOT EXISTS requiresname ON requires (name)")
+            cur.execute("CREATE INDEX IF NOT EXISTS pkgrequires ON requires (pkgKey)")
+            cur.execute("CREATE INDEX IF NOT EXISTS pkgconflicts ON conflicts (pkgKey)")
+            cur.execute("CREATE INDEX IF NOT EXISTS pkgobsoletes ON obsoletes (pkgKey)")
+            cur.execute("CREATE INDEX IF NOT EXISTS filenames ON files (name)")
         elif datatype == 'filelists':
             self.filelistsdb[repo] = dataobj
+            cur = dataobj.cursor()
+            cur.execute("CREATE INDEX IF NOT EXISTS dirnames ON filelist (dirname)")
         elif datatype == 'otherdata':
             self.otherdb[repo] = dataobj
         else:
commit 0c186d4aa575257e64fc6b8cbd7934fc55e508a0
Author: Florian Festi <ffesti at redhat.com>
Date:   Tue Jul 24 15:11:00 2007 +0200

    only search in sqlite db if there are any sqlitedb pkgs in the transaction

diff --git a/yum/transactioninfo.py b/yum/transactioninfo.py
index 0233939..1fc172c 100644
--- a/yum/transactioninfo.py
+++ b/yum/transactioninfo.py
@@ -43,6 +43,7 @@ class TransactionData:
 
         self.rpmdb = None
         self.pkgSack = None
+        self.pkgSackPackages = 0
         self.localSack = PackageSack()
 
         # lists of txmbrs in their states - just placeholders
@@ -169,6 +170,8 @@ class TransactionData:
         # Is this the right criteria?
         if not isinstance(txmember.po, (YumInstalledPackage, YumAvailablePackageSqlite)):
             self.localSack.addPackage(txmember.po)
+        elif isinstance(txmember.po, YumAvailablePackageSqlite):
+            self.pkgSackPackages += 1
 
         if self.conditionals.has_key(txmember.name):
             for po in self.conditionals[txmember.name]:
@@ -186,6 +189,8 @@ class TransactionData:
             # Is this the right criteria?
             if not isinstance(txmbr.po, (YumInstalledPackage, YumAvailablePackageSqlite)):
                 self.localSack.delPackage(txmbr.po)
+            elif isinstance(txmbr.po, YumAvailablePackageSqlite):
+                self.pkgSackPackages -= 1
         
         self.removedmembers.setdefault(pkgtup, []).extend(self.pkgdict[pkgtup])
         del self.pkgdict[pkgtup]
@@ -375,9 +380,10 @@ class TransactionData:
         """return dict { packages -> list of matching provides }
         searches in packages to be installed"""
         result = { }
-        for pkg, hits in self.pkgSack.getProvides(name, flag, version).iteritems():
-            if self.getMembersWithState(pkg.pkgtup, TS_INSTALL_STATES):
-                result[pkg] = hits
+        if self.pkgSackPackages:
+            for pkg, hits in self.pkgSack.getProvides(name, flag, version).iteritems():
+                if self.getMembersWithState(pkg.pkgtup, TS_INSTALL_STATES):
+                    result[pkg] = hits
         result.update(self.localSack.getProvides(name, flag, version))
         return result
 
@@ -400,9 +406,10 @@ class TransactionData:
         """return dict { packages -> list of matching provides }
         searches in packages to be installed"""
         result = { }
-        for pkg, hits in self.pkgSack.getRequires(name, flag, version).iteritems():
-            if self.getMembersWithState(pkg.pkgtup, TS_INSTALL_STATES):
-                result[pkg] = hits
+        if self.pkgSackPackages:
+            for pkg, hits in self.pkgSack.getRequires(name, flag, version).iteritems():
+                if self.getMembersWithState(pkg.pkgtup, TS_INSTALL_STATES):
+                    result[pkg] = hits
         result.update(self.localSack.getRequires(name, flag, version))
         return result
 
commit cec2d343d6596853e033e73ffee1af4e9704897a
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 20 14:58:42 2007 +0200

    fix copy/paste error: match new conflicts against whole transaction

diff --git a/yum/depsolve.py b/yum/depsolve.py
index 9f65f87..93e40f6 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
@@ -1089,7 +1089,7 @@ class Depsolve(object):
             po = txmbr.po
             for conflict in txmbr.po.returnPrco('conflicts'):
                 (r, f, v) = conflict
-                for conflicting_po in self.tsInfo.getNewProvides(r, f, v):
+                for conflicting_po in self.tsInfo.getProvides(r, f, v):
                     if conflicting_po.pkgtup[0] == po.pkgtup[0] and conflicting_po.pkgtup[2:] == po.pkgtup[2:]:
                         continue
                     ret.append( ((po.name, po.version, po.release),
commit 5e59d1d420db1948af12db5e864df0f9dee9b127
Author: Florian Festi <ffesti at redhat.com>
Date:   Wed Jul 18 16:00:54 2007 +0200

    Add some test cases for rangeCompare

diff --git a/test/packagetests.py b/test/packagetests.py
index a779689..56f73ec 100644
--- a/test/packagetests.py
+++ b/test/packagetests.py
@@ -2,6 +2,7 @@ import unittest
 import settestpath
 
 from yum import packages
+from rpmUtils import miscutils
 
 class InPrcoRangePackageTests(unittest.TestCase):
 
@@ -183,12 +184,26 @@ class BuildPackageDictRefTests(unittest.TestCase):
 
         self.assertEquals(0, len(unseen_keys))
 
+class RangeCompareTests(unittest.TestCase):
+
+    def testRangeCompare(self):
+        for requires, provides, result in (
+            (('foo', 'EQ', ('0', '1.4.4', '0')),   ('foo', 'EQ', ('0', '1.4.4', '0')),  1),
+            (('foo', 'EQ', ('0', '1.4.4', '0')),   ('foo', 'EQ', ('0', '1.4.4', None)), 1),
+            (('foo', 'EQ', ('0', '1.4.4', None)),  ('foo', 'EQ', ('0', '1.4.4', '8')),  1),
+            (('foo', 'LT', ('0', '1.5.4', None)),  ('foo', 'EQ', ('0', '1.4.4', '7')),  1),
+            (('foo', 'GE', ('0', '1.4.4', '7.1')), ('foo', 'EQ', ('0', '1.4.4', '7')),  0),
+            (('foo', 'EQ', ('0', '1.4', None)),    ('foo', 'EQ', ('0', '1.4.4', '7')),  0),
+            (('foo', 'GT', ('1', '1.4.4', None)),  ('foo', 'EQ', ('3', '1.2.4', '7')),  1),
+            ):
+            self.assertEquals(miscutils.rangeCompare(requires, provides), result)
 
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(unittest.makeSuite(InPrcoRangePackageTests))
     suite.addTest(unittest.makeSuite(PackageEvrTests))
     suite.addTest(unittest.makeSuite(BuildPackageDictRefTests))
+    suite.addTest(unittest.makeSuite(RangeCompareTests))
     return suite
                 
 if __name__ == "__main__":
commit f230df50389bf22de629da03b5054de643f9103e
Author: Florian Festi <ffesti at redhat.com>
Date:   Tue Jul 17 10:04:54 2007 +0200

    Don't treat installed obsoletes as conflicts

diff --git a/yum/depsolve.py b/yum/depsolve.py
index 22bc85f..9f65f87 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
@@ -1077,8 +1077,7 @@ class Depsolve(object):
         for po in self.rpmdb.returnPackages():
             if self.tsInfo.getMembersWithState(po.pkgtup, output_states=TS_REMOVE_STATES):
                 continue
-            for conflict in po.returnPrco('conflicts') + \
-                    po.returnPrco('obsoletes'):
+            for conflict in po.returnPrco('conflicts'):
                 (r, f, v) = conflict
                 for conflicting_po in self.tsInfo.getNewProvides(r, f, v):
                     if conflicting_po.pkgtup[0] == po.pkgtup[0] and conflicting_po.pkgtup[2:] == po.pkgtup[2:]:
commit 16114e696bf50aa17d633f93fa3f79db6ad6c22e
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 16:10:08 2007 +0200

    load PRCO only once from the sqlitedb - even if it is empty

diff --git a/yum/sqlitesack.py b/yum/sqlitesack.py
index 8ed4b56..113fd0a 100644
--- a/yum/sqlitesack.py
+++ b/yum/sqlitesack.py
@@ -37,10 +37,10 @@ import rpmUtils.miscutils
 class YumAvailablePackageSqlite(YumAvailablePackage, PackageObject, RpmBase):
     def __init__(self, repo, db_obj):
         self._checksums = []
-        self.prco = { 'obsoletes': [],
-                      'conflicts': [],
-                      'requires': [],
-                      'provides': [] }
+        self.prco = { 'obsoletes': (),
+                      'conflicts': (),
+                      'requires': (),
+                      'provides': () }
         self._files = {}
         self.sack = repo.sack
         self.repoid = repo.id
@@ -183,16 +183,13 @@ class YumAvailablePackageSqlite(YumAvailablePackage, PackageObject, RpmBase):
         return map(lambda x: x['fname'], cur)
 
     def returnPrco(self, prcotype, printable=False):
-        if not self.prco[prcotype]:
+        if isinstance(self.prco[prcotype], tuple):
             cache = self.sack.primarydb[self.repo]
             cur = cache.cursor()
-            query = "select %s.name as name, %s.version as version, "\
-                        "%s.release as release, %s.epoch as epoch, "\
-                        "%s.flags as flags from %s "\
-                        "where %s.pkgKey = '%s'" % (prcotype, prcotype,
-                        prcotype, prcotype, prcotype, prcotype, prcotype,
-                        self.pkgKey)
+            query = "select name, version, release, epoch, flags from %s "\
+                        "where pkgKey = '%s'" % (prcotype, self.pkgKey)
             executeSQL(cur, query)
+            self.prco[prcotype] = [ ]
             for ob in cur:
                 self.prco[prcotype].append((ob['name'], ob['flags'],
                                            (ob['epoch'], ob['version'], 
commit fdf386b3bb3c23943479ac2fd59692de3b23178b
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 16:00:40 2007 +0200

    Make PackageSack.matchPackageNames() match all other implementations of this method, needed to use PackageSack as a part of a MetaSack

diff --git a/yum/packageSack.py b/yum/packageSack.py
index cf23cad..3b57e50 100644
--- a/yum/packageSack.py
+++ b/yum/packageSack.py
@@ -145,8 +145,8 @@ class PackageSackBase(object):
     def searchAll(self, arg, query_type):
         raise NotImplementedError()
     
-    def matchPackageNames(self, input, casematch=False):
-        """take a user strings and match the packages in the sack against it
+    def matchPackageNames(self, pkgspecs):
+        """take a list strings and match the packages in the sack against it
            this will match against:
            name
            name.arch
@@ -156,40 +156,24 @@ class PackageSackBase(object):
            epoch:name-ver-rel.arch
            name-epoch:ver-rel.arch
            
-           it yields a package object for each match
-
-            Arguments:
-             input: string
-               string to match
-             
-             casematch: Boolean
-                if true then match case sensitively
-                if false then match case insensitively
-                default False
+           return [exact matches], [glob matches], [unmatch search terms]
            """
         # Setup match() for the search we're doing
-        if re.search('[\*\[\]\{\}\?]', input):
-            restring = fnmatch.translate(input)
-            if casematch:
-                regex = re.compile(restring)             # case sensitive
-            else:
-                regex = re.compile(restring, flags=re.I) # case insensitive
-
-            def match(s):
-                return regex.match(s)
+        matched = []
+        exactmatch = []
+        unmatched = set(pkgspecs)
 
-        else:
-            if casematch:
-                def match(s):
-                    return s == input
+        specs = {}
+        for p in pkgspecs:
+            if re.search('[\*\[\]\{\}\?]', p):
+                restring = fnmatch.translate(p)
+                specs[p] = re.compile(restring)
             else:
-                input = input.lower()
-                def match(s):
-                    return s.lower() == input
+                specs[p] = p
          
         for pkgtup in self.simplePkgList():
             (n,a,e,v,r) = pkgtup
-            names = (
+            names = set((
                 n, 
                 '%s.%s' % (n, a),
                 '%s-%s-%s.%s' % (n, v, r, a),
@@ -197,13 +181,18 @@ class PackageSackBase(object):
                 '%s-%s-%s' % (n, v, r),
                 '%s:%s-%s-%s.%s' % (e, n, v, r, a),
                 '%s-%s:%s-%s.%s' % (n, e, v, r, a),
-                )
-            for name in names:
-                if match(name):
-                    for po in self.searchPkgTuple(pkgtup):
-                        yield po
-                    break       # Only match once per package
-
+                ))
+            for term, query in specs:
+                if term == query:
+                    if query in names:
+                        exactmatch.append(self.searchPkgTuple(pkgtup)[0])
+                        unmatched.discard(term)
+                else:
+                    for n in names:
+                        if query.match(n):
+                            matched.append(self.searchPkgTuple(pkgtup)[0])
+                            unmatched.discard(term)
+        return misc.unique(exactmatch), misc.unique(matched), list(unmatched)
 
 
 class MetaSack(PackageSackBase):
commit b017aee03e68bcdfb0761860800e4e040160535d
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 15:57:47 2007 +0200

    keep PackageSack indexes up2date

diff --git a/yum/packageSack.py b/yum/packageSack.py
index cfe6a4e..cf23cad 100644
--- a/yum/packageSack.py
+++ b/yum/packageSack.py
@@ -540,7 +540,7 @@ class PackageSack(PackageSackBase):
 
     def _delFromListOfDict(self, dict, key, data):
         if not dict.has_key(key):
-            dict[key] = []
+            return
         try:
             dict[key].remove(data)
         except ValueError:
@@ -561,13 +561,23 @@ class PackageSack(PackageSackBase):
                 self._addToDictAsList(self.pkgsByRepo, repoid, obj)
         else:
             self._addToDictAsList(self.pkgsByRepo, repoid, obj)
-
+        if self.indexesBuilt:
+            self._addPackageToIndex(obj)
 
     def buildIndexes(self):
         """builds the useful indexes for searching/querying the packageSack
            This should be called after all the necessary packages have been 
            added/deleted"""
+
+        self.clearIndexes()
         
+        for repoid in self.pkgsByRepo.keys():
+            for obj in self.pkgsByRepo[repoid]:
+                self._addPackageToIndex(obj)
+        self.indexesBuilt = 1
+
+
+    def clearIndexes(self):
         # blank out the indexes
         self.obsoletes = {}
         self.requires = {}
@@ -576,36 +586,50 @@ class PackageSack(PackageSackBase):
         self.filenames = {}
         self.nevra = {}
         self.pkgsByID = {}
-        
-        for repoid in self.pkgsByRepo.keys():
-            for obj in self.pkgsByRepo[repoid]:
-            # store the things provided just on name, not the whole require+version
-            # this lets us reduce the set of pkgs to search when we're trying to depSolve
-                for (n, fl, (e,v,r)) in obj.returnPrco('obsoletes'):
-                    self._addToDictAsList(self.obsoletes, n, obj)
-                for (n, fl, (e,v,r)) in obj.returnPrco('requires'):
-                    self._addToDictAsList(self.requires, n, obj)
-                for (n, fl, (e,v,r)) in obj.returnPrco('provides'):
-                    self._addToDictAsList(self.provides, n, obj)
-                for (n, fl, (e,v,r)) in obj.returnPrco('conflicts'):
-                    self._addToDictAsList(self.conflicts, n, obj)
-                for ftype in obj.returnFileTypes():
-                    for file in obj.returnFileEntries(ftype):
-                        self._addToDictAsList(self.filenames, file, obj)
-                self._addToDictAsList(self.pkgsByID, obj.id, obj)
-                (name, arch, epoch, ver, rel) = obj.pkgtup
-                self._addToDictAsList(self.nevra, (name, epoch, ver, rel, arch), obj)
-                self._addToDictAsList(self.nevra, (name, None, None, None, None), obj)
-        
-        self.indexesBuilt = 1
-        
 
+        self.indexesBuilt = 0
+        
+    def _addPackageToIndex(self, obj):
+        # store the things provided just on name, not the whole require+version
+        # this lets us reduce the set of pkgs to search when we're trying to depSolve
+        for (n, fl, (e,v,r)) in obj.returnPrco('obsoletes'):
+            self._addToDictAsList(self.obsoletes, n, obj)
+        for (n, fl, (e,v,r)) in obj.returnPrco('requires'):
+            self._addToDictAsList(self.requires, n, obj)
+        for (n, fl, (e,v,r)) in obj.returnPrco('provides'):
+            self._addToDictAsList(self.provides, n, obj)
+        for (n, fl, (e,v,r)) in obj.returnPrco('conflicts'):
+            self._addToDictAsList(self.conflicts, n, obj)
+        for ftype in obj.returnFileTypes():
+            for file in obj.returnFileEntries(ftype):
+                self._addToDictAsList(self.filenames, file, obj)
+        self._addToDictAsList(self.pkgsByID, obj.id, obj)
+        (name, arch, epoch, ver, rel) = obj.pkgtup
+        self._addToDictAsList(self.nevra, (name, epoch, ver, rel, arch), obj)
+        self._addToDictAsList(self.nevra, (name, None, None, None, None), obj)
+
+    def _delPackageFromIndex(self, obj):
+        for (n, fl, (e,v,r)) in obj.returnPrco('obsoletes'):
+            self._delFromListOfDict(self.obsoletes, n, obj)
+        for (n, fl, (e,v,r)) in obj.returnPrco('requires'):
+            self._delFromListOfDict(self.requires, n, obj)
+        for (n, fl, (e,v,r)) in obj.returnPrco('provides'):
+            self._delFromListOfDict(self.provides, n, obj)
+        for (n, fl, (e,v,r)) in obj.returnPrco('conflicts'):
+            self._delFromListOfDict(self.conflicts, n, obj)
+        for ftype in obj.returnFileTypes():
+            for file in obj.returnFileEntries(ftype):
+                self._delFromListOfDict(self.filenames, file, obj)
+        self._delFromListOfDict(self.pkgsByID, obj.id, obj)
+        (name, arch, epoch, ver, rel) = obj.pkgtup
+        self._delFromListOfDict(self.nevra, (name, epoch, ver, rel, arch), obj)
+        self._delFromListOfDict(self.nevra, (name, None, None, None, None), obj)
         
     def delPackage(self, obj):
         """delete a pkgobject"""
         self._delFromListOfDict(self.pkgsByRepo, obj.repoid, obj)
-        if self.indexesBuilt: # if we've built indexes, delete it b/c we've just deleted something
-            self.indexesBuilt = 0
+        if self.indexesBuilt: 
+            self._delPackageFromIndex(obj)
         
     def returnPackages(self, repoid=None):
         """return list of all packages, takes optional repoid"""
commit 316f4c0d15567a5a7c74dc2f14dd402b98b50f8c
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 14:46:03 2007 +0200

    remove code obsoleted by new search API

diff --git a/yum/depsolve.py b/yum/depsolve.py
index ba024d5..22bc85f 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
@@ -52,7 +52,6 @@ class Depsolve(object):
         self.logger = logging.getLogger("yum.Depsolve")
         self.verbose_logger = logging.getLogger("yum.verbose.Depsolve")
 
-        self.deps = {}
         self.path = []
         self.loops = []
 
@@ -721,35 +720,6 @@ class Depsolve(object):
         errors.append(msg)
         return CheckDeps, conflicts
 
-    def _provideToPkg(self, req):
-        best = None
-        (r, f, v) = req
-
-        for pkgtup in self.rpmdb.whatProvides(r, f, v):
-            # check the rpmdb first for something providing it that's not
-            # set to be removed
-            txmbrs = self.tsInfo.getMembersWithState(pkgtup, TS_REMOVE_STATES)
-            if not txmbrs:
-                po = self.getInstalledPackageObject(pkgtup)            
-                self.deps[req] = po                
-                return po
-
-        for po in self.whatProvides(r, f, v):
-            # if we already have something to be installed which
-            # does the provide then that's obviously the one we want to use.
-            # this takes care of the case that we select, eg, kernel-smp
-            # and then have something which requires kernel
-            if self.tsInfo.getMembers(po.pkgtup):
-                self.deps[req] = po
-                return po
-        
-        for txmbr in self.tsInfo.getMembersWithState(None, TS_INSTALL_STATES):
-            if txmbr.po.checkPrco('provides', (r, f, v)):
-                self.deps[req] = txmbr.po
-                return txmbr.po
-                
-        return None # for new ts check attempt
-
     def _undoDepInstalls(self):
         # clean up after ourselves in the case of failures
         for txmbr in self.tsInfo:
@@ -1128,97 +1098,6 @@ class Depsolve(object):
                                  None, rpm.RPMDEP_SENSE_CONFLICTS) )
         return ret
 
-    def _requiredByPkg(self, prov, pos = []):
-        """check to see if anything will or does require the provide, return 
-           list of requiring pkg objects if so"""
-
-        (r, f, v) = prov
-
-        removeList = []
-        # see what requires this provide name
-
-        for instpo in pos:
-            pkgtup = instpo.pkgtup
-            # ignore stuff already being removed
-            if self.tsInfo.getMembersWithState(pkgtup, TS_REMOVE_STATES):
-                continue
-            if pkgtup in self._removing:
-                continue
-            # check to ensure that we really fulfill instpo's need for r
-            if not instpo.checkPrco('requires', (r,f,v)): 
-                continue
-
-            self.verbose_logger.log(logginglevels.DEBUG_2, "looking at %s as a requirement of %s", r, pkgtup)                
-            isok = False
-            # now see if anything else is providing what we need
-            for provtup in self.rpmdb.whatProvides(r, None, None):
-                # check if this provider is being removed
-                if provtup in self._removing:
-                    continue
-                if self.tsInfo.getMembersWithState(provtup, TS_REMOVE_STATES):
-                    continue
-
-                provpo = self.getInstalledPackageObject(provtup)
-                if provpo in removeList:
-                    continue
-                # check if provpo actually satisfies instpo's need for r
-                # if so, we're golden
-                ok = True
-                for (rr, rf, rv) in instpo.requires:
-                    if rr != r:
-                        continue
-                    if not provpo.checkPrco('provides', (rr, rf, rv)):
-                        ok = False
-                if ok:
-                    isok = True
-                    break
-
-            if isok:
-                continue
-
-            # for files, we need to do a searchProvides() to take
-            # advantage of the shortcut of the files globbed into
-            # primary.xml.gz.  this is a bit of a hack, but saves us
-            # from having to download the filelists for a lot of cases
-            if r[0] == "/":
-                for po in self.pkgSack.searchProvides(r):
-                    if self.tsInfo.getMembersWithState(po.pkgtup, TS_INSTALL_STATES):
-                        isok = True
-                        break
-                for po in self.rpmdb.searchFiles(r):
-                    if not self.tsInfo.getMembersWithState(po.pkgtup, TS_REMOVE_STATES):
-                        isok = True
-                        break
-            if isok:
-                continue
-
-            # now do the same set of checks with packages that are
-            # set to be installed.  
-            for txmbr in self.tsInfo.getMembersWithState(None, TS_INSTALL_STATES):
-                if txmbr.po.checkPrco('provides',
-                                      (r, None, (None,None,None))):
-                    ok = True
-                    for (rr, rf, rv) in instpo.requires:
-                        if rr != r:
-                            continue
-                        if not txmbr.po.checkPrco('provides', (rr, rf, rv)):
-                            ok = False
-                    if ok:
-                        isok = True
-                        break
-
-                # FIXME: it's ugly to have to check files separately here
-                elif r[0] == "/" and r in txmbr.po.filelist:
-                    isok = True
-                    break
-
-            if isok:
-                continue
-
-            if not isok:
-                removeList.append(instpo)
-                self._removing.append(instpo.pkgtup)
-        return removeList
 
     def isPackageInstalled(self, pkgname):
         installed = False
commit ac6380247f2a2c50c625e50bfc16cedbc2caa235
Author: Florian Festi <ffesti at redhat.com>
Date:   Wed Jul 25 10:51:27 2007 +0200

    trigger file requires check when install members got removed from transaction

diff --git a/yum/depsolve.py b/yum/depsolve.py
index 8854446..ba024d5 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
@@ -826,6 +826,7 @@ class Depsolve(object):
                                     "Checking deps for %s" %(txmbr,))
             if txmbr.output_state in TS_INSTALL_STATES:
                 thisneeds = self._checkRemove(txmbr)
+                check_removes = True
             elif txmbr.output_state in TS_REMOVE_STATES:
                 thisneeds = self._checkInstall(txmbr)
             if len(thisneeds) == 0:
commit 7664e0381969320d796ddec321264c16401f68aa
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 14:43:14 2007 +0200

    Check removed transaction members to avoid missing dependencies

diff --git a/yum/depsolve.py b/yum/depsolve.py
index 8042018..8854446 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
@@ -812,6 +812,26 @@ class Depsolve(object):
             ret.extend(thisneeds)
             self._dcobj.already_seen[txmbr] = 1
 
+        # check transaction members that got removed from the transaction again
+        for txmbr in self.tsInfo.getRemovedMembers():
+            if self.dcobj.already_seen_removed.has_key(txmbr):
+                continue
+            if self.dsCallback and txmbr.ts_state:
+                if txmbr.ts_state == 'i':
+                    self.dsCallback.pkgAdded(txmbr.pkgtup, 'e')
+                else:
+                    self.dsCallback.pkgAdded(txmbr.pkgtup, 'i')
+
+            self.verbose_logger.log(logginglevels.DEBUG_2,
+                                    "Checking deps for %s" %(txmbr,))
+            if txmbr.output_state in TS_INSTALL_STATES:
+                thisneeds = self._checkRemove(txmbr)
+            elif txmbr.output_state in TS_REMOVE_STATES:
+                thisneeds = self._checkInstall(txmbr)
+            if len(thisneeds) == 0:
+                self.dcobj.already_seen_removed[txmbr] = 1
+            ret.extend(thisneeds)
+
         if check_removes:
             ret.extend(self._checkFileRequires())
         ret.extend(self._checkConflicts())
@@ -1225,7 +1245,8 @@ class DepCheck(object):
         self.requires = []
         self.conflicts = []
         self.already_seen = {}
-        
+        self.already_seen_removed = {}
+
     def addRequires(self, po, req_tuple_list):
         # fixme - do checking for duplicates or additions in here to zip things along
         reqobj = Requires(po, req_tuple_list)
diff --git a/yum/transactioninfo.py b/yum/transactioninfo.py
index 69b4c65..0233939 100644
--- a/yum/transactioninfo.py
+++ b/yum/transactioninfo.py
@@ -35,6 +35,7 @@ class TransactionData:
         self.probFilterFlags = []
         self.root = '/'
         self.pkgdict = {} # key = pkgtup, val = list of TransactionMember obj
+        self.removedmembers = {}
         self.debug = 0
         self.changed = False
         
@@ -86,6 +87,21 @@ class TransactionData:
 
         return returnlist
             
+    def getRemovedMembers(self, pkgtup=None):
+        """takes an optional package tuple and returns all transaction members
+           matching, no pkgtup means it returns all transaction members"""
+
+        returnlist = []
+
+        if pkgtup is None:
+            for members in self.removedmembers.itervalues():
+                returnlist.extend(members)
+        elif self.removedmembers.has_key(pkgtup):
+            returnlist.extend(self.pkgdict[pkgtup])
+
+        return returnlist
+
+
     def getMode(self, name=None, arch=None, epoch=None, ver=None, rel=None):
         """returns the mode of the first match from the transaction set, 
            otherwise, returns None"""
@@ -171,6 +187,7 @@ class TransactionData:
             if not isinstance(txmbr.po, (YumInstalledPackage, YumAvailablePackageSqlite)):
                 self.localSack.delPackage(txmbr.po)
         
+        self.removedmembers.setdefault(pkgtup, []).extend(self.pkgdict[pkgtup])
         del self.pkgdict[pkgtup]
         self.changed = True        
     
commit 5d3a9cab763678bc01f518b8cdea01039fd39394
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 12:30:20 2007 +0200

    Use new search API in checkRemove
    
    New .checkFileRequires() inow checks all file requires insted of removed files

diff --git a/yum/depsolve.py b/yum/depsolve.py
index 4aabbf3..8042018 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
@@ -56,6 +56,9 @@ class Depsolve(object):
         self.path = []
         self.loops = []
 
+        self.installedFileRequires = None
+        self.installedUnresolvedFileRequires = None
+
     def doTsSetup(self):
         warnings.warn('doTsSetup() will go away in a future version of Yum.\n',
                 Errors.YumFutureDeprecationWarning, stacklevel=2)
@@ -788,6 +791,7 @@ class Depsolve(object):
 
 
         ret = []
+        check_removes = False
         for txmbr in self.tsInfo.getMembers():
             
             if self._dcobj.already_seen.has_key(txmbr):
@@ -802,10 +806,14 @@ class Depsolve(object):
                 thisneeds = self._checkInstall(txmbr)
             elif txmbr.output_state in TS_REMOVE_STATES:
                 thisneeds = self._checkRemove(txmbr)
+                check_removes = True
             if len(thisneeds) == 0:
                 self._dcobj.already_seen[txmbr] = 1
             ret.extend(thisneeds)
+            self._dcobj.already_seen[txmbr] = 1
 
+        if check_removes:
+            ret.extend(self._checkFileRequires())
         ret.extend(self._checkConflicts())
             
         return ret
@@ -990,93 +998,89 @@ class Depsolve(object):
         po = txmbr.po
         provs = po.returnPrco('provides')
 
-        # get the files in the package and express them as "provides"
-        files = po.filelist
-        filesasprovs = map(lambda f: (f, None, (None,None,None)), files)
-        provs.extend(filesasprovs)
-
         # if this is an update, we should check what the new package
         # provides to make things faster
         newpoprovs = {}
         for newpo in txmbr.updated_by:
             for p in newpo.provides:
                 newpoprovs[p] = 1
-            for f in newpo.simpleFiles(): # newpo.filelist:
-                newpoprovs[(f, None, (None, None, None))] = 1
-
         ret = []
-        self._removing = []
-        goneprovs = {}
-        gonefiles = {}
-        removes = {}
         
         # iterate over the provides of the package being removed
         # and see what's actually going away
         for prov in provs:
             if prov[0].startswith('rpmlib('): # ignore rpmlib() provides
                 continue
-            if prov[0].startswith("/usr/share/doc"): # XXX: ignore doc files
-                continue
             if newpoprovs.has_key(prov):
                 continue
-            if not prov[0][0] == "/":
-                goneprovs[prov[0]] = prov
-            else:
-                gonefiles[prov[0]] = prov
-
-        # now see what from the rpmdb really requires these
-        for (provname, prov) in goneprovs.items() + gonefiles.items():
-            instrequirers = []
-            for pkgtup in self.rpmdb.whatRequires(provname, None, None):
-                instpo = self.getInstalledPackageObject(pkgtup)
-                instrequirers.append(instpo)
-            
-            self.verbose_logger.log(logginglevels.DEBUG_4, "looking to see what requires %s of %s", prov, po)
-            removes[prov] = self._requiredByPkg(prov, instrequirers)
+            for pkg, hits in self.tsInfo.getRequires(*prov).iteritems():
+                for rn, rf, rv in hits:
+                    if not self.tsInfo.getProvides(rn, rf, rv):
+                        reqtuple = (rn, version_tuple_to_string(rv), flags[rf])
+                        self._dcobj.addRequires(pkg, [reqtuple])
+                        ret.append(
+                            ((pkg.name, pkg.version, pkg.release),
+                             (rn, version_tuple_to_string(rv)),
+                             flags[rf], None, rpm.RPMDEP_SENSE_REQUIRES) )
+        return ret
 
-        # now, let's see if anything that we're installing requires anything
-        # that this provides
-        for txmbr in self.tsInfo.getMembersWithState(None, TS_INSTALL_STATES):
-            for r in txmbr.po.requires_names:
-                prov = None
-                if r in goneprovs.keys():
-                    prov = goneprovs[r]
-                elif r[0] == "/" and r in gonefiles:
-                    prov = gonefiles[r]
-
-                if prov and not removes.has_key(prov):
-                    removes[prov] = self._requiredByPkg(prov, [txmbr.po])
-                elif prov:
-                    removes[prov].extend(self._requiredByPkg(prov, [txmbr.po]))                        
-
-        # now we know what needs to be removed and the provide causing it
-        # to be removed.  let's stick them in the ret list
-        for (prov, removeList) in removes.items():
-            (r, f, v) = prov
-            for po in removeList:
-                flags = {"GT": rpm.RPMSENSE_GREATER,
-                         "GE": rpm.RPMSENSE_EQUAL | rpm.RPMSENSE_GREATER,
-                         "LT": rpm.RPMSENSE_LESS,
-                         "LE": rpm.RPMSENSE_LESS | rpm.RPMSENSE_EQUAL,
-                         "EQ": rpm.RPMSENSE_EQUAL,
-                         None: 0 }
-                f = v = None
-                for (rr, rf, rv) in po.requires:
-                    if rr == r:
-                        f = rf
-                        v = rv
-                        break
+    def _checkFileRequires(self):
+        fileRequires = set()
+        reverselookup = {}
+        ret = []
 
-                self._removing.append(po.pkgtup)
-                reqtuple = (r, version_tuple_to_string(v), flags[f])
-                self._dcobj.addRequires(po, [reqtuple])
-                
-                ret.append( ((po.name, po.version, po.release),
-                             (r, version_tuple_to_string(v)),
-                             flags[f], None, rpm.RPMDEP_SENSE_REQUIRES) )
+        # generate list of file requirement in rpmdb
+        if self.installedFileRequires is None:
+            self.installedFileRequires = {}
+            self.installedUnresolvedFileRequires = set()
+            resolved = set()
+            for pkg in self.rpmdb.returnPackages():
+                for name, flag, evr in pkg.requires:
+                    if not name.startswith('/'):
+                        continue
+                    self.installedFileRequires.setdefault(pkg, []).append(name)
+                    if name not in resolved:
+                        dep = self.rpmdb.getProvides(name, flag, evr)
+                        resolved.add(name)
+                        if not dep:
+                            self.installedUnresolvedFileRequires.add(name)
+
+        # get file requirements from packages not deleted
+        for po, files in self.installedFileRequires.iteritems():
+            if not self._tsInfo.getMembersWithState(po.pkgtup, output_states=TS_REMOVE_STATES):
+                fileRequires.update(files)
+                for filename in files:
+                    reverselookup.setdefault(filename, []).append(po)
+
+        fileRequires -= self.installedUnresolvedFileRequires
+
+        # get file requirements from new packages
+        for txmbr in self._tsInfo.getMembersWithState(output_states=TS_INSTALL_STATES):
+            for name, flag, evr in txmbr.po.requires:
+                if name.startswith('/'):
+                    # check if file requires was already unresolved in update
+                    if name in self.installedUnresolvedFileRequires:
+                        already_broken = False
+                        for oldpo in txmbr.updates:
+                            if oldpo.checkPrco('requires', (name, None, (None, None, None))):
+                                already_broken = True
+                                break
+                        if already_broken:
+                            continue
+                    fileRequires.add(name)
+                    reverselookup.setdefault(name, []).append(txmbr.po)
+
+        # check the file requires
+        for filename in fileRequires:
+            if not self.tsInfo.getOldProvides(filename) and not self.tsInfo.getNewProvides(filename):
+                for po in reverselookup[filename]:
+                    ret.append( ((po.name, po.version, po.release),
+                                 (filename, ''), 0, None,
+                                 rpm.RPMDEP_SENSE_REQUIRES) )
 
         return ret
 
+
     def _checkConflicts(self):
         ret = [ ]
         for po in self.rpmdb.returnPackages():
commit 340132409a802dbc172023c064d82d371c2d8e17
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 12:22:50 2007 +0200

    New conflict check implementation using new search API, fixes rh#245707

diff --git a/yum/depsolve.py b/yum/depsolve.py
index 7020673..4aabbf3 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
@@ -805,6 +805,8 @@ class Depsolve(object):
             if len(thisneeds) == 0:
                 self._dcobj.already_seen[txmbr] = 1
             ret.extend(thisneeds)
+
+        ret.extend(self._checkConflicts())
             
         return ret
 
@@ -982,40 +984,6 @@ class Depsolve(object):
                     pkgtup=po.pkgtup, output_states=TS_INSTALL_STATES):
                     member.setAsDep(txmbr.po)
 
-
-        for conflict in txmbr.po.returnPrco('conflicts'):
-            (r, f, v) = conflict
-            txmbrs = self.tsInfo.matchNaevr(name=r)
-            for tx in self.tsInfo.getMembersWithState(output_states = TS_INSTALL_STATES):
-                if tx.name != r and r not in tx.po.provides_names:
-                    continue
-                if tx.po.checkPrco('provides', (r, f, v)):
-                    ret.append( ((txmbr.name, txmbr.version, txmbr.release),
-                                 (r, version_tuple_to_string(v)), flags[f],
-                                 None, rpm.RPMDEP_SENSE_CONFLICTS) )
-
-            inst = self.rpmdb.whatProvides(r, None, None)
-            for pkgtup in inst:
-                txmbrs = self.tsInfo.getMembersWithState(pkgtup,
-                                                         TS_REMOVE_STATES)
-                if not txmbrs:
-                    po = self.getInstalledPackageObject(pkgtup)
-                    if po.checkPrco('provides', (r, f, v)):
-                        ret.append( ((txmbr.name, txmbr.version, txmbr.release),
-                                     (r, version_tuple_to_string(v)), flags[f],
-                                     None, rpm.RPMDEP_SENSE_CONFLICTS) )
-        
-        for instpkg in self.rpmdb.searchConflicts(txmbr.name):
-            prcotuple = (txmbr.name, 'EQ', (txmbr.epoch, txmbr.version, txmbr.release))
-            if instpkg.checkPrco('conflicts', prcotuple):
-                # if the conflict-having-version is being removed then well, it doesn't matter
-                if self.tsInfo.getMembersWithState(instpkg.pkgtup, output_states=TS_REMOVE_STATES):
-                    continue
-                instevr = (instpkg.epoch, instpkg.ver, instpkg.rel)
-                ret.append( ((txmbr.name, txmbr.version, txmbr.release),
-                             (instpkg.name, version_tuple_to_string(instevr)), rpm.RPMSENSE_EQUAL,
-                                     None, rpm.RPMDEP_SENSE_CONFLICTS) )
-                
         return ret
 
     def _checkRemove(self, txmbr):
@@ -1109,6 +1077,32 @@ class Depsolve(object):
 
         return ret
 
+    def _checkConflicts(self):
+        ret = [ ]
+        for po in self.rpmdb.returnPackages():
+            if self.tsInfo.getMembersWithState(po.pkgtup, output_states=TS_REMOVE_STATES):
+                continue
+            for conflict in po.returnPrco('conflicts') + \
+                    po.returnPrco('obsoletes'):
+                (r, f, v) = conflict
+                for conflicting_po in self.tsInfo.getNewProvides(r, f, v):
+                    if conflicting_po.pkgtup[0] == po.pkgtup[0] and conflicting_po.pkgtup[2:] == po.pkgtup[2:]:
+                        continue
+                    ret.append( ((po.name, po.version, po.release),
+                                 (r, version_tuple_to_string(v)), flags[f],
+                                 None, rpm.RPMDEP_SENSE_CONFLICTS) )
+        for txmbr in self.tsInfo.getMembersWithState(output_states=TS_INSTALL_STATES):
+            po = txmbr.po
+            for conflict in txmbr.po.returnPrco('conflicts'):
+                (r, f, v) = conflict
+                for conflicting_po in self.tsInfo.getNewProvides(r, f, v):
+                    if conflicting_po.pkgtup[0] == po.pkgtup[0] and conflicting_po.pkgtup[2:] == po.pkgtup[2:]:
+                        continue
+                    ret.append( ((po.name, po.version, po.release),
+                                 (r, version_tuple_to_string(v)), flags[f],
+                                 None, rpm.RPMDEP_SENSE_CONFLICTS) )
+        return ret
+
     def _requiredByPkg(self, prov, pos = []):
         """check to see if anything will or does require the provide, return 
            list of requiring pkg objects if so"""
commit 8715bbbd062d826a018e7c23d5fc13c186656264
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 12:08:51 2007 +0200

    use new search API in checkInstall

diff --git a/yum/depsolve.py b/yum/depsolve.py
index b6c3c6f..7020673 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
@@ -946,20 +946,14 @@ class Depsolve(object):
 
     def _checkInstall(self, txmbr):
         reqs = txmbr.po.returnPrco('requires')
-        provs = txmbr.po.returnPrco('provides')
-
-        flags = {"GT": rpm.RPMSENSE_GREATER,
-                 "GE": rpm.RPMSENSE_EQUAL | rpm.RPMSENSE_GREATER,
-                 "LT": rpm.RPMSENSE_LESS,
-                 "LE": rpm.RPMSENSE_LESS | rpm.RPMSENSE_EQUAL,
-                 "EQ": rpm.RPMSENSE_EQUAL,
-                 None: 0 }
+        provs = set(txmbr.po.returnPrco('provides'))
 
         # if this is an update, we should check what the old
         # requires were to make things faster
         oldreqs = []
         for oldpo in txmbr.updates:
             oldreqs.extend(oldpo.returnPrco('requires'))
+        oldreqs = set(oldreqs)
 
         ret = []
         for req in reqs:
@@ -971,39 +965,24 @@ class Depsolve(object):
                 continue
             
             self.verbose_logger.log(logginglevels.DEBUG_2, "looking for %s as a requirement of %s", req, txmbr)
-            dep = self.deps.get(req, None)
-            if dep is None:
-                dep = self._provideToPkg(req)
-                if dep is None:
-                    reqtuple = (req[0], version_tuple_to_string(req[2]), flags[req[1]])
-                    self._dcobj.addRequires(txmbr.po, [reqtuple])
-                    ret.append( ((txmbr.name, txmbr.version, txmbr.release),
-                                 (req[0], version_tuple_to_string(req[2])), flags[req[1]], None,
-                                 rpm.RPMDEP_SENSE_REQUIRES) )
-                    continue
-
-            # Skip filebased requires on self, etc
-            if txmbr.name == dep.name:
-                continue
-            # FIXME: Yum doesn't need this, right?
-            #if (dep.name, txmbr.name) in whiteout.whitetup:
-            #   log.debug("ignoring %s>%s in whiteout" %(dep.name, txmbr.name))
-            #   continue
-            if self.isPackageInstalled(dep.name):
+            provs = self.tsInfo.getProvides(*req)
+            if not provs:
+                reqtuple = (req[0], version_tuple_to_string(req[2]), flags[req[1]])
+                self._dcobj.addRequires(txmbr.po, [reqtuple])
+                ret.append( ((txmbr.name, txmbr.version, txmbr.release),
+                             (req[0], version_tuple_to_string(req[2])), flags[req[1]], None,
+                             rpm.RPMDEP_SENSE_REQUIRES) )
                 continue
-            if self.tsInfo.exists(dep.pkgtup):
-                pkgs = self.tsInfo.getMembers(pkgtup=dep.pkgtup)
-                member = self.bestPackagesFromList(pkgs)[0]
-
-                #Add relationship
-                found = False
-                for dependspo in txmbr.depends_on:
-                    if member.po == dependspo:
-                        found = True
-                        break
-                if not found:
+
+            #Add relationship
+            for po in provs:
+                if txmbr.name == po.name:
+                    continue
+                for member in self.tsInfo.getMembersWithState(
+                    pkgtup=po.pkgtup, output_states=TS_INSTALL_STATES):
                     member.setAsDep(txmbr.po)
 
+
         for conflict in txmbr.po.returnPrco('conflicts'):
             (r, f, v) = conflict
             txmbrs = self.tsInfo.matchNaevr(name=r)
commit 8f8e07b31343afe03f5503e70d60cb855e285b25
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 12:06:53 2007 +0200

    ajust to new tsInfo interface
    
    move flags maping to module name space

diff --git a/yum/depsolve.py b/yum/depsolve.py
index a42259d..b6c3c6f 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
@@ -36,6 +36,13 @@ import Errors
 import warnings
 warnings.simplefilter("ignore", Errors.YumFutureDeprecationWarning)
 
+flags = {"GT": rpm.RPMSENSE_GREATER,
+         "GE": rpm.RPMSENSE_EQUAL | rpm.RPMSENSE_GREATER,
+         "LT": rpm.RPMSENSE_LESS,
+         "LE": rpm.RPMSENSE_LESS | rpm.RPMSENSE_EQUAL,
+         "EQ": rpm.RPMSENSE_EQUAL,
+         None: 0 }
+
 class Depsolve(object):
     def __init__(self):
         packages.base = self
@@ -66,12 +73,13 @@ class Depsolve(object):
             raise Errors.YumBaseError, 'Setting up TransactionSets before config class is up'
         
         self._tsInfo = self._transactionDataFactory()
+        self._tsInfo.setDatabases(self.rpmdb, self.pkgSack)
         self.initActionTs()
     
     def _getTsInfo(self):
         if self._tsInfo is None:
             self._tsInfo = self._transactionDataFactory()
-
+            self._tsInfo.setDatabases(self.rpmdb, self.pkgSack)
         return self._tsInfo
 
     def _setTsInfo(self, value):
commit 5f8557e8b95c2b6c8f566c3549bb6566cd05d865
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 11:21:40 2007 +0200

    add .get(Old|New)?Provides(), .get(Old|New)?Requires() to TransactionData (ak tsInfo)

diff --git a/yum/transactioninfo.py b/yum/transactioninfo.py
index 8ea2a72..69b4c65 100644
--- a/yum/transactioninfo.py
+++ b/yum/transactioninfo.py
@@ -21,7 +21,9 @@
 # with the given txmbr. 
 
 from constants import *
-from packageSack import ListPackageSack
+from packageSack import ListPackageSack, PackageSack
+from packages import YumInstalledPackage
+from sqlitesack import YumAvailablePackageSqlite
 import Errors
 import warnings
 
@@ -38,6 +40,10 @@ class TransactionData:
         
         self.conditionals = {} # key = pkgname, val = list of pos to add
 
+        self.rpmdb = None
+        self.pkgSack = None
+        self.localSack = PackageSack()
+
         # lists of txmbrs in their states - just placeholders
         self.instgroups = []
         self.removedgroups = []
@@ -144,6 +150,10 @@ class TransactionData:
         self.pkgdict[txmember.pkgtup].append(txmember)
         self.changed = True
 
+        # Is this the right criteria?
+        if not isinstance(txmember.po, (YumInstalledPackage, YumAvailablePackageSqlite)):
+            self.localSack.addPackage(txmember.po)
+
         if self.conditionals.has_key(txmember.name):
             for po in self.conditionals[txmember.name]:
                 condtxmbr = self.addInstall(po)
@@ -157,6 +167,9 @@ class TransactionData:
             return
         for txmbr in self.pkgdict[pkgtup]:
             txmbr.po.state = None
+            # Is this the right criteria?
+            if not isinstance(txmbr.po, (YumInstalledPackage, YumAvailablePackageSqlite)):
+                self.localSack.delPackage(txmbr.po)
         
         del self.pkgdict[pkgtup]
         self.changed = True        
@@ -337,6 +350,61 @@ class TransactionData:
         return txmbr
 
 
+    def setDatabases(self, rpmdb, pkgSack):
+        self.rpmdb = rpmdb
+        self.pkgSack = pkgSack
+
+    def getNewProvides(self, name, flag=None, version=None):
+        """return dict { packages -> list of matching provides }
+        searches in packages to be installed"""
+        result = { }
+        for pkg, hits in self.pkgSack.getProvides(name, flag, version).iteritems():
+            if self.getMembersWithState(pkg.pkgtup, TS_INSTALL_STATES):
+                result[pkg] = hits
+        result.update(self.localSack.getProvides(name, flag, version))
+        return result
+
+    def getOldProvides(self, name, flag=None, version=None):
+        """return dict { packages -> list of matching provides }
+        searches in packages already installed and not going to be removed"""
+        result = { }
+        for pkg, hits in self.rpmdb.getProvides(name, flag, version).iteritems():
+            if not self.getMembersWithState(pkg.pkgtup, TS_REMOVE_STATES):
+                result[pkg] = hits
+        return result
+
+    def getProvides(self, name, flag=None, version=None):
+        """return dict { packages -> list of matching provides }"""
+        result = self.getOldProvides(name, flag, version)
+        result.update(self.getNewProvides(name, flag, version))
+        return result
+
+    def getNewRequires(self, name, flag=None, version=None):
+        """return dict { packages -> list of matching provides }
+        searches in packages to be installed"""
+        result = { }
+        for pkg, hits in self.pkgSack.getRequires(name, flag, version).iteritems():
+            if self.getMembersWithState(pkg.pkgtup, TS_INSTALL_STATES):
+                result[pkg] = hits
+        result.update(self.localSack.getRequires(name, flag, version))
+        return result
+
+
+    def getOldRequires(self, name, flag=None, version=None):
+        """return dict { packages -> list of matching provides }
+        searches in packages already installed and not going to be removed"""
+        result = { }
+        for pkg, hits in self.rpmdb.getRequires(name, flag, version).iteritems():
+            if not self.getMembersWithState(pkg.pkgtup, TS_REMOVE_STATES):
+                result[pkg] = hits
+        return result
+
+    def getRequires(self, name, flag=None, version=None):
+        """return dict { packages -> list of matching provides }"""
+        result = self.getOldRequires(name, flag, version)
+        result.update(self.getNewRequires(name, flag, version))
+        return result
+
 class ConditionalTransactionData(TransactionData):
     """A transaction data implementing conditional package addition"""
     def __init__(self):
commit 06bce7916c7669d7fe2fffda4b6eeaa200a36d8a
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 11:10:50 2007 +0200

    add .getProvides(), .getRequires() to PackageSack, MetaSack

diff --git a/yum/packageSack.py b/yum/packageSack.py
index fce183f..cfe6a4e 100644
--- a/yum/packageSack.py
+++ b/yum/packageSack.py
@@ -65,6 +65,14 @@ class PackageSackBase(object):
         (n,a,e,v,r) = pkgtup
         return self.searchNevra(name=n, arch=a, epoch=e, ver=v, rel=r)
         
+    def getProvides(self, name, flags=None, version=None):
+        """return dict { packages -> list of matching provides }"""
+        raise NotImplementedError()
+
+    def getRequires(self, name, flags=None, version=None):
+        """return dict { packages -> list of matching requires }"""
+        raise NotImplementedError()
+
     def searchRequires(self, name):
         """return list of package requiring the name (any evr and flag)"""
         raise NotImplementedError()
@@ -231,6 +239,14 @@ class MetaSack(PackageSackBase):
         """return list of pkgobjects matching the nevra requested"""
         return self._computeAggregateListResult("searchNevra", name, epoch, ver, rel, arch)
 
+    def getProvides(self, name, flags=None, version=None):
+        """return dict { packages -> list of matching provides }"""
+        return self._computeAggregateDictResult("getProvides", name, flags, version)
+
+    def getRequires(self, name, flags=None, version=None):
+        """return dict { packages -> list of matching requires }"""
+        return self._computeAggregateDictResult("getRequires", name, flags, version)
+
     def searchRequires(self, name):
         """return list of package requiring the name (any evr and flag)"""
         return self._computeAggregateListResult("searchRequires", name)
@@ -435,6 +451,26 @@ class PackageSack(PackageSackBase):
         else:
             return []
         
+    def getProvides(self, name, flags=None, version=None):
+        """return dict { packages -> list of matching provides }"""
+        self._checkIndexes(failure='build')
+        result = { }
+        for po in self.provides.get(name, []):
+            hits = po.matchingPrcos('provides', (name, flags, version))
+            if hits:
+                result[po] = hits
+        return result
+
+    def getRequires(self, name, flags=None, version=None):
+        """return dict { packages -> list of matching requires }"""
+        self._checkIndexes(failure='build')
+        result = { }
+        for po in self.requires.get(name, []):
+            hits = po.matchingPrcos('requires', (name, flags, version))
+            if hits:
+                result[po] = hits
+        return result
+
     def searchRequires(self, name):
         """return list of package requiring the name (any evr and flag)"""
         self._checkIndexes(failure='build')        
commit 4d63b3ee908a058ac78f6d43c3ea76e3995122c7
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 11:05:29 2007 +0200

    add .getProvides(), .getRequires() to SqliteSack

diff --git a/yum/sqlitesack.py b/yum/sqlitesack.py
index 436aab5..8ed4b56 100644
--- a/yum/sqlitesack.py
+++ b/yum/sqlitesack.py
@@ -32,6 +32,7 @@ import misc
 import warnings
 
 from sqlutils import executeSQL
+import rpmUtils.miscutils
 
 class YumAvailablePackageSqlite(YumAvailablePackage, PackageObject, RpmBase):
     def __init__(self, repo, db_obj):
@@ -210,6 +211,10 @@ class YumSqlitePackageSack(yumRepo.YumPackageSack):
         self.filelistsdb = {}
         self.otherdb = {}
         self.excludes = {}
+        self._search_cache = {
+            'provides' : { },
+            'requires' : { },
+            }
 
     def __len__(self):
         for (rep,cache) in self.primarydb.items():
@@ -427,6 +432,74 @@ class YumSqlitePackageSack(yumRepo.YumPackageSack):
         
         return pkgs
         
+
+    def _search(self, prcotype, name, flags, version):
+        if flags == 0:
+            flags = None
+        if type(version) in (str, type(None), unicode):
+            req = (name, flags, rpmUtils.miscutils.stringToVersion(
+                version))
+        elif type(version) in (tuple, list): # would this ever be a list?
+            req = (name, flags, version)
+
+        if self._search_cache[prcotype].has_key(req):
+            return self._search_cache[prcotype][req]
+
+        result = { }
+
+        for (rep,cache) in self.primarydb.items():
+            cur = cache.cursor()
+            executeSQL(cur, "select * from %s where name=?" % prcotype,
+                       (name,))
+            tmp = { }
+            for x in cur:
+                val = (x['name'], x['flags'],
+                       (x['epoch'], x['version'], x['release']))
+                if rpmUtils.miscutils.rangeCompare(req, val):
+                    tmp.setdefault(x['pkgKey'], []).append(val)
+            for pkgKey, hits in tmp.iteritems():
+                executeSQL(cur, "select * from packages where pkgKey=?",
+                           (pkgKey,))
+                x = cur.fetchone()
+                if self._excluded(rep,x['pkgId']):
+                    continue
+                result[self.pc(rep,x)] = hits
+
+        if prcotype != 'provides' or name[0] != '/':
+            self._search_cache[prcotype][req] = result
+            return result
+
+        matched = 0
+        globs = ['.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$']
+        for thisglob in globs:
+            globc = re.compile(thisglob)
+            if globc.match(name):
+                matched = 1
+
+        if not matched: # if its not in the primary.xml files
+            # search the files.xml file info
+            for pkg in self.searchFiles(name):
+                result[pkg] = [(name, None, None)]
+            self._search_cache[prcotype][req] = result
+            return result
+
+        # If it is a filename, search the primary.xml file info
+        for (rep,cache) in self.primarydb.items():
+            cur = cache.cursor()
+            executeSQL(cur, "select DISTINCT packages.* from files,packages where files.name = ? and files.pkgKey = packages.pkgKey", (name,))
+            for x in cur:
+                if self._excluded(rep,x['pkgId']):
+                    continue
+                result[self.pc(rep,x)] = [(name, None, None)]
+        self._search_cache[prcotype][req] = result
+        return result
+
+    def getProvides(self, name, flags=None, version=None):
+        return self._search("provides", name, flags, version)
+
+    def getRequires(self, name, flags=None, version=None):
+        return self._search("requires", name, flags, version)
+
     
     def searchPrco(self, name, prcotype):
         """return list of packages having prcotype name (any evr and flag)"""
commit 3f3fc42139ea108f51b2643deb7b587d3e248340
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 11:02:34 2007 +0200

    move PRCO compare code out of package

diff --git a/rpmUtils/miscutils.py b/rpmUtils/miscutils.py
index 25ea956..7c382be 100644
--- a/rpmUtils/miscutils.py
+++ b/rpmUtils/miscutils.py
@@ -127,10 +127,20 @@ def rangeCheck(reqtuple, pkgtuple):
        ex: foo >= 2.1-1"""
     # we only ever get here if we have a versioned prco
     # nameonly shouldn't ever raise it
-    (reqn, reqf, (reqe, reqv, reqr)) = reqtuple
+    #(reqn, reqf, (reqe, reqv, reqr)) = reqtuple
     (n, a, e, v, r) = pkgtuple
-    #simple failures
-    if reqn != n: return 0
+    return rangeCompare(reqtuple, (n, 'EQ', (e, v, r)))
+
+def rangeCompare(reqtuple, provtuple):
+    """returns true if provtuple satisfies reqtuple"""
+    (reqn, reqf, (reqe, reqv, reqr)) = reqtuple
+    (n, f, (e, v, r)) = provtuple
+    if reqn != n:
+        return 0
+
+    if f is None or reqf is None:
+        return 1
+
     # and you thought we were done having fun
     # if the requested release is left out then we have
     # to remove release from the package prco to make sure the match
@@ -142,20 +152,55 @@ def rangeCheck(reqtuple, pkgtuple):
         e = None
     if reqv is None: # just for the record if ver is None then we're going to segfault
         v = None
-        
-    rc = compareEVR((e, v, r), (reqe, reqv, reqr))
-            
+
+    # if we just require foo-version, then foo-version-* will match
+    if r is None:
+        reqr = None
+
+    rc = rpmUtils.miscutils.compareEVR((e, v, r), (reqe, reqv, reqr))
+
+    # does not match unless
     if rc >= 1:
         if reqf in ['GT', 'GE', 4, 12]:
             return 1
+        if reqf in ['EQ', 8]:
+            if f in ['LE', 10]:
+                return 1
     if rc == 0:
-        if reqf in ['GE', 'LE', 'EQ', 8, 10, 12]:
-            return 1
+        if reqf in ['GT', 4]:
+            if f in ['GT', 'GE', 4, 12]:
+                return 1
+        if reqf in ['GE', 12]:
+            if f in ['GT', 'GE', 'EQ', 'LE', 4, 12, 8, 10]:
+                return 1
+        if reqf in ['EQ', 8]:
+            if f in ['EQ', 'GE', 'LE', 8, 12, 10]:
+                return 1
+        if reqf in ['LE', 10]:
+            if f in ['EQ', 'LE', 'LT', 'GE', 8, 10, 2, 12]:
+                return 1
+        if reqf in ['LT', 2]:
+            if f in ['LE', 'LT', 10, 2]:
+                return 1
     if rc <= -1:
-        if reqf in ['LT', 'LE', 2, 10]:
+        if reqf in ['GT', 'GE', 'EQ', 4, 12, 8]:
+            if f in ['GT', 'GE', 4, 12]:
+                return 1
+        if reqf in ['LE', 'LT', 10, 2]:
             return 1
+#                if rc >= 1:
+#                    if reqf in ['GT', 'GE', 4, 12]:
+#                        return 1
+#                if rc == 0:
+#                    if reqf in ['GE', 'LE', 'EQ', 8, 10, 12]:
+#                        return 1
+#                if rc <= -1:
+#                    if reqf in ['LT', 'LE', 2, 10]:
+#                        return 1
+
     return 0
 
+
 ###########
 # Title: Remove duplicates from a sequence
 # Submitter: Tim Peters 
diff --git a/yum/packages.py b/yum/packages.py
index 1ee931c..7e33b2a 100644
--- a/yum/packages.py
+++ b/yum/packages.py
@@ -259,92 +259,44 @@ class RpmBase(object):
                         return 1
 
         return 0
-                
+
     def inPrcoRange(self, prcotype, reqtuple):
         """returns true if the package has a the prco that satisfies 
            the reqtuple range, assume false.
            Takes: prcotype, requested prco tuple"""
+        return bool(self.matchingPrcos(prcotype, reqtuple))
+
+    def matchingPrcos(self, prcotype, reqtuple):
         # we only ever get here if we have a versioned prco
         # nameonly shouldn't ever raise it
         (reqn, reqf, (reqe, reqv, reqr)) = reqtuple
         # however, just in case
         # find the named entry in pkgobj, do the comparsion
+        result = []
         for (n, f, (e, v, r)) in self.returnPrco(prcotype):
-            if reqn == n:
-                # found it
-                if f is None:
-                    return 1
-                if f != 'EQ' and prcotype == 'provides':                
-                    # isn't this odd, it's not 'EQ' and it is a provides
-                    # - it really should be EQ
-                    # use the pkgobj's evr for the comparison
-                    if e is None:
-                        e = self.epoch
-                    if v is None:
-                        v = self.ver
-                    if r is None:
-                        r = self.rel
-                    
-                    #(e, v, r) = (self.epoch, self.ver, self.rel)
-                # and you thought we were done having fun
-                # if the requested release is left out then we have
-                # to remove release from the package prco to make sure the match
-                # is a success - ie: if the request is EQ foo 1:3.0.0 and we have 
-                # foo 1:3.0.0-15 then we have to drop the 15 so we can match
-                if reqr is None:
-                    r = None
-                if reqe is None:
-                    e = None
-                if reqv is None: # just for the record if ver is None then we're going to segfault
-                    v = None
-
-                # if we just require foo-version, then foo-version-* will match
+            if reqn != n:
+                continue
+
+            if f != 'EQ' and prcotype == 'provides':
+                # isn't this odd, it's not 'EQ' and it is a provides
+                # - it really should be EQ
+                # use the pkgobj's evr for the comparison
+                if e is None:
+                    e = self.epoch
+                if v is None:
+                    v = self.ver
                 if r is None:
-                    reqr = None
+                    r = self.rel
+                #(e, v, r) = (self.epoch, self.ver, self.rel)
+
+            matched = rpmUtils.miscutils.rangeCompare(
+                reqtuple, (n, f, (e, v, r)))
+            if matched:
+                result.append((n, f, (e, v, r)))
+
+        return result
+
 
-                rc = rpmUtils.miscutils.compareEVR((e, v, r), (reqe, reqv, reqr))
-                
-                # does not match unless
-                if rc >= 1:
-                    if reqf in ['GT', 'GE', 4, 12]:
-                        return 1
-                    if reqf in ['EQ', 8]:
-                        if f in ['LE', 10]:
-                            return 1
-                if rc == 0:
-                    if reqf in ['GT', 4]:
-                        if f in ['GT', 'GE', 4, 12]:
-                            return 1
-                    if reqf in ['GE', 12]:
-                        if f in ['GT', 'GE', 'EQ', 'LE', 4, 12, 8, 10]:
-                            return 1
-                    if reqf in ['EQ', 8]:
-                        if f in ['EQ', 'GE', 'LE', 8, 12, 10]:
-                            return 1
-                    if reqf in ['LE', 10]:
-                        if f in ['EQ', 'LE', 'LT', 'GE', 8, 10, 2, 12]:
-                            return 1
-                    if reqf in ['LT', 2]:
-                        if f in ['LE', 'LT', 10, 2]:
-                            return 1
-                if rc <= -1:
-                    if reqf in ['GT', 'GE', 'EQ', 4, 12, 8]:
-                        if f in ['GT', 'GE', 4, 12]:
-                            return 1
-                    if reqf in ['LE', 'LT', 10, 2]:
-                        return 1
-                
-                
-#                if rc >= 1:
-#                    if reqf in ['GT', 'GE', 4, 12]:
-#                        return 1
-#                if rc == 0:
-#                    if reqf in ['GE', 'LE', 'EQ', 8, 10, 12]:
-#                        return 1
-#                if rc <= -1:
-#                    if reqf in ['LT', 'LE', 2, 10]:
-#                        return 1
-        return 0
         
     def returnChangelog(self):
         """return changelog entries"""
commit f735b9286676e57b8e942d9e3346069d0c21ac7e
Author: Florian Festi <ffesti at redhat.com>
Date:   Fri Jul 13 10:56:59 2007 +0200

    Add .getRequire() .getProvides() to RpmSack

diff --git a/yum/rpmsack.py b/yum/rpmsack.py
index a3d732c..b32af4d 100644
--- a/yum/rpmsack.py
+++ b/yum/rpmsack.py
@@ -379,7 +379,7 @@ class RPMDBPackageSack(PackageSackBase):
         # Can't support this now
         raise NotImplementedError
 
-    def whatProvides(self, name, flags, version):
+    def getProvides(self, name, flags=None, version=None):
         """searches the rpmdb for what provides the arguments
            returns a list of pkgtuples of providing packages, possibly empty"""
 
@@ -398,24 +398,23 @@ class RPMDBPackageSack(PackageSackBase):
         elif type(version) is types.NoneType:
             r_e = r_v = r_r = None
         
-        defSack = ListPackageSack() # holder for items definitely providing this dep
+        result = { }
         
         for po in pkgs:
             if name[0] == '/' and r_v is None:
-                # file dep add all matches to the defSack
-                defSack.addPackage(po)
+                result[po] = [(name, None, (None, None, None))]
                 continue
+            hits = po.matchingPrcos(
+                'provides', (name, flags, (r_e, r_v, r_r)))
+            if hits:
+                result[po] = hits
+        return result
 
-            if po.checkPrco('provides', (name, flags, (r_e, r_v, r_r))):
-                defSack.addPackage(po)
-
-        returnlist = []
-        for pkg in defSack.returnPackages():
-            returnlist.append(pkg.pkgtup)
-        
-        return returnlist
+    def whatProvides(self, name, flags, version):
+        # XXX deprecate?
+        return [po.pkgtup for po in self.getProvides(name, flags, version)]
 
-    def whatRequires(self, name, flags, version):
+    def getRequires(self, name, flags=None, version=None):
         """searches the rpmdb for what provides the arguments
            returns a list of pkgtuples of providing packages, possibly empty"""
 
@@ -429,23 +428,23 @@ class RPMDBPackageSack(PackageSackBase):
             (r_e, r_v, r_r) = version
         elif type(version) is types.NoneType:
             r_e = r_v = r_r = None
-        
-        defSack = ListPackageSack() # holder for items definitely providing this dep
-        
+
+        result = { }
+
         for po in pkgs:
             if name[0] == '/' and r_v is None:
                 # file dep add all matches to the defSack
-                defSack.addPackage(po)
+                result[po] = [(name, None, (None, None, None))]
                 continue
+            hits = po.matchingPrcos(
+                'requires', (name, flags, (r_e, r_v, r_r)))
+            if hits:
+                result[po] = hits
+        return result
 
-            if po.checkPrco('requires', (name, flags, (r_e, r_v, r_r))):
-                defSack.addPackage(po)
-
-        returnlist = []
-        for pkg in defSack.returnPackages():
-            returnlist.append(pkg.pkgtup)
-        
-        return returnlist    
+    def whatRequires(self, name, flags, version):
+        # XXX deprecate?
+        return [po.pkgtup for po in self.getProvides(name, flags, version)]
             
 def main():
     sack = RPMDBPackageSack('/')



More information about the Yum-cvs-commits mailing list