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
[ -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."
[ -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."
[ -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."
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
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
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
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
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 \
"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",
is missing)</para></listitem>
<listitem><para><varname>world-candidate</varname>, which determines if
given package should be added to the <varname>world</varname> set</para></listitem>
- <listitem><para><varname>extend</varname> to include the contents of other package sets</para>
- </listitem>
- <listitem><para><varname>remove</varname> to remove the contents of other package sets</para>
- </listitem>
- <listitem><para><varname>intersect</varname> to only include packages that are also
- included in one or more other package sets</para></listitem>
</itemizedlist>
<para>
Some handler classes might require additional options for their configuration,
sets each section still requires the <varname>class</varname> option,
but to indicate that the section should generate multiple sets it's
also necessary to set the <varname>multiset</varname> option to
- <parameter>true</parameter>. The <varname>world-candidate</varname>,
- <varname>extend</varname>, <varname>remove</varname> and
- <varname>intersect</varname> options are also supported like with
+ <parameter>true</parameter>. The <varname>world-candidate</varname>
+ option also supported like with
single sets (they'll apply to all sets generated by the section).
</para>
<para>
class = portage.sets.dbapi.CategorySet
multiset = true
name_pattern = $category/*
- intersect = installed
</programlisting>
</para>
<!-- TODO: reference list of available set handler classes here -->
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)
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
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:
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:
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()
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":
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):
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:
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
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:
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
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:
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)!
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.
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):