#!/usr/bin/python -tt # # Copyright (c) 2010, 2011 Intel, 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; version 2 of the License # # 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 import shutil import urlparse import rpm import zypp if not hasattr(zypp, 'PoolQuery') or \ not hasattr(zypp.RepoManager, 'loadSolvFile'): raise ImportError("python-zypp in host system cannot support PoolQuery or " "loadSolvFile interface, please update it to enhanced " "version which can be found in download.tizen.org/tools") from mic import msger from mic.kickstart import ksparser from mic.utils import misc, rpmmisc, runner, fs_related from mic.utils.grabber import myurlgrab, TextProgress from mic.utils.proxy import get_proxy_for from mic.utils.errors import CreatorError, RepoError, RpmError from mic.imager.baseimager import BaseImageCreator 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.nocache = False self.enabled = True self.autorefresh = True self.keeppackages = True self.priority = None from mic.pluginbase import BackendPlugin class Zypp(BackendPlugin): name = 'zypp' def __init__(self, target_arch, instroot, cachedir): self.cachedir = cachedir self.instroot = instroot self.target_arch = target_arch self.__pkgs_license = {} self.__pkgs_content = {} self.__pkgs_vcsinfo = {} self.repos = [] self.to_deselect = [] self.localpkgs = {} self.repo_manager = None self.repo_manager_options = None self.Z = None self.ts = None self.ts_pre = None self.incpkgs = {} self.excpkgs = {} self.pre_pkgs = [] self.probFilterFlags = [ rpm.RPMPROB_FILTER_OLDPACKAGE, rpm.RPMPROB_FILTER_REPLACEPKG ] self.has_prov_query = True self.install_debuginfo = False 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): if self.ts: self.ts.closeDB() self.ts = None if self.ts_pre: self.ts_pre.closeDB() self.ts = None 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): self.close() def _cleanupRpmdbLocks(self, installroot): # cleans up temporary files left by bdb so that differing # versions of rpm don't cause problems import glob for f in glob.glob(installroot + "/var/lib/rpm/__db*"): os.unlink(f) def _cleanupZyppJunk(self, installroot): try: shutil.rmtree(os.path.join(installroot, '.zypp')) except: pass def setup(self): self._cleanupRpmdbLocks(self.instroot) def whatObsolete(self, pkg): query = zypp.PoolQuery() query.addKind(zypp.ResKind.package) query.addAttribute(zypp.SolvAttr.obsoletes, pkg) query.setMatchExact() for pi in query.queryResults(self.Z.pool()): return pi return None def _zyppQueryPackage(self, pkg): query = zypp.PoolQuery() query.addKind(zypp.ResKind.package) query.addAttribute(zypp.SolvAttr.name,pkg) query.setMatchExact() for pi in query.queryResults(self.Z.pool()): return pi return None def _splitPkgString(self, pkg): sp = pkg.rsplit(".",1) name = sp[0] arch = None if len(sp) == 2: arch = sp[1] sysarch = zypp.Arch(self.target_arch) if not zypp.Arch(arch).compatible_with (sysarch): arch = None name = ".".join(sp) return name, arch def selectPackage(self, pkg): """Select a given package or package pattern, can be specified with name.arch or name* or *name """ if not self.Z: self.__initialize_zypp() def markPoolItem(obs, pi): if obs == None: pi.status().setToBeInstalled (zypp.ResStatus.USER) else: obs.status().setToBeInstalled (zypp.ResStatus.USER) def cmpEVR(p1, p2): # compare criterion: arch compatibility first, then repo # priority, and version last a1 = p1.arch() a2 = p2.arch() if str(a1) != str(a2): if a1.compatible_with(a2): return -1 else: return 1 # Priority of a repository is an integer value between 0 (the # highest priority) and 99 (the lowest priority) pr1 = int(p1.repoInfo().priority()) pr2 = int(p2.repoInfo().priority()) if pr1 > pr2: return -1 elif pr1 < pr2: return 1 ed1 = p1.edition() ed2 = p2.edition() (e1, v1, r1) = map(str, [ed1.epoch(), ed1.version(), ed1.release()]) (e2, v2, r2) = map(str, [ed2.epoch(), ed2.version(), ed2.release()]) return rpm.labelCompare((e1, v1, r1), (e2, v2, r2)) found = False startx = pkg.startswith("*") endx = pkg.endswith("*") ispattern = startx or endx name, arch = self._splitPkgString(pkg) q = zypp.PoolQuery() q.addKind(zypp.ResKind.package) if ispattern: if startx and not endx: pattern = '%s$' % (pkg[1:]) if endx and not startx: pattern = '^%s' % (pkg[0:-1]) if endx and startx: pattern = '%s' % (pkg[1:-1]) q.setMatchRegex() q.addAttribute(zypp.SolvAttr.name,pattern) elif arch: q.setMatchExact() q.addAttribute(zypp.SolvAttr.name,name) else: q.setMatchExact() q.addAttribute(zypp.SolvAttr.name,pkg) for pitem in sorted( q.queryResults(self.Z.pool()), cmp=lambda x,y: cmpEVR(zypp.asKindPackage(x), zypp.asKindPackage(y)), reverse=True): item = zypp.asKindPackage(pitem) if item.name() in self.excpkgs.keys() and \ self.excpkgs[item.name()] == item.repoInfo().name(): continue if item.name() in self.incpkgs.keys() and \ self.incpkgs[item.name()] != item.repoInfo().name(): continue found = True obspkg = self.whatObsolete(item.name()) if arch: if arch == str(item.arch()): item.status().setToBeInstalled (zypp.ResStatus.USER) else: markPoolItem(obspkg, pitem) if not ispattern: break # Can't match using package name, then search from packge # provides infomation if found == False and not ispattern: q.addAttribute(zypp.SolvAttr.provides, pkg) q.addAttribute(zypp.SolvAttr.name,'') for pitem in sorted( q.queryResults(self.Z.pool()), cmp=lambda x,y: cmpEVR(zypp.asKindPackage(x), zypp.asKindPackage(y)), reverse=True): item = zypp.asKindPackage(pitem) if item.name() in self.excpkgs.keys() and \ self.excpkgs[item.name()] == item.repoInfo().name(): continue if item.name() in self.incpkgs.keys() and \ self.incpkgs[item.name()] != item.repoInfo().name(): continue found = True obspkg = self.whatObsolete(item.name()) markPoolItem(obspkg, pitem) break if found: return None else: raise CreatorError("Unable to find package: %s" % (pkg,)) def inDeselectPackages(self, pitem): """check if specified pacakges are in the list of inDeselectPackages """ item = zypp.asKindPackage(pitem) name = item.name() for pkg in self.to_deselect: startx = pkg.startswith("*") endx = pkg.endswith("*") ispattern = startx or endx pkgname, pkgarch = self._splitPkgString(pkg) if not ispattern: if pkgarch: if name == pkgname and str(item.arch()) == pkgarch: return True; else: if name == pkgname: return True; else: if startx and name.endswith(pkg[1:]): return True; if endx and name.startswith(pkg[:-1]): return True; return False; def deselectPackage(self, pkg): """collect packages should not be installed""" self.to_deselect.append(pkg) def selectGroup(self, grp, include = ksparser.GROUP_DEFAULT): if not self.Z: self.__initialize_zypp() found = False q=zypp.PoolQuery() q.addKind(zypp.ResKind.pattern) for pitem in q.queryResults(self.Z.pool()): item = zypp.asKindPattern(pitem) summary = "%s" % item.summary() name = "%s" % item.name() if name == grp or summary == grp: found = True pitem.status().setToBeInstalled (zypp.ResStatus.USER) break if found: if include == ksparser.GROUP_REQUIRED: map( lambda p: self.deselectPackage(p), grp.default_packages.keys()) return None else: raise CreatorError("Unable to find pattern: %s" % (grp,)) def addRepository(self, name, url = None, mirrorlist = None, proxy = None, proxy_username = None, proxy_password = None, inc = None, exc = None, ssl_verify = True, nocache = False, cost=None, priority=None): # TODO: Handle cost attribute for repos if not self.repo_manager: self.__initialize_repo_manager() if not proxy and url: proxy = get_proxy_for(url) repo = RepositoryStub() repo.name = name repo.id = name repo.proxy = proxy repo.proxy_username = proxy_username repo.proxy_password = proxy_password repo.ssl_verify = ssl_verify repo.nocache = nocache repo.baseurl.append(url) if inc: for pkg in inc: self.incpkgs[pkg] = name if exc: for pkg in exc: self.excpkgs[pkg] = name # check LICENSE files if not rpmmisc.checkRepositoryEULA(name, repo): msger.warning('skip repo:%s for failed EULA confirmation' % name) return None if mirrorlist: repo.mirrorlist = mirrorlist # Enable gpg check for verifying corrupt packages repo.gpgcheck = 1 if priority is not None: # priority 0 has issue in RepoInfo.setPriority repo.priority = priority + 1 try: repo_info = zypp.RepoInfo() repo_info.setAlias(repo.name) repo_info.setName(repo.name) repo_info.setEnabled(repo.enabled) repo_info.setAutorefresh(repo.autorefresh) repo_info.setKeepPackages(repo.keeppackages) baseurl = zypp.Url(repo.baseurl[0]) if not ssl_verify: baseurl.setQueryParam("ssl_verify", "no") if proxy: scheme, host, path, parm, query, frag = urlparse.urlparse(proxy) proxyinfo = host.split(":") host = proxyinfo[0] port = "80" if len(proxyinfo) > 1: port = proxyinfo[1] if proxy.startswith("socks") and len(proxy.rsplit(':', 1)) == 2: host = proxy.rsplit(':', 1)[0] port = proxy.rsplit(':', 1)[1] baseurl.setQueryParam ("proxy", host) baseurl.setQueryParam ("proxyport", port) repo.baseurl[0] = baseurl.asCompleteString() self.repos.append(repo) repo_info.addBaseUrl(baseurl) if repo.priority is not None: repo_info.setPriority(repo.priority) # this hack is used to change zypp credential file location # the default one is $HOME/.zypp, which cause conflicts when # installing some basic packages, and the location doesn't # have any interface actually, so use a tricky way anyway homedir = None if 'HOME' in os.environ: homedir = os.environ['HOME'] os.environ['HOME'] = '/' else: os.environ['HOME'] = '/' self.repo_manager.addRepository(repo_info) # save back the $HOME env if homedir: os.environ['HOME'] = homedir else: del os.environ['HOME'] self.__build_repo_cache(name) except RuntimeError, e: raise CreatorError(str(e)) msger.verbose('repo: %s was added' % name) return repo def installHasFile(self, file): return False def preInstall(self, pkg): self.pre_pkgs.append(pkg) def runInstall(self, checksize = 0): os.environ["HOME"] = "/" os.environ["LD_PRELOAD"] = "" self.buildTransaction() todo = zypp.GetResolvablesToInsDel(self.Z.pool()) installed_pkgs = todo._toInstall dlpkgs = [] for pitem in installed_pkgs: if not zypp.isKindPattern(pitem) and \ not self.inDeselectPackages(pitem): item = zypp.asKindPackage(pitem) dlpkgs.append(item) if not self.install_debuginfo or str(item.arch()) == "noarch": continue dipkg = self._zyppQueryPackage("%s-debuginfo" % item.name()) if dipkg: ditem = zypp.asKindPackage(dipkg) dlpkgs.append(ditem) else: msger.warning("No debuginfo rpm found for: %s" \ % item.name()) # record all pkg and the content localpkgs = self.localpkgs.keys() for pkg in dlpkgs: license = '' if pkg.name() in localpkgs: hdr = rpmmisc.readRpmHeader(self.ts, self.localpkgs[pkg.name()]) pkg_long_name = misc.RPM_FMT % { 'name': hdr['name'], 'arch': hdr['arch'], 'version': hdr['version'], 'release': hdr['release'] } license = hdr['license'] else: pkg_long_name = misc.RPM_FMT % { 'name': pkg.name(), 'arch': pkg.arch(), 'version': pkg.edition().version(), 'release': pkg.edition().release() } license = pkg.license() if license in self.__pkgs_license.keys(): self.__pkgs_license[license].append(pkg_long_name) else: self.__pkgs_license[license] = [pkg_long_name] total_count = len(dlpkgs) cached_count = 0 download_total_size = sum(map(lambda x: int(x.downloadSize()), dlpkgs)) localpkgs = self.localpkgs.keys() msger.info("Checking packages cached ...") for po in dlpkgs: # Check if it is cached locally if po.name() in localpkgs: cached_count += 1 else: local = self.getLocalPkgPath(po) name = str(po.repoInfo().name()) try: repo = filter(lambda r: r.name == name, self.repos)[0] except IndexError: repo = None nocache = repo.nocache if repo else False if os.path.exists(local): if nocache or self.checkPkg(local) !=0: os.unlink(local) else: download_total_size -= int(po.downloadSize()) cached_count += 1 cache_avail_size = misc.get_filesystem_avail(self.cachedir) if cache_avail_size < download_total_size: raise CreatorError("No enough space used for downloading.") # record the total size of installed pkgs install_total_size = sum(map(lambda x: int(x.installSize()), dlpkgs)) # check needed size before actually download and install # FIXME: for multiple partitions for loop type, check fails # skip the check temporarily #if checksize and install_total_size > checksize: # raise CreatorError("No enough space used for installing, " # "please resize partition size in ks file") download_count = total_count - cached_count msger.info("Packages: %d Total, %d Cached, %d Missed" \ % (total_count, cached_count, download_count)) try: if download_count > 0: msger.info("Downloading packages ...") self.downloadPkgs(dlpkgs, download_count) self.installPkgs(dlpkgs) except (RepoError, RpmError): raise except Exception, e: raise CreatorError("Package installation failed: %s" % (e,)) def getVcsInfo(self): if self.__pkgs_vcsinfo: return if not self.ts: self.__initialize_transaction() mi = self.ts.dbMatch() for hdr in mi: lname = misc.RPM_FMT % { 'name': hdr['name'], 'arch': hdr['arch'], 'version': hdr['version'], 'release': hdr['release'] } self.__pkgs_vcsinfo[lname] = hdr['VCS'] return self.__pkgs_vcsinfo def getAllContent(self): if self.__pkgs_content: return self.__pkgs_content if not self.ts: self.__initialize_transaction() mi = self.ts.dbMatch() for hdr in mi: lname = misc.RPM_FMT % { 'name': hdr['name'], 'arch': hdr['arch'], 'version': hdr['version'], 'release': hdr['release'] } self.__pkgs_content[lname] = hdr['FILENAMES'] return self.__pkgs_content def getPkgsLicense(self): return self.__pkgs_license def getFilelist(self, pkgname): if not pkgname: return None if not self.ts: self.__initialize_transaction() mi = self.ts.dbMatch('name', pkgname) for header in mi: return header['FILENAMES'] def __initialize_repo_manager(self): if self.repo_manager: return # Clean up repo metadata shutil.rmtree(self.cachedir + "/etc", ignore_errors = True) shutil.rmtree(self.cachedir + "/solv", ignore_errors = True) shutil.rmtree(self.cachedir + "/raw", 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.instroot)) self.repo_manager_options.knownReposPath = \ zypp.Pathname(self.cachedir + "/etc/zypp/repos.d") self.repo_manager_options.repoCachePath = \ zypp.Pathname(self.cachedir) self.repo_manager_options.repoRawCachePath = \ zypp.Pathname(self.cachedir + "/raw") self.repo_manager_options.repoSolvCachePath = \ zypp.Pathname(self.cachedir + "/solv") self.repo_manager_options.repoPackagesCachePath = \ zypp.Pathname(self.cachedir + "/packages") self.repo_manager = zypp.RepoManager(self.repo_manager_options) def __build_repo_cache(self, name): repo = self.repo_manager.getRepositoryInfo(name) if self.repo_manager.isCached(repo) or not repo.enabled(): return msger.info('Refreshing repository: %s ...' % name) self.repo_manager.buildCache(repo, zypp.RepoManager.BuildIfNeeded) def __initialize_zypp(self): if self.Z: return zconfig = zypp.ZConfig_instance() # Set system architecture if self.target_arch: zconfig.setSystemArchitecture(zypp.Arch(self.target_arch)) msger.info("zypp architecture is <%s>" % zconfig.systemArchitecture()) # 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 self.repo_manager.loadFromCache(repo) self.Z = zypp.ZYppFactory_instance().getZYpp() self.Z.initializeTarget(zypp.Pathname(self.instroot)) self.Z.target().load() def buildTransaction(self): if not self.Z.resolver().resolvePool(): probs = self.Z.resolver().problems() for problem in probs: msger.warning("repo problem: %s, %s" \ % (problem.description().decode("utf-8"), problem.details().decode("utf-8"))) raise RepoError("found %d resolver problem, abort!" \ % len(probs)) def getLocalPkgPath(self, po): repoinfo = po.repoInfo() cacheroot = repoinfo.packagesPath() location= po.location() rpmpath = str(location.filename()) pkgpath = "%s/%s" % (cacheroot, os.path.basename(rpmpath)) return pkgpath def installLocal(self, pkg, po=None, updateonly=False): if not self.ts: self.__initialize_transaction() solvfile = "%s/.solv" % (self.cachedir) rc, out = runner.runtool([fs_related.find_binary_path("rpms2solv"), pkg]) if rc == 0: f = open(solvfile, "w+") f.write(out) f.close() warnmsg = self.repo_manager.loadSolvFile(solvfile, os.path.basename(pkg)) if warnmsg: msger.warning(warnmsg) os.unlink(solvfile) else: msger.warning('Can not get %s solv data.' % pkg) hdr = rpmmisc.readRpmHeader(self.ts, pkg) arch = zypp.Arch(hdr['arch']) sysarch = zypp.Arch(self.target_arch) if arch.compatible_with (sysarch): pkgname = hdr['name'] self.localpkgs[pkgname] = pkg self.selectPackage(pkgname) msger.info("Marking %s to be installed" % (pkg)) else: msger.warning("Cannot add package %s to transaction. " "Not a compatible architecture: %s" \ % (pkg, hdr['arch'])) def downloadPkgs(self, package_objects, count): localpkgs = self.localpkgs.keys() progress_obj = TextProgress(count) for po in package_objects: if po.name() in localpkgs: continue filename = self.getLocalPkgPath(po) if os.path.exists(filename): if self.checkPkg(filename) == 0: continue dirn = os.path.dirname(filename) if not os.path.exists(dirn): os.makedirs(dirn) url = self.get_url(po) proxies = self.get_proxies(po) try: filename = myurlgrab(url, filename, proxies, progress_obj) except CreatorError: self.close() raise def preinstallPkgs(self): if not self.ts_pre: self.__initialize_transaction() self.ts_pre.order() cb = rpmmisc.RPMInstallCallback(self.ts_pre) cb.headmsg = "Preinstall" installlogfile = "%s/__catched_stderr.buf" % (self.instroot) # start to catch stderr output from librpm msger.enable_logstderr(installlogfile) errors = self.ts_pre.run(cb.callback, '') # stop catch msger.disable_logstderr() self.ts_pre.closeDB() self.ts_pre = None if errors is not None: if len(errors) == 0: msger.warning('scriptlet or other non-fatal errors occurred ' 'during transaction.') else: for e in errors: msger.warning(e[0]) raise RepoError('Could not run transaction.') def installPkgs(self, package_objects): if not self.ts: self.__initialize_transaction() # clean rpm lock self._cleanupRpmdbLocks(self.instroot) self._cleanupZyppJunk(self.instroot) # Set filters probfilter = 0 for flag in self.probFilterFlags: probfilter |= flag self.ts.setProbFilter(probfilter) self.ts_pre.setProbFilter(probfilter) 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): # Maybe it is a local repo rpmuri = self.get_url(po) if rpmuri.startswith("file:/"): rpmpath = rpmuri[5:] if not os.path.exists(rpmpath): raise RpmError("Error: %s doesn't exist" % rpmpath) h = rpmmisc.readRpmHeader(self.ts, rpmpath) if pkgname in self.pre_pkgs: msger.verbose("pre-install package added: %s" % pkgname) self.ts_pre.addInstall(h, rpmpath, 'u') self.ts.addInstall(h, rpmpath, 'u') unresolved_dependencies = self.ts.check() if not unresolved_dependencies: if self.pre_pkgs: self.preinstallPkgs() self.ts.order() cb = rpmmisc.RPMInstallCallback(self.ts) installlogfile = "%s/__catched_stderr.buf" % (self.instroot) # start to catch stderr output from librpm msger.enable_logstderr(installlogfile) errors = self.ts.run(cb.callback, '') # stop catch msger.disable_logstderr() self.ts.closeDB() self.ts = None if errors is not None: if len(errors) == 0: msger.warning('scriptlet or other non-fatal errors occurred ' 'during transaction.') else: for e in errors: msger.warning(e[0]) raise RepoError('Could not run transaction.') else: for pkg, need, needflags, sense, key in unresolved_dependencies: package = '-'.join(pkg) if needflags == rpm.RPMSENSE_LESS: deppkg = ' < '.join(need) elif needflags == rpm.RPMSENSE_EQUAL: deppkg = ' = '.join(need) elif needflags == rpm.RPMSENSE_GREATER: deppkg = ' > '.join(need) else: deppkg = '-'.join(need) if sense == rpm.RPMDEP_SENSE_REQUIRES: msger.warning("[%s] Requires [%s], which is not provided" \ % (package, deppkg)) elif sense == rpm.RPMDEP_SENSE_CONFLICTS: msger.warning("[%s] Conflicts with [%s]" %(package,deppkg)) raise RepoError("Unresolved dependencies, transaction failed.") def __initialize_transaction(self): if not self.ts: self.ts = rpm.TransactionSet(self.instroot) # Set to not verify DSA signatures. self.ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS) if not self.ts_pre: self.ts_pre = rpm.TransactionSet(self.instroot) # Just unpack the files, don't run scripts self.ts_pre.setFlags(rpm.RPMTRANS_FLAG_ALLFILES | rpm.RPMTRANS_FLAG_NOSCRIPTS) # Set to not verify DSA signatures. self.ts_pre.setVSFlags(rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS) def checkPkg(self, pkg): ret = 1 if not os.path.exists(pkg): return ret ret = rpmmisc.checkRpmIntegrity('rpm', pkg) if ret != 0: msger.warning("package %s is damaged: %s" \ % (os.path.basename(pkg), pkg)) return ret def _add_prob_flags(self, *flags): for flag in flags: if flag not in self.probFilterFlags: self.probFilterFlags.append(flag) def get_proxies(self, pobj): if not pobj: return None proxy = None proxies = None repoinfo = pobj.repoInfo() reponame = "%s" % repoinfo.name() repos = filter(lambda r: r.name == reponame, self.repos) repourl = str(repoinfo.baseUrls()[0]) if repos: proxy = repos[0].proxy if not proxy: proxy = get_proxy_for(repourl) if proxy: proxies = {str(repourl.split(':')[0]): str(proxy)} return proxies def get_url(self, pobj): if not pobj: return None name = str(pobj.repoInfo().name()) try: repo = filter(lambda r: r.name == name, self.repos)[0] except IndexError: return None baseurl = repo.baseurl[0] index = baseurl.find("?") if index > -1: baseurl = baseurl[:index] location = pobj.location() location = str(location.filename()) if location.startswith("./"): location = location[2:] return os.path.join(baseurl, location) def package_url(self, pkgname): def cmpEVR(p1, p2): ed1 = p1.edition() ed2 = p2.edition() (e1, v1, r1) = map(str, [ed1.epoch(), ed1.version(), ed1.release()]) (e2, v2, r2) = map(str, [ed2.epoch(), ed2.version(), ed2.release()]) return rpm.labelCompare((e1, v1, r1), (e2, v2, r2)) if not self.Z: self.__initialize_zypp() q = zypp.PoolQuery() q.addKind(zypp.ResKind.package) q.setMatchExact() q.addAttribute(zypp.SolvAttr.name, pkgname) items = sorted(q.queryResults(self.Z.pool()), cmp=lambda x,y: cmpEVR(zypp.asKindPackage(x), zypp.asKindPackage(y)), reverse=True) if items: item = zypp.asKindPackage(items[0]) url = self.get_url(item) proxies = self.get_proxies(item) return (url, proxies) return (None, None)