326 lines
11 KiB
Python
326 lines
11 KiB
Python
#!/usr/bin/python -tt
|
|
# 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 Library 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.
|
|
#
|
|
# Copyright (C) 2007 Tim Lauridsen <timlau@fedoraproject.org>
|
|
# Copyright (C) 2007 Red Hat Inc, Seth Vidal <skvidal@fedoraproject.org>
|
|
# Copyright (C) 2007 Luke Macken <lmacken@redhat.com>
|
|
|
|
|
|
# imports
|
|
|
|
import sys
|
|
|
|
from packagekit import *
|
|
import yum
|
|
from urlgrabber.progress import BaseMeter,format_time,format_number
|
|
from yum.rpmtrans import RPMBaseCallback
|
|
from yum.constants import *
|
|
|
|
|
|
class PackageKitYumBackend(PackageKitBaseBackend):
|
|
|
|
def __init__(self,args):
|
|
PackageKitBaseBackend.__init__(self,args)
|
|
self.yumbase = yum.YumBase()
|
|
|
|
def _do_search(self,searchlist,opt,key):
|
|
'''
|
|
Search for yum packages
|
|
@param searchlist: The yum package fields to search in
|
|
@param opt: package types to search (all,installed,available)
|
|
@param key: key to seach for
|
|
'''
|
|
self.yumbase.conf.cache = 1 # Only look in cache.
|
|
res = self.yumbase.searchGenerator(searchlist, [key])
|
|
|
|
count = 1
|
|
for (pkg,values) in res:
|
|
print pkg
|
|
if count > 100:
|
|
break
|
|
count+=1
|
|
installed = '0'
|
|
|
|
# are we installed?
|
|
if self.yumbase.rpmdb.installed(pkg.name):
|
|
installed = '1'
|
|
|
|
# do we print to stdout?
|
|
do_print = 0;
|
|
if opt == 'installed' and installed == '1':
|
|
do_print = 1
|
|
elif opt == 'available' and installed == '0':
|
|
do_print = 1
|
|
elif opt == 'all':
|
|
do_print = 1
|
|
|
|
# print in correct format
|
|
if do_print == 1:
|
|
id = self.get_package_id(pkg.name, pkg.version, pkg.arch, pkg.repo)
|
|
self.package(id,installed, pkg.summary)
|
|
|
|
def search_name(self,opt,key):
|
|
'''
|
|
Implement the {backend}-search-nam functionality
|
|
'''
|
|
searchlist = ['name']
|
|
self._do_search(searchlist, opt, key)
|
|
|
|
def search_details(self,opt,key):
|
|
'''
|
|
Implement the {backend}-search-details functionality
|
|
'''
|
|
searchlist = ['name', 'summary', 'description', 'group']
|
|
self._do_search(searchlist, opt, key)
|
|
|
|
def get_deps(self,package):
|
|
'''
|
|
Print a list of dependencies for a given package
|
|
'''
|
|
res = self.yumbase.searchGenerator(['name'], [package])
|
|
|
|
for (pkg, name) in res:
|
|
if name[0] == package:
|
|
deps = self.yumbase.findDeps([pkg]).values()[0]
|
|
for deplist in deps.values():
|
|
for dep in deplist:
|
|
if not results.has_key(dep.name):
|
|
results[dep.name] = dep
|
|
break
|
|
|
|
for pkg in results.values():
|
|
id = self.get_package_id(pkg.name, pkg.version, pkg.arch, pkg.repo)
|
|
self.package(id, 1, pkg.summary)
|
|
|
|
def update_system(self):
|
|
'''
|
|
Implement the {backend}-update-system functionality
|
|
Needed to be implemented in a sub class
|
|
'''
|
|
self.error(ERROR_NOT_SUPPORTED,"This function is not implemented in this backend")
|
|
|
|
def refresh_cache(self):
|
|
'''
|
|
Implement the {backend}-refresh_cache functionality
|
|
Needed to be implemented in a sub class
|
|
'''
|
|
self.yumbase.doConfigSetup() # Setup Yum Config
|
|
callback = DownloadCallback(self) # Download callback
|
|
self.yumbase.repos.setProgressBar( callback ) # Setup the download callback class
|
|
pct = 0
|
|
self.percentage(pct)
|
|
try:
|
|
if len(self.yumbase.repos.listEnabled()) == 0:
|
|
self.percentage(100)
|
|
return
|
|
|
|
#work out the slice for each one
|
|
bump = (100/len(self.yumbase.repos.listEnabled()))/2
|
|
|
|
for repo in self.yumbase.repos.listEnabled():
|
|
repo.metadata_expire = 0
|
|
self.yumbase.repos.populateSack(which=[repo.id], mdtype='metadata', cacheonly=1)
|
|
pct+=bump
|
|
self.percentage(pct)
|
|
self.yumbase.repos.populateSack(which=[repo.id], mdtype='filelists', cacheonly=1)
|
|
pct+=bump
|
|
self.percentage(pct)
|
|
|
|
#we might have a rounding error
|
|
self.percentage(100)
|
|
|
|
except yum.Errors.YumBaseError, e:
|
|
self.error(ERROR_INTERNAL_ERROR,str(e))
|
|
|
|
def install(self, package):
|
|
'''
|
|
Implement the {backend}-install functionality
|
|
This will only work with yum 3.2.4 or higher
|
|
'''
|
|
self.yumbase.doConfigSetup() # Setup Yum Config
|
|
callback = DownloadCallback(self,showNames=True) # Download callback
|
|
self.yumbase.repos.setProgressBar( callback ) # Setup the download callback class
|
|
self.percentage(0)
|
|
txmbr = self.yumbase.install(name=package)
|
|
if txmbr:
|
|
self._runYumTransaction()
|
|
else:
|
|
self.error(ERROR_INTERNAL_ERROR,"Nothing to do")
|
|
|
|
def _runYumTransaction(self):
|
|
'''
|
|
Run the yum Transaction
|
|
This will only work with yum 3.2.4 or higher
|
|
'''
|
|
rc,msgs = self.yumbase.buildTransaction()
|
|
if rc !=2:
|
|
retmsg = "Error in Dependency Resolution\n" +"\n".join(msgs)
|
|
self.error(ERROR_DEP_RESOLUTION_FAILED,retmsg)
|
|
else:
|
|
try:
|
|
rpmDisplay = PackageKitCallback(self)
|
|
callback = ProcessTransPackageKitCallback(self)
|
|
self.yumbase.processTransaction(callback=callback,
|
|
rpmDisplay=rpmDisplay)
|
|
except yum.Errors.YumDownloadError, msgs:
|
|
retmsg = "Error in Download\n" +"\n".join(msgs)
|
|
self.error(ERROR_PACKAGE_DOWNLOAD_FAILED,retmsg)
|
|
except yum.Errors.YumGPGCheckError, msgs:
|
|
retmsg = "Error in Package Signatures\n" +"\n".join(msgs)
|
|
self.error(ERROR_INTERNAL_ERROR,retmsg)
|
|
except yum.Errors.YumBaseError, msgs:
|
|
retmsg = "Error in Transaction Processing\n" +"\n".join(msgs)
|
|
self.error(ERROR_INTERNAL_ERROR,retmsg)
|
|
|
|
def remove(self, allowdep, package):
|
|
'''
|
|
Implement the {backend}-remove functionality
|
|
Needed to be implemented in a sub class
|
|
'''
|
|
self.error(ERROR_NOT_SUPPORTED,"This function is not implemented in this backend")
|
|
|
|
def get_description(self, package):
|
|
'''
|
|
Print a detailed description for a given package
|
|
'''
|
|
res = self.yumbase.searchGenerator(['name'], [package])
|
|
for (pkg, name) in res:
|
|
if name[0] == package:
|
|
id = self.get_package_id(pkg.name, pkg.version,
|
|
pkg.arch, pkg.repo)
|
|
self.description(id, "%s-%s" % (pkg.version, pkg.release),
|
|
repr(pkg.description), pkg.url)
|
|
break
|
|
|
|
class DownloadCallback( BaseMeter ):
|
|
""" Customized version of urlgrabber.progress.BaseMeter class """
|
|
def __init__(self,base,showNames = False):
|
|
BaseMeter.__init__( self )
|
|
self.totSize = ""
|
|
self.base = base
|
|
self.showNames = showNames
|
|
self.oldName = None
|
|
self.lastPct = 0
|
|
|
|
def update( self, amount_read, now=None ):
|
|
BaseMeter.update( self, amount_read, now )
|
|
|
|
def _do_start( self, now=None ):
|
|
name = self._getName()
|
|
self.updateProgress(name,0.0,"","")
|
|
if not self.size is None:
|
|
self.totSize = format_number( self.size )
|
|
|
|
def _do_update( self, amount_read, now=None ):
|
|
fread = format_number( amount_read )
|
|
name = self._getName()
|
|
if self.size is None:
|
|
# Elapsed time
|
|
etime = self.re.elapsed_time()
|
|
fetime = format_time( etime )
|
|
frac = 0.0
|
|
self.updateProgress(name,frac,fread,fetime)
|
|
else:
|
|
# Remaining time
|
|
rtime = self.re.remaining_time()
|
|
frtime = format_time( rtime )
|
|
frac = self.re.fraction_read()
|
|
self.updateProgress(name,frac,fread,frtime)
|
|
|
|
|
|
def _do_end( self, amount_read, now=None ):
|
|
total_time = format_time( self.re.elapsed_time() )
|
|
total_size = format_number( amount_read )
|
|
name = self._getName()
|
|
self.updateProgress(name,1.0,total_size,total_time)
|
|
|
|
def _getName(self):
|
|
'''
|
|
Get the name of the package being downloaded
|
|
'''
|
|
if self.text and type( self.text ) == type( "" ):
|
|
name = self.text
|
|
else:
|
|
name = self.basename
|
|
return name
|
|
|
|
def updateProgress(self,name,frac,fread,ftime):
|
|
'''
|
|
Update the progressbar (Overload in child class)
|
|
@param name: filename
|
|
@param frac: Progress fracment (0 -> 1)
|
|
@param fread: formated string containing BytesRead
|
|
@param ftime : formated string containing remaining or elapsed time
|
|
'''
|
|
pct = int( frac*100 )
|
|
if self.lastPct != pct:
|
|
self.lastPct = pct
|
|
self.base.sub_percentage(int( frac*100 ))
|
|
if name != self.oldName:
|
|
self.oldName = name
|
|
if self.showNames:
|
|
self.base.data(name)
|
|
|
|
class PackageKitCallback(RPMBaseCallback):
|
|
def __init__(self,base):
|
|
RPMBaseCallback.__init__(self)
|
|
self.base = base
|
|
self.pct = 0
|
|
self.curpkg = None
|
|
self.actions = { 'Updating' : STATE_UPDATE,
|
|
'Erasing' : STATE_REMOVE,
|
|
'Installing' : STATE_INSTALL}
|
|
|
|
def event(self, package, action, te_current, te_total, ts_current, ts_total):
|
|
if str(package) != self.curpkg:
|
|
self.curpkg = str(package)
|
|
self.base.data(package)
|
|
print action
|
|
if action in TS_INSTALL_STATES:
|
|
self.base.status(STATE_INSTALL)
|
|
elif action in TS_REMOVE_STATES:
|
|
self.base.status(STATE_REMOVE)
|
|
val = (ts_current*100L)/ts_total
|
|
if val != self.pct:
|
|
self.pct = val
|
|
self.base.sub_percentage(val)
|
|
|
|
def errorlog(self, msg):
|
|
# grrrrrrrr
|
|
pass
|
|
|
|
PT_DOWNLOAD = 0
|
|
PT_GPGCHECK = 1
|
|
PT_TEST_TRANS = 2
|
|
PT_TRANSACTION = 3
|
|
|
|
class ProcessTransPackageKitCallback:
|
|
def __init__(self,base):
|
|
self.base = base
|
|
|
|
def event(self,state):
|
|
if state == PT_DOWNLOAD:
|
|
self.base.percentage(10)
|
|
self.base.status(STATE_DOWNLOAD)
|
|
elif state == PT_GPGCHECK:
|
|
self.base.percentage(40)
|
|
pass
|
|
elif state == PT_TEST_TRANS:
|
|
self.base.percentage(45)
|
|
pass
|
|
elif state == PT_TRANSACTION:
|
|
self.base.percentage(50)
|
|
pass
|