commit 7f49e9ef65bc592c31f881c8ab83275cfa3c9283
Author: Yi Yang <[email protected]>
Date: Wed Nov 17 16:21:21 2010 +0800
Add zypper package manager implementation
Note: with this commit, mic2 can work without yum dependency, but
this commit depends on libzypp-bindings, currently this implementation
is just experimental and still undergoing changes.
diff --git a/mic/appcreate/nand.py b/mic/appcreate/nand.py
index 9d56835..30c27f5 100644
--- a/mic/appcreate/nand.py
+++ b/mic/appcreate/nand.py
@@ -282,7 +282,14 @@ class NandImageCreator(ApplianceImageCreator):
yum_conf = self._mktemp(prefix = "yum.conf-")
self._required_pkgs = self._get_required_packages()
- pkg_manager = self.get_pkg_manager()
+
+ keep_record = None
+ if self._include_src:
+ keep_record = 'include_src'
+ if self._recording_pkgs in ('name', 'content'):
+ keep_record = self._recording_pkgs
+
+ pkg_manager = self.get_pkg_manager(keep_record, target_arch =
self.target_arch)
pkg_manager.setup(yum_conf, self._instroot)
for repo in kickstart.get_repos(self.ks, repo_urls):
@@ -332,6 +339,8 @@ class NandImageCreator(ApplianceImageCreator):
except CreatorError, e:
raise CreatorError("%s" % (e,))
finally:
+ if keep_record:
+ self._pkgs_content = pkg_manager.getAllContent()
pkg_manager.closeRpmDB()
pkg_manager.close()
os.unlink(yum_conf)
diff --git a/mic/imgcreate/creator.py b/mic/imgcreate/creator.py
index ee78b92..90fe744 100644
--- a/mic/imgcreate/creator.py
+++ b/mic/imgcreate/creator.py
@@ -785,7 +785,7 @@ class ImageCreator(object):
keep_record = None
if self._include_src:
keep_record = 'include_src'
- if self._recording_pkgs in ('name', 'contents'):
+ if self._recording_pkgs in ('name', 'content'):
keep_record = self._recording_pkgs
pkg_manager = self.get_pkg_manager(keep_record, target_arch =
self.target_arch)
@@ -1080,7 +1080,7 @@ class ImageCreator(object):
pkgmgr_instance = self.pkgmgr.get_default_pkg_manager()
if not pkgmgr_instance:
raise CreatorError("No pakcgae manager available")
- return pkgmgr_instance(recording_pkgs, target_arch)
+ return pkgmgr_instance(self, recording_pkgs, target_arch)
class LoopImageCreator(ImageCreator):
"""Installs a system into a loopback-mountable filesystem image.
diff --git a/mic/imgcreate/pkgmanagers/__init__.py
b/mic/imgcreate/pkgmanagers/__init__.py
index 4114403..d5f461e 100644
--- a/mic/imgcreate/pkgmanagers/__init__.py
+++ b/mic/imgcreate/pkgmanagers/__init__.py
@@ -46,6 +46,6 @@ class pkgManager:
exec("pkgmgr = %s._pkgmgr" % pkgmgrmod)
self.register_pkg_manager(pkgmgr[0], pkgmgr[1])
except:
- raise
+ continue
if not self.managers.keys():
raise CreatorError("No packag manager available")
diff --git a/mic/imgcreate/pkgmanagers/yumpkgmgr.py
b/mic/imgcreate/pkgmanagers/yumpkgmgr.py
index b19be72..2855606 100644
--- a/mic/imgcreate/pkgmanagers/yumpkgmgr.py
+++ b/mic/imgcreate/pkgmanagers/yumpkgmgr.py
@@ -33,9 +33,12 @@ import subprocess
from mic.imgcreate.errors import *
from mic.imgcreate.fs import *
+from mic.imgcreate.creator import ImageCreator
class Yum(yum.YumBase):
- def __init__(self, recording_pkgs=None, target_arch = None):
+ def __init__(self, creator, recording_pkgs=None, target_arch = None):
+ if not isinstance(creator, ImageCreator):
+ raise CreatorError("Invalid argument: creator")
yum.YumBase.__init__(self)
if target_arch:
if rpmUtils.arch.arches.has_key(target_arch):
@@ -45,6 +48,7 @@ class Yum(yum.YumBase):
self.__recording_pkgs = recording_pkgs
self.__pkgs_content = {}
+ self.creator = creator
def doFileLogSetup(self, uid, logfile):
# don't do the file log for the livecd as it can lead to open fds
diff --git a/mic/imgcreate/pkgmanagers/zypperpkgmgr.py
b/mic/imgcreate/pkgmanagers/zypperpkgmgr.py
index 567ff8a..f3e2002 100644
--- a/mic/imgcreate/pkgmanagers/zypperpkgmgr.py
+++ b/mic/imgcreate/pkgmanagers/zypperpkgmgr.py
@@ -1,7 +1,568 @@
#!/usr/bin/python
+import os
+import sys
+import glob
+import re
+import zypp
+import rpm
+import shutil
+import tempfile
+import urlparse
+import urllib2 as u2
+from mic.imgcreate.errors import *
+from mic.imgcreate.creator import ImageCreator
+import pykickstart.parser
+from mic.imgcreate.fs import *
+from mic.imgcreate.misc import *
+from mic.imgcreate.rpmmisc import *
+
+class RepositoryStub:
+ def __init__(self):
+ self.name = None
+ self.baseurl = []
+ self.mirrorlist = None
+ self.proxy = None
+ self.proxy_username = None
+ self.proxy_password = None
+ self.includepkgs = None
+ self.includepkgs = None
+ self.exclude = None
+
+ self.enabled = True
+ self.autorefresh = True
+ self.keeppackages = True
+
+class RepoError(CreatorError):
+ pass
+
+class RpmError(CreatorError):
+ pass
+
class Zypper:
- def __init__(self, recording_pkgs=None, target_arch = None):
+ def __init__(self, creator, recording_pkgs=None, target_arch = None):
+ if not isinstance(creator, ImageCreator):
+ raise CreatorError("Invalid argument: creator")
+
+ self.__recording_pkgs = recording_pkgs
+ self.__pkgs_content = {}
+ self.creator = creator
+ self.repos = []
+ self.packages = []
+ self.patterns = []
+ self.localpkgs = {}
+ self.repo_manager = None
+ self.repo_manager_options = None
+ self.Z = None
+ self.ts = None
+
+ def doFileLogSetup(self, uid, logfile):
+ # don't do the file log for the livecd as it can lead to open fds
+ # being left and an inability to clean up after ourself
pass
+ def closeRpmDB(self):
+ pass
+
+ def close(self):
+ try:
+ os.unlink(self.installroot + "/yum.conf")
+ except:
+ pass
+ self.closeRpmDB()
+ if not os.path.exists("/etc/fedora-release") and not
os.path.exists("/etc/meego-release"):
+ for i in range(3, os.sysconf("SC_OPEN_MAX")):
+ try:
+ os.close(i)
+ except:
+ pass
+
+ def __del__(self):
+ pass
+
+ def _writeConf(self, confpath, installroot):
+ conf = "[main]\n"
+ conf += "installroot=%s\n" % installroot
+ conf += "cachedir=/var/cache/yum\n"
+ conf += "plugins=0\n"
+ conf += "reposdir=\n"
+ conf += "failovermethod=priority\n"
+ conf += "http_caching=packages\n"
+
+ f = file(confpath, "w+")
+ f.write(conf)
+ f.close()
+
+ os.chmod(confpath, 0644)
+
+ def _cleanupRpmdbLocks(self, installroot):
+ # cleans up temporary files left by bdb so that differing
+ # versions of rpm don't cause problems
+ for f in glob.glob(installroot + "/var/lib/rpm/__db*"):
+ os.unlink(f)
+
+ def setup(self, confpath, installroot):
+ self._writeConf(confpath, installroot)
+ self._cleanupRpmdbLocks(installroot)
+ self.installroot = installroot
+
+ def selectPackage(self, pkg):
+ """Select a given package. Can be specified with name.arch or name*"""
+ if not self.Z:
+ self.__initialize_zypp()
+
+ found = False
+ for item in self.Z.pool():
+ kind = "%s" % item.kind()
+ if kind == "package":
+ name = "%s" % item.name()
+ if name == pkg:
+ found = True
+ if name not in self.packages:
+ self.packages.append(name)
+ item.status().setToBeInstalled (zypp.ResStatus.USER)
+
+ if found:
+ return None
+ else:
+ raise CreatorError("Unable to find package: %s" % (pkg,))
+
+ def deselectPackage(self, pkg):
+ if not self.Z:
+ self.__initialize_zypp()
+
+ """Deselect package. Can be specified as name.arch or name*"""
+ sp = pkg.rsplit(".", 2)
+ found = False
+ for item in self.Z.pool():
+ kind = "%s" % item.kind()
+ if kind == "package":
+ name = "%s" % item.name()
+ if name == sp[0]:
+ found = True
+ if item.status().isInstalled():
+ item.status().setToBeUninstalled (zypp.ResStatus.USER)
+ if name in self.packages:
+ self.packages.remove(name)
+
+
+ def selectGroup(self, grp, include = pykickstart.parser.GROUP_DEFAULT):
+ if not self.Z:
+ self.__initialize_zypp()
+ found = False
+ for item in self.Z.pool():
+ kind = "%s" % item.kind()
+ if kind == "pattern":
+ summary = "%s" % item.summary()
+ name = "%s" % item.name()
+ if name == grp.name or summary == grp.name:
+ found = True
+ if name not in self.patterns:
+ self.patterns.append(name)
+ item.status().setToBeInstalled (zypp.ResStatus.USER)
+ if found:
+ if include == pykickstart.parser.GROUP_REQUIRED:
+ map(lambda p: self.deselectPackage(p),
grp.default_packages.keys())
+ elif include == pykickstart.parser.GROUP_ALL:
+ map(lambda p: self.selectPackage(p),
grp.optional_packages.keys())
+ return None
+ else:
+ raise CreatorError("Unable to find pattern: %s" % (grp.name,))
+
+ def __checkAndDownloadURL(self, u2opener, url, savepath):
+ try:
+ if u2opener:
+ f = u2opener.open(url)
+ else:
+ f = u2.urlopen(url)
+ except u2.HTTPError, httperror:
+ if httperror.code in (404, 503):
+ return None
+ else:
+ raise CreatorError(httperror)
+ except OSError, oserr:
+ if oserr.errno == 2:
+ return None
+ else:
+ raise CreatorError(oserr)
+ except IOError, oserr:
+ if hasattr(oserr, "reason") and oserr.reason.errno == 2:
+ return None
+ else:
+ raise CreatorError(oserr)
+ except u2.URLError, err:
+ raise CreatorError(err)
+
+ # save to file
+ licf = open(savepath, "w")
+ licf.write(f.read())
+ licf.close()
+ f.close()
+
+ return savepath
+
+ def __pagerFile(self, savepath):
+ if os.path.splitext(savepath)[1].upper() in ('.HTM', '.HTML'):
+ pagers = ('w3m', 'links', 'lynx', 'less', 'more')
+ else:
+ pagers = ('less', 'more')
+
+ file_showed = None
+ for pager in pagers:
+ try:
+ subprocess.call([pager, savepath])
+ except OSError:
+ continue
+ else:
+ file_showed = True
+ break
+ if not file_showed:
+ f = open(savepath)
+ print f.read()
+ f.close()
+ raw_input('press <ENTER> to continue...')
+
+ def checkRepositoryEULA(self, name, repo):
+ """ This function is to check the LICENSE file if provided. """
+
+ # when proxy needed, make urllib2 follow it
+ proxy = repo.proxy
+ proxy_username = repo.proxy_username
+ proxy_password = repo.proxy_password
+
+ handlers = []
+ auth_handler =
u2.HTTPBasicAuthHandler(u2.HTTPPasswordMgrWithDefaultRealm())
+ u2opener = None
+ if proxy:
+ if proxy_username:
+ proxy_netloc = urlparse.urlsplit(proxy).netloc
+ if proxy_password:
+ proxy_url = 'http://%s:%...@%s' % (proxy_username,
proxy_password, proxy_netloc)
+ else:
+ proxy_url = 'http://%...@%s' % (proxy_username,
proxy_netloc)
+ else:
+ proxy_url = proxy
+
+ proxy_support = u2.ProxyHandler({'http': proxy_url,
+ 'ftp': proxy_url})
+ handlers.append(proxy_support)
+
+ # download all remote files to one temp dir
+ baseurl = None
+ repo_lic_dir = tempfile.mkdtemp(prefix = 'repolic')
+
+ for url in repo.baseurl:
+ if not url.endswith('/'):
+ url += '/'
+ tmphandlers = handlers
+ (scheme, host, path, parm, query, frag) = urlparse.urlparse(url)
+ if scheme not in ("http", "https", "ftp", "ftps", "file"):
+ raise CreateError("Error: invalid url %s" % url)
+ if '@' in host:
+ try:
+ user_pass, host = host.split('@', 1)
+ if ':' in user_pass:
+ user, password = user_pass.split(':', 1)
+ except ValueError, e:
+ raise CreateError('Bad URL: %s' % url)
+ print "adding HTTP auth: %s, %s" %(user, password)
+ auth_handler.add_password(None, host, user, password)
+ tmphandlers.append(auth_handler)
+ url = scheme + "://" + host + path + parm + query + frag
+ if len(tmphandlers) != 0:
+ u2opener = u2.build_opener(*tmphandlers)
+ # try to download
+ repo_eula_url = urlparse.urljoin(url, "LICENSE.txt")
+ repo_eula_path = self.__checkAndDownloadURL(
+ u2opener,
+ repo_eula_url,
+ os.path.join(repo_lic_dir, repo.id +
'_LICENSE.txt'))
+ if repo_eula_path:
+ # found
+ baseurl = url
+ break
+
+ if not baseurl:
+ return True
+
+ # show the license file
+ print 'For the software packages in this yum repo:'
+ print ' %s: %s' % (name, baseurl)
+ print 'There is an "End User License Agreement" file that need to be
checked.'
+ print 'Please read the terms and conditions outlined in it and answer
the followed qustions.'
+ raw_input('press <ENTER> to continue...')
+
+ self.__pagerFile(repo_eula_path)
+
+ # Asking for the "Accept/Decline"
+ accept = True
+ while accept:
+ input_accept = raw_input('Would you agree to the terms and
conditions outlined in the above End User License Agreement? (Yes/No): ')
+ if input_accept.upper() in ('YES', 'Y'):
+ break
+ elif input_accept.upper() in ('NO', 'N'):
+ accept = None
+ print 'Will not install pkgs from this repo.'
+
+ if not accept:
+ #cleanup
+ shutil.rmtree(repo_lic_dir)
+ return None
+
+ # try to find support_info.html for extra infomation
+ repo_info_url = urlparse.urljoin(baseurl, "support_info.html")
+ repo_info_path = self.__checkAndDownloadURL(
+ u2opener,
+ repo_info_url,
+ os.path.join(repo_lic_dir, repo.id +
'_support_info.html'))
+ if repo_info_path:
+ print 'There is one more file in the repo for additional support
information, please read it'
+ raw_input('press <ENTER> to continue...')
+ self.__pagerFile(repo_info_path)
+
+ #cleanup
+ shutil.rmtree(repo_lic_dir)
+ return True
+
+ def addRepository(self, name, url = None, mirrorlist = None, proxy = None,
proxy_username = None, proxy_password = None):
+ if not self.repo_manager:
+ self.__initialize_repo_manager()
+
+ repo = RepositoryStub()
+ repo.name = name
+ repo.id = name
+ repo.proxy = proxy
+ repo.proxy_username = proxy_username
+ repo.proxy_password = proxy_password
+ repo.baseurl.append(url)
+
+ # check LICENSE files
+ if not self.checkRepositoryEULA(name, repo):
+ return None
+
+ if mirrorlist:
+ repo.mirrorlist = mirrorlist
+
+ # Enable gpg check for verifying corrupt packages
+ repo.gpgcheck = 1
+ self.repos.append(repo)
+
+
+ repo_info = zypp.RepoInfo()
+ repo_info.setAlias(repo.id)
+ repo_info.setName(repo.name)
+ repo_info.setEnabled(repo.enabled)
+ repo_info.setAutorefresh(repo.autorefresh)
+ repo_info.setKeepPackages(repo.keeppackages)
+ repo_info.addBaseUrl(zypp.Url(repo.baseurl[0]))
+ self.repo_manager.addRepository(repo_info)
+ self.__build_repo_cache(name)
+
+ return repo
+
+ def installHasFile(self, file):
+ return False
+
+ def runInstall(self, checksize = 0):
+ os.environ["HOME"] = "/"
+ self.buildTransaction()
+
+ todo = zypp.GetResolvablesToInsDel(self.Z.pool())
+ installed_pkgs = todo._toInstall
+ dlpkgs = []
+ print "\n\nThese packages will be installed:"
+ for item in installed_pkgs:
+ if not zypp.isKindPattern(item):
+ dlpkgs.append(item)
+ print "%s" % item.name()
+
+ # record the total size of installed pkgs
+ pkgs_total_size = sum(map(lambda x: int(x.installSize()), dlpkgs))
+
+ # check needed size before actually download and install
+ if checksize and pkgs_total_size > checksize:
+ raise CreatorError("Size of specified root partition in kickstart
file is too small to install all selected packages.")
+
+ if self.__recording_pkgs:
+ # record all pkg and the content
+ for pkg in dlpkgs:
+ pkg_long_name = "%s.%s %s" % (pkg.name(), pkg.arch(),
pkg.edition())
+ self.__pkgs_content[pkg_long_name] = {} #TBD: to get file list
+
+ total_count = len(dlpkgs)
+ cached_count = 0
+ localpkgs = self.localpkgs.keys()
+ for po in dlpkgs:
+ """ Check if it is cached locally """
+ if po.name() in localpkgs:
+ cached_count += 1
+ else:
+ local = self.getLocalPkgPath(po)
+ if os.path.exists(local):
+ cached_count += 1
+ print "%d packages to be installed, %d packages gotten from cache, %d
packages to be downloaded" % (total_count, cached_count, total_count -
cached_count)
+ try:
+ self.downloadPkgs(dlpkgs)
+ self.installPkgs(dlpkgs)
+
+ except RepoError, e:
+ raise CreatorError("Unable to download from repo : %s" % (e,))
+ except RpmError, e:
+ raise CreatorError("Unable to install: %s" % (e,))
+
+ def getAllContent(self):
+ return self.__pkgs_content
+
+ def __initialize_repo_manager(self):
+ if self.repo_manager:
+ return
+
+ """ Clean up repo metadata """
+ shutil.rmtree(self.creator.cachedir + "/var", ignore_errors = True)
+ shutil.rmtree(self.creator.cachedir + "/etc", ignore_errors = True)
+ shutil.rmtree(self.creator.cachedir + "/raw", ignore_errors = True)
+ shutil.rmtree(self.creator.cachedir + "/solv", ignore_errors = True)
+
+ zypp.KeyRing.setDefaultAccept( zypp.KeyRing.ACCEPT_UNSIGNED_FILE
+ |
zypp.KeyRing.ACCEPT_VERIFICATION_FAILED
+ | zypp.KeyRing.ACCEPT_UNKNOWNKEY
+ | zypp.KeyRing.TRUST_KEY_TEMPORARILY
+ )
+ self.repo_manager_options =
zypp.RepoManagerOptions(zypp.Pathname(self.creator._instroot))
+ self.repo_manager_options.knownReposPath =
zypp.Pathname(self.creator.cachedir + "/etc/zypp/repos.d")
+ self.repo_manager_options.repoCachePath =
zypp.Pathname(self.creator.cachedir + "/var/cache/zypp")
+ self.repo_manager_options.repoRawCachePath =
zypp.Pathname(self.creator.cachedir + "/raw")
+ self.repo_manager_options.repoSolvCachePath =
zypp.Pathname(self.creator.cachedir + "/solv")
+ self.repo_manager_options.repoPackagesCachePath =
zypp.Pathname(self.creator.cachedir + "/packages")
+
+ self.repo_manager = zypp.RepoManager(self.repo_manager_options)
+
+
+ def __build_repo_cache(self, name):
+ repos = self.repo_manager.knownRepositories()
+ for repo in repos:
+ if not repo.enabled():
+ continue
+ reponame = "%s" % repo.name()
+ if reponame != name:
+ continue
+ if self.repo_manager.isCached( repo ):
+ return
+ print "Retrieving repo metedata from %s ..." % repo.url()
+ self.repo_manager.buildCache( repo, zypp.RepoManager.BuildIfNeeded
)
+
+
+ def __initialize_zypp(self):
+ if self.Z:
+ return
+
+ """ repoPackagesCachePath is corrected by this """
+ self.repo_manager = zypp.RepoManager(self.repo_manager_options)
+ repos = self.repo_manager.knownRepositories()
+ for repo in repos:
+ if not repo.enabled():
+ continue
+ if not self.repo_manager.isCached( repo ):
+ print "Retrieving repo metedata from %s ..." % repo.url()
+ self.repo_manager.buildCache( repo,
zypp.RepoManager.BuildIfNeeded )
+ else:
+ self.repo_manager.refreshMetadata(repo,
zypp.RepoManager.BuildIfNeeded)
+ self.repo_manager.loadFromCache( repo );
+
+ self.Z = zypp.ZYppFactory_instance().getZYpp()
+ self.Z.initializeTarget( zypp.Pathname(self.creator._instroot) )
+ self.Z.target().load();
+
+
+ def buildTransaction(self):
+ print self.packages
+ print self.patterns
+ if not self.Z.resolver().resolvePool():
+ print self.Z.resolver().problems()
+ #print "Problem count: %d" % len(self.Z.resolver().problems())
+ for problem in self.Z.resolver().problems():
+ print "%s" % problem
+ #raise CreatorError("Solver Error")
+ pass
+
+ def getLocalPkgPath(self, po):
+ repoinfo = po.repoInfo()
+ name = po.name()
+ cacheroot = repoinfo.packagesPath()
+ arch = po.arch()
+ version = po.edition()
+ pkgpath = "%s/%s/%s-%s.%s.rpm" % (cacheroot, arch, name, version, arch)
+ return pkgpath
+
+ def installLocal(self, pkg, po=None, updateonly=False):
+ if not self.ts:
+ self.__initialize_transaction()
+ pkgname = self.__get_pkg_name(pkg)
+ self.localpkgs[pkgname] = pkg
+ self.selectPackage(pkgname)
+
+ def __get_pkg_name(self, pkgpath):
+ h = readRpmHeader(self.ts, pkgpath)
+ return h["name"]
+
+ def downloadPkgs(self, package_objects):
+ localpkgs = self.localpkgs.keys()
+ for po in package_objects:
+ if po.name() in localpkgs:
+ continue
+ filename = self.getLocalPkgPath(po)
+ if os.path.exists(filename):
+ continue
+ dir = os.path.dirname(filename)
+ if not os.path.exists(dir):
+ makedirs(dir)
+ baseurl = "%s" % po.repoInfo().baseUrls()[0]
+ proxy = get_proxy(baseurl)
+ proxies = {}
+ if proxy:
+ proxies = {str(proxy.split(":")[0]):str(proxy)}
+
+ url = baseurl + "/%s/%s" % (po.arch(), os.path.basename(filename))
+ filename = myurlgrab(url, filename, proxies)
+
+ def installPkgs(self, package_objects):
+ if not self.ts:
+ self.__initialize_transaction()
+ localpkgs = self.localpkgs.keys()
+ for po in package_objects:
+ pkgname = po.name()
+ if pkgname in localpkgs:
+ rpmpath = self.localpkgs[pkgname]
+ else:
+ rpmpath = self.getLocalPkgPath(po)
+ if not os.path.exists(rpmpath):
+ raise RpmError("Error: %s doesn't exist" % rpmpath)
+ h = readRpmHeader(self.ts, rpmpath)
+ self.ts.addInstall(h, rpmpath, 'u')
+
+ unresolved_dependencies = self.ts.check()
+ if not unresolved_dependencies:
+ self.ts.order()
+ cb = RPMInstallCallback(self.ts)
+ self.ts.run(cb.callback, '')
+ self.ts.closeDB()
+ else:
+ print unresolved_dependencies
+ raise RepoError("Error: Unresolved dependencies, transaction
failed.")
+
+ def __initialize_transaction(self):
+ if not self.ts:
+ self.ts = rpm.TransactionSet(self.creator._instroot)
+ # Set to not verify DSA signatures.
+ self.ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS)
+
+ def zypp_install(self):
+ policy = zypp.ZYppCommitPolicy()
+ policy.downloadMode(zypp.DownloadInAdvance)
+ policy.dryRun( False )
+ policy.syncPoolAfterCommit( False )
+ result = self.Z.commit( policy )
+ print result
+
_pkgmgr = ["zypper", Zypper]
+
diff --git a/mic/imgcreate/rpmmisc.py b/mic/imgcreate/rpmmisc.py
new file mode 100644
index 0000000..a1fe7e6
--- /dev/null
+++ b/mic/imgcreate/rpmmisc.py
@@ -0,0 +1,146 @@
+import rpm, os, sys, re
+
+class RPMInstallCallback:
+ """
+ command line callback class for callbacks from the RPM library.
+ """
+
+ def __init__(self, ts, output=1):
+ self.output = output
+ self.callbackfilehandles = {}
+ self.total_actions = 0
+ self.total_installed = 0
+ self.installed_pkg_names = []
+ self.total_removed = 0
+ self.mark = "#"
+ self.marks = 27
+ self.lastmsg = None
+ self.tsInfo = None # this needs to be set for anything else to work
+ self.ts = ts
+
+ 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 _localprint(self, msg):
+ if self.output:
+ print msg
+
+ def _makefmt(self, percent, progress = True):
+ l = len(str(self.total_actions))
+ size = "%s.%s" % (l, l)
+ fmt_done = "[%" + size + "s/%" + size + "s]"
+ done = fmt_done % (self.total_installed + self.total_removed,
+ self.total_actions)
+ marks = self.marks - (2 * l)
+ width = "%s.%s" % (marks, marks)
+ fmt_bar = "%-" + width + "s"
+ if progress:
+ bar = fmt_bar % (self.mark * int(marks * (percent / 100.0)), )
+ fmt = "\r %-10.10s: %-28.28s " + bar + " " + done
+ else:
+ bar = fmt_bar % (self.mark * marks, )
+ fmt = " %-10.10s: %-28.28s " + bar + " " + done
+ return fmt
+
+ def _logPkgString(self, hdr):
+ """return nice representation of the package for the log"""
+ (n,a,e,v,r) = self._dopkgtup(hdr)
+ if e == '0':
+ pkg = '%s.%s %s-%s' % (n, a, v, r)
+ else:
+ pkg = '%s.%s %s:%s-%s' % (n, a, e, v, r)
+
+ return pkg
+
+ def callback(self, what, bytes, total, h, user):
+ if what == rpm.RPMCALLBACK_TRANS_START:
+ if bytes == 6:
+ self.total_actions = total
+
+ elif what == rpm.RPMCALLBACK_TRANS_PROGRESS:
+ pass
+
+ elif what == rpm.RPMCALLBACK_TRANS_STOP:
+ pass
+
+ elif what == rpm.RPMCALLBACK_INST_OPEN_FILE:
+ self.lastmsg = None
+ hdr = None
+ if h is not None:
+ rpmloc = h
+ hdr = readRpmHeader(self.ts, h)
+ handle = self._makeHandle(hdr)
+ fd = os.open(rpmloc, os.O_RDONLY)
+ self.callbackfilehandles[handle]=fd
+ self.total_installed += 1
+ self.installed_pkg_names.append(hdr['name'])
+ return fd
+ else:
+ self._localprint("No header - huh?")
+
+ elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE:
+ hdr = None
+ if h is not None:
+ rpmloc = h
+ hdr = readRpmHeader(self.ts, h)
+ handle = self._makeHandle(hdr)
+ os.close(self.callbackfilehandles[handle])
+ fd = 0
+
+ # log stuff
+ pkgtup = self._dopkgtup(hdr)
+
+
+ elif what == rpm.RPMCALLBACK_INST_PROGRESS:
+ if h is not None:
+ if total == 0:
+ percent = 0
+ else:
+ percent = (bytes*100L)/total
+ m = re.match("(.*)-(\d+.*)-(\d+\.\d+)\.(.+)\.rpm",
os.path.basename(h))
+ if m:
+ pkgname = m.group(1)
+ else:
+ pkgname = os.path.basename(h)
+ if self.output and (sys.stdout.isatty() or bytes == total):
+ fmt = self._makefmt(percent)
+ msg = fmt % ("Installing", pkgname)
+ if msg != self.lastmsg:
+ sys.stdout.write(msg)
+ sys.stdout.flush()
+ self.lastmsg = msg
+ if bytes == total:
+ print " "
+
+ elif what == rpm.RPMCALLBACK_UNINST_START:
+ pass
+
+ elif what == rpm.RPMCALLBACK_UNINST_PROGRESS:
+ pass
+
+ elif what == rpm.RPMCALLBACK_UNINST_STOP:
+ self.total_removed += 1
+
+ elif what == rpm.RPMCALLBACK_REPACKAGE_START:
+ pass
+ elif what == rpm.RPMCALLBACK_REPACKAGE_STOP:
+ pass
+ elif what == rpm.RPMCALLBACK_REPACKAGE_PROGRESS:
+ pass
+
+def readRpmHeader(ts, filename):
+ """ Read an rpm header. """
+ fd = os.open(filename, os.O_RDONLY)
+ h = ts.hdrFromFdno(fd)
+ os.close(fd)
+ return h
_______________________________________________
MeeGo-dev mailing list
[email protected]
http://lists.meego.com/listinfo/meego-dev