From: Fabian Groffen Date: Thu, 20 Mar 2008 20:32:23 +0000 (-0000) Subject: Merged from trunk 9468:9491 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=9b234be0f9a9f4c0db08361c5fc1eeabb73cd528;p=portage.git Merged from trunk 9468:9491 | 9469 | add a placeholder for repository paths in 'filename' and | | genone | 'directory' options for StaticFileSet | | 9470 | avoid importing portage to improve performance | | genone | | | 9471 | When in strict mode, make paren_reduce() detect missing | | zmedico | whitespace around parenthesis tokens and raise an | | | InvalidDependString exception. Strict mode is not enabled | | | when handling installed packages, so this will only affect | | | repoman and packages that haven't been installed yet. Thanks | | | to zlin for reporting. | | 9472 | Bug #213540 - Make sure DESTTREE=/usr is set before inherit | | zmedico | calls. | | 9473 | Bug #213592 - Fix --onlydeps breakage. | | zmedico | | | 9474 | Bug #212882 - For compatibility with ENOENT exceptions | | zmedico | raised from fstat calls with CIFS, wrap fstat calls with an | | | appropriate exception handler. | | 9475 | Bug #174634 - Fix ebuild 'digest' and 'manifest' behave 100% | | zmedico | identically and update the docs to reflect this. | | 9476 | Bug #149745 - Generate an eqawarn message if dohtml is | | zmedico | called on a directory without the recursive option. Thanks | | | to brad walker for reporting. | | 9477 | use a dict with CP keys in unmerge() to avoid double | | genone | unmerges if a package is matched by multiple atoms | | 9478 | fix artifact from r9477 | | genone | | | 9479 | add @ to the list of invalid atom chars so sets with prefix | | genone | aren't considered as atoms accidentally | | 9480 | add unmerge protection for packages still referenced by | | genone | installed package sets | | 9481 | make filesets non-greedy by default | | genone | | | 9482 | Bug #139023 - When the --digest option is enabled, advise | | zmedico | the user that `repoman manifest` is the preferred way to | | | generate manifests. | | 9483 | Bug #201045 - Fix unmerge() to preserve unmerge order so | | zmedico | that dependencies are respected. Also, eliminate duplicate | | | package selections since the same package may be selected by | | | multiple atoms but we can only unmerge it once. | | 9484 | Only show the eqawarn from bug #149745 when nothing is found | | zmedico | to install. Also, exit successfully unless nothing is found | | | to install. | | 9485 | Bug #210575 - Optimize doins -r so that it doesn't call | | zmedico | itself recursively, since it's faster to handle the | | | recursion internally. Thanks to Benedikt Böhm | | | for the initial patch. | | 9486 | Bug #210690 - Fix --help output to show the leading slash on | | zmedico | the path to the world file. | | 9487 | Strip trailing slashes from directory paths if necessary. | | zmedico | | | 9488 | display versions of other slots for new-slot installs (bug | | genone | #213790) | | 9489 | Fix quoting. | | zmedico | | | 9491 | readd digestentry.unused category as it's still relevant | | genone | | svn path=/main/branches/prefix/; revision=9492 --- diff --git a/bin/dohtml b/bin/dohtml index def135d67..d65a31a15 100755 --- a/bin/dohtml +++ b/bin/dohtml @@ -39,6 +39,15 @@ def dodir(path): def dofile(src,dst): os.spawnlp(os.P_WAIT, "install", "install", "-m0644", src, dst) +def eqawarn(lines): + cmd = "source '%s/isolated-functions.sh' ; " % \ + os.environ["PORTAGE_BIN_PATH"] + for line in lines: + cmd += "eqawarn \"%s\" ; " % line + os.spawnlp(os.P_WAIT, "bash", "bash", "-c", cmd) + +skipped_directories = [] + def install(basename, dirname, options, prefix=""): fullpath = basename if prefix: @@ -62,6 +71,10 @@ def install(basename, dirname, options, prefix=""): pfx = basename if prefix: pfx = prefix + "/" + pfx install(i, dirname, options, pfx) + elif not options.recurse and os.path.isdir(fullpath): + global skipped_directories + skipped_directories.append(fullpath) + return False else: return False return True @@ -155,19 +168,22 @@ def main(): print "Document prefix : '" + options.doc_prefix + "'" print "Allowed files :", options.allowed_files - success = True + success = False for x in args: basename = os.path.basename(x) dirname = os.path.dirname(x) - if not install(basename, dirname, options): - success = False - + success |= install(basename, dirname, options) + if success: retcode = 0 else: retcode = 1 - + global skipped_directories + for x in skipped_directories: + eqawarn(["QA Notice: dohtml on directory " + \ + "'%s' without recursion option" % x]) + sys.exit(retcode) if __name__ == "__main__": diff --git a/bin/doins b/bin/doins index 16a1b85a1..26496a8bb 100755 --- a/bin/doins +++ b/bin/doins @@ -16,11 +16,6 @@ if [[ "$1" == "-r" ]] ; then else DOINSRECUR=n fi -[[ -z ${INSDEPTH} ]] && declare -i INSDEPTH=0 -if [[ ${INSDEPTH} -gt 30 ]] ; then - echo "${0##*/}: sanity check ... 30 directories is too much :(" 2>&1 - exit 1 -fi if [[ ${INSDESTTREE#${D}} != "${INSDESTTREE}" ]]; then vecho "-------------------------------------------------------" 1>&2 @@ -40,24 +35,41 @@ fi [[ ! -d ${ED}${INSDESTTREE} ]] && dodir "${INSDESTTREE}" +_doins() { + local mysrc="$1" mydir="$2" + + if [ -L "$mysrc" ] ; then + cp "$mysrc" "${T}" + mysrc="${T}/${mysrc##*/}" + fi + + install ${INSOPTIONS} "${mysrc}" "${ED}${INSDESTTREE}/${mydir}" +} + +_xdoins() { + while read -d $'\0' x ; do + _doins "$x" "${x%/*}" + done +} + for x in "$@" ; do - if [ -L "$x" ] ; then - cp "$x" "${T}" - mysrc="${T}/$(basename "${x}")" - elif [ -d "$x" ] ; then + if [ -d "$x" ] ; then if [ "${DOINSRECUR}" == "n" ] ; then continue fi - mydir="${INSDESTTREE}/$(basename "${x}")" - find "${x}" -mindepth 1 -maxdepth 1 -exec \ - env \ - INSDESTTREE="${mydir}" \ - INSDEPTH=$((INSDEPTH+1)) \ - doins -r {} \; - continue + while [ "$x" != "${x%/}" ] ; do + x=${x%/} + done + if [ "$x" = "${x%/*}" ] ; then + pushd "$PWD" >/dev/null + else + pushd "${x%/*}" >/dev/null + fi + find "${x##*/}" -type d -exec dodir "${INSDESTTREE}/{}" \; + find "${x##*/}" \( -type f -or -type l \) -print0 | _xdoins + popd >/dev/null else - mysrc="${x}" + _doins "${x}" fi - install ${INSOPTIONS} "${mysrc}" "${ED}${INSDESTTREE}" done diff --git a/bin/ebuild b/bin/ebuild index e106fdcbc..53fa7cdd4 100755 --- a/bin/ebuild +++ b/bin/ebuild @@ -179,7 +179,7 @@ for arg in pargs: stale_env_warning() checked_for_stale_env = True - if arg == "digest" and force: + if arg in ("digest", "manifest") and force: discard_digests(ebuild, tmpsettings, portage.portdb) a = portage.doebuild(ebuild, arg, portage.root, tmpsettings, debug=debug, tree=mytree) diff --git a/bin/ebuild.sh b/bin/ebuild.sh index 1e5a4e539..471743ce0 100755 --- a/bin/ebuild.sh +++ b/bin/ebuild.sh @@ -263,6 +263,10 @@ register_die_hook() { #if no perms are specified, dirs/files will have decent defaults #(not secretive, but not stupid) umask 022 +export DESTTREE=/usr +export INSDESTTREE="" +export _E_EXEDESTTREE_="" +export _E_DOCDESTTREE_="" export INSOPTIONS="-m0644" export EXEOPTIONS="-m0755" export LIBOPTIONS="-m0644" @@ -1060,7 +1064,7 @@ dyn_help() { echo " help : show this help screen" echo " setup : execute package specific setup actions" echo " fetch : download source archive(s) and patches" - echo " digest : create a digest and a manifest file for the package" + echo " digest : create a manifest file for the package" echo " manifest : create a manifest file for the package" echo " unpack : unpack/patch sources (auto-fetch if needed)" echo " compile : compile sources (auto-fetch/unpack if needed)" diff --git a/bin/pkgname b/bin/pkgname index 41ae9f13d..e50b35352 100755 --- a/bin/pkgname +++ b/bin/pkgname @@ -3,8 +3,6 @@ # Distributed under the terms of the GNU General Public License v2 # $Id$ -import sys, os - # for an explanation on this logic, see pym/_emerge/__init__.py import os import sys @@ -13,8 +11,9 @@ if os.environ.__contains__("PORTAGE_PYTHONPATH"): else: sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym")) import portage +from portage.versions import pkgsplit -a=portage.pkgsplit(sys.argv[1]) +a=pkgsplit(sys.argv[1]) if a: print a[0],a[1],a[2][1:] sys.exit(0) diff --git a/bin/regenworld b/bin/regenworld index 369d7faba..fe88a2410 100755 --- a/bin/regenworld +++ b/bin/regenworld @@ -44,12 +44,14 @@ def isunwanted(pkgline): __uniqlist__.append(pkgline) return True +world_file = os.path.join("/", portage.WORLD_FILE) + # show a little description if we have arguments if len(sys.argv) >= 2 and sys.argv[1] in ["-h", "--help"]: print "This script regenerates the portage world file by checking the portage" print "logfile for all actions that you've done in the past. It ignores any" print "arguments except --help. It is recommended that you make a backup of" - print "your existing world file (%s) before using this tool." % portage.WORLD_FILE + print "your existing world file (%s) before using this tool." % world_file sys.exit(0) worldlist = portage.grabfile(os.path.join("/", portage.WORLD_FILE)) diff --git a/bin/repoman b/bin/repoman index ae0a5ca32..da0cfc4f7 100755 --- a/bin/repoman +++ b/bin/repoman @@ -282,6 +282,7 @@ qahelp={ "LICENSE.invalid":"This ebuild is listing a license that doesnt exist in portages license/ dir.", "KEYWORDS.invalid":"This ebuild contains KEYWORDS that are not listed in profiles/arch.list or for which no valid profile was found", "RESTRICT.invalid":"This ebuild contains invalid RESTRICT values.", + "digestentry.unused":"Some files listed in the Manifest aren't referenced in SRC_URI", "ebuild.nostable":"There are no ebuilds that are marked as stable for your ARCH", "ebuild.allmasked":"All ebuilds are masked for this package (Package level only)", "ebuild.majorsyn":"This ebuild has a major syntax error that may cause the ebuild to fail partially or fully", @@ -301,6 +302,7 @@ qacats.sort() qawarnings=[ "changelog.missing", "changelog.notadded", +"digestentry.unused", "ebuild.notadded", "ebuild.nostable", "ebuild.allmasked", diff --git a/man/ebuild.1 b/man/ebuild.1 index e7ebabfe0..4e74a2783 100644 --- a/man/ebuild.1 +++ b/man/ebuild.1 @@ -64,18 +64,17 @@ in files/digest\-[package]\-[version\-rev], a warning is printed and ebuild exits with an error code of 1. .TP .BR digest -Creates a digest file for the package in -/usr/portage/[category]/[package]/files/. This digest file lists the -checksums of all the files found in the SRC_URI. See the \fB\-\-force\fR -option if you would like to prevent digests from being assumed. For further -information regarding the behavior of this command, see the documentation for -the \fIassume\-digests\fR value of the \fBFEATURES\fR variable in -\fBmake.conf\fR(5). +This is now equivalent to the \fImanifest\fR command. .TP .BR manifest -Updates the manifest file for the package. This performs the second half -of the digest command, creating md5sums for the files in the files -directory as well as the ebuild. +Updates the manifest file for the package. This creates checksums for all +of the files found in the same directory as the current ebuild as well as +the recursive contents of the files subdirectory. It also creates checksums +for all of the files listed in SRC_URI for each ebuild. For further +information regarding the behavior of this command, see the documentation for +the \fIassume\-digests\fR value of the \fBFEATURES\fR variable in +\fBmake.conf\fR(5). See the \fB\-\-force\fR option if you would like to +prevent digests from being assumed. .TP .BR unpack Extracts the sources to a subdirectory in the \fIbuild directory\fR @@ -173,7 +172,8 @@ information is not incorporated into the RPM. .SH OPTIONS .TP \fB--force\fR -When used together with the digest command, this option forces regeneration of +When used together with the digest or manifest command, +this option forces regeneration of digests for all distfiles associated with the current ebuild. Any distfiles that do not already exist in ${DISTDIR} will be automatically fetched. .SH "REPORTING BUGS" diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index 1bf636090..8d2178195 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -1271,7 +1271,7 @@ class SetArg(DependencyArg): class Dependency(object): __slots__ = ("__weakref__", "atom", "blocker", "depth", - "parent", "priority", "root") + "parent", "onlydeps", "priority", "root") def __init__(self, **kwargs): for myattr in self.__slots__: if myattr == "__weakref__": @@ -1694,7 +1694,8 @@ class depgraph(object): ("blocks", dep.parent.root, dep.atom), set()).add( dep.parent) continue - dep_pkg, existing_node = self._select_package(dep.root, dep.atom) + dep_pkg, existing_node = self._select_package(dep.root, dep.atom, + onlydeps=dep.onlydeps) if not dep_pkg: if allow_unsatisfied: self._unsatisfied_deps.append(dep) @@ -2324,7 +2325,7 @@ class depgraph(object): return 0, myfavorites self._dep_stack.append( - Dependency(atom=atom, root=myroot, parent=arg)) + Dependency(atom=atom, onlydeps=onlydeps, root=myroot, parent=arg)) if not self._create_graph(): if isinstance(arg, SetArg): sys.stderr.write(("\n\n!!! Problem resolving " + \ @@ -3716,7 +3717,8 @@ class depgraph(object): #we need to use "--emptrytree" testing here rather than "empty" param testing because "empty" #param is used for -u, where you still *do* want to see when something is being upgraded. - myoldbest="" + myoldbest = "" + myinslotlist = None installed_versions = vardb.match(portage.cpv_getkey(pkg_key)) if vardb.cpv_exists(pkg_key): addl=" "+yellow("R")+fetch+" " @@ -3738,21 +3740,22 @@ class depgraph(object): portage.cpv_getkey(pkg_key): myinslotlist = None if myinslotlist: - myoldbest=portage.best(myinslotlist) - addl=" "+fetch + myoldbest = portage.best(myinslotlist) + addl = " " + fetch if portage.pkgcmp(portage.pkgsplit(x[2]), portage.pkgsplit(myoldbest)) < 0: # Downgrade in slot - addl+=turquoise("U")+blue("D") + addl += turquoise("U")+blue("D") if ordered: counters.downgrades += 1 else: # Update in slot - addl+=turquoise("U")+" " + addl += turquoise("U") + " " if ordered: counters.upgrades += 1 else: # New slot, mark it new. - addl=" "+green("NS")+fetch+" " + addl = " " + green("NS") + fetch + " " + myoldbest = vardb.match(portage.cpv_getkey(pkg_key)) if ordered: counters.newslot += 1 @@ -3765,11 +3768,11 @@ class depgraph(object): portdb.findname(pkg_key), inst_matches[0], pkg_key)) else: - addl=" "+green("N")+" "+fetch+" " + addl = " " + green("N") + " " + fetch + " " if ordered: counters.new += 1 - verboseadd="" + verboseadd = "" if True: # USE flag display @@ -3786,7 +3789,7 @@ class depgraph(object): cur_use = pkg_use cur_use = [flag for flag in cur_use if flag in cur_iuse] - if myoldbest: + if myoldbest and myinslotlist: pkg = myoldbest else: pkg = x[2] @@ -3928,10 +3931,10 @@ class depgraph(object): verboseadd += teal("[%s]" % repoadd) xs = list(portage.pkgsplit(x[2])) - if xs[2]=="r0": - xs[2]="" + if xs[2] == "r0": + xs[2] = "" else: - xs[2]="-"+xs[2] + xs[2] = "-" + xs[2] mywidth = 130 if "COLUMNWIDTH" in self.settings: @@ -3943,16 +3946,22 @@ class depgraph(object): "!!! Unable to parse COLUMNWIDTH='%s'\n" % \ self.settings["COLUMNWIDTH"], noiselevel=-1) del e - oldlp=mywidth-30 - newlp=oldlp-30 + oldlp = mywidth - 30 + newlp = oldlp - 30 indent = " " * depth if myoldbest: - myoldbest=portage.pkgsplit(myoldbest)[1]+"-"+portage.pkgsplit(myoldbest)[2] - if myoldbest[-3:]=="-r0": - myoldbest=myoldbest[:-3] - myoldbest=blue("["+myoldbest+"]") + if myinslotlist: + myoldbest = [myoldbest] + for key in myoldbest: + pos = myoldbest.index(key) + key = portage.pkgsplit(key)[1] + "-" + portage.pkgsplit(key)[2] + if key[-3:] == "-r0": + key = key[:-3] + myoldbest[pos] = key + myoldbest = blue("["+", ".join(myoldbest)+"]") + pkg_cp = xs[0] root_config = self.roots[myroot] @@ -4940,7 +4949,7 @@ def unmerge(root_config, myopts, unmerge_action, mysettings = portage.config(clone=settings) if not unmerge_files: - if "unmerge"==unmerge_action: + if unmerge_action == "unmerge": print print bold("emerge unmerge") + " can only be used with specific package names" print @@ -5024,9 +5033,13 @@ def unmerge(root_config, myopts, unmerge_action, not ("--quiet" in myopts): print darkgreen(newline+\ ">>> These are the packages that would be unmerged:") - + + # Preservation of order is required for --depclean and --prune so + # that dependencies are respected. Use all_selected to eliminate + # duplicate packages since the same package may be selected by + # multiple atoms. pkgmap = [] - numselected=0 + all_selected = set() for x in candidate_catpkgs: # cycle through all our candidate deps and determine # what will and will not get unmerged @@ -5051,13 +5064,15 @@ def unmerge(root_config, myopts, unmerge_action, portage.writemsg("\n--- Couldn't find '%s' to %s.\n" % \ (x, unmerge_action), noiselevel=-1) continue - pkgmap.append({"protected":[], "selected":[], "omitted":[] }) + + pkgmap.append( + {"protected": set(), "selected": set(), "omitted": set()}) mykey = len(pkgmap) - 1 if unmerge_action=="unmerge": for y in mymatch: - if y not in pkgmap[mykey]["selected"]: - pkgmap[mykey]["selected"].append(y) - numselected=numselected+len(mymatch) + if y not in all_selected: + pkgmap[mykey]["selected"].add(y) + all_selected.add(y) elif unmerge_action == "prune": if len(mymatch) == 1: continue @@ -5078,38 +5093,41 @@ def unmerge(root_config, myopts, unmerge_action, best_version = mypkg best_slot = myslot best_counter = mycounter - pkgmap[mykey]["protected"].append(best_version) - pkgmap[mykey]["selected"] = [mypkg for mypkg in mymatch \ - if mypkg != best_version] - numselected = numselected + len(pkgmap[mykey]["selected"]) + pkgmap[mykey]["protected"].add(best_version) + pkgmap[mykey]["selected"].update(mypkg for mypkg in mymatch \ + if mypkg != best_version and mypkg not in all_selected) + all_selected.update(pkgmap[mykey]["selected"]) else: # unmerge_action == "clean" slotmap={} for mypkg in mymatch: - if unmerge_action=="clean": - myslot=localtree.getslot(mypkg) + if unmerge_action == "clean": + myslot = localtree.getslot(mypkg) else: # since we're pruning, we don't care about slots # and put all the pkgs in together - myslot=0 + myslot = 0 if not slotmap.has_key(myslot): - slotmap[myslot]={} - slotmap[myslot][localtree.dbapi.cpv_counter(mypkg)]=mypkg + slotmap[myslot] = {} + slotmap[myslot][localtree.dbapi.cpv_counter(mypkg)] = mypkg + for myslot in slotmap: - counterkeys=slotmap[myslot].keys() - counterkeys.sort() + counterkeys = slotmap[myslot].keys() if not counterkeys: continue counterkeys.sort() - pkgmap[mykey]["protected"].append( + pkgmap[mykey]["protected"].add( slotmap[myslot][counterkeys[-1]]) del counterkeys[-1] #be pretty and get them in order of merge: for ckey in counterkeys: - pkgmap[mykey]["selected"].append(slotmap[myslot][ckey]) - numselected=numselected+1 + mypkg = slotmap[myslot][ckey] + if mypkg not in all_selected: + pkgmap[mykey]["selected"].add(mypkg) + all_selected.add(mypkg) # ok, now the last-merged package # is protected, and the rest are selected + numselected = len(all_selected) if global_unmerge and not numselected: portage.writemsg_stdout("\n>>> No outdated packages were found on your system.\n") return 0 @@ -5122,9 +5140,55 @@ def unmerge(root_config, myopts, unmerge_action, finally: if vdb_lock: portage.locks.unlockdir(vdb_lock) - all_selected = set() - for x in pkgmap: - all_selected.update(x["selected"]) + + from portage.sets.base import EditablePackageSet + + # generate a list of package sets that are directly or indirectly listed in "world", + # as there is no persistent list of "installed" sets + installed_sets = ["world"] + stop = False + pos = 0 + while not stop: + stop = True + pos = len(installed_sets) + for s in installed_sets[pos - 1:]: + candidates = [x[len(SETPREFIX):] for x in sets[s].getNonAtoms() if x.startswith(SETPREFIX)] + if candidates: + stop = False + installed_sets += candidates + del stop, pos + + # we don't want to unmerge packages that are still listed in user-editable package sets + # listed in "world" as they would be remerged on the next update of "world" or the + # relevant package sets. + for cp in xrange(len(pkgmap)): + for cpv in pkgmap[cp]["selected"].copy(): + parents = [] + for s in installed_sets: + # skip sets that the user requested to unmerge, and skip world + # unless we're unmerging a package set (as the package would be + # removed from "world" later on) + if s in root_config.setconfig.active or (s == "world" and not root_config.setconfig.active): + continue + # only check instances of EditablePackageSet as other classes are generally used for + # special purposes and can be ignored here (and are usually generated dynamically, so the + # user can't do much about them anyway) + elif sets[s].containsCPV(cpv) \ + and isinstance(sets[s], EditablePackageSet): + parents.append(s) + if parents: + #print colorize("WARN", "Package %s is going to be unmerged," % cpv) + #print colorize("WARN", "but still listed in the following package sets:") + #print " %s\n" % ", ".join(parents) + print colorize("WARN", "Not unmerging package %s as it is" % cpv) + print colorize("WARN", "still referenced by the following package sets:") + print " %s\n" % ", ".join(parents) + # adjust pkgmap so the display output is correct + pkgmap[cp]["selected"].remove(cpv) + pkgmap[cp]["protected"].add(cpv) + + del installed_sets + for x in xrange(len(pkgmap)): selected = pkgmap[x]["selected"] if not selected: @@ -5132,15 +5196,14 @@ def unmerge(root_config, myopts, unmerge_action, for mytype, mylist in pkgmap[x].iteritems(): if mytype == "selected": continue - pkgmap[x][mytype] = \ - [cpv for cpv in mylist if cpv not in all_selected] - cp = portage.cpv_getkey(selected[0]) + mylist.difference_update(all_selected) + cp = portage.cpv_getkey(iter(selected).next()) for y in localtree.dep_match(cp): if y not in pkgmap[x]["omitted"] and \ - y not in pkgmap[x]["selected"] and \ - y not in pkgmap[x]["protected"] and \ - y not in all_selected: - pkgmap[x]["omitted"].append(y) + y not in pkgmap[x]["selected"] and \ + y not in pkgmap[x]["protected"] and \ + y not in all_selected: + pkgmap[x]["omitted"].add(y) if global_unmerge and not pkgmap[x]["selected"]: #avoid cluttering the preview printout with stuff that isn't getting unmerged continue @@ -5158,15 +5221,14 @@ def unmerge(root_config, myopts, unmerge_action, if "--quiet" not in myopts: portage.writemsg_stdout((mytype + ": ").rjust(14), noiselevel=-1) if pkgmap[x][mytype]: - sorted_pkgs = [portage.catpkgsplit(mypkg)[1:] \ - for mypkg in pkgmap[x][mytype]] + sorted_pkgs = [portage.catpkgsplit(mypkg)[1:] for mypkg in pkgmap[x][mytype]] sorted_pkgs.sort(portage.pkgcmp) for pn, ver, rev in sorted_pkgs: if rev == "r0": myversion = ver else: myversion = ver + "-" + rev - if mytype=="selected": + if mytype == "selected": portage.writemsg_stdout( colorize("UNMERGE_WARN", myversion + " "), noiselevel=-1) else: @@ -5204,7 +5266,7 @@ def unmerge(root_config, myopts, unmerge_action, for y in pkgmap[x]["selected"]: print ">>> Unmerging "+y+"..." emergelog(xterm_titles, "=== Unmerging... ("+y+")") - mysplit=y.split("/") + mysplit = y.split("/") #unmerge... retval = portage.unmerge(mysplit[0], mysplit[1], settings["ROOT"], mysettings, unmerge_action not in ["clean","prune"], @@ -6825,6 +6887,18 @@ def action_build(settings, trees, mtimedb, if pretend or fetchonly: # make the mtimedb readonly mtimedb.filename = None + if "--digest" in myopts: + msg = "The --digest option can prevent corruption from being" + \ + " noticed. The `repoman manifest` command is the preferred" + \ + " way to generate manifests and it is capable of doing an" + \ + " entire repository or category at once." + prefix = bad(" * ") + writemsg(prefix + "\n") + from textwrap import wrap + for line in wrap(msg, 72): + writemsg("%s%s\n" % (prefix, line)) + writemsg(prefix + "\n") + if "--quiet" not in myopts and \ ("--pretend" in myopts or "--ask" in myopts or \ "--tree" in myopts or "--verbose" in myopts): @@ -7442,6 +7516,7 @@ def emerge_main(): sys.stderr.write(line + "\n") return 1 unmerge_actions = ("unmerge", "prune", "clean", "depclean") + # In order to know exactly which atoms/sets should be added to the # world file, the depgraph performs set expansion later. It will get # confused about where the atoms came from if it's not allowed to @@ -7463,6 +7538,7 @@ def emerge_main(): print "emerge: there are no sets to satisfy %s." % \ colorize("INFORM", s) return 1 + setconfig.active.append(s) if myaction in unmerge_actions and \ not sets[s].supportsOperation("unmerge"): sys.stderr.write("emerge: the given set %s does " + \ diff --git a/pym/portage/dep.py b/pym/portage/dep.py index 2a1a3cfa5..b12411d63 100644 --- a/pym/portage/dep.py +++ b/pym/portage/dep.py @@ -65,6 +65,8 @@ def strip_empty(myarr): """ return [x for x in myarr if x] +_paren_whitespace_re = re.compile(r'\S(\(|\))|(\(|\))\S') + def paren_reduce(mystr,tokenize=1): """ Take a string and convert all paren enclosed entities into sublists, optionally @@ -83,6 +85,12 @@ def paren_reduce(mystr,tokenize=1): @rtype: Array @return: The reduced string in an array """ + global _dep_check_strict, _paren_whitespace_re + if _dep_check_strict: + m = _paren_whitespace_re.search(mystr) + if m is not None: + raise portage.exception.InvalidDependString( + "missing space by parenthesis: '%s'" % m.group(0)) mylist = [] while mystr: left_paren = mystr.find("(") @@ -446,7 +454,7 @@ def dep_getusedeps( depend ): open_bracket = depend.find( '[', open_bracket+1 ) return use_list -_invalid_atom_chars_regexp = re.compile("[()|?]") +_invalid_atom_chars_regexp = re.compile("[()|?@]") def isvalidatom(atom, allow_blockers=False): """ diff --git a/pym/portage/locks.py b/pym/portage/locks.py index 49b1166a5..021141234 100644 --- a/pym/portage/locks.py +++ b/pym/portage/locks.py @@ -108,7 +108,7 @@ def lockfile(mypath, wantnewlockfile=0, unlinkfile=0, waiting_msg=None): if type(lockfilename) == types.StringType and \ - myfd != HARDLINK_FD and os.fstat(myfd).st_nlink == 0: + myfd != HARDLINK_FD and _fstat_nlink(myfd) == 0: # The file was deleted on us... Keep trying to make one... os.close(myfd) writemsg("lockfile recurse\n",1) @@ -119,6 +119,22 @@ def lockfile(mypath, wantnewlockfile=0, unlinkfile=0, waiting_msg=None): writemsg(str((lockfilename,myfd,unlinkfile))+"\n",1) return (lockfilename,myfd,unlinkfile,locking_method) +def _fstat_nlink(fd): + """ + @param fd: an open file descriptor + @type fd: Integer + @rtype: Integer + @return: the current number of hardlinks to the file + """ + try: + return os.fstat(fd).st_nlink + except EnvironmentError, e: + if e.errno == errno.ENOENT: + # Some filesystems such as CIFS return + # ENOENT which means st_nlink == 0. + return 0 + raise + def unlockfile(mytuple): import fcntl @@ -164,7 +180,7 @@ def unlockfile(mytuple): # We won the lock, so there isn't competition for it. # We can safely delete the file. writemsg("Got the lockfile...\n",1) - if os.fstat(myfd).st_nlink == 1: + if _fstat_nlink(myfd) == 1: os.unlink(lockfilename) writemsg("Unlinked lockfile...\n",1) locking_method(myfd,fcntl.LOCK_UN) diff --git a/pym/portage/sets/files.py b/pym/portage/sets/files.py index e11a36e4f..81d204b76 100644 --- a/pym/portage/sets/files.py +++ b/pym/portage/sets/files.py @@ -3,6 +3,7 @@ # $Id$ import os +import re from itertools import chain from portage.util import grabfile, write_atomic, ensure_dirs @@ -19,7 +20,9 @@ __all__ = ["StaticFileSet", "ConfigFileSet", "WorldSet"] class StaticFileSet(EditablePackageSet): _operations = ["merge", "unmerge"] - + _repopath_match = re.compile(r'.*\$\{repository:(?P.+)\}.*') + _repopath_sub = re.compile(r'\$\{repository:(?P.+)\}') + def __init__(self, filename, greedy=False, dbapi=None): super(StaticFileSet, self).__init__() self._filename = filename @@ -92,17 +95,26 @@ class StaticFileSet(EditablePackageSet): def singleBuilder(self, options, settings, trees): if not "filename" in options: raise SetConfigError("no filename specified") - greedy = get_boolean(options, "greedy", True) - return StaticFileSet(options["filename"], greedy=greedy, dbapi=trees["vartree"].dbapi) + greedy = get_boolean(options, "greedy", False) + filename = options["filename"] + # look for repository path variables + match = self._repopath_match.match(filename) + if match: + filename = self._repopath_sub.sub(trees["porttree"].dbapi.treemap[match.groupdict()["reponame"]], filename) + return StaticFileSet(filename, greedy=greedy, dbapi=trees["vartree"].dbapi) singleBuilder = classmethod(singleBuilder) def multiBuilder(self, options, settings, trees): rValue = {} directory = options.get("directory", os.path.join(settings["PORTAGE_CONFIGROOT"], USER_CONFIG_PATH.lstrip(os.sep), "sets")) - name_pattern = options.get("name_pattern", "sets/$name") + name_pattern = options.get("name_pattern", "sets/${name}") if not "$name" in name_pattern and not "${name}" in name_pattern: - raise SetConfigError("name_pattern doesn't include $name placeholder") - greedy = get_boolean(options, "greedy", True) + raise SetConfigError("name_pattern doesn't include ${name} placeholder") + greedy = get_boolean(options, "greedy", False) + # look for repository path variables + match = self._repopath_match.match(directory) + if match: + directory = self._repopath_sub.sub(trees["porttree"].dbapi.treemap[match.groupdict()["reponame"]], directory) if os.path.isdir(directory): for filename in os.listdir(directory): if filename.endswith(".metadata"):