[yum] latest head include panu's callback patches
Seth Vidal
skvidal at fedoraproject.org
Mon Feb 28 20:21:35 UTC 2011
commit cee74cde026fc5d0813635871d556b2810b3cdd6
Author: Seth Vidal <skvidal at fedoraproject.org>
Date: Mon Feb 28 15:21:26 2011 -0500
latest head include panu's callback patches
yum-HEAD.patch | 739 +++++++++++++++++++++++++++++++++++++++++++++++++-------
yum.spec | 5 +-
2 files changed, 659 insertions(+), 85 deletions(-)
---
diff --git a/yum-HEAD.patch b/yum-HEAD.patch
index 8509f33..a079b82 100644
--- a/yum-HEAD.patch
+++ b/yum-HEAD.patch
@@ -1,8 +1,16 @@
diff --git a/cli.py b/cli.py
-index 640f190..6cf6753 100644
+index 640f190..a4c7c79 100644
--- a/cli.py
+++ b/cli.py
-@@ -504,30 +504,35 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -73,6 +73,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+ self.logger = logging.getLogger("yum.cli")
+ self.verbose_logger = logging.getLogger("yum.verbose.cli")
+ self.yum_cli_commands = {}
++ self.use_txmbr_in_callback = True
+ self.registerCommand(yumcommands.InstallCommand())
+ self.registerCommand(yumcommands.UpdateCommand())
+ self.registerCommand(yumcommands.InfoCommand())
+@@ -504,30 +505,35 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
if self.gpgsigcheck(downloadpkgs) != 0:
return 1
@@ -32,7 +40,7 @@ index 640f190..6cf6753 100644
+ rcd_st = time.time()
+ self.verbose_logger.log(yum.logginglevels.INFO_2,
+ _('Running Transaction Check'))
-+ msgs = self.ts.check()
++ msgs = self._run_rpm_check()
+ if msgs:
+ rpmlib_only = True
+ for msg in msgs:
@@ -59,7 +67,7 @@ index 640f190..6cf6753 100644
tt_st = time.time()
self.verbose_logger.log(yum.logginglevels.INFO_2,
-@@ -535,14 +540,10 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -535,14 +541,10 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
if not self.conf.diskspacecheck:
self.tsInfo.probFilterFlags.append(rpm.RPMPROB_FILTER_DISKSPACE)
@@ -76,7 +84,7 @@ index 640f190..6cf6753 100644
tserrors = self.ts.test(testcb)
del testcb
-@@ -555,7 +556,6 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -555,7 +557,6 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
self.errorSummary(errstring)
self.verbose_logger.log(yum.logginglevels.INFO_2,
_('Transaction Test Succeeded'))
@@ -84,7 +92,7 @@ index 640f190..6cf6753 100644
self.verbose_logger.debug('Transaction Test time: %0.3f' % (time.time() - tt_st))
-@@ -563,10 +563,6 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -563,10 +564,6 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
signal.signal(signal.SIGQUIT, signal.SIG_DFL)
ts_st = time.time()
@@ -95,6 +103,47 @@ index 640f190..6cf6753 100644
# put back our depcheck callback
self.dsCallback = dscb
+@@ -629,7 +626,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+ ", ".join(matches))
+ self.verbose_logger.log(yum.logginglevels.INFO_2, to_unicode(msg))
+
+- def _checkMaybeYouMeant(self, arg, always_output=True):
++ def _checkMaybeYouMeant(self, arg, always_output=True, rpmdb_only=False):
+ """ If the update/remove argument doesn't match with case, or due
+ to not being installed, tell the user. """
+ # always_output is a wart due to update/remove not producing the
+@@ -638,7 +635,12 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+ # skip it.
+ if not arg or arg[0] == '@':
+ return
+- matches = self.doPackageLists(patterns=[arg], ignore_case=False)
++
++ pkgnarrow='all'
++ if rpmdb_only:
++ pkgnarrow='installed'
++
++ matches = self.doPackageLists(pkgnarrow=pkgnarrow, patterns=[arg], ignore_case=False)
+ if (matches.installed or (not matches.available and
+ self.returnInstalledPackagesByDep(arg))):
+ return # Found a match so ignore
+@@ -651,7 +653,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+ return
+
+ # No package name, so do the maybeYouMeant thing here too
+- matches = self.doPackageLists(patterns=[arg], ignore_case=True)
++ matches = self.doPackageLists(pkgnarrow=pkgnarrow, patterns=[arg], ignore_case=True)
+ if not matches.installed and matches.available:
+ self.verbose_logger.log(yum.logginglevels.INFO_2,
+ _('Package(s) %s%s%s available, but not installed.'),
+@@ -822,7 +824,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+ for arg in userlist:
+ rms = self.remove(pattern=arg)
+ if not rms:
+- self._checkMaybeYouMeant(arg, always_output=False)
++ self._checkMaybeYouMeant(arg, always_output=False, rpmdb_only=True)
+ all_rms.extend(rms)
+
+ if all_rms:
diff --git a/docs/yum.8 b/docs/yum.8
index 52f6b53..3b414e2 100644
--- a/docs/yum.8
@@ -308,25 +357,17 @@ index b1d92e5..08fe0e3 100755
limit = 20
diff --git a/rpmUtils/transaction.py b/rpmUtils/transaction.py
-index e8f4459..c5167d3 100644
+index e8f4459..121ad5b 100644
--- a/rpmUtils/transaction.py
+++ b/rpmUtils/transaction.py
-@@ -13,6 +13,7 @@
-
- import rpm
- import miscutils
-+from yum.i18n import to_str
-
- read_ts = None
- ts = None
-@@ -22,18 +23,12 @@ ts = None
+@@ -22,18 +22,13 @@ ts = None
class TransactionWrapper:
def __init__(self, root='/'):
self.ts = rpm.TransactionSet(root)
- self._methods = ['dbMatch',
- 'check',
-- 'order',
-+ self._methods = ['order',
++ self._methods = ['check',
+ 'order',
'addErase',
'addInstall',
'run',
@@ -339,21 +380,10 @@ index e8f4459..c5167d3 100644
'problems',
'setFlags',
'setVSFlags',
-@@ -54,6 +49,28 @@ class TransactionWrapper:
+@@ -54,6 +49,17 @@ class TransactionWrapper:
self.ts = None
self.open = False
-+ def check(self):
-+ results = []
-+ self.ts.check()
-+ for prob in self.ts.problems():
-+ # Newer rpm (4.8.0+) has problem objects, older have just strings.
-+ # Should probably move to using the new objects, when we can. For
-+ # now just be compatible.
-+ results.append(to_str(prob))
-+
-+ return results
-+
+ def dbMatch(self, *args, **kwds):
+ if 'patterns' in kwds:
+ patterns = kwds.pop('patterns')
@@ -368,7 +398,7 @@ index e8f4459..c5167d3 100644
def __getattr__(self, attr):
if attr in self._methods:
return self.getMethod(attr)
-@@ -91,6 +108,9 @@ class TransactionWrapper:
+@@ -91,6 +97,9 @@ class TransactionWrapper:
def isTsFlagSet(self, flag):
val = self.getTsFlags()
return bool(flag & val)
@@ -378,7 +408,7 @@ index e8f4459..c5167d3 100644
# def addProblemFilter(self, filt):
# curfilter = self.ts.setProbFilter(0)
-@@ -100,12 +120,14 @@ class TransactionWrapper:
+@@ -100,12 +109,14 @@ class TransactionWrapper:
"""tests the ts we've setup, takes a callback function and a conf dict
for flags and what not"""
@@ -422,7 +452,7 @@ index a1fbc72..65a2397 100644
%config(noreplace) %{_sysconfdir}/sysconfig/yum-cron
diff --git a/yum/__init__.py b/yum/__init__.py
-index f6e8a6b..e395cc5 100644
+index f6e8a6b..5c44245 100644
--- a/yum/__init__.py
+++ b/yum/__init__.py
@@ -349,7 +349,10 @@ class YumBase(depsolve.Depsolve):
@@ -449,7 +479,31 @@ index f6e8a6b..e395cc5 100644
thisrepo.base_persistdir = self.conf._repos_persistdir
-@@ -1435,12 +1435,17 @@ class YumBase(depsolve.Depsolve):
+@@ -574,6 +574,11 @@ class YumBase(depsolve.Depsolve):
+
+ self.getReposFromConfig()
+
++ # For rhnplugin, and in theory other stuff, calling
++ # .getReposFromConfig() recurses back into this function but only once.
++ # This means that we have two points on the stack leaving the above call
++ # but only one of them can do the repos setup. BZ 678043.
++ if hasattr(self, 'prerepoconf'):
+ # Recursion
+ prerepoconf = self.prerepoconf
+ del self.prerepoconf
+@@ -1024,6 +1029,11 @@ class YumBase(depsolve.Depsolve):
+ for txmbr in txmbrs:
+ if kern_pkgtup is not None and txmbr.pkgtup == kern_pkgtup:
+ pass
++ elif kern_pkgtup is not None and txmbr.name == kern_pkgtup[0]:
++ # We don't care if they've explicitly set protected on the
++ # kernel package. Because we don't allow you to uninstall the
++ # running one so it has _special_ semantics anyway.
++ continue
+ elif txmbr.name not in protected:
+ continue
+ if txmbr.name not in bad_togo:
+@@ -1435,12 +1445,17 @@ class YumBase(depsolve.Depsolve):
# will be we store what we thought, not what happened (so it'll be an
# invalid cache).
self.rpmdb.transactionResultVersion(frpmdbv)
@@ -472,7 +526,7 @@ index f6e8a6b..e395cc5 100644
self._ts_save_file = None
errors = self.ts.run(cb.callback, '')
-@@ -1485,7 +1490,12 @@ class YumBase(depsolve.Depsolve):
+@@ -1485,7 +1500,12 @@ class YumBase(depsolve.Depsolve):
# drop out the rpm cache so we don't step on bad hdr indexes
@@ -486,7 +540,7 @@ index f6e8a6b..e395cc5 100644
self.plugins.run('posttrans')
# sync up what just happened versus what is in the rpmdb
if not self.ts.isTsFlagSet(rpm.RPMTRANS_FLAG_TEST):
-@@ -1674,8 +1684,11 @@ class YumBase(depsolve.Depsolve):
+@@ -1674,8 +1694,11 @@ class YumBase(depsolve.Depsolve):
def doLock(self, lockfile = YUM_PID_FILE):
"""perform the yum locking, raise yum-based exceptions, not OSErrors"""
@@ -499,7 +553,7 @@ index f6e8a6b..e395cc5 100644
root = self.conf.cachedir
# Don't want <cachedir>/var/run/yum.pid ... just: <cachedir>/yum.pid
lockfile = os.path.basename(lockfile)
-@@ -1690,7 +1703,7 @@ class YumBase(depsolve.Depsolve):
+@@ -1690,7 +1713,7 @@ class YumBase(depsolve.Depsolve):
fd = open(lockfile, 'r')
except (IOError, OSError), e:
msg = _("Could not open lock %s: %s") % (lockfile, e)
@@ -508,7 +562,7 @@ index f6e8a6b..e395cc5 100644
try: oldpid = int(fd.readline())
except ValueError:
-@@ -1707,7 +1720,7 @@ class YumBase(depsolve.Depsolve):
+@@ -1707,7 +1730,7 @@ class YumBase(depsolve.Depsolve):
else:
# Whoa. What the heck happened?
msg = _('Unable to check if PID %s is active') % oldpid
@@ -517,7 +571,7 @@ index f6e8a6b..e395cc5 100644
else:
# Another copy seems to be running.
msg = _('Existing lock %s: another copy is running as pid %s.') % (lockfile, oldpid)
-@@ -1752,7 +1765,7 @@ class YumBase(depsolve.Depsolve):
+@@ -1752,7 +1775,7 @@ class YumBase(depsolve.Depsolve):
if not msg.errno == errno.EEXIST:
# Whoa. What the heck happened?
errmsg = _('Could not create lock at %s: %s ') % (filename, str(msg))
@@ -526,7 +580,76 @@ index f6e8a6b..e395cc5 100644
return 0
else:
os.write(fd, contents)
-@@ -4557,16 +4570,25 @@ class YumBase(depsolve.Depsolve):
+@@ -3417,7 +3440,6 @@ class YumBase(depsolve.Depsolve):
+ pkgs = po.obsoletedBy(pkgs, limit=1)
+ if pkgs:
+ already_obs = pkgs[0]
+- continue
+
+ if already_obs:
+ self.verbose_logger.warning(_('Package %s is obsoleted by %s which is already installed'),
+@@ -4462,17 +4484,20 @@ class YumBase(depsolve.Depsolve):
+ be imported using askcb.
+
+ @param po: Package object to retrieve the key of.
+- @param askcb: Callback function to use for asking for verification.
++ @param askcb: Callback function to use for asking for permission to
++ import a key. This is verification, but also "choice".
+ Takes arguments of the po, the userid for the key, and
+ the keyid.
+- @param fullaskcb: Callback function to use for asking for verification
+- of a key. Differs from askcb in that it gets passed
+- a dictionary so that we can expand the values passed.
++ @param fullaskcb: Callback function to use for asking for permission to
++ import a key. This is verification, but also "choice".
++ Differs from askcb in that it gets passed a
++ dictionary so that we can expand the values passed.
+ """
+ repo = self.repos.getRepo(po.repoid)
+ keyurls = repo.gpgkey
+ key_installed = False
+
++ user_cb_fail = False
+ for keyurl in keyurls:
+ keys = self._retrievePublicKey(keyurl, repo)
+
+@@ -4509,7 +4534,8 @@ class YumBase(depsolve.Depsolve):
+ rc = askcb(po, info['userid'], info['hexkeyid'])
+
+ if not rc:
+- raise Errors.YumBaseError, _("Not installing key")
++ user_cb_fail = True
++ continue
+
+ # Import the key
+ ts = self.rpmdb.readOnlyTS()
+@@ -4520,6 +4546,9 @@ class YumBase(depsolve.Depsolve):
+ self.logger.info(_('Key imported successfully'))
+ key_installed = True
+
++ if not key_installed and user_cb_fail:
++ raise Errors.YumBaseError, _("Didn't install any keys")
++
+ if not key_installed:
+ raise Errors.YumBaseError, \
+ _('The GPG keys listed for the "%s" repository are ' \
+@@ -4543,11 +4572,13 @@ class YumBase(depsolve.Depsolve):
+ @param destdir: destination of the gpg pub ring
+ @param keyurl_list: list of urls for gpg keys
+ @param is_cakey: bool - are we pulling in a ca key or not
+- @param callback: Callback function to use for asking for verification
+- of a key. Takes a dictionary of key info.
++ @param callback: Callback function to use for asking for permission to
++ import a key. This is verification, but also "choice".
++ Takes a dictionary of key info.
+ """
+
+ key_installed = False
++ user_cb_fail = False
+ for keyurl in keyurl_list:
+ keys = self._retrievePublicKey(keyurl, repo, getSig=not is_cakey)
+ for info in keys:
+@@ -4557,16 +4588,25 @@ class YumBase(depsolve.Depsolve):
keyurl, info['hexkeyid']))
key_installed = True
continue
@@ -557,11 +680,20 @@ index f6e8a6b..e395cc5 100644
self._getKeyImportMessage(info, keyurl, keytype)
rc = False
if self.conf.assumeyes:
-@@ -4587,7 +4609,18 @@ class YumBase(depsolve.Depsolve):
+@@ -4579,7 +4619,8 @@ class YumBase(depsolve.Depsolve):
+
+
+ if not rc:
+- raise Errors.YumBaseError, _("Not installing key for repo %s") % repo
++ user_cb_fail = True
++ continue
+
+ # Import the key
+ result = misc.import_key_to_pubring(info['raw_key'], info['hexkeyid'], gpgdir=destdir)
+@@ -4587,6 +4628,20 @@ class YumBase(depsolve.Depsolve):
raise Errors.YumBaseError, _('Key import failed')
self.logger.info(_('Key imported successfully'))
key_installed = True
--
+ # write out the key id to imported_cakeys in the repos basedir
+ if is_cakey and key_installed:
+ if info['hexkeyid'] not in cakeys:
@@ -573,11 +705,13 @@ index f6e8a6b..e395cc5 100644
+ except (IOError, OSError):
+ # maybe a warning - but in general this is not-critical, just annoying to the user
+ pass
-+
++
++ if not key_installed and user_cb_fail:
++ raise Errors.YumBaseError, _("Didn't install any keys for repo %s") % repo
+
if not key_installed:
raise Errors.YumBaseError, \
- _('The GPG keys listed for the "%s" repository are ' \
-@@ -4775,26 +4808,31 @@ class YumBase(depsolve.Depsolve):
+@@ -4775,26 +4830,31 @@ class YumBase(depsolve.Depsolve):
def _doTestTransaction(self,callback,display=None):
''' Do the RPM test transaction '''
@@ -609,7 +743,7 @@ index f6e8a6b..e395cc5 100644
- raise Errors.YumRPMCheckError,retmsgs
+ self.verbose_logger.log(logginglevels.INFO_2,
+ _('Running Transaction Check'))
-+ msgs = self.ts.check()
++ msgs = self._run_rpm_check()
+ if msgs:
+ rpmlib_only = True
+ for msg in msgs:
@@ -628,7 +762,7 @@ index f6e8a6b..e395cc5 100644
tsConf = {}
for feature in ['diskspacecheck']: # more to come, I'm sure
-@@ -4804,14 +4842,7 @@ class YumBase(depsolve.Depsolve):
+@@ -4804,14 +4864,7 @@ class YumBase(depsolve.Depsolve):
# overwrite the default display class
if display:
testcb.display = display
@@ -643,29 +777,28 @@ index f6e8a6b..e395cc5 100644
tserrors = self.ts.test( testcb, conf=tsConf )
del testcb
-@@ -4839,22 +4870,6 @@ class YumBase(depsolve.Depsolve):
+@@ -4839,12 +4892,8 @@ class YumBase(depsolve.Depsolve):
cb.display = display
self.runTransaction( cb=cb )
- def _run_rpm_check_debug(self):
-- results = []
++ def _run_rpm_check(self):
+ results = []
- # save our dsCallback out
- dscb = self.dsCallback
- self.dsCallback = None # dumb, dumb dumb dumb!
- self.populateTs(test=1)
-- self.ts.check()
-- for prob in self.ts.problems():
-- # Newer rpm (4.8.0+) has problem objects, older have just strings.
-- # Should probably move to using the new objects, when we can. For
-- # now just be compatible.
-- results.append(to_str(prob))
--
+ self.ts.check()
+ for prob in self.ts.problems():
+ # Newer rpm (4.8.0+) has problem objects, older have just strings.
+@@ -4852,7 +4901,6 @@ class YumBase(depsolve.Depsolve):
+ # now just be compatible.
+ results.append(to_str(prob))
+
- self.dsCallback = dscb
-- return results
--
+ return results
+
def add_enable_repo(self, repoid, baseurls=[], mirrorlist=None, **kwargs):
- """add and enable a repo with just a baseurl/mirrorlist and repoid
- requires repoid and at least one of baseurl and mirrorlist
diff --git a/yum/config.py b/yum/config.py
index 97e5e3d..9c2db93 100644
--- a/yum/config.py
@@ -679,10 +812,34 @@ index 97e5e3d..9c2db93 100644
disable_excludes = ListOption()
skip_broken = BoolOption(False)
diff --git a/yum/depsolve.py b/yum/depsolve.py
-index de2849a..3aaba0e 100644
+index de2849a..8f18ccc 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
-@@ -799,9 +799,9 @@ class Depsolve(object):
+@@ -69,6 +69,8 @@ class Depsolve(object):
+ self._ts = None
+ self._tsInfo = None
+ self.dsCallback = None
++ # Callback-style switch, default to legacy (hdr, file) mode
++ self.use_txmbr_in_callback = False
+ self.logger = logging.getLogger("yum.Depsolve")
+ self.verbose_logger = logging.getLogger("yum.verbose.Depsolve")
+
+@@ -220,8 +222,13 @@ class Depsolve(object):
+ txmbr.ts_state = 'i'
+ txmbr.output_state = TS_INSTALL
+
++ # New-style callback with just txmbr instead of full headers?
++ if self.use_txmbr_in_callback:
++ cbkey = txmbr
++ else:
++ cbkey = (hdr, rpmfile)
+
+- self.ts.addInstall(hdr, (hdr, rpmfile), txmbr.ts_state)
++ self.ts.addInstall(hdr, cbkey, txmbr.ts_state)
+ self.verbose_logger.log(logginglevels.DEBUG_1,
+ _('Adding Package %s in mode %s'), txmbr.po, txmbr.ts_state)
+ if self.dsCallback:
+@@ -799,9 +806,9 @@ class Depsolve(object):
continue
done.add((po, err))
self.verbose_logger.log(logginglevels.DEBUG_4,
@@ -694,8 +851,40 @@ index de2849a..3aaba0e 100644
return (1, errors)
if not len(self.tsInfo):
+diff --git a/yum/misc.py b/yum/misc.py
+index 15e571f..8e81c34 100644
+--- a/yum/misc.py
++++ b/yum/misc.py
+@@ -252,6 +252,9 @@ class Checksums:
+ def __len__(self):
+ return self._len
+
++ # Note that len(x) is assert limited to INT_MAX, which is 2GB on i686.
++ length = property(fget=lambda self: self._len)
++
+ def update(self, data):
+ self._len += len(data)
+ for sumalgo in self._sumalgos:
+@@ -323,7 +326,7 @@ def checksum(sumtype, file, CHUNK=2**16, datasize=None):
+
+ data = Checksums([sumtype])
+ while data.read(fo, CHUNK):
+- if datasize is not None and len(data) > datasize:
++ if datasize is not None and data.length > datasize:
+ break
+
+ if type(file) is types.StringType:
+@@ -332,7 +335,7 @@ def checksum(sumtype, file, CHUNK=2**16, datasize=None):
+
+ # This screws up the length, but that shouldn't matter. We only care
+ # if this checksum == what we expect.
+- if datasize is not None and datasize != len(data):
++ if datasize is not None and datasize != data.length:
+ return '!%u!%s' % (datasize, data.hexdigest(sumtype))
+
+ return data.hexdigest(sumtype)
diff --git a/yum/packages.py b/yum/packages.py
-index 6f61fea..15eeeaa 100644
+index 6f61fea..db3e973 100644
--- a/yum/packages.py
+++ b/yum/packages.py
@@ -1069,6 +1069,9 @@ class YumAvailablePackage(PackageObject, RpmBase):
@@ -708,11 +897,112 @@ index 6f61fea..15eeeaa 100644
msg +=""" <rpm:header-range start="%s" end="%s"/>""" % (self.hdrstart,
self.hdrend)
msg += self._dump_pco('provides')
+@@ -1243,18 +1246,32 @@ class YumHeaderPackage(YumAvailablePackage):
+ self.ver = self.version
+ self.rel = self.release
+ self.pkgtup = (self.name, self.arch, self.epoch, self.version, self.release)
+- # Summaries "can be" empty, which rpm return [], see BZ 473239, *sigh*
+- self.summary = self.hdr['summary'] or ''
+- self.summary = misc.share_data(self.summary.replace('\n', ''))
+- self.description = self.hdr['description'] or ''
+- self.description = misc.share_data(self.description)
++ self._loaded_summary = None
++ self._loaded_description = None
+ self.pkgid = self.hdr[rpm.RPMTAG_SHA1HEADER]
+ if not self.pkgid:
+ self.pkgid = "%s.%s" %(self.hdr['name'], self.hdr['buildtime'])
+ self.packagesize = self.hdr['size']
+ self.__mode_cache = {}
+ self.__prcoPopulated = False
+-
++
++ def _loadSummary(self):
++ # Summaries "can be" empty, which rpm return [], see BZ 473239, *sigh*
++ if self._loaded_summary is None:
++ summary = self._get_hdr()['summary'] or ''
++ summary = misc.share_data(summary.replace('\n', ''))
++ self._loaded_summary = summary
++ return self._loaded_summary
++ summary = property(lambda x: x._loadSummary())
++
++ def _loadDescription(self):
++ if self._loaded_description is None:
++ description = self._get_hdr()['description'] or ''
++ description = misc.share_data(description)
++ self._loaded_description = description
++ return self._loaded_description
++ description = property(lambda x: x._loadDescription())
++
+ def __str__(self):
+ if self.epoch == '0':
+ val = '%s-%s-%s.%s' % (self.name, self.version, self.release,
+@@ -1828,7 +1845,6 @@ class YumInstalledPackage(YumHeaderPackage):
+ my_mode = my_st.st_mode
+ if 'ghost' in ftypes: # This is what rpm does, although it
+ my_mode &= 0777 # doesn't usually get here.
+- mode &= 0777
+ if check_perms and pf.verify_mode and my_mode != pf.mode:
+ prob = _PkgVerifyProb('mode', 'mode does not match', ftypes)
+ prob.database_value = pf.mode
+diff --git a/yum/parser.py b/yum/parser.py
+index e46d611..fccf528 100644
+--- a/yum/parser.py
++++ b/yum/parser.py
+@@ -144,6 +144,11 @@ class ConfigPreProcessor:
+ # the current file returned EOF, pop it off the stack.
+ self._popfile()
+
++ # if the section is prefixed by a space then it is breaks iniparser/configparser
++ # so fix it
++ broken_sec_match = re.match(r'\s+\[(?P<section>.*)\]', line)
++ if broken_sec_match:
++ line = line.lstrip()
+ # at this point we have a line from the topmost file on the stack
+ # or EOF if the stack is empty
+ if self._vars:
diff --git a/yum/rpmsack.py b/yum/rpmsack.py
-index 0982a7c..227ed89 100644
+index 0982a7c..e93df20 100644
--- a/yum/rpmsack.py
+++ b/yum/rpmsack.py
-@@ -234,7 +234,7 @@ class RPMDBPackageSack(PackageSackBase):
+@@ -42,11 +42,6 @@ class RPMInstalledPackage(YumInstalledPackage):
+ def __init__(self, rpmhdr, index, rpmdb):
+ self._has_hdr = True
+ YumInstalledPackage.__init__(self, rpmhdr, yumdb=rpmdb.yumdb)
+- # NOTE: We keep summary/description/url because it doesn't add much
+- # and "yum search" uses them all.
+- self.url = rpmhdr['url']
+- # Also keep sourcerpm for pirut/etc.
+- self.sourcerpm = rpmhdr['sourcerpm']
+
+ self.idx = index
+ self.rpmdb = rpmdb
+@@ -67,13 +62,19 @@ class RPMInstalledPackage(YumInstalledPackage):
+ raise Errors.PackageSackError, 'Rpmdb changed underneath us'
+
+ def __getattr__(self, varname):
+- self.hdr = val = self._get_hdr()
+- self._has_hdr = True
+- # If these existed, then we wouldn't get here ... and nothing in the DB
+- # starts and ends with __'s. So these are missing.
+- if varname.startswith('__') and varname.endswith('__'):
++ # If these existed, then we wouldn't get here...
++ # Prevent access of __foo__, _cached_foo etc from loading the header
++ if varname.startswith('_'):
+ raise AttributeError, "%s has no attribute %s" % (self, varname)
+-
++
++ if varname != 'hdr': # Don't cache the hdr, unless explicitly requested
++ # Note that we don't even cache the .blah value, but looking up the
++ # header is _really_ fast so it's not obvious any of it is worth it.
++ # This is different to prco etc. data, which is loaded separately.
++ val = self._get_hdr()
++ else:
++ self.hdr = val = self._get_hdr()
++ self._has_hdr = True
+ if varname != 'hdr': # This is unusual, for anything that happens
+ val = val[varname] # a lot we should preload at __init__.
+ # Also note that pkg.no_value raises KeyError.
+@@ -234,7 +235,7 @@ class RPMDBPackageSack(PackageSackBase):
self._simple_pkgtup_list = csumpkgtups.keys()
if not self._simple_pkgtup_list:
@@ -721,7 +1011,7 @@ index 0982a7c..227ed89 100644
self._simple_pkgtup_list.append(self._hdr2pkgTuple(hdr))
return self._simple_pkgtup_list
-@@ -378,54 +378,36 @@ class RPMDBPackageSack(PackageSackBase):
+@@ -378,54 +379,36 @@ class RPMDBPackageSack(PackageSackBase):
pass
def searchAll(self, name, query_type='like'):
@@ -771,18 +1061,18 @@ index 0982a7c..227ed89 100644
+ pkg = self._makePackageObject(hdr, idx)
result.setdefault(pkg.pkgid, pkg)
- del mi
-
+-
- result = result.values()
-
- if self.auto_close:
- self.ts.close()
--
+
- return result
+ return result.values()
def searchPrco(self, name, prcotype):
-@@ -438,21 +420,15 @@ class RPMDBPackageSack(PackageSackBase):
+@@ -438,21 +421,15 @@ class RPMDBPackageSack(PackageSackBase):
if misc.re_glob(n):
glob = True
@@ -806,7 +1096,7 @@ index 0982a7c..227ed89 100644
# If it's not a provides or filename, we are done
if prcotype == 'provides' and name[0] == '/':
-@@ -463,9 +439,6 @@ class RPMDBPackageSack(PackageSackBase):
+@@ -463,9 +440,6 @@ class RPMDBPackageSack(PackageSackBase):
result = result.values()
self._cache[prcotype][name] = result
@@ -816,7 +1106,7 @@ index 0982a7c..227ed89 100644
return result
def searchProvides(self, name):
-@@ -607,7 +580,7 @@ class RPMDBPackageSack(PackageSackBase):
+@@ -607,7 +581,7 @@ class RPMDBPackageSack(PackageSackBase):
if not self._completely_loaded:
rpats = self._compile_patterns(patterns, ignore_case)
@@ -825,7 +1115,7 @@ index 0982a7c..227ed89 100644
if self._match_repattern(rpats, hdr, ignore_case):
self._makePackageObject(hdr, idx)
self._completely_loaded = patterns is None
-@@ -636,18 +609,13 @@ class RPMDBPackageSack(PackageSackBase):
+@@ -636,18 +610,13 @@ class RPMDBPackageSack(PackageSackBase):
if self._cached_conflicts_data is None:
result = {}
@@ -846,7 +1136,7 @@ index 0982a7c..227ed89 100644
result[po.pkgid] = po
if po._has_hdr:
continue # Unlikely, but, meh...
-@@ -659,9 +627,6 @@ class RPMDBPackageSack(PackageSackBase):
+@@ -659,9 +628,6 @@ class RPMDBPackageSack(PackageSackBase):
del po.hdr
self._cached_conflicts_data = result.values()
@@ -856,7 +1146,7 @@ index 0982a7c..227ed89 100644
return self._cached_conflicts_data
def _write_conflicts_new(self, pkgs, rpmdbv):
-@@ -1168,7 +1133,7 @@ class RPMDBPackageSack(PackageSackBase):
+@@ -1168,7 +1134,7 @@ class RPMDBPackageSack(PackageSackBase):
if not lowered:
searchstrings = map(lambda x: x.lower(), searchstrings)
ret = []
@@ -865,7 +1155,7 @@ index 0982a7c..227ed89 100644
n = self._find_search_fields(fields, searchstrings, hdr)
if n > 0:
ret.append((self._makePackageObject(hdr, idx), n))
-@@ -1190,41 +1155,20 @@ class RPMDBPackageSack(PackageSackBase):
+@@ -1190,41 +1156,20 @@ class RPMDBPackageSack(PackageSackBase):
return [ self._makePackageObject(h, mi) for (h, mi) in ts.returnLeafNodes(headers=True) ]
# Helper functions
@@ -887,12 +1177,12 @@ index 0982a7c..227ed89 100644
del mi
- if self.auto_close:
- self.ts.close()
--
+
- def _header_from_index(self, idx):
- """returns a package header having been given an index"""
- warnings.warn('_header_from_index() will go away in a future version of Yum.\n',
- Errors.YumFutureDeprecationWarning, stacklevel=2)
-
+-
- ts = self.readOnlyTS()
- try:
- mi = ts.dbMatch(0, idx)
@@ -913,7 +1203,7 @@ index 0982a7c..227ed89 100644
def _search(self, name=None, epoch=None, ver=None, rel=None, arch=None):
'''List of matching packages, to zero or more of NEVRA.'''
if name is not None and name in self._pkgname_fails:
-@@ -1254,18 +1198,16 @@ class RPMDBPackageSack(PackageSackBase):
+@@ -1254,18 +1199,16 @@ class RPMDBPackageSack(PackageSackBase):
ts = self.readOnlyTS()
if name is not None:
@@ -937,7 +1227,7 @@ index 0982a7c..227ed89 100644
# We create POs out of all matching names, even if we don't return
# them.
self._pkgnames_loaded.add(po.name)
-@@ -1277,9 +1219,6 @@ class RPMDBPackageSack(PackageSackBase):
+@@ -1277,9 +1220,6 @@ class RPMDBPackageSack(PackageSackBase):
else:
ret.append(po)
@@ -947,7 +1237,7 @@ index 0982a7c..227ed89 100644
if not done and name is not None:
self._pkgname_fails.add(name)
-@@ -1323,7 +1262,7 @@ class RPMDBPackageSack(PackageSackBase):
+@@ -1323,7 +1263,7 @@ class RPMDBPackageSack(PackageSackBase):
def getHdrList(self):
warnings.warn('getHdrList() will go away in a future version of Yum.\n',
DeprecationWarning, stacklevel=2)
@@ -957,10 +1247,32 @@ index 0982a7c..227ed89 100644
def getNameArchPkgList(self):
warnings.warn('getNameArchPkgList() will go away in a future version of Yum.\n',
diff --git a/yum/rpmtrans.py b/yum/rpmtrans.py
-index 0340153..d479829 100644
+index 0340153..08bf99d 100644
--- a/yum/rpmtrans.py
+++ b/yum/rpmtrans.py
-@@ -209,8 +209,7 @@ class RPMTransaction:
+@@ -25,6 +25,7 @@ import types
+ import sys
+ from yum.constants import *
+ from yum import _
++from yum.transactioninfo import TransactionMember
+ import misc
+ import tempfile
+
+@@ -174,11 +175,11 @@ class RPMTransaction:
+ self.base = base # base yum object b/c we need so much
+ self.test = test # are we a test?
+ self.trans_running = False
+- self.filehandles = {}
++ self.fd = None
+ self.total_actions = 0
+ self.total_installed = 0
+ self.complete_actions = 0
+- self.installed_pkg_names = []
++ self.installed_pkg_names = set()
+ self.total_removed = 0
+ self.logger = logging.getLogger('yum.filelogging.RPMInstallCallback')
+ self.filelog = False
+@@ -209,8 +210,7 @@ class RPMTransaction:
io_r = tempfile.NamedTemporaryFile()
self._readpipe = io_r
self._writepipe = open(io_r.name, 'w+b')
@@ -970,6 +1282,249 @@ index 0340153..d479829 100644
rpmverbosity = {'critical' : 'crit',
'emergency' : 'emerg',
'error' : 'err',
+@@ -255,12 +255,23 @@ class RPMTransaction:
+
+ return (hdr['name'], hdr['arch'], epoch, hdr['version'], hdr['release'])
+
+- def _makeHandle(self, hdr):
+- handle = '%s:%s.%s-%s-%s' % (hdr['epoch'], hdr['name'], hdr['version'],
+- hdr['release'], hdr['arch'])
++ # Find out txmbr based on the callback key. On erasures we dont know
++ # the exact txmbr but we always have a name, so return (name, txmbr)
++ # tuples so callers have less twists to deal with.
++ def _getTxmbr(self, cbkey):
++ if isinstance(cbkey, TransactionMember):
++ return (cbkey.name, cbkey)
++ elif isinstance(cbkey, tuple):
++ pkgtup = self._dopkgtup(cbkey[0])
++ txmbrs = self.base.tsInfo.getMembers(pkgtup=pkgtup)
++ # if this is not one, somebody screwed up
++ assert len(txmbrs) == 1
++ return (txmbrs[0].name, txmbrs[0])
++ elif isinstance(cbkey, basestring):
++ return (cbkey, None)
++ else:
++ return (None, None)
+
+- return handle
+-
+ def ts_done(self, package, action):
+ """writes out the portions of the transaction which have completed"""
+
+@@ -409,11 +420,10 @@ class RPMTransaction:
+
+
+ def _transStart(self, bytes, total, h):
+- if bytes == 6:
+- self.total_actions = total
+- if self.test: return
+- self.trans_running = True
+- self.ts_all() # write out what transaction will do
++ self.total_actions = total
++ if self.test: return
++ self.trans_running = True
++ self.ts_all() # write out what transaction will do
+
+ def _transProgress(self, bytes, total, h):
+ pass
+@@ -423,62 +433,52 @@ class RPMTransaction:
+
+ def _instOpenFile(self, bytes, total, h):
+ self.lastmsg = None
+- hdr = None
+- if h is not None:
+- hdr, rpmloc = h[0], h[1]
+- handle = self._makeHandle(hdr)
++ name, txmbr = self._getTxmbr(h)
++ if txmbr is not None:
++ rpmloc = txmbr.po.localPkg()
+ try:
+- fd = os.open(rpmloc, os.O_RDONLY)
+- except OSError, e:
++ self.fd = file(rpmloc)
++ except IOError, e:
+ self.display.errorlog("Error: Cannot open file %s: %s" % (rpmloc, e))
+ else:
+- self.filehandles[handle]=fd
+ if self.trans_running:
+ self.total_installed += 1
+ self.complete_actions += 1
+- self.installed_pkg_names.append(hdr['name'])
+- return fd
++ self.installed_pkg_names.add(name)
++ return self.fd.fileno()
+ else:
+ self.display.errorlog("Error: No Header to INST_OPEN_FILE")
+
+ def _instCloseFile(self, bytes, total, h):
+- hdr = None
+- if h is not None:
+- hdr, rpmloc = h[0], h[1]
+- handle = self._makeHandle(hdr)
+- os.close(self.filehandles[handle])
+- fd = 0
++ name, txmbr = self._getTxmbr(h)
++ if txmbr is not None:
++ self.fd.close()
++ self.fd = None
+ if self.test: return
+ if self.trans_running:
+- pkgtup = self._dopkgtup(hdr)
+- txmbrs = self.base.tsInfo.getMembers(pkgtup=pkgtup)
+- for txmbr in txmbrs:
+- self.display.filelog(txmbr.po, txmbr.output_state)
+- self._scriptout(txmbr.po)
+- # NOTE: We only do this for install, not erase atm.
+- # because we don't get pkgtup data for erase (this
+- # includes "Updated" pkgs).
+- pid = self.base.history.pkg2pid(txmbr.po)
+- state = self.base.history.txmbr2state(txmbr)
+- self.base.history.trans_data_pid_end(pid, state)
+- self.ts_done(txmbr.po, txmbr.output_state)
++ self.display.filelog(txmbr.po, txmbr.output_state)
++ self._scriptout(txmbr.po)
++ # NOTE: We only do this for install, not erase atm.
++ # because we don't get pkgtup data for erase (this
++ # includes "Updated" pkgs).
++ pid = self.base.history.pkg2pid(txmbr.po)
++ state = self.base.history.txmbr2state(txmbr)
++ self.base.history.trans_data_pid_end(pid, state)
++ self.ts_done(txmbr.po, txmbr.output_state)
+
+ def _instProgress(self, bytes, total, h):
+- if h is not None:
+- # If h is a string, we're repackaging.
++ name, txmbr = self._getTxmbr(h)
++ if name is not None:
++ # If we only have a name, we're repackaging.
+ # Why the RPMCALLBACK_REPACKAGE_PROGRESS flag isn't set, I have no idea
+- if type(h) == type(""):
+- self.display.event(h, 'repackaging', bytes, total,
++ if txmbr is None:
++ self.display.event(name, 'repackaging', bytes, total,
+ self.complete_actions, self.total_actions)
+-
+ else:
+- hdr, rpmloc = h[0], h[1]
+- pkgtup = self._dopkgtup(hdr)
+- txmbrs = self.base.tsInfo.getMembers(pkgtup=pkgtup)
+- for txmbr in txmbrs:
+- action = txmbr.output_state
+- self.display.event(txmbr.po, action, bytes, total,
+- self.complete_actions, self.total_actions)
++ action = txmbr.output_state
++ self.display.event(txmbr.po, action, bytes, total,
++ self.complete_actions, self.total_actions)
++
+ def _unInstStart(self, bytes, total, h):
+ pass
+
+@@ -486,20 +486,21 @@ class RPMTransaction:
+ pass
+
+ def _unInstStop(self, bytes, total, h):
++ name, txmbr = self._getTxmbr(h)
+ self.total_removed += 1
+ self.complete_actions += 1
+- if h not in self.installed_pkg_names:
+- self.display.filelog(h, TS_ERASE)
++ if name not in self.installed_pkg_names:
++ self.display.filelog(name, TS_ERASE)
+ action = TS_ERASE
+ else:
+ action = TS_UPDATED
+
+- self.display.event(h, action, 100, 100, self.complete_actions,
++ self.display.event(name, action, 100, 100, self.complete_actions,
+ self.total_actions)
+- self._scriptout(h)
++ self._scriptout(name)
+
+ if self.test: return # and we're done
+- self.ts_done(h, action)
++ self.ts_done(name, action)
+
+
+ def _rePackageStart(self, bytes, total, h):
+@@ -512,20 +513,16 @@ class RPMTransaction:
+ pass
+
+ def _cpioError(self, bytes, total, h):
+- hdr, rpmloc = h[0], h[1]
+- pkgtup = self._dopkgtup(hdr)
+- txmbrs = self.base.tsInfo.getMembers(pkgtup=pkgtup)
+- for txmbr in txmbrs:
++ name, txmbr = self._getTxmbr(h)
++ if txmbr is not None:
+ msg = "Error in cpio payload of rpm package %s" % txmbr.po
+ txmbr.output_state = TS_FAILED
+ self.display.errorlog(msg)
+ # FIXME - what else should we do here? raise a failure and abort?
+
+ def _unpackError(self, bytes, total, h):
+- hdr, rpmloc = h[0], h[1]
+- pkgtup = self._dopkgtup(hdr)
+- txmbrs = self.base.tsInfo.getMembers(pkgtup=pkgtup)
+- for txmbr in txmbrs:
++ name, txmbr = self._getTxmbr(h)
++ if txmbr is not None:
+ txmbr.output_state = TS_FAILED
+ msg = "Error unpacking rpm package %s" % txmbr.po
+ self.display.errorlog(msg)
+@@ -533,35 +530,24 @@ class RPMTransaction:
+ # right behavior should be
+
+ def _scriptError(self, bytes, total, h):
+- if not isinstance(h, types.TupleType):
+- # fun with install/erase transactions, see rhbz#484729
+- h = (h, None)
+- hdr, rpmloc = h[0], h[1]
+- remove_hdr = False # if we're in a clean up/remove then hdr will not be an rpm.hdr
+- if not isinstance(hdr, rpm.hdr):
+- txmbrs = [hdr]
+- remove_hdr = True
++ # "bytes" carries the failed scriptlet tag,
++ # "total" carries fatal/non-fatal status
++ scriptlet_name = rpm.tagnames.get(bytes, "<unknown>")
++
++ name, txmbr = self._getTxmbr(h)
++ if txmbr is None:
++ package_name = name
+ else:
+- pkgtup = self._dopkgtup(hdr)
+- txmbrs = self.base.tsInfo.getMembers(pkgtup=pkgtup)
++ package_name = txmbr.po
+
+- for pkg in txmbrs:
+- # "bytes" carries the failed scriptlet tag,
+- # "total" carries fatal/non-fatal status
+- scriptlet_name = rpm.tagnames.get(bytes, "<unknown>")
+- if remove_hdr:
+- package_name = pkg
+- else:
+- package_name = pkg.po
+-
+- if total:
+- msg = ("Error in %s scriptlet in rpm package %s" %
+- (scriptlet_name, package_name))
+- if not remove_hdr:
+- pkg.output_state = TS_FAILED
+- else:
+- msg = ("Non-fatal %s scriptlet failure in rpm package %s" %
+- (scriptlet_name, package_name))
+- self.display.errorlog(msg)
+- # FIXME - what else should we do here? raise a failure and abort?
++ if total:
++ msg = ("Error in %s scriptlet in rpm package %s" %
++ (scriptlet_name, package_name))
++ if txmbr is not None:
++ txmbr.output_state = TS_FAILED
++ else:
++ msg = ("Non-fatal %s scriptlet failure in rpm package %s" %
++ (scriptlet_name, package_name))
++ self.display.errorlog(msg)
++ # FIXME - what else should we do here? raise a failure and abort?
+
diff --git a/yum/update_md.py b/yum/update_md.py
index 83e56c6..39fa72e 100644
--- a/yum/update_md.py
@@ -1000,7 +1555,7 @@ index 83e56c6..39fa72e 100644
try:
un = UpdateNotice(elem)
diff --git a/yumcommands.py b/yumcommands.py
-index ecce347..f196477 100644
+index ecce347..62b8746 100644
--- a/yumcommands.py
+++ b/yumcommands.py
@@ -46,7 +46,7 @@ def checkRootUID(base):
@@ -1012,7 +1567,23 @@ index ecce347..f196477 100644
msg = _("""
You have enabled checking of packages via GPG keys. This is a good thing.
However, you do not have any GPG public keys installed. You need to download
-@@ -972,6 +972,12 @@ class RepoListCommand(YumCommand):
+@@ -626,13 +626,14 @@ class CheckUpdateCommand(YumCommand):
+ checkEnabledRepo(base)
+
+ def doCommand(self, base, basecmd, extcmds):
++ obscmds = ['obsoletes'] + extcmds
+ base.extcmds.insert(0, 'updates')
+ result = 0
+ try:
+ ypl = base.returnPkgLists(extcmds)
+ if (base.conf.obsoletes or
+ base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)):
+- typl = base.returnPkgLists(['obsoletes'])
++ typl = base.returnPkgLists(obscmds)
+ ypl.obsoletes = typl.obsoletes
+ ypl.obsoletesTuples = typl.obsoletesTuples
+
+@@ -972,6 +973,12 @@ class RepoListCommand(YumCommand):
elif repo.mirrorlist:
out += [base.fmtKeyValFill(_("Repo-mirrors : "),
repo.mirrorlist)]
diff --git a/yum.spec b/yum.spec
index 79e3a82..ca4c9fd 100644
--- a/yum.spec
+++ b/yum.spec
@@ -7,7 +7,7 @@
Summary: RPM package installer/updater/manager
Name: yum
Version: 3.2.29
-Release: 6%{?dist}
+Release: 7%{?dist}
License: GPLv2+
Group: System Environment/Base
Source0: http://yum.baseurl.org/download/3.2/%{name}-%{version}.tar.gz
@@ -248,6 +248,9 @@ exit 0
%config(noreplace) %{_sysconfdir}/sysconfig/yum-cron
%changelog
+* Mon Feb 28 2011 Seth Vidal <skvidal at fedoraproject.org> - 3.2.29-7
+- latest head including all of Panu's rpmutils/callback patches
+
* Thu Feb 17 2011 Seth Vidal <skvidal at fedoraproject.org> - 3.2.29-6
- add rpmutils-recursive-import.patch to work around recursive import problems
More information about the scm-commits
mailing list