Gentoo Archives: gentoo-portage-dev

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