From 07941458ede65a048ec9ea7f6ad4f83c01b3a3df Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Mon, 2 Jun 2008 20:33:01 +0000 Subject: [PATCH] Merged from trunk 10458:10480 | 10459 | Bug #222439 - Add doman support for foo.lang.N filenames. | | zmedico | Behavior is as follows: foo.1 -> man/man1/foo.1 foo.lang.1 | | | -> man/lang/man1/foo.1 Thanks to Yuri Vasilevski for the | | | initial patch. I've modified it to use bash's =~ operator | | | and corresponding $BASH_REMATCH array. | | 10460 | Convert doman to use bash's =~ operator instead of calling | | zmedico | egrep. | | 10461 | Make set_term_size() handle the CommandNotFound exception if | | zmedico | stty is missing for some reason. | | 10462 | Make the new behavior from bug #222439 conditional on EAPI | | zmedico | being something other than 0 or 1. | | 10465 | Bug #223447 - Adjust the "installed packages are masked" | | zmedico | display to recognize packages that are masked by keywords | | | and are eligible for uninstallation by depclean. This is a | | | workaround for the fact that depclean may fail to recognize | | | that the package is eligible for uninstall due to | | | differences in visibility filtering which can lead to | | | differences in || dep evaluation. TODO: Share visibility | | | code to fix this inconsistency. | | 10467 | Update the fix from bug #220341 to protect USE deps from | | zmedico | being neglected. | | 10468 | Skip redundant Atom construction in select_package(). | | zmedico | | | 10470 | Fix the code from bug #220341 so that it matches the atom | | zmedico | against the installed package, like it's supposed to. | | 10471 | Filter out installed keyword masked packages when populating | | zmedico | RootConfig.visible_pkgs since otherwise such packages can | | | trigger undesireable results inside | | | depgraph._iter_atoms_for_pkg(). | | 10474 | Make the unmerge time CONFIG_MEMORY_FILE pruning slightly | | zmedico | more aggressive, so that anything not claimed by another | | | package in the same slot is pruned. | | 10476 | Save the content of CONFIG_MEMORY_FILE in dblink.treewalk() | | zmedico | _before_ unmerging other instances, in order to avoid | | | overwritting/undoing the pruning that's done during unmerge. | | 10478 | Make --skipfirst handle missing dependencies by dropping the | | zmedico | merge tasks that have missing dependencies. This involves | | | creating an entirely new depgraph each time that a missing | | | dependency is discovered. This isn't the most efficient | | | approach but it's simple and it works well. This new | | | behavior can server as a fix for bug #12768 by calling | | | emerge --resume --skipfirst each time that emerge exits | | | unsuccessfully. This was possible before, but now packages | | | with unsatisfied dependencies will be properly identified | | | and dropped from the list. | | 10479 | Clean up exception reference from previous commit. | | zmedico | | | 10480 | When --skipfirst drops packages due to unsatisfied | | zmedico | dependencies, display a warning message with the list of | | | dropped packages. | svn path=/main/branches/prefix/; revision=10542 --- bin/doman | 13 ++- pym/_emerge/__init__.py | 148 ++++++++++++++++++++++++++++------- pym/portage/__init__.py | 10 +-- pym/portage/dbapi/vartree.py | 21 ++--- pym/portage/output.py | 8 +- 5 files changed, 149 insertions(+), 51 deletions(-) diff --git a/bin/doman b/bin/doman index 1e8203215..59de97794 100755 --- a/bin/doman +++ b/bin/doman @@ -31,15 +31,22 @@ for x in "$@" ; do suffix=${realname##*.} fi - mandir=${i18n}man${suffix:0:1} + if ! hasq "${EAPI:-0}" 0 1 && \ + [[ $x =~ (.*)\.([a-z][a-z](_[A-Z][A-Z])?)\.(.*) ]] ; then + name=${BASH_REMATCH[1]##*/}.${BASH_REMATCH[4]} + mandir=${BASH_REMATCH[2]}/man${suffix:0:1} + else + name=${x##*/} + mandir=${i18n}man${suffix:0:1} + fi - if echo ${mandir} | @EGREP@ -q 'man[0-9n](|f|p|pm)$' -; then + if [[ ${mandir} =~ man[0-9n](|f|p|pm)$ ]] ; then if [[ -s ${x} ]] ; then if [[ ! -d ${ED}/usr/share/man/${mandir} ]] ; then install -d "${ED}/usr/share/man/${mandir}" fi - install -m0644 "${x}" "${ED}/usr/share/man/${mandir}" + install -m0644 "${x}" "${ED}/usr/share/man/${mandir}/${name}" ((ret+=$?)) elif [[ ! -e ${x} ]] ; then vecho "doman: ${x} does not exist" 1>&2 diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index 5d0bce859..c84e3beb0 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -2017,7 +2017,7 @@ class depgraph(object): self._displayed_list = None self._pprovided_args = [] self._missing_args = [] - self._masked_installed = [] + self._masked_installed = set() self._unsatisfied_deps_for_display = [] self._unsatisfied_blockers_for_display = None self._circular_deps_for_display = None @@ -2326,12 +2326,6 @@ class depgraph(object): del e return 0 - if pkg.installed: - # Warn if an installed package is masked and it - # is pulled into the graph. - if not visible(pkgsettings, pkg): - self._masked_installed.append((pkg, pkgsettings)) - if args: self._set_nodes.add(pkg) @@ -3061,7 +3055,8 @@ class depgraph(object): # List of acceptable packages, ordered by type preference. matched_packages = [] highest_version = None - atom = portage.dep.Atom(atom) + if not isinstance(atom, portage.dep.Atom): + atom = portage.dep.Atom(atom) atom_cp = atom.cp existing_node = None myeb = None @@ -3104,12 +3099,31 @@ class depgraph(object): # the newly built package still won't have the expected slot. # Therefore, assume that such SLOT dependencies are already # satisfied rather than forcing a rebuild. - if installed and not cpv_list and matched_packages \ - and portage.dep.dep_getslot(atom): + if installed and not cpv_list and \ + matched_packages and atom.slot: for pkg in matched_packages: - if vardb.cpv_exists(pkg.cpv): - cpv_list = [pkg.cpv] - break + if not vardb.cpv_exists(pkg.cpv): + continue + inst_pkg = self._pkg_cache.get( + (pkg_type, root, pkg.cpv, "nomerge")) + if inst_pkg is None: + metadata = izip(self._mydbapi_keys, + vardb.aux_get(cpv, self._mydbapi_keys)) + inst_pkg = Package(built=built, cpv=pkg.cpv, + installed=installed, metadata=metadata, + onlydeps=onlydeps, root_config=root_config, + type_name=pkg_type) + self._pkg_cache[inst_pkg] = inst_pkg + # Remove the slot from the atom and verify that + # the package matches the resulting atom. + atom_without_slot = portage.dep.remove_slot(atom) + if atom.use: + atom_without_slot += str(atom.use) + atom_without_slot = portage.dep.Atom(atom_without_slot) + if portage.match_from_list( + atom_without_slot, [inst_pkg]): + cpv_list = [inst_pkg.cpv] + break if not cpv_list: continue @@ -3455,11 +3469,51 @@ class depgraph(object): portdb = self.trees[myroot]["porttree"].dbapi pkgsettings = self.pkgsettings[myroot] final_db = self.mydbapi[myroot] + + graph_complete_for_root = "complete" in self.myparams or \ + (myroot == self.target_root and \ + ("deep" in self.myparams or "empty" in self.myparams) and \ + not self._required_set_names.difference(self._sets)) + blocker_cache = BlockerCache(myroot, vardb) stale_cache = set(blocker_cache) for pkg in vardb: cpv = pkg.cpv stale_cache.discard(cpv) + + # Check for masked installed packages. For keyword + # mask there are a couple of common cases that are + # likely to generate unwanted noise: + # + # * Packages missing /var/db/pkg/*/*/KEYWORDS entries + # due to having been installed by an old version of + # portage. + # + # * Packages installed by overriding ACCEPT_KEYWORDS + # via the environment. + # + # To avoid unwanted noise, only warn about keyword + # masks if all of the following are true: + # + # * KEYWORDS is not empty (not installed by old portage). + # + # * The graph is complete and the package has not been + # pulled into the dependency graph. It's eligible for + # depclean, but depclean may fail to recognize it as + # such due to differences in visibility filtering which + # can lead to differences in || dep evaluation. + # TODO: Share visibility code to fix this inconsistency. + + if pkg in final_db: + if not visible(pkgsettings, pkg): + self._masked_installed.add(pkg) + elif graph_complete_for_root and \ + pkgsettings.getMissingKeywords( + pkg.cpv, pkg.metadata) and \ + pkg.metadata["KEYWORDS"].split() and \ + not self.digraph.contains(pkg): + self._masked_installed.add(pkg) + blocker_atoms = None blockers = None if self.digraph.contains(pkg): @@ -5124,8 +5178,9 @@ class depgraph(object): sys.stderr.write("".join(msg)) masked_packages = [] - for pkg, pkgsettings in self._masked_installed: - root_config = self.roots[pkg.root] + for pkg in self._masked_installed: + root_config = pkg.root_config + pkgsettings = root_config.settings mreasons = get_masking_status(pkg, pkgsettings, root_config) masked_packages.append((root_config, pkgsettings, pkg.cpv, pkg.metadata, mreasons)) @@ -5254,13 +5309,6 @@ class depgraph(object): if not isinstance(mergelist, list): mergelist = [] - if mergelist and "--skipfirst" in self.myopts: - for i, task in enumerate(mergelist): - if isinstance(task, list) and \ - task and task[-1] == "merge": - del mergelist[i] - break - fakedb = self.mydbapi trees = self.trees serialized_tasks = [] @@ -5577,7 +5625,9 @@ class depgraph(object): def __setitem__(self, k, v): dict.__setitem__(self, k, v) root_config = self._depgraph.roots[v.root] - if visible(root_config.settings, v): + if visible(root_config.settings, v) and \ + not (v.installed and \ + v.root_config.settings.getMissingKeywords(v.cpv, v.metadata)): root_config.visible_pkgs.cpv_inject(v) class RepoDisplay(object): @@ -8393,11 +8443,43 @@ def action_build(settings, trees, mtimedb, if show_spinner: print "Calculating dependencies ", myparams = create_depgraph_params(myopts, myaction) - mydepgraph = depgraph(settings, trees, - myopts, myparams, spinner) + + resume_data = mtimedb["resume"] + mergelist = resume_data["mergelist"] + if mergelist and "--skipfirst" in myopts: + for i, task in enumerate(mergelist): + if isinstance(task, list) and \ + task and task[-1] == "merge": + del mergelist[i] + break + + dropped_tasks = set() + success = False try: - success = mydepgraph.loadResumeCommand(mtimedb["resume"]) + while True: + mydepgraph = depgraph(settings, trees, + myopts, myparams, spinner) + try: + success = mydepgraph.loadResumeCommand(mtimedb["resume"]) + except depgraph.UnsatisfiedResumeDep, e: + if "--skipfirst" not in myopts: + raise + unsatisfied_parents = set(dep.parent for dep in e.value) + pruned_mergelist = [] + for task in mergelist: + if isinstance(task, list) and \ + tuple(task) in unsatisfied_parents: + continue + pruned_mergelist.append(task) + if not pruned_mergelist: + raise + mergelist[:] = pruned_mergelist + dropped_tasks.update(unsatisfied_parents) + del e + continue + else: + break except (portage.exception.PackageNotFound, mydepgraph.UnsatisfiedResumeDep), e: if show_spinner: @@ -8431,7 +8513,9 @@ def action_build(settings, trees, mtimedb, msg = "The resume list contains packages " + \ "with dependencies that have not been " + \ "installed yet. Please restart/continue " + \ - "the operation manually." + "the operation manually, or use --skipfirst " + \ + "to skip the first package in the list and " + \ + "any other packages that may have missing dependencies." for line in wrap(msg, 72): out.eerror(line) elif isinstance(e, portage.exception.PackageNotFound): @@ -8448,7 +8532,15 @@ def action_build(settings, trees, mtimedb, if show_spinner: print "\b\b... done!" - if not success: + if success: + if dropped_tasks: + portage.writemsg("!!! One or more packages have been " + \ + "dropped due to unsatisfied dependencies:\n\n", + noiselevel=-1) + for task in dropped_tasks: + portage.writemsg(" " + str(task) + "\n", noiselevel=-1) + portage.writemsg("\n", noiselevel=-1) + else: mydepgraph.display_problems() if not (ask or pretend): # delete the current list and also the backup diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index 1c68e38da..e4b493baa 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -6228,11 +6228,6 @@ def getmaskingstatus(mycpv, settings=None, portdb=None): kmask="~"+myarch break - # Assume that the user doesn't want to be bothered about - # KEYWORDS of packages that are already installed. - if kmask and not installed: - rValue.append(kmask+" keyword") - try: missing_licenses = settings.getMissingLicenses(mycpv, metadata) if missing_licenses: @@ -6247,6 +6242,11 @@ def getmaskingstatus(mycpv, settings=None, portdb=None): except portage.exception.InvalidDependString, e: rValue.append("LICENSE: "+str(e)) + # Only show KEYWORDS masks for installed packages + # if they're not masked for any other reason. + if kmask and (not installed or not rValue): + rValue.append(kmask+" keyword") + return rValue diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py index 9539e46b4..1cba9a55b 100644 --- a/pym/portage/dbapi/vartree.py +++ b/pym/portage/dbapi/vartree.py @@ -1620,9 +1620,6 @@ class dblink(object): continue if obj.startswith(dest_root): relative_path = obj[dest_root_len:] - if not others_in_slot and \ - relative_path in cfgfiledict: - stale_confmem.append(relative_path) is_owned = False for dblnk in others_in_slot: if dblnk.isowner(relative_path, dest_root): @@ -1633,6 +1630,8 @@ class dblink(object): # don't unmerge it. show_unmerge("---", "replaced", file_type, obj) continue + elif relative_path in cfgfiledict: + stale_confmem.append(relative_path) # next line includes a tweak to protect modules from being unmerged, # but we don't protect modules from being overwritten if they are # upgraded. We effectively only want one half of the config protection @@ -2430,6 +2429,12 @@ class dblink(object): outfile.flush() outfile.close() + # write out our collection of md5sums + cfgfiledict.pop("IGNORE", None) + ensure_dirs(os.path.dirname(conf_mem_file), + gid=portage_gid, mode=02750, mask=02) + writedict(cfgfiledict, conf_mem_file) + # These caches are populated during collision-protect and the data # they contain is now invalid. It's very important to invalidate # the contents_inodes cache so that FEATURES=unmerge-orphans @@ -2517,16 +2522,6 @@ class dblink(object): self.vartree.dbapi.cpcache.pop(self.mysplit[0], None) contents = self.getcontents() - #write out our collection of md5sums - if cfgfiledict.has_key("IGNORE"): - del cfgfiledict["IGNORE"] - - my_private_path = os.path.join(destroot, PRIVATE_PATH) - ensure_dirs(my_private_path, gid=portage_gid, mode=02750, mask=02) - - writedict(cfgfiledict, conf_mem_file) - del conf_mem_file - # regenerate reverse NEEDED map self.vartree.dbapi.linkmap.rebuild() diff --git a/pym/portage/output.py b/pym/portage/output.py index e9a1a559a..a7a500cd4 100644 --- a/pym/portage/output.py +++ b/pym/portage/output.py @@ -13,7 +13,8 @@ import shlex import sys from portage.const import COLOR_MAP_FILE from portage.util import writemsg -from portage.exception import PortageException, ParseError, PermissionDenied, FileNotFound +from portage.exception import CommandNotFound, FileNotFound, \ + ParseError, PermissionDenied, PortageException havecolor=1 dotitles=1 @@ -405,7 +406,10 @@ def set_term_size(lines, columns, fd): """ from portage.process import spawn cmd = ["stty", "rows", str(lines), "columns", str(columns)] - spawn(cmd, env=os.environ, fd_pipes={0:fd}) + try: + spawn(cmd, env=os.environ, fd_pipes={0:fd}) + except CommandNotFound: + writemsg("portage: stty: command not found\n", noiselevel=-1) class EOutput(object): """ -- 2.26.2