Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH] BinpkgExtractorAsync: xz and gzip decompression (142579)
Date: Fri, 16 Jan 2015 08:31:03
Message-Id: 1421397031-9158-1-git-send-email-zmedico@gentoo.org
In Reply to: Re: [gentoo-portage-dev] [PATCH] BinpkgExtractorAsync: xz and gzip decompression (142579) by Brian Dolbec
1 This adds support for using a binary package's compression header to
2 determine the compression type, providing forward-compatibility for
3 xz and gzip decompression. The file name extension is disregared, so
4 that it will be possible to use a compression-independent file naming
5 scheme in the future (see bug #150031 for discussion about proposed
6 file naming schemes).
7
8 Currently, only decompression is supported. It's useful to provide
9 forward-compatibility now, so that binhost clients will be prepared
10 to handle future binhost servers that use xz or gzip compression.
11
12 X-Gentoo-Bug: 142579
13 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=142579
14 ---
15 pym/_emerge/BinpkgExtractorAsync.py | 25 ++++++++++---
16 pym/portage/util/compression_probe.py | 68 +++++++++++++++++++++++++++++++++++
17 2 files changed, 89 insertions(+), 4 deletions(-)
18 create mode 100644 pym/portage/util/compression_probe.py
19
20 diff --git a/pym/_emerge/BinpkgExtractorAsync.py b/pym/_emerge/BinpkgExtractorAsync.py
21 index be74c2f..6aaa448 100644
22 --- a/pym/_emerge/BinpkgExtractorAsync.py
23 +++ b/pym/_emerge/BinpkgExtractorAsync.py
24 @@ -1,8 +1,13 @@
25 # Copyright 1999-2013 Gentoo Foundation
26 # Distributed under the terms of the GNU General Public License v2
27
28 +import logging
29 +
30 from _emerge.SpawnProcess import SpawnProcess
31 import portage
32 +from portage.localization import _
33 +from portage.util.compression_probe import (compression_probe,
34 + _decompressors)
35 import signal
36 import subprocess
37
38 @@ -20,19 +25,31 @@ class BinpkgExtractorAsync(SpawnProcess):
39 if b"--xattrs" in output:
40 tar_options = "--xattrs"
41
42 - # Add -q to bzip2 opts, in order to avoid "trailing garbage after
43 - # EOF ignored" warning messages due to xpak trailer.
44 + decomp_cmd = _decompressors.get(
45 + compression_probe(self.pkg_path))
46 + if decomp_cmd is None:
47 + self.scheduler.output("!!! %s\n" %
48 + _("File compression header unrecognized: %s") %
49 + self.pkg_path, log_path=self.logfile,
50 + background=self.background, level=logging.ERROR)
51 + self.returncode = 1
52 + self._async_wait()
53 + return
54 +
55 + # Add -q to decomp_cmd opts, in order to avoid "trailing garbage
56 + # after EOF ignored" warning messages due to xpak trailer.
57 # SIGPIPE handling (128 + SIGPIPE) should be compatible with
58 # assert_sigpipe_ok() that's used by the ebuild unpack() helper.
59 self.args = [self._shell_binary, "-c",
60 - ("${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d} -cq -- %s | tar -xp %s -C %s -f - ; " + \
61 + ("%s -cq -- %s | tar -xp %s -C %s -f - ; " + \
62 "p=(${PIPESTATUS[@]}) ; " + \
63 "if [[ ${p[0]} != 0 && ${p[0]} != %d ]] ; then " % (128 + signal.SIGPIPE) + \
64 "echo bzip2 failed with status ${p[0]} ; exit ${p[0]} ; fi ; " + \
65 "if [ ${p[1]} != 0 ] ; then " + \
66 "echo tar failed with status ${p[1]} ; exit ${p[1]} ; fi ; " + \
67 "exit 0 ;") % \
68 - (portage._shell_quote(self.pkg_path),
69 + (decomp_cmd,
70 + portage._shell_quote(self.pkg_path),
71 tar_options,
72 portage._shell_quote(self.image_dir))]
73
74 diff --git a/pym/portage/util/compression_probe.py b/pym/portage/util/compression_probe.py
75 new file mode 100644
76 index 0000000..1dc3547
77 --- /dev/null
78 +++ b/pym/portage/util/compression_probe.py
79 @@ -0,0 +1,68 @@
80 +# Copyright 2015 Gentoo Foundation
81 +# Distributed under the terms of the GNU General Public License v2
82 +
83 +import errno
84 +import re
85 +import sys
86 +
87 +if sys.hexversion >= 0x3000000:
88 + basestring = str
89 +
90 +from portage import _encodings, _unicode_encode
91 +from portage.exception import FileNotFound, PermissionDenied
92 +
93 +_decompressors = {
94 + "bzip2": "${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d}",
95 + "gzip": "gzip -d",
96 + "xz": "xz -d",
97 +}
98 +
99 +_compression_re = re.compile(b'^(' +
100 + b'(?P<bzip2>\x42\x5a\x68\x39)|' +
101 + b'(?P<gzip>\x1f\x8b)|' +
102 + b'(?P<xz>\xfd\x37\x7a\x58\x5a\x00))')
103 +
104 +def compression_probe(f):
105 + """
106 + Identify the compression type of a file. Returns one of the
107 + following identifier strings:
108 +
109 + bzip2
110 + gzip
111 + xz
112 +
113 + @param f: a file path, or file-like object
114 + @type f: str or file
115 + @return: a string identifying the compression type, or None if the
116 + compression type is unrecognized
117 + @rtype str or None
118 + """
119 +
120 + open_file = isinstance(f, basestring)
121 + if open_file:
122 + try:
123 + f = open(_unicode_encode(f,
124 + encoding=_encodings['fs'], errors='strict'), mode='rb')
125 + except IOError as e:
126 + if e.errno == PermissionDenied.errno:
127 + raise PermissionDenied(f)
128 + elif e.errno in (errno.ENOENT, errno.ESTALE):
129 + raise FileNotFound(f)
130 + else:
131 + raise
132 +
133 + try:
134 + return _compression_probe_file(f)
135 + finally:
136 + if open_file:
137 + f.close()
138 +
139 +def _compression_probe_file(f):
140 +
141 + m = _compression_re.match(f.read(6))
142 + if m is not None:
143 + for k, v in m.groupdict().items():
144 + if v is not None:
145 + return k
146 +
147 + return None
148 --
149 2.0.5

Replies