Gentoo Archives: gentoo-commits

From: "Manuel Rüger" <mrueg@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:master commit in: pym/_emerge/, man/, pym/portage/package/ebuild/_config/, pym/portage/util/, ...
Date: Sat, 29 Jul 2017 22:54:43
Message-Id: 1501375973.cff2c0149142843316e1851c2e73bcec30f08471.mrueg@gentoo
1 commit: cff2c0149142843316e1851c2e73bcec30f08471
2 Author: Manuel Rüger <mrueg <AT> gentoo <DOT> org>
3 AuthorDate: Thu Jun 15 15:11:04 2017 +0000
4 Commit: Manuel Rüger <mrueg <AT> gentoo <DOT> org>
5 CommitDate: Sun Jul 30 00:52:53 2017 +0000
6 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=cff2c014
7
8 Support different compressors for binary packages
9
10 This patch allows to set the compressor for binary packages via a
11 BINPKG_COMPRESSION variable. BINPKG_COMPRESSION_ARGS allows to specify
12 command-line arguments for the chosen compressor.
13
14 Reviewed-By: Zac Medico <zmedico <AT> gentoo.org>
15
16 bin/misc-functions.sh | 6 ++-
17 bin/quickpkg | 62 ++++++++++++++++------
18 man/make.conf.5 | 25 +++++++++
19 pym/_emerge/BinpkgExtractorAsync.py | 43 +++++++++++++--
20 pym/portage/dbapi/bintree.py | 8 +--
21 .../package/ebuild/_config/special_env_vars.py | 2 +-
22 pym/portage/package/ebuild/doebuild.py | 34 ++++++++++--
23 pym/portage/util/compression_probe.py | 45 +++++++++++++---
24 8 files changed, 186 insertions(+), 39 deletions(-)
25
26 diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh
27 index 58755a1e1..079369313 100755
28 --- a/bin/misc-functions.sh
29 +++ b/bin/misc-functions.sh
30 @@ -453,7 +453,7 @@ __dyn_package() {
31 # Make sure $PWD is not ${D} so that we don't leave gmon.out files
32 # in there in case any tools were built with -pg in CFLAGS.
33
34 - cd "${T}"
35 + cd "${T}" || die
36
37 if [[ -n ${PKG_INSTALL_MASK} ]] ; then
38 PROOT=${T}/packaging/
39 @@ -478,8 +478,10 @@ __dyn_package() {
40 [ -z "${PORTAGE_BINPKG_TMPFILE}" ] && \
41 die "PORTAGE_BINPKG_TMPFILE is unset"
42 mkdir -p "${PORTAGE_BINPKG_TMPFILE%/*}" || die "mkdir failed"
43 + [ -z "${PORTAGE_COMPRESSION_COMMAND}" ] && \
44 + die "PORTAGE_COMPRESSION_COMMAND is unset"
45 tar $tar_options -cf - $PORTAGE_BINPKG_TAR_OPTS -C "${PROOT}" . | \
46 - $PORTAGE_BZIP2_COMMAND -c > "$PORTAGE_BINPKG_TMPFILE"
47 + $PORTAGE_COMPRESSION_COMMAND -c > "$PORTAGE_BINPKG_TMPFILE"
48 assert "failed to pack binary package: '$PORTAGE_BINPKG_TMPFILE'"
49 PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \
50 "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH"/xpak-helper.py recompose \
51
52 diff --git a/bin/quickpkg b/bin/quickpkg
53 index 4f26ee912..750400592 100755
54 --- a/bin/quickpkg
55 +++ b/bin/quickpkg
56 @@ -8,6 +8,7 @@ import argparse
57 import errno
58 import math
59 import signal
60 +import subprocess
61 import sys
62 import tarfile
63
64 @@ -22,11 +23,13 @@ from portage.dbapi.dep_expand import dep_expand
65 from portage.dep import Atom, use_reduce
66 from portage.exception import (AmbiguousPackageName, InvalidAtom, InvalidData,
67 InvalidDependString, PackageSetNotFound, PermissionDenied)
68 -from portage.util import ConfigProtect, ensure_dirs, shlex_split, _xattr
69 +from portage.util import ConfigProtect, ensure_dirs, shlex_split, varexpand, _xattr
70 xattr = _xattr.xattr
71 from portage.dbapi.vartree import dblink, tar_contents
72 from portage.checksum import perform_md5
73 from portage._sets import load_default_config, SETPREFIX
74 +from portage.process import find_binary
75 +from portage.util.compression_probe import _compressors
76
77 def quickpkg_atom(options, infos, arg, eout):
78 settings = portage.settings
79 @@ -50,16 +53,16 @@ def quickpkg_atom(options, infos, arg, eout):
80 " ".join(e.args[0]))
81 del e
82 infos["missing"].append(arg)
83 - return
84 + return 1
85 except (InvalidAtom, InvalidData):
86 eout.eerror("Invalid atom: %s" % (arg,))
87 infos["missing"].append(arg)
88 - return
89 + return 1
90 if atom[:1] == '=' and arg[:1] != '=':
91 # dep_expand() allows missing '=' but it's really invalid
92 eout.eerror("Invalid atom: %s" % (arg,))
93 infos["missing"].append(arg)
94 - return
95 + return 1
96
97 matches = vardb.match(atom)
98 pkgs_for_arg = 0
99 @@ -108,16 +111,16 @@ def quickpkg_atom(options, infos, arg, eout):
100 in settings.features))
101 def protect(filename):
102 if not confprot.isprotected(filename):
103 - return False
104 + return 1
105 if include_unmodified_config:
106 file_data = contents[filename]
107 if file_data[0] == "obj":
108 orig_md5 = file_data[2].lower()
109 cur_md5 = perform_md5(filename, calc_prelink=1)
110 if orig_md5 == cur_md5:
111 - return False
112 + return 1
113 excluded_config_files.append(filename)
114 - return True
115 + return os.EX_OK
116 existing_metadata = dict(zip(fix_metadata_keys,
117 vardb.aux_get(cpv, fix_metadata_keys)))
118 category, pf = portage.catsplit(cpv)
119 @@ -134,12 +137,32 @@ def quickpkg_atom(options, infos, arg, eout):
120 binpkg_tmpfile = os.path.join(bintree.pkgdir,
121 cpv + ".tbz2." + str(os.getpid()))
122 ensure_dirs(os.path.dirname(binpkg_tmpfile))
123 - # The tarfile module will write pax headers holding the
124 - # xattrs only if PAX_FORMAT is specified here.
125 - tar = tarfile.open(binpkg_tmpfile, "w:bz2",
126 - format=tarfile.PAX_FORMAT if xattrs else tarfile.DEFAULT_FORMAT)
127 - tar_contents(contents, root, tar, protect=protect, xattrs=xattrs)
128 - tar.close()
129 + binpkg_compression = settings.get("BINPKG_COMPRESSION", "bzip2")
130 + try:
131 + compression = _compressors[binpkg_compression]
132 + except KeyError as e:
133 + eout.eerror("Invalid or unsupported compression method: %s" % e.args[0])
134 + return 1
135 + try:
136 + compression_binary = shlex_split(varexpand(compression["compress"], mydict=settings))[0]
137 + except IndexError as e:
138 + eout.eerror("Invalid or unsupported compression method: %s" % e.args[0])
139 + return 1
140 + if find_binary(compression_binary) is None:
141 + missing_package = compression["package"]
142 + eout.eerror("File compression unsupported %s. Missing package: %s" % (binpkg_compression, missing_package))
143 + return 1
144 + cmd = [varexpand(x, mydict=settings) for x in shlex_split(compression["compress"])]
145 + # Filter empty elements that make Popen fail
146 + cmd = [x for x in cmd if x != ""]
147 + with open(binpkg_tmpfile, "wb") as fobj:
148 + proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=fobj)
149 + # The tarfile module will write pax headers holding the
150 + # xattrs only if PAX_FORMAT is specified here.
151 + with tarfile.open(mode="w|",format=tarfile.PAX_FORMAT if xattrs else tarfile.DEFAULT_FORMAT, fileobj=proc.stdin) as tar:
152 + tar_contents(contents, root, tar, protect=protect, xattrs=xattrs)
153 + proc.stdin.close()
154 + proc.wait()
155 xpak.tbz2(binpkg_tmpfile).recompose_mem(xpdata)
156 finally:
157 if have_lock:
158 @@ -154,16 +177,20 @@ def quickpkg_atom(options, infos, arg, eout):
159 eout.eerror(str(e))
160 del e
161 eout.eerror("Failed to create package: '%s'" % binpkg_path)
162 + return 1
163 else:
164 eout.eend(0)
165 infos["successes"].append((cpv, s.st_size))
166 infos["config_files_excluded"] += len(excluded_config_files)
167 for filename in excluded_config_files:
168 eout.ewarn("Excluded config: '%s'" % filename)
169 + return os.EX_OK
170 if not pkgs_for_arg:
171 eout.eerror("Could not find anything " + \
172 "to match '%s'; skipping" % arg)
173 infos["missing"].append(arg)
174 + return 1
175 + return os.EX_OK
176
177 def quickpkg_set(options, infos, arg, eout):
178 eroot = portage.settings['EROOT']
179 @@ -179,7 +206,7 @@ def quickpkg_set(options, infos, arg, eout):
180 if not set in sets:
181 eout.eerror("Package set not found: '%s'; skipping" % (arg,))
182 infos["missing"].append(arg)
183 - return
184 + return 1
185
186 try:
187 atoms = setconfig.getSetAtoms(set)
188 @@ -187,10 +214,11 @@ def quickpkg_set(options, infos, arg, eout):
189 eout.eerror("Failed to process package set '%s' because " % set +
190 "it contains the non-existent package set '%s'; skipping" % e)
191 infos["missing"].append(arg)
192 - return
193 -
194 + return 1
195 + retval = os.EX_OK
196 for atom in atoms:
197 - quickpkg_atom(options, infos, atom, eout)
198 + retval |= quickpkg_atom(options, infos, atom, eout)
199 + return retval
200
201
202 def quickpkg_extended_atom(options, infos, atom, eout):
203
204 diff --git a/man/make.conf.5 b/man/make.conf.5
205 index aea189e4a..8e0d04967 100644
206 --- a/man/make.conf.5
207 +++ b/man/make.conf.5
208 @@ -110,6 +110,31 @@ ACCEPT_RESTRICT="*"
209 ACCEPT_RESTRICT="* -bindist"
210 .fi
211 .TP
212 +\fBBINPKG_COMPRESSION\fR = \fI"compression"\fR
213 +This variable is used to determine the compression used for \fIbinary
214 +packages\fR. Supported settings and compression algorithms are: bzip2, gzip,
215 +lz4, lzip, lzop, xz, zstd.
216 +.br
217 +Defaults to "bzip2".
218 +.br
219 +.I Example:
220 +.nf
221 +# Set it to use lz4:
222 +BINPKG_COMPRESSION="lz4"
223 +.fi
224 +.TP
225 +\fBBINPKG_COMPRESSION_ARGS\fR = \fI"arguments for compression command"\fR
226 +This variable is used to add additional arguments to the compression command
227 +selected by \fBBINPKG_COMPRESSION\fR.
228 +.br
229 +Defaults to "".
230 +.br
231 +.I Example:
232 +.nf
233 +# Set it to use compression level 9:
234 +BINPKG_COMPRESSION_ARGS="-9"
235 +.fi
236 +.TP
237 .B CBUILD
238 This variable is passed by the \fIebuild scripts\fR to the \fIconfigure\fR
239 as \fI\-\-build=${CBUILD}\fR only if it is defined. Do not set this yourself
240
241 diff --git a/pym/_emerge/BinpkgExtractorAsync.py b/pym/_emerge/BinpkgExtractorAsync.py
242 index 0bf3c74c9..e85f4ecac 100644
243 --- a/pym/_emerge/BinpkgExtractorAsync.py
244 +++ b/pym/_emerge/BinpkgExtractorAsync.py
245 @@ -6,8 +6,15 @@ import logging
246 from _emerge.SpawnProcess import SpawnProcess
247 import portage
248 from portage.localization import _
249 -from portage.util.compression_probe import (compression_probe,
250 - _decompressors)
251 +from portage.util.compression_probe import (
252 + compression_probe,
253 + _compressors,
254 +)
255 +from portage.process import find_binary
256 +from portage.util import (
257 + shlex_split,
258 + varexpand,
259 +)
260 import signal
261 import subprocess
262
263 @@ -28,8 +35,11 @@ class BinpkgExtractorAsync(SpawnProcess):
264 tar_options.append(portage._shell_quote("--xattrs-exclude=%s" % x))
265 tar_options = " ".join(tar_options)
266
267 - decomp_cmd = _decompressors.get(
268 - compression_probe(self.pkg_path))
269 + decomp = _compressors.get(compression_probe(self.pkg_path))
270 + if decomp is not None:
271 + decomp_cmd = decomp.get("decompress")
272 + else:
273 + decomp_cmd = None
274 if decomp_cmd is None:
275 self.scheduler.output("!!! %s\n" %
276 _("File compression header unrecognized: %s") %
277 @@ -39,6 +49,31 @@ class BinpkgExtractorAsync(SpawnProcess):
278 self._async_wait()
279 return
280
281 + try:
282 + decompression_binary = shlex_split(varexpand(decomp_cmd, mydict=self.env))[0]
283 + except IndexError:
284 + decompression_binary = ""
285 +
286 + if find_binary(decompression_binary) is None:
287 + # Try alternative command if it exists
288 + if _compressors.get(compression_probe(self.pkg_path)).get("decompress_alt"):
289 + decomp_cmd = _compressors.get(
290 + compression_probe(self.pkg_path)).get("decompress_alt")
291 + try:
292 + decompression_binary = shlex_split(varexpand(decomp_cmd, mydict=self.env))[0]
293 + except IndexError:
294 + decompression_binary = ""
295 +
296 + if find_binary(decompression_binary) is None:
297 + missing_package = _compressors.get(compression_probe(self.pkg_path)).get("package")
298 + self.scheduler.output("!!! %s\n" %
299 + _("File compression unsupported %s.\n Command was: %s.\n Maybe missing package: %s") %
300 + (self.pkg_path, varexpand(decomp_cmd, mydict=self.env), missing_package), log_path=self.logfile,
301 + background=self.background, level=logging.ERROR)
302 + self.returncode = 1
303 + self._async_wait()
304 + return
305 +
306 # Add -q to decomp_cmd opts, in order to avoid "trailing garbage
307 # after EOF ignored" warning messages due to xpak trailer.
308 # SIGPIPE handling (128 + SIGPIPE) should be compatible with
309
310 diff --git a/pym/portage/dbapi/bintree.py b/pym/portage/dbapi/bintree.py
311 index ca90ba8f9..c833968c2 100644
312 --- a/pym/portage/dbapi/bintree.py
313 +++ b/pym/portage/dbapi/bintree.py
314 @@ -141,7 +141,6 @@ class bindbapi(fakedbapi):
315 return [aux_cache.get(x, "") for x in wants]
316 mysplit = mycpv.split("/")
317 mylist = []
318 - tbz2name = mysplit[1]+".tbz2"
319 if not self.bintree._remotepkgs or \
320 not self.bintree.isremote(mycpv):
321 try:
322 @@ -1448,9 +1447,10 @@ class binarytree(object):
323 @staticmethod
324 def _parse_build_id(filename):
325 build_id = -1
326 - hyphen = filename.rfind("-", 0, -6)
327 + suffixlen = len(".xpak")
328 + hyphen = filename.rfind("-", 0, -(suffixlen + 1))
329 if hyphen != -1:
330 - build_id = filename[hyphen+1:-5]
331 + build_id = filename[hyphen+1:-suffixlen]
332 try:
333 build_id = long(build_id)
334 except ValueError:
335 @@ -1497,7 +1497,7 @@ class binarytree(object):
336 if self._remote_has_index:
337 rel_url = self._remotepkgs[instance_key].get("PATH")
338 if not rel_url:
339 - rel_url = pkgname+".tbz2"
340 + rel_url = pkgname + ".tbz2"
341 remote_base_uri = self._remotepkgs[instance_key]["BASE_URI"]
342 url = remote_base_uri.rstrip("/") + "/" + rel_url.lstrip("/")
343 else:
344
345 diff --git a/pym/portage/package/ebuild/_config/special_env_vars.py b/pym/portage/package/ebuild/_config/special_env_vars.py
346 index f7810e007..f9b29af93 100644
347 --- a/pym/portage/package/ebuild/_config/special_env_vars.py
348 +++ b/pym/portage/package/ebuild/_config/special_env_vars.py
349 @@ -56,7 +56,7 @@ environ_whitelist += [
350 "PORTAGE_BIN_PATH",
351 "PORTAGE_BUILDDIR", "PORTAGE_BUILD_GROUP", "PORTAGE_BUILD_USER",
352 "PORTAGE_BUNZIP2_COMMAND", "PORTAGE_BZIP2_COMMAND",
353 - "PORTAGE_COLORMAP", "PORTAGE_COMPRESS",
354 + "PORTAGE_COLORMAP", "PORTAGE_COMPRESS", "PORTAGE_COMPRESSION_COMMAND",
355 "PORTAGE_COMPRESS_EXCLUDE_SUFFIXES",
356 "PORTAGE_CONFIGROOT", "PORTAGE_DEBUG", "PORTAGE_DEPCACHEDIR",
357 "PORTAGE_DOHTML_UNWARNED_SKIPPED_EXTENSIONS",
358
359 diff --git a/pym/portage/package/ebuild/doebuild.py b/pym/portage/package/ebuild/doebuild.py
360 index e7db54bcf..3e75d1a51 100644
361 --- a/pym/portage/package/ebuild/doebuild.py
362 +++ b/pym/portage/package/ebuild/doebuild.py
363 @@ -68,11 +68,19 @@ from portage.exception import (DigestException, FileNotFound,
364 from portage.localization import _
365 from portage.output import colormap
366 from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
367 -from portage.util import apply_recursive_permissions, \
368 - apply_secpass_permissions, noiselimit, \
369 - writemsg, writemsg_stdout, write_atomic
370 +from portage.process import find_binary
371 +from portage.util import ( apply_recursive_permissions,
372 + apply_secpass_permissions,
373 + noiselimit,
374 + shlex_split,
375 + varexpand,
376 + writemsg,
377 + writemsg_stdout,
378 + write_atomic
379 + )
380 from portage.util.cpuinfo import get_cpu_count
381 from portage.util.lafilefixer import rewrite_lafile
382 +from portage.util.compression_probe import _compressors
383 from portage.util.socks5 import get_socks5_proxy
384 from portage.versions import _pkgsplit
385 from _emerge.BinpkgEnvExtractor import BinpkgEnvExtractor
386 @@ -518,6 +526,26 @@ def doebuild_environment(myebuild, mydo, myroot=None, settings=None,
387 mysettings["KV"] = ""
388 mysettings.backup_changes("KV")
389
390 + binpkg_compression = mysettings.get("BINPKG_COMPRESSION", "bzip2")
391 + try:
392 + compression = _compressors[binpkg_compression]
393 + except KeyError as e:
394 + writemsg("Warning: Invalid or unsupported compression method: %s" % e.args[0])
395 + else:
396 + try:
397 + compression_binary = shlex_split(varexpand(compression["compress"], mydict=settings))[0]
398 + except IndexError as e:
399 + writemsg("Warning: Invalid or unsupported compression method: %s" % e.args[0])
400 + else:
401 + if find_binary(compression_binary) is None:
402 + missing_package = compression["package"]
403 + writemsg("Warning: File compression unsupported %s. Missing package: %s" % (binpkg_compression, missing_package))
404 + else:
405 + cmd = [varexpand(x, mydict=settings) for x in shlex_split(compression["compress"])]
406 + # Filter empty elements
407 + cmd = [x for x in cmd if x != ""]
408 + mysettings['PORTAGE_COMPRESSION_COMMAND'] = ' '.join(cmd)
409 +
410 _doebuild_manifest_cache = None
411 _doebuild_broken_ebuilds = set()
412 _doebuild_broken_manifests = set()
413
414 diff --git a/pym/portage/util/compression_probe.py b/pym/portage/util/compression_probe.py
415 index 754621016..b15200044 100644
416 --- a/pym/portage/util/compression_probe.py
417 +++ b/pym/portage/util/compression_probe.py
418 @@ -11,14 +11,43 @@ if sys.hexversion >= 0x3000000:
419 from portage import _encodings, _unicode_encode
420 from portage.exception import FileNotFound, PermissionDenied
421
422 -_decompressors = {
423 - "bzip2": "${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d}",
424 - "gzip": "gzip -d",
425 - "lz4": "lz4 -d",
426 - "lzip": "lzip -d",
427 - "lzop": "lzop -d",
428 - "xz": "xz -d",
429 - "zstd": "zstd -d",
430 +_compressors = {
431 + "bzip2": {
432 + "compress": "${PORTAGE_BZIP2_COMMAND} ${BINPKG_COMPRESSION_ARGS}",
433 + "decompress": "${PORTAGE_BUNZIP2_COMMAND}",
434 + "decompress_alt": "${PORTAGE_BZIP2_COMMAND} -d",
435 + "package": "app-arch/bzip2",
436 + },
437 + "gzip": {
438 + "compress": "gzip ${BINPKG_COMPRESSION_ARGS}",
439 + "decompress": "gzip -d",
440 + "package": "app-arch/gzip",
441 + },
442 + "lz4": {
443 + "compress": "lz4 ${BINPKG_COMPRESSION_ARGS}",
444 + "decompress": "lz4 -d",
445 + "package": "app-arch/lz4",
446 + },
447 + "lzip": {
448 + "compress": "lzip ${BINPKG_COMPRESSION_ARGS}",
449 + "decompress": "lzip -d",
450 + "package": "app-arch/lzip",
451 + },
452 + "lzop": {
453 + "compress": "lzop ${BINPKG_COMPRESSION_ARGS}",
454 + "decompress": "lzop -d",
455 + "package": "app-arch/lzop",
456 + },
457 + "xz": {
458 + "compress": "xz ${BINPKG_COMPRESSION_ARGS}",
459 + "decompress": "xz -d",
460 + "package": "app-arch/xz-utils",
461 + },
462 + "zstd": {
463 + "compress": "zstd ${BINPKG_COMPRESSION_ARGS}",
464 + "decompress": "zstd -d",
465 + "package": "app-arch/zstd",
466 + },
467 }
468
469 _compression_re = re.compile(b'^(' +