|
Server : Apache/2.2.2 (Fedora) System : Linux App1.pathumtani.go.th 2.6.20-1.2320.fc5smp #1 SMP Tue Jun 12 19:40:16 EDT 2007 i686 User : apache ( 48) PHP Version : 5.2.9 Disable Function : NONE Directory : /proc/self/root/usr/lib/python2.4/site-packages/pirut/ |
Upload File : |
#!/usr/bin/python -tt
#
# Copyright 2005 Red Hat, Inc.
#
# Jeremy Katz <katzj@redhat.com>
#
# 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; version 2 only
#
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import os, sys, fcntl
import string
import time
import rpm
import urllib2
import gtk
import gtk.glade
import gtk.gdk as gdk
import gobject
import pango
from rhpl.translate import _, N_
import yum
import yum.plugins
import yum.Errors
from yum.logger import Logger
from yum.constants import *
import urlgrabber, urlgrabber.progress
import DetailsDialog
import GroupSelector
import PackageList
import Progress
from constants import *
from Errors import *
PirutDetailsDialog = DetailsDialog.PirutDetailsDialog
PirutTransactionProgress = Progress.PirutTransactionProgress
PirutProgress = Progress.PirutProgress
PirutProgressCallback = Progress.PirutProgressCallback
PirutPackageList = PackageList.PirutPackageList
PirutGroupSelector = GroupSelector.GroupSelector
# lame main loop runner... this should probably just be where we need it
def _runGtkMain(*args):
while gtk.events_pending():
gtk.main_iteration()
YUM_PID_FILE = '/var/run/yum.pid'
class GraphicalYumBase(yum.YumBase):
# FIXME: this is pulled directly from yum/output.py just for debugging
def listTransaction(self):
"""returns a string rep of the transaction in an easy-to-read way."""
self.tsInfo.makelists()
if len(self.tsInfo) > 0:
out = """
=============================================================================
%-22s %-9s %-15s %-16s %-5s
=============================================================================
""" % ('Package', 'Arch', 'Version', 'Repository', 'Size')
else:
out = ""
for (action, pkglist) in [('Installing', self.tsInfo.installed),
('Updating', self.tsInfo.updated),
('Removing', self.tsInfo.removed),
('Installing for dependencies', self.tsInfo.depinstalled),
('Updating for dependencies', self.tsInfo.depupdated),
('Removing for dependencies', self.tsInfo.depremoved)]:
if pkglist:
totalmsg = "%s:\n" % action
for txmbr in pkglist:
(n,a,e,v,r) = txmbr.pkgtup
evr = txmbr.po.printVer()
repoid = txmbr.repoid
pkgsize = float(txmbr.po.size())
size = pkgsize
msg = " %-22s %-9s %-15s %-16s %5s\n" % (n, a,
evr, repoid, size)
for (obspo, relationship) in txmbr.relatedto:
if relationship == 'obsoletes':
appended = ' replacing %s.%s %s\n\n' % (obspo.name, obspo.arch, obspo.printVer())
msg = msg+appended
totalmsg = totalmsg + msg
if pkglist:
out = out + totalmsg
summary = """
Transaction Summary
=============================================================================
Install %5.5s Package(s)
Update %5.5s Package(s)
Remove %5.5s Package(s)
""" % (len(self.tsInfo.installed + self.tsInfo.depinstalled),
len(self.tsInfo.updated + self.tsInfo.depupdated),
len(self.tsInfo.removed + self.tsInfo.depremoved))
out = out + summary
return out
def __init__(self, run_long = True, configfn = "/etc/yum.conf"):
"""run_long is whether or not to run 'long' steps."""
self.logfile = None
yum.YumBase.__init__(self)
try:
self.doConfigSetup(configfn)
except yum.Errors.ConfigError, e:
raise PirutError, e
self.doPluginSetup(types=(yum.plugins.TYPE_CORE,))
self.closeRpmDB()
self.doTsSetup()
self.unsignedok = False
if run_long:
self.reposSetup()
def reposSetup(self, callback = None):
if callback:
self.repos.callback = callback
callback.num_tasks += 10
self.doLock(YUM_PID_FILE)
self.doRpmDBSetup()
if callback: callback.next_task()
try:
self.doRepoSetup()
except yum.Errors.RepoError, e:
raise PirutDownloadError, e
if callback: callback.next_task()
try:
self.doGroupSetup()
except yum.Errors.GroupsError:
self.errorlog(1, "no groups present!")
if callback: callback.next_task(next = 5) # hack... next should be long
self.doSackSetup()
if callback: callback.next_task(incr=3)
if callback: self.repos.callback = None
def errorlog(self, level, msg):
_runGtkMain()
if level <= 0:
print >> sys.stderr, "ERROR:", msg
else:
print >> sys.stderr, "WARNING:", msg
def log(self, level, msg):
_runGtkMain()
if level <= 0:
print >> sys.stderr, "LOG:", msg
def filelog(self, level, msg):
_runGtkMain()
if self.logfile:
self.logfile(level, msg)
def simpleDBInstalled(self, name):
# FIXME: doing this directly instead of using self.rpmdb.installed()
# speeds things up by 400%
mi = self.ts.ts.dbMatch('name', name)
if mi.count() > 0:
return True
return False
def isPackageInstalled(self, name = None, epoch = None, version = None,
release = None, arch = None, po = None):
# FIXME: this sucks. we should probably suck it into yum proper
# but it'll need a bit of cleanup first.
if po is not None:
(name, epoch, version, release, arch) = po.returnNevraTuple()
installed = False
if name and not (epoch or version or release or arch):
installed = self.simpleDBInstalled(name)
elif self.rpmdb.installed(name = name, epoch = epoch, ver = version,
rel = release, arch = arch):
installed = True
lst = self.tsInfo.matchNaevr(name = name, epoch = epoch,
ver = version, rel = release,
arch = arch)
for txmbr in lst:
if txmbr.output_state in TS_INSTALL_STATES:
return True
if installed and len(lst) > 0:
# if we get here, then it was installed, but it's in the tsInfo
# for an erase or obsoleted --> not going to be installed at end
return False
return installed
def isGroupInstalled(self, grp):
if grp.selected:
return True
elif grp.installed and not grp.toremove:
return True
return False
def deselectGroup(self, grpid):
group = self.comps.return_group(grpid)
if group.selected:
yum.YumBase.deselectGroup(self, grpid)
else:
self.groupRemove(grpid)
def selectGroup(self, grpid):
group = self.comps.return_group(grpid)
if group.toremove:
self.groupUnremove(grpid)
else:
yum.YumBase.selectGroup(self, grpid)
def _getKeyForPackage(self, po, mainwin = None):
# FIXME: this should be in yum. it's basically straight out of
# yum/cli.py. the userconfirm stuff is a little silly, though
repo = self.repos.getRepo(po.repoid)
keyurls = repo.gpgkey
key_installed = False
for keyurl in keyurls:
self.log(1, 'Retrieving GPG key from %s' % keyurl)
# Go get the GPG key from the given URL
try:
rawkey = urlgrabber.urlread(keyurl, limit=9999)
except urlgrabber.grabber.URLGrabError, e:
raise yum.Errors.YumBaseError('GPG key retrieval failed: ' +
str(e))
# Parse the key
try:
keyinfo = yum.misc.getgpgkeyinfo(rawkey)
keyid = keyinfo['keyid']
hexkeyid = yum.misc.keyIdToRPMVer(keyid).upper()
timestamp = keyinfo['timestamp']
userid = keyinfo['userid']
except ValueError, e:
raise yum.Errors.YumBaseError, \
'GPG key parsing failed: ' + str(e)
# Check if key is already installed
if yum.misc.keyInstalled(self.read_ts, keyid, timestamp) >= 0:
self.errorlog(1, 'GPG key at %s (0x%s) is already installed' % (
keyurl, hexkeyid))
continue
# Try installing/updating GPG key
self.log(1, 'Importing GPG key 0x%s "%s"' % (hexkeyid, userid))
if hasattr(self.conf, "getConfigOption"):
opt = self.conf.getConfigOption('assumeyes')
else:
opt = self.conf.assumeyes
if not opt:
d = gtk.MessageDialog(mainwin, gtk.DIALOG_MODAL,
gtk.MESSAGE_QUESTION,
message_format = _("Import key?"))
sec = gobject.markup_escape_text(
_("The package %s is signed with a key "
"from %s (0x%s). Would you like to "
"import this key?") %(po, userid, hexkeyid))
d.format_secondary_text(sec)
b = d.add_button('gtk-cancel', gtk.RESPONSE_CANCEL)
b = d.add_button(_("_Import key"), gtk.RESPONSE_OK)
b.set_image(gtk.image_new_from_stock(gtk.STOCK_OK,
gtk.ICON_SIZE_BUTTON))
rc = d.run()
d.destroy()
if rc != gtk.RESPONSE_OK:
raise yum.Errors.YumBaseError, "Not installing key"
# Import the key
result = self.ts.pgpImportPubkey(yum.misc.procgpgkey(rawkey))
if result != 0:
raise yum.Errors.YumBaseError, \
'Key import failed (code %d)' % result
self.log(1, 'Key imported successfully')
key_installed = True
if not key_installed:
raise yum.Errors.YumBaseError, \
'The GPG keys listed for the "%s" repository are ' \
'already installed but they are not correct for this ' \
'package.\n' \
'Check that the correct key URLs are configured for ' \
'this repository.' % (repo.name)
# Check if the newly installed keys helped
result, errmsg = self.sigCheckPkg(po)
if result != 0:
self.log(0, "Import of key(s) didn't help, wrong key(s)?")
raise yum.Errors.YumBaseError, errmsg
def downloadPackages(self, mainwin):
class dlcb(urlgrabber.progress.BaseMeter):
def __init__(self, pbar, dlpkgs):
urlgrabber.progress.BaseMeter.__init__(self)
self.pbar = pbar
self.total = float(len(dlpkgs))
self.current = 0
self.last = 0
def _do_start(self, now):
txt = _("Downloading %s") %(urllib2.unquote(self.basename),)
self.pbar.set_markup("<i>%s</i>" %(txt,))
def _do_end(self, amount_read, now=None):
self.current += 1
self.pbar.set_fraction(self.current / self.total)
def update(self, amount_read, now=None):
urlgrabber.progress.BaseMeter.update(self, amount_read, now)
def _do_update(self, amount_read, now=None):
if self.size is None:
return
pct = float(amount_read) / self.size
curval = self.pbar.get_fraction()
newval = (pct * 1/self.total) + (self.current / self.total)
if newval > curval + 0.001 or time.time() > self.last + 1:
self.pbar.set_fraction(newval)
_runGtkMain()
self.last = time.time()
def downloadErrorDialog(mainwin, secondary, details = None):
d = PirutDetailsDialog(mainwin, gtk.MESSAGE_ERROR,
[('gtk-ok', gtk.RESPONSE_OK)],
_("Error downloading packages"),
secondary)
if details:
d.set_details("%s" %(details,))
d.run()
d.destroy()
raise PirutDownloadError
dlpkgs = map(lambda x: x.po, filter(lambda txmbr:
txmbr.ts_state in ("i", "u"),
self.tsInfo.getMembers()))
pbar = PirutProgress(_("Downloading packages"), mainwin)
dlCb = dlcb(pbar, dlpkgs)
self.repos.setProgressBar(dlCb)
pbar.show()
try:
probs = self.downloadPkgs(dlpkgs)
except yum.Errors.RepoError, errmsg:
downloadErrorDialog(mainwin, secondary = None, details = errmsg)
except IndexError:
downloadErrorDialog(mainwin, _("Unable to find a suitable mirror."))
self.repos.setProgressBar(None)
pbar.destroy()
if len(probs.keys()) > 0:
errstr = []
for key in probs.keys():
errors = yum.misc.unique(probs[key])
for error in errors:
errstr.append("%s: %s" %(key, error))
downloadErrorDialog(mainwin, _("Errors were encountered while "
"downloading packages."),
details = string.join(errstr, "\n"))
return dlpkgs
def checkDeps(self, mainwin):
class dscb:
def __init__(self, pbar, ayum):
self.log = ayum.log
self.errorlog = ayum.errorlog
self.pbar = pbar
# if we run pending events when we get a callback, things
# seem more responsive which is good (tm)
self.pkgAdded = self.procReq = self.transactionPopulation = self.downloadHeader = self.tscheck = self.start = self.unresolved = self.procConflict = _runGtkMain
def restartLoop(self):
cur = self.pbar.get_fraction()
new = ((1.0 - cur) / 2) + cur
self.pbar.set_fraction(new)
_runGtkMain()
def end(self):
self.pbar.set_fraction(1.0)
_runGtkMain()
pbar = PirutProgress(_("Resolving dependencies for updates"), mainwin)
dsCB = dscb(pbar, self)
self.dsCallback = dsCB
pbar.show()
try:
(result, msgs) = self.buildTransaction()
except yum.Errors.RepoError, errmsg:
self.dsCallback = None # we only wanted this here. blah.
pbar.destroy()
d = PirutDetailsDialog(mainwin, gtk.MESSAGE_ERROR,
[('gtk-ok', gtk.RESPONSE_OK)],
_("Error downloading headers"),
_("Errors were encountered while "
"downloading package headers."))
d.set_details("%s" %(errmsg,))
d.run()
d.destroy()
raise PirutDownloadError
self.dsCallback = None # we only wanted this here. blah.
pbar.destroy()
if result == 1:
d = PirutDetailsDialog(mainwin, gtk.MESSAGE_ERROR,
[('gtk-ok', gtk.RESPONSE_OK)],
_("Error resolving dependencies"),
_("Unable to resolve dependencies for some "
"packages selected for installation."))
d.set_details(string.join(msgs, "\n"))
d.run()
d.destroy()
raise PirutDependencyError
def depDetails(self, mainwin):
self.tsInfo.makelists()
if (len(self.tsInfo.depinstalled) > 0 or
len(self.tsInfo.depupdated) > 0 or
len(self.tsInfo.depremoved) > 0):
d = PirutDetailsDialog(mainwin, gtk.MESSAGE_INFO,
[('gtk-cancel', gtk.RESPONSE_CANCEL),
(_("Continue"), gtk.RESPONSE_OK, 'gtk-ok')],
_("Dependencies added"),
_("Updating these packages requires "
"additional updates for proper "
"operation."))
b = gtk.TextBuffer()
tag = b.create_tag('bold')
tag.set_property('weight', pango.WEIGHT_BOLD)
tag = b.create_tag('indented')
tag.set_property('left-margin', 10)
types=[(self.tsInfo.depinstalled,_("Adding for dependencies:\n")),
(self.tsInfo.depremoved, _("Removing for dependencies:\n")),
(self.tsInfo.depupdated, _("Updating for dependencies:\n"))]
for (lst, strng) in types:
if len(lst) > 0:
i = b.get_end_iter()
b.insert_with_tags_by_name(i, strng, "bold")
for txmbr in lst:
i = b.get_end_iter()
(n,a,e,v,r) = txmbr.pkgtup
b.insert_with_tags_by_name(i, "%s-%s-%s\n" % (n,v,r),
"indented")
d.set_details(buffer = b)
rc = d.run(timeout=20)
d.destroy()
if rc != gtk.RESPONSE_OK:
raise PirutError
def checkSignatures(self, pkgs, mainwin):
pbar = PirutProgress(_("Verifying packages"), mainwin)
num = float(len(pkgs))
i = 1
for po in pkgs:
result, errmsg = self.sigCheckPkg(po)
pbar.set_fraction(i / num)
i+=1
if result == 0:
continue
elif result == 1:
found = True
try:
self._getKeyForPackage(po, mainwin)
except yum.Errors.YumBaseError, errmsg:
found = False
if found:
continue
# if we got here, either it failed to verify originally or failed
# when we attempted to do an automagic import
d = PirutDetailsDialog(mainwin, gtk.MESSAGE_ERROR,
text = _("Unable to verify %s") %(po,))
d.set_details("%s" %(errmsg,))
if not self.unsignedok:
pbar.destroy()
d.add_button(_("_Close"), gtk.RESPONSE_CLOSE, 'gtk-close')
else:
d.format_secondary_markup(_("Malicious software can damage "
"your computer or cause other "
"harm. Are you sure you wish "
"to install this package?"))
b = d.add_button(_("_Cancel"), gtk.RESPONSE_CANCEL,
'gtk-cancel')
b = d.add_button(_("_Install anyway"), gtk.RESPONSE_OK,
'gtk-ok')
d.set_default_response(gtk.RESPONSE_CANCEL)
rc = d.run()
d.destroy()
if rc != gtk.RESPONSE_OK:
raise PirutVerifyError
pbar.destroy()
def runTransaction(self, mainwin):
def transactionErrors(errs):
d = PirutDetailsDialog(mainwin, gtk.MESSAGE_ERROR,
buttons = [('gtk-ok', 0)],
text = _("Error updating software"))
d.format_secondary_text(_("There were errors encountered in "
"trying to update the software "
"you selected"))
d.set_details("%s" %(errs,))
d.run()
d.destroy()
# FIXME: it's not always updating...
pbar = PirutProgress(_("Updating software"), mainwin)
tsprog = PirutTransactionProgress(pbar)
del self.ts
self.initActionTs() # make a new, blank ts to populate
self.populateTs(keepold=0)
self.ts.check() #required for ordering
self.ts.order() # order
tsprog.filelog = self.filelog
tsprog.tsInfo = self.tsInfo
pbar.show()
try:
tserrors = yum.YumBase.runTransaction(self, tsprog)
except yum.Errors.YumBaseError, err:
# FIXME: these errors are actually pretty bad and should be
# formatted better
pbar.destroy()
transactionErrors(err)
raise PirutError
pbar.destroy()
def setupLogging(self, logfn = None):
# FIXME: this is all from yum/{cli,output}.py
def printtime():
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
now = time.localtime(time.time())
ret = months[int(time.strftime('%m', now)) - 1] + \
time.strftime(' %d %T ', now)
return ret
if logfn is None:
logfn = self.conf.logfile
logpath = os.path.dirname(logfn)
if not os.path.exists(logpath):
try:
os.makedirs(logpath, mode=0755)
except OSError, e:
self.errorlog(0, _('Cannot make directory for logfile %s' % logpath))
sys.exit(1)
try:
logfd = os.open(logfn, os.O_WRONLY |
os.O_APPEND | os.O_CREAT, 0644)
except OSError, e:
self.errorlog(0, _('Cannot open logfile %s' % logfn))
sys.exit(1)
logfile = os.fdopen(logfd, 'a')
fcntl.fcntl(logfd, fcntl.F_SETFD)
self.logfile = Logger(threshold = 10, file_object = logfile,
preprefix = printtime)
def applyChanges(self, mainwin):
"""Apply all of the packaging changes requested."""
# do depsolve. determine if we've added anything or not.
self.checkDeps(mainwin)
self.depDetails(mainwin)
# download and verify packages
dlpkgs = self.downloadPackages(mainwin)
self.checkSignatures(dlpkgs, mainwin)
# run transaction
self.runTransaction(mainwin)
def quit(self, *args):
# FIXME: should make sure we close down access to lock files and dbs
# cleanly here
try:
self.closeRpmDB()
except Exception, e:
print >> sys.stderr, "Error closing rpmdb: ", e
self.doUnlock(YUM_PID_FILE)
try:
gtk.main_quit()
except:
pass
sys.exit(0)
def startupError(err):
d = PirutDetailsDialog(None, gtk.MESSAGE_ERROR,
[(_("Exit"), gtk.RESPONSE_OK, 'gtk-quit')],
_("Config error."),
_("Unable to start due to a configuration "
"error."))
d.set_details(str(err))
d.run()
d.destroy()
sys.exit(2)