From 331083293034440f2da28ff993fe203321e7be69 Mon Sep 17 00:00:00 2001 From: genone Date: Wed, 30 May 2007 17:13:31 +0000 Subject: [PATCH] improve SLOT handling, add option for emerge-like resolver svn path=/; revision=403 --- trunk/ChangeLog | 5 ++++ trunk/src/glsa-check/glsa-check | 26 +++++++++++++----- trunk/src/glsa-check/glsa.py | 47 ++++++++++++++++++++++----------- 3 files changed, 57 insertions(+), 21 deletions(-) diff --git a/trunk/ChangeLog b/trunk/ChangeLog index e150ce2..442a1a8 100644 --- a/trunk/ChangeLog +++ b/trunk/ChangeLog @@ -1,3 +1,8 @@ +2007-05-30: Marius Mauch + * glsa-check: check SLOT when selecting and displaying upgrades + * glsa-check: new --emergelike option to use the best version + within the same SLOT instead of the one with the smallest delta. + 2007-05-21: Paul Varner * echangelog: Add patch from genstef to fix issues from Bug 176337 diff --git a/trunk/src/glsa-check/glsa-check b/trunk/src/glsa-check/glsa-check index 6d2a11b..5789547 100644 --- a/trunk/src/glsa-check/glsa-check +++ b/trunk/src/glsa-check/glsa-check @@ -17,7 +17,7 @@ from getopt import getopt,GetoptError __program__ = "glsa-check" __author__ = "Marius Mauch " -__version__ = "0.8" +__version__ = "0.9" optionmap = [ ["-l", "--list", "list all unapplied GLSA"], @@ -27,6 +27,7 @@ optionmap = [ ["-f", "--fix", "try to auto-apply this GLSA (experimental)"], ["-i", "--inject", "inject the given GLSA into the checkfile"], ["-n", "--nocolor", "disable colors (option)"], +["-e", "--emergelike", "do not use a least-change algorithm (option)"], ["-h", "--help", "show this help message"], ["-V", "--version", "some information about this tool"], ["-v", "--verbose", "print more information (option)"], @@ -67,6 +68,12 @@ try: if option in args: list_cve = True args.remove(option) + + least_change = True + for option in ["--emergelike", "-e"]: + if option in args: + least_change = False + args.remove(option) # sanity checking if len(args) <= 0: @@ -125,6 +132,9 @@ from glsa import * glsaconfig = checkconfig(portage.config(clone=portage.settings)) +vardb = portage.db["/"]["vartree"].dbapi +portdb = portage.db["/"]["porttree"].dbapi + # Check that we really have a glsa dir to work on if not (os.path.exists(glsaconfig["GLSA_DIR"]) and os.path.isdir(glsaconfig["GLSA_DIR"])): sys.stderr.write(red("ERROR")+": GLSA_DIR %s doesn't exist. Please fix this.\n" % glsaconfig["GLSA_DIR"]) @@ -203,7 +213,7 @@ def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr): fd1.write("... ") else: for pkg in myglsa.packages.keys(): - mylist = portage.db["/"]["vartree"].dbapi.match(portage.dep_getkey(pkg)) + mylist = vardb.match(portage.dep_getkey(pkg)) if len(mylist) > 0: pkg = color(" ".join(mylist)) fd1.write(" " + pkg + " ") @@ -230,7 +240,7 @@ if mode in ["dump", "fix", "inject", "pretend"]: myglsa.dump() elif mode == "fix": sys.stdout.write("fixing "+myid+"\n") - mergelist = myglsa.getMergeList() + mergelist = myglsa.getMergeList(least_change=least_change) for pkg in mergelist: sys.stdout.write(">>> merging "+pkg+"\n") # using emerge for the actual merging as it contains the dependency @@ -245,12 +255,16 @@ if mode in ["dump", "fix", "inject", "pretend"]: myglsa.inject() elif mode == "pretend": sys.stdout.write("Checking GLSA "+myid+"\n") - mergelist = myglsa.getMergeList() + mergelist = myglsa.getMergeList(least_change=least_change) if mergelist: sys.stdout.write("The following updates will be performed for this GLSA:\n") for pkg in mergelist: - # we simplify a bit here - oldver = portage.db["/"]["vartree"].dbapi.match(portage.dep_getkey(pkg))[-1] + oldver = None + for x in vardb.match(portage.dep_getkey(pkg)): + if vardb.aux_get(x, ["SLOT"]) == portdb.aux_get(pkg, ["SLOT"]): + oldver = x + if oldver == None: + raise ValueError("could not find old version for package %s" % pkg) oldver = oldver[len(portage.dep_getkey(oldver))+1:] sys.stdout.write(" " + pkg + " (" + oldver + ")\n") else: diff --git a/trunk/src/glsa-check/glsa.py b/trunk/src/glsa-check/glsa.py index 474f9f2..87a39e4 100644 --- a/trunk/src/glsa-check/glsa.py +++ b/trunk/src/glsa-check/glsa.py @@ -288,7 +288,7 @@ def makeVersion(versionNode): return opMapping[versionNode.getAttribute("range")] \ +getText(versionNode, format="strip") -def match(atom, portdbname): +def match(atom, portdbname, match_type="default"): """ wrapper that calls revisionMatch() or portage.dbapi.match() depending on the given atom. @@ -297,16 +297,22 @@ def match(atom, portdbname): @param atom: a <~ or >~ atom or a normal portage atom that contains the atom to match against @type portdb: portage.dbapi @param portdb: one of the portage databases to use as information source + @type match_type: string + @param match_type: if != "default" passed as first argument to dbapi.xmatch + to apply the wanted visibility filters @rtype: list of strings @return: a list with the matching versions """ + db = portage.db["/"][portdbname].dbapi if atom[2] == "~": - return revisionMatch(atom, portage.db["/"][portdbname].dbapi) + return revisionMatch(atom, db, match_type=match_type) + elif match_type == "default" or not hasattr(db, "xmatch"): + return db.match(atom) else: - return portage.db["/"][portdbname].dbapi.match(atom) + return db.xmatch(match_type, atom) -def revisionMatch(revisionAtom, portdb): +def revisionMatch(revisionAtom, portdb, match_type="default"): """ handler for the special >~, >=~, <=~ and <~ atoms that are supposed to behave as > and < except that they are limited to the same version, the range only @@ -316,11 +322,17 @@ def revisionMatch(revisionAtom, portdb): @param revisionAtom: a <~ or >~ atom that contains the atom to match against @type portdb: portage.dbapi @param portdb: one of the portage databases to use as information source + @type match_type: string + @param match_type: if != "default" passed as first argument to portdb.xmatch + to apply the wanted visibility filters @rtype: list of strings @return: a list with the matching versions """ - mylist = portdb.match(re.sub("-r[0-9]+$", "", revisionAtom[2:])) + if match_type == "default" or not hasattr(portdb, "xmatch"): + mylist = portdb.match(re.sub("-r[0-9]+$", "", revisionAtom[2:])) + else: + mylist = portdb.xmatch(match_type, re.sub("-r[0-9]+$", "", revisionAtom[2:])) rValue = [] for v in mylist: r1 = portage.pkgsplit(v)[-1][1:] @@ -330,7 +342,7 @@ def revisionMatch(revisionAtom, portdb): return rValue -def getMinUpgrade(vulnerableList, unaffectedList): +def getMinUpgrade(vulnerableList, unaffectedList, minimize=True): """ Checks if the systemstate is matching an atom in I{vulnerableList} and returns string describing @@ -344,6 +356,9 @@ def getMinUpgrade(vulnerableList, unaffectedList): @param vulnerableList: atoms matching vulnerable package versions @type unaffectedList: List of Strings @param unaffectedList: atoms matching unaffected package versions + @type minimize: Boolean + @param minimize: True for a least-change upgrade, False for emerge-like algorithm + @rtype: String | None @return: the lowest unaffected version that is greater than the installed version. @@ -363,22 +378,22 @@ def getMinUpgrade(vulnerableList, unaffectedList): install_unaffected = False if install_unaffected: - return [] + return rValue for u in unaffectedList: - if u[2] == "~": - mylist = revisionMatch(u, portage.db["/"]["porttree"].dbapi) - else: - mylist = portage.db["/"]["porttree"].dbapi.xmatch("match-all", u) + mylist = match(u, "porttree", match_type="match-all") for c in mylist: c_pv = portage.catpkgsplit(c) i_pv = portage.catpkgsplit(portage.best(v_installed)) - if portage.pkgcmp(c_pv[1:], i_pv[1:]) > 0 and (rValue == None or portage.pkgcmp(c_pv[1:], portage.catpkgsplit(rValue)[1:]) < 0): + if portage.pkgcmp(c_pv[1:], i_pv[1:]) > 0 \ + and (rValue == None or (minimize ^ (portage.pkgcmp(c_pv[1:], portage.catpkgsplit(rValue)[1:]) > 0))) \ + and portage.db["/"]["porttree"].dbapi.aux_get(c, ["SLOT"]) == portage.db["/"]["vartree"].dbapi.aux_get(portage.best(v_installed), ["SLOT"]): rValue = c_pv[0]+"/"+c_pv[1]+"-"+c_pv[2] if c_pv[3] != "r0": # we don't like -r0 for display rValue += "-"+c_pv[3] return rValue + # simple Exception classes to catch specific errors class GlsaTypeException(Exception): def __init__(self, doctype): @@ -602,20 +617,22 @@ class Glsa: checkfile.close() return None - def getMergeList(self): + def getMergeList(self, least_change=True): """ Returns the list of package-versions that have to be merged to apply this GLSA properly. The versions are as low as possible while avoiding downgrades (see L{getMinUpgrade}). + @type least_change: Boolean + @param least_change: True if the smallest possible upgrade should be selected, + False for an emerge-like algorithm @rtype: List of Strings @return: list of package-versions that have to be merged """ rValue = [] for pkg in self.packages.keys(): for path in self.packages[pkg]: - update = getMinUpgrade(path["vul_atoms"], - path["unaff_atoms"]) + update = getMinUpgrade(path["vul_atoms"], path["unaff_atoms"], minimize=least_change) if update: rValue.append(update) return rValue -- 2.26.2