blob: 3733bdeb5b0af38ff806ff5d804b9dca238cc0e6 [file] [log] [blame]
# 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)