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> |