[yum-cvs] test/testbase.py yum/config.py yum/depsolve.py yum/__init__.py
Tim Lauridsen
timlau at linux.duke.edu
Tue Dec 11 07:10:10 UTC 2007
test/testbase.py | 1 +
yum/__init__.py | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
yum/config.py | 1 +
yum/depsolve.py | 29 +++++++++++++++++++++++++----
4 files changed, 82 insertions(+), 4 deletions(-)
New commits:
commit 30476c7da4aa2c0795855d2f4364395661fd7c70
Author: Tim Lauridsen <tim at naboo.local>
Date: Tue Dec 11 08:07:57 2007 +0100
Added skip-broken code
diff --git a/test/testbase.py b/test/testbase.py
index bdb3e81..5b9d261 100644
--- a/test/testbase.py
+++ b/test/testbase.py
@@ -31,6 +31,7 @@ class FakeConf(object):
self.installroot = '/'
self.tsflags = []
self.installonly_limit = 0
+ self.skip_broken = False
self.disable_excludes = []
class FakeRepo(object):
diff --git a/yum/__init__.py b/yum/__init__.py
index a003489..821e298 100644
--- a/yum/__init__.py
+++ b/yum/__init__.py
@@ -580,9 +580,64 @@ class YumBase(depsolve.Depsolve):
if self.tsInfo.changed:
(rescode, restring) = self.resolveDeps()
+
+ # if depsolve failed and skipbroken is enabled
+ # The remove the broken packages from the transactions and
+ # Try another depsolve
+ if self.conf.skip_broken and rescode==1:
+ rescode, restring = self._skipPackagesWithProblems(rescode, restring)
return rescode, restring
+ def _skipPackagesWithProblems(self, rescode, restring):
+ ''' Remove the packages with depsolve errors and depsolve again '''
+ # Keep removing packages & Depsolve until all errors is gone
+ # or the transaction is empty
+ depTree = self._buildDepTree()
+ while len(self.po_with_problems) > 0 and rescode == 1:
+ startTs = set(self.tsInfo)
+ toRemove = []
+ for po,wpo in self.po_with_problems:
+ # check if the problem is caused by a package in the transaction
+ if not self.tsInfo.exists(po.pkgtup):
+ if wpo:
+ toRemove = self._getPackagesToRemove(wpo, depTree, toRemove)
+ else:
+ continue
+ else:
+ toRemove = self._getPackagesToRemove(po, depTree, toRemove)
+ if toRemove:
+ for po in toRemove:
+ if self.tsInfo.exists(po.pkgtup):
+ self.verbose_logger.debug("skipping %s because of depsolving problems" % str(po))
+ self.tsInfo.remove(po.pkgtup)
+ else: # Nothing was removed, so we still got a problem
+ break # Bail out
+ rescode, restring = self.resolveDeps()
+ endTs = set(self.tsInfo)
+ # Check if tsInfo has changes since we started to skip packages
+ # if there is no changes then we got a loop.
+ if startTs-endTs == set():
+ break # bail out
+ return rescode, restring
+
+ def _buildDepTree(self):
+ depTree = {}
+ for txmbr in self.tsInfo:
+ if not txmbr.po in depTree.keys():
+ depTree[txmbr.po] = []
+ for po in (txmbr.updates + txmbr.obsoletes+txmbr.depends_on):
+ depTree[txmbr.po].append(po)
+ return depTree
+
+ def _getPackagesToRemove(self,po,deptree,toRemove):
+ if po not in toRemove:
+ toRemove.append(po)
+ for child in deptree[po]:
+ if child not in toRemove:
+ toRemove = self._getPackagesToRemove(child, deptree, toRemove)
+ return toRemove
+
def runTransaction(self, cb):
"""takes an rpm callback object, performs the transaction"""
diff --git a/yum/config.py b/yum/config.py
index 0162336..7834211 100644
--- a/yum/config.py
+++ b/yum/config.py
@@ -600,6 +600,7 @@ class YumConf(StartupConf):
mirrorlist_expire = SecondsOption(86400) # time in seconds (1 day)
rpm_check_debug = BoolOption(True)
disable_excludes = ListOption()
+ skip_broken = BoolOption(False)
_reposlist = []
diff --git a/yum/depsolve.py b/yum/depsolve.py
index 25f5f76..18ddae4 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
@@ -258,6 +258,11 @@ class Depsolve(object):
CheckDeps, missingdep = self._requiringFromTransaction(po, requirement, errormsgs)
else:
CheckDeps, missingdep = self._requiringFromInstalled(po, requirement, errormsgs)
+
+ # Check packages with problems
+ if missingdep:
+ self.po_with_problems.add((po,self._working_po))
+
return (CheckDeps, missingdep, errormsgs)
def _requiringFromInstalled(self, requiringPo, requirement, errorlist):
@@ -560,13 +565,13 @@ class Depsolve(object):
name))
# FIXME: we should probably handle updating multiple packages...
txmbr = self.tsInfo.addUpdate(best, inst[0])
- txmbr.setAsDep()
+ txmbr.setAsDep(po=requiringPo)
txmbr.reason = "dep"
else:
self.verbose_logger.debug('TSINFO: Marking %s as install for %s', best,
name)
txmbr = self.tsInfo.addInstall(best)
- txmbr.setAsDep()
+ txmbr.setAsDep(po=requiringPo)
# if we had other packages with this name.arch that we found
# before, they're not going to be installed anymore, so we
@@ -589,6 +594,7 @@ class Depsolve(object):
needname, flags, needversion = conflict
(name, arch, epoch, ver, rel) = po.pkgtup
+ requiringPo = po
niceformatneed = rpmUtils.miscutils.formatRequire(needname, needversion, flags)
if self.dsCallback: self.dsCallback.procConflict(name, niceformatneed)
@@ -640,7 +646,7 @@ class Depsolve(object):
self.verbose_logger.log(logginglevels.DEBUG_2,
'TSINFO: Updating %s to resolve conflict.', po)
txmbr = self.tsInfo.addUpdate(po, confpkg)
- txmbr.setAsDep()
+ txmbr.setAsDep(po=requiringPo)
txmbr.reason = "dep"
CheckDeps = 1
@@ -649,7 +655,9 @@ class Depsolve(object):
CheckDeps, conflicts = self._unresolveableConflict(conf, name, errormsgs)
self.verbose_logger.log(logginglevels.DEBUG_1, '%s conflicts: %s',
name, conf)
-
+ if conflicts:
+ self.po_with_problems.add((requiringPo,None))
+
return (CheckDeps, conflicts, errormsgs)
def _unresolveableConflict(self, conf, name, errors):
@@ -703,6 +711,8 @@ class Depsolve(object):
# reset what we've seen as things may have changed between calls
# to resolveDeps (rh#242368, rh#308321)
self._dcobj.reset()
+ self.po_with_problems = set()
+ self._working_po = None
CheckDeps = True
CheckRemoves = False
@@ -770,6 +780,8 @@ class Depsolve(object):
self.tsInfo.changed = False
if len(errors) > 0:
errors = unique(errors)
+ for po,wpo in self.po_with_problems:
+ self.verbose_logger.debug("%s has depsolving problems" % po)
return (1, errors)
if len(self.tsInfo) > 0:
@@ -794,6 +806,15 @@ class Depsolve(object):
self.verbose_logger.log(logginglevels.DEBUG_2,
"Checking deps for %s" %(txmbr,))
+ # store the primary po we currently are working on
+ # so we can store it in self.po_with_problems.
+ # it is useful when an update is breaking an require of an installed package
+ # then we want to know who is causing the problem, not just who is having the problem.
+ if not txmbr.updates and txmbr.relatedto:
+ self._working_po = txmbr.relatedto[0][0]
+ else:
+ self._working_po = txmbr.po
+
if txmbr.output_state in inst:
thisneeds = self._checkInstall(txmbr)
CheckInstalls = True
More information about the Yum-cvs-commits
mailing list