[yum-commits] 9 commits - cli.py docs/yum.8 test/check-po-yes-no.py test/simpleobsoletestests.py test/testbase.py yumcommands.py yum/depsolve.py yum/__init__.py yum/rpmsack.py
James Antill
james at osuosl.org
Thu Apr 4 15:21:32 UTC 2013
cli.py | 6 +-
docs/yum.8 | 22 +++++++++
test/check-po-yes-no.py | 7 ++-
test/simpleobsoletestests.py | 69 +++++++++++++++++++++++++++++--
test/testbase.py | 8 +++
yum/__init__.py | 4 +
yum/depsolve.py | 95 +++++++++++++++++++++++++++++--------------
yum/rpmsack.py | 82 ++++++++++++++++++++++++++++++++++---
yumcommands.py | 28 ++++++++++++
9 files changed, 278 insertions(+), 43 deletions(-)
New commits:
commit d63cafbe190efd7f6a632afdcc2cfd951388500c
Author: James Antill <james at and.org>
Date: Thu Apr 4 11:20:39 2013 -0400
Add repo-pkgs upgrade-to, add file req obs. tests that do nothing.
diff --git a/docs/yum.8 b/docs/yum.8
index 00f191e..a3f409a 100644
--- a/docs/yum.8
+++ b/docs/yum.8
@@ -387,9 +387,16 @@ only shows packages from the givien repository.
"repository\-packages <repo> install" - Install all of the packages in the
repository, basicallly the same as: yum install $(repoquery --repoid=<repo> -a).
+Specific packages/wildcards can be specified.
"repository\-packages <repo> upgrade" - Update all of the packages in the
repository, basicallly the same as: yum upgrade $(repoquery --repoid=<repo> -a).
+Specific packages/wildcards can be specified.
+
+"repository\-packages <repo> upgrade-to" - Update all of the packages in the
+repository, basicallly the same as: yum upgrade $(repoquery --repoid=<repo> -a).
+Without arguments it works the same as upgrade, with arguments it just
+interprets them as the versions you want to move to.
"repository\-packages <repo> reinstall-old" - ReInstall all of the packages
that are installed from the repository and available in the
diff --git a/test/simpleobsoletestests.py b/test/simpleobsoletestests.py
index 5f0cdfb..6cede1e 100644
--- a/test/simpleobsoletestests.py
+++ b/test/simpleobsoletestests.py
@@ -704,6 +704,69 @@ class SimpleObsoletesTests(OperationsTests):
# Just d2 is fine too, although less likely what the user wants
self.assertResult((c2,d2))
+ def testRLFileReqTransObs1(self):
+ fr1 = FakePackage('fr1', '1', '1')
+ fr1.addRequires('/foo')
+ fr2 = FakePackage('fr2', '2', '2')
+
+ fp1 = FakePackage('fp1', '1', '2')
+ fp1.addFile('/foo')
+ fp2 = FakePackage('fpl2', '1', '2')
+ fp2.addFile('/foo')
+
+ ob1 = FakePackage('ob1', '1', '3')
+ ob1.addObsoletes('fp1', None, (None, None, None))
+
+ res, msg = self.runOperation(['install', 'ob1', 'fr1'], [],
+ [fr1, fr2, fp1, fp2, ob1])
+
+ self.assert_(res=='err', msg)
+ # Should really be:
+ # self.assertResult([ob1, fr1, fp2])
+
+ def testRLFileReqTransObs2(self):
+ fr1 = FakePackage('fr1', '1', '1')
+ fr1.addRequires('/foo')
+ fr2 = FakePackage('fr2', '2', '2')
+ fr2.addRequires('/bar')
+
+ fp1 = FakePackage('fp1', '1', '2')
+ fp1.addFile('/foo')
+ fp2 = FakePackage('fpl2', '1', '2')
+ fp2.addFile('/foo')
+
+ ob1 = FakePackage('ob1', '1', '3')
+ ob1.addObsoletes('fp1', None, (None, None, None))
+ ob1.addFile('/bar')
+
+ res, msg = self.runOperation(['install', 'fr1', 'fr2'], [],
+ [fr1, fr2, fp1, fp2, ob1])
+
+ self.assert_(res=='err', msg)
+ # Should really be:
+ # self.assertResult([ob1, fr1, fp2])
+
+ def testRLFileReqInstObs(self):
+ fr1 = FakePackage('fr1', '1', '1')
+ fr1.addRequires('/foo')
+ fr2 = FakePackage('fr2', '2', '2')
+
+ fp1 = FakePackage('fp1', '1', '2')
+ fp1.addFile('/foo')
+ fp2 = FakePackage('fpl2', '1', '2')
+ fp2.addFile('/foo')
+
+ ob1 = FakePackage('ob1', '1', '3')
+ ob1.addObsoletes('fp1', None, (None, None, None))
+
+ res, msg = self.runOperation(['install', 'fr1'], [ob1],
+ [fr1, fr2, fp1, fp2, ob1])
+ print "JDBG:", "test:", res, msg
+
+ self.assert_(res=='err', msg)
+ # Should really be:
+ # self.assertResult([ob1, fr1, fp2])
+
class GitMetapackageObsoletesTests(OperationsTests):
diff --git a/yumcommands.py b/yumcommands.py
index 2f789a7..968f231 100644
--- a/yumcommands.py
+++ b/yumcommands.py
@@ -3462,6 +3462,7 @@ class RepoPkgsCommand(YumCommand):
'erase-or-distribution-synchronization' : 'remove-or-sync',
'remove-or-distribution-synchronization' : 'remove-or-sync',
'upgrade' : 'update', # Hack, but meh.
+ 'upgrade-to' : 'update-to', # Hack, but meh.
}
cmd = remap.get(cmd, cmd)
@@ -3491,6 +3492,16 @@ class RepoPkgsCommand(YumCommand):
return 2, P_('%d package to update', '%d packages to update',
num)
+ elif cmd == 'update-to': # update is basically the same as install...
+ for arg in args:
+ txmbrs = base.update(pattern=arg, update_to=True, repoid=repoid)
+ _add_repopkg2txmbrs(txmbrs, repoid)
+ num += len(txmbrs)
+
+ if num:
+ return 2, P_('%d package to update', '%d packages to update',
+ num)
+
elif cmd in ('reinstall-old', 'reinstall-installed'):
# We have to choose for reinstall, for "reinstall foo" do we mean:
# 1. reinstall the packages that are currently installed from "foo".
commit feddccc0d9bea838fe416e7bb744a33c9be8f903
Author: James Antill <james at and.org>
Date: Mon Apr 1 13:47:13 2013 -0400
Document autoremove, also mention config. options in remove command.
diff --git a/docs/yum.8 b/docs/yum.8
index 4012a7f..00f191e 100644
--- a/docs/yum.8
+++ b/docs/yum.8
@@ -35,6 +35,8 @@ gnome\-packagekit application\&.
.br
.I \fR * remove | erase package1 [package2] [\&.\&.\&.]
.br
+.I \fR * autoremove [package1] [\&.\&.\&.]
+.br
.I \fR * list [\&.\&.\&.]
.br
.I \fR * info [\&.\&.\&.]
@@ -172,11 +174,24 @@ the "install" command\&.(See \fBSpecifying package names\fP for more information
Note that "yum" is included in the protected_packages configuration, by default.
So you can't accidentally remove yum itself.
+The remove_leaf_only configuration changes the behaviour of this command
+to only remove packages which aren't required by something else.
+
+The clean_requirements_on_remove configuration changes the behaviour of this
+command to also remove packages that are only dependencies of this package.
+
Because remove does a lot of work to make it as easy as possible to use, there
are also a few specific remove commands "\fBremove-n\fP", "\fBremove-na\fP"
and "\fBremove-nevra\fP". These only work on package names, and do not process
wildcards etc.
.IP
+.IP "\fBautoremove\fP"
+.IP
+With one or more arguments this command works like running the "\fBremove\fP"
+command with the clean_requirements_on_remove turned on. However you can also
+specify no arguments, at which point it tries to remove any packages that
+weren't installed explicitly by the user and which aren't required by
+anything (so called leaf packages).
.IP "\fBlist\fP"
Is used to list various information about available
packages; more complete details are available in the \fIList Options\fP
commit fa6970d80197fd583808b892c6d4eb94d4862a95
Author: James Antill <james at and.org>
Date: Thu Mar 28 16:04:11 2013 -0400
Fix check-po-yes-no for distro. building.
diff --git a/test/check-po-yes-no.py b/test/check-po-yes-no.py
index b9cb8aa..b8f3406 100755
--- a/test/check-po-yes-no.py
+++ b/test/check-po-yes-no.py
@@ -6,7 +6,12 @@
import sys
import glob
-from yum.misc import to_utf8
+# Don't import from yum, as it isn't there when we are distro. building...
+def to_utf8(obj, errors='replace'):
+ '''convert 'unicode' to an encoded utf-8 byte string '''
+ if isinstance(obj, unicode):
+ obj = obj.encode('utf-8', errors)
+ return obj
def trans(msg, default):
if msg == 'msgstr ""\n':
commit 5be5462585e0f56f80108f87735ff5fc9ca24680
Author: James Antill <james at and.org>
Date: Thu Mar 28 15:25:59 2013 -0400
Don't auto. add the opt. pkgs. to the igroup. BZ 923547.
diff --git a/yum/__init__.py b/yum/__init__.py
index e067dd3..a5e21fb 100644
--- a/yum/__init__.py
+++ b/yum/__init__.py
@@ -3666,7 +3666,9 @@ much more problems).
else:
self.igroups.add_group(thisgroup.groupid,
thisgroup.packages, ievgrp)
- pkgs.extend(list(igroup_data.keys()))
+ for pkg in igroup_data:
+ if igroup_data[pkg] == 'installed':
+ pkgs.append(pkg)
old_txmbrs = len(txmbrs_used)
for pkg in pkgs:
commit c60df0384bd35cd8acb2c55870fcb30ca0df6ce1
Author: James Antill <james at and.org>
Date: Thu Mar 28 15:04:39 2013 -0400
Add cacheRequirement() method to groups command.
diff --git a/yumcommands.py b/yumcommands.py
index 85d1fb8..2f789a7 100644
--- a/yumcommands.py
+++ b/yumcommands.py
@@ -1233,6 +1233,23 @@ class GroupsCommand(YumCommand):
return True
return False
+ def cacheRequirement(self, base, basecmd, extcmds):
+ """Return the cache requirements for the remote repos.
+
+ :param base: a :class:`yum.Yumbase` object
+ :param basecmd: the name of the command
+ :param extcmds: a list of arguments passed to *basecmd*
+ :return: Type of requirement: read-only:past, read-only:present, read-only:future, write
+ """
+ cmd, extcmds = self._grp_cmd(basecmd, extcmds)
+
+ if cmd in ('list', 'info', 'summary'):
+ return 'read-only:past'
+ if cmd.startswith('mark') or cmd.startswith('unmark'):
+ return 'read-only:past'
+ return 'write'
+
+
class MakeCacheCommand(YumCommand):
"""A class containing methods needed by the cli to execute the
makecache command.
commit b9767f4accdbae50b01f01806ad3ce0d01c31f7b
Author: James Antill <james at and.org>
Date: Tue Mar 26 18:10:34 2013 -0400
Create _checkObsoletes in depsolver, and use returnObsoletePackages() in it.
Moves the old check transaction obsoletes code here too.
Fixes the (now pretty old) installed obsoletes testcases, and thus.
make check works again and can be turned on. BZ 907401.
diff --git a/yum/depsolve.py b/yum/depsolve.py
index 79600e6..d810a17 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
@@ -900,35 +900,10 @@ class Depsolve(object):
if checkdep:
break # The next conflict might be the same pkg
- # check Obsoletes
- # Atm. This is _just_ checking for transaction members which
- # obsolete each other. Because rpm will now auto. obs. those
- # anyway. We _don't_ check for installed pkgs. which might obs.
- # something to be installed, even though rpm will also do that.
- for txmbr in self.tsInfo.getMembersWithState(None, output_states=TS_INSTALL_STATES):
- for obs_n in txmbr.po.obsoletes_names:
- for otxmbr in self.tsInfo.matchNaevr(name=obs_n):
- if otxmbr.output_state not in TS_INSTALL_STATES:
- continue
- if otxmbr.po == txmbr.po:
- # Not sure if we should just ignore this for
- # us, or for everyone...
- continue
- if otxmbr.po.obsoletedBy([txmbr.po]):
- if txmbr.po.obsoletedBy([otxmbr.po]):
- # Have to deal with loops!
- continue
- # No callback?
- msg = _('Removing %s due to obsoletes from %s')
- self.verbose_logger.log(logginglevels.DEBUG_1,
- msg, otxmbr, txmbr)
- self.tsInfo.remove(otxmbr.pkgtup)
- # We need to remove an obsoleted entry that
- # was maybe used to resolve something ... ?
- CheckDeps = True
- self._last_req = None
- self.pkgSack.delPackage(otxmbr.po)
- self.up.delPackage(otxmbr.pkgtup)
+ if True: # Always have to check obsoletes...
+ if self._checkObsoletes():
+ CheckDeps = True
+ self._last_req = None
if CheckDeps:
if self.dsCallback: self.dsCallback.restartLoop()
@@ -1328,6 +1303,68 @@ class Depsolve(object):
self.rpmdb.transactionCacheConflictPackages(cpkgs)
return ret
+ # This is checking for installed / transaction members which
+ # obsolete each other. Because rpm will now auto. obs. those
+ # anyway (even if we have obsoletes turned off).
+ def _checkObsoletes(self):
+ opkgs = []
+
+ ret = False
+
+ def _do_obs(otxmbr):
+ self.tsInfo.remove(otxmbr.pkgtup)
+ # We need to remove an obsoleted entry that
+ # was maybe used to resolve something ... ?
+ self.pkgSack.delPackage(otxmbr.po)
+ self.up.delPackage(otxmbr.pkgtup)
+
+ for po in self.rpmdb.returnObsoletePackages():
+ if self.tsInfo.getMembersWithState(po.pkgtup, output_states=TS_REMOVE_STATES):
+ continue
+ obsoletes = po.returnPrco('obsoletes')
+ if not obsoletes: # We broke this due to dbMatch() usage.
+ continue
+ opkgs.append(po)
+ for obs_name,f,v in obsoletes:
+ for otxmbr in self.tsInfo.matchNaevr(name=obs_name):
+ if not otxmbr.po.obsoletedBy([po]):
+ continue
+ if po.obsoletedBy([otxmbr.po]): # Loops, hope for rpm.
+ continue
+ msg = _('Removing %s due to obsoletes from installed %s')
+ self.verbose_logger.log(logginglevels.DEBUG_1,
+ msg, otxmbr, po)
+ _do_obs(otxmbr)
+ ret = True
+
+ for txmbr in self.tsInfo.getMembersWithState(None, output_states=TS_INSTALL_STATES):
+ done = False
+ for obs_n in txmbr.po.obsoletes_names:
+ if not done:
+ opkgs.append(txmbr.po)
+ done = True
+
+ for otxmbr in self.tsInfo.matchNaevr(name=obs_n):
+ if otxmbr.output_state not in TS_INSTALL_STATES:
+ continue
+ if otxmbr.po == txmbr.po:
+ # Not sure if we should just ignore this for
+ # us, or for everyone...
+ continue
+ if not otxmbr.po.obsoletedBy([txmbr.po]):
+ continue
+ if txmbr.po.obsoletedBy([otxmbr.po]):
+ # Have to deal with loops! Hope rpm behaves too.
+ continue
+ msg = _('Removing %s due to obsoletes from %s')
+ self.verbose_logger.log(logginglevels.DEBUG_1,
+ msg, otxmbr, txmbr)
+ _do_obs(otxmbr)
+ ret = True
+
+ self.rpmdb.transactionCacheObsoletePackages(opkgs)
+ return ret
+
def isPackageInstalled(self, pkgname):
"""Return whether the given package in installed.
commit 1bcf1694e30f20da056308284049e9183e2e8ba5
Author: James Antill <james at and.org>
Date: Tue Mar 26 18:09:57 2013 -0400
Fix installed obs. testcases, and mock out the returnObsoletePackages() API.
diff --git a/test/simpleobsoletestests.py b/test/simpleobsoletestests.py
index e9b2c09..5f0cdfb 100644
--- a/test/simpleobsoletestests.py
+++ b/test/simpleobsoletestests.py
@@ -247,14 +247,12 @@ class SimpleObsoletesTests(OperationsTests):
def testObsoletesOffPostInst1(self):
p = self.pkgs
res, msg = self.runOperation(['install', 'zsh'], [p.obsoletes_i386], [p.installed_i386])
- self.assert_(res=='ok', msg)
- self.assertResult((p.obsoletes_i386,))
+ self.assert_(res=='empty', msg)
def testObsoletesOffPostInst2(self):
p = self.pkgs
res, msg = self.runOperation(['install', 'zsh'], [p.obsoletes_i386], [p.installed_i386], {'obsoletes' : False})
- self.assert_(res=='ok', msg)
- self.assertResult((p.obsoletes_i386,))
+ self.assert_(res=='empty', msg)
def testObsoletesOffPostAvail1(self):
p = self.pkgs
diff --git a/test/testbase.py b/test/testbase.py
index c9bbb88..13ef821 100644
--- a/test/testbase.py
+++ b/test/testbase.py
@@ -321,6 +321,12 @@ class FakeRpmDb(packageSack.PackageSack):
if len(pkg.conflicts):
ret.append(pkg)
return ret
+ def returnObsoletePackages(self):
+ ret = []
+ for pkg in self.returnPackages():
+ if len(pkg.obsoletes):
+ ret.append(pkg)
+ return ret
def fileRequiresData(self):
installedFileRequires = {}
installedUnresolvedFileRequires = set()
@@ -355,6 +361,8 @@ class FakeRpmDb(packageSack.PackageSack):
return
def transactionCacheConflictPackages(self, pkgs):
return
+ def transactionCacheObsoletePackages(self, pkgs):
+ return
def transactionResultVersion(self, rpmdbv):
return
def transactionReset(self):
commit 478c68cb6305d6fb2349f1607a592145d7fd5153
Author: James Antill <james at and.org>
Date: Fri Mar 1 16:32:44 2013 -0500
Create the obsoletes as conflicts cache, so we can workaround new rpm.
diff --git a/yum/rpmsack.py b/yum/rpmsack.py
index 82aa29e..c1f85e2 100644
--- a/yum/rpmsack.py
+++ b/yum/rpmsack.py
@@ -690,11 +690,56 @@ class RPMDBPackageSack(PackageSackBase):
rpmdbv = self.simpleVersion(main_only=True)[0]
self._write_conflicts_new(pkgs, rpmdbv)
+ def _uncached_returnObsoletePackages(self):
+ """ Load the packages which have obsoletes from the rpmdb, this is
+ needed because newer rpm's have obsoletes imply conflicts. """
+
+ if self._cached_obsoletes_data is None:
+ result = {}
+
+ for hdr, idx in self._get_packages('obsoletename'):
+ if not hdr[rpm.RPMTAG_OBSOLETENAME]:
+ # Pre. rpm-4.9.x the above dbMatch() does nothing.
+ continue
+
+ po = self._makePackageObject(hdr, idx)
+ result[po.pkgid] = po
+ if po._has_hdr:
+ continue # Unlikely, but, meh...
+
+ po.hdr = hdr
+ po._has_hdr = True
+ po.obsoletes
+ po._has_hdr = False
+ del po.hdr
+ self._cached_obsoletes_data = result.values()
+
+ return self._cached_obsoletes_data
+
+ def _write_obsoletes_new(self, pkgs, rpmdbv):
+ if not os.access(self._cachedir, os.W_OK):
+ return
+
+ obsoletes_fname = self._cachedir + '/obsoletes'
+ fo = _open_no_umask(obsoletes_fname + '.tmp', 'w')
+ fo.write("%s\n" % rpmdbv)
+ fo.write("%u\n" % len(pkgs))
+ for pkg in sorted(pkgs):
+ for var in pkg.pkgtup:
+ fo.write("%s\n" % var)
+ fo.close()
+ os.rename(obsoletes_fname + '.tmp', obsoletes_fname)
+
+ def _write_obsoletes(self, pkgs):
+ rpmdbv = self.simpleVersion(main_only=True)[0]
+ self._write_obsoletes_new(pkgs, rpmdbv)
+
def _deal_with_bad_rpmdbcache(self, caller):
""" This shouldn't be called, but people are hitting weird stuff so
we want to deal with it so it doesn't stay broken "forever". """
misc.unlink_f(self._cachedir + "/version")
misc.unlink_f(self._cachedir + '/conflicts')
+ misc.unlink_f(self._cachedir + '/obsoletes')
misc.unlink_f(self._cachedir + '/file-requires')
misc.unlink_f(self._cachedir + '/pkgtups-checksums')
# We have a couple of options here, we can:
@@ -711,15 +756,15 @@ class RPMDBPackageSack(PackageSackBase):
if __debug__:
raise Errors.PackageSackError, 'Rpmdb checksum is invalid: %s' % caller
- def _read_conflicts(self):
+ def _read_pkglist(self, fname):
if not self.__cache_rpmdb__:
return None
def _read_str(fo):
return fo.readline()[:-1]
- conflict_fname = self._cachedir + '/conflicts'
- fo, e = _iopen(conflict_fname)
+ full_fname = self._cachedir + '/' + fname
+ fo, e = _iopen(full_fname)
if fo is None:
return None
frpmdbv = fo.readline()
@@ -729,7 +774,7 @@ class RPMDBPackageSack(PackageSackBase):
ret = []
try:
- # Read the conflicts...
+ # Read the pkgs...
pkgtups_num = int(_read_str(fo))
while pkgtups_num > 0:
pkgtups_num -= 1
@@ -742,10 +787,13 @@ class RPMDBPackageSack(PackageSackBase):
if fo.readline() != '': # Should be EOF
return None
except ValueError:
- self._deal_with_bad_rpmdbcache("conflicts")
+ self._deal_with_bad_rpmdbcache(fname)
return None
- self._cached_conflicts_data = ret
+ return ret
+
+ def _read_conflicts(self):
+ self._cached_conflicts_data = self._read_pkglist("conflicts")
return self._cached_conflicts_data
def transactionCacheConflictPackages(self, pkgs):
@@ -762,6 +810,24 @@ class RPMDBPackageSack(PackageSackBase):
return pkgs
+ def transactionCacheObsoletePackages(self, pkgs):
+ if self.__cache_rpmdb__:
+ self._trans_cache_store['obsoletes'] = pkgs
+
+ def _read_obsoletes(self):
+ self._cached_obsoletes_data = self._read_pkglist("obsoletes")
+ return self._cached_obsoletes_data
+
+ def returnObsoletePackages(self):
+ """ Return a list of packages that have obsoletes. """
+ pkgs = self._read_obsoletes()
+ if pkgs is None:
+ pkgs = self._uncached_returnObsoletePackages()
+ if self.__cache_rpmdb__:
+ self._write_obsoletes(pkgs)
+
+ return pkgs
+
def transactionResultVersion(self, rpmdbv):
""" We are going to do a transaction, and the parameter will be the
rpmdb version when we finish. The idea being we can update all
@@ -775,6 +841,10 @@ class RPMDBPackageSack(PackageSackBase):
pkgs = self._trans_cache_store['conflicts']
self._write_conflicts_new(pkgs, rpmdbv)
+ if 'obsoletes' in self._trans_cache_store:
+ pkgs = self._trans_cache_store['obsoletes']
+ self._write_obsoletes_new(pkgs, rpmdbv)
+
if 'file-requires' in self._trans_cache_store:
data = self._trans_cache_store['file-requires']
self._write_file_requires(rpmdbv, data)
commit d47caf8ac795ee17fe663b8cfad569ccaf0c93b3
Author: James Antill <james at and.org>
Date: Tue Mar 19 11:50:36 2013 -0400
Ignore case for deplist command.
diff --git a/cli.py b/cli.py
index 0d6a83c..8ea5d1f 100755
--- a/cli.py
+++ b/cli.py
@@ -1445,10 +1445,12 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
thispkg = yum.packages.YumUrlPackage(self, self.ts, arg)
pkgs.append(thispkg)
elif self.conf.showdupesfromrepos:
- pkgs.extend(self.pkgSack.returnPackages(patterns=[arg]))
+ pkgs.extend(self.pkgSack.returnPackages(patterns=[arg],
+ ignore_case=True))
else:
try:
- pkgs.extend(self.pkgSack.returnNewestByName(patterns=[arg]))
+ pkgs.extend(self.pkgSack.returnNewestByName(patterns=[arg],
+ ignore_case=True))
except yum.Errors.PackageSackError:
pass
More information about the Yum-commits
mailing list