[yum-cvs] 2 commits - cli.py docs/yum.conf.5 yum/config.py yum/__init__.py yum/rpmtrans.py
Seth Vidal
skvidal at linux.duke.edu
Thu Aug 16 12:50:13 UTC 2007
cli.py | 4 -
docs/yum.conf.5 | 4 +
yum/__init__.py | 9 +++
yum/config.py | 3 -
yum/rpmtrans.py | 151 +++++++++++++++++++++++++++++++++++++++++++++++++-------
5 files changed, 150 insertions(+), 21 deletions(-)
New commits:
commit bc6f746d416340b5dbe58f1028fee06d2e1e89aa
Merge: 13fa959... cbbaf1a...
Author: Seth Vidal <skvidal at fedoraproject.org>
Date: Thu Aug 16 08:46:48 2007 -0400
Merge branch 'master' of ssh://login.linux.duke.edu/home/groups/yum/git/yum
* 'master' of ssh://login.linux.duke.edu/home/groups/yum/git/yum:
Make the BaseConfig write method work better and make it support
commit 13fa959ab54b6fa6112f2064f7e8983fa15f3b11
Author: Seth Vidal <skvidal at fedoraproject.org>
Date: Thu Aug 16 08:46:33 2007 -0400
implement transaction journalling:
transaction-done.datestamp and transaction-all.datestamp files
will be made in /var/lib/yum (persistdir in the conf file). These files
describe the entire transaction and which portions of it have finished.
adds persistdir to configuration - for persistent information b/t runs - unlike cachedir
fixes a couple of lingering bugs in the new rpm callback.
diff --git a/cli.py b/cli.py
index 683fb15..4459699 100644
--- a/cli.py
+++ b/cli.py
@@ -340,7 +340,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
for feature in ['diskspacecheck']: # more to come, I'm sure
tsConf[feature] = getattr(self.conf, feature)
- testcb = RPMTransaction(self.tsInfo)
+ testcb = RPMTransaction(self, test=True)
self.initActionTs()
# save our dsCallback out
@@ -374,7 +374,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
# put back our depcheck callback
self.dsCallback = dscb
# setup our rpm ts callback
- cb = RPMTransaction(self.tsInfo, display=output.YumCliRPMCallBack)
+ cb = RPMTransaction(self, display=output.YumCliRPMCallBack)
if self.conf.debuglevel < 2:
cb.display.output = False
diff --git a/docs/yum.conf.5 b/docs/yum.conf.5
index 8094b58..5f00b38 100644
--- a/docs/yum.conf.5
+++ b/docs/yum.conf.5
@@ -26,6 +26,10 @@ following options:
Directory where yum should store its cache and db files. The default is
`/var/cache/yum'.
+.IP \fBpersistdir\fR
+Directory where yum should store information that should persist over multiple
+runs. The default is `/var/lib/yum'.
+
.IP \fBkeepcache\fR
Either `1' or `0'. Determines whether or not yum keeps the cache
of headers and packages after succesful installation. Default is '1'
diff --git a/yum/__init__.py b/yum/__init__.py
index 80a9e52..33a0e76 100644
--- a/yum/__init__.py
+++ b/yum/__init__.py
@@ -573,6 +573,15 @@ class YumBase(depsolve.Depsolve):
if not self.conf.keepcache:
self.cleanUsedHeadersPackages()
+
+ for i in ('ts_all_fn', 'ts_done_fn'):
+ if hasattr(cb, i):
+ fn = getattr(cb, i)
+ if os.path.exists(fn):
+ try:
+ os.unlink(fn)
+ except (IOError, OSError), e:
+ self.logger.critical('Failed to remove transaction file %s' % fn)
self.plugins.run('posttrans')
diff --git a/yum/config.py b/yum/config.py
index 6ae7d0d..0af2099 100644
--- a/yum/config.py
+++ b/yum/config.py
@@ -474,6 +474,7 @@ class YumConf(StartupConf):
recent = IntOption(7)
cachedir = Option('/var/cache/yum')
+ persistdir = Option('/var/lib/yum')
keepcache = BoolOption(True)
logfile = Option('/var/log/yum.log')
reposdir = ListOption(['/etc/yum/repos.d', '/etc/yum.repos.d'])
@@ -609,7 +610,7 @@ def readMainConfig(startupconf):
yumconf.populate(startupconf._parser, 'main')
# Apply the installroot to directory options
- for option in ('cachedir', 'logfile'):
+ for option in ('cachedir', 'logfile', 'persistdir'):
path = getattr(yumconf, option)
setattr(yumconf, option, yumconf.installroot + path)
diff --git a/yum/rpmtrans.py b/yum/rpmtrans.py
index 1c1d1b2..42c094f 100644
--- a/yum/rpmtrans.py
+++ b/yum/rpmtrans.py
@@ -18,8 +18,10 @@
import rpm
import os
-import sys
+import time
import logging
+import types
+import sys
from yum.constants import *
@@ -87,6 +89,7 @@ class RPMBaseCallback:
def errorlog(self, msg):
+ # FIXME this should probably dump to the filelog, too
print >> sys.stderr, msg
def filelog(self, package, action):
@@ -111,10 +114,11 @@ class SimpleCliCallBack(RPMBaseCallback):
self.lastpackage = package
class RPMTransaction:
- def __init__(self, tsInfo, display=NoOutputCallBack):
- self.display = display()
- self.tsInfo = tsInfo
-
+ def __init__(self, base, test=False, display=NoOutputCallBack):
+ self.display = display() # display callback
+ self.base = base # base yum object b/c we need so much
+ self.test = test # are we a test?
+
self.filehandles = {}
self.total_actions = 0
self.total_installed = 0
@@ -123,7 +127,8 @@ class RPMTransaction:
self.total_removed = 0
self.logger = logging.getLogger('yum.filelogging.RPMInstallCallback')
self.filelog = False
-
+
+
def _dopkgtup(self, hdr):
tmpepoch = hdr['epoch']
if tmpepoch is None: epoch = '0'
@@ -136,7 +141,101 @@ class RPMTransaction:
hdr['release'], hdr['arch'])
return handle
+
+ def ts_done(self, package, action):
+ """writes out the portions of the transaction which have completed"""
+
+ if self.test: return
+
+ if not hasattr(self, '_ts_done'):
+ # need config variable to put this in a better path/name
+ te_fn = '%s/transaction-done.%s' % (self.base.conf.persistdir, self._ts_time)
+ self.ts_done_fn = te_fn
+ try:
+ self._ts_done = open(te_fn, 'w')
+ except (IOError, OSError), e:
+ self.display.errorlog('could not open ts_done file: %s' % e)
+ return
+
+ # walk back through self._te_tuples
+ # make sure the package and the action make some kind of sense
+ # write it out and pop(0) from the list
+ (t,e,n,v,r,a) = self._te_tuples[0] # what we should be on
+
+ # make sure we're in the right action state
+ msg = 'ts_done state is %s %s should be %s %s' % (package, action, t, n)
+ if action in TS_REMOVE_STATES:
+ if t != 'erase':
+ self.display.errorlog(msg)
+ if action in TS_INSTALL_STATES:
+ if t != 'install':
+ self.display.errorlog(msg)
+
+ # check the pkg name out to make sure it matches
+ if type(package) in types.StringTypes:
+ name = package
+ else:
+ name = package.name
+
+ if n != name:
+ msg = 'ts_done name in te is %s should be %s' % (n, package)
+ self.display.errorlog(msg)
+
+ # hope springs eternal that this isn't wrong
+ msg = '%s %s:%s-%s-%s.%s\n' % (t,e,n,v,r,a)
+
+ self._ts_done.write(msg)
+ self._ts_done.flush()
+ self._te_tuples.pop(0)
+
+ def ts_all(self):
+ """write out what our transaction will do"""
+
+ # save the transaction elements into a list so we can run across them
+ if not hasattr(self, '_te_tuples'):
+ self._te_tuples = []
+
+ for te in self.base.ts:
+ n = te.N()
+ a = te.A()
+ v = te.V()
+ r = te.R()
+ e = te.E()
+ if e is None:
+ e = '0'
+ if te.Type() == 1:
+ t = 'install'
+ elif te.Type() == 2:
+ t = 'erase'
+ else:
+ t = te.Type()
+
+ # save this in a list
+ self._te_tuples.append((t,e,n,v,r,a))
+
+ # write to a file
+ self._ts_time = time.strftime('%Y-%m-%d.%H:%M.%S')
+ tsfn = '%s/transaction-all.%s' % (self.base.conf.persistdir, self._ts_time)
+ self.ts_all_fn = tsfn
+ try:
+ # fixme - we should probably be making this elsewhere but I'd
+ # rather that the transaction not fail so we do it here, anyway
+ if not os.path.exists(self.base.conf.persistdir):
+ os.makedirs(self.base.conf.persistdir) # make the dir, just in case
+
+ fo = open(tsfn, 'w')
+ except (IOError, OSError), e:
+ self.display.errorlog('could not open ts_all file: %s' % e)
+ return
+
+
+ for (t,e,n,v,r,a) in self._te_tuples:
+ msg = "%s %s:%s-%s-%s.%s\n" % (t,e,n,v,r,a)
+ fo.write(msg)
+ fo.flush()
+ fo.close()
+
def callback( self, what, bytes, total, h, user ):
if what == rpm.RPMCALLBACK_TRANS_START:
self._transStart( bytes, total, h )
@@ -165,17 +264,22 @@ class RPMTransaction:
elif what == rpm.RPMCALLBACK_CPIO_ERROR:
self._cpioError(bytes, total, h)
elif what == rpm.RPMCALLBACK_UNPACK_ERROR:
- self.unpackError(bytes, total, h)
+ self._unpackError(bytes, total, h)
def _transStart(self, bytes, total, h):
if bytes == 6:
self.total_actions = total
-
+ if self.test: return
+
+ self.ts_all() # write out what transaction will do
+
def _transProgress(self, bytes, total, h):
pass
+
def _transStop(self, bytes, total, h):
pass
+
def _instOpenFile(self, bytes, total, h):
self.lastmsg = None
hdr = None
@@ -190,6 +294,7 @@ class RPMTransaction:
return fd
else:
self.display.errorlog("Error: No Header to INST_OPEN_FILE")
+
def _instCloseFile(self, bytes, total, h):
hdr = None
if h is not None:
@@ -197,11 +302,15 @@ class RPMTransaction:
handle = self._makeHandle(hdr)
os.close(self.filehandles[handle])
fd = 0
-
+ if self.test: return
+
pkgtup = self._dopkgtup(hdr)
- txmbrs = self.tsInfo.getMembers(pkgtup=pkgtup)
+ txmbrs = self.base.tsInfo.getMembers(pkgtup=pkgtup)
for txmbr in txmbrs:
self.display.filelog(txmbr.po, txmbr.output_state)
+ self.ts_done(txmbr.po, txmbr.output_state)
+
+
def _instProgress(self, bytes, total, h):
if h is not None:
@@ -214,14 +323,14 @@ class RPMTransaction:
else:
hdr, rpmloc = h
pkgtup = self._dopkgtup(hdr)
- txmbrs = self.tsInfo.getMembers(pkgtup=pkgtup)
+ 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)
def _unInstStart(self, bytes, total, h):
pass
-
+
def _unInstProgress(self, bytes, total, h):
pass
@@ -233,10 +342,14 @@ class RPMTransaction:
action = TS_ERASE
else:
action = TS_UPDATED
-
+
self.display.event(h, action, 100, 100, self.complete_actions,
self.total_actions)
-
+
+ if self.test: return # and we're done
+ self.ts_done(h, action)
+
+
def _rePackageStart(self, bytes, total, h):
pass
@@ -249,17 +362,19 @@ class RPMTransaction:
def _cpioError(self, bytes, total, h):
(hdr, rpmloc) = h
pkgtup = self._dopkgtup(hdr)
- txmbrs = self.tsInfo.getMembers(pkgtup=pkgtup)
+ txmbrs = self.base.tsInfo.getMembers(pkgtup=pkgtup)
for txmbr in txmbrs:
- self.display.errorlog("Error in cpio payload of rpm package %s" % txmbr.po)
+ msg = "Error in cpio payload of rpm package %s" % txmbr.po
+ 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
pkgtup = self._dopkgtup(hdr)
- txmbrs = self.tsInfo.getMembers(pkgtup=pkgtup)
+ txmbrs = self.base.tsInfo.getMembers(pkgtup=pkgtup)
for txmbr in txmbrs:
- self.display.errorlog("Error unpacking rpm package %s" % txmbr.po)
+ msg = "Error unpacking rpm package %s" % txmbr.po
+ self.display.errorlog(msg)
# FIXME - should we raise? I need a test case pkg to see what the
# right behavior should be
More information about the Yum-cvs-commits
mailing list