From 50daef1ab961c42a3352281e915da5a89297e3a9 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Mon, 30 Aug 2010 20:55:11 -0700 Subject: [PATCH] Bug #335340 - Add support for PORTAGE_BZIP2_COMMAND and 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 | 1 + bin/misc-functions.sh | 2 +- cnf/make.globals | 2 + man/make.conf.5 | 10 +++++ pym/_emerge/Binpkg.py | 1 + pym/_emerge/BinpkgEnvExtractor.py | 2 +- pym/_emerge/BinpkgExtractorAsync.py | 3 +- .../ebuild/_config/env_var_validation.py | 23 +++++++++++ .../ebuild/_config/special_env_vars.py | 14 ++++--- pym/portage/package/ebuild/config.py | 39 ++++++++++++++++++- 10 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 pym/portage/package/ebuild/_config/env_var_validation.py diff --git a/bin/isolated-functions.sh b/bin/isolated-functions.sh index cd1039b07..46685f891 100644 --- a/bin/isolated-functions.sh +++ b/bin/isolated-functions.sh @@ -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 \ diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh index d7e0f5688..32d3bfc00 100755 --- a/bin/misc-functions.sh +++ b/bin/misc-functions.sh @@ -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 \ diff --git a/cnf/make.globals b/cnf/make.globals index c16102ac7..6679918fd 100644 --- a/cnf/make.globals +++ b/cnf/make.globals @@ -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" diff --git a/man/make.conf.5 b/man/make.conf.5 index fb7ee85bb..71e9581ad 100644 --- a/man/make.conf.5 +++ b/man/make.conf.5 @@ -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. diff --git a/pym/_emerge/Binpkg.py b/pym/_emerge/Binpkg.py index cfb32ad5d..ac9a68a0f 100644 --- a/pym/_emerge/Binpkg.py +++ b/pym/_emerge/Binpkg.py @@ -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"), diff --git a/pym/_emerge/BinpkgEnvExtractor.py b/pym/_emerge/BinpkgEnvExtractor.py index 77060589a..f68971b35 100644 --- a/pym/_emerge/BinpkgEnvExtractor.py +++ b/pym/_emerge/BinpkgEnvExtractor.py @@ -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( diff --git a/pym/_emerge/BinpkgExtractorAsync.py b/pym/_emerge/BinpkgExtractorAsync.py index a2bbe7a45..004544e92 100644 --- a/pym/_emerge/BinpkgExtractorAsync.py +++ b/pym/_emerge/BinpkgExtractorAsync.py @@ -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 index 000000000..d3db545cb --- /dev/null +++ b/pym/portage/package/ebuild/_config/env_var_validation.py @@ -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) diff --git a/pym/portage/package/ebuild/_config/special_env_vars.py b/pym/portage/package/ebuild/_config/special_env_vars.py index 2a515dd0d..4a29b1446 100644 --- a/pym/portage/package/ebuild/_config/special_env_vars.py +++ b/pym/portage/package/ebuild/_config/special_env_vars.py @@ -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. diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py index 847ac1ccb..01950f9af 100644 --- a/pym/portage/package/ebuild/config.py +++ b/pym/portage/package/ebuild/config.py @@ -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 -- 2.26.2