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 03:01:18
Message-Id: 20150115190055.758716b3.dolsen@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH] BinpkgExtractorAsync: xz and gzip decompression (142579) by Zac Medico
1 On Thu, 15 Jan 2015 17:27:23 -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 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 > pym/_emerge/BinpkgExtractorAsync.py | 28 ++++++++++++++--
19 > pym/portage/util/compression_probe.py | 62
20 > +++++++++++++++++++++++++++++++++++ 2 files changed, 88
21 > insertions(+), 2 deletions(-) create mode 100644
22 > pym/portage/util/compression_probe.py
23 >
24 > diff --git a/pym/_emerge/BinpkgExtractorAsync.py
25 > b/pym/_emerge/BinpkgExtractorAsync.py index be74c2f..8d446f9 100644
26 > --- a/pym/_emerge/BinpkgExtractorAsync.py
27 > +++ b/pym/_emerge/BinpkgExtractorAsync.py
28 > @@ -1,8 +1,12 @@
29 > # Copyright 1999-2013 Gentoo Foundation
30 > # Distributed under the terms of the GNU General Public License v2
31 >
32 > +import logging
33 > +
34 > from _emerge.SpawnProcess import SpawnProcess
35 > import portage
36 > +from portage.localization import _
37 > +from portage.util.compression_probe import compression_probe
38 > import signal
39 > import subprocess
40 >
41 > @@ -20,19 +24,39 @@ class BinpkgExtractorAsync(SpawnProcess):
42 > if b"--xattrs" in output:
43 > tar_options = "--xattrs"
44 >
45 > + comp = compression_probe(self.pkg_path)
46 > + if comp is None:
47 > + self.scheduler.output("!!! %s\n" %
48 > + _("File compression header
49 > unrecognized: %s") %
50 > + self.pkg_path, log_path=self.logfile,
51 > + background=self.background,
52 > level=logging.ERROR)
53 > + self.returncode = 1
54 > + self._async_wait()
55 > + return
56 > +
57 > # Add -q to bzip2 opts, in order to avoid "trailing
58 > garbage after # EOF ignored" warning messages due to xpak trailer.
59 > + if comp == "bzip2":
60 > + decomp_cmd =
61 > "${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d}"
62 > + elif comp == "xz":
63 > + decomp_cmd = "xz -d"
64 > + elif comp == "gzip":
65 > + decomp_cmd = "gzip -d"
66 > + else:
67 > + raise AssertionError("Unexpected
68 > compression: %s" % comp) +
69 > # SIGPIPE handling (128 + SIGPIPE) should be
70 > compatible with # assert_sigpipe_ok() that's used by the ebuild
71 > unpack() helper. self.args = [self._shell_binary, "-c",
72 > -
73 > ("${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d} -cq -- %s |
74 > tar -xp %s -C %s -f - ; " + \
75 > + ("%s -cq -- %s | tar -xp %s -C %s -f - ; " +
76 > \ "p=(${PIPESTATUS[@]}) ; " + \
77 > "if [[ ${p[0]} != 0 && ${p[0]} != %d ]] ;
78 > then " % (128 + signal.SIGPIPE) + \ "echo bzip2 failed with status
79 > ${p[0]} ; exit ${p[0]} ; fi ; " + \ "if [ ${p[1]} != 0 ] ; then " + \
80 > "echo tar failed with status ${p[1]} ; exit
81 > ${p[1]} ; fi ; " + \ "exit 0 ;") % \
82 > - (portage._shell_quote(self.pkg_path),
83 > + (decomp_cmd,
84 > + portage._shell_quote(self.pkg_path),
85 > tar_options,
86 > portage._shell_quote(self.image_dir))]
87 >
88
89 No offense, but yuk to the if foo .... else bar... else...
90
91 I already have code that does this much better, I decided I was going
92 to release it separately from catalyst because it is generally useful
93 and in many ways more future proof. I know you were interested in it,
94 but I hadn't gotten around to establishing it in a separate repo. I
95 also didn't know you were already working on this.
96
97 I've attached it to this email for you to look over. It needs a bit of
98 work for an independent release, but it is easily extended with
99 configuration changes. It can also be easily extended with custom
100 commands if needed.
101
102 If you are interested, it would not take long to have it release worthy
103 and in the tree.
104
105
106 > diff --git a/pym/portage/util/compression_probe.py
107 > b/pym/portage/util/compression_probe.py new file mode 100644
108 > index 0000000..7bdd28f
109 > --- /dev/null
110 > +++ b/pym/portage/util/compression_probe.py
111 > @@ -0,0 +1,62 @@
112 > +# Copyright 2015 Gentoo Foundation
113 > +# Distributed under the terms of the GNU General Public License v2
114 > +
115 > +import errno
116 > +import re
117 > +import sys
118 > +
119 > +if sys.hexversion >= 0x3000000:
120 > + basestring = str
121 > +
122 > +from portage import _encodings, _unicode_encode
123 > +from portage.exception import FileNotFound, PermissionDenied
124 > +
125 > +_compression_re = re.compile(b'^(' +
126 > + b'(?P<gzip>\x1f\x8b)|' +
127 > + b'(?P<bzip2>\x42\x5a\x68\x39)|' +
128 > + b'(?P<xz>\xfd\x37\x7a\x58\x5a\x00))')
129 > +
130 > +def compression_probe(f):
131 > + """
132 > + Identify the compression type of a file. Returns one of the
133 > + following identifier strings:
134 > +
135 > + bzip2
136 > + gzip
137 > + xz
138 > +
139 > + @param f: a file path, or file-like object
140 > + @type f: file-like object
141 > + @return: a string identifying the compression type, or None
142 > if the
143 > + compression type is unrecognized
144 > + @rtype str or None
145 > + """
146 > +
147 > + open_file = isinstance(f, basestring)
148 > + if open_file:
149 > + try:
150 > + f = open(_unicode_encode(f,
151 > + encoding=_encodings['fs'],
152 > errors='strict'), mode='rb')
153 > + except IOError as e:
154 > + if e.errno == PermissionDenied.errno:
155 > + raise PermissionDenied(f)
156 > + elif e.errno in (errno.ENOENT, errno.ESTALE):
157 > + raise FileNotFound(f)
158 > + else:
159 > + raise
160 > +
161 > + try:
162 > + return _compression_probe_file(f)
163 > + finally:
164 > + if open_file:
165 > + f.close()
166 > +
167 > +def _compression_probe_file(f):
168 > +
169 > + m = _compression_re.match(f.read(6))
170 > + if m is not None:
171 > + for k, v in m.groupdict().items():
172 > + if v is not None:
173 > + return k
174 > +
175 > + return None
176
177
178
179 --
180 Brian Dolbec <dolsen>

Attachments

File name MIME type
compress.py text/x-python

Replies