From 4d38c855abacad06ea5bf2680cc1f9a3443c75e5 Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Tue, 20 Oct 2009 15:26:57 +0000 Subject: [PATCH] Merged from trunk -r14674:14696 | 14675 | Fix messages broken in r14616. Thanks to Arfrever for | | zmedico | reporting and thanks to Jonathan Callen for this | | | patch. | | 14676 | Move filtering of misc bash variables from | | zmedico | save_ebuild_env() to filter_readonly_variables(). Add | | | additional variables found in the output of `env -i bash -c | | | 'declare -p'`. | | 14677 | Add a boolean expand_nested_sets parameter to | | zmedico | SetConfig.getSetAtoms(). This will be useful for adding | | | support to the dependency graph for keeping track of | | | precisely which nested set each atom comes from. | | 14678 | Revert r14677 since it doesn't interact well with the | | zmedico | 'extend', 'remove', and 'intersect' code in | | | SetConfig.getSetAtoms(). | | 14679 | Remove support for 'extend', 'remove', and 'intersect' | | zmedico | sets.conf section attributes in SetConfig.getSetAtoms() | | | since the current implementation does not meet user | | | expectations, as mentioned in bug #253802, comment #5: | | | Package set operators currently operate on atoms, but what | | | users really need is for them to operate on the packages | | | themselves. This will allow one set to add or subtract | | | packages from another even though the sets to not use the | | | exact same atoms to refer to the given packages. I imagine | | | the way this should be done is to create a mapping of atom | | | -> package for each set, perform the intersection using the | | | packages, and then map the package intersection back into a | | | set of atoms. | | 14680 | Add support for display of nested sets in --depclean and | | zmedico | --prune reverse dependency output. This also fixes a bug | | | from the 'selected' set changes which could cause the | | | system set to be disregarded in some cases. | | 14681 | Bug #259697 - Update IUSE.invalid docs for glep 56. Thanks | | zmedico | to Alec Warner for this patch. | | 14694 | drop IMAGE -- people have had years to catch up | | SpankMan | | | 14695 | Remove the docs for the extend, remove, and intersect | | zmedico | attributes that are not supported now. | | 14696 | Fix license_groups parsing to stack the lists, so | | zmedico | license_groups from overlays extend groups from the main | | | tree instead of overwritting them. Thanks to Vlastimil | | | Babka for reporting. | svn path=/main/branches/prefix/; revision=14700 --- bin/ebuild.sh | 19 ++++----- bin/isolated-functions.sh | 7 +--- bin/repoman | 2 +- doc/config/sets.docbook | 12 +----- pym/_emerge/actions.py | 80 +++++++++++++++++++----------------- pym/_emerge/depgraph.py | 24 ++++++++--- pym/portage/__init__.py | 8 ++-- pym/portage/sets/__init__.py | 31 ++------------ 8 files changed, 85 insertions(+), 98 deletions(-) diff --git a/bin/ebuild.sh b/bin/ebuild.sh index 4d843d1ed..a79e9fd83 100755 --- a/bin/ebuild.sh +++ b/bin/ebuild.sh @@ -81,10 +81,6 @@ unset GZIP BZIP BZIP2 CDPATH GREP_OPTIONS GREP_COLOR GLOBIGNORE source "${PORTAGE_BIN_PATH}/isolated-functions.sh" &>/dev/null -# Set IMAGE for minimal backward compatibility with -# overlays or user's bashrc, but don't export it. -[ "${EBUILD_PHASE}" == "preinst" ] && IMAGE=${D} - [[ $PORTAGE_QUIET != "" ]] && export PORTAGE_QUIET # the sandbox is disabled by default except when overridden in the relevant stages @@ -934,7 +930,7 @@ dyn_prepare() { [ -n "$EBUILD_PHASE" ] && rm -f "$T/logging/$EBUILD_PHASE" ebuild_phase pre_src_prepare - vecho ">>> Preparing source in $srcdir ..." + vecho ">>> Preparing source in $PWD ..." ebuild_phase src_prepare touch "$PORTAGE_BUILDDIR"/.prepared vecho ">>> Source prepared." @@ -966,7 +962,7 @@ dyn_configure() { [ -n "$EBUILD_PHASE" ] && rm -f "$T/logging/$EBUILD_PHASE" ebuild_phase pre_src_configure - vecho ">>> Configuring source in $srcdir ..." + vecho ">>> Configuring source in $PWD ..." ebuild_phase src_configure touch "$PORTAGE_BUILDDIR"/.configured vecho ">>> Source configured." @@ -999,7 +995,7 @@ dyn_compile() { [ -n "$EBUILD_PHASE" ] && rm -f "$T/logging/$EBUILD_PHASE" ebuild_phase pre_src_compile - vecho ">>> Compiling source in ${srcdir} ..." + vecho ">>> Compiling source in $PWD ..." ebuild_phase src_compile touch "$PORTAGE_BUILDDIR"/.compiled vecho ">>> Source compiled." @@ -1061,7 +1057,6 @@ dyn_install() { ebuild_phase pre_src_install rm -rf "${PORTAGE_BUILDDIR}/image" mkdir "${PORTAGE_BUILDDIR}/image" - local srcdir if [[ -d $S ]] ; then cd "${S}" elif hasq $EAPI 0 1 2; then @@ -1656,11 +1651,15 @@ filter_readonly_variables() { local x filtered_vars local readonly_bash_vars="BASHPID DIRSTACK EUID FUNCNAME GROUPS PIPESTATUS PPID SHELLOPTS UID" + local bash_misc_vars="BASH BASH_.* COMP_WORDBREAKS HISTCMD + HISTFILE HOSTNAME HOSTTYPE IFS LINENO MACHTYPE OLDPWD + OPTERR OPTIND OSTYPE POSIXLY_CORRECT PS4 PWD RANDOM + SECONDS SHELL SHLVL" local filtered_sandbox_vars="SANDBOX_ACTIVE SANDBOX_BASHRC SANDBOX_DEBUG_LOG SANDBOX_DISABLED SANDBOX_LIB SANDBOX_LOG SANDBOX_ON" - filtered_vars="${readonly_bash_vars} ${READONLY_PORTAGE_VARS} - BASH_.* HISTFILE PATH POSIXLY_CORRECT" + filtered_vars="$readonly_bash_vars $bash_misc_vars + $READONLY_PORTAGE_VARS PATH" if hasq --filter-sandbox $* ; then filtered_vars="${filtered_vars} SANDBOX_.*" else diff --git a/bin/isolated-functions.sh b/bin/isolated-functions.sh index 5987a522b..f1b73a701 100755 --- a/bin/isolated-functions.sh +++ b/bin/isolated-functions.sh @@ -505,10 +505,6 @@ save_ebuild_env() { fi fi - # misc variables set by bash - unset BASH HOSTTYPE IFS MACHTYPE OLDPWD \ - OPTERR OPTIND OSTYPE PS4 PWD SHELL SHLVL - # misc variables inherited from the calling environment unset COLORTERM DISPLAY EDITOR LESS LESSOPEN LOGNAME LS_COLORS PAGER \ TERM TERMCAP USER @@ -551,6 +547,7 @@ save_ebuild_env() { source_all_bashrcs ebuild_main \ ebuild_phase ebuild_phase_with_hooks \ _ebuild_arg_to_phase _ebuild_phase_funcs default \ + _pipestatus \ ${QA_INTERCEPTORS} # portage config variables and variables set directly by portage @@ -558,7 +555,7 @@ save_ebuild_env() { DISTCC_DIR DISTDIR DOC_SYMLINKS_DIR \ EBUILD_EXIT_STATUS_FILE EBUILD_FORCE_TEST EBUILD_MASTER_PID \ ECLASSDIR ECLASS_DEPTH ENDCOL FAKEROOTKEY \ - GOOD HILITE HOME IMAGE \ + GOOD HILITE HOME \ LAST_E_CMD LAST_E_LEN LD_PRELOAD MISC_FUNCTIONS_ARGS MOPREFIX \ NOCOLOR NORMAL PKGDIR PKGUSE PKG_LOGDIR PKG_TMPDIR \ PORTAGE_ACTUAL_DISTDIR PORTAGE_ARCHLIST \ diff --git a/bin/repoman b/bin/repoman index 961d013a4..68a8f799e 100755 --- a/bin/repoman +++ b/bin/repoman @@ -309,7 +309,7 @@ qahelp={ "variable.readonly":"Assigning a readonly variable", "LIVEVCS.stable":"This ebuild is a live checkout from a VCS but has stable keywords.", "LIVEVCS.unmasked":"This ebuild is a live checkout from a VCS but has keywords and is not masked in the global package.mask.", - "IUSE.invalid":"This ebuild has a variable in IUSE that is not in the use.desc or use.local.desc file", + "IUSE.invalid":"This ebuild has a variable in IUSE that is not in the use.desc or its metadata.xml file", "IUSE.undefined":"This ebuild does not define IUSE (style guideline says to define IUSE even when empty)", "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", diff --git a/doc/config/sets.docbook b/doc/config/sets.docbook index 8f93b1df2..ec8ff9a2a 100644 --- a/doc/config/sets.docbook +++ b/doc/config/sets.docbook @@ -57,12 +57,6 @@ is missing) world-candidate, which determines if given package should be added to the world set - extend to include the contents of other package sets - - remove to remove the contents of other package sets - - intersect to only include packages that are also - included in one or more other package sets Some handler classes might require additional options for their configuration, @@ -100,9 +94,8 @@ sets each section still requires the class option, but to indicate that the section should generate multiple sets it's also necessary to set the multiset option to - true. The world-candidate, - extend, remove and - intersect options are also supported like with + true. The world-candidate + option also supported like with single sets (they'll apply to all sets generated by the section). @@ -132,7 +125,6 @@ class = portage.sets.dbapi.CategorySet multiset = true name_pattern = $category/* - intersect = installed diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py index 4f319dbf3..ec661ad86 100644 --- a/pym/_emerge/actions.py +++ b/pym/_emerge/actions.py @@ -630,32 +630,44 @@ def calc_depclean(settings, trees, ldpath_mtimes, xterm_titles = "notitles" not in settings.features myroot = settings["ROOT"] root_config = trees[myroot]["root_config"] - getSetAtoms = root_config.setconfig.getSetAtoms + psets = root_config.setconfig.psets vardb = trees[myroot]["vartree"].dbapi deselect = myopts.get('--deselect') != 'n' - required_set_names = ("world",) + required_set_stack = ["world"] required_sets = {} set_args = [] - for s in required_set_names: - required_sets[s] = InternalPackageSet( - initial_atoms=getSetAtoms(s)) - - - # When removing packages, use a temporary version of world - # which excludes packages that are intended to be eligible for + # Recursively create InternalPackageSet instances for world + # and any sets nested within it. + while required_set_stack: + s = required_set_stack.pop() + if s in required_sets: + continue + pset = psets.get(s) + if pset is not None: + required_sets[s] = InternalPackageSet( + initial_atoms=pset.getAtoms()) + for n in pset.getNonAtoms(): + if n.startswith(SETPREFIX): + required_set_stack.append(n[len(SETPREFIX):]) + + # When removing packages, use a temporary version of world 'selected' + # set which excludes packages that are intended to be eligible for # removal. - world_temp_set = required_sets["world"] - system_set = root_config.sets["system"] + selected_set = required_sets["selected"] + protected_set = InternalPackageSet() + protected_set_name = '____depclean_protected_set____' + required_sets[protected_set_name] = protected_set + system_set = required_sets.get("system") - if not system_set or not world_temp_set: + if not system_set or not selected_set: if not system_set: writemsg_level("!!! You have no system list.\n", level=logging.ERROR, noiselevel=-1) - if not world_temp_set: + if not selected_set: writemsg_level("!!! You have no world file.\n", level=logging.WARNING, noiselevel=-1) @@ -678,7 +690,7 @@ def calc_depclean(settings, trees, ldpath_mtimes, if args_set: if deselect: - world_temp_set.clear() + selected_set.clear() # Pull in everything that's installed but not matched # by an argument atom since we don't want to clean any @@ -688,23 +700,23 @@ def calc_depclean(settings, trees, ldpath_mtimes, try: if args_set.findAtomForPackage(pkg) is None: - world_temp_set.add("=" + pkg.cpv) + protected_set.add("=" + pkg.cpv) continue except portage.exception.InvalidDependString as e: show_invalid_depstring_notice(pkg, pkg.metadata["PROVIDE"], str(e)) del e - world_temp_set.add("=" + pkg.cpv) + protected_set.add("=" + pkg.cpv) continue elif action == "prune": if deselect: - world_temp_set.clear() + selected_set.clear() # Pull in everything that's installed since we don't # to prune a package if something depends on it. - world_temp_set.update(vardb.cp_all()) + protected_set.update(vardb.cp_all()) if not args_set: @@ -727,7 +739,7 @@ def calc_depclean(settings, trees, ldpath_mtimes, highest_version = pkgs_for_cp[-1] if pkg == highest_version: # pkg is the highest version - world_temp_set.add("=" + pkg.cpv) + protected_set.add("=" + pkg.cpv) continue if len(pkgs_for_cp) <= 1: @@ -737,27 +749,16 @@ def calc_depclean(settings, trees, ldpath_mtimes, try: if args_set.findAtomForPackage(pkg) is None: - world_temp_set.add("=" + pkg.cpv) + protected_set.add("=" + pkg.cpv) continue except portage.exception.InvalidDependString as e: show_invalid_depstring_notice(pkg, pkg.metadata["PROVIDE"], str(e)) del e - world_temp_set.add("=" + pkg.cpv) + protected_set.add("=" + pkg.cpv) continue - set_args = {} - for s, package_set in required_sets.items(): - set_atom = SETPREFIX + s - set_arg = SetArg(arg=set_atom, set=package_set, - root_config=resolver._frozen_config.roots[myroot]) - set_args[s] = set_arg - for atom in set_arg.set: - resolver._dynamic_config._dep_stack.append( - Dependency(atom=atom, root=myroot, parent=set_arg)) - resolver._dynamic_config.digraph.add(set_arg, None) - - success = resolver._complete_graph() + success = resolver._complete_graph(required_sets={myroot:required_sets}) writemsg_level("\b\b... done!\n") resolver.display_problems() @@ -841,6 +842,13 @@ def calc_depclean(settings, trees, ldpath_mtimes, return -1 def create_cleanlist(): + + # Never display the special internal protected_set. + for node in graph: + if isinstance(node, SetArg) and node.name == protected_set_name: + graph.remove(node) + break + pkgs_to_remove = [] if action == "depclean": @@ -868,9 +876,6 @@ def calc_depclean(settings, trees, ldpath_mtimes, show_parents(pkg) elif action == "prune": - # Prune really uses all installed instead of world. It's not - # a real reverse dependency so don't display it as such. - graph.remove(set_args["world"]) for atom in args_set: for pkg in vardb.match_pkgs(atom): @@ -1062,7 +1067,8 @@ def calc_depclean(settings, trees, ldpath_mtimes, return 1, [], False, 0 writemsg_level("\nCalculating dependencies ") - success = resolver._complete_graph() + success = resolver._complete_graph( + required_sets={myroot:required_sets}) writemsg_level("\b\b... done!\n") resolver.display_problems() if not success: diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index 607f0255d..fcda3ec65 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -2565,7 +2565,7 @@ class depgraph(object): in_graph = self._dynamic_config._slot_pkg_map[root].get(pkg.slot_atom) return pkg, in_graph - def _complete_graph(self): + def _complete_graph(self, required_sets=None): """ Add any deep dependencies of required sets (args, system, world) that have not been pulled into the graph yet. This ensures that the graph @@ -2576,6 +2576,10 @@ class depgraph(object): Since this method can consume enough time to disturb users, it is currently only enabled by the --complete-graph option. + + @param required_sets: contains required sets (currently only used + for depclean and prune removal operations) + @type required_sets: dict """ if "--buildpkgonly" in self._frozen_config.myopts or \ "recurse" not in self._dynamic_config.myparams: @@ -2598,11 +2602,16 @@ class depgraph(object): self._dynamic_config.myparams["deep"] = True for root in self._frozen_config.roots: - required_set_names = self._frozen_config._required_set_names.copy() + if required_sets is None or root not in required_sets: + required_set_names = self._frozen_config._required_set_names.copy() + else: + required_set_names = set(required_sets[root]) if root == self._frozen_config.target_root and \ (already_deep or "empty" in self._dynamic_config.myparams): required_set_names.difference_update(self._dynamic_config._sets) - if not required_set_names and not self._dynamic_config._ignored_deps: + if not required_set_names and \ + not self._dynamic_config._ignored_deps and \ + not self._dynamic_config._dep_stack: continue root_config = self._frozen_config.roots[root] setconfig = root_config.setconfig @@ -2618,11 +2627,16 @@ class depgraph(object): required_set_names.remove(arg.name) # Create new SetArg instances only when necessary. for s in required_set_names: - expanded_set = InternalPackageSet( - initial_atoms=setconfig.getSetAtoms(s)) + if required_sets is None or root not in required_sets: + expanded_set = InternalPackageSet( + initial_atoms=setconfig.getSetAtoms(s)) + else: + expanded_set = required_sets[root][s] atom = SETPREFIX + s args.append(SetArg(arg=atom, set=expanded_set, root_config=root_config)) + if root == self._frozen_config.target_root: + self._dynamic_config._sets[s] = expanded_set vardb = root_config.trees["vartree"].dbapi for arg in args: for atom in arg.set: diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index e247faa7a..11c80fccb 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -2143,9 +2143,11 @@ class config(object): self.pprovideddict[mycatpkg]=[x] # parse licensegroups + license_groups = self._license_groups for x in locations: - self._license_groups.update( - grabdict(os.path.join(x, "license_groups"))) + for k, v in grabdict( + os.path.join(x, "license_groups")).items(): + license_groups.setdefault(k, []).extend(v) # reasonable defaults; this is important as without USE_ORDER, # USE will always be "" (nothing set)! @@ -3988,7 +3990,7 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakero Optiosn include: Sandbox: Sandbox means the spawned process will be limited in its ability t - read and write files (normally this means it is restricted to ${IMAGE}/) + read and write files (normally this means it is restricted to ${D}/) SElinux Sandbox: Enables sandboxing on SElinux Reduced Privileges: Drops privilages such that the process runs as portage:portage instead of as root. diff --git a/pym/portage/sets/__init__.py b/pym/portage/sets/__init__.py index ab67642b8..59c3dbfd7 100644 --- a/pym/portage/sets/__init__.py +++ b/pym/portage/sets/__init__.py @@ -155,44 +155,21 @@ class SetConfig(object): raise PackageSetNotFound(setname) myatoms = myset.getAtoms() parser = self._parser - extend = set() - remove = set() - intersect = set() - + if ignorelist is None: ignorelist = set() - # If sets.conf is corrupt then emerge generates - # fallback sets without the 'creator' attribute. - if setname not in ignorelist and hasattr(myset, 'creator'): - if parser.has_option(myset.creator, "extend"): - extend.update(parser.get(myset.creator, "extend").split()) - if parser.has_option(myset.creator, "remove"): - remove.update(parser.get(myset.creator, "remove").split()) - if parser.has_option(myset.creator, "intersect"): - intersect.update(parser.get(myset.creator, "intersect").split()) - ignorelist.add(setname) for n in myset.getNonAtoms(): if n.startswith(SETPREFIX): s = n[len(SETPREFIX):] if s in self.psets: - extend.add(n[len(SETPREFIX):]) + if s not in ignorelist: + myatoms.update(self.getSetAtoms(s, + ignorelist=ignorelist)) else: raise PackageSetNotFound(s) - for s in ignorelist: - extend.discard(s) - remove.discard(s) - intersect.discard(s) - - for s in extend: - myatoms.update(self.getSetAtoms(s, ignorelist=ignorelist)) - for s in remove: - myatoms.difference_update(self.getSetAtoms(s, ignorelist=ignorelist)) - for s in intersect: - myatoms.intersection_update(self.getSetAtoms(s, ignorelist=ignorelist)) - return myatoms def load_default_config(settings, trees): -- 2.26.2