# # yumwrapper.py # yum wrapper # # Copyright (C) 2009 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Red Hat Author(s): Martin Gracik # import sys import os import yum import yum.callbacks import yum.rpmtrans from pylorax.misc import seq, get_console_size class Callback(yum.rpmtrans.SimpleCliCallBack): def __init__(self): yum.rpmtrans.SimpleCliCallBack.__init__(self) self.height, self.width = get_console_size() def event(self, package, action, te_current, te_total, ts_current, ts_total): progress = float(te_current) / float(te_total) percentage = int(progress * 100) bar_length = 20 bar = int(percentage / (100 / bar_length)) total_progress_str = "[%s/%s] " % (ts_current, ts_total) package_progress_str = " [%s%s] %3d%%" % ("#" * bar, "-" * (bar_length - bar), percentage) action_str = "%s %s" % (self.action[action], package) chars_left = self.width - len(total_progress_str) - len(package_progress_str) if len(action_str) > chars_left: action_str = action_str[:chars_left-3] action_str = action_str + "..." else: action_str = action_str + " " * (chars_left - len(action_str)) msg = total_progress_str + action_str + package_progress_str sys.stdout.write(msg) sys.stdout.write("\r") if percentage == 100: sys.stdout.write("\n") sys.stdout.flush() class Yum(object): def __init__(self, yumconf="/etc/yum/yum.conf", installroot="/", errfile="/dev/null"): self.yb = yum.YumBase() self.yumconf = os.path.abspath(yumconf) self.installroot = os.path.abspath(installroot) self.errfile = errfile self.yb.preconf.fn = self.yumconf self.yb.preconf.root = self.installroot self.yb._getConfig() self.yb._getRpmDB() self.yb._getRepos() self.yb._getSacks() def find(self, patterns): pl = self.yb.doPackageLists(patterns=seq(patterns)) return pl.installed, pl.available def add_package(self, pattern): try: self.yb.install(name=pattern) except yum.Errors.InstallError: # didn't find an exact package name match try: self.yb.install(pattern=pattern) except yum.Errors.InstallError: # no package found return False return True def install(self): self.yb.resolveDeps() self.yb.buildTransaction() cb = yum.callbacks.ProcessTransBaseCallback() #cb = yum.callbacks.ProcessTransNoOutputCallback() rpmcb = Callback() # XXX ATTENTION! ugly rpm error output hack # we redirect the error output from rpm to errfile, # so it does not show up in our "nice" output # 2 = err descriptor standard_err = os.dup(2) my_err = open(self.errfile, "a") os.dup2(my_err.fileno(), 2) # now we process the transactions without errors showing up in the output self.yb.processTransaction(callback=cb, rpmDisplay=rpmcb) # and we put the standard error output back, so nobody will notice os.dup2(standard_err, 2) my_err.close() self.yb.closeRpmDB() self.yb.close()