| # Copyright 1999-2013 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| import logging |
| |
| from _emerge.SpawnProcess import SpawnProcess |
| import portage |
| from portage.localization import _ |
| from portage.util.compression_probe import ( |
| compression_probe, |
| _compressors, |
| ) |
| from portage.process import find_binary |
| from portage.util import ( |
| shlex_split, |
| varexpand, |
| ) |
| import signal |
| import subprocess |
| import tarfile |
| |
| |
| class BinpkgExtractorAsync(SpawnProcess): |
| |
| __slots__ = ("features", "image_dir", "pkg", "pkg_path") |
| |
| _shell_binary = portage.const.BASH_BINARY |
| |
| def _start(self): |
| tar_options = "" |
| if "xattr" in self.features: |
| process = subprocess.Popen( |
| ["tar", "--help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE |
| ) |
| output = process.communicate()[0] |
| if b"--xattrs" in output: |
| tar_options = ["--xattrs", "--xattrs-include='*'"] |
| for x in portage.util.shlex_split( |
| self.env.get("PORTAGE_XATTR_EXCLUDE", "") |
| ): |
| tar_options.append(portage._shell_quote("--xattrs-exclude=%s" % x)) |
| tar_options = " ".join(tar_options) |
| |
| decomp = _compressors.get(compression_probe(self.pkg_path)) |
| if decomp is not None: |
| decomp_cmd = decomp.get("decompress") |
| elif tarfile.is_tarfile( |
| portage._unicode_encode( |
| self.pkg_path, encoding=portage._encodings["fs"], errors="strict" |
| ) |
| ): |
| decomp_cmd = "cat" |
| decomp = { |
| "compress": "cat", |
| "package": "sys-apps/coreutils", |
| } |
| else: |
| decomp_cmd = None |
| if decomp_cmd is None: |
| self.scheduler.output( |
| "!!! %s\n" |
| % _("File compression header unrecognized: %s") |
| % self.pkg_path, |
| log_path=self.logfile, |
| background=self.background, |
| level=logging.ERROR, |
| ) |
| self.returncode = 1 |
| self._async_wait() |
| return |
| |
| try: |
| decompression_binary = shlex_split(varexpand(decomp_cmd, mydict=self.env))[ |
| 0 |
| ] |
| except IndexError: |
| decompression_binary = "" |
| |
| if find_binary(decompression_binary) is None: |
| # Try alternative command if it exists |
| if decomp.get("decompress_alt"): |
| decomp_cmd = decomp.get("decompress_alt") |
| try: |
| decompression_binary = shlex_split( |
| varexpand(decomp_cmd, mydict=self.env) |
| )[0] |
| except IndexError: |
| decompression_binary = "" |
| |
| if find_binary(decompression_binary) is None: |
| missing_package = decomp.get("package") |
| self.scheduler.output( |
| "!!! %s\n" |
| % _( |
| "File compression unsupported %s.\n Command was: %s.\n Maybe missing package: %s" |
| ) |
| % ( |
| self.pkg_path, |
| varexpand(decomp_cmd, mydict=self.env), |
| missing_package, |
| ), |
| log_path=self.logfile, |
| background=self.background, |
| level=logging.ERROR, |
| ) |
| self.returncode = 1 |
| self._async_wait() |
| return |
| |
| pkg_xpak = portage.xpak.tbz2(self.pkg_path) |
| pkg_xpak.scan() |
| |
| # 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", |
| ( |
| "cmd0=(head -c %d -- %s) cmd1=(%s) cmd2=(tar -xp %s -C %s -f -); " |
| + '"${cmd0[@]}" | "${cmd1[@]}" | "${cmd2[@]}"; ' |
| + "p=(${PIPESTATUS[@]}) ; for i in {0..2}; do " |
| + "if [[ ${p[$i]} != 0 && ${p[$i]} != %d ]] ; then " |
| + 'echo command $(eval "echo \\"\'\\${cmd$i[*]}\'\\"") ' |
| + "failed with status ${p[$i]} ; exit ${p[$i]} ; fi ; done; " |
| + "if [ ${p[$i]} != 0 ] ; then " |
| + 'echo command $(eval "echo \\"\'\\${cmd$i[*]}\'\\"") ' |
| + "failed with status ${p[$i]} ; exit ${p[$i]} ; fi ; " |
| + "exit 0 ;" |
| ) |
| % ( |
| pkg_xpak.filestat.st_size - pkg_xpak.xpaksize, |
| portage._shell_quote(self.pkg_path), |
| decomp_cmd, |
| tar_options, |
| portage._shell_quote(self.image_dir), |
| 128 + signal.SIGPIPE, |
| ), |
| ] |
| |
| SpawnProcess._start(self) |