Bug #335340 - Add support for PORTAGE_BZIP2_COMMAND and
authorZac Medico <zmedico@gentoo.org>
Tue, 31 Aug 2010 03:55:11 +0000 (20:55 -0700)
committerZac Medico <zmedico@gentoo.org>
Tue, 31 Aug 2010 03:55:11 +0000 (20:55 -0700)
PORTAGE_BUNZIP2_COMMAND settings in make.conf. This only adds support
for binary packages, since that's where pbzip2 can provide the most
benefit in common cases.

bin/isolated-functions.sh
bin/misc-functions.sh
cnf/make.globals
man/make.conf.5
pym/_emerge/Binpkg.py
pym/_emerge/BinpkgEnvExtractor.py
pym/_emerge/BinpkgExtractorAsync.py
pym/portage/package/ebuild/_config/env_var_validation.py [new file with mode: 0644]
pym/portage/package/ebuild/_config/special_env_vars.py
pym/portage/package/ebuild/config.py

index cd1039b07e6636eac9dd3864bab0c718562d85c6..46685f8911de954f7ff1c6dc5481ec23aec7ff9a 100644 (file)
@@ -596,6 +596,7 @@ save_ebuild_env() {
                        PORTAGE_ACTUAL_DISTDIR PORTAGE_ARCHLIST \
                        PORTAGE_BASHRC PM_EBUILD_HOOK_DIR PORTAGE_BASHRCS_SOURCED \
                        PORTAGE_BINPKG_TAR_OPTS PORTAGE_BINPKG_TMPFILE PORTAGE_BUILDDIR \
+                       PORTAGE_BUNZIP2_COMMAND PORTAGE_BZIP2_COMMAND \
                        PORTAGE_COLORMAP PORTAGE_CONFIGROOT PORTAGE_DEBUG \
                        PORTAGE_DEPCACHEDIR PORTAGE_EBUILD_EXIT_FILE PORTAGE_GID \
                        PORTAGE_GRPNAME PORTAGE_INST_GID \
index d7e0f568837ea9d3ff761149b97ba299be404a97..32d3bfc00ad145c2e7f6784907648009efd7f458 100755 (executable)
@@ -855,7 +855,7 @@ dyn_package() {
                PORTAGE_BINPKG_TMPFILE="${PKGDIR}/${CATEGORY}/${PF}.tbz2"
        mkdir -p "${PORTAGE_BINPKG_TMPFILE%/*}" || die "mkdir failed"
        tar $tar_options -cf - $PORTAGE_BINPKG_TAR_OPTS -C "${D}" . | \
-               bzip2 -cf > "$PORTAGE_BINPKG_TMPFILE"
+               $PORTAGE_BZIP2_COMMAND -c > "$PORTAGE_BINPKG_TMPFILE"
        assert "failed to pack binary package: '$PORTAGE_BINPKG_TMPFILE'"
        PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \
                "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH"/xpak-helper.py recompose \
index c16102ac774213d2469e922e8618a4fb004f2e56..6679918fd2fa4b26cef8531c7d3c9219341c9922 100644 (file)
@@ -70,6 +70,8 @@ EMERGE_WARNING_DELAY="10"
 # This option will be removed and forced to yes.
 AUTOCLEAN="yes"
 
+PORTAGE_BZIP2_COMMAND="bzip2"
+
 # Don't compress files with these suffixes.
 PORTAGE_COMPRESS_EXCLUDE_SUFFIXES="css gif htm[l]? jp[e]?g js pdf png"
 
index fb7ee85bba4421137f05b0b350a5d648ef143e43..71e9581ad6847a7e5b296340ec9311760b189722 100644 (file)
@@ -594,6 +594,16 @@ setting as the base URI.
 This variable contains options to be passed to the tar command for creation
 of binary packages.
 .TP
+\fBPORTAGE_BUNZIP2_COMMAND\fR = \fI[bunzip2 command string]\fR
+This variable should contain a command that is suitable for portage to call
+for bunzip2 extraction operations.
+.TP
+\fBPORTAGE_BZIP2_COMMAND\fR = \fI[bzip2 command string]\fR
+This variable should contain a command that is suitable for portage to call
+for bzip2 compression operations. \fBPORTAGE_BZIP2_COMMAND\fR will also be
+called for extraction operation, with -d appended, unless the
+\fBPORTAGE_BUNZIP2_COMMAND\fR variable is set.
+.TP
 \fBPORTAGE_COMPRESS\fR = \fI"bzip2"\fR
 This variable contains the command used to compress documentation during the
 install phase.
index cfb32ad5da66ced0516f0b467f970c08af44acfd..ac9a68a0f62ff1ec35e685c57f49246271379cc2 100644 (file)
@@ -274,6 +274,7 @@ class Binpkg(CompositeTask):
                        return
 
                extractor = BinpkgExtractorAsync(background=self.background,
+                       env=self.settings.environ(),
                        image_dir=self._image_dir,
                        pkg=self.pkg, pkg_path=self._pkg_path,
                        logfile=self.settings.get("PORTAGE_LOG_FILE"),
index 77060589a0139638105fd5173a187496659d73b8..f68971b3509b0f2b0d68cb746bacc84282ef8c1a 100644 (file)
@@ -30,7 +30,7 @@ class BinpkgEnvExtractor(CompositeTask):
        def _start(self):
                saved_env_path = self._get_saved_env_path()
                dest_env_path = self._get_dest_env_path()
-               shell_cmd = "bzip2 -dc %s > %s" % \
+               shell_cmd = "${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d} -c -- %s > %s" % \
                        (_shell_quote(saved_env_path),
                        _shell_quote(dest_env_path))
                extractor_proc = SpawnProcess(
index a2bbe7a45a50ab04815d7bcd978cdac5e916618d..004544e9290fdcff791bd2061c99187eb38a8125 100644 (file)
@@ -16,7 +16,7 @@ class BinpkgExtractorAsync(SpawnProcess):
                # SIGPIPE handling (128 + SIGPIPE) should be compatible with
                # assert_sigpipe_ok() that's used by the ebuild unpack() helper.
                self.args = [self._shell_binary, "-c",
-                       ("bzip2 -dqc -- %s | tar -xp -C %s -f - ; " + \
+                       ("${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d} -c -- %s | tar -xp -C %s -f - ; " + \
                        "p=(${PIPESTATUS[@]}) ; " + \
                        "if [[ ${p[0]} != 0 && ${p[0]} != %d ]] ; then " % (128 + signal.SIGPIPE) + \
                        "echo bzip2 failed with status ${p[0]} ; exit ${p[0]} ; fi ; " + \
@@ -26,5 +26,4 @@ class BinpkgExtractorAsync(SpawnProcess):
                        (portage._shell_quote(self.pkg_path),
                        portage._shell_quote(self.image_dir))]
 
-               self.env = os.environ.copy()
                SpawnProcess._start(self)
diff --git a/pym/portage/package/ebuild/_config/env_var_validation.py b/pym/portage/package/ebuild/_config/env_var_validation.py
new file mode 100644 (file)
index 0000000..d3db545
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from portage.process import find_binary
+from portage.util import shlex_split
+
+def validate_cmd_var(v):
+       """
+       Validate an evironment variable value to see if it
+       contains an executable command as the first token.
+       returns (valid, token_list) where 'valid' is boolean and 'token_list'
+       is the (possibly empty) list of tokens split by shlex.
+       """
+       invalid = False
+       v_split = shlex_split(v)
+       if not v_split:
+               invalid = True
+       elif os.path.isabs(v_split[0]):
+               invalid = not os.access(v_split[0], os.EX_OK)
+       elif find_binary(v_split[0]) is None:
+               invalid = True
+       return (not invalid, v_split)
index 2a515dd0d620b4feb2c920dc9aeb6644753486ec..4a29b1446cad86adb7988e6bd5586f7f58cfd8cc 100644 (file)
@@ -43,7 +43,8 @@ environ_whitelist += [
        "PORTAGE_BINPKG_FILE", "PORTAGE_BINPKG_TAR_OPTS",
        "PORTAGE_BINPKG_TMPFILE",
        "PORTAGE_BIN_PATH",
-       "PORTAGE_BUILDDIR", "PORTAGE_COLORMAP",
+       "PORTAGE_BUILDDIR", "PORTAGE_BUNZIP2_COMMAND", "PORTAGE_BZIP2_COMMAND",
+       "PORTAGE_COLORMAP",
        "PORTAGE_CONFIGROOT", "PORTAGE_DEBUG", "PORTAGE_DEPCACHEDIR",
        "PORTAGE_EBUILD_EXIT_FILE", "PORTAGE_FEATURES",
        "PORTAGE_GID", "PORTAGE_GRPNAME",
@@ -152,10 +153,13 @@ environ_filter += [
 
 environ_filter = frozenset(environ_filter)
 
-default_globals = (
-       ('ACCEPT_LICENSE',           '* -@EULA'),
-       ('ACCEPT_PROPERTIES',        '*'),
-)
+default_globals = {
+       'ACCEPT_LICENSE':           '* -@EULA',
+       'ACCEPT_PROPERTIES':        '*',
+       'PORTAGE_BZIP2_COMMAND':    'bzip2',
+}
+
+validate_commands = ('PORTAGE_BZIP2_COMMAND', 'PORTAGE_BUNZIP2_COMMAND',)
 
 # To enhance usability, make some vars case insensitive
 # by forcing them to lower case.
index 847ac1ccb0ab0093733bc1c39f501ea922ae74a9..01950f9af37723b74b5b217573aee39f714fec4d 100644 (file)
@@ -46,6 +46,7 @@ from portage.util import ensure_dirs, getconfig, grabdict, \
 from portage.versions import catpkgsplit, catsplit, cpv_getkey
 
 from portage.package.ebuild._config import special_env_vars
+from portage.package.ebuild._config.env_var_validation import validate_cmd_var
 from portage.package.ebuild._config.features_set import features_set
 from portage.package.ebuild._config.LicenseManager import LicenseManager
 from portage.package.ebuild._config.UseManager import UseManager
@@ -444,7 +445,7 @@ class config(object):
                        if self.mygcfg is None:
                                self.mygcfg = {}
 
-                       for k, v in self._default_globals:
+                       for k, v in self._default_globals.items():
                                self.mygcfg.setdefault(k, v)
 
                        self.configlist.append(self.mygcfg)
@@ -773,6 +774,8 @@ class config(object):
 
                        self._iuse_implicit_match = _iuse_implicit_match_cache(self)
 
+                       self._validate_commands()
+
                for k in self._case_insensitive_vars:
                        if k in self:
                                self[k] = self[k].lower()
@@ -781,6 +784,40 @@ class config(object):
                if mycpv:
                        self.setcpv(mycpv)
 
+       def _validate_commands(self):
+               for k in special_env_vars.validate_commands:
+                       v = self.get(k)
+                       if v is not None:
+                               valid, v_split = validate_cmd_var(v)
+
+                               if not valid:
+                                       if v_split:
+                                               writemsg_level(_("%s setting is invalid: '%s'\n") % \
+                                                       (k, v), level=logging.ERROR, noiselevel=-1)
+
+                                       # before deleting the invalid setting, backup
+                                       # the default value if available
+                                       v = self.configdict['globals'].get(k)
+                                       if v is not None:
+                                               default_valid, v_split = validate_cmd_var(v)
+                                               if not default_valid:
+                                                       if v_split:
+                                                               writemsg_level(
+                                                                       _("%s setting from make.globals" + \
+                                                                       " is invalid: '%s'\n") % \
+                                                                       (k, v), level=logging.ERROR, noiselevel=-1)
+                                                       # make.globals seems corrupt, so try for
+                                                       # a hardcoded default instead
+                                                       v = self._default_globals.get(k)
+
+                                       # delete all settings for this key,
+                                       # including the invalid one
+                                       del self[k]
+                                       self.backupenv.pop(k, None)
+                                       if v:
+                                               # restore validated default
+                                               self.configdict['globals'][k] = v
+
        def _init_dirs(self):
                """
                Create a few directories that are critical to portage operation