From c9f6aa9f0151adb3c86706eaef1914cdbdcf2b6d Mon Sep 17 00:00:00 2001 From: Ruud Koolen Date: Mon, 17 Jun 2013 09:21:41 +0200 Subject: [PATCH] Add cross-prefix support This patch series adds support for using a portage installed in one prefix to build packages with a different prefix. The current portage has a single EPREFIX variable specifying both the prefix of the portage installation, and the prefix of the packages portage is building. This patch series splits it into two parts: the portage.const.EPREFIX variable specifying the prefix of the portage installation, used for constructing the PATH as well as the paths to files belonging to a portage installation itself rather than a target root; and the EPREFIX setting in config instances, specifying the prefix of the to-be-built packages and being used for almost everything else. The EPREFIX config setting defaults to const.EPREFIX, but can be overridden by the EPREFIX environment variable, as well as the emerge --prefix option. This allows one to install systems with different prefixes using `EPREFIX=/foo emerge @system`, though some unrelated changes need to happen elsewhere first in order to make that a reality. Ruud Koolen (3): Distinguish between portage prefix and package prefix Based GLOBAL_CONFIG_PATH and DEPCACHE_PATH on portage prefix Pick up EPREFIX environment variable --- bin/dispatch-conf | 2 +- bin/phase-helpers.sh | 12 ++++++-- bin/portageq | 2 +- man/emerge.1 | 10 +++++++ pym/_emerge/actions.py | 11 +++---- pym/_emerge/main.py | 7 +++++ pym/portage/_legacy_globals.py | 3 +- pym/portage/_sets/__init__.py | 5 ++-- pym/portage/dispatch_conf.py | 2 +- .../ebuild/_config/LocationsManager.py | 25 ++-------------- pym/portage/package/ebuild/config.py | 30 ++++++------------- pym/portage/package/ebuild/doebuild.py | 2 +- pym/portage/package/ebuild/fetch.py | 4 +-- .../tests/resolver/ResolverPlayground.py | 2 ++ 14 files changed, 58 insertions(+), 59 deletions(-) diff --git a/bin/dispatch-conf b/bin/dispatch-conf index a41464f2a..10455f444 100755 --- a/bin/dispatch-conf +++ b/bin/dispatch-conf @@ -79,7 +79,7 @@ class dispatch: confs = [] count = 0 - config_root = portage.const.EPREFIX or os.sep + config_root = portage.settings["EPREFIX"] or os.sep self.options = portage.dispatch_conf.read_config(MANDATORY_OPTS) if "log-file" in self.options: diff --git a/bin/phase-helpers.sh b/bin/phase-helpers.sh index a97323ace..3d51eb002 100644 --- a/bin/phase-helpers.sh +++ b/bin/phase-helpers.sh @@ -676,7 +676,11 @@ has_version() { fi if ___eapi_has_prefix_variables; then - eroot=${root%/}${EPREFIX}/ + if [[ ${root} == / ]] ; then + eroot=${root%/}${PORTAGE_OVERRIDE_EPREFIX}/ + else + eroot=${root%/}${EPREFIX}/ + fi else eroot=${root} fi @@ -728,7 +732,11 @@ best_version() { fi if ___eapi_has_prefix_variables; then - eroot=${root%/}${EPREFIX}/ + if [[ ${root} == / ]] ; then + eroot=${root%/}${PORTAGE_OVERRIDE_EPREFIX}/ + else + eroot=${root%/}${EPREFIX}/ + fi else eroot=${root} fi diff --git a/bin/portageq b/bin/portageq index c88ee8804..1ae1fe16e 100755 --- a/bin/portageq +++ b/bin/portageq @@ -1232,7 +1232,7 @@ def main(argv): sys.stderr.write("Run portageq with --help for info\n") sys.stderr.flush() sys.exit(os.EX_USAGE) - eprefix = portage.const.EPREFIX + eprefix = portage.settings["EPREFIX"] eroot = portage.util.normalize_path(argv[2]) if eprefix: diff --git a/man/emerge.1 b/man/emerge.1 index 05373cf83..609020251 100644 --- a/man/emerge.1 +++ b/man/emerge.1 @@ -631,6 +631,9 @@ exhaustively apply the entire history of package moves, regardless of whether or not any of the package moves have been previously applied. .TP +.BR \-\-prefix=DIR +Set the \fBEPREFIX\fR environment variable. +.TP .BR "\-\-pretend " (\fB\-p\fR) Instead of actually performing the merge, simply display what *would* have been installed if \fB\-\-pretend\fR weren't used. Using \fB\-\-pretend\fR @@ -847,6 +850,13 @@ This setting can be added to command line. .SH "ENVIRONMENT OPTIONS" .TP +\fBEPREFIX\fR = \fI[path]\fR +Use \fBEPREFIX\fR to specify the target prefix to be used for merging packages +or ebuilds. This variable can be set via the \fB\-\-prefix\fR +option or in \fBmake.conf\fR(5) (the command line overrides other settings). +.br +Defaults to the prefix where portage is currently installed. +.TP \fBROOT\fR = \fI[path]\fR Use \fBROOT\fR to specify the target root filesystem to be used for merging packages or ebuilds. This variable can be set via the \fB\-\-root\fR diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py index 6dc384b70..b331b10c1 100644 --- a/pym/_emerge/actions.py +++ b/pym/_emerge/actions.py @@ -2017,8 +2017,8 @@ def action_sync(settings, trees, mtimedb, myopts, myaction): myportdir = None out = portage.output.EOutput() global_config_path = GLOBAL_CONFIG_PATH - if settings['EPREFIX']: - global_config_path = os.path.join(settings['EPREFIX'], + if portage.const.EPREFIX: + global_config_path = os.path.join(portage.const.EPREFIX, GLOBAL_CONFIG_PATH.lstrip(os.sep)) if not myportdir: sys.stderr.write("!!! PORTDIR is undefined. " + \ @@ -3150,7 +3150,8 @@ def load_emerge_config(emerge_config=None, **kargs): emerge_config = _emerge_config(**kargs) kwargs = {} - for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT")): + for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT"), + ("eprefix", "EPREFIX")): v = os.environ.get(envvar, None) if v and v.strip(): kwargs[k] = v @@ -3334,8 +3335,8 @@ def missing_sets_warning(root_config, missing_sets): if root_config.sets: msg.append(" sets defined: %s" % ", ".join(root_config.sets)) global_config_path = portage.const.GLOBAL_CONFIG_PATH - if root_config.settings['EPREFIX']: - global_config_path = os.path.join(root_config.settings['EPREFIX'], + if portage.const.EPREFIX: + global_config_path = os.path.join(portage.const.EPREFIX, portage.const.GLOBAL_CONFIG_PATH.lstrip(os.sep)) msg.append(" This usually means that '%s'" % \ (os.path.join(global_config_path, "sets/portage.conf"),)) diff --git a/pym/_emerge/main.py b/pym/_emerge/main.py index fdbd4f917..b26ce306b 100644 --- a/pym/_emerge/main.py +++ b/pym/_emerge/main.py @@ -541,6 +541,11 @@ def parse_opts(tmpcmdline, silent=False): "choices" : true_y_or_n }, + "--prefix": { + "help" : "specify the installation prefix", + "action" : "store" + }, + "--quiet": { "shortopt" : "-q", "help" : "reduced or condensed output", @@ -1024,6 +1029,8 @@ def emerge_main(args=None): os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"] if "--root" in myopts: os.environ["ROOT"] = myopts["--root"] + if "--prefix" in myopts: + os.environ["EPREFIX"] = myopts["--prefix"] if "--accept-properties" in myopts: os.environ["ACCEPT_PROPERTIES"] = myopts["--accept-properties"] if "--accept-restrict" in myopts: diff --git a/pym/portage/_legacy_globals.py b/pym/portage/_legacy_globals.py index abffa0e9a..bb9691a77 100644 --- a/pym/portage/_legacy_globals.py +++ b/pym/portage/_legacy_globals.py @@ -27,7 +27,8 @@ def _get_legacy_global(name): os.umask(0o22) kwargs = {} - for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT")): + for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), + ("target_root", "ROOT"), ("eprefix", "EPREFIX")): kwargs[k] = os.environ.get(envvar) portage._initializing_globals = True diff --git a/pym/portage/_sets/__init__.py b/pym/portage/_sets/__init__.py index c196a7071..a545dba58 100644 --- a/pym/portage/_sets/__init__.py +++ b/pym/portage/_sets/__init__.py @@ -17,6 +17,7 @@ try: from configparser import SafeConfigParser except ImportError: from ConfigParser import SafeConfigParser, NoOptionError, ParsingError +import portage from portage import os from portage import load_mod from portage import _unicode_decode @@ -295,8 +296,8 @@ def load_default_config(settings, trees): return SetConfig(None, settings, trees) global_config_path = GLOBAL_CONFIG_PATH - if settings['EPREFIX']: - global_config_path = os.path.join(settings['EPREFIX'], + if portage.const.EPREFIX: + global_config_path = os.path.join(portage.const.EPREFIX, GLOBAL_CONFIG_PATH.lstrip(os.sep)) def _getfiles(): for path, dirs, files in os.walk(os.path.join(global_config_path, "sets")): diff --git a/pym/portage/dispatch_conf.py b/pym/portage/dispatch_conf.py index 4c68dfc7b..570bd8c46 100644 --- a/pym/portage/dispatch_conf.py +++ b/pym/portage/dispatch_conf.py @@ -43,7 +43,7 @@ def diffstatusoutput(cmd, file1, file2): return (proc.wait(), output) def read_config(mandatory_opts): - eprefix = portage.const.EPREFIX + eprefix = portage.settings["EPREFIX"] config_path = os.path.join(eprefix or os.sep, "etc/dispatch-conf.conf") loader = KeyValuePairFileLoader(config_path, None) opts, errors = loader.load() diff --git a/pym/portage/package/ebuild/_config/LocationsManager.py b/pym/portage/package/ebuild/_config/LocationsManager.py index 5057f95d5..7e799b840 100644 --- a/pym/portage/package/ebuild/_config/LocationsManager.py +++ b/pym/portage/package/ebuild/_config/LocationsManager.py @@ -275,29 +275,10 @@ class LocationsManager(object): self.eroot = self.target_root.rstrip(os.sep) + self.eprefix + os.sep - # make.globals should not be relative to config_root - # because it only contains constants. However, if EPREFIX - # is set then there are two possible scenarios: - # 1) If $ROOT == "/" then make.globals should be - # relative to EPREFIX. - # 2) If $ROOT != "/" then the correct location of - # make.globals needs to be specified in the constructor - # parameters, since it's a property of the host system - # (and the current config represents the target system). self.global_config_path = GLOBAL_CONFIG_PATH - if self.eprefix: - if self.target_root == "/": - # case (1) above - self.global_config_path = os.path.join(self.eprefix, - GLOBAL_CONFIG_PATH.lstrip(os.sep)) - else: - # case (2) above - # For now, just assume make.globals is relative - # to EPREFIX. - # TODO: Pass in more info to the constructor, - # so we know the host system configuration. - self.global_config_path = os.path.join(self.eprefix, - GLOBAL_CONFIG_PATH.lstrip(os.sep)) + if portage.const.EPREFIX: + self.global_config_path = os.path.join(portage.const.EPREFIX, + 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 1c29af9eb..befdee218 100644 --- a/pym/portage/package/ebuild/config.py +++ b/pym/portage/package/ebuild/config.py @@ -594,17 +594,17 @@ class config(object): self.backup_changes("PORTAGE_CONFIGROOT") self["ROOT"] = target_root self.backup_changes("ROOT") - - # The PORTAGE_OVERRIDE_EPREFIX variable propagates the EPREFIX - # of this config instance to any portage commands or API - # consumers running in subprocesses. self["EPREFIX"] = eprefix self.backup_changes("EPREFIX") - self["PORTAGE_OVERRIDE_EPREFIX"] = eprefix - self.backup_changes("PORTAGE_OVERRIDE_EPREFIX") self["EROOT"] = eroot self.backup_changes("EROOT") + # The prefix of the running portage instance is used in the + # ebuild environment to implement the --host-root option for + # best_version and has_version. + self["PORTAGE_OVERRIDE_EPREFIX"] = portage.const.EPREFIX + self.backup_changes("PORTAGE_OVERRIDE_EPREFIX") + self._ppropertiesdict = portage.dep.ExtendedAtomDict(dict) self._paccept_restrict = portage.dep.ExtendedAtomDict(dict) self._penvdict = portage.dep.ExtendedAtomDict(dict) @@ -781,21 +781,9 @@ class config(object): self.backupenv["USE_ORDER"] = "env:pkg:conf:defaults:pkginternal:repo:env.d" self.depcachedir = DEPCACHE_PATH - if eprefix: - # See comments about make.globals and EPREFIX - # above. DEPCACHE_PATH is similar. - if target_root == "/": - # case (1) above - self.depcachedir = os.path.join(eprefix, - DEPCACHE_PATH.lstrip(os.sep)) - else: - # case (2) above - # For now, just assume DEPCACHE_PATH is relative - # to EPREFIX. - # TODO: Pass in more info to the constructor, - # so we know the host system configuration. - self.depcachedir = os.path.join(eprefix, - DEPCACHE_PATH.lstrip(os.sep)) + if portage.const.EPREFIX: + self.depcachedir = os.path.join(portage.const.EPREFIX, + DEPCACHE_PATH.lstrip(os.sep)) if self.get("PORTAGE_DEPCACHEDIR", None): self.depcachedir = self["PORTAGE_DEPCACHEDIR"] diff --git a/pym/portage/package/ebuild/doebuild.py b/pym/portage/package/ebuild/doebuild.py index 6de47bb6b..69463d2e8 100644 --- a/pym/portage/package/ebuild/doebuild.py +++ b/pym/portage/package/ebuild/doebuild.py @@ -159,7 +159,7 @@ def _doebuild_path(settings, eapi=None): # Note: PORTAGE_BIN_PATH may differ from the global constant # when portage is reinstalling itself. portage_bin_path = settings["PORTAGE_BIN_PATH"] - eprefix = settings["EPREFIX"] + eprefix = portage.const.EPREFIX prerootpath = [x for x in settings.get("PREROOTPATH", "").split(":") if x] rootpath = [x for x in settings.get("ROOTPATH", "").split(":") if x] overrides = [x for x in settings.get( diff --git a/pym/portage/package/ebuild/fetch.py b/pym/portage/package/ebuild/fetch.py index 50a1b7216..fe5c5e395 100644 --- a/pym/portage/package/ebuild/fetch.py +++ b/pym/portage/package/ebuild/fetch.py @@ -865,8 +865,8 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0, protocol = loc[0:loc.find("://")] global_config_path = GLOBAL_CONFIG_PATH - if mysettings['EPREFIX']: - global_config_path = os.path.join(mysettings['EPREFIX'], + if portage.const.EPREFIX: + global_config_path = os.path.join(portage.const.EPREFIX, GLOBAL_CONFIG_PATH.lstrip(os.sep)) missing_file_param = False diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py index bff4512fe..d2ceb320a 100644 --- a/pym/portage/tests/resolver/ResolverPlayground.py +++ b/pym/portage/tests/resolver/ResolverPlayground.py @@ -66,6 +66,8 @@ class ResolverPlayground(object): """ self.debug = debug self.eprefix = normalize_path(tempfile.mkdtemp()) + portage.const.EPREFIX = self.eprefix.rstrip(os.sep) + self.eroot = self.eprefix + os.sep if targetroot: self.target_root = os.path.join(self.eroot, 'target_root') -- 2.26.2