Add cross-prefix support
authorRuud Koolen <redlizard@redlizard.nl>
Mon, 17 Jun 2013 07:21:41 +0000 (09:21 +0200)
committerZac Medico <zmedico@gentoo.org>
Tue, 18 Jun 2013 20:32:22 +0000 (13:32 -0700)
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

14 files changed:
bin/dispatch-conf
bin/phase-helpers.sh
bin/portageq
man/emerge.1
pym/_emerge/actions.py
pym/_emerge/main.py
pym/portage/_legacy_globals.py
pym/portage/_sets/__init__.py
pym/portage/dispatch_conf.py
pym/portage/package/ebuild/_config/LocationsManager.py
pym/portage/package/ebuild/config.py
pym/portage/package/ebuild/doebuild.py
pym/portage/package/ebuild/fetch.py
pym/portage/tests/resolver/ResolverPlayground.py

index a41464f2a3cce1eea920e59f89160e046872389c..10455f444633d6737035d26871fd08fb5c54f484 100755 (executable)
@@ -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:
index a97323ace05627cc1b8242c5b148c1682526479e..3d51eb0029d5e478fea0b60648870f6b1a8a7187 100644 (file)
@@ -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
index c88ee8804e03aeccc3d56587e3d60687940c6126..1ae1fe16e0aa61d24643056f18e9aa6037f83ad8 100755 (executable)
@@ -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:
index 05373cf834cc7940f8d3e8756e136aa2ab66e66d..6090202510b9ea452a5601c4625890269c11c5b7 100644 (file)
@@ -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
index 6dc384b70951dfa4e3024938f06f0ab8d74a514e..b331b10c1b9f845b67b9b8aec399ecc95b17589b 100644 (file)
@@ -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"),))
index fdbd4f9176ad12d32202af3de051302256106570..b26ce306be7f4c81813430e1ea5e1e64e4e6fc07 100644 (file)
@@ -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:
index abffa0e9a0f110a8f7a84f62fdd190a852f62337..bb9691a775a80fc7b6098f282ca70ec52e3c6f74 100644 (file)
@@ -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
index c196a7071fac5c8ccfc44b2efa6dc83ee96eecee..a545dba58de5f87ced23f9b139842c2e35fa9bd1 100644 (file)
@@ -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")):
index 4c68dfc7b8df23649f652e17a15f3fae4effe4c1..570bd8c464a7ee29a1e369174d9708b2e5dbcd00 100644 (file)
@@ -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()
index 5057f95d5dc01b6631bd218a807515fec6b92109..7e799b8407518008a22b52d5dd1d898f63a78f5e 100644 (file)
@@ -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
index 1c29af9eb74d4c42c35629e86e274bd6474652fe..befdee218993c2beeca971a66ed03402801eb039 100644 (file)
@@ -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"]
index 6de47bb6bb5c73da03330cb600f3461164ceb126..69463d2e8d57cf9d2570abb57075b5b21bb52ae6 100644 (file)
@@ -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(
index 50a1b7216e134124a429426b8f8421e0632e485f..fe5c5e3950df5678fdc8291fab32f0c57d1b5274 100644 (file)
@@ -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
index bff4512fed092e8990faa2936ff841a7d2d2d1b7..d2ceb320af6def85883cbb6b5cbb2876b796b81d 100644 (file)
@@ -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')