[yum-commits] 2 commits - test/revdepupdatetests.py yum/__init__.py

James Antill james at osuosl.org
Mon May 21 20:18:17 UTC 2012


 test/revdepupdatetests.py |   70 ++++++++++++++++++++++++++++++++++++++++++++++
 yum/__init__.py           |   30 +++++++++++--------
 2 files changed, 87 insertions(+), 13 deletions(-)

New commits:
commit e11fe7141b69648d0e80e0719118a8f02fc8b773
Author: Casey Jao <cjao at ugcs.caltech.edu>
Date:   Fri May 18 22:33:59 2012 -0700

    Add tests for revdep handling in yum update.
    
    This test models the scenario in Bug 773440
    regarding clean_requirements_on_remove
    (https://bugzilla.redhat.com/show_bug.cgi?id=773440), which
    exposes an error in the current implementation of _has_needed_revdeps.
    
    The basic setup is this. For packages A and B, we write A -> B to mean
    "B requires A". Packages are dep-installed if they begin with "D" and
    user-installed if they begin with "P".
    
    Suppose we have installed {D1, D2, D3, P1} with the relations
    D1 -> D2 -> P1 <- D3 and  D3 -> D2. That is, D3 is needed by
    both D2 and P1. Suppose we want to update P1 with P1.1 such that
    P1.1 no longer needs D3 but still needs D2.
    
    The current remove_old_deps+_has_needed_revdeps combo will incorrectly
    try to remove D3 if it hits D3 first when looping through the
    deps of P1. This occurs because _has_needed_revdeps does not detect
    whether a reverse dependency of D3 is needed by an incoming package;
    in this case P1.1 needs D2, which is broken by removing D3.
    
    The patched _has_needed_revdeps checks whether each reverse-dep
    is needed by an incoming package. In the above case,
    the patched method sees that D2 is needed by P1.1 and marks D2
    off-limits for removal. Hence it keeps D3 as well.

diff --git a/test/revdepupdatetests.py b/test/revdepupdatetests.py
new file mode 100644
index 0000000..a98341d
--- /dev/null
+++ b/test/revdepupdatetests.py
@@ -0,0 +1,70 @@
+from testbase import *
+
+class RevdepUpdateTests(OperationsTests):
+
+    @staticmethod
+    def buildPkgs(pkgs, *args):
+        """ This test checks that remove_old_deps handles reverse 
+        dependencies properly during yum update. Specifically, 
+        remove_old_deps should remove precisely the packages which are not 
+        required by any package currently installed or pending 
+        installation. Two cases:
+        
+        For packages A, B, we write A -> B if B requires A. Packages 
+        with a dep prefix are dep-installed.
+
+        1) Installed: dep1 -> dep2 -> pkg1 <- dep3 and dep3 -> dep2
+           Update: pkg1, which requires dep2 but no longer requires dep3.
+           Correct outcome: dep1, dep2, dep3, pkg1, since dep2 still 
+           needs dep3.
+
+        2) Installed: dep1 -> dep2 -> pkg1 <- dep3 and dep3 -> dep2
+           Update: pkg1, which now requires only dep1
+           Correct outcome: dep1, pkg1, since dep2 and dep3 are 
+           no longer needed.
+           
+        """
+
+        
+        pkgs.installed_1 = FakePackage('dep1', '1', '0', '0', 'noarch')
+        pkgs.installed_1.yumdb_info.reason = 'dep'
+        
+        pkgs.installed_2 = FakePackage('dep2', '1', '0', '0', 'noarch')
+        pkgs.installed_2.yumdb_info.reason = 'dep'
+        
+        pkgs.installed_3 = FakePackage('pkg1', '1', '0', '0', 'noarch')
+        pkgs.installed_3.yumdb_info.reason = 'user'
+
+        pkgs.installed_4 = FakePackage('dep3', '1', '0', '0', 'noarch')
+        pkgs.installed_4.yumdb_info.reason = 'dep'
+        
+        pkgs.installed_1.addRequiringPkg(pkgs.installed_2)
+        pkgs.installed_2.addRequiringPkg(pkgs.installed_3)
+        pkgs.installed_4.addRequiringPkg(pkgs.installed_2)
+
+        pkgs.installed_2.addRequiresPkg(pkgs.installed_1)
+        pkgs.installed_2.addRequiresPkg(pkgs.installed_4)
+        pkgs.installed_3.addRequiresPkg(pkgs.installed_4)
+        pkgs.installed_3.addRequiresPkg(pkgs.installed_2)
+
+        pkgs.update_2 = FakePackage('dep2', '2', '0', '0', 'noarch')
+        pkgs.update_2.addRequires('dep1', 'EQ', ('0', '1', '0'))
+
+        pkgs.update_3 = FakePackage('pkg1', '2', '0', '0', 'noarch')
+        pkgs.update_3.addRequires('dep2', 'EQ', ('0', '1', '0'))
+
+        pkgs.update_4 = FakePackage('pkg1', '2', '0', '0', 'noarch')
+        pkgs.update_4.addRequires('dep1', 'EQ', ('0', '1', '0'))
+
+    def testUpdate(self):
+        p = self.pkgs
+        res, msg = self.runOperation(['update'], [p.installed_1, p.installed_2, p.installed_3, p.installed_4], [p.update_3])
+        self.assert_(res=='ok', msg)
+        self.assertResult( (p.installed_1, p.installed_2, p.update_3, p.installed_4) )
+    
+    def testUpdate2(self):
+        p = self.pkgs
+        res, msg = self.runOperation(['update'], [p.installed_1, p.installed_2, p.installed_3, p.installed_4], [p.update_4])
+        self.assert_(res=='ok', msg)
+        self.assertResult( (p.installed_1, p.update_4) )
+
commit 737cf55c05fc7d828ce49163819b30d183e3559c
Author: Casey Jao <cjao at ugcs.caltech.edu>
Date:   Fri May 18 22:33:21 2012 -0700

    Move some dependency checks to _has_needed_revdeps.
    
    This patch is intended to address Bug 773440 regarding
    clean_requirements_on_remove
    (https://bugzilla.redhat.com/show_bug.cgi?id=773440).
    
    Currently we only consider a reverse dependency of a pkg "needed"
    if it was user-installed. The patch checks if the revdep is needed
    by a pkg to be installed in the transaction. The corresponding
    check in _remove_old_deps is now redundant since _has_needed_revdeps
    considers a pkg as a revdep of itself.

diff --git a/yum/__init__.py b/yum/__init__.py
index 5be32e9..1e4acd5 100644
--- a/yum/__init__.py
+++ b/yum/__init__.py
@@ -6298,18 +6298,6 @@ class YumBase(depsolve.Depsolve):
                     if requiring == required: # if they are self-requiring skip them
                         continue
                         
-                # go through the stuff in the ts to be installed - make sure none of that needs the required pkg, either.
-                for (provn,provf,provevr) in required.provides:
-                    if self.tsInfo.getNewRequires(provn, provf, provevr).keys():
-                        still_needed = True
-                        okay_to_remove[required] = False
-                        break
-                for fn in required.filelist + required.dirlist:
-                    if self.tsInfo.getNewRequires(fn, None,(None,None,None)).keys():
-                        okay_to_remove[required] = False
-                        still_needed = True
-                        break
-                            
                     #for tbi_pkg in self.tsInfo.getMembersWithState(output_states=TS_INSTALL_STATES):
                     #   for reqtuple in tbi_pkg.po.requires:
                     #        if required.provides_for(reqtuple):
@@ -6361,7 +6349,24 @@ class YumBase(depsolve.Depsolve):
                     # Debugging output
                     self.verbose_logger.log(logginglevels.DEBUG_2, _("%s has revdep %s which was user-installed."), pkg, curpkg)
                     ok_to_remove[pkg] = False
+                    ok_to_remove[curpkg] = False
                     return True
+
+                #  Go through the stuff in the ts to be installed - make sure
+                # none of that needs the required pkg, either.
+                for (provn,provf,provevr) in curpkg.provides:
+                    if self.tsInfo.getNewRequires(provn, provf, provevr).keys():
+                        ok_to_remove[pkg] = False
+                        ok_to_remove[curpkg] = False
+                        self.verbose_logger.log(logginglevels.DEBUG_2, _("%s is needed by a package to be installed."), curpkg)
+                        return True
+                for fn in curpkg.filelist + curpkg.dirlist:
+                    if self.tsInfo.getNewRequires(fn, None,(None,None,None)).keys():
+                        ok_to_remove[pkg] = False
+                        ok_to_remove[curpkg] = False
+                        self.verbose_logger.log(logginglevels.DEBUG_2, _("%s is needed by a package to be installed."), curpkg)
+                        return True
+
                 visited[curpkg] = True
             all_leaves_visited = True
             leaves = curpkg.requiring_packages()
@@ -6375,4 +6380,3 @@ class YumBase(depsolve.Depsolve):
         # Debugging output
         self.verbose_logger.log(logginglevels.DEBUG_2, _("%s has no user-installed revdeps."), pkg)
         return False
-


More information about the Yum-commits mailing list