summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys-apps/portage/files/portage-2.2.14-prefix-chaining.patch873
-rw-r--r--sys-apps/portage/files/portage-2.3.18-prefix-chaining.patch927
-rw-r--r--sys-apps/portage/files/portage-2.3.40-prefix-chaining.patch921
-rw-r--r--sys-apps/portage/files/portage-2.3.62-prefix-stack.patch80
-rw-r--r--sys-apps/portage/files/portage-2.3.8-prefix-chaining.patch927
-rw-r--r--sys-apps/portage/metadata.xml1
-rw-r--r--sys-apps/portage/portage-2.3.52.2.ebuild6
-rw-r--r--sys-apps/portage/portage-2.3.55.1.ebuild4
-rw-r--r--sys-apps/portage/portage-2.3.62-r00.1.ebuild271
-rw-r--r--sys-apps/portage/portage-2.3.62.ebuild4
10 files changed, 355 insertions, 3659 deletions
diff --git a/sys-apps/portage/files/portage-2.2.14-prefix-chaining.patch b/sys-apps/portage/files/portage-2.2.14-prefix-chaining.patch
deleted file mode 100644
index 5c38795bb2..0000000000
--- a/sys-apps/portage/files/portage-2.2.14-prefix-chaining.patch
+++ /dev/null
@@ -1,873 +0,0 @@
-diff -ru prefix-portage-2.2.14.orig/bin/install-qa-check.d/05prefix prefix-portage-2.2.14/bin/install-qa-check.d/05prefix
---- prefix-portage-2.2.14.orig/bin/install-qa-check.d/05prefix 2014-09-28 19:31:20.000000000 +0200
-+++ prefix-portage-2.2.14/bin/install-qa-check.d/05prefix 2015-06-17 10:08:15.074682823 +0200
-@@ -79,16 +79,42 @@
- # unprefixed shebang, is the script directly in $PATH or an init
- # script?
- if [[ ":${PATH}:${EPREFIX}/etc/init.d:" == *":${fp}:"* ]] ; then
-- if [[ -e ${EROOT}${line[0]} || -e ${ED}${line[0]} ]] ; then
-+ all_epfs="$PORTAGE_READONLY_EPREFIXES:$EPREFIX:$EROOT:$ED"
-+ save_IFS=$IFS
-+ IFS=:
-+ epfs=( $all_epfs )
-+ IFS=$save_IFS
-+
-+ found=
-+ for x in "${epfs[@]}"; do
-+ [[ -z "${x}" ]] && continue
-+ check="${x}${line[0]}"
-+
-+ # might already contain a prefix
-+ if [[ "${line[0]}" == "${x}"* ]]; then
-+ check="${line[0]}"
-+ fi
-+
-+ if [[ -e ${check} ]]; then
-+ found="${check}"
-+ fi
-+ done
-+
-+ if [[ -n ${found} ]] ; then
- # is it unprefixed, but we can just fix it because a
- # prefixed variant exists
- eqawarn "prefixing shebang of ${fn#${D}}"
-+
-+ if [[ ${found} == "${ED}"* || ${found} == "${EROOT}"* ]]; then
-+ found="${EPREFIX}${line[0]}"
-+ fi
-+
- # statement is made idempotent on purpose, because
- # symlinks may point to the same target, and hence the
- # same real file may be sedded multiple times since we
- # read the shebangs in one go upfront for performance
- # reasons
-- sed -i -e '1s:^#! \?'"${line[0]}"':#!'"${EPREFIX}"${line[0]}':' "${rf}"
-+ sed -i -e '1s:^#! \?'"${line[0]}"':#!'"${found}"':' "${rf}"
- continue
- else
- # this is definitely wrong: script in $PATH and invalid shebang
-diff -ru prefix-portage-2.2.14.orig/bin/phase-helpers.sh prefix-portage-2.2.14/bin/phase-helpers.sh
---- prefix-portage-2.2.14.orig/bin/phase-helpers.sh 2014-09-28 19:12:31.000000000 +0200
-+++ prefix-portage-2.2.14/bin/phase-helpers.sh 2015-06-17 10:24:28.997164214 +0200
-@@ -758,6 +758,10 @@
- "${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" has_version "${eroot}" "${atom}"
- fi
- local retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ ${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${READONLY_EPREFIX%:*}'/usr/lib/portage/bin/portageq has_version '${READONLY_EPREFIX%:*}' '${atom}'"
-+ retval=$?
-+ fi
- case "${retval}" in
- 0|1)
- return ${retval}
-@@ -817,6 +821,10 @@
- "${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" best_version "${eroot}" "${atom}"
- fi
- local retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ ${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${READONLY_EPREFIX%:*}'/usr/lib/portage/bin/portageq best_version '${READONLY_EPREFIX%:*}' '${atom}'"
-+ retval=$?
-+ fi
- case "${retval}" in
- 0|1)
- return ${retval}
-@@ -846,6 +854,10 @@
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" master_repositories "${EROOT}" "${repository}")
- fi
- retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${READONLY_EPREFIX%:*}'/usr/lib/portage/bin/portageq master_repositories '${READONLY_EPREFIX%:*}' '${repository}'")
-+ retval=$?
-+ fi
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
- 0|1)
-@@ -877,6 +889,10 @@
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" get_repo_path "${EROOT}" "${repository}")
- fi
- retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${READONLY_EPREFIX%:*}'/usr/lib/portage/bin/portageq repository_path '${READONLY_EPREFIX%:*}' '${repository}'")
-+ retval=$?
-+ fi
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
- 0|1)
-@@ -907,6 +923,10 @@
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" available_eclasses "${EROOT}" "${repository}")
- fi
- retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${READONLY_EPREFIX%:*}'/usr/lib/portage/bin/portageq available_eclasses '${READONLY_EPREFIX%:*}' '${repository}'")
-+ retval=$?
-+ fi
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
- 0|1)
-@@ -937,6 +957,10 @@
- else
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" eclass_path "${EROOT}" "${repository}" "${eclass}")
- fi
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${READONLY_EPREFIX%:*}'/usr/lib/portage/bin/portageq eclass_path '${READONLY_EPREFIX%:*}' '${repository}' '${eclass}'")
-+ retval=$?
-+ fi
- retval=$?
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
-@@ -968,6 +992,10 @@
- else
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" license_path "${EROOT}" "${repository}" "${license}")
- fi
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${READONLY_EPREFIX%:*}'/usr/lib/portage/bin/portageq license_path '${READONLY_EPREFIX%:*}' '${repository}' '${license}'")
-+ retval=$?
-+ fi
- retval=$?
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
-Only in prefix-portage-2.2.14/bin: phase-helpers.sh.orig
-diff -ru prefix-portage-2.2.14.orig/pym/_emerge/actions.py prefix-portage-2.2.14/pym/_emerge/actions.py
---- prefix-portage-2.2.14.orig/pym/_emerge/actions.py 2014-10-02 20:48:26.000000000 +0200
-+++ prefix-portage-2.2.14/pym/_emerge/actions.py 2015-06-17 10:24:28.997164214 +0200
-@@ -38,7 +38,7 @@
- from portage import shutil
- from portage import eapi_is_supported, _encodings, _unicode_decode
- from portage.cache.cache_errors import CacheError
--from portage.const import EPREFIX
-+from portage.const import EPREFIX, BPREFIX
- from portage.const import GLOBAL_CONFIG_PATH, VCS_DIRS, _DEPCLEAN_LIB_CHECK_DEFAULT
- from portage.const import SUPPORTED_BINPKG_FORMATS, TIMESTAMP_FORMAT
- from portage.dbapi.dep_expand import dep_expand
-@@ -62,6 +62,7 @@
- from portage.util._async.run_main_scheduler import run_main_scheduler
- from portage.util._async.SchedulerInterface import SchedulerInterface
- from portage.util._eventloop.global_event_loop import global_event_loop
-+from portage.util._path import exists_raise_eaccess
- from portage._global_updates import _global_updates
-
- from _emerge.clear_caches import clear_caches
-@@ -2629,7 +2630,8 @@
- out.eerror(line)
- return exitcode
- elif repo.sync_type == "cvs":
-- if not os.path.exists(EPREFIX + "/usr/bin/cvs"):
-+ cvs_bin = portage.process.find_binary("cvs")
-+ if cvs_bin is None:
- print("!!! %s/usr/bin/cvs does not exist, so CVS support is disabled." % (EPREFIX))
- print("!!! Type \"emerge %s\" to enable CVS support." % portage.const.CVS_PACKAGE_ATOM)
- return os.EX_UNAVAILABLE
-@@ -2697,6 +2699,13 @@
- writemsg_level(" %s spawn failed of %s\n" % (bad("*"), postsync,),
- level=logging.ERROR, noiselevel=-1)
-
-+ postsync = os.path.join(BPREFIX, portage.USER_CONFIG_PATH, "bin", "post_sync")
-+ if os.access(postsync, os.X_OK):
-+ retval = portage.process.spawn([postsync, dosyncuri], env=settings.environ())
-+ if retval != os.EX_OK:
-+ writemsg_level(" %s spawn failed of %s\n" % (bad("*"), postsync,),
-+ level=logging.ERROR, noiselevel=-1)
-+
- return os.EX_OK
-
- def action_uninstall(settings, trees, ldpath_mtimes,
-@@ -3413,6 +3422,9 @@
- if portage.const.EPREFIX:
- global_config_path = os.path.join(portage.const.EPREFIX,
- portage.const.GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(global_config_path) and portage.const.BPREFIX:
-+ global_config_path = os.path.join(portage.const.BPREFIX,
-+ portage.const.GLOBAL_CONFIG_PATH.lstrip(os.sep))
- msg.append(" This usually means that '%s'" % \
- (os.path.join(global_config_path, "sets/portage.conf"),))
- msg.append(" is missing or corrupt.")
-Only in prefix-portage-2.2.14/pym/_emerge: actions.py.orig
-diff -ru prefix-portage-2.2.14.orig/pym/_emerge/depgraph.py prefix-portage-2.2.14/pym/_emerge/depgraph.py
---- prefix-portage-2.2.14.orig/pym/_emerge/depgraph.py 2014-11-12 18:26:12.000000000 +0100
-+++ prefix-portage-2.2.14/pym/_emerge/depgraph.py 2015-06-17 10:19:41.254082296 +0200
-@@ -2743,23 +2743,24 @@
- edepend["HDEPEND"] = ""
-
- deps = (
-- (depend_root, edepend["DEPEND"],
-+ (depend_root, "DEPEND",
- self._priority(buildtime=True,
- optional=(pkg.built or ignore_depend_deps),
- ignored=ignore_depend_deps)),
-- (self._frozen_config._running_root.root, edepend["HDEPEND"],
-+ (self._frozen_config._running_root.root, "HDEPEND",
- self._priority(buildtime=True,
- optional=(pkg.built or ignore_hdepend_deps),
- ignored=ignore_hdepend_deps)),
-- (myroot, edepend["RDEPEND"],
-+ (myroot, "RDEPEND",
- self._priority(runtime=True)),
-- (myroot, edepend["PDEPEND"],
-+ (myroot, "PDEPEND",
- self._priority(runtime_post=True))
- )
-
- debug = "--debug" in self._frozen_config.myopts
-
-- for dep_root, dep_string, dep_priority in deps:
-+ for dep_root, dep_type, dep_priority in deps:
-+ dep_string = edepend[dep_type]
- if not dep_string:
- continue
- if debug:
-@@ -2797,7 +2798,7 @@
-
- try:
- dep_string = list(self._queue_disjunctive_deps(
-- pkg, dep_root, dep_priority, dep_string))
-+ pkg, dep_root, dep_priority, dep_string, dep_type))
- except portage.exception.InvalidDependString as e:
- if pkg.installed:
- self._dynamic_config._masked_installed.add(pkg)
-@@ -2812,14 +2813,14 @@
-
- if not self._add_pkg_dep_string(
- pkg, dep_root, dep_priority, dep_string,
-- allow_unsatisfied):
-+ allow_unsatisfied, dep_type):
- return 0
-
- self._dynamic_config._traversed_pkg_deps.add(pkg)
- return 1
-
- def _add_pkg_dep_string(self, pkg, dep_root, dep_priority, dep_string,
-- allow_unsatisfied):
-+ allow_unsatisfied, dep_type=None):
- _autounmask_backup = self._dynamic_config._autounmask
- if dep_priority.optional or dep_priority.ignored:
- # Temporarily disable autounmask for deps that
-@@ -2828,7 +2829,7 @@
- try:
- return self._wrapped_add_pkg_dep_string(
- pkg, dep_root, dep_priority, dep_string,
-- allow_unsatisfied)
-+ allow_unsatisfied, dep_type)
- finally:
- self._dynamic_config._autounmask = _autounmask_backup
-
-@@ -2864,7 +2865,7 @@
- not slot_operator_rebuild
-
- def _wrapped_add_pkg_dep_string(self, pkg, dep_root, dep_priority,
-- dep_string, allow_unsatisfied):
-+ dep_string, allow_unsatisfied, dep_type=None):
- if isinstance(pkg.depth, int):
- depth = pkg.depth + 1
- else:
-@@ -2888,7 +2889,7 @@
- try:
- selected_atoms = self._select_atoms(dep_root,
- dep_string, myuse=self._pkg_use_enabled(pkg), parent=pkg,
-- strict=strict, priority=dep_priority)
-+ strict=strict, priority=dep_priority, dep_type=dep_type)
- except portage.exception.InvalidDependString:
- if pkg.installed:
- self._dynamic_config._masked_installed.add(pkg)
-@@ -3186,7 +3187,7 @@
- child_pkgs.sort()
- yield (atom, child_pkgs[-1])
-
-- def _queue_disjunctive_deps(self, pkg, dep_root, dep_priority, dep_struct):
-+ def _queue_disjunctive_deps(self, pkg, dep_root, dep_priority, dep_struct, dep_type=None):
- """
- Queue disjunctive (virtual and ||) deps in self._dynamic_config._dep_disjunctive_stack.
- Yields non-disjunctive deps. Raises InvalidDependString when
-@@ -3195,33 +3196,33 @@
- for x in dep_struct:
- if isinstance(x, list):
- if x and x[0] == "||":
-- self._queue_disjunction(pkg, dep_root, dep_priority, [x])
-+ self._queue_disjunction(pkg, dep_root, dep_priority, [x], dep_type)
- else:
- for y in self._queue_disjunctive_deps(
-- pkg, dep_root, dep_priority, x):
-+ pkg, dep_root, dep_priority, x, dep_type):
- yield y
- else:
- # Note: Eventually this will check for PROPERTIES=virtual
- # or whatever other metadata gets implemented for this
- # purpose.
- if x.cp.startswith('virtual/'):
-- self._queue_disjunction(pkg, dep_root, dep_priority, [x])
-+ self._queue_disjunction(pkg, dep_root, dep_priority, [x], dep_type)
- else:
- yield x
-
-- def _queue_disjunction(self, pkg, dep_root, dep_priority, dep_struct):
-+ def _queue_disjunction(self, pkg, dep_root, dep_priority, dep_struct, dep_type=None):
- self._dynamic_config._dep_disjunctive_stack.append(
-- (pkg, dep_root, dep_priority, dep_struct))
-+ (pkg, dep_root, dep_priority, dep_struct, dep_type))
-
- def _pop_disjunction(self, allow_unsatisfied):
- """
- Pop one disjunctive dep from self._dynamic_config._dep_disjunctive_stack, and use it to
- populate self._dynamic_config._dep_stack.
- """
-- pkg, dep_root, dep_priority, dep_struct = \
-+ pkg, dep_root, dep_priority, dep_struct, dep_type = \
- self._dynamic_config._dep_disjunctive_stack.pop()
- if not self._add_pkg_dep_string(
-- pkg, dep_root, dep_priority, dep_struct, allow_unsatisfied):
-+ pkg, dep_root, dep_priority, dep_struct, allow_unsatisfied, dep_type):
- return 0
- return 1
-
-@@ -4030,7 +4031,7 @@
- **portage._native_kwargs(kwargs))
-
- def _select_atoms_highest_available(self, root, depstring,
-- myuse=None, parent=None, strict=True, trees=None, priority=None):
-+ myuse=None, parent=None, strict=True, trees=None, priority=None, dep_type=None):
- """This will raise InvalidDependString if necessary. If trees is
- None then self._dynamic_config._filtered_trees is used."""
-
-@@ -4053,6 +4054,13 @@
- pkgsettings = self._frozen_config.pkgsettings[root]
- if trees is None:
- trees = self._dynamic_config._filtered_trees
-+
-+ # this one is needed to guarantee good readonly root
-+ # resolution display in the merge list. required since
-+ # parent (below) can be None
-+ trees[root]["disp_parent"] = parent
-+
-+
- mytrees = trees[root]
- atom_graph = digraph()
- if True:
-@@ -4081,7 +4089,7 @@
-
- mycheck = portage.dep_check(depstring, None,
- pkgsettings, myuse=myuse,
-- myroot=root, trees=trees)
-+ myroot=root, trees=trees, dep_type=dep_type)
- finally:
- # restore state
- self._dynamic_config._autounmask = _autounmask_backup
-@@ -4152,6 +4160,7 @@
- continue
- node_stack.append((child_node, node, child_atom))
-
-+ trees[root].pop("disp_parent")
- return selected_atoms
-
- def _expand_virt_from_graph(self, root, atom):
-diff -ru prefix-portage-2.2.14.orig/pym/_emerge/resolver/output.py prefix-portage-2.2.14/pym/_emerge/resolver/output.py
---- prefix-portage-2.2.14.orig/pym/_emerge/resolver/output.py 2014-05-06 21:32:08.000000000 +0200
-+++ prefix-portage-2.2.14/pym/_emerge/resolver/output.py 2015-06-17 10:24:28.920497614 +0200
-@@ -22,11 +22,12 @@
- from portage.package.ebuild.config import _get_feature_flags
- from portage.package.ebuild._spawn_nofetch import spawn_nofetch
- from portage.output import ( blue, colorize, create_color_func,
-- darkblue, darkgreen, green, nc_len, teal)
-+ darkblue, darkgreen, green, nc_len, teal, yellow, turquoise)
- bad = create_color_func("BAD")
- from portage._sets.base import InternalPackageSet
- from portage.util import writemsg_stdout
- from portage.versions import best, cpv_getversion
-+from portage.dep.dep_check import ro_selected
-
- from _emerge.Blocker import Blocker
- from _emerge.create_world_atom import create_world_atom
-@@ -556,6 +557,42 @@
- writemsg_stdout("%s\n" % (pkg,), noiselevel=-1)
- return
-
-+ def print_readonly_prefix(self):
-+ """Performs the actual output printing for the readonly prefix
-+ information stuff
-+ """
-+ out = sys.stdout
-+
-+ # print readonly selected packages
-+ if len(ro_selected) > 0:
-+ out.write("\n%s\n\n" % (darkgreen("Packages resolved from readonly installations:")))
-+
-+ ro_mismatch_warning = False
-+ ro_dupcheck = []
-+ for x in ro_selected:
-+ tmp_type = x["type"].replace("END","")
-+ while len(tmp_type) < 4:
-+ tmp_type += " "
-+ if x["parent"] and str(x["atom"]) not in ro_dupcheck:
-+ out.write("[%s %s] %s %s %s (%s by %s)" % (teal("readonly"),
-+ green(tmp_type), green(str(x["matches"][0])), yellow("from"),
-+ blue(x["ro_root"]), turquoise(str(x["atom"])), green(x["parent"].cpv)))
-+
-+ ro_dupcheck.append(str(x["atom"]))
-+
-+ if x["host_mismatch"]:
-+ ro_mismatch_warning = True
-+ out.write(" %s\n" % (red("**")))
-+ else:
-+ out.write("\n")
-+
-+ if ro_mismatch_warning:
-+ out.write("\n%s:" % (red("**")))
-+ out.write(yellow(" WARNING: packages marked with ** have been resolved as a\n"))
-+ out.write(yellow(" runtime dependency, but the CHOST variable for the parent\n"))
-+ out.write(yellow(" and dependency package don't match. This could cause link\n"))
-+ out.write(yellow(" errors. It is recommended to use RDEPEND READONLY_EPREFIX's\n"))
-+ out.write(yellow(" only with matching CHOST portage instances.\n"))
-
- def print_verbose(self, show_repos):
- """Prints the verbose output to std_out
-@@ -907,6 +944,7 @@
- # now finally print out the messages
- self.print_messages(show_repos)
- self.print_blockers()
-+ self.print_readonly_prefix()
- if self.conf.verbosity == 3:
- self.print_verbose(show_repos)
- for pkg, pkg_info in self.restrict_fetch_list.items():
-diff -ru prefix-portage-2.2.14.orig/pym/portage/const.py prefix-portage-2.2.14/pym/portage/const.py
---- prefix-portage-2.2.14.orig/pym/portage/const.py 2014-11-12 18:26:12.000000000 +0100
-+++ prefix-portage-2.2.14/pym/portage/const.py 2015-06-17 10:24:28.963830910 +0200
-@@ -187,6 +187,7 @@
- "notitles",
- "parallel-fetch",
- "parallel-install",
-+ "prefix-chaining",
- "prelink-checksums",
- "preserve-libs",
- "protect-owned",
-@@ -265,6 +266,11 @@
- #EPREFIX = ""
- # END PREFIX LOCAL
-
-+BPREFIX = EPREFIX
-+
-+# --prefix commandline arg always rules, ends up in os.environ["EPREFIX"]
-+if "EPREFIX" in os.environ:
-+ os.environ["PORTAGE_OVERRIDE_EPREFIX"] = os.environ["EPREFIX"]
- # pick up EPREFIX from the environment if set
- if "PORTAGE_OVERRIDE_EPREFIX" in os.environ:
- EPREFIX = os.environ["PORTAGE_OVERRIDE_EPREFIX"]
-Only in prefix-portage-2.2.14/pym/portage: const.py.orig
-diff -ru prefix-portage-2.2.14.orig/pym/portage/dbapi/vartree.py prefix-portage-2.2.14/pym/portage/dbapi/vartree.py
---- prefix-portage-2.2.14.orig/pym/portage/dbapi/vartree.py 2014-11-12 18:28:33.000000000 +0100
-+++ prefix-portage-2.2.14/pym/portage/dbapi/vartree.py 2015-06-17 10:24:28.973830901 +0200
-@@ -184,8 +184,19 @@
- self._counter_path = os.path.join(self._eroot,
- CACHE_PATH, "counter")
-
-- self._plib_registry = PreservedLibsRegistry(settings["ROOT"],
-- os.path.join(self._eroot, PRIVATE_PATH, "preserved_libs_registry"))
-+ plibreg_path = os.path.join(self._eroot, PRIVATE_PATH, "preserved_libs_registry")
-+
-+ if vartree:
-+ self._kill_eprefix = vartree._kill_eprefix
-+ else:
-+ self._kill_eprefix = False
-+
-+ if self._kill_eprefix:
-+ self._aux_cache_filename = self._aux_cache_filename.replace(EPREFIX, "")
-+ self._counter_path = self._counter_path.replace(EPREFIX, "")
-+ plibreg_path = plibreg_path.replace(EPREFIX, "")
-+
-+ self._plib_registry = PreservedLibsRegistry(settings["ROOT"], plibreg_path)
- self._linkmap = LinkageMap(self)
- chost = self.settings.get('CHOST')
- if not chost:
-@@ -215,6 +226,9 @@
- # This is an optimized hotspot, so don't use unicode-wrapped
- # os module and don't use os.path.join().
- rValue = self._eroot + VDB_PATH + _os.sep + mykey
-+ if self._kill_eprefix:
-+ rValue = rValue.replace(EPREFIX, "")
-+
- if filename is not None:
- # If filename is always relative, we can do just
- # rValue += _os.sep + filename
-@@ -440,6 +454,9 @@
- returnme = []
- basepath = os.path.join(self._eroot, VDB_PATH) + os.path.sep
-
-+ if self._kill_eprefix:
-+ basepath = os.path.join(self.root, basepath.replace(EPREFIX, ""))
-+
- if use_cache:
- from portage import listdir
- else:
-@@ -530,11 +547,17 @@
- del self.matchcache[mycat]
- return list(self._iter_match(mydep,
- self.cp_list(mydep.cp, use_cache=use_cache)))
-+
-+ _tmp_path = os.path.join(self._eroot, VDB_PATH, mycat)
-+
-+ if self._kill_eprefix:
-+ _tmp_path = _tmp_path.replace(EPREFIX, "")
-+
- try:
- if sys.hexversion >= 0x3030000:
-- curmtime = os.stat(os.path.join(self._eroot, VDB_PATH, mycat)).st_mtime_ns
-+ curmtime = os.stat(_tmp_path).st_mtime_ns
- else:
-- curmtime = os.stat(os.path.join(self._eroot, VDB_PATH, mycat)).st_mtime
-+ curmtime = os.stat(_tmp_path).st_mtime
- except (IOError, OSError):
- curmtime=0
-
-@@ -1339,7 +1362,7 @@
- class vartree(object):
- "this tree will scan a var/db/pkg database located at root (passed to init)"
- def __init__(self, root=None, virtual=DeprecationWarning, categories=None,
-- settings=None):
-+ settings=None, kill_eprefix=None):
-
- if settings is None:
- settings = portage.settings
-@@ -1357,6 +1380,7 @@
- " constructor is unused",
- DeprecationWarning, stacklevel=2)
-
-+ self._kill_eprefix = kill_eprefix
- self.settings = settings
- self.dbapi = vardbapi(settings=settings, vartree=self)
- self.populated = 1
-Only in prefix-portage-2.2.14/pym/portage/dbapi: vartree.py.orig
-diff -ru prefix-portage-2.2.14.orig/pym/portage/dep/dep_check.py prefix-portage-2.2.14/pym/portage/dep/dep_check.py
---- prefix-portage-2.2.14.orig/pym/portage/dep/dep_check.py 2014-09-28 19:12:31.000000000 +0200
-+++ prefix-portage-2.2.14/pym/portage/dep/dep_check.py 2015-06-17 10:24:28.973830901 +0200
-@@ -247,6 +247,95 @@
- __slots__ = ('atoms', 'slot_map', 'cp_map', 'all_available',
- 'all_installed_slots')
-
-+ro_trees={}
-+ro_vartrees={}
-+ro_selected=[]
-+
-+def dep_match_readonly_roots(settings, atom, dep_type, parent=None):
-+ if len(ro_trees) < len(settings.readonly_prefixes):
-+ # MDUFT: create additional vartrees for every readonly root here.
-+ # the ro_vartrees instances are created below as they are needed to
-+ # avoid reading vartrees of portage instances which aren't required
-+ # while resolving this dependencies.
-+ for type in ("DEPEND","RDEPEND", "PDEPEND"):
-+ ro_trees[type] = []
-+
-+ for ro_root, ro_dep_types in settings.readonly_prefixes.items():
-+ if type in ro_dep_types:
-+ ro_trees[type].append(ro_root)
-+
-+ if len(ro_trees) == 0:
-+ return []
-+
-+ matches = []
-+
-+ for ro_root in ro_trees[dep_type]:
-+ if not ro_vartrees.has_key(ro_root):
-+ # target_root=ro_root ok? or should it be the real target_root?
-+ _tmp_settings = portage.config(config_root=ro_root, target_root=ro_root,
-+ config_incrementals=portage.const.INCREMENTALS)
-+
-+ ro_vartrees[ro_root] = portage.vartree(root=ro_root,
-+ categories=_tmp_settings.categories,
-+ settings=_tmp_settings, kill_eprefix=True)
-+
-+ ro_matches = ro_vartrees[ro_root].dbapi.match(atom)
-+
-+ if ro_matches:
-+ ro_host_mismatch = False
-+ if dep_type is "RDEPEND":
-+ # we need to assure binary compatability, so it needs to be
-+ # the same CHOST! But how? for now i cannot do anything...
-+ if parent and parent.metadata["CHOST"] != ro_vartrees[ro_root].settings.get("CHOST", ""):
-+ # provocate a big fat warning in the list of external packages.
-+ ro_host_mismatch = True
-+ pass
-+
-+ matches.append({ "ro_root": ro_root, "atom": atom, "matches": ro_matches,
-+ "type": dep_type, "parent": parent, "host_mismatch": ro_host_mismatch })
-+
-+ return matches
-+
-+def dep_wordreduce_readonly(reduced, unreduced, settings, dep_type, parent):
-+ for mypos, token in enumerate(unreduced):
-+ # recurse if it's a list.
-+ if isinstance(reduced[mypos], list):
-+ reduced[mypos] = dep_wordreduce_readonly(reduced[mypos],
-+ unreduced[mypos], settings, dep_type, parent)
-+
-+ # do nothing if it's satisfied already.
-+ elif not reduced[mypos]:
-+ ro_matches = dep_match_readonly_roots(settings, unreduced[mypos], dep_type, parent)
-+
-+ if ro_matches:
-+ # TODO: select a match if there are more than one?
-+ # for now, the first match is taken...
-+ ro_selected.append(ro_matches[0])
-+ reduced[mypos] = True
-+
-+ return reduced
-+
-+# this may be better placed somewhere else, but i put it here for now, to
-+# keep all functions in the patch on one big heap.
-+def readonly_pathmatch_any(settings, path):
-+ path = path.lstrip('/')
-+ # first try locally, and match that if it exists.
-+ if os.path.exists(os.path.join(EPREFIX,path)):
-+ return os.path.join(EPREFIX,path)
-+
-+ # after that try all readonly roots where DEPEND is allowed. this makes
-+ # sure that executing binaries is possible from there.
-+ for ro_root, ro_deps in settings.readonly_roots.items():
-+ if "DEPEND" in ro_deps:
-+ print(" --- checking %s --- " % (os.path.join(ro_root,path)))
-+ if os.path.exists(os.path.join(ro_root,path)):
-+ return os.path.join(ro_root,path)
-+ break
-+
-+ # as a fallback make the string the same as it was originally.
-+ # even though this path doesn't exist.
-+ return os.path.join(EPREFIX,path)
-+
- def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None):
- """
- Takes an unreduced and reduced deplist and removes satisfied dependencies.
-@@ -567,7 +656,7 @@
- assert(False) # This point should not be reachable
-
- def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None,
-- use_cache=1, use_binaries=0, myroot=None, trees=None):
-+ use_cache=1, use_binaries=0, myroot=None, trees=None, dep_type=None):
- """
- Takes a depend string, parses it, and selects atoms.
- The myroot parameter is unused (use mysettings['EROOT'] instead).
-@@ -663,6 +752,14 @@
- writemsg("mysplit: %s\n" % (mysplit), 1)
- writemsg("mysplit2: %s\n" % (mysplit2), 1)
-
-+ if dep_type is not None:
-+ mysplit2=dep_wordreduce_readonly(unreduced=mysplit[:],
-+ reduced=mysplit2, settings=mysettings,
-+ dep_type=dep_type, parent=trees[myroot].get("disp_parent"))
-+
-+ writemsg("\n", 1)
-+ writemsg("mysplit2 after readonly reduce: %s\n" % (mysplit2), 1)
-+
- selected_atoms = dep_zapdeps(mysplit, mysplit2, myroot,
- use_binaries=use_binaries, trees=trees)
-
-Only in prefix-portage-2.2.14/pym/portage/dep: dep_check.py.orig
-diff -ru prefix-portage-2.2.14.orig/pym/portage/package/ebuild/_config/LocationsManager.py prefix-portage-2.2.14/pym/portage/package/ebuild/_config/LocationsManager.py
---- prefix-portage-2.2.14.orig/pym/portage/package/ebuild/_config/LocationsManager.py 2014-02-06 21:49:32.000000000 +0100
-+++ prefix-portage-2.2.14/pym/portage/package/ebuild/_config/LocationsManager.py 2015-06-17 10:24:28.983830892 +0200
-@@ -285,6 +285,9 @@
- if portage.const.EPREFIX:
- self.global_config_path = os.path.join(portage.const.EPREFIX,
- GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(self.global_config_path) and portage.const.BPREFIX:
-+ self.global_config_path = os.path.join(portage.const.BPREFIX,
-+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
-
- def set_port_dirs(self, portdir, portdir_overlay):
- self.portdir = portdir
-diff -ru prefix-portage-2.2.14.orig/pym/portage/package/ebuild/config.py prefix-portage-2.2.14/pym/portage/package/ebuild/config.py
---- prefix-portage-2.2.14.orig/pym/portage/package/ebuild/config.py 2014-09-28 19:12:31.000000000 +0200
-+++ prefix-portage-2.2.14/pym/portage/package/ebuild/config.py 2015-06-17 10:24:28.983830892 +0200
-@@ -298,6 +298,7 @@
- self.features = features_set(self)
- self.features._features = copy.deepcopy(clone.features._features)
- self._features_overrides = copy.deepcopy(clone._features_overrides)
-+ self.readonly_prefixes = copy.deepcopy(clone.readonly_prefixes)
-
- #Strictly speaking _license_manager is not immutable. Users need to ensure that
- #extract_global_changes() is called right after __init__ (if at all).
-@@ -894,6 +895,63 @@
-
- self._validate_commands()
-
-+ # expand READONLY_EPREFIX to a list of all readonly portage instances
-+ # all the way down to the last one. beware that ATM a deeper instance
-+ # in the chain can provide more than the toplevel! this means that
-+ # if you only inherit DEPENDS from one instance, that instance may
-+ # inherit RDEPENDs from another one, making the top-level instance
-+ # inherit RDEPENDs from there too - even if the intermediate prefix
-+ # does not do this.
-+ self.readonly_prefixes = {}
-+ ro_cfg_root = config_root
-+ ro_widest_depset = set(['DEPEND', 'RDEPEND', 'PDEPEND'])
-+
-+ while ro_cfg_root:
-+ ro_make_conf_paths = [
-+ os.path.join(ro_cfg_root, 'etc', 'make.conf'),
-+ os.path.join(ro_cfg_root, MAKE_CONF_FILE)
-+ ]
-+ try:
-+ if os.path.samefile(*ro_make_conf_paths):
-+ ro_make_conf_paths.pop()
-+ except OSError:
-+ pass
-+
-+ ro_cfg_root = None
-+ for ro_make_conf in ro_make_conf_paths:
-+ if not os.path.exists(ro_make_conf):
-+ continue
-+
-+ ro_cfg = getconfig(ro_make_conf, tolerant=True, allow_sourcing=True)
-+ if not ro_cfg.has_key("READONLY_EPREFIX"):
-+ continue
-+
-+ if not ro_cfg["READONLY_EPREFIX"].find(":"):
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: malformed READONLY_EPREFIX in %s" % (ro_make_conf))
-+
-+ if ro_cfg_root is not None:
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: duplicate READONLY_EPREFIX in %s and %s" % tuple(ro_make_conf_paths))
-+
-+ (ro_cfg_root,ro_cfg_root_deps) = ro_cfg["READONLY_EPREFIX"].rsplit(":",1)
-+
-+ if not os.path.exists(ro_cfg_root):
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: malformed READONLY_EPREFIX in %s: %s does not exist!" % (ro_make_conf, ro_cfg_root))
-+
-+ if os.path.samefile(ro_cfg_root, config_root):
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: cannot add this instance (%s) as READONLY_EPREFIX in %s." % (ro_cfg_root, ro_make_conf))
-+
-+ if self.readonly_prefixes.has_key(ro_cfg_root):
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: circular READONLY_EPREFIX's in %s. %s already checked for %s" % (ro_make_conf, ro_cfg_root, self.readonly_prefixes[ro_cfg_root]))
-+
-+ # intersect the widest depset with the current one to strip down
-+ # the allowed dependency resolution to not be wider than the
-+ # next higher one. this way we can prevent for a given prefix
-+ # to resolve RDEPENDs from a prefix with a different CHOST that
-+ # is a few levels deeper in the chain.
-+ ro_widest_depset = set(ro_cfg_root_deps.split(",")) & ro_widest_depset
-+ self.readonly_prefixes[ro_cfg_root] = ro_widest_depset
-+ pass
-+
- for k in self._case_insensitive_vars:
- if k in self:
- self[k] = self[k].lower()
-@@ -2671,6 +2729,10 @@
- if not eapi_exports_merge_type(eapi):
- mydict.pop("MERGE_TYPE", None)
-
-+ # populate with PORTAGE_READONLY_EPREFIXES
-+ if self.readonly_prefixes and len(self.readonly_prefixes) > 0:
-+ mydict["PORTAGE_READONLY_EPREFIXES"] = ':'.join(self.readonly_prefixes)
-+
- # Prefix variables are supported beginning with EAPI 3, or when
- # force-prefix is in FEATURES, since older EAPIs would otherwise be
- # useless with prefix configurations. This brings compatibility with
-Only in prefix-portage-2.2.14/pym/portage/package/ebuild: config.py.orig
-diff -ru prefix-portage-2.2.14.orig/pym/portage/package/ebuild/doebuild.py prefix-portage-2.2.14/pym/portage/package/ebuild/doebuild.py
---- prefix-portage-2.2.14.orig/pym/portage/package/ebuild/doebuild.py 2014-09-28 19:25:39.000000000 +0200
-+++ prefix-portage-2.2.14/pym/portage/package/ebuild/doebuild.py 2015-06-17 10:23:25.703886164 +0200
-@@ -46,6 +46,7 @@
- unmerge, _encodings, _os_merge, \
- _shell_quote, _unicode_decode, _unicode_encode
- from portage.const import EBUILD_SH_ENV_FILE, EBUILD_SH_ENV_DIR, \
-+ GLOBAL_CONFIG_PATH, \
- EBUILD_SH_BINARY, INVALID_ENV_FILE, MISC_SH_BINARY, PORTAGE_PYM_PACKAGES, EPREFIX, MACOSSANDBOX_PROFILE
- from portage.data import portage_gid, portage_uid, secpass, \
- uid, userpriv_groups
-@@ -66,7 +67,8 @@
- from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
- from portage.util import apply_recursive_permissions, \
- apply_secpass_permissions, noiselimit, normalize_path, \
-- writemsg, writemsg_stdout, write_atomic
-+ writemsg, writemsg_stdout, write_atomic, getconfig
-+from portage.util._path import exists_raise_eaccess
- from portage.util.lafilefixer import rewrite_lafile
- from portage.versions import _pkgsplit
- from _emerge.BinpkgEnvExtractor import BinpkgEnvExtractor
-@@ -212,8 +214,27 @@
- path.append(os.path.join(portage_bin_path, "ebuild-helpers", "bsd"))
-
- path.append(os.path.join(portage_bin_path, "ebuild-helpers"))
-+
-+ # PREFIX CHAINING: append default path for all prefixes involved
-+ pfxs = [ eprefix ]
-+ pfxs.extend(settings.readonly_prefixes)
-+ for prefix in pfxs:
-+ global_config_path = os.path.join(prefix, GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ make_globals_path = os.path.join(global_config_path, "make.globals")
-+ if exists_raise_eaccess(make_globals_path):
-+ expand_map = { "EPREFIX": prefix }
-+ pxcfg = getconfig(make_globals_path, True, expand_map)
-+ pxdefp = [x for x in pxcfg.get("DEFAULT_PATH", "").split(":") if x]
-+ for x in pxdefp:
-+ if x.startswith(prefix) and not x in path:
-+ path.append(x)
-+ else:
-+ pxdefs = [prefix + "/usr/sbin", prefix + "/usr/bin", prefix + "/sbin", prefix + "/bin"]
-+ path.extend(pxdefs)
-+ # END PREFIX CHAINING
-+
- path.extend(prerootpath)
-- path.extend(defaultpath)
-+ # path.extend(defaultpath) # PREFIX CHAINING appends the default path for involved prefixes above
- path.extend(rootpath)
- path.extend(extrapath)
- # END PREFIX LOCAL
-diff -ru prefix-portage-2.2.14.orig/pym/portage/package/ebuild/fetch.py prefix-portage-2.2.14/pym/portage/package/ebuild/fetch.py
---- prefix-portage-2.2.14.orig/pym/portage/package/ebuild/fetch.py 2014-04-22 21:50:06.000000000 +0200
-+++ prefix-portage-2.2.14/pym/portage/package/ebuild/fetch.py 2015-06-17 10:24:28.983830892 +0200
-@@ -43,6 +43,7 @@
- from portage.util import apply_recursive_permissions, \
- apply_secpass_permissions, ensure_dirs, grabdict, shlex_split, \
- varexpand, writemsg, writemsg_level, writemsg_stdout
-+from portage.util._path import exists_raise_eaccess
- from portage.process import spawn
-
- _userpriv_spawn_kwargs = (
-@@ -869,6 +870,9 @@
- global_config_path = GLOBAL_CONFIG_PATH
- if portage.const.EPREFIX:
- global_config_path = os.path.join(portage.const.EPREFIX,
-+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(global_config_path) and portage.const.BPREFIX:
-+ global_config_path = os.path.join(portage.const.BPREFIX,
- GLOBAL_CONFIG_PATH.lstrip(os.sep))
-
- missing_file_param = False
-diff -ru prefix-portage-2.2.14.orig/pym/portage/_sets/__init__.py prefix-portage-2.2.14/pym/portage/_sets/__init__.py
---- prefix-portage-2.2.14.orig/pym/portage/_sets/__init__.py 2014-01-06 10:44:16.000000000 +0100
-+++ prefix-portage-2.2.14/pym/portage/_sets/__init__.py 2015-06-17 10:24:28.983830892 +0200
-@@ -28,6 +28,7 @@
- from portage.exception import PackageSetNotFound
- from portage.localization import _
- from portage.util import writemsg_level
-+from portage.util._path import exists_raise_eaccess
-
- SETPREFIX = "@"
-
-@@ -299,6 +300,10 @@
- if portage.const.EPREFIX:
- global_config_path = os.path.join(portage.const.EPREFIX,
- GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(global_config_path) and portage.const.BPREFIX:
-+ global_config_path = os.path.join(portage.const.BPREFIX,
-+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+
- def _getfiles():
- for path, dirs, files in os.walk(os.path.join(global_config_path, "sets")):
- for f in files:
-diff -ru prefix-portage-2.2.14.orig/pym/portage/util/_dyn_libs/LinkageMapELF.py prefix-portage-2.2.14/pym/portage/util/_dyn_libs/LinkageMapELF.py
---- prefix-portage-2.2.14.orig/pym/portage/util/_dyn_libs/LinkageMapELF.py 2013-05-04 18:36:19.000000000 +0200
-+++ prefix-portage-2.2.14/pym/portage/util/_dyn_libs/LinkageMapELF.py 2015-06-17 10:24:28.987164223 +0200
-@@ -17,7 +17,7 @@
- from portage.util import grabfile
- from portage.util import normalize_path
- from portage.util import writemsg_level
--from portage.const import EPREFIX
-+from portage.const import BPREFIX
-
- class LinkageMapELF(object):
-
-@@ -235,7 +235,7 @@
- continue
- plibs.update((x, cpv) for x in items)
- if plibs:
-- args = [EPREFIX + "/usr/bin/scanelf", "-qF", "%a;%F;%S;%r;%n"]
-+ args = [BPREFIX + "/usr/bin/scanelf", "-qF", "%a;%F;%S;%r;%n"]
- args.extend(os.path.join(root, x.lstrip("." + os.sep)) \
- for x in plibs)
- try:
diff --git a/sys-apps/portage/files/portage-2.3.18-prefix-chaining.patch b/sys-apps/portage/files/portage-2.3.18-prefix-chaining.patch
deleted file mode 100644
index 728b3261ba..0000000000
--- a/sys-apps/portage/files/portage-2.3.18-prefix-chaining.patch
+++ /dev/null
@@ -1,927 +0,0 @@
-From 2ce322b10b0f1971b174067ca9dac373322e4035 Mon Sep 17 00:00:00 2001
-From: Michael Haubenwallner <haubi@gentoo.org>
-Date: Thu, 23 Mar 2017 13:52:32 +0100
-Subject: [PATCH] add prefix-chaining support
-
----
- bin/install-qa-check.d/05prefix | 30 ++++++-
- bin/phase-helpers.sh | 28 ++++++
- pym/_emerge/actions.py | 6 +-
- pym/_emerge/depgraph.py | 51 ++++++-----
- pym/_emerge/resolver/output.py | 40 ++++++++-
- pym/portage/_sets/__init__.py | 5 ++
- pym/portage/const.py | 6 ++
- pym/portage/dbapi/vartree.py | 34 ++++++--
- pym/portage/dep/dep_check.py | 99 +++++++++++++++++++++-
- .../package/ebuild/_config/LocationsManager.py | 3 +
- pym/portage/package/ebuild/config.py | 62 ++++++++++++++
- pym/portage/package/ebuild/doebuild.py | 24 +++++-
- pym/portage/package/ebuild/fetch.py | 4 +
- pym/portage/sync/controller.py | 27 +++---
- pym/portage/util/_dyn_libs/LinkageMapELF.py | 4 +-
- 15 files changed, 376 insertions(+), 47 deletions(-)
-
-diff --git a/bin/install-qa-check.d/05prefix b/bin/install-qa-check.d/05prefix
-index 32561e263..0c1147367 100644
---- a/bin/install-qa-check.d/05prefix
-+++ b/bin/install-qa-check.d/05prefix
-@@ -79,16 +79,42 @@ install_qa_check_prefix() {
- # unprefixed shebang, is the script directly in $PATH or an init
- # script?
- if [[ ":${PATH}:${EPREFIX}/etc/init.d:" == *":${fp}:"* ]] ; then
-- if [[ -e ${EROOT}${line[0]} || -e ${ED}${line[0]} ]] ; then
-+ all_epfs="$PORTAGE_READONLY_EPREFIXES:$EPREFIX:$EROOT:$ED"
-+ save_IFS=$IFS
-+ IFS=:
-+ epfs=( $all_epfs )
-+ IFS=$save_IFS
-+
-+ found=
-+ for x in "${epfs[@]}"; do
-+ [[ -z "${x}" ]] && continue
-+ check="${x}${line[0]}"
-+
-+ # might already contain a prefix
-+ if [[ "${line[0]}" == "${x}"* ]]; then
-+ check="${line[0]}"
-+ fi
-+
-+ if [[ -e ${check} ]]; then
-+ found="${check}"
-+ fi
-+ done
-+
-+ if [[ -n ${found} ]] ; then
- # is it unprefixed, but we can just fix it because a
- # prefixed variant exists
- eqawarn "prefixing shebang of ${fn#${D}}"
-+
-+ if [[ ${found} == "${ED}"* || ${found} == "${EROOT}"* ]]; then
-+ found="${EPREFIX}${line[0]}"
-+ fi
-+
- # statement is made idempotent on purpose, because
- # symlinks may point to the same target, and hence the
- # same real file may be sedded multiple times since we
- # read the shebangs in one go upfront for performance
- # reasons
-- sed -i -e '1s:^#! \?'"${line[0]}"':#!'"${EPREFIX}"${line[0]}':' "${rf}"
-+ sed -i -e '1s:^#! \?'"${line[0]}"':#!'"${found}"':' "${rf}"
- continue
- else
- # this is definitely wrong: script in $PATH and invalid shebang
-diff --git a/bin/phase-helpers.sh b/bin/phase-helpers.sh
-index 2cac6f426..b7b5c8ce6 100644
---- a/bin/phase-helpers.sh
-+++ b/bin/phase-helpers.sh
-@@ -868,6 +868,10 @@ has_version() {
- "${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" has_version "${eroot}" "${atom}"
- fi
- local retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ ${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' has_version '${READONLY_EPREFIX%:*}' '${atom}'"
-+ retval=$?
-+ fi
- case "${retval}" in
- 0|1)
- return ${retval}
-@@ -927,6 +931,10 @@ best_version() {
- "${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" best_version "${eroot}" "${atom}"
- fi
- local retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ ${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' best_version '${READONLY_EPREFIX%:*}' '${atom}'"
-+ retval=$?
-+ fi
- case "${retval}" in
- 0|1)
- return ${retval}
-@@ -1167,6 +1175,10 @@ if ___eapi_has_master_repositories; then
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" master_repositories "${EROOT}" "${repository}")
- fi
- retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' master_repositories '${READONLY_EPREFIX%:*}' '${repository}'")
-+ retval=$?
-+ fi
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
- 0|1)
-@@ -1198,6 +1210,10 @@ if ___eapi_has_repository_path; then
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" get_repo_path "${EROOT}" "${repository}")
- fi
- retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' repository_path '${READONLY_EPREFIX%:*}' '${repository}'")
-+ retval=$?
-+ fi
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
- 0|1)
-@@ -1228,6 +1244,10 @@ if ___eapi_has_available_eclasses; then
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" available_eclasses "${EROOT}" "${repository}")
- fi
- retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' available_eclasses '${READONLY_EPREFIX%:*}' '${repository}'")
-+ retval=$?
-+ fi
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
- 0|1)
-@@ -1258,6 +1278,10 @@ if ___eapi_has_eclass_path; then
- else
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" eclass_path "${EROOT}" "${repository}" "${eclass}")
- fi
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' eclass_path '${READONLY_EPREFIX%:*}' '${repository}' '${eclass}'")
-+ retval=$?
-+ fi
- retval=$?
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
-@@ -1289,6 +1313,10 @@ if ___eapi_has_license_path; then
- else
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" license_path "${EROOT}" "${repository}" "${license}")
- fi
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' license_path '${READONLY_EPREFIX%:*}' '${repository}' '${license}'")
-+ retval=$?
-+ fi
- retval=$?
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
-diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py
-index 1d37d0ece..2b185ef73 100644
---- a/pym/_emerge/actions.py
-+++ b/pym/_emerge/actions.py
-@@ -39,7 +39,7 @@ from portage import os
- from portage import shutil
- from portage import eapi_is_supported, _encodings, _unicode_decode
- from portage.cache.cache_errors import CacheError
--from portage.const import EPREFIX
-+from portage.const import EPREFIX, BPREFIX
- from portage.const import GLOBAL_CONFIG_PATH, VCS_DIRS, _DEPCLEAN_LIB_CHECK_DEFAULT
- from portage.const import SUPPORTED_BINPKG_FORMATS, TIMESTAMP_FORMAT
- from portage.dbapi.dep_expand import dep_expand
-@@ -65,6 +65,7 @@ from portage.util.SlotObject import SlotObject
- from portage.util._async.run_main_scheduler import run_main_scheduler
- from portage.util._async.SchedulerInterface import SchedulerInterface
- from portage.util._eventloop.global_event_loop import global_event_loop
-+from portage.util._path import exists_raise_eaccess
- from portage._global_updates import _global_updates
- from portage.sync.old_tree_timestamp import old_tree_timestamp_warn
- from portage.localization import _
-@@ -2659,6 +2660,9 @@ def missing_sets_warning(root_config, missing_sets):
- if portage.const.EPREFIX:
- global_config_path = os.path.join(portage.const.EPREFIX,
- portage.const.GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(global_config_path) and portage.const.BPREFIX:
-+ global_config_path = os.path.join(portage.const.BPREFIX,
-+ portage.const.GLOBAL_CONFIG_PATH.lstrip(os.sep))
- msg.append(" This usually means that '%s'" % \
- (os.path.join(global_config_path, "sets/portage.conf"),))
- msg.append(" is missing or corrupt.")
-diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
-index 8d00f93df..fe317f119 100644
---- a/pym/_emerge/depgraph.py
-+++ b/pym/_emerge/depgraph.py
-@@ -3239,15 +3239,15 @@ class depgraph(object):
- # _dep_disjunctive_stack first, so that choices for build-time
- # deps influence choices for run-time deps (bug 639346).
- deps = (
-- (myroot, edepend["RDEPEND"],
-+ (myroot, "RDEPEND",
- self._priority(runtime=True)),
-- (myroot, edepend["PDEPEND"],
-+ (myroot, "PDEPEND",
- self._priority(runtime_post=True)),
-- (depend_root, edepend["DEPEND"],
-+ (depend_root, "DEPEND",
- self._priority(buildtime=True,
- optional=(pkg.built or ignore_depend_deps),
- ignored=ignore_depend_deps)),
-- (self._frozen_config._running_root.root, edepend["HDEPEND"],
-+ (self._frozen_config._running_root.root, "HDEPEND",
- self._priority(buildtime=True,
- optional=(pkg.built or ignore_hdepend_deps),
- ignored=ignore_hdepend_deps)),
-@@ -3255,7 +3255,8 @@ class depgraph(object):
-
- debug = "--debug" in self._frozen_config.myopts
-
-- for dep_root, dep_string, dep_priority in deps:
-+ for dep_root, dep_type, dep_priority in deps:
-+ dep_string = edepend[dep_type]
- if not dep_string:
- continue
- if debug:
-@@ -3293,7 +3294,7 @@ class depgraph(object):
-
- try:
- dep_string = list(self._queue_disjunctive_deps(
-- pkg, dep_root, dep_priority, dep_string))
-+ pkg, dep_root, dep_priority, dep_string, dep_type))
- except portage.exception.InvalidDependString as e:
- if pkg.installed:
- self._dynamic_config._masked_installed.add(pkg)
-@@ -3308,14 +3309,14 @@ class depgraph(object):
-
- if not self._add_pkg_dep_string(
- pkg, dep_root, dep_priority, dep_string,
-- allow_unsatisfied):
-+ allow_unsatisfied, dep_type):
- return 0
-
- self._dynamic_config._traversed_pkg_deps.add(pkg)
- return 1
-
- def _add_pkg_dep_string(self, pkg, dep_root, dep_priority, dep_string,
-- allow_unsatisfied):
-+ allow_unsatisfied, dep_type=None):
- _autounmask_backup = self._dynamic_config._autounmask
- if dep_priority.optional or dep_priority.ignored:
- # Temporarily disable autounmask for deps that
-@@ -3324,7 +3325,7 @@ class depgraph(object):
- try:
- return self._wrapped_add_pkg_dep_string(
- pkg, dep_root, dep_priority, dep_string,
-- allow_unsatisfied)
-+ allow_unsatisfied, dep_type)
- finally:
- self._dynamic_config._autounmask = _autounmask_backup
-
-@@ -3360,7 +3361,7 @@ class depgraph(object):
- not slot_operator_rebuild
-
- def _wrapped_add_pkg_dep_string(self, pkg, dep_root, dep_priority,
-- dep_string, allow_unsatisfied):
-+ dep_string, allow_unsatisfied, dep_type=None):
- if isinstance(pkg.depth, int):
- depth = pkg.depth + 1
- else:
-@@ -3384,7 +3385,7 @@ class depgraph(object):
- try:
- selected_atoms = self._select_atoms(dep_root,
- dep_string, myuse=self._pkg_use_enabled(pkg), parent=pkg,
-- strict=strict, priority=dep_priority)
-+ strict=strict, priority=dep_priority, dep_type=dep_type)
- except portage.exception.InvalidDependString:
- if pkg.installed:
- self._dynamic_config._masked_installed.add(pkg)
-@@ -3691,7 +3692,7 @@ class depgraph(object):
- child_pkgs.sort()
- yield (atom, child_pkgs[-1])
-
-- def _queue_disjunctive_deps(self, pkg, dep_root, dep_priority, dep_struct):
-+ def _queue_disjunctive_deps(self, pkg, dep_root, dep_priority, dep_struct, dep_type=None):
- """
- Queue disjunctive (virtual and ||) deps in self._dynamic_config._dep_disjunctive_stack.
- Yields non-disjunctive deps. Raises InvalidDependString when
-@@ -3700,33 +3701,33 @@ class depgraph(object):
- for x in dep_struct:
- if isinstance(x, list):
- if x and x[0] == "||":
-- self._queue_disjunction(pkg, dep_root, dep_priority, [x])
-+ self._queue_disjunction(pkg, dep_root, dep_priority, [x], dep_type)
- else:
- for y in self._queue_disjunctive_deps(
-- pkg, dep_root, dep_priority, x):
-+ pkg, dep_root, dep_priority, x, dep_type):
- yield y
- else:
- # Note: Eventually this will check for PROPERTIES=virtual
- # or whatever other metadata gets implemented for this
- # purpose.
- if x.cp.startswith('virtual/'):
-- self._queue_disjunction(pkg, dep_root, dep_priority, [x])
-+ self._queue_disjunction(pkg, dep_root, dep_priority, [x], dep_type)
- else:
- yield x
-
-- def _queue_disjunction(self, pkg, dep_root, dep_priority, dep_struct):
-+ def _queue_disjunction(self, pkg, dep_root, dep_priority, dep_struct, dep_type=None):
- self._dynamic_config._dep_disjunctive_stack.append(
-- (pkg, dep_root, dep_priority, dep_struct))
-+ (pkg, dep_root, dep_priority, dep_struct, dep_type))
-
- def _pop_disjunction(self, allow_unsatisfied):
- """
- Pop one disjunctive dep from self._dynamic_config._dep_disjunctive_stack, and use it to
- populate self._dynamic_config._dep_stack.
- """
-- pkg, dep_root, dep_priority, dep_struct = \
-+ pkg, dep_root, dep_priority, dep_struct, dep_type = \
- self._dynamic_config._dep_disjunctive_stack.pop()
- if not self._add_pkg_dep_string(
-- pkg, dep_root, dep_priority, dep_struct, allow_unsatisfied):
-+ pkg, dep_root, dep_priority, dep_struct, allow_unsatisfied, dep_type):
- return 0
- return 1
-
-@@ -4579,7 +4580,7 @@ class depgraph(object):
- return self._select_atoms_highest_available(*pargs, **kwargs)
-
- def _select_atoms_highest_available(self, root, depstring,
-- myuse=None, parent=None, strict=True, trees=None, priority=None):
-+ myuse=None, parent=None, strict=True, trees=None, priority=None, dep_type=None):
- """This will raise InvalidDependString if necessary. If trees is
- None then self._dynamic_config._filtered_trees is used."""
-
-@@ -4602,6 +4603,13 @@ class depgraph(object):
- pkgsettings = self._frozen_config.pkgsettings[root]
- if trees is None:
- trees = self._dynamic_config._filtered_trees
-+
-+ # this one is needed to guarantee good readonly root
-+ # resolution display in the merge list. required since
-+ # parent (below) can be None
-+ trees[root]["disp_parent"] = parent
-+
-+
- mytrees = trees[root]
- atom_graph = digraph()
- if True:
-@@ -4633,7 +4641,7 @@ class depgraph(object):
-
- mycheck = portage.dep_check(depstring, None,
- pkgsettings, myuse=myuse,
-- myroot=root, trees=trees)
-+ myroot=root, trees=trees, dep_type=dep_type)
- finally:
- # restore state
- self._dynamic_config._autounmask = _autounmask_backup
-@@ -4709,6 +4717,7 @@ class depgraph(object):
- continue
- node_stack.append((child_node, node, child_atom))
-
-+ trees[root].pop("disp_parent")
- return selected_atoms
-
- def _expand_virt_from_graph(self, root, atom):
-diff --git a/pym/_emerge/resolver/output.py b/pym/_emerge/resolver/output.py
-index e993ce17d..32a942c73 100644
---- a/pym/_emerge/resolver/output.py
-+++ b/pym/_emerge/resolver/output.py
-@@ -22,11 +22,12 @@ from portage.localization import localized_size
- from portage.package.ebuild.config import _get_feature_flags
- from portage.package.ebuild._spawn_nofetch import spawn_nofetch
- from portage.output import ( blue, colorize, create_color_func,
-- darkblue, darkgreen, green, nc_len, teal)
-+ darkblue, darkgreen, green, nc_len, teal, yellow, turquoise)
- bad = create_color_func("BAD")
- from portage._sets.base import InternalPackageSet
- from portage.util import writemsg_stdout
- from portage.versions import best, cpv_getversion
-+from portage.dep.dep_check import ro_selected
-
- from _emerge.Blocker import Blocker
- from _emerge.create_world_atom import create_world_atom
-@@ -563,6 +564,42 @@ class Display(object):
- writemsg_stdout("%s\n" % (pkg,), noiselevel=-1)
- return
-
-+ def print_readonly_prefix(self):
-+ """Performs the actual output printing for the readonly prefix
-+ information stuff
-+ """
-+ out = sys.stdout
-+
-+ # print readonly selected packages
-+ if len(ro_selected) > 0:
-+ out.write("\n%s\n\n" % (darkgreen("Packages resolved from readonly installations:")))
-+
-+ ro_mismatch_warning = False
-+ ro_dupcheck = []
-+ for x in ro_selected:
-+ tmp_type = x["type"].replace("END","")
-+ while len(tmp_type) < 4:
-+ tmp_type += " "
-+ if x["parent"] and str(x["atom"]) not in ro_dupcheck:
-+ out.write("[%s %s] %s %s %s (%s by %s)" % (teal("readonly"),
-+ green(tmp_type), green(str(x["matches"][0])), yellow("from"),
-+ blue(x["ro_root"]), turquoise(str(x["atom"])), green(x["parent"].cpv)))
-+
-+ ro_dupcheck.append(str(x["atom"]))
-+
-+ if x["host_mismatch"]:
-+ ro_mismatch_warning = True
-+ out.write(" %s\n" % (red("**")))
-+ else:
-+ out.write("\n")
-+
-+ if ro_mismatch_warning:
-+ out.write("\n%s:" % (red("**")))
-+ out.write(yellow(" WARNING: packages marked with ** have been resolved as a\n"))
-+ out.write(yellow(" runtime dependency, but the CHOST variable for the parent\n"))
-+ out.write(yellow(" and dependency package don't match. This could cause link\n"))
-+ out.write(yellow(" errors. It is recommended to use RDEPEND READONLY_EPREFIX's\n"))
-+ out.write(yellow(" only with matching CHOST portage instances.\n"))
-
- def print_verbose(self, show_repos):
- """Prints the verbose output to std_out
-@@ -913,6 +950,7 @@ class Display(object):
- show_repos = self.quiet_repo_display and repoadd_set and repoadd_set != set(["0"])
-
- # now finally print out the messages
-+ self.print_readonly_prefix()
- self.print_messages(show_repos)
- self.print_blockers()
- if self.conf.verbosity == 3:
-diff --git a/pym/portage/_sets/__init__.py b/pym/portage/_sets/__init__.py
-index 2c9bf9715..6a2784207 100644
---- a/pym/portage/_sets/__init__.py
-+++ b/pym/portage/_sets/__init__.py
-@@ -21,6 +21,7 @@ from portage.const import _ENABLE_SET_CONFIG
- from portage.exception import PackageSetNotFound
- from portage.localization import _
- from portage.util import writemsg_level
-+from portage.util._path import exists_raise_eaccess
- from portage.util.configparser import (SafeConfigParser,
- NoOptionError, ParsingError, read_configs)
-
-@@ -281,6 +282,10 @@ def load_default_config(settings, trees):
- if portage.const.EPREFIX:
- global_config_path = os.path.join(portage.const.EPREFIX,
- GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(global_config_path) and portage.const.BPREFIX:
-+ global_config_path = os.path.join(portage.const.BPREFIX,
-+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+
- vcs_dirs = [_unicode_encode(x, encoding=_encodings['fs']) for x in VCS_DIRS]
- def _getfiles():
- for path, dirs, files in os.walk(os.path.join(global_config_path, "sets")):
-diff --git a/pym/portage/const.py b/pym/portage/const.py
-index dd4657835..6be443082 100644
---- a/pym/portage/const.py
-+++ b/pym/portage/const.py
-@@ -189,6 +189,7 @@ SUPPORTED_FEATURES = frozenset([
- "notitles",
- "parallel-fetch",
- "parallel-install",
-+ "prefix-chaining",
- "prelink-checksums",
- "preserve-libs",
- "protect-owned",
-@@ -239,6 +240,11 @@ MANIFEST2_IDENTIFIERS = ("AUX", "MISC", "DIST", "EBUILD")
- #EPREFIX = ""
- # END PREFIX LOCAL
-
-+BPREFIX = EPREFIX
-+
-+# --prefix commandline arg always rules, ends up in os.environ["EPREFIX"]
-+if "EPREFIX" in os.environ:
-+ os.environ["PORTAGE_OVERRIDE_EPREFIX"] = os.environ["EPREFIX"]
- # pick up EPREFIX from the environment if set
- if "PORTAGE_OVERRIDE_EPREFIX" in os.environ:
- EPREFIX = os.environ["PORTAGE_OVERRIDE_EPREFIX"]
-diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
-index d2c35f9e3..79d612b2d 100644
---- a/pym/portage/dbapi/vartree.py
-+++ b/pym/portage/dbapi/vartree.py
-@@ -195,8 +195,19 @@ class vardbapi(dbapi):
- self._counter_path = os.path.join(self._eroot,
- CACHE_PATH, "counter")
-
-- self._plib_registry = PreservedLibsRegistry(settings["ROOT"],
-- os.path.join(self._eroot, PRIVATE_PATH, "preserved_libs_registry"))
-+ plibreg_path = os.path.join(self._eroot, PRIVATE_PATH, "preserved_libs_registry")
-+
-+ if vartree:
-+ self._kill_eprefix = vartree._kill_eprefix
-+ else:
-+ self._kill_eprefix = False
-+
-+ if self._kill_eprefix:
-+ self._aux_cache_filename = self._aux_cache_filename.replace(EPREFIX, "")
-+ self._counter_path = self._counter_path.replace(EPREFIX, "")
-+ plibreg_path = plibreg_path.replace(EPREFIX, "")
-+
-+ self._plib_registry = PreservedLibsRegistry(settings["ROOT"], plibreg_path)
- self._linkmap = LinkageMap(self)
- chost = self.settings.get('CHOST')
- if not chost:
-@@ -237,6 +248,9 @@ class vardbapi(dbapi):
- # This is an optimized hotspot, so don't use unicode-wrapped
- # os module and don't use os.path.join().
- rValue = self._eroot + VDB_PATH + _os.sep + mykey
-+ if self._kill_eprefix:
-+ rValue = rValue.replace(EPREFIX, "")
-+
- if filename is not None:
- # If filename is always relative, we can do just
- # rValue += _os.sep + filename
-@@ -500,6 +514,9 @@ class vardbapi(dbapi):
- returnme = []
- basepath = os.path.join(self._eroot, VDB_PATH) + os.path.sep
-
-+ if self._kill_eprefix:
-+ basepath = os.path.join(self.root, basepath.replace(EPREFIX, ""))
-+
- if use_cache:
- from portage import listdir
- else:
-@@ -596,11 +613,17 @@ class vardbapi(dbapi):
- del self.matchcache[mycat]
- return list(self._iter_match(mydep,
- self.cp_list(mydep.cp, use_cache=use_cache)))
-+
-+ _tmp_path = os.path.join(self._eroot, VDB_PATH, mycat)
-+
-+ if self._kill_eprefix:
-+ _tmp_path = _tmp_path.replace(EPREFIX, "")
-+
- try:
- if sys.hexversion >= 0x3030000:
-- curmtime = os.stat(os.path.join(self._eroot, VDB_PATH, mycat)).st_mtime_ns
-+ curmtime = os.stat(_tmp_path).st_mtime_ns
- else:
-- curmtime = os.stat(os.path.join(self._eroot, VDB_PATH, mycat)).st_mtime
-+ curmtime = os.stat(_tmp_path).st_mtime
- except (IOError, OSError):
- curmtime=0
-
-@@ -1448,7 +1471,7 @@ class vardbapi(dbapi):
- class vartree(object):
- "this tree will scan a var/db/pkg database located at root (passed to init)"
- def __init__(self, root=None, virtual=DeprecationWarning, categories=None,
-- settings=None):
-+ settings=None, kill_eprefix=None):
-
- if settings is None:
- settings = portage.settings
-@@ -1466,6 +1489,7 @@ class vartree(object):
- " constructor is unused",
- DeprecationWarning, stacklevel=2)
-
-+ self._kill_eprefix = kill_eprefix
- self.settings = settings
- self.dbapi = vardbapi(settings=settings, vartree=self)
- self.populated = 1
-diff --git a/pym/portage/dep/dep_check.py b/pym/portage/dep/dep_check.py
-index 2bb9dc339..cc017a2a7 100644
---- a/pym/portage/dep/dep_check.py
-+++ b/pym/portage/dep/dep_check.py
-@@ -298,6 +298,95 @@ class _dep_choice(SlotObject):
- __slots__ = ('atoms', 'slot_map', 'cp_map', 'all_available',
- 'all_installed_slots')
-
-+ro_trees={}
-+ro_vartrees={}
-+ro_selected=[]
-+
-+def dep_match_readonly_roots(settings, atom, dep_type, parent=None):
-+ if len(ro_trees) < len(settings.readonly_prefixes):
-+ # MDUFT: create additional vartrees for every readonly root here.
-+ # the ro_vartrees instances are created below as they are needed to
-+ # avoid reading vartrees of portage instances which aren't required
-+ # while resolving this dependencies.
-+ for type in ("DEPEND","RDEPEND", "PDEPEND"):
-+ ro_trees[type] = []
-+
-+ for ro_root, ro_dep_types in settings.readonly_prefixes.items():
-+ if type in ro_dep_types:
-+ ro_trees[type].append(ro_root)
-+
-+ if len(ro_trees) == 0:
-+ return []
-+
-+ matches = []
-+
-+ for ro_root in ro_trees[dep_type]:
-+ if not ro_root in ro_vartrees:
-+ # target_root=ro_root ok? or should it be the real target_root?
-+ _tmp_settings = portage.config(config_root=ro_root, target_root=ro_root,
-+ config_incrementals=portage.const.INCREMENTALS)
-+
-+ ro_vartrees[ro_root] = portage.vartree(root=ro_root,
-+ categories=_tmp_settings.categories,
-+ settings=_tmp_settings, kill_eprefix=True)
-+
-+ ro_matches = ro_vartrees[ro_root].dbapi.match(atom)
-+
-+ if ro_matches:
-+ ro_host_mismatch = False
-+ if dep_type is "RDEPEND":
-+ # we need to assure binary compatability, so it needs to be
-+ # the same CHOST! But how? for now i cannot do anything...
-+ if parent and parent.metadata["CHOST"] != ro_vartrees[ro_root].settings.get("CHOST", ""):
-+ # provocate a big fat warning in the list of external packages.
-+ ro_host_mismatch = True
-+ pass
-+
-+ matches.append({ "ro_root": ro_root, "atom": atom, "matches": ro_matches,
-+ "type": dep_type, "parent": parent, "host_mismatch": ro_host_mismatch })
-+
-+ return matches
-+
-+def dep_wordreduce_readonly(reduced, unreduced, settings, dep_type, parent):
-+ for mypos, token in enumerate(unreduced):
-+ # recurse if it's a list.
-+ if isinstance(reduced[mypos], list):
-+ reduced[mypos] = dep_wordreduce_readonly(reduced[mypos],
-+ unreduced[mypos], settings, dep_type, parent)
-+
-+ # do nothing if it's satisfied already.
-+ elif not reduced[mypos]:
-+ ro_matches = dep_match_readonly_roots(settings, unreduced[mypos], dep_type, parent)
-+
-+ if ro_matches:
-+ # TODO: select a match if there are more than one?
-+ # for now, the first match is taken...
-+ ro_selected.append(ro_matches[0])
-+ reduced[mypos] = True
-+
-+ return reduced
-+
-+# this may be better placed somewhere else, but i put it here for now, to
-+# keep all functions in the patch on one big heap.
-+def readonly_pathmatch_any(settings, path):
-+ path = path.lstrip('/')
-+ # first try locally, and match that if it exists.
-+ if os.path.exists(os.path.join(EPREFIX,path)):
-+ return os.path.join(EPREFIX,path)
-+
-+ # after that try all readonly roots where DEPEND is allowed. this makes
-+ # sure that executing binaries is possible from there.
-+ for ro_root, ro_deps in settings.readonly_roots.items():
-+ if "DEPEND" in ro_deps:
-+ print(" --- checking %s --- " % (os.path.join(ro_root,path)))
-+ if os.path.exists(os.path.join(ro_root,path)):
-+ return os.path.join(ro_root,path)
-+ break
-+
-+ # as a fallback make the string the same as it was originally.
-+ # even though this path doesn't exist.
-+ return os.path.join(EPREFIX,path)
-+
- def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None):
- """
- Takes an unreduced and reduced deplist and removes satisfied dependencies.
-@@ -695,7 +784,7 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None):
- assert(False) # This point should not be reachable
-
- def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None,
-- use_cache=1, use_binaries=0, myroot=None, trees=None):
-+ use_cache=1, use_binaries=0, myroot=None, trees=None, dep_type=None):
- """
- Takes a depend string, parses it, and selects atoms.
- The myroot parameter is unused (use mysettings['EROOT'] instead).
-@@ -796,6 +885,14 @@ def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None,
- writemsg("mysplit: %s\n" % (mysplit), 1)
- writemsg("mysplit2: %s\n" % (mysplit2), 1)
-
-+ if dep_type is not None:
-+ mysplit2=dep_wordreduce_readonly(unreduced=mysplit[:],
-+ reduced=mysplit2, settings=mysettings,
-+ dep_type=dep_type, parent=trees[myroot].get("disp_parent"))
-+
-+ writemsg("\n", 1)
-+ writemsg("mysplit2 after readonly reduce: %s\n" % (mysplit2), 1)
-+
- selected_atoms = dep_zapdeps(mysplit, mysplit2, myroot,
- use_binaries=use_binaries, trees=trees)
-
-diff --git a/pym/portage/package/ebuild/_config/LocationsManager.py b/pym/portage/package/ebuild/_config/LocationsManager.py
-index 55b8c089a..32e969ed7 100644
---- a/pym/portage/package/ebuild/_config/LocationsManager.py
-+++ b/pym/portage/package/ebuild/_config/LocationsManager.py
-@@ -307,6 +307,9 @@ class LocationsManager(object):
- if portage.const.EPREFIX:
- self.global_config_path = os.path.join(portage.const.EPREFIX,
- GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(self.global_config_path) and portage.const.BPREFIX:
-+ self.global_config_path = os.path.join(portage.const.BPREFIX,
-+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
-
- def set_port_dirs(self, portdir, portdir_overlay):
- self.portdir = portdir
-diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py
-index d013b0d5c..fdb1552e9 100644
---- a/pym/portage/package/ebuild/config.py
-+++ b/pym/portage/package/ebuild/config.py
-@@ -306,6 +306,7 @@ class config(object):
- self.features = features_set(self)
- self.features._features = copy.deepcopy(clone.features._features)
- self._features_overrides = copy.deepcopy(clone._features_overrides)
-+ self.readonly_prefixes = copy.deepcopy(clone.readonly_prefixes)
-
- #Strictly speaking _license_manager is not immutable. Users need to ensure that
- #extract_global_changes() is called right after __init__ (if at all).
-@@ -945,6 +946,63 @@ class config(object):
-
- self._validate_commands()
-
-+ # expand READONLY_EPREFIX to a list of all readonly portage instances
-+ # all the way down to the last one. beware that ATM a deeper instance
-+ # in the chain can provide more than the toplevel! this means that
-+ # if you only inherit DEPENDS from one instance, that instance may
-+ # inherit RDEPENDs from another one, making the top-level instance
-+ # inherit RDEPENDs from there too - even if the intermediate prefix
-+ # does not do this.
-+ self.readonly_prefixes = {}
-+ ro_cfg_root = config_root
-+ ro_widest_depset = set(['DEPEND', 'RDEPEND', 'PDEPEND'])
-+
-+ while ro_cfg_root:
-+ ro_make_conf_paths = [
-+ os.path.join(ro_cfg_root, 'etc', 'make.conf'),
-+ os.path.join(ro_cfg_root, MAKE_CONF_FILE)
-+ ]
-+ try:
-+ if os.path.samefile(*ro_make_conf_paths):
-+ ro_make_conf_paths.pop()
-+ except OSError:
-+ pass
-+
-+ ro_cfg_root = None
-+ for ro_make_conf in ro_make_conf_paths:
-+ if not os.path.exists(ro_make_conf):
-+ continue
-+
-+ ro_cfg = getconfig(ro_make_conf, tolerant=True, allow_sourcing=True)
-+ if not "READONLY_EPREFIX" in ro_cfg:
-+ continue
-+
-+ if not ro_cfg["READONLY_EPREFIX"].find(":"):
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: malformed READONLY_EPREFIX in %s" % (ro_make_conf))
-+
-+ if ro_cfg_root is not None:
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: duplicate READONLY_EPREFIX in %s and %s" % tuple(ro_make_conf_paths))
-+
-+ (ro_cfg_root,ro_cfg_root_deps) = ro_cfg["READONLY_EPREFIX"].rsplit(":",1)
-+
-+ if not os.path.exists(ro_cfg_root):
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: malformed READONLY_EPREFIX in %s: %s does not exist!" % (ro_make_conf, ro_cfg_root))
-+
-+ if os.path.samefile(ro_cfg_root, config_root):
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: cannot add this instance (%s) as READONLY_EPREFIX in %s." % (ro_cfg_root, ro_make_conf))
-+
-+ if ro_cfg_root in self.readonly_prefixes:
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: circular READONLY_EPREFIX's in %s. %s already checked for %s" % (ro_make_conf, ro_cfg_root, self.readonly_prefixes[ro_cfg_root]))
-+
-+ # intersect the widest depset with the current one to strip down
-+ # the allowed dependency resolution to not be wider than the
-+ # next higher one. this way we can prevent for a given prefix
-+ # to resolve RDEPENDs from a prefix with a different CHOST that
-+ # is a few levels deeper in the chain.
-+ ro_widest_depset = set(ro_cfg_root_deps.split(",")) & ro_widest_depset
-+ self.readonly_prefixes[ro_cfg_root] = ro_widest_depset
-+ pass
-+
- for k in self._case_insensitive_vars:
- if k in self:
- self[k] = self[k].lower()
-@@ -2813,6 +2871,10 @@ class config(object):
- if not eapi_exports_merge_type(eapi):
- mydict.pop("MERGE_TYPE", None)
-
-+ # populate with PORTAGE_READONLY_EPREFIXES
-+ if self.readonly_prefixes and len(self.readonly_prefixes) > 0:
-+ mydict["PORTAGE_READONLY_EPREFIXES"] = ':'.join(self.readonly_prefixes)
-+
- # Prefix variables are supported beginning with EAPI 3, or when
- # force-prefix is in FEATURES, since older EAPIs would otherwise be
- # useless with prefix configurations. This brings compatibility with
-diff --git a/pym/portage/package/ebuild/doebuild.py b/pym/portage/package/ebuild/doebuild.py
-index a24f8fec8..82fcba9e2 100644
---- a/pym/portage/package/ebuild/doebuild.py
-+++ b/pym/portage/package/ebuild/doebuild.py
-@@ -51,6 +51,7 @@ from portage import bsd_chflags, \
- unmerge, _encodings, _os_merge, \
- _shell_quote, _unicode_decode, _unicode_encode
- from portage.const import EBUILD_SH_ENV_FILE, EBUILD_SH_ENV_DIR, \
-+ GLOBAL_CONFIG_PATH, \
- EBUILD_SH_BINARY, INVALID_ENV_FILE, MISC_SH_BINARY, PORTAGE_PYM_PACKAGES, EPREFIX, MACOSSANDBOX_PROFILE
- from portage.data import portage_gid, portage_uid, secpass, \
- uid, userpriv_groups
-@@ -72,6 +73,7 @@ from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
- from portage.process import find_binary
- from portage.util import ( apply_recursive_permissions,
- apply_secpass_permissions,
-+ getconfig,
- noiselimit,
- shlex_split,
- varexpand,
-@@ -79,6 +81,7 @@ from portage.util import ( apply_recursive_permissions,
- writemsg_stdout,
- write_atomic
- )
-+from portage.util._path import exists_raise_eaccess
- from portage.util.cpuinfo import get_cpu_count
- from portage.util.lafilefixer import rewrite_lafile
- from portage.util.compression_probe import _compressors
-@@ -241,8 +244,27 @@ def _doebuild_path(settings, eapi=None):
-
- for x in portage_bin_path:
- path.append(os.path.join(x, "ebuild-helpers"))
-+
-+ # PREFIX CHAINING: append default path for all prefixes involved
-+ pfxs = [ eprefix ]
-+ pfxs.extend(settings.readonly_prefixes)
-+ for prefix in pfxs:
-+ global_config_path = os.path.join(prefix, GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ make_globals_path = os.path.join(global_config_path, "make.globals")
-+ if exists_raise_eaccess(make_globals_path):
-+ expand_map = { "EPREFIX": prefix }
-+ pxcfg = getconfig(make_globals_path, True, expand_map)
-+ pxdefp = [x for x in pxcfg.get("DEFAULT_PATH", "").split(":") if x]
-+ for x in pxdefp:
-+ if x.startswith(prefix) and not x in path:
-+ path.append(x)
-+ else:
-+ pxdefs = [prefix + "/usr/sbin", prefix + "/usr/bin", prefix + "/sbin", prefix + "/bin"]
-+ path.extend(pxdefs)
-+ # END PREFIX CHAINING
-+
- path.extend(prerootpath)
-- path.extend(defaultpath)
-+ # path.extend(defaultpath) # PREFIX CHAINING appends the default path for involved prefixes above
- path.extend(rootpath)
- path.extend(extrapath)
- # END PREFIX LOCAL
-diff --git a/pym/portage/package/ebuild/fetch.py b/pym/portage/package/ebuild/fetch.py
-index 265d0c9fc..2ec6ff472 100644
---- a/pym/portage/package/ebuild/fetch.py
-+++ b/pym/portage/package/ebuild/fetch.py
-@@ -43,6 +43,7 @@ from portage.output import colorize, EOutput
- from portage.util import apply_recursive_permissions, \
- apply_secpass_permissions, ensure_dirs, grabdict, shlex_split, \
- varexpand, writemsg, writemsg_level, writemsg_stdout
-+from portage.util._path import exists_raise_eaccess
- from portage.process import spawn
-
- _userpriv_spawn_kwargs = (
-@@ -874,6 +875,9 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0,
- global_config_path = GLOBAL_CONFIG_PATH
- if portage.const.EPREFIX:
- global_config_path = os.path.join(portage.const.EPREFIX,
-+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(global_config_path) and portage.const.BPREFIX:
-+ global_config_path = os.path.join(portage.const.BPREFIX,
- GLOBAL_CONFIG_PATH.lstrip(os.sep))
-
- missing_file_param = False
-diff --git a/pym/portage/sync/controller.py b/pym/portage/sync/controller.py
-index 3bccf6f74..cacd63797 100644
---- a/pym/portage/sync/controller.py
-+++ b/pym/portage/sync/controller.py
-@@ -94,19 +94,20 @@ class SyncManager(object):
- self.module_controller = portage.sync.module_controller
- self.module_names = self.module_controller.module_names
- self.hooks = {}
-- for _dir in ["repo.postsync.d", "postsync.d"]:
-- postsync_dir = os.path.join(self.settings["PORTAGE_CONFIGROOT"],
-- portage.USER_CONFIG_PATH, _dir)
-- hooks = OrderedDict()
-- for filepath in util._recursive_file_list(postsync_dir):
-- name = filepath.split(postsync_dir)[1].lstrip(os.sep)
-- if os.access(filepath, os.X_OK):
-- hooks[filepath] = name
-- else:
-- writemsg_level(" %s %s hook: '%s' is not executable\n"
-- % (warn("*"), _dir, _unicode_decode(name),),
-- level=logging.WARN, noiselevel=2)
-- self.hooks[_dir] = hooks
-+ for _confroot in [self.settings["PORTAGE_CONFIGROOT"], portage.const.BPREFIX]:
-+ for _dir in ["repo.postsync.d", "postsync.d"]:
-+ postsync_dir = os.path.join(_confroot,
-+ portage.USER_CONFIG_PATH, _dir)
-+ hooks = OrderedDict()
-+ for filepath in util._recursive_file_list(postsync_dir):
-+ name = filepath.split(postsync_dir)[1].lstrip(os.sep)
-+ if os.access(filepath, os.X_OK):
-+ hooks[filepath] = name
-+ else:
-+ writemsg_level(" %s %s hook: '%s' is not executable\n"
-+ % (warn("*"), _dir, _unicode_decode(name),),
-+ level=logging.WARN, noiselevel=2)
-+ self.hooks[_dir] = hooks
-
- def __getattr__(self, name):
- if name == 'async':
-diff --git a/pym/portage/util/_dyn_libs/LinkageMapELF.py b/pym/portage/util/_dyn_libs/LinkageMapELF.py
-index a063621c1..968fbd339 100644
---- a/pym/portage/util/_dyn_libs/LinkageMapELF.py
-+++ b/pym/portage/util/_dyn_libs/LinkageMapELF.py
-@@ -12,7 +12,7 @@ from portage import _os_merge
- from portage import _unicode_decode
- from portage import _unicode_encode
- from portage.cache.mappings import slot_dict_class
--from portage.const import EPREFIX
-+from portage.const import BPREFIX
- from portage.dep.soname.multilib_category import compute_multilib_category
- from portage.exception import CommandNotFound, InvalidData
- from portage.localization import _
-@@ -268,7 +268,7 @@ class LinkageMapELF(object):
- continue
- plibs.update((x, cpv) for x in items)
- if plibs:
-- args = [os.path.join(EPREFIX or "/", "usr/bin/scanelf"), "-qF", "%a;%F;%S;%r;%n"]
-+ args = [os.path.join(BPREFIX or "/", "usr/bin/scanelf"), "-qF", "%a;%F;%S;%r;%n"]
- args.extend(os.path.join(root, x.lstrip("." + os.sep)) \
- for x in plibs)
- try:
---
-2.13.6
-
diff --git a/sys-apps/portage/files/portage-2.3.40-prefix-chaining.patch b/sys-apps/portage/files/portage-2.3.40-prefix-chaining.patch
deleted file mode 100644
index 8e0864990d..0000000000
--- a/sys-apps/portage/files/portage-2.3.40-prefix-chaining.patch
+++ /dev/null
@@ -1,921 +0,0 @@
-From 9c991762d6becb779925d59289eb0324f269ad18 Mon Sep 17 00:00:00 2001
-From: Michael Haubenwallner <haubi@gentoo.org>
-Date: Thu, 23 Mar 2017 13:52:32 +0100
-Subject: [PATCH 2/2] add prefix-chaining support
-
----
- bin/install-qa-check.d/05prefix | 30 ++++++-
- bin/phase-helpers.sh | 24 ++++++
- pym/_emerge/actions.py | 6 +-
- pym/_emerge/depgraph.py | 53 +++++++-----
- pym/_emerge/resolver/output.py | 40 ++++++++-
- pym/portage/_sets/__init__.py | 5 ++
- pym/portage/const.py | 6 ++
- pym/portage/dbapi/vartree.py | 34 ++++++--
- pym/portage/dep/dep_check.py | 99 +++++++++++++++++++++-
- .../package/ebuild/_config/LocationsManager.py | 3 +
- pym/portage/package/ebuild/config.py | 62 ++++++++++++++
- pym/portage/package/ebuild/doebuild.py | 24 +++++-
- pym/portage/package/ebuild/fetch.py | 4 +
- pym/portage/sync/controller.py | 27 +++---
- pym/portage/util/_dyn_libs/LinkageMapELF.py | 4 +-
- 15 files changed, 373 insertions(+), 48 deletions(-)
-
-diff --git a/bin/install-qa-check.d/05prefix b/bin/install-qa-check.d/05prefix
-index 32561e263..0c1147367 100644
---- a/bin/install-qa-check.d/05prefix
-+++ b/bin/install-qa-check.d/05prefix
-@@ -79,16 +79,42 @@ install_qa_check_prefix() {
- # unprefixed shebang, is the script directly in $PATH or an init
- # script?
- if [[ ":${PATH}:${EPREFIX}/etc/init.d:" == *":${fp}:"* ]] ; then
-- if [[ -e ${EROOT}${line[0]} || -e ${ED}${line[0]} ]] ; then
-+ all_epfs="$PORTAGE_READONLY_EPREFIXES:$EPREFIX:$EROOT:$ED"
-+ save_IFS=$IFS
-+ IFS=:
-+ epfs=( $all_epfs )
-+ IFS=$save_IFS
-+
-+ found=
-+ for x in "${epfs[@]}"; do
-+ [[ -z "${x}" ]] && continue
-+ check="${x}${line[0]}"
-+
-+ # might already contain a prefix
-+ if [[ "${line[0]}" == "${x}"* ]]; then
-+ check="${line[0]}"
-+ fi
-+
-+ if [[ -e ${check} ]]; then
-+ found="${check}"
-+ fi
-+ done
-+
-+ if [[ -n ${found} ]] ; then
- # is it unprefixed, but we can just fix it because a
- # prefixed variant exists
- eqawarn "prefixing shebang of ${fn#${D}}"
-+
-+ if [[ ${found} == "${ED}"* || ${found} == "${EROOT}"* ]]; then
-+ found="${EPREFIX}${line[0]}"
-+ fi
-+
- # statement is made idempotent on purpose, because
- # symlinks may point to the same target, and hence the
- # same real file may be sedded multiple times since we
- # read the shebangs in one go upfront for performance
- # reasons
-- sed -i -e '1s:^#! \?'"${line[0]}"':#!'"${EPREFIX}"${line[0]}':' "${rf}"
-+ sed -i -e '1s:^#! \?'"${line[0]}"':#!'"${found}"':' "${rf}"
- continue
- else
- # this is definitely wrong: script in $PATH and invalid shebang
-diff --git a/bin/phase-helpers.sh b/bin/phase-helpers.sh
-index 75d92b407..c32533fb3 100644
---- a/bin/phase-helpers.sh
-+++ b/bin/phase-helpers.sh
-@@ -934,6 +934,10 @@ ___best_version_and_has_version_common() {
- fi
- "${cmd[@]}"
- local retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ ${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' '${FUNCNAME[1]}' '${READONLY_EPREFIX%:*}' '${atom}'"
-+ retval=$?
-+ fi
- case "${retval}" in
- 0|1)
- return ${retval}
-@@ -1194,6 +1198,10 @@ if ___eapi_has_master_repositories; then
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" master_repositories "${EROOT}" "${repository}")
- fi
- retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' master_repositories '${READONLY_EPREFIX%:*}' '${repository}'")
-+ retval=$?
-+ fi
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
- 0|1)
-@@ -1225,6 +1233,10 @@ if ___eapi_has_repository_path; then
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" get_repo_path "${EROOT}" "${repository}")
- fi
- retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' get_repo_path '${READONLY_EPREFIX%:*}' '${repository}'")
-+ retval=$?
-+ fi
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
- 0|1)
-@@ -1255,6 +1267,10 @@ if ___eapi_has_available_eclasses; then
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" available_eclasses "${EROOT}" "${repository}")
- fi
- retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' available_eclasses '${READONLY_EPREFIX%:*}' '${repository}'")
-+ retval=$?
-+ fi
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
- 0|1)
-@@ -1285,6 +1301,10 @@ if ___eapi_has_eclass_path; then
- else
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" eclass_path "${EROOT}" "${repository}" "${eclass}")
- fi
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' eclass_path '${READONLY_EPREFIX%:*}' '${repository}' '${eclass}'")
-+ retval=$?
-+ fi
- retval=$?
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
-@@ -1316,6 +1336,10 @@ if ___eapi_has_license_path; then
- else
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" license_path "${EROOT}" "${repository}" "${license}")
- fi
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' license_path '${READONLY_EPREFIX%:*}' '${repository}' '${license}'")
-+ retval=$?
-+ fi
- retval=$?
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
-diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py
-index 432fc57e3..764462fc5 100644
---- a/pym/_emerge/actions.py
-+++ b/pym/_emerge/actions.py
-@@ -39,7 +39,7 @@ from portage import os
- from portage import shutil
- from portage import eapi_is_supported, _encodings, _unicode_decode
- from portage.cache.cache_errors import CacheError
--from portage.const import EPREFIX
-+from portage.const import EPREFIX, BPREFIX
- from portage.const import GLOBAL_CONFIG_PATH, VCS_DIRS, _DEPCLEAN_LIB_CHECK_DEFAULT
- from portage.const import SUPPORTED_BINPKG_FORMATS, TIMESTAMP_FORMAT
- from portage.dbapi.dep_expand import dep_expand
-@@ -65,6 +65,7 @@ from portage.util.SlotObject import SlotObject
- from portage.util._async.run_main_scheduler import run_main_scheduler
- from portage.util._async.SchedulerInterface import SchedulerInterface
- from portage.util._eventloop.global_event_loop import global_event_loop
-+from portage.util._path import exists_raise_eaccess
- from portage._global_updates import _global_updates
- from portage.sync.old_tree_timestamp import old_tree_timestamp_warn
- from portage.localization import _
-@@ -2672,6 +2673,9 @@ def missing_sets_warning(root_config, missing_sets):
- if portage.const.EPREFIX:
- global_config_path = os.path.join(portage.const.EPREFIX,
- portage.const.GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(global_config_path) and portage.const.BPREFIX:
-+ global_config_path = os.path.join(portage.const.BPREFIX,
-+ portage.const.GLOBAL_CONFIG_PATH.lstrip(os.sep))
- msg.append(" This usually means that '%s'" % \
- (os.path.join(global_config_path, "sets/portage.conf"),))
- msg.append(" is missing or corrupt.")
-diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
-index f7bac69f9..a6eb0d3d4 100644
---- a/pym/_emerge/depgraph.py
-+++ b/pym/_emerge/depgraph.py
-@@ -3355,19 +3355,19 @@ class depgraph(object):
- # _dep_disjunctive_stack first, so that choices for build-time
- # deps influence choices for run-time deps (bug 639346).
- deps = (
-- (myroot, edepend["RDEPEND"],
-+ (myroot, "RDEPEND",
- self._priority(runtime=True)),
-- (myroot, edepend["PDEPEND"],
-+ (myroot, "PDEPEND",
- self._priority(runtime_post=True)),
-- (depend_root, edepend["DEPEND"],
-+ (depend_root, "DEPEND",
- self._priority(buildtime=True,
- optional=(pkg.built or ignore_depend_deps),
- ignored=ignore_depend_deps)),
-- (self._frozen_config._running_root.root, edepend["HDEPEND"],
-+ (self._frozen_config._running_root.root, "HDEPEND",
- self._priority(buildtime=True,
- optional=(pkg.built or ignore_hdepend_deps),
- ignored=ignore_hdepend_deps)),
-- (self._frozen_config._running_root.root, edepend["BDEPEND"],
-+ (self._frozen_config._running_root.root, "BDEPEND",
- self._priority(buildtime=True,
- optional=(pkg.built or ignore_bdepend_deps),
- ignored=ignore_bdepend_deps)),
-@@ -3375,7 +3375,8 @@ class depgraph(object):
-
- debug = "--debug" in self._frozen_config.myopts
-
-- for dep_root, dep_string, dep_priority in deps:
-+ for dep_root, dep_type, dep_priority in deps:
-+ dep_string = edepend[dep_type]
- if not dep_string:
- continue
- if debug:
-@@ -3413,7 +3414,7 @@ class depgraph(object):
-
- try:
- dep_string = list(self._queue_disjunctive_deps(
-- pkg, dep_root, dep_priority, dep_string))
-+ pkg, dep_root, dep_priority, dep_string, dep_type))
- except portage.exception.InvalidDependString as e:
- if pkg.installed:
- self._dynamic_config._masked_installed.add(pkg)
-@@ -3428,14 +3429,14 @@ class depgraph(object):
-
- if not self._add_pkg_dep_string(
- pkg, dep_root, dep_priority, dep_string,
-- allow_unsatisfied):
-+ allow_unsatisfied, dep_type):
- return 0
-
- self._dynamic_config._traversed_pkg_deps.add(pkg)
- return 1
-
- def _add_pkg_dep_string(self, pkg, dep_root, dep_priority, dep_string,
-- allow_unsatisfied):
-+ allow_unsatisfied, dep_type=None):
- _autounmask_backup = self._dynamic_config._autounmask
- if dep_priority.optional or dep_priority.ignored:
- # Temporarily disable autounmask for deps that
-@@ -3444,7 +3445,7 @@ class depgraph(object):
- try:
- return self._wrapped_add_pkg_dep_string(
- pkg, dep_root, dep_priority, dep_string,
-- allow_unsatisfied)
-+ allow_unsatisfied, dep_type)
- finally:
- self._dynamic_config._autounmask = _autounmask_backup
-
-@@ -3480,7 +3481,7 @@ class depgraph(object):
- not slot_operator_rebuild
-
- def _wrapped_add_pkg_dep_string(self, pkg, dep_root, dep_priority,
-- dep_string, allow_unsatisfied):
-+ dep_string, allow_unsatisfied, dep_type=None):
- if isinstance(pkg.depth, int):
- depth = pkg.depth + 1
- else:
-@@ -3504,7 +3505,7 @@ class depgraph(object):
- try:
- selected_atoms = self._select_atoms(dep_root,
- dep_string, myuse=self._pkg_use_enabled(pkg), parent=pkg,
-- strict=strict, priority=dep_priority)
-+ strict=strict, priority=dep_priority, dep_type=dep_type)
- except portage.exception.InvalidDependString:
- if pkg.installed:
- self._dynamic_config._masked_installed.add(pkg)
-@@ -3811,7 +3812,7 @@ class depgraph(object):
- child_pkgs.sort()
- yield (atom, child_pkgs[-1])
-
-- def _queue_disjunctive_deps(self, pkg, dep_root, dep_priority, dep_struct):
-+ def _queue_disjunctive_deps(self, pkg, dep_root, dep_priority, dep_struct, dep_type=None):
- """
- Queue disjunctive (virtual and ||) deps in self._dynamic_config._dep_disjunctive_stack.
- Yields non-disjunctive deps. Raises InvalidDependString when
-@@ -3820,33 +3821,33 @@ class depgraph(object):
- for x in dep_struct:
- if isinstance(x, list):
- if x and x[0] == "||":
-- self._queue_disjunction(pkg, dep_root, dep_priority, [x])
-+ self._queue_disjunction(pkg, dep_root, dep_priority, [x], dep_type)
- else:
- for y in self._queue_disjunctive_deps(
-- pkg, dep_root, dep_priority, x):
-+ pkg, dep_root, dep_priority, x, dep_type):
- yield y
- else:
- # Note: Eventually this will check for PROPERTIES=virtual
- # or whatever other metadata gets implemented for this
- # purpose.
- if x.cp.startswith('virtual/'):
-- self._queue_disjunction(pkg, dep_root, dep_priority, [x])
-+ self._queue_disjunction(pkg, dep_root, dep_priority, [x], dep_type)
- else:
- yield x
-
-- def _queue_disjunction(self, pkg, dep_root, dep_priority, dep_struct):
-+ def _queue_disjunction(self, pkg, dep_root, dep_priority, dep_struct, dep_type=None):
- self._dynamic_config._dep_disjunctive_stack.append(
-- (pkg, dep_root, dep_priority, dep_struct))
-+ (pkg, dep_root, dep_priority, dep_struct, dep_type))
-
- def _pop_disjunction(self, allow_unsatisfied):
- """
- Pop one disjunctive dep from self._dynamic_config._dep_disjunctive_stack, and use it to
- populate self._dynamic_config._dep_stack.
- """
-- pkg, dep_root, dep_priority, dep_struct = \
-+ pkg, dep_root, dep_priority, dep_struct, dep_type = \
- self._dynamic_config._dep_disjunctive_stack.pop()
- if not self._add_pkg_dep_string(
-- pkg, dep_root, dep_priority, dep_struct, allow_unsatisfied):
-+ pkg, dep_root, dep_priority, dep_struct, allow_unsatisfied, dep_type):
- return 0
- return 1
-
-@@ -4699,7 +4700,7 @@ class depgraph(object):
- return self._select_atoms_highest_available(*pargs, **kwargs)
-
- def _select_atoms_highest_available(self, root, depstring,
-- myuse=None, parent=None, strict=True, trees=None, priority=None):
-+ myuse=None, parent=None, strict=True, trees=None, priority=None, dep_type=None):
- """This will raise InvalidDependString if necessary. If trees is
- None then self._dynamic_config._filtered_trees is used."""
-
-@@ -4722,6 +4723,13 @@ class depgraph(object):
- pkgsettings = self._frozen_config.pkgsettings[root]
- if trees is None:
- trees = self._dynamic_config._filtered_trees
-+
-+ # this one is needed to guarantee good readonly root
-+ # resolution display in the merge list. required since
-+ # parent (below) can be None
-+ trees[root]["disp_parent"] = parent
-+
-+
- mytrees = trees[root]
- atom_graph = digraph()
- if True:
-@@ -4753,7 +4761,7 @@ class depgraph(object):
-
- mycheck = portage.dep_check(depstring, None,
- pkgsettings, myuse=myuse,
-- myroot=root, trees=trees)
-+ myroot=root, trees=trees, dep_type=dep_type)
- finally:
- # restore state
- self._dynamic_config._autounmask = _autounmask_backup
-@@ -4829,6 +4837,7 @@ class depgraph(object):
- continue
- node_stack.append((child_node, node, child_atom))
-
-+ trees[root].pop("disp_parent")
- return selected_atoms
-
- def _expand_virt_from_graph(self, root, atom):
-diff --git a/pym/_emerge/resolver/output.py b/pym/_emerge/resolver/output.py
-index 24340576c..4a1741f3a 100644
---- a/pym/_emerge/resolver/output.py
-+++ b/pym/_emerge/resolver/output.py
-@@ -22,11 +22,12 @@ from portage.localization import localized_size
- from portage.package.ebuild.config import _get_feature_flags
- from portage.package.ebuild._spawn_nofetch import spawn_nofetch
- from portage.output import ( blue, colorize, create_color_func,
-- darkblue, darkgreen, green, nc_len, teal)
-+ darkblue, darkgreen, green, nc_len, teal, yellow, turquoise)
- bad = create_color_func("BAD")
- from portage._sets.base import InternalPackageSet
- from portage.util import writemsg_stdout
- from portage.versions import best, cpv_getversion
-+from portage.dep.dep_check import ro_selected
-
- from _emerge.Blocker import Blocker
- from _emerge.create_world_atom import create_world_atom
-@@ -563,6 +564,42 @@ class Display(object):
- writemsg_stdout("%s\n" % (pkg,), noiselevel=-1)
- return
-
-+ def print_readonly_prefix(self):
-+ """Performs the actual output printing for the readonly prefix
-+ information stuff
-+ """
-+ out = sys.stdout
-+
-+ # print readonly selected packages
-+ if len(ro_selected) > 0:
-+ out.write("\n%s\n\n" % (darkgreen("Packages resolved from readonly installations:")))
-+
-+ ro_mismatch_warning = False
-+ ro_dupcheck = []
-+ for x in ro_selected:
-+ tmp_type = x["type"].replace("END","")
-+ while len(tmp_type) < 4:
-+ tmp_type += " "
-+ if x["parent"] and str(x["atom"]) not in ro_dupcheck:
-+ out.write("[%s %s] %s %s %s (%s by %s)" % (teal("readonly"),
-+ green(tmp_type), green(str(x["matches"][0])), yellow("from"),
-+ blue(x["ro_root"]), turquoise(str(x["atom"])), green(x["parent"].cpv)))
-+
-+ ro_dupcheck.append(str(x["atom"]))
-+
-+ if x["host_mismatch"]:
-+ ro_mismatch_warning = True
-+ out.write(" %s\n" % (red("**")))
-+ else:
-+ out.write("\n")
-+
-+ if ro_mismatch_warning:
-+ out.write("\n%s:" % (red("**")))
-+ out.write(yellow(" WARNING: packages marked with ** have been resolved as a\n"))
-+ out.write(yellow(" runtime dependency, but the CHOST variable for the parent\n"))
-+ out.write(yellow(" and dependency package don't match. This could cause link\n"))
-+ out.write(yellow(" errors. It is recommended to use RDEPEND READONLY_EPREFIX's\n"))
-+ out.write(yellow(" only with matching CHOST portage instances.\n"))
-
- def print_verbose(self, show_repos):
- """Prints the verbose output to std_out
-@@ -913,6 +950,7 @@ class Display(object):
- show_repos = self.quiet_repo_display and repoadd_set and repoadd_set != set(["0"])
-
- # now finally print out the messages
-+ self.print_readonly_prefix()
- self.print_messages(show_repos)
- self.print_blockers()
- if self.conf.verbosity == 3:
-diff --git a/pym/portage/_sets/__init__.py b/pym/portage/_sets/__init__.py
-index 2c9bf9715..6a2784207 100644
---- a/pym/portage/_sets/__init__.py
-+++ b/pym/portage/_sets/__init__.py
-@@ -21,6 +21,7 @@ from portage.const import _ENABLE_SET_CONFIG
- from portage.exception import PackageSetNotFound
- from portage.localization import _
- from portage.util import writemsg_level
-+from portage.util._path import exists_raise_eaccess
- from portage.util.configparser import (SafeConfigParser,
- NoOptionError, ParsingError, read_configs)
-
-@@ -281,6 +282,10 @@ def load_default_config(settings, trees):
- if portage.const.EPREFIX:
- global_config_path = os.path.join(portage.const.EPREFIX,
- GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(global_config_path) and portage.const.BPREFIX:
-+ global_config_path = os.path.join(portage.const.BPREFIX,
-+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+
- vcs_dirs = [_unicode_encode(x, encoding=_encodings['fs']) for x in VCS_DIRS]
- def _getfiles():
- for path, dirs, files in os.walk(os.path.join(global_config_path, "sets")):
-diff --git a/pym/portage/const.py b/pym/portage/const.py
-index d9c57f300..a3d927c3b 100644
---- a/pym/portage/const.py
-+++ b/pym/portage/const.py
-@@ -190,6 +190,7 @@ SUPPORTED_FEATURES = frozenset([
- "notitles",
- "parallel-fetch",
- "parallel-install",
-+ "prefix-chaining",
- "prelink-checksums",
- "preserve-libs",
- "protect-owned",
-@@ -241,6 +242,11 @@ MANIFEST2_IDENTIFIERS = ("AUX", "MISC", "DIST", "EBUILD")
- #EPREFIX = ""
- # END PREFIX LOCAL
-
-+BPREFIX = EPREFIX
-+
-+# --prefix commandline arg always rules, ends up in os.environ["EPREFIX"]
-+if "EPREFIX" in os.environ:
-+ os.environ["PORTAGE_OVERRIDE_EPREFIX"] = os.environ["EPREFIX"]
- # pick up EPREFIX from the environment if set
- if "PORTAGE_OVERRIDE_EPREFIX" in os.environ:
- EPREFIX = os.environ["PORTAGE_OVERRIDE_EPREFIX"]
-diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
-index 77a72b5b1..f20c6763e 100644
---- a/pym/portage/dbapi/vartree.py
-+++ b/pym/portage/dbapi/vartree.py
-@@ -196,8 +196,19 @@ class vardbapi(dbapi):
- self._counter_path = os.path.join(self._eroot,
- CACHE_PATH, "counter")
-
-- self._plib_registry = PreservedLibsRegistry(settings["ROOT"],
-- os.path.join(self._eroot, PRIVATE_PATH, "preserved_libs_registry"))
-+ plibreg_path = os.path.join(self._eroot, PRIVATE_PATH, "preserved_libs_registry")
-+
-+ if vartree:
-+ self._kill_eprefix = vartree._kill_eprefix
-+ else:
-+ self._kill_eprefix = False
-+
-+ if self._kill_eprefix:
-+ self._aux_cache_filename = self._aux_cache_filename.replace(EPREFIX, "")
-+ self._counter_path = self._counter_path.replace(EPREFIX, "")
-+ plibreg_path = plibreg_path.replace(EPREFIX, "")
-+
-+ self._plib_registry = PreservedLibsRegistry(settings["ROOT"], plibreg_path)
- self._linkmap = LinkageMap(self)
- chost = self.settings.get('CHOST')
- if not chost:
-@@ -238,6 +249,9 @@ class vardbapi(dbapi):
- # This is an optimized hotspot, so don't use unicode-wrapped
- # os module and don't use os.path.join().
- rValue = self._eroot + VDB_PATH + _os.sep + mykey
-+ if self._kill_eprefix:
-+ rValue = rValue.replace(EPREFIX, "")
-+
- if filename is not None:
- # If filename is always relative, we can do just
- # rValue += _os.sep + filename
-@@ -502,6 +516,9 @@ class vardbapi(dbapi):
- returnme = []
- basepath = os.path.join(self._eroot, VDB_PATH) + os.path.sep
-
-+ if self._kill_eprefix:
-+ basepath = os.path.join(self.root, basepath.replace(EPREFIX, ""))
-+
- if use_cache:
- from portage import listdir
- else:
-@@ -598,11 +615,17 @@ class vardbapi(dbapi):
- del self.matchcache[mycat]
- return list(self._iter_match(mydep,
- self.cp_list(mydep.cp, use_cache=use_cache)))
-+
-+ _tmp_path = os.path.join(self._eroot, VDB_PATH, mycat)
-+
-+ if self._kill_eprefix:
-+ _tmp_path = _tmp_path.replace(EPREFIX, "")
-+
- try:
- if sys.hexversion >= 0x3030000:
-- curmtime = os.stat(os.path.join(self._eroot, VDB_PATH, mycat)).st_mtime_ns
-+ curmtime = os.stat(_tmp_path).st_mtime_ns
- else:
-- curmtime = os.stat(os.path.join(self._eroot, VDB_PATH, mycat)).st_mtime
-+ curmtime = os.stat(_tmp_path).st_mtime
- except (IOError, OSError):
- curmtime=0
-
-@@ -1450,7 +1473,7 @@ class vardbapi(dbapi):
- class vartree(object):
- "this tree will scan a var/db/pkg database located at root (passed to init)"
- def __init__(self, root=None, virtual=DeprecationWarning, categories=None,
-- settings=None):
-+ settings=None, kill_eprefix=None):
-
- if settings is None:
- settings = portage.settings
-@@ -1468,6 +1491,7 @@ class vartree(object):
- " constructor is unused",
- DeprecationWarning, stacklevel=2)
-
-+ self._kill_eprefix = kill_eprefix
- self.settings = settings
- self.dbapi = vardbapi(settings=settings, vartree=self)
- self.populated = 1
-diff --git a/pym/portage/dep/dep_check.py b/pym/portage/dep/dep_check.py
-index 2896e2389..c700a3651 100644
---- a/pym/portage/dep/dep_check.py
-+++ b/pym/portage/dep/dep_check.py
-@@ -298,6 +298,95 @@ class _dep_choice(SlotObject):
- __slots__ = ('atoms', 'slot_map', 'cp_map', 'all_available',
- 'all_installed_slots', 'new_slot_count')
-
-+ro_trees={}
-+ro_vartrees={}
-+ro_selected=[]
-+
-+def dep_match_readonly_roots(settings, atom, dep_type, parent=None):
-+ if len(ro_trees) < len(settings.readonly_prefixes):
-+ # MDUFT: create additional vartrees for every readonly root here.
-+ # the ro_vartrees instances are created below as they are needed to
-+ # avoid reading vartrees of portage instances which aren't required
-+ # while resolving this dependencies.
-+ for type in ("DEPEND","RDEPEND", "PDEPEND"):
-+ ro_trees[type] = []
-+
-+ for ro_root, ro_dep_types in settings.readonly_prefixes.items():
-+ if type in ro_dep_types:
-+ ro_trees[type].append(ro_root)
-+
-+ if len(ro_trees) == 0:
-+ return []
-+
-+ matches = []
-+
-+ for ro_root in ro_trees[dep_type]:
-+ if not ro_root in ro_vartrees:
-+ # target_root=ro_root ok? or should it be the real target_root?
-+ _tmp_settings = portage.config(config_root=ro_root, target_root=ro_root,
-+ config_incrementals=portage.const.INCREMENTALS)
-+
-+ ro_vartrees[ro_root] = portage.vartree(root=ro_root,
-+ categories=_tmp_settings.categories,
-+ settings=_tmp_settings, kill_eprefix=True)
-+
-+ ro_matches = ro_vartrees[ro_root].dbapi.match(atom)
-+
-+ if ro_matches:
-+ ro_host_mismatch = False
-+ if dep_type is "RDEPEND":
-+ # we need to assure binary compatability, so it needs to be
-+ # the same CHOST! But how? for now i cannot do anything...
-+ if parent and parent.metadata["CHOST"] != ro_vartrees[ro_root].settings.get("CHOST", ""):
-+ # provocate a big fat warning in the list of external packages.
-+ ro_host_mismatch = True
-+ pass
-+
-+ matches.append({ "ro_root": ro_root, "atom": atom, "matches": ro_matches,
-+ "type": dep_type, "parent": parent, "host_mismatch": ro_host_mismatch })
-+
-+ return matches
-+
-+def dep_wordreduce_readonly(reduced, unreduced, settings, dep_type, parent):
-+ for mypos, token in enumerate(unreduced):
-+ # recurse if it's a list.
-+ if isinstance(reduced[mypos], list):
-+ reduced[mypos] = dep_wordreduce_readonly(reduced[mypos],
-+ unreduced[mypos], settings, dep_type, parent)
-+
-+ # do nothing if it's satisfied already.
-+ elif not reduced[mypos]:
-+ ro_matches = dep_match_readonly_roots(settings, unreduced[mypos], dep_type, parent)
-+
-+ if ro_matches:
-+ # TODO: select a match if there are more than one?
-+ # for now, the first match is taken...
-+ ro_selected.append(ro_matches[0])
-+ reduced[mypos] = True
-+
-+ return reduced
-+
-+# this may be better placed somewhere else, but i put it here for now, to
-+# keep all functions in the patch on one big heap.
-+def readonly_pathmatch_any(settings, path):
-+ path = path.lstrip('/')
-+ # first try locally, and match that if it exists.
-+ if os.path.exists(os.path.join(EPREFIX,path)):
-+ return os.path.join(EPREFIX,path)
-+
-+ # after that try all readonly roots where DEPEND is allowed. this makes
-+ # sure that executing binaries is possible from there.
-+ for ro_root, ro_deps in settings.readonly_roots.items():
-+ if "DEPEND" in ro_deps:
-+ print(" --- checking %s --- " % (os.path.join(ro_root,path)))
-+ if os.path.exists(os.path.join(ro_root,path)):
-+ return os.path.join(ro_root,path)
-+ break
-+
-+ # as a fallback make the string the same as it was originally.
-+ # even though this path doesn't exist.
-+ return os.path.join(EPREFIX,path)
-+
- def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None,
- minimize_slots=False):
- """
-@@ -725,7 +814,7 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None,
- assert(False) # This point should not be reachable
-
- def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None,
-- use_cache=1, use_binaries=0, myroot=None, trees=None):
-+ use_cache=1, use_binaries=0, myroot=None, trees=None, dep_type=None):
- """
- Takes a depend string, parses it, and selects atoms.
- The myroot parameter is unused (use mysettings['EROOT'] instead).
-@@ -829,6 +918,14 @@ def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None,
- writemsg("mysplit: %s\n" % (mysplit), 1)
- writemsg("mysplit2: %s\n" % (mysplit2), 1)
-
-+ if dep_type is not None:
-+ mysplit2=dep_wordreduce_readonly(unreduced=mysplit[:],
-+ reduced=mysplit2, settings=mysettings,
-+ dep_type=dep_type, parent=trees[myroot].get("disp_parent"))
-+
-+ writemsg("\n", 1)
-+ writemsg("mysplit2 after readonly reduce: %s\n" % (mysplit2), 1)
-+
- selected_atoms = dep_zapdeps(mysplit, mysplit2, myroot,
- use_binaries=use_binaries, trees=trees, minimize_slots=dnf)
-
-diff --git a/pym/portage/package/ebuild/_config/LocationsManager.py b/pym/portage/package/ebuild/_config/LocationsManager.py
-index f7d7209ff..e37e5b1a9 100644
---- a/pym/portage/package/ebuild/_config/LocationsManager.py
-+++ b/pym/portage/package/ebuild/_config/LocationsManager.py
-@@ -326,6 +326,9 @@ class LocationsManager(object):
- if portage.const.EPREFIX:
- self.global_config_path = os.path.join(portage.const.EPREFIX,
- GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(self.global_config_path) and portage.const.BPREFIX:
-+ self.global_config_path = os.path.join(portage.const.BPREFIX,
-+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
-
- def set_port_dirs(self, portdir, portdir_overlay):
- self.portdir = portdir
-diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py
-index 059aa83ce..3bf6049e8 100644
---- a/pym/portage/package/ebuild/config.py
-+++ b/pym/portage/package/ebuild/config.py
-@@ -309,6 +309,7 @@ class config(object):
- self.features = features_set(self)
- self.features._features = copy.deepcopy(clone.features._features)
- self._features_overrides = copy.deepcopy(clone._features_overrides)
-+ self.readonly_prefixes = copy.deepcopy(clone.readonly_prefixes)
-
- #Strictly speaking _license_manager is not immutable. Users need to ensure that
- #extract_global_changes() is called right after __init__ (if at all).
-@@ -969,6 +970,63 @@ class config(object):
-
- self._validate_commands()
-
-+ # expand READONLY_EPREFIX to a list of all readonly portage instances
-+ # all the way down to the last one. beware that ATM a deeper instance
-+ # in the chain can provide more than the toplevel! this means that
-+ # if you only inherit DEPENDS from one instance, that instance may
-+ # inherit RDEPENDs from another one, making the top-level instance
-+ # inherit RDEPENDs from there too - even if the intermediate prefix
-+ # does not do this.
-+ self.readonly_prefixes = {}
-+ ro_cfg_root = config_root
-+ ro_widest_depset = set(['DEPEND', 'RDEPEND', 'PDEPEND'])
-+
-+ while ro_cfg_root:
-+ ro_make_conf_paths = [
-+ os.path.join(ro_cfg_root, 'etc', 'make.conf'),
-+ os.path.join(ro_cfg_root, MAKE_CONF_FILE)
-+ ]
-+ try:
-+ if os.path.samefile(*ro_make_conf_paths):
-+ ro_make_conf_paths.pop()
-+ except OSError:
-+ pass
-+
-+ ro_cfg_root = None
-+ for ro_make_conf in ro_make_conf_paths:
-+ if not os.path.exists(ro_make_conf):
-+ continue
-+
-+ ro_cfg = getconfig(ro_make_conf, tolerant=True, allow_sourcing=True)
-+ if not "READONLY_EPREFIX" in ro_cfg:
-+ continue
-+
-+ if not ro_cfg["READONLY_EPREFIX"].find(":"):
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: malformed READONLY_EPREFIX in %s" % (ro_make_conf))
-+
-+ if ro_cfg_root is not None:
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: duplicate READONLY_EPREFIX in %s and %s" % tuple(ro_make_conf_paths))
-+
-+ (ro_cfg_root,ro_cfg_root_deps) = ro_cfg["READONLY_EPREFIX"].rsplit(":",1)
-+
-+ if not os.path.exists(ro_cfg_root):
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: malformed READONLY_EPREFIX in %s: %s does not exist!" % (ro_make_conf, ro_cfg_root))
-+
-+ if os.path.samefile(ro_cfg_root, config_root):
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: cannot add this instance (%s) as READONLY_EPREFIX in %s." % (ro_cfg_root, ro_make_conf))
-+
-+ if ro_cfg_root in self.readonly_prefixes:
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: circular READONLY_EPREFIX's in %s. %s already checked for %s" % (ro_make_conf, ro_cfg_root, self.readonly_prefixes[ro_cfg_root]))
-+
-+ # intersect the widest depset with the current one to strip down
-+ # the allowed dependency resolution to not be wider than the
-+ # next higher one. this way we can prevent for a given prefix
-+ # to resolve RDEPENDs from a prefix with a different CHOST that
-+ # is a few levels deeper in the chain.
-+ ro_widest_depset = set(ro_cfg_root_deps.split(",")) & ro_widest_depset
-+ self.readonly_prefixes[ro_cfg_root] = ro_widest_depset
-+ pass
-+
- for k in self._case_insensitive_vars:
- if k in self:
- self[k] = self[k].lower()
-@@ -2771,6 +2829,10 @@ class config(object):
- if not (src_phase and eapi_attrs.broot):
- mydict.pop("BROOT", None)
-
-+ # populate with PORTAGE_READONLY_EPREFIXES
-+ if self.readonly_prefixes and len(self.readonly_prefixes) > 0:
-+ mydict["PORTAGE_READONLY_EPREFIXES"] = ':'.join(self.readonly_prefixes)
-+
- # Prefix variables are supported beginning with EAPI 3, or when
- # force-prefix is in FEATURES, since older EAPIs would otherwise be
- # useless with prefix configurations. This brings compatibility with
-diff --git a/pym/portage/package/ebuild/doebuild.py b/pym/portage/package/ebuild/doebuild.py
-index f8b784d6b..a6548a43b 100644
---- a/pym/portage/package/ebuild/doebuild.py
-+++ b/pym/portage/package/ebuild/doebuild.py
-@@ -52,6 +52,7 @@ from portage import bsd_chflags, \
- unmerge, _encodings, _os_merge, \
- _shell_quote, _unicode_decode, _unicode_encode
- from portage.const import EBUILD_SH_ENV_FILE, EBUILD_SH_ENV_DIR, \
-+ GLOBAL_CONFIG_PATH, \
- EBUILD_SH_BINARY, INVALID_ENV_FILE, MISC_SH_BINARY, PORTAGE_PYM_PACKAGES, EPREFIX, MACOSSANDBOX_PROFILE
- from portage.data import portage_gid, portage_uid, secpass, \
- uid, userpriv_groups
-@@ -73,6 +74,7 @@ from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
- from portage.process import find_binary
- from portage.util import ( apply_recursive_permissions,
- apply_secpass_permissions,
-+ getconfig,
- noiselimit,
- shlex_split,
- varexpand,
-@@ -80,6 +82,7 @@ from portage.util import ( apply_recursive_permissions,
- writemsg_stdout,
- write_atomic
- )
-+from portage.util._path import exists_raise_eaccess
- from portage.util.cpuinfo import get_cpu_count
- from portage.util.lafilefixer import rewrite_lafile
- from portage.util.compression_probe import _compressors
-@@ -243,8 +246,27 @@ def _doebuild_path(settings, eapi=None):
-
- for x in portage_bin_path:
- path.append(os.path.join(x, "ebuild-helpers"))
-+
-+ # PREFIX CHAINING: append default path for all prefixes involved
-+ pfxs = [ eprefix ]
-+ pfxs.extend(settings.readonly_prefixes)
-+ for prefix in pfxs:
-+ global_config_path = os.path.join(prefix, GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ make_globals_path = os.path.join(global_config_path, "make.globals")
-+ if exists_raise_eaccess(make_globals_path):
-+ expand_map = { "EPREFIX": prefix }
-+ pxcfg = getconfig(make_globals_path, True, expand_map)
-+ pxdefp = [x for x in pxcfg.get("DEFAULT_PATH", "").split(":") if x]
-+ for x in pxdefp:
-+ if x.startswith(prefix) and not x in path:
-+ path.append(x)
-+ else:
-+ pxdefs = [prefix + "/usr/sbin", prefix + "/usr/bin", prefix + "/sbin", prefix + "/bin"]
-+ path.extend(pxdefs)
-+ # END PREFIX CHAINING
-+
- path.extend(prerootpath)
-- path.extend(defaultpath)
-+ # path.extend(defaultpath) # PREFIX CHAINING appends the default path for involved prefixes above
- path.extend(rootpath)
- path.extend(extrapath)
- # END PREFIX LOCAL
-diff --git a/pym/portage/package/ebuild/fetch.py b/pym/portage/package/ebuild/fetch.py
-index 265d0c9fc..2ec6ff472 100644
---- a/pym/portage/package/ebuild/fetch.py
-+++ b/pym/portage/package/ebuild/fetch.py
-@@ -43,6 +43,7 @@ from portage.output import colorize, EOutput
- from portage.util import apply_recursive_permissions, \
- apply_secpass_permissions, ensure_dirs, grabdict, shlex_split, \
- varexpand, writemsg, writemsg_level, writemsg_stdout
-+from portage.util._path import exists_raise_eaccess
- from portage.process import spawn
-
- _userpriv_spawn_kwargs = (
-@@ -874,6 +875,9 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0,
- global_config_path = GLOBAL_CONFIG_PATH
- if portage.const.EPREFIX:
- global_config_path = os.path.join(portage.const.EPREFIX,
-+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(global_config_path) and portage.const.BPREFIX:
-+ global_config_path = os.path.join(portage.const.BPREFIX,
- GLOBAL_CONFIG_PATH.lstrip(os.sep))
-
- missing_file_param = False
-diff --git a/pym/portage/sync/controller.py b/pym/portage/sync/controller.py
-index 3bccf6f74..cacd63797 100644
---- a/pym/portage/sync/controller.py
-+++ b/pym/portage/sync/controller.py
-@@ -94,19 +94,20 @@ class SyncManager(object):
- self.module_controller = portage.sync.module_controller
- self.module_names = self.module_controller.module_names
- self.hooks = {}
-- for _dir in ["repo.postsync.d", "postsync.d"]:
-- postsync_dir = os.path.join(self.settings["PORTAGE_CONFIGROOT"],
-- portage.USER_CONFIG_PATH, _dir)
-- hooks = OrderedDict()
-- for filepath in util._recursive_file_list(postsync_dir):
-- name = filepath.split(postsync_dir)[1].lstrip(os.sep)
-- if os.access(filepath, os.X_OK):
-- hooks[filepath] = name
-- else:
-- writemsg_level(" %s %s hook: '%s' is not executable\n"
-- % (warn("*"), _dir, _unicode_decode(name),),
-- level=logging.WARN, noiselevel=2)
-- self.hooks[_dir] = hooks
-+ for _confroot in [self.settings["PORTAGE_CONFIGROOT"], portage.const.BPREFIX]:
-+ for _dir in ["repo.postsync.d", "postsync.d"]:
-+ postsync_dir = os.path.join(_confroot,
-+ portage.USER_CONFIG_PATH, _dir)
-+ hooks = OrderedDict()
-+ for filepath in util._recursive_file_list(postsync_dir):
-+ name = filepath.split(postsync_dir)[1].lstrip(os.sep)
-+ if os.access(filepath, os.X_OK):
-+ hooks[filepath] = name
-+ else:
-+ writemsg_level(" %s %s hook: '%s' is not executable\n"
-+ % (warn("*"), _dir, _unicode_decode(name),),
-+ level=logging.WARN, noiselevel=2)
-+ self.hooks[_dir] = hooks
-
- def __getattr__(self, name):
- if name == 'async':
-diff --git a/pym/portage/util/_dyn_libs/LinkageMapELF.py b/pym/portage/util/_dyn_libs/LinkageMapELF.py
-index a063621c1..968fbd339 100644
---- a/pym/portage/util/_dyn_libs/LinkageMapELF.py
-+++ b/pym/portage/util/_dyn_libs/LinkageMapELF.py
-@@ -12,7 +12,7 @@ from portage import _os_merge
- from portage import _unicode_decode
- from portage import _unicode_encode
- from portage.cache.mappings import slot_dict_class
--from portage.const import EPREFIX
-+from portage.const import BPREFIX
- from portage.dep.soname.multilib_category import compute_multilib_category
- from portage.exception import CommandNotFound, InvalidData
- from portage.localization import _
-@@ -268,7 +268,7 @@ class LinkageMapELF(object):
- continue
- plibs.update((x, cpv) for x in items)
- if plibs:
-- args = [os.path.join(EPREFIX or "/", "usr/bin/scanelf"), "-qF", "%a;%F;%S;%r;%n"]
-+ args = [os.path.join(BPREFIX or "/", "usr/bin/scanelf"), "-qF", "%a;%F;%S;%r;%n"]
- args.extend(os.path.join(root, x.lstrip("." + os.sep)) \
- for x in plibs)
- try:
---
-2.16.1
-
diff --git a/sys-apps/portage/files/portage-2.3.62-prefix-stack.patch b/sys-apps/portage/files/portage-2.3.62-prefix-stack.patch
new file mode 100644
index 0000000000..b0bdf2a20e
--- /dev/null
+++ b/sys-apps/portage/files/portage-2.3.62-prefix-stack.patch
@@ -0,0 +1,80 @@
+From 1fe30e79c368ce71e024d70c3ec07a6aed3ef262 Mon Sep 17 00:00:00 2001
+From: Michael Haubenwallner <haubi@gentoo.org>
+Date: Fri, 22 Mar 2019 17:52:05 +0100
+Subject: [PATCH] from FEATURES=stacked-prefix to USE=prefix-stack
+
+Rather than telling the base prefix' portage to support stacked prefix,
+be explicit in the stacked prefix about to USE that feature.
+Bug: https://bugs.gentoo.org/658572
+---
+ bin/install-qa-check.d/05prefix | 10 +++-------
+ bin/phase-helpers.sh | 12 ++++--------
+ lib/portage/const.py | 1 -
+ 3 files changed, 7 insertions(+), 16 deletions(-)
+
+diff --git a/bin/install-qa-check.d/05prefix b/bin/install-qa-check.d/05prefix
+index 03da3bbce..4f48e4216 100644
+--- a/bin/install-qa-check.d/05prefix
++++ b/bin/install-qa-check.d/05prefix
+@@ -36,16 +36,12 @@ install_qa_check_prefix() {
+ local WHITELIST=" /usr/bin/env "
+ # shebang can be an absolutised path, bug #342929
+ local eprefix=$(canonicalize ${EPREFIX})
+- # Without the stacked-prefix feature, tests using BPREFIX
+- # are redundant to EPREFIX, but run only if we will fail.
++ # Without USE=prefix-stack, tests using BPREFIX are
++ # redundant to EPREFIX, but run only if we will fail.
+ # Otherways, BPREFIX really is BROOT (the EAPI 7 one).
+ local BPREFIX=${EPREFIX}
+ local bprefix=${eprefix}
+- if has stacked-prefix ${FEATURES} &&
+- [[ -z ${ROOT%/} ]] &&
+- [[ ${CBUILD} == ${CHOST} ]] &&
+- [[ ${EPREFIX} != ${BROOT-${PORTAGE_OVERRIDE_EPREFIX}} ]] &&
+- :; then
++ if has prefix-stack ${USE} ; then
+ BPREFIX=${BROOT-${PORTAGE_OVERRIDE_EPREFIX}}
+ bprefix=$(canonicalize ${BPREFIX})
+ fi
+diff --git a/bin/phase-helpers.sh b/bin/phase-helpers.sh
+index 606b1cdfd..c64f1106b 100644
+--- a/bin/phase-helpers.sh
++++ b/bin/phase-helpers.sh
+@@ -932,18 +932,14 @@ ___best_version_and_has_version_common() {
+ fi ;;
+ esac
+
+- # PREFIX LOCAL: stacked-prefix feature
++ # PREFIX LOCAL: prefix-stack feature
+ if ___eapi_has_prefix_variables &&
+ has "${root_arg}" '--host-root' '-b' &&
+- has stacked-prefix ${FEATURES} &&
++ has prefix-stack ${USE} &&
+ [[ -z ${ROOT%/} ]] &&
+- [[ ${CBUILD} == ${CHOST} ]] &&
+- [[ ${EPREFIX} != ${BROOT-${PORTAGE_OVERRIDE_EPREFIX}} ]] &&
+ :; then
+- # When we merge into another EPREFIX, but not into some ROOT,
+- # and CHOST is equal to CBUILD, build tools found in EPREFIX
+- # perfectly work for the current build environment.
+- # In a "stacked prefix" we explicitly utilize this situation.
++ # When we merge into "stacked" EPREFIX, but not into some ROOT, build
++ # tools found in EPREFIX perfectly work for current build environment.
+ "${FUNCNAME[1]}" "${atom}" && return 0
+ fi
+ # END PREFIX LOCAL
+diff --git a/lib/portage/const.py b/lib/portage/const.py
+index eddce377d..db02cbc56 100644
+--- a/lib/portage/const.py
++++ b/lib/portage/const.py
+@@ -207,7 +207,6 @@ SUPPORTED_FEATURES = frozenset([
+ "splitdebug",
+ "split-elog",
+ "split-log",
+- "stacked-prefix", # PREFIX LOCAL
+ "strict",
+ "strict-keepdir",
+ "stricter",
+--
+2.19.2
+
diff --git a/sys-apps/portage/files/portage-2.3.8-prefix-chaining.patch b/sys-apps/portage/files/portage-2.3.8-prefix-chaining.patch
deleted file mode 100644
index 036d022191..0000000000
--- a/sys-apps/portage/files/portage-2.3.8-prefix-chaining.patch
+++ /dev/null
@@ -1,927 +0,0 @@
-From 448d210bb312ed0930763376d5182ebfbed1abd8 Mon Sep 17 00:00:00 2001
-From: Michael Haubenwallner <haubi@gentoo.org>
-Date: Thu, 23 Mar 2017 13:52:32 +0100
-Subject: [PATCH] add prefix-chaining support
-
----
- bin/install-qa-check.d/05prefix | 30 ++++++-
- bin/phase-helpers.sh | 28 ++++++
- pym/_emerge/actions.py | 6 +-
- pym/_emerge/depgraph.py | 51 ++++++-----
- pym/_emerge/resolver/output.py | 40 ++++++++-
- pym/portage/_sets/__init__.py | 5 ++
- pym/portage/const.py | 6 ++
- pym/portage/dbapi/vartree.py | 34 ++++++--
- pym/portage/dep/dep_check.py | 99 +++++++++++++++++++++-
- .../package/ebuild/_config/LocationsManager.py | 3 +
- pym/portage/package/ebuild/config.py | 62 ++++++++++++++
- pym/portage/package/ebuild/doebuild.py | 24 +++++-
- pym/portage/package/ebuild/fetch.py | 4 +
- pym/portage/sync/controller.py | 27 +++---
- pym/portage/util/_dyn_libs/LinkageMapELF.py | 4 +-
- 15 files changed, 376 insertions(+), 47 deletions(-)
-
-diff --git a/bin/install-qa-check.d/05prefix b/bin/install-qa-check.d/05prefix
-index 32561e2..0c11473 100644
---- a/bin/install-qa-check.d/05prefix
-+++ b/bin/install-qa-check.d/05prefix
-@@ -79,16 +79,42 @@ install_qa_check_prefix() {
- # unprefixed shebang, is the script directly in $PATH or an init
- # script?
- if [[ ":${PATH}:${EPREFIX}/etc/init.d:" == *":${fp}:"* ]] ; then
-- if [[ -e ${EROOT}${line[0]} || -e ${ED}${line[0]} ]] ; then
-+ all_epfs="$PORTAGE_READONLY_EPREFIXES:$EPREFIX:$EROOT:$ED"
-+ save_IFS=$IFS
-+ IFS=:
-+ epfs=( $all_epfs )
-+ IFS=$save_IFS
-+
-+ found=
-+ for x in "${epfs[@]}"; do
-+ [[ -z "${x}" ]] && continue
-+ check="${x}${line[0]}"
-+
-+ # might already contain a prefix
-+ if [[ "${line[0]}" == "${x}"* ]]; then
-+ check="${line[0]}"
-+ fi
-+
-+ if [[ -e ${check} ]]; then
-+ found="${check}"
-+ fi
-+ done
-+
-+ if [[ -n ${found} ]] ; then
- # is it unprefixed, but we can just fix it because a
- # prefixed variant exists
- eqawarn "prefixing shebang of ${fn#${D}}"
-+
-+ if [[ ${found} == "${ED}"* || ${found} == "${EROOT}"* ]]; then
-+ found="${EPREFIX}${line[0]}"
-+ fi
-+
- # statement is made idempotent on purpose, because
- # symlinks may point to the same target, and hence the
- # same real file may be sedded multiple times since we
- # read the shebangs in one go upfront for performance
- # reasons
-- sed -i -e '1s:^#! \?'"${line[0]}"':#!'"${EPREFIX}"${line[0]}':' "${rf}"
-+ sed -i -e '1s:^#! \?'"${line[0]}"':#!'"${found}"':' "${rf}"
- continue
- else
- # this is definitely wrong: script in $PATH and invalid shebang
-diff --git a/bin/phase-helpers.sh b/bin/phase-helpers.sh
-index b28fd92..dcfd263 100644
---- a/bin/phase-helpers.sh
-+++ b/bin/phase-helpers.sh
-@@ -867,6 +867,10 @@ has_version() {
- "${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" has_version "${eroot}" "${atom}"
- fi
- local retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ ${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' has_version '${READONLY_EPREFIX%:*}' '${atom}'"
-+ retval=$?
-+ fi
- case "${retval}" in
- 0|1)
- return ${retval}
-@@ -926,6 +930,10 @@ best_version() {
- "${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" best_version "${eroot}" "${atom}"
- fi
- local retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ ${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' best_version '${READONLY_EPREFIX%:*}' '${atom}'"
-+ retval=$?
-+ fi
- case "${retval}" in
- 0|1)
- return ${retval}
-@@ -1166,6 +1174,10 @@ if ___eapi_has_master_repositories; then
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" master_repositories "${EROOT}" "${repository}")
- fi
- retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' master_repositories '${READONLY_EPREFIX%:*}' '${repository}'")
-+ retval=$?
-+ fi
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
- 0|1)
-@@ -1197,6 +1209,10 @@ if ___eapi_has_repository_path; then
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" get_repo_path "${EROOT}" "${repository}")
- fi
- retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' repository_path '${READONLY_EPREFIX%:*}' '${repository}'")
-+ retval=$?
-+ fi
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
- 0|1)
-@@ -1227,6 +1243,10 @@ if ___eapi_has_available_eclasses; then
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" available_eclasses "${EROOT}" "${repository}")
- fi
- retval=$?
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' available_eclasses '${READONLY_EPREFIX%:*}' '${repository}'")
-+ retval=$?
-+ fi
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
- 0|1)
-@@ -1257,6 +1277,10 @@ if ___eapi_has_eclass_path; then
- else
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" eclass_path "${EROOT}" "${repository}" "${eclass}")
- fi
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=$(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' eclass_path '${READONLY_EPREFIX%:*}' '${repository}' '${eclass}'")
-+ retval=$?
-+ fi
- retval=$?
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
-@@ -1288,6 +1312,10 @@ if ___eapi_has_license_path; then
- else
- output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" license_path "${EROOT}" "${repository}" "${license}")
- fi
-+ if [[ ${retval} -eq 1 && -n ${READONLY_EPREFIX} ]]; then
-+ output=(${SHELL} -c "EPREFIX='${READONLY_EPREFIX%:*}' EPYTHON= '${PORTAGE_BIN_PATH}/ebuild-helpers/portageq' license_path '${READONLY_EPREFIX%:*}' '${repository}' '${license}'")
-+ retval=$?
-+ fi
- retval=$?
- [[ -n ${output} ]] && echo "${output}"
- case "${retval}" in
-diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py
-index 1d37d0e..2b185ef 100644
---- a/pym/_emerge/actions.py
-+++ b/pym/_emerge/actions.py
-@@ -39,7 +39,7 @@ from portage import os
- from portage import shutil
- from portage import eapi_is_supported, _encodings, _unicode_decode
- from portage.cache.cache_errors import CacheError
--from portage.const import EPREFIX
-+from portage.const import EPREFIX, BPREFIX
- from portage.const import GLOBAL_CONFIG_PATH, VCS_DIRS, _DEPCLEAN_LIB_CHECK_DEFAULT
- from portage.const import SUPPORTED_BINPKG_FORMATS, TIMESTAMP_FORMAT
- from portage.dbapi.dep_expand import dep_expand
-@@ -65,6 +65,7 @@ from portage.util.SlotObject import SlotObject
- from portage.util._async.run_main_scheduler import run_main_scheduler
- from portage.util._async.SchedulerInterface import SchedulerInterface
- from portage.util._eventloop.global_event_loop import global_event_loop
-+from portage.util._path import exists_raise_eaccess
- from portage._global_updates import _global_updates
- from portage.sync.old_tree_timestamp import old_tree_timestamp_warn
- from portage.localization import _
-@@ -2659,6 +2660,9 @@ def missing_sets_warning(root_config, missing_sets):
- if portage.const.EPREFIX:
- global_config_path = os.path.join(portage.const.EPREFIX,
- portage.const.GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(global_config_path) and portage.const.BPREFIX:
-+ global_config_path = os.path.join(portage.const.BPREFIX,
-+ portage.const.GLOBAL_CONFIG_PATH.lstrip(os.sep))
- msg.append(" This usually means that '%s'" % \
- (os.path.join(global_config_path, "sets/portage.conf"),))
- msg.append(" is missing or corrupt.")
-diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
-index 76f1370..8f681d6 100644
---- a/pym/_emerge/depgraph.py
-+++ b/pym/_emerge/depgraph.py
-@@ -3180,23 +3180,24 @@ class depgraph(object):
- edepend["HDEPEND"] = ""
-
- deps = (
-- (depend_root, edepend["DEPEND"],
-+ (depend_root, "DEPEND",
- self._priority(buildtime=True,
- optional=(pkg.built or ignore_depend_deps),
- ignored=ignore_depend_deps)),
-- (self._frozen_config._running_root.root, edepend["HDEPEND"],
-+ (self._frozen_config._running_root.root, "HDEPEND",
- self._priority(buildtime=True,
- optional=(pkg.built or ignore_hdepend_deps),
- ignored=ignore_hdepend_deps)),
-- (myroot, edepend["RDEPEND"],
-+ (myroot, "RDEPEND",
- self._priority(runtime=True)),
-- (myroot, edepend["PDEPEND"],
-+ (myroot, "PDEPEND",
- self._priority(runtime_post=True))
- )
-
- debug = "--debug" in self._frozen_config.myopts
-
-- for dep_root, dep_string, dep_priority in deps:
-+ for dep_root, dep_type, dep_priority in deps:
-+ dep_string = edepend[dep_type]
- if not dep_string:
- continue
- if debug:
-@@ -3234,7 +3235,7 @@ class depgraph(object):
-
- try:
- dep_string = list(self._queue_disjunctive_deps(
-- pkg, dep_root, dep_priority, dep_string))
-+ pkg, dep_root, dep_priority, dep_string, dep_type))
- except portage.exception.InvalidDependString as e:
- if pkg.installed:
- self._dynamic_config._masked_installed.add(pkg)
-@@ -3249,14 +3250,14 @@ class depgraph(object):
-
- if not self._add_pkg_dep_string(
- pkg, dep_root, dep_priority, dep_string,
-- allow_unsatisfied):
-+ allow_unsatisfied, dep_type):
- return 0
-
- self._dynamic_config._traversed_pkg_deps.add(pkg)
- return 1
-
- def _add_pkg_dep_string(self, pkg, dep_root, dep_priority, dep_string,
-- allow_unsatisfied):
-+ allow_unsatisfied, dep_type=None):
- _autounmask_backup = self._dynamic_config._autounmask
- if dep_priority.optional or dep_priority.ignored:
- # Temporarily disable autounmask for deps that
-@@ -3265,7 +3266,7 @@ class depgraph(object):
- try:
- return self._wrapped_add_pkg_dep_string(
- pkg, dep_root, dep_priority, dep_string,
-- allow_unsatisfied)
-+ allow_unsatisfied, dep_type)
- finally:
- self._dynamic_config._autounmask = _autounmask_backup
-
-@@ -3301,7 +3302,7 @@ class depgraph(object):
- not slot_operator_rebuild
-
- def _wrapped_add_pkg_dep_string(self, pkg, dep_root, dep_priority,
-- dep_string, allow_unsatisfied):
-+ dep_string, allow_unsatisfied, dep_type=None):
- if isinstance(pkg.depth, int):
- depth = pkg.depth + 1
- else:
-@@ -3325,7 +3326,7 @@ class depgraph(object):
- try:
- selected_atoms = self._select_atoms(dep_root,
- dep_string, myuse=self._pkg_use_enabled(pkg), parent=pkg,
-- strict=strict, priority=dep_priority)
-+ strict=strict, priority=dep_priority, dep_type=dep_type)
- except portage.exception.InvalidDependString:
- if pkg.installed:
- self._dynamic_config._masked_installed.add(pkg)
-@@ -3623,7 +3624,7 @@ class depgraph(object):
- child_pkgs.sort()
- yield (atom, child_pkgs[-1])
-
-- def _queue_disjunctive_deps(self, pkg, dep_root, dep_priority, dep_struct):
-+ def _queue_disjunctive_deps(self, pkg, dep_root, dep_priority, dep_struct, dep_type=None):
- """
- Queue disjunctive (virtual and ||) deps in self._dynamic_config._dep_disjunctive_stack.
- Yields non-disjunctive deps. Raises InvalidDependString when
-@@ -3632,33 +3633,33 @@ class depgraph(object):
- for x in dep_struct:
- if isinstance(x, list):
- if x and x[0] == "||":
-- self._queue_disjunction(pkg, dep_root, dep_priority, [x])
-+ self._queue_disjunction(pkg, dep_root, dep_priority, [x], dep_type)
- else:
- for y in self._queue_disjunctive_deps(
-- pkg, dep_root, dep_priority, x):
-+ pkg, dep_root, dep_priority, x, dep_type):
- yield y
- else:
- # Note: Eventually this will check for PROPERTIES=virtual
- # or whatever other metadata gets implemented for this
- # purpose.
- if x.cp.startswith('virtual/'):
-- self._queue_disjunction(pkg, dep_root, dep_priority, [x])
-+ self._queue_disjunction(pkg, dep_root, dep_priority, [x], dep_type)
- else:
- yield x
-
-- def _queue_disjunction(self, pkg, dep_root, dep_priority, dep_struct):
-+ def _queue_disjunction(self, pkg, dep_root, dep_priority, dep_struct, dep_type=None):
- self._dynamic_config._dep_disjunctive_stack.append(
-- (pkg, dep_root, dep_priority, dep_struct))
-+ (pkg, dep_root, dep_priority, dep_struct, dep_type))
-
- def _pop_disjunction(self, allow_unsatisfied):
- """
- Pop one disjunctive dep from self._dynamic_config._dep_disjunctive_stack, and use it to
- populate self._dynamic_config._dep_stack.
- """
-- pkg, dep_root, dep_priority, dep_struct = \
-+ pkg, dep_root, dep_priority, dep_struct, dep_type = \
- self._dynamic_config._dep_disjunctive_stack.pop()
- if not self._add_pkg_dep_string(
-- pkg, dep_root, dep_priority, dep_struct, allow_unsatisfied):
-+ pkg, dep_root, dep_priority, dep_struct, allow_unsatisfied, dep_type):
- return 0
- return 1
-
-@@ -4511,7 +4512,7 @@ class depgraph(object):
- return self._select_atoms_highest_available(*pargs, **kwargs)
-
- def _select_atoms_highest_available(self, root, depstring,
-- myuse=None, parent=None, strict=True, trees=None, priority=None):
-+ myuse=None, parent=None, strict=True, trees=None, priority=None, dep_type=None):
- """This will raise InvalidDependString if necessary. If trees is
- None then self._dynamic_config._filtered_trees is used."""
-
-@@ -4534,6 +4535,13 @@ class depgraph(object):
- pkgsettings = self._frozen_config.pkgsettings[root]
- if trees is None:
- trees = self._dynamic_config._filtered_trees
-+
-+ # this one is needed to guarantee good readonly root
-+ # resolution display in the merge list. required since
-+ # parent (below) can be None
-+ trees[root]["disp_parent"] = parent
-+
-+
- mytrees = trees[root]
- atom_graph = digraph()
- if True:
-@@ -4565,7 +4573,7 @@ class depgraph(object):
-
- mycheck = portage.dep_check(depstring, None,
- pkgsettings, myuse=myuse,
-- myroot=root, trees=trees)
-+ myroot=root, trees=trees, dep_type=dep_type)
- finally:
- # restore state
- self._dynamic_config._autounmask = _autounmask_backup
-@@ -4641,6 +4649,7 @@ class depgraph(object):
- continue
- node_stack.append((child_node, node, child_atom))
-
-+ trees[root].pop("disp_parent")
- return selected_atoms
-
- def _expand_virt_from_graph(self, root, atom):
-diff --git a/pym/_emerge/resolver/output.py b/pym/_emerge/resolver/output.py
-index e993ce1..32a942c 100644
---- a/pym/_emerge/resolver/output.py
-+++ b/pym/_emerge/resolver/output.py
-@@ -22,11 +22,12 @@ from portage.localization import localized_size
- from portage.package.ebuild.config import _get_feature_flags
- from portage.package.ebuild._spawn_nofetch import spawn_nofetch
- from portage.output import ( blue, colorize, create_color_func,
-- darkblue, darkgreen, green, nc_len, teal)
-+ darkblue, darkgreen, green, nc_len, teal, yellow, turquoise)
- bad = create_color_func("BAD")
- from portage._sets.base import InternalPackageSet
- from portage.util import writemsg_stdout
- from portage.versions import best, cpv_getversion
-+from portage.dep.dep_check import ro_selected
-
- from _emerge.Blocker import Blocker
- from _emerge.create_world_atom import create_world_atom
-@@ -563,6 +564,42 @@ class Display(object):
- writemsg_stdout("%s\n" % (pkg,), noiselevel=-1)
- return
-
-+ def print_readonly_prefix(self):
-+ """Performs the actual output printing for the readonly prefix
-+ information stuff
-+ """
-+ out = sys.stdout
-+
-+ # print readonly selected packages
-+ if len(ro_selected) > 0:
-+ out.write("\n%s\n\n" % (darkgreen("Packages resolved from readonly installations:")))
-+
-+ ro_mismatch_warning = False
-+ ro_dupcheck = []
-+ for x in ro_selected:
-+ tmp_type = x["type"].replace("END","")
-+ while len(tmp_type) < 4:
-+ tmp_type += " "
-+ if x["parent"] and str(x["atom"]) not in ro_dupcheck:
-+ out.write("[%s %s] %s %s %s (%s by %s)" % (teal("readonly"),
-+ green(tmp_type), green(str(x["matches"][0])), yellow("from"),
-+ blue(x["ro_root"]), turquoise(str(x["atom"])), green(x["parent"].cpv)))
-+
-+ ro_dupcheck.append(str(x["atom"]))
-+
-+ if x["host_mismatch"]:
-+ ro_mismatch_warning = True
-+ out.write(" %s\n" % (red("**")))
-+ else:
-+ out.write("\n")
-+
-+ if ro_mismatch_warning:
-+ out.write("\n%s:" % (red("**")))
-+ out.write(yellow(" WARNING: packages marked with ** have been resolved as a\n"))
-+ out.write(yellow(" runtime dependency, but the CHOST variable for the parent\n"))
-+ out.write(yellow(" and dependency package don't match. This could cause link\n"))
-+ out.write(yellow(" errors. It is recommended to use RDEPEND READONLY_EPREFIX's\n"))
-+ out.write(yellow(" only with matching CHOST portage instances.\n"))
-
- def print_verbose(self, show_repos):
- """Prints the verbose output to std_out
-@@ -913,6 +950,7 @@ class Display(object):
- show_repos = self.quiet_repo_display and repoadd_set and repoadd_set != set(["0"])
-
- # now finally print out the messages
-+ self.print_readonly_prefix()
- self.print_messages(show_repos)
- self.print_blockers()
- if self.conf.verbosity == 3:
-diff --git a/pym/portage/_sets/__init__.py b/pym/portage/_sets/__init__.py
-index 2c9bf97..6a27842 100644
---- a/pym/portage/_sets/__init__.py
-+++ b/pym/portage/_sets/__init__.py
-@@ -21,6 +21,7 @@ from portage.const import _ENABLE_SET_CONFIG
- from portage.exception import PackageSetNotFound
- from portage.localization import _
- from portage.util import writemsg_level
-+from portage.util._path import exists_raise_eaccess
- from portage.util.configparser import (SafeConfigParser,
- NoOptionError, ParsingError, read_configs)
-
-@@ -281,6 +282,10 @@ def load_default_config(settings, trees):
- if portage.const.EPREFIX:
- global_config_path = os.path.join(portage.const.EPREFIX,
- GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(global_config_path) and portage.const.BPREFIX:
-+ global_config_path = os.path.join(portage.const.BPREFIX,
-+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+
- vcs_dirs = [_unicode_encode(x, encoding=_encodings['fs']) for x in VCS_DIRS]
- def _getfiles():
- for path, dirs, files in os.walk(os.path.join(global_config_path, "sets")):
-diff --git a/pym/portage/const.py b/pym/portage/const.py
-index a0ad1f9..4f14bc8 100644
---- a/pym/portage/const.py
-+++ b/pym/portage/const.py
-@@ -189,6 +189,7 @@ SUPPORTED_FEATURES = frozenset([
- "notitles",
- "parallel-fetch",
- "parallel-install",
-+ "prefix-chaining",
- "prelink-checksums",
- "preserve-libs",
- "protect-owned",
-@@ -266,6 +267,11 @@ MANIFEST2_IDENTIFIERS = ("AUX", "MISC", "DIST", "EBUILD")
- #EPREFIX = ""
- # END PREFIX LOCAL
-
-+BPREFIX = EPREFIX
-+
-+# --prefix commandline arg always rules, ends up in os.environ["EPREFIX"]
-+if "EPREFIX" in os.environ:
-+ os.environ["PORTAGE_OVERRIDE_EPREFIX"] = os.environ["EPREFIX"]
- # pick up EPREFIX from the environment if set
- if "PORTAGE_OVERRIDE_EPREFIX" in os.environ:
- EPREFIX = os.environ["PORTAGE_OVERRIDE_EPREFIX"]
-diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
-index 0006bc5..2ea5f16 100644
---- a/pym/portage/dbapi/vartree.py
-+++ b/pym/portage/dbapi/vartree.py
-@@ -194,8 +194,19 @@ class vardbapi(dbapi):
- self._counter_path = os.path.join(self._eroot,
- CACHE_PATH, "counter")
-
-- self._plib_registry = PreservedLibsRegistry(settings["ROOT"],
-- os.path.join(self._eroot, PRIVATE_PATH, "preserved_libs_registry"))
-+ plibreg_path = os.path.join(self._eroot, PRIVATE_PATH, "preserved_libs_registry")
-+
-+ if vartree:
-+ self._kill_eprefix = vartree._kill_eprefix
-+ else:
-+ self._kill_eprefix = False
-+
-+ if self._kill_eprefix:
-+ self._aux_cache_filename = self._aux_cache_filename.replace(EPREFIX, "")
-+ self._counter_path = self._counter_path.replace(EPREFIX, "")
-+ plibreg_path = plibreg_path.replace(EPREFIX, "")
-+
-+ self._plib_registry = PreservedLibsRegistry(settings["ROOT"], plibreg_path)
- self._linkmap = LinkageMap(self)
- chost = self.settings.get('CHOST')
- if not chost:
-@@ -236,6 +247,9 @@ class vardbapi(dbapi):
- # This is an optimized hotspot, so don't use unicode-wrapped
- # os module and don't use os.path.join().
- rValue = self._eroot + VDB_PATH + _os.sep + mykey
-+ if self._kill_eprefix:
-+ rValue = rValue.replace(EPREFIX, "")
-+
- if filename is not None:
- # If filename is always relative, we can do just
- # rValue += _os.sep + filename
-@@ -499,6 +513,9 @@ class vardbapi(dbapi):
- returnme = []
- basepath = os.path.join(self._eroot, VDB_PATH) + os.path.sep
-
-+ if self._kill_eprefix:
-+ basepath = os.path.join(self.root, basepath.replace(EPREFIX, ""))
-+
- if use_cache:
- from portage import listdir
- else:
-@@ -595,11 +612,17 @@ class vardbapi(dbapi):
- del self.matchcache[mycat]
- return list(self._iter_match(mydep,
- self.cp_list(mydep.cp, use_cache=use_cache)))
-+
-+ _tmp_path = os.path.join(self._eroot, VDB_PATH, mycat)
-+
-+ if self._kill_eprefix:
-+ _tmp_path = _tmp_path.replace(EPREFIX, "")
-+
- try:
- if sys.hexversion >= 0x3030000:
-- curmtime = os.stat(os.path.join(self._eroot, VDB_PATH, mycat)).st_mtime_ns
-+ curmtime = os.stat(_tmp_path).st_mtime_ns
- else:
-- curmtime = os.stat(os.path.join(self._eroot, VDB_PATH, mycat)).st_mtime
-+ curmtime = os.stat(_tmp_path).st_mtime
- except (IOError, OSError):
- curmtime=0
-
-@@ -1410,7 +1433,7 @@ class vardbapi(dbapi):
- class vartree(object):
- "this tree will scan a var/db/pkg database located at root (passed to init)"
- def __init__(self, root=None, virtual=DeprecationWarning, categories=None,
-- settings=None):
-+ settings=None, kill_eprefix=None):
-
- if settings is None:
- settings = portage.settings
-@@ -1428,6 +1451,7 @@ class vartree(object):
- " constructor is unused",
- DeprecationWarning, stacklevel=2)
-
-+ self._kill_eprefix = kill_eprefix
- self.settings = settings
- self.dbapi = vardbapi(settings=settings, vartree=self)
- self.populated = 1
-diff --git a/pym/portage/dep/dep_check.py b/pym/portage/dep/dep_check.py
-index 35caecc..f0dca8a 100644
---- a/pym/portage/dep/dep_check.py
-+++ b/pym/portage/dep/dep_check.py
-@@ -255,6 +255,95 @@ class _dep_choice(SlotObject):
- __slots__ = ('atoms', 'slot_map', 'cp_map', 'all_available',
- 'all_installed_slots')
-
-+ro_trees={}
-+ro_vartrees={}
-+ro_selected=[]
-+
-+def dep_match_readonly_roots(settings, atom, dep_type, parent=None):
-+ if len(ro_trees) < len(settings.readonly_prefixes):
-+ # MDUFT: create additional vartrees for every readonly root here.
-+ # the ro_vartrees instances are created below as they are needed to
-+ # avoid reading vartrees of portage instances which aren't required
-+ # while resolving this dependencies.
-+ for type in ("DEPEND","RDEPEND", "PDEPEND"):
-+ ro_trees[type] = []
-+
-+ for ro_root, ro_dep_types in settings.readonly_prefixes.items():
-+ if type in ro_dep_types:
-+ ro_trees[type].append(ro_root)
-+
-+ if len(ro_trees) == 0:
-+ return []
-+
-+ matches = []
-+
-+ for ro_root in ro_trees[dep_type]:
-+ if not ro_root in ro_vartrees:
-+ # target_root=ro_root ok? or should it be the real target_root?
-+ _tmp_settings = portage.config(config_root=ro_root, target_root=ro_root,
-+ config_incrementals=portage.const.INCREMENTALS)
-+
-+ ro_vartrees[ro_root] = portage.vartree(root=ro_root,
-+ categories=_tmp_settings.categories,
-+ settings=_tmp_settings, kill_eprefix=True)
-+
-+ ro_matches = ro_vartrees[ro_root].dbapi.match(atom)
-+
-+ if ro_matches:
-+ ro_host_mismatch = False
-+ if dep_type is "RDEPEND":
-+ # we need to assure binary compatability, so it needs to be
-+ # the same CHOST! But how? for now i cannot do anything...
-+ if parent and parent.metadata["CHOST"] != ro_vartrees[ro_root].settings.get("CHOST", ""):
-+ # provocate a big fat warning in the list of external packages.
-+ ro_host_mismatch = True
-+ pass
-+
-+ matches.append({ "ro_root": ro_root, "atom": atom, "matches": ro_matches,
-+ "type": dep_type, "parent": parent, "host_mismatch": ro_host_mismatch })
-+
-+ return matches
-+
-+def dep_wordreduce_readonly(reduced, unreduced, settings, dep_type, parent):
-+ for mypos, token in enumerate(unreduced):
-+ # recurse if it's a list.
-+ if isinstance(reduced[mypos], list):
-+ reduced[mypos] = dep_wordreduce_readonly(reduced[mypos],
-+ unreduced[mypos], settings, dep_type, parent)
-+
-+ # do nothing if it's satisfied already.
-+ elif not reduced[mypos]:
-+ ro_matches = dep_match_readonly_roots(settings, unreduced[mypos], dep_type, parent)
-+
-+ if ro_matches:
-+ # TODO: select a match if there are more than one?
-+ # for now, the first match is taken...
-+ ro_selected.append(ro_matches[0])
-+ reduced[mypos] = True
-+
-+ return reduced
-+
-+# this may be better placed somewhere else, but i put it here for now, to
-+# keep all functions in the patch on one big heap.
-+def readonly_pathmatch_any(settings, path):
-+ path = path.lstrip('/')
-+ # first try locally, and match that if it exists.
-+ if os.path.exists(os.path.join(EPREFIX,path)):
-+ return os.path.join(EPREFIX,path)
-+
-+ # after that try all readonly roots where DEPEND is allowed. this makes
-+ # sure that executing binaries is possible from there.
-+ for ro_root, ro_deps in settings.readonly_roots.items():
-+ if "DEPEND" in ro_deps:
-+ print(" --- checking %s --- " % (os.path.join(ro_root,path)))
-+ if os.path.exists(os.path.join(ro_root,path)):
-+ return os.path.join(ro_root,path)
-+ break
-+
-+ # as a fallback make the string the same as it was originally.
-+ # even though this path doesn't exist.
-+ return os.path.join(EPREFIX,path)
-+
- def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None):
- """
- Takes an unreduced and reduced deplist and removes satisfied dependencies.
-@@ -643,7 +732,7 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None):
- assert(False) # This point should not be reachable
-
- def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None,
-- use_cache=1, use_binaries=0, myroot=None, trees=None):
-+ use_cache=1, use_binaries=0, myroot=None, trees=None, dep_type=None):
- """
- Takes a depend string, parses it, and selects atoms.
- The myroot parameter is unused (use mysettings['EROOT'] instead).
-@@ -741,6 +830,14 @@ def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None,
- writemsg("mysplit: %s\n" % (mysplit), 1)
- writemsg("mysplit2: %s\n" % (mysplit2), 1)
-
-+ if dep_type is not None:
-+ mysplit2=dep_wordreduce_readonly(unreduced=mysplit[:],
-+ reduced=mysplit2, settings=mysettings,
-+ dep_type=dep_type, parent=trees[myroot].get("disp_parent"))
-+
-+ writemsg("\n", 1)
-+ writemsg("mysplit2 after readonly reduce: %s\n" % (mysplit2), 1)
-+
- selected_atoms = dep_zapdeps(mysplit, mysplit2, myroot,
- use_binaries=use_binaries, trees=trees)
-
-diff --git a/pym/portage/package/ebuild/_config/LocationsManager.py b/pym/portage/package/ebuild/_config/LocationsManager.py
-index 55b8c08..32e969e 100644
---- a/pym/portage/package/ebuild/_config/LocationsManager.py
-+++ b/pym/portage/package/ebuild/_config/LocationsManager.py
-@@ -307,6 +307,9 @@ class LocationsManager(object):
- if portage.const.EPREFIX:
- self.global_config_path = os.path.join(portage.const.EPREFIX,
- GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(self.global_config_path) and portage.const.BPREFIX:
-+ self.global_config_path = os.path.join(portage.const.BPREFIX,
-+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
-
- def set_port_dirs(self, portdir, portdir_overlay):
- self.portdir = portdir
-diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py
-index b5fb42e..8cac700 100644
---- a/pym/portage/package/ebuild/config.py
-+++ b/pym/portage/package/ebuild/config.py
-@@ -306,6 +306,7 @@ class config(object):
- self.features = features_set(self)
- self.features._features = copy.deepcopy(clone.features._features)
- self._features_overrides = copy.deepcopy(clone._features_overrides)
-+ self.readonly_prefixes = copy.deepcopy(clone.readonly_prefixes)
-
- #Strictly speaking _license_manager is not immutable. Users need to ensure that
- #extract_global_changes() is called right after __init__ (if at all).
-@@ -945,6 +946,63 @@ class config(object):
-
- self._validate_commands()
-
-+ # expand READONLY_EPREFIX to a list of all readonly portage instances
-+ # all the way down to the last one. beware that ATM a deeper instance
-+ # in the chain can provide more than the toplevel! this means that
-+ # if you only inherit DEPENDS from one instance, that instance may
-+ # inherit RDEPENDs from another one, making the top-level instance
-+ # inherit RDEPENDs from there too - even if the intermediate prefix
-+ # does not do this.
-+ self.readonly_prefixes = {}
-+ ro_cfg_root = config_root
-+ ro_widest_depset = set(['DEPEND', 'RDEPEND', 'PDEPEND'])
-+
-+ while ro_cfg_root:
-+ ro_make_conf_paths = [
-+ os.path.join(ro_cfg_root, 'etc', 'make.conf'),
-+ os.path.join(ro_cfg_root, MAKE_CONF_FILE)
-+ ]
-+ try:
-+ if os.path.samefile(*ro_make_conf_paths):
-+ ro_make_conf_paths.pop()
-+ except OSError:
-+ pass
-+
-+ ro_cfg_root = None
-+ for ro_make_conf in ro_make_conf_paths:
-+ if not os.path.exists(ro_make_conf):
-+ continue
-+
-+ ro_cfg = getconfig(ro_make_conf, tolerant=True, allow_sourcing=True)
-+ if not "READONLY_EPREFIX" in ro_cfg:
-+ continue
-+
-+ if not ro_cfg["READONLY_EPREFIX"].find(":"):
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: malformed READONLY_EPREFIX in %s" % (ro_make_conf))
-+
-+ if ro_cfg_root is not None:
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: duplicate READONLY_EPREFIX in %s and %s" % tuple(ro_make_conf_paths))
-+
-+ (ro_cfg_root,ro_cfg_root_deps) = ro_cfg["READONLY_EPREFIX"].rsplit(":",1)
-+
-+ if not os.path.exists(ro_cfg_root):
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: malformed READONLY_EPREFIX in %s: %s does not exist!" % (ro_make_conf, ro_cfg_root))
-+
-+ if os.path.samefile(ro_cfg_root, config_root):
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: cannot add this instance (%s) as READONLY_EPREFIX in %s." % (ro_cfg_root, ro_make_conf))
-+
-+ if ro_cfg_root in self.readonly_prefixes:
-+ raise portage.exception.InvalidReadonlyERoot("ERROR: circular READONLY_EPREFIX's in %s. %s already checked for %s" % (ro_make_conf, ro_cfg_root, self.readonly_prefixes[ro_cfg_root]))
-+
-+ # intersect the widest depset with the current one to strip down
-+ # the allowed dependency resolution to not be wider than the
-+ # next higher one. this way we can prevent for a given prefix
-+ # to resolve RDEPENDs from a prefix with a different CHOST that
-+ # is a few levels deeper in the chain.
-+ ro_widest_depset = set(ro_cfg_root_deps.split(",")) & ro_widest_depset
-+ self.readonly_prefixes[ro_cfg_root] = ro_widest_depset
-+ pass
-+
- for k in self._case_insensitive_vars:
- if k in self:
- self[k] = self[k].lower()
-@@ -2805,6 +2863,10 @@ class config(object):
- if not eapi_exports_merge_type(eapi):
- mydict.pop("MERGE_TYPE", None)
-
-+ # populate with PORTAGE_READONLY_EPREFIXES
-+ if self.readonly_prefixes and len(self.readonly_prefixes) > 0:
-+ mydict["PORTAGE_READONLY_EPREFIXES"] = ':'.join(self.readonly_prefixes)
-+
- # Prefix variables are supported beginning with EAPI 3, or when
- # force-prefix is in FEATURES, since older EAPIs would otherwise be
- # useless with prefix configurations. This brings compatibility with
-diff --git a/pym/portage/package/ebuild/doebuild.py b/pym/portage/package/ebuild/doebuild.py
-index c6d6133..f914091 100644
---- a/pym/portage/package/ebuild/doebuild.py
-+++ b/pym/portage/package/ebuild/doebuild.py
-@@ -51,6 +51,7 @@ from portage import bsd_chflags, \
- unmerge, _encodings, _os_merge, \
- _shell_quote, _unicode_decode, _unicode_encode
- from portage.const import EBUILD_SH_ENV_FILE, EBUILD_SH_ENV_DIR, \
-+ GLOBAL_CONFIG_PATH, \
- EBUILD_SH_BINARY, INVALID_ENV_FILE, MISC_SH_BINARY, PORTAGE_PYM_PACKAGES, EPREFIX, MACOSSANDBOX_PROFILE
- from portage.data import portage_gid, portage_uid, secpass, \
- uid, userpriv_groups
-@@ -72,6 +73,7 @@ from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
- from portage.process import find_binary
- from portage.util import ( apply_recursive_permissions,
- apply_secpass_permissions,
-+ getconfig,
- noiselimit,
- shlex_split,
- varexpand,
-@@ -79,6 +81,7 @@ from portage.util import ( apply_recursive_permissions,
- writemsg_stdout,
- write_atomic
- )
-+from portage.util._path import exists_raise_eaccess
- from portage.util.cpuinfo import get_cpu_count
- from portage.util.lafilefixer import rewrite_lafile
- from portage.util.compression_probe import _compressors
-@@ -241,8 +244,27 @@ def _doebuild_path(settings, eapi=None):
-
- for x in portage_bin_path:
- path.append(os.path.join(x, "ebuild-helpers"))
-+
-+ # PREFIX CHAINING: append default path for all prefixes involved
-+ pfxs = [ eprefix ]
-+ pfxs.extend(settings.readonly_prefixes)
-+ for prefix in pfxs:
-+ global_config_path = os.path.join(prefix, GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ make_globals_path = os.path.join(global_config_path, "make.globals")
-+ if exists_raise_eaccess(make_globals_path):
-+ expand_map = { "EPREFIX": prefix }
-+ pxcfg = getconfig(make_globals_path, True, expand_map)
-+ pxdefp = [x for x in pxcfg.get("DEFAULT_PATH", "").split(":") if x]
-+ for x in pxdefp:
-+ if x.startswith(prefix) and not x in path:
-+ path.append(x)
-+ else:
-+ pxdefs = [prefix + "/usr/sbin", prefix + "/usr/bin", prefix + "/sbin", prefix + "/bin"]
-+ path.extend(pxdefs)
-+ # END PREFIX CHAINING
-+
- path.extend(prerootpath)
-- path.extend(defaultpath)
-+ # path.extend(defaultpath) # PREFIX CHAINING appends the default path for involved prefixes above
- path.extend(rootpath)
- path.extend(extrapath)
- # END PREFIX LOCAL
-diff --git a/pym/portage/package/ebuild/fetch.py b/pym/portage/package/ebuild/fetch.py
-index 265d0c9..2ec6ff4 100644
---- a/pym/portage/package/ebuild/fetch.py
-+++ b/pym/portage/package/ebuild/fetch.py
-@@ -43,6 +43,7 @@ from portage.output import colorize, EOutput
- from portage.util import apply_recursive_permissions, \
- apply_secpass_permissions, ensure_dirs, grabdict, shlex_split, \
- varexpand, writemsg, writemsg_level, writemsg_stdout
-+from portage.util._path import exists_raise_eaccess
- from portage.process import spawn
-
- _userpriv_spawn_kwargs = (
-@@ -874,6 +875,9 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0,
- global_config_path = GLOBAL_CONFIG_PATH
- if portage.const.EPREFIX:
- global_config_path = os.path.join(portage.const.EPREFIX,
-+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
-+ if not exists_raise_eaccess(global_config_path) and portage.const.BPREFIX:
-+ global_config_path = os.path.join(portage.const.BPREFIX,
- GLOBAL_CONFIG_PATH.lstrip(os.sep))
-
- missing_file_param = False
-diff --git a/pym/portage/sync/controller.py b/pym/portage/sync/controller.py
-index 3bccf6f..cacd637 100644
---- a/pym/portage/sync/controller.py
-+++ b/pym/portage/sync/controller.py
-@@ -94,19 +94,20 @@ class SyncManager(object):
- self.module_controller = portage.sync.module_controller
- self.module_names = self.module_controller.module_names
- self.hooks = {}
-- for _dir in ["repo.postsync.d", "postsync.d"]:
-- postsync_dir = os.path.join(self.settings["PORTAGE_CONFIGROOT"],
-- portage.USER_CONFIG_PATH, _dir)
-- hooks = OrderedDict()
-- for filepath in util._recursive_file_list(postsync_dir):
-- name = filepath.split(postsync_dir)[1].lstrip(os.sep)
-- if os.access(filepath, os.X_OK):
-- hooks[filepath] = name
-- else:
-- writemsg_level(" %s %s hook: '%s' is not executable\n"
-- % (warn("*"), _dir, _unicode_decode(name),),
-- level=logging.WARN, noiselevel=2)
-- self.hooks[_dir] = hooks
-+ for _confroot in [self.settings["PORTAGE_CONFIGROOT"], portage.const.BPREFIX]:
-+ for _dir in ["repo.postsync.d", "postsync.d"]:
-+ postsync_dir = os.path.join(_confroot,
-+ portage.USER_CONFIG_PATH, _dir)
-+ hooks = OrderedDict()
-+ for filepath in util._recursive_file_list(postsync_dir):
-+ name = filepath.split(postsync_dir)[1].lstrip(os.sep)
-+ if os.access(filepath, os.X_OK):
-+ hooks[filepath] = name
-+ else:
-+ writemsg_level(" %s %s hook: '%s' is not executable\n"
-+ % (warn("*"), _dir, _unicode_decode(name),),
-+ level=logging.WARN, noiselevel=2)
-+ self.hooks[_dir] = hooks
-
- def __getattr__(self, name):
- if name == 'async':
-diff --git a/pym/portage/util/_dyn_libs/LinkageMapELF.py b/pym/portage/util/_dyn_libs/LinkageMapELF.py
-index a063621..968fbd3 100644
---- a/pym/portage/util/_dyn_libs/LinkageMapELF.py
-+++ b/pym/portage/util/_dyn_libs/LinkageMapELF.py
-@@ -12,7 +12,7 @@ from portage import _os_merge
- from portage import _unicode_decode
- from portage import _unicode_encode
- from portage.cache.mappings import slot_dict_class
--from portage.const import EPREFIX
-+from portage.const import BPREFIX
- from portage.dep.soname.multilib_category import compute_multilib_category
- from portage.exception import CommandNotFound, InvalidData
- from portage.localization import _
-@@ -268,7 +268,7 @@ class LinkageMapELF(object):
- continue
- plibs.update((x, cpv) for x in items)
- if plibs:
-- args = [os.path.join(EPREFIX or "/", "usr/bin/scanelf"), "-qF", "%a;%F;%S;%r;%n"]
-+ args = [os.path.join(BPREFIX or "/", "usr/bin/scanelf"), "-qF", "%a;%F;%S;%r;%n"]
- args.extend(os.path.join(root, x.lstrip("." + os.sep)) \
- for x in plibs)
- try:
---
-2.10.2
-
diff --git a/sys-apps/portage/metadata.xml b/sys-apps/portage/metadata.xml
index 1e859c1071..c66241962c 100644
--- a/sys-apps/portage/metadata.xml
+++ b/sys-apps/portage/metadata.xml
@@ -23,6 +23,5 @@
<flag name="xattr">Preserve extended attributes (filesystem-stored metadata)
when installing files. Usually only required for hardened systems.
</flag>
- <flag name="prefix-chaining">mduft's experimental prefix chaining facilities</flag>
</use>
</pkgmetadata>
diff --git a/sys-apps/portage/portage-2.3.52.2.ebuild b/sys-apps/portage/portage-2.3.52.2.ebuild
index 9797e183cd..e2ca476f68 100644
--- a/sys-apps/portage/portage-2.3.52.2.ebuild
+++ b/sys-apps/portage/portage-2.3.52.2.ebuild
@@ -1,4 +1,4 @@
-# Copyright 1999-2018 Gentoo Authors
+# Copyright 1999-2019 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
EAPI=5
@@ -17,7 +17,7 @@ HOMEPAGE="https://wiki.gentoo.org/wiki/Project:Portage"
LICENSE="GPL-2"
KEYWORDS="~ppc-aix ~x64-cygwin ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~m68k-mint ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris"
SLOT="0"
-IUSE="build doc epydoc +ipc +native-extensions selinux xattr prefix-chaining"
+IUSE="build doc epydoc +ipc +native-extensions selinux xattr"
DEPEND="!build? ( $(python_gen_impl_dep 'ssl(+)') )
>=app-arch/tar-1.27
@@ -92,8 +92,6 @@ python_prepare_all() {
distutils-r1_python_prepare_all
epatch "${FILESDIR}"/${PN}-2.3.45-ebuildshell.patch # 155161
- use prefix-chaining && # maybe useful even with stacked-prefix
- epatch "${FILESDIR}"/${PN}-2.3.40-prefix-chaining.patch
if use native-extensions; then
printf "[build_ext]\nportage-ext-modules=true\n" >> \
diff --git a/sys-apps/portage/portage-2.3.55.1.ebuild b/sys-apps/portage/portage-2.3.55.1.ebuild
index 9528084055..e2ca476f68 100644
--- a/sys-apps/portage/portage-2.3.55.1.ebuild
+++ b/sys-apps/portage/portage-2.3.55.1.ebuild
@@ -17,7 +17,7 @@ HOMEPAGE="https://wiki.gentoo.org/wiki/Project:Portage"
LICENSE="GPL-2"
KEYWORDS="~ppc-aix ~x64-cygwin ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~m68k-mint ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris"
SLOT="0"
-IUSE="build doc epydoc +ipc +native-extensions selinux xattr prefix-chaining"
+IUSE="build doc epydoc +ipc +native-extensions selinux xattr"
DEPEND="!build? ( $(python_gen_impl_dep 'ssl(+)') )
>=app-arch/tar-1.27
@@ -92,8 +92,6 @@ python_prepare_all() {
distutils-r1_python_prepare_all
epatch "${FILESDIR}"/${PN}-2.3.45-ebuildshell.patch # 155161
- use prefix-chaining && # maybe useful even with stacked-prefix
- epatch "${FILESDIR}"/${PN}-2.3.40-prefix-chaining.patch
if use native-extensions; then
printf "[build_ext]\nportage-ext-modules=true\n" >> \
diff --git a/sys-apps/portage/portage-2.3.62-r00.1.ebuild b/sys-apps/portage/portage-2.3.62-r00.1.ebuild
new file mode 100644
index 0000000000..8dab4da44e
--- /dev/null
+++ b/sys-apps/portage/portage-2.3.62-r00.1.ebuild
@@ -0,0 +1,271 @@
+# Copyright 1999-2019 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=5
+
+PYTHON_COMPAT=(
+ pypy
+ python3_4 python3_5 python3_6 python3_7
+ python2_7
+)
+PYTHON_REQ_USE='bzip2(+),threads(+)'
+
+inherit eutils distutils-r1 multilib
+
+DESCRIPTION="Portage package manager used in Gentoo Prefix"
+HOMEPAGE="https://wiki.gentoo.org/wiki/Project:Portage"
+LICENSE="GPL-2"
+KEYWORDS="~ppc-aix ~x64-cygwin ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~m68k-mint ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris"
+SLOT="0"
+IUSE="build doc epydoc +ipc +native-extensions selinux xattr"
+
+DEPEND="!build? ( $(python_gen_impl_dep 'ssl(+)') )
+ >=app-arch/tar-1.27
+ dev-lang/python-exec:2
+ >=sys-apps/sed-4.0.5 sys-devel/patch
+ doc? ( app-text/xmlto ~app-text/docbook-xml-dtd-4.4 )
+ epydoc? ( >=dev-python/epydoc-2.0[$(python_gen_usedep 'python2*')] )"
+# Require sandbox-2.2 for bug #288863.
+# For xattr, we can spawn getfattr and setfattr from sys-apps/attr, but that's
+# quite slow, so it's not considered in the dependencies as an alternative to
+# to python-3.3 / pyxattr. Also, xattr support is only tested with Linux, so
+# for now, don't pull in xattr deps for other kernels.
+# For whirlpool hash, require python[ssl] (bug #425046).
+# For compgen, require bash[readline] (bug #445576).
+RDEPEND="
+ >=app-arch/tar-1.27
+ dev-lang/python-exec:2
+ !build? (
+ >=sys-apps/sed-4.0.5
+ app-shells/bash:0[readline]
+ >=app-admin/eselect-1.2
+ $(python_gen_cond_dep 'dev-python/pyblake2[${PYTHON_USEDEP}]' \
+ python{2_7,3_4,3_5} pypy)
+ )
+ elibc_FreeBSD? ( !prefix? ( sys-freebsd/freebsd-bin ) )
+ elibc_glibc? ( !prefix? ( >=sys-apps/sandbox-2.2 ) )
+ elibc_uclibc? ( !prefix? ( >=sys-apps/sandbox-2.2 ) )
+ kernel_linux? ( >=app-misc/pax-utils-0.1.17 )
+ kernel_SunOS? ( >=app-misc/pax-utils-0.1.17 )
+ kernel_FreeBSD? ( >=app-misc/pax-utils-0.1.17 )
+ kernel_Darwin? ( >=app-misc/pax-utils-0.1.18 )
+ kernel_AIX? ( >=sys-apps/aix-miscutils-0.1.1634 )
+ selinux? ( >=sys-libs/libselinux-2.0.94[python,${PYTHON_USEDEP}] )
+ xattr? ( kernel_linux? (
+ >=sys-apps/install-xattr-0.3
+ $(python_gen_cond_dep 'dev-python/pyxattr[${PYTHON_USEDEP}]' \
+ python2_7 pypy)
+ ) )
+ !<app-admin/logrotate-3.8.0"
+PDEPEND="
+ !build? (
+ >=net-misc/rsync-2.6.4
+ userland_GNU? ( >=sys-apps/coreutils-6.4 )
+ )"
+# coreutils-6.4 rdep is for date format in emerge-webrsync #164532
+# NOTE: FEATURES=installsources requires debugedit and rsync
+
+REQUIRED_USE="epydoc? ( $(python_gen_useflags 'python2*') )"
+
+SRC_ARCHIVES="https://dev.gentoo.org/~zmedico/portage/archives https://dev.gentoo.org/~grobian/distfiles"
+
+prefix_src_archives() {
+ local x y
+ for x in ${@}; do
+ for y in ${SRC_ARCHIVES}; do
+ echo ${y}/${x}
+ done
+ done
+}
+
+TARBALL_PV=${PV}
+SRC_URI="mirror://gentoo/prefix-${PN}-${TARBALL_PV}.tar.bz2
+ $(prefix_src_archives prefix-${PN}-${TARBALL_PV}.tar.bz2)"
+
+S="${WORKDIR}"/prefix-${PN}-${TARBALL_PV}
+
+pkg_setup() {
+ use epydoc && DISTUTILS_ALL_SUBPHASE_IMPLS=( python2.7 )
+}
+
+python_prepare_all() {
+ distutils-r1_python_prepare_all
+
+ epatch "${FILESDIR}"/${PN}-2.3.62-prefix-stack.patch # 658572
+ epatch "${FILESDIR}"/${PN}-2.3.45-ebuildshell.patch # 155161
+
+ if use native-extensions; then
+ printf "[build_ext]\nportage-ext-modules=true\n" >> \
+ setup.cfg || die
+ fi
+
+ if ! use ipc ; then
+ einfo "Disabling ipc..."
+ sed -e "s:_enable_ipc_daemon = True:_enable_ipc_daemon = False:" \
+ -i lib/_emerge/AbstractEbuildProcess.py || \
+ die "failed to patch AbstractEbuildProcess.py"
+ fi
+
+ if use xattr && use kernel_linux ; then
+ einfo "Adding FEATURES=xattr to make.globals ..."
+ echo -e '\nFEATURES="${FEATURES} xattr"' >> cnf/make.globals \
+ || die "failed to append to make.globals"
+ fi
+
+ if [[ -n ${EPREFIX} ]] ; then
+ # PREFIX LOCAL: only hack const_autotool
+ local extrapath="/usr/sbin:/usr/bin:/sbin:/bin"
+ # ok, we can't rely on PORTAGE_ROOT_USER being there yet, as people
+ # tend not to update that often, as long as we are a separate ebuild
+ # we can assume when unset, it's time for some older trick
+ if [[ -z ${PORTAGE_ROOT_USER} ]] ; then
+ PORTAGE_ROOT_USER=$(python -c 'from portage.const import rootuser; print rootuser')
+ fi
+ # We need to probe for bash in the Prefix, because it may not
+ # exist, in which case we fall back to the currently in use
+ # bash. This logic is necessary in particular during bootstrap,
+ # where we pull ourselves out of a temporary place with tools
+ local bash="${EPREFIX}/bin/bash"
+ [[ ! -x ${bash} ]] && bash=${BASH}
+
+ einfo "Adjusting sources for ${EPREFIX}"
+ find . -type f -exec \
+ sed -e "s|@PORTAGE_EPREFIX@|${EPREFIX}|" \
+ -e "s|@PORTAGE_MV@|$(type -P mv)|" \
+ -e "s|@PORTAGE_BASH@|${bash}|" \
+ -e "s|@PREFIX_PORTAGE_PYTHON@|$(type -P python)|" \
+ -e "s|@EXTRA_PATH@|${extrapath}|" \
+ -e "s|@portagegroup@|${PORTAGE_GROUP:-portage}|" \
+ -e "s|@portageuser@|${PORTAGE_USER:-portage}|" \
+ -e "s|@rootuser@|${PORTAGE_ROOT_USER:-root}|" \
+ -e "s|@rootuid@|$(id -u ${PORTAGE_ROOT_USER:-root})|" \
+ -e "s|@rootgid@|$(id -g ${PORTAGE_ROOT_USER:-root})|" \
+ -e "s|@sysconfdir@|${EPREFIX}/etc|" \
+ -i '{}' + || \
+ die "Failed to patch sources"
+ # We don't need the below, since setup.py deals with this (and
+ # more) so we don't have to make this correct
+ # -e "s|@PORTAGE_BASE@|${EPREFIX}/usr/lib/portage/${EPYTHON}|" \
+
+ # remove Makefiles, or else they will get installed
+ find . -name "Makefile.*" -delete
+
+ einfo "Prefixing shebangs ..."
+ while read -r -d $'\0' ; do
+ local shebang=$(head -n1 "$REPLY")
+ if [[ ${shebang} == "#!"* && ! ${shebang} == "#!${EPREFIX}/"* ]] ; then
+ sed -i -e "1s:.*:#!${EPREFIX}${shebang:2}:" "$REPLY" || \
+ die "sed failed"
+ fi
+ done < <(find . -type f -print0)
+
+ einfo "Setting gentoo_prefix as reponame for emerge-webrsync"
+ sed -i -e 's/repo_name=gentoo/repo_name=gentoo_prefix/' \
+ bin/emerge-webrsync || die
+
+ einfo "Making absent gemato non-fatal"
+ sed -i -e '/exitcode = 127/d' \
+ lib/portage/sync/modules/rsync/rsync.py || die
+
+ if [[ ${CHOST} == powerpc*-darwin* ]] ; then
+ # asyncio triggers some python bug, not worth fixing on
+ # ppc-macos, bug #656830
+ sed -i -e '/^_asyncio_enabled/s/=.*$/= False/' \
+ lib/portage/util/_eventloop/global_event_loop.py || die
+ fi
+ # END PREFIX LOCAL
+ fi
+
+ # PREFIX LOCAL: make.conf is written by bootstrap-prefix.sh
+ if use !prefix ; then
+ cd "${S}/cnf" || die
+ if [ -f "make.conf.example.${ARCH}".diff ]; then
+ patch make.conf.example "make.conf.example.${ARCH}".diff || \
+ die "Failed to patch make.conf.example"
+ else
+ eerror ""
+ eerror "Portage does not have an arch-specific configuration for this arch."
+ eerror "Please notify the arch maintainer about this issue. Using generic."
+ eerror ""
+ fi
+ fi
+}
+
+python_compile_all() {
+ local targets=()
+ use doc && targets+=( docbook )
+ use epydoc && targets+=( epydoc )
+
+ if [[ ${targets[@]} ]]; then
+ esetup.py "${targets[@]}"
+ fi
+}
+
+python_test() {
+ esetup.py test
+}
+
+python_install() {
+ # Install sbin scripts to bindir for python-exec linking
+ # they will be relocated in pkg_preinst()
+ distutils-r1_python_install \
+ --system-prefix="${EPREFIX}/usr" \
+ --bindir="$(python_get_scriptdir)" \
+ --docdir="${EPREFIX}/usr/share/doc/${PF}" \
+ --htmldir="${EPREFIX}/usr/share/doc/${PF}/html" \
+ --portage-bindir="${EPREFIX}/usr/lib/portage/${EPYTHON}" \
+ --sbindir="$(python_get_scriptdir)" \
+ --sysconfdir="${EPREFIX}/etc" \
+ "${@}"
+}
+
+python_install_all() {
+ distutils-r1_python_install_all
+
+ local targets=()
+ use doc && targets+=(
+ install_docbook
+ --htmldir="${EPREFIX}/usr/share/doc/${PF}/html"
+ )
+ use epydoc && targets+=(
+ install_epydoc
+ --htmldir="${EPREFIX}/usr/share/doc/${PF}/html"
+ )
+
+ # install docs
+ if [[ ${targets[@]} ]]; then
+ esetup.py "${targets[@]}"
+ fi
+
+ # Due to distutils/python-exec limitations
+ # these must be installed to /usr/bin.
+ local sbin_relocations='archive-conf dispatch-conf emaint env-update etc-update fixpackages regenworld'
+ einfo "Moving admin scripts to the correct directory"
+ dodir /usr/sbin
+ for target in ${sbin_relocations}; do
+ einfo "Moving /usr/bin/${target} to /usr/sbin/${target}"
+ mv "${ED}usr/bin/${target}" "${ED}usr/sbin/${target}" || die "sbin scripts move failed!"
+ done
+}
+
+pkg_preinst() {
+ # comment out sanity test until it is fixed to work
+ # with the new PORTAGE_PYM_PATH
+ #if [[ $ROOT == / ]] ; then
+ ## Run some minimal tests as a sanity check.
+ #local test_runner=$(find "${ED}" -name runTests)
+ #if [[ -n $test_runner && -x $test_runner ]] ; then
+ #einfo "Running preinst sanity tests..."
+ #"$test_runner" || die "preinst sanity tests failed"
+ #fi
+ #fi
+
+ # elog dir must exist to avoid logrotate error for bug #415911.
+ # This code runs in preinst in order to bypass the mapping of
+ # portage:portage to root:root which happens after src_install.
+ keepdir /var/log/portage/elog
+ # This is allowed to fail if the user/group are invalid for prefix users.
+ if chown ${PORTAGE_USER}:${PORTAGE_GROUP} "${ED}"var/log/portage{,/elog} 2>/dev/null ; then
+ chmod g+s,ug+rwx "${ED}"var/log/portage{,/elog}
+ fi
+}
diff --git a/sys-apps/portage/portage-2.3.62.ebuild b/sys-apps/portage/portage-2.3.62.ebuild
index 9528084055..e2ca476f68 100644
--- a/sys-apps/portage/portage-2.3.62.ebuild
+++ b/sys-apps/portage/portage-2.3.62.ebuild
@@ -17,7 +17,7 @@ HOMEPAGE="https://wiki.gentoo.org/wiki/Project:Portage"
LICENSE="GPL-2"
KEYWORDS="~ppc-aix ~x64-cygwin ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~m68k-mint ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris"
SLOT="0"
-IUSE="build doc epydoc +ipc +native-extensions selinux xattr prefix-chaining"
+IUSE="build doc epydoc +ipc +native-extensions selinux xattr"
DEPEND="!build? ( $(python_gen_impl_dep 'ssl(+)') )
>=app-arch/tar-1.27
@@ -92,8 +92,6 @@ python_prepare_all() {
distutils-r1_python_prepare_all
epatch "${FILESDIR}"/${PN}-2.3.45-ebuildshell.patch # 155161
- use prefix-chaining && # maybe useful even with stacked-prefix
- epatch "${FILESDIR}"/${PN}-2.3.40-prefix-chaining.patch
if use native-extensions; then
printf "[build_ext]\nportage-ext-modules=true\n" >> \