def _write(self, attr, value): # check for self._conf.writable before going on? if not os.path.exists(self._mydir): _makedirs_no_umask(self._mydir) attr = _sanitize(attr) if attr in self._read_cached_data: del self._read_cached_data[attr] fn = self._attr2fn(attr) if attr.endswith('.tmp'): raise AttributeError, "Cannot set attribute %s on %s" % (attr, self) # Auto hardlink some of the attrs... if self._link_yumdb_cache(fn, value): return # Default write()+rename()... hardlink -c can still help. misc.unlink_f(fn + '.tmp') fo = _open_no_umask(fn + '.tmp', 'w') try: fo.write(value) except (OSError, IOError), e: raise AttributeError, "Cannot set attribute %s on %s" % (attr, self)
def ts_done_write(self, msg): """ Write some data to the transaction done file. """ if self._ts_done is None: return try: self._ts_done.write(msg) self._ts_done.flush() except (IOError, OSError), e: # Having incomplete transactions is probably worse than having # nothing. self.display.errorlog('could not write to ts_done file: %s' % e) self._ts_done = None misc.unlink_f(self.ts_done_fn)
def _link_yumdb_cache(self, fn, value): """ If we have a matching yumdb cache, link() to it instead of having to open()+write(). """ if self._yumdb_cache is None: return False self._unlink_yumdb_cache(fn) if value not in self._yumdb_cache['attr']: return False assert self._yumdb_cache['attr'][value][2] try: lfn = iter(self._yumdb_cache['attr'][value][2]).next() misc.unlink_f(fn + '.tmp') os.link(lfn, fn + '.tmp') os.rename(fn + '.tmp', fn) except: return False self._yumdb_cache['attr'][value][2].add(fn) self._yumdb_cache[fn] = value return True
except (IOError, OSError), e: self.display.errorlog('could not open ts_all file: %s' % e) self._ts_done = None return try: 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() except (IOError, OSError), e: # Having incomplete transactions is probably worse than having # nothing. self.display.errorlog('could not write to ts_all file: %s' % e) misc.unlink_f(tsfn) self._ts_done = None def callback(self, what, bytes, total, h, user): if what == rpm.RPMCALLBACK_TRANS_START: self._transStart(bytes, total, h) elif what == rpm.RPMCALLBACK_TRANS_PROGRESS: self._transProgress(bytes, total, h) elif what == rpm.RPMCALLBACK_TRANS_STOP: self._transStop(bytes, total, h) elif what == rpm.RPMCALLBACK_INST_OPEN_FILE: return self._instOpenFile(bytes, total, h) elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE: self._instCloseFile(bytes, total, h) elif what == rpm.RPMCALLBACK_INST_PROGRESS: self._instProgress(bytes, total, h)
except (IOError, OSError), e: self.display.errorlog('could not open ts_all file: %s' % e) self._ts_done = None return try: 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() except (IOError, OSError), e: # Having incomplete transactions is probably worse than having # nothing. self.display.errorlog('could not write to ts_all file: %s' % e) misc.unlink_f(tsfn) self._ts_done = None def callback( self, what, bytes, total, h, user ): if what == rpm.RPMCALLBACK_TRANS_START: self._transStart( bytes, total, h ) elif what == rpm.RPMCALLBACK_TRANS_PROGRESS: self._transProgress( bytes, total, h ) elif what == rpm.RPMCALLBACK_TRANS_STOP: self._transStop( bytes, total, h ) elif what == rpm.RPMCALLBACK_INST_OPEN_FILE: return self._instOpenFile( bytes, total, h ) elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE: self._instCloseFile( bytes, total, h ) elif what == rpm.RPMCALLBACK_INST_PROGRESS: self._instProgress( bytes, total, h )
class RPMTransaction: def __init__(self, base, test=False, display=NoOutputCallBack): if not callable(display): self.display = display else: self.display = display() # display callback self.display = _WrapNoExceptions(self.display) 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.total_actions = 0 self.total_installed = 0 self.complete_actions = 0 self.installed_pkg_names = [] self.total_removed = 0 self.logger = logging.getLogger('yum.filelogging.RPMInstallCallback') self.filelog = False self._setupOutputLogging(base.conf.rpmverbosity) if not os.path.exists(self.base.conf.persistdir): os.makedirs(self.base.conf.persistdir) # make the dir, just in case # Error checking? -- these should probably be where else def _fdSetNonblock(self, fd): """ Set the Non-blocking flag for a filedescriptor. """ flag = os.O_NONBLOCK current_flags = fcntl.fcntl(fd, fcntl.F_GETFL) if current_flags & flag: return fcntl.fcntl(fd, fcntl.F_SETFL, current_flags | flag) def _fdSetCloseOnExec(self, fd): """ Set the close on exec. flag for a filedescriptor. """ flag = fcntl.FD_CLOEXEC current_flags = fcntl.fcntl(fd, fcntl.F_GETFD) if current_flags & flag: return fcntl.fcntl(fd, fcntl.F_SETFD, current_flags | flag) def _setupOutputLogging(self, rpmverbosity="info"): # UGLY... set up the transaction to record output from scriptlets io_r = tempfile.NamedTemporaryFile() self._readpipe = io_r self._writepipe = open(io_r.name, 'w+b') # This is dark magic, it really needs to be "base.ts.ts". self.base.ts.ts.scriptFd = self._writepipe.fileno() rpmverbosity = {'critical' : 'crit', 'emergency' : 'emerg', 'error' : 'err', 'information' : 'info', 'warn' : 'warning'}.get(rpmverbosity, rpmverbosity) rpmverbosity = 'RPMLOG_' + rpmverbosity.upper() if not hasattr(rpm, rpmverbosity): rpmverbosity = 'RPMLOG_INFO' rpm.setVerbosity(getattr(rpm, rpmverbosity)) rpm.setLogFile(self._writepipe) def _shutdownOutputLogging(self): # reset rpm bits from reording output rpm.setVerbosity(rpm.RPMLOG_NOTICE) rpm.setLogFile(sys.stderr) try: self._writepipe.close() except: pass def _scriptOutput(self): try: out = self._readpipe.read() if not out: return None return out except IOError: pass def _scriptout(self, data): msgs = self._scriptOutput() self.display.scriptout(data, msgs) self.base.history.log_scriptlet_output(data, msgs) def __del__(self): self._shutdownOutputLogging() def _dopkgtup(self, hdr): tmpepoch = hdr['epoch'] if tmpepoch is None: epoch = '0' else: epoch = str(tmpepoch) 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']) 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'): self.ts_done_fn = '%s/transaction-done.%s' % (self.base.conf.persistdir, self._ts_time) try: self._ts_done = open(self.ts_done_fn, 'w') except (IOError, OSError), e: self.display.errorlog('could not open ts_done file: %s' % e) return self._fdSetCloseOnExec(self._ts_done.fileno()) # 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 # make sure we have a list to work from if len(self._te_tuples) == 0: # if we don't then this is pretrans or postrans or a trigger # either way we have to respond correctly so just return and don't # emit anything return (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.filelog(package, msg) if action in TS_INSTALL_STATES: if t != 'install': self.display.filelog(package, 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.filelog(package, msg) # hope springs eternal that this isn't wrong msg = '%s %s:%s-%s-%s.%s\n' % (t,e,n,v,r,a) try: self._ts_done.write(msg) self._ts_done.flush() except (IOError, OSError), e: # Having incomplete transactions is probably worse than having # nothing. del self._ts_done misc.unlink_f(self.ts_done_fn)
try: fo = open(tsfn, 'w') except (IOError, OSError), e: self.display.errorlog('could not open ts_all file: %s' % e) return try: 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() except (IOError, OSError), e: # Having incomplete transactions is probably worse than having # nothing. misc.unlink_f(self.ts_all_fn) def callback(self, what, bytes, total, h, user): if what == rpm.RPMCALLBACK_TRANS_START: self._transStart(bytes, total, h) elif what == rpm.RPMCALLBACK_TRANS_PROGRESS: self._transProgress(bytes, total, h) elif what == rpm.RPMCALLBACK_TRANS_STOP: self._transStop(bytes, total, h) elif what == rpm.RPMCALLBACK_INST_OPEN_FILE: return self._instOpenFile(bytes, total, h) elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE: self._instCloseFile(bytes, total, h) elif what == rpm.RPMCALLBACK_INST_PROGRESS: self._instProgress(bytes, total, h) elif what == rpm.RPMCALLBACK_UNINST_START: