diff options
-rw-r--r-- | sys-apps/portage/files/portage-2.2.14-prefix-chaining.patch | 873 | ||||
-rw-r--r-- | sys-apps/portage/files/portage-2.3.18-prefix-chaining.patch | 927 | ||||
-rw-r--r-- | sys-apps/portage/files/portage-2.3.40-prefix-chaining.patch | 921 | ||||
-rw-r--r-- | sys-apps/portage/files/portage-2.3.62-prefix-stack.patch | 80 | ||||
-rw-r--r-- | sys-apps/portage/files/portage-2.3.8-prefix-chaining.patch | 927 | ||||
-rw-r--r-- | sys-apps/portage/metadata.xml | 1 | ||||
-rw-r--r-- | sys-apps/portage/portage-2.3.52.2.ebuild | 6 | ||||
-rw-r--r-- | sys-apps/portage/portage-2.3.55.1.ebuild | 4 | ||||
-rw-r--r-- | sys-apps/portage/portage-2.3.62-r00.1.ebuild | 271 | ||||
-rw-r--r-- | sys-apps/portage/portage-2.3.62.ebuild | 4 |
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" >> \ |