1 |
commit: fa901a6510c4a5f72dec6aad86db6fe7efd6e7b3 |
2 |
Author: Sheng Yu <syu.os <AT> protonmail <DOT> com> |
3 |
AuthorDate: Tue Sep 6 18:38:27 2022 +0000 |
4 |
Commit: Michał Górny <mgorny <AT> gentoo <DOT> org> |
5 |
CommitDate: Fri Sep 9 10:16:06 2022 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=fa901a65 |
7 |
|
8 |
Add BUILD_ID to metadata during binary packaging |
9 |
|
10 |
Also create placeholder for new multi-instance package before actually |
11 |
packaging to avoid race. |
12 |
|
13 |
Signed-off-by: Sheng Yu <syu.os <AT> protonmail.com> |
14 |
Closes: https://github.com/gentoo/portage/pull/893 |
15 |
Signed-off-by: Michał Górny <mgorny <AT> gentoo.org> |
16 |
|
17 |
bin/gpkg-helper.py | 4 +- |
18 |
bin/misc-functions.sh | 6 +- |
19 |
bin/quickpkg | 2 +- |
20 |
lib/_emerge/Binpkg.py | 2 +- |
21 |
lib/_emerge/BinpkgFetcher.py | 27 ++-- |
22 |
lib/_emerge/BinpkgPrefetcher.py | 8 +- |
23 |
lib/_emerge/EbuildBinpkg.py | 35 +++-- |
24 |
lib/_emerge/Scheduler.py | 2 +- |
25 |
lib/portage/dbapi/bintree.py | 145 +++++++++++---------- |
26 |
.../package/ebuild/_config/special_env_vars.py | 1 + |
27 |
lib/portage/package/ebuild/doebuild.py | 3 +- |
28 |
11 files changed, 126 insertions(+), 109 deletions(-) |
29 |
|
30 |
diff --git a/bin/gpkg-helper.py b/bin/gpkg-helper.py |
31 |
index d45177f3e..4752c84ee 100755 |
32 |
--- a/bin/gpkg-helper.py |
33 |
+++ b/bin/gpkg-helper.py |
34 |
@@ -19,7 +19,7 @@ def command_compose(args): |
35 |
sys.stderr.write("4 arguments are required, got %s\n" % len(args)) |
36 |
return 1 |
37 |
|
38 |
- cpv, binpkg_path, metadata_dir, image_dir = args |
39 |
+ basename, binpkg_path, metadata_dir, image_dir = args |
40 |
|
41 |
if not os.path.isdir(metadata_dir): |
42 |
sys.stderr.write(usage) |
43 |
@@ -31,7 +31,7 @@ def command_compose(args): |
44 |
sys.stderr.write("Argument 4 is not a directory: '%s'\n" % image_dir) |
45 |
return 1 |
46 |
|
47 |
- gpkg_file = portage.gpkg.gpkg(portage.settings, cpv, binpkg_path) |
48 |
+ gpkg_file = portage.gpkg.gpkg(portage.settings, basename, binpkg_path) |
49 |
metadata = gpkg_file._generate_metadata_from_dir(metadata_dir) |
50 |
gpkg_file.compress(image_dir, metadata) |
51 |
return os.EX_OK |
52 |
|
53 |
diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh |
54 |
index faa8184c6..170e60d1c 100755 |
55 |
--- a/bin/misc-functions.sh |
56 |
+++ b/bin/misc-functions.sh |
57 |
@@ -512,6 +512,10 @@ __dyn_package() { |
58 |
die "PORTAGE_BINPKG_TMPFILE is unset" |
59 |
mkdir -p "${PORTAGE_BINPKG_TMPFILE%/*}" || die "mkdir failed" |
60 |
|
61 |
+ if [[ ! -z "${BUILD_ID}" ]]; then |
62 |
+ echo -n "${BUILD_ID}" > "${PORTAGE_BUILDDIR}"/build-info/BUILD_ID |
63 |
+ fi |
64 |
+ |
65 |
if [[ "${BINPKG_FORMAT}" == "xpak" ]]; then |
66 |
local tar_options="" |
67 |
|
68 |
@@ -547,7 +551,7 @@ __dyn_package() { |
69 |
elif [[ "${BINPKG_FORMAT}" == "gpkg" ]]; then |
70 |
PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ |
71 |
"${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}"/gpkg-helper.py compress \ |
72 |
- "${CATEGORY}/${PF}" "${PORTAGE_BINPKG_TMPFILE}" "${PORTAGE_BUILDDIR}/build-info" "${D}" |
73 |
+ "${PF}${BUILD_ID:+-${BUILD_ID}}" "${PORTAGE_BINPKG_TMPFILE}" "${PORTAGE_BUILDDIR}/build-info" "${D}" |
74 |
if [[ $? -ne 0 ]]; then |
75 |
rm -f "${PORTAGE_BINPKG_TMPFILE}" |
76 |
die "Failed to create binpkg file" |
77 |
|
78 |
diff --git a/bin/quickpkg b/bin/quickpkg |
79 |
index 773c1c07e..eef5f912f 100755 |
80 |
--- a/bin/quickpkg |
81 |
+++ b/bin/quickpkg |
82 |
@@ -206,7 +206,7 @@ def quickpkg_atom(options, infos, arg, eout): |
83 |
finally: |
84 |
if have_lock: |
85 |
dblnk.unlockdb() |
86 |
- pkg_info = bintree.inject(cpv, filename=binpkg_tmpfile) |
87 |
+ pkg_info = bintree.inject(cpv, current_pkg_path=binpkg_tmpfile) |
88 |
# The pkg_info value ensures that the following getname call |
89 |
# returns the correct path when FEATURES=binpkg-multi-instance |
90 |
# is enabled, but fallback to cpv in case the inject call |
91 |
|
92 |
diff --git a/lib/_emerge/Binpkg.py b/lib/_emerge/Binpkg.py |
93 |
index 15eb56092..949ac8ee7 100644 |
94 |
--- a/lib/_emerge/Binpkg.py |
95 |
+++ b/lib/_emerge/Binpkg.py |
96 |
@@ -246,7 +246,7 @@ class Binpkg(CompositeTask): |
97 |
|
98 |
if self._fetched_pkg: |
99 |
pkg_path = self._bintree.getname( |
100 |
- self._bintree.inject(pkg.cpv, filename=self._fetched_pkg), |
101 |
+ self._bintree.inject(pkg.cpv, current_pkg_path=self._fetched_pkg), |
102 |
allocate_new=False, |
103 |
) |
104 |
else: |
105 |
|
106 |
diff --git a/lib/_emerge/BinpkgFetcher.py b/lib/_emerge/BinpkgFetcher.py |
107 |
index d5275ea11..b7021e276 100644 |
108 |
--- a/lib/_emerge/BinpkgFetcher.py |
109 |
+++ b/lib/_emerge/BinpkgFetcher.py |
110 |
@@ -12,6 +12,7 @@ import sys |
111 |
import portage |
112 |
from portage import os |
113 |
from portage.const import SUPPORTED_GENTOO_BINPKG_FORMATS |
114 |
+from portage.const import SUPPORTED_XPAK_EXTENSIONS, SUPPORTED_GPKG_EXTENSIONS |
115 |
from portage.exception import FileNotFound, InvalidBinaryPackageFormat |
116 |
from portage.util._async.AsyncTaskFuture import AsyncTaskFuture |
117 |
from portage.util._pty import _create_pty_or_pipe |
118 |
@@ -19,27 +20,31 @@ from portage.util._pty import _create_pty_or_pipe |
119 |
|
120 |
class BinpkgFetcher(CompositeTask): |
121 |
|
122 |
- __slots__ = ("pkg", "pretend", "logfile", "pkg_path") |
123 |
+ __slots__ = ("pkg", "pretend", "logfile", "pkg_path", "pkg_allocated_path") |
124 |
|
125 |
def __init__(self, **kwargs): |
126 |
CompositeTask.__init__(self, **kwargs) |
127 |
|
128 |
pkg = self.pkg |
129 |
bintree = pkg.root_config.trees["bintree"] |
130 |
- binpkg_path = None |
131 |
+ instance_key = bintree.dbapi._instance_key(pkg.cpv) |
132 |
+ binpkg_format = bintree._remotepkgs[instance_key].get("BINPKG_FORMAT", None) |
133 |
|
134 |
- if bintree._remote_has_index: |
135 |
- instance_key = bintree.dbapi._instance_key(pkg.cpv) |
136 |
+ if binpkg_format is None: |
137 |
binpkg_path = bintree._remotepkgs[instance_key].get("PATH") |
138 |
- if binpkg_path: |
139 |
- self.pkg_path = binpkg_path + ".partial" |
140 |
+ if binpkg_path.endswith(SUPPORTED_XPAK_EXTENSIONS): |
141 |
+ binpkg_format = "xpak" |
142 |
+ elif binpkg_path.endswith(SUPPORTED_GPKG_EXTENSIONS): |
143 |
+ binpkg_format = "gpkg" |
144 |
else: |
145 |
- self.pkg_path = ( |
146 |
- pkg.root_config.trees["bintree"].getname(pkg.cpv, allocate_new=True) |
147 |
- + ".partial" |
148 |
+ raise InvalidBinaryPackageFormat( |
149 |
+ f"Unsupported binary package format from '{binpkg_path}'" |
150 |
) |
151 |
- else: |
152 |
- raise FileNotFound("Binary packages index not found") |
153 |
+ |
154 |
+ self.pkg_allocated_path = pkg.root_config.trees["bintree"].getname( |
155 |
+ pkg.cpv, allocate_new=True, remote_binpkg_format=binpkg_format |
156 |
+ ) |
157 |
+ self.pkg_path = self.pkg_allocated_path + ".partial" |
158 |
|
159 |
def _start(self): |
160 |
fetcher = _BinpkgFetcherProcess( |
161 |
|
162 |
diff --git a/lib/_emerge/BinpkgPrefetcher.py b/lib/_emerge/BinpkgPrefetcher.py |
163 |
index 3df9ebd76..912673bd1 100644 |
164 |
--- a/lib/_emerge/BinpkgPrefetcher.py |
165 |
+++ b/lib/_emerge/BinpkgPrefetcher.py |
166 |
@@ -11,6 +11,7 @@ class BinpkgPrefetcher(CompositeTask): |
167 |
|
168 |
__slots__ = ("pkg",) + ( |
169 |
"pkg_path", |
170 |
+ "pkg_allocated_path", |
171 |
"_bintree", |
172 |
) |
173 |
|
174 |
@@ -23,6 +24,7 @@ class BinpkgPrefetcher(CompositeTask): |
175 |
scheduler=self.scheduler, |
176 |
) |
177 |
self.pkg_path = fetcher.pkg_path |
178 |
+ self.pkg_allocated_path = fetcher.pkg_allocated_path |
179 |
self._start_task(fetcher, self._fetcher_exit) |
180 |
|
181 |
def _fetcher_exit(self, fetcher): |
182 |
@@ -45,7 +47,11 @@ class BinpkgPrefetcher(CompositeTask): |
183 |
self.wait() |
184 |
return |
185 |
|
186 |
- self._bintree.inject(self.pkg.cpv, filename=self.pkg_path) |
187 |
+ self._bintree.inject( |
188 |
+ self.pkg.cpv, |
189 |
+ current_pkg_path=self.pkg_path, |
190 |
+ allocated_pkg_path=self.pkg_allocated_path, |
191 |
+ ) |
192 |
|
193 |
self._current_task = None |
194 |
self.returncode = os.EX_OK |
195 |
|
196 |
diff --git a/lib/_emerge/EbuildBinpkg.py b/lib/_emerge/EbuildBinpkg.py |
197 |
index ccdd30f7b..04a17f283 100644 |
198 |
--- a/lib/_emerge/EbuildBinpkg.py |
199 |
+++ b/lib/_emerge/EbuildBinpkg.py |
200 |
@@ -6,8 +6,6 @@ from _emerge.EbuildPhase import EbuildPhase |
201 |
|
202 |
import portage |
203 |
from portage import os |
204 |
-from portage.const import SUPPORTED_GENTOO_BINPKG_FORMATS |
205 |
-from portage.exception import InvalidBinaryPackageFormat |
206 |
|
207 |
|
208 |
class EbuildBinpkg(CompositeTask): |
209 |
@@ -15,30 +13,27 @@ class EbuildBinpkg(CompositeTask): |
210 |
This assumes that src_install() has successfully completed. |
211 |
""" |
212 |
|
213 |
- __slots__ = ("pkg", "settings") + ("_binpkg_tmpfile", "_binpkg_info") |
214 |
+ __slots__ = ("pkg", "settings") + ( |
215 |
+ "_binpkg_tmpfile", |
216 |
+ "_binpkg_info", |
217 |
+ "pkg_allocated_path", |
218 |
+ ) |
219 |
|
220 |
def _start(self): |
221 |
pkg = self.pkg |
222 |
root_config = pkg.root_config |
223 |
bintree = root_config.trees["bintree"] |
224 |
- binpkg_format = self.settings.get( |
225 |
- "BINPKG_FORMAT", SUPPORTED_GENTOO_BINPKG_FORMATS[0] |
226 |
+ pkg_allocated_path, build_id = bintree.getname_build_id( |
227 |
+ pkg.cpv, allocate_new=True |
228 |
) |
229 |
- if binpkg_format == "xpak": |
230 |
- binpkg_tmpfile = os.path.join( |
231 |
- bintree.pkgdir, pkg.cpv + ".tbz2." + str(portage.getpid()) |
232 |
- ) |
233 |
- elif binpkg_format == "gpkg": |
234 |
- binpkg_tmpfile = os.path.join( |
235 |
- bintree.pkgdir, pkg.cpv + ".gpkg.tar." + str(portage.getpid()) |
236 |
- ) |
237 |
- else: |
238 |
- raise InvalidBinaryPackageFormat(binpkg_format) |
239 |
- bintree._ensure_dir(os.path.dirname(binpkg_tmpfile)) |
240 |
|
241 |
- self._binpkg_tmpfile = binpkg_tmpfile |
242 |
+ self.pkg_allocated_path = pkg_allocated_path |
243 |
+ self._binpkg_tmpfile = self.pkg_allocated_path + "." + str(portage.getpid()) |
244 |
self.settings["PORTAGE_BINPKG_TMPFILE"] = self._binpkg_tmpfile |
245 |
|
246 |
+ if "binpkg-multi-instance" in self.settings.features: |
247 |
+ self.settings["BUILD_ID"] = str(build_id) |
248 |
+ |
249 |
package_phase = EbuildPhase( |
250 |
background=self.background, |
251 |
phase="package", |
252 |
@@ -61,7 +56,11 @@ class EbuildBinpkg(CompositeTask): |
253 |
|
254 |
pkg = self.pkg |
255 |
bintree = pkg.root_config.trees["bintree"] |
256 |
- self._binpkg_info = bintree.inject(pkg.cpv, filename=self._binpkg_tmpfile) |
257 |
+ self._binpkg_info = bintree.inject( |
258 |
+ pkg.cpv, |
259 |
+ current_pkg_path=self._binpkg_tmpfile, |
260 |
+ allocated_pkg_path=self.pkg_allocated_path, |
261 |
+ ) |
262 |
|
263 |
self._current_task = None |
264 |
self.returncode = os.EX_OK |
265 |
|
266 |
diff --git a/lib/_emerge/Scheduler.py b/lib/_emerge/Scheduler.py |
267 |
index bc3531627..9e210f182 100644 |
268 |
--- a/lib/_emerge/Scheduler.py |
269 |
+++ b/lib/_emerge/Scheduler.py |
270 |
@@ -975,7 +975,7 @@ class Scheduler(PollScheduler): |
271 |
continue |
272 |
|
273 |
if fetched: |
274 |
- bintree.inject(x.cpv, filename=fetched) |
275 |
+ bintree.inject(x.cpv, current_pkg_path=fetched) |
276 |
|
277 |
infloc = os.path.join(build_dir_path, "build-info") |
278 |
ensure_dirs(infloc) |
279 |
|
280 |
diff --git a/lib/portage/dbapi/bintree.py b/lib/portage/dbapi/bintree.py |
281 |
index 814e6627c..7f5dc051c 100644 |
282 |
--- a/lib/portage/dbapi/bintree.py |
283 |
+++ b/lib/portage/dbapi/bintree.py |
284 |
@@ -47,6 +47,7 @@ from portage.exception import ( |
285 |
from portage.localization import _ |
286 |
from portage.output import colorize |
287 |
from portage.package.ebuild.profile_iuse import iter_iuse_vars |
288 |
+from portage.util import ensure_dirs |
289 |
from portage.util.file_copy import copyfile |
290 |
from portage.util.futures import asyncio |
291 |
from portage.util.futures.executor.fork import ForkExecutor |
292 |
@@ -733,7 +734,8 @@ class binarytree: |
293 |
# assuming that it will be deleted by eclean-pkg when its |
294 |
# time comes. |
295 |
mynewcpv = _pkg_str(mynewcpv, metadata=metadata, db=self.dbapi) |
296 |
- update_path = self.getname(mynewcpv, allocate_new=True) + ".partial" |
297 |
+ allocated_pkg_path = self.getname(mynewcpv, allocate_new=True) |
298 |
+ update_path = allocated_pkg_path + ".partial" |
299 |
self._ensure_dir(os.path.dirname(update_path)) |
300 |
update_path_lock = None |
301 |
try: |
302 |
@@ -747,7 +749,11 @@ class binarytree: |
303 |
mybinpkg.update_metadata(mydata, new_basename=mynewcpv) |
304 |
else: |
305 |
raise InvalidBinaryPackageFormat(binpkg_format) |
306 |
- self.inject(mynewcpv, filename=update_path) |
307 |
+ self.inject( |
308 |
+ mynewcpv, |
309 |
+ current_pkg_path=update_path, |
310 |
+ allocated_pkg_path=allocated_pkg_path, |
311 |
+ ) |
312 |
finally: |
313 |
if update_path_lock is not None: |
314 |
try: |
315 |
@@ -1590,13 +1596,17 @@ class binarytree: |
316 |
self._additional_pkgs[instance_key] = pkg |
317 |
self.dbapi.cpv_inject(pkg) |
318 |
|
319 |
- def inject(self, cpv, filename=None): |
320 |
+ def inject(self, cpv, current_pkg_path=None, allocated_pkg_path=None): |
321 |
"""Add a freshly built package to the database. This updates |
322 |
$PKGDIR/Packages with the new package metadata (including MD5). |
323 |
@param cpv: The cpv of the new package to inject |
324 |
@type cpv: string |
325 |
- @param filename: File path of the package to inject, or None if it's |
326 |
- already in the location returned by getname() |
327 |
+ @param current_pkg_path: File path of the package to inject, |
328 |
+ or None if it's already in the location returned by getname() |
329 |
+ @type filename: string |
330 |
+ @rtype: _pkg_str or None |
331 |
+ @param allocated_pkg_path: File path of the package that was newly |
332 |
+ allocated or None if it's not allocated. |
333 |
@type filename: string |
334 |
@rtype: _pkg_str or None |
335 |
@return: A _pkg_str instance on success, or None on failure. |
336 |
@@ -1604,10 +1614,10 @@ class binarytree: |
337 |
mycat, mypkg = catsplit(cpv) |
338 |
if not self.populated: |
339 |
self.populate() |
340 |
- if filename is None: |
341 |
+ if current_pkg_path is None: |
342 |
full_path = self.getname(cpv) |
343 |
else: |
344 |
- full_path = filename |
345 |
+ full_path = current_pkg_path |
346 |
try: |
347 |
s = os.stat(full_path) |
348 |
except OSError as e: |
349 |
@@ -1615,7 +1625,7 @@ class binarytree: |
350 |
raise |
351 |
del e |
352 |
writemsg( |
353 |
- _("!!! Binary package does not exist: '%s'\n") % full_path, |
354 |
+ f"!!! Binary package does not exist: '{full_path}'\n", |
355 |
noiselevel=-1, |
356 |
) |
357 |
return |
358 |
@@ -1664,48 +1674,19 @@ class binarytree: |
359 |
try: |
360 |
os.makedirs(self.pkgdir, exist_ok=True) |
361 |
pkgindex_lock = lockfile(self._pkgindex_file, wantnewlockfile=1) |
362 |
- if filename is not None: |
363 |
- new_filename = self.getname(cpv, allocate_new=True) |
364 |
+ if current_pkg_path is not None: |
365 |
+ if allocated_pkg_path is not None: |
366 |
+ new_path = allocated_pkg_path |
367 |
+ else: |
368 |
+ new_path = self.getname(cpv, allocate_new=True) |
369 |
try: |
370 |
- samefile = os.path.samefile(filename, new_filename) |
371 |
+ samefile = os.path.samefile(current_pkg_path, new_path) |
372 |
except OSError: |
373 |
samefile = False |
374 |
if not samefile: |
375 |
- self._ensure_dir(os.path.dirname(new_filename)) |
376 |
- _movefile(filename, new_filename, mysettings=self.settings) |
377 |
- full_path = new_filename |
378 |
- |
379 |
- basename = os.path.basename(full_path) |
380 |
- pf = catsplit(cpv)[1] |
381 |
- if (build_id is None) and (not fetched) and binpkg_format: |
382 |
- # Apply the newly assigned BUILD_ID. This is intended |
383 |
- # to occur only for locally built packages. If the |
384 |
- # package was fetched, we want to preserve its |
385 |
- # attributes, so that we can later distinguish that it |
386 |
- # is identical to its remote counterpart. |
387 |
- build_id = self._parse_build_id(basename) |
388 |
- if build_id > 0: |
389 |
- metadata["BUILD_ID"] = str(build_id) |
390 |
- cpv = _pkg_str( |
391 |
- cpv, metadata=metadata, settings=self.settings, db=self.dbapi |
392 |
- ) |
393 |
- if binpkg_format == "xpak": |
394 |
- if basename.endswith(".xpak"): |
395 |
- binpkg = portage.xpak.tbz2(full_path) |
396 |
- binary_data = binpkg.get_data() |
397 |
- binary_data[b"BUILD_ID"] = _unicode_encode( |
398 |
- metadata["BUILD_ID"] |
399 |
- ) |
400 |
- binpkg.recompose_mem(portage.xpak.xpak_mem(binary_data)) |
401 |
- elif binpkg_format == "gpkg": |
402 |
- binpkg = portage.gpkg.gpkg(self.settings, cpv, full_path) |
403 |
- binpkg_metadata = binpkg.get_metadata() |
404 |
- binpkg_metadata["BUILD_ID"] = _unicode_encode( |
405 |
- metadata["BUILD_ID"] |
406 |
- ) |
407 |
- binpkg.update_metadata(binpkg_metadata) |
408 |
- else: |
409 |
- raise InvalidBinaryPackageFormat(basename) |
410 |
+ self._ensure_dir(os.path.dirname(new_path)) |
411 |
+ _movefile(current_pkg_path, new_path, mysettings=self.settings) |
412 |
+ full_path = new_path |
413 |
|
414 |
self._file_permissions(full_path) |
415 |
pkgindex = self._load_pkgindex() |
416 |
@@ -2055,7 +2036,12 @@ class binarytree: |
417 |
return "" |
418 |
return mymatch |
419 |
|
420 |
- def getname(self, cpv, allocate_new=None): |
421 |
+ def getname(self, cpv, allocate_new=None, remote_binpkg_format=None): |
422 |
+ return self.getname_build_id( |
423 |
+ cpv, allocate_new=allocate_new, remote_binpkg_format=remote_binpkg_format |
424 |
+ )[0] |
425 |
+ |
426 |
+ def getname_build_id(self, cpv, allocate_new=None, remote_binpkg_format=None): |
427 |
"""Returns a file location for this package. |
428 |
If cpv has both build_time and build_id attributes, then the |
429 |
path to the specific corresponding instance is returned. |
430 |
@@ -2072,8 +2058,9 @@ class binarytree: |
431 |
cpv = _pkg_str(cpv) |
432 |
|
433 |
filename = None |
434 |
+ build_id = None |
435 |
if allocate_new: |
436 |
- filename = self._allocate_filename(cpv) |
437 |
+ filename, build_id = self._allocate_filename(cpv) |
438 |
elif self._is_specific_instance(cpv): |
439 |
instance_key = self.dbapi._instance_key(cpv) |
440 |
path = self._pkg_paths.get(instance_key) |
441 |
@@ -2090,7 +2077,7 @@ class binarytree: |
442 |
if filename is not None: |
443 |
filename = os.path.join(self.pkgdir, filename) |
444 |
elif instance_key in self._additional_pkgs: |
445 |
- return None |
446 |
+ return (None, None) |
447 |
|
448 |
if filename is None: |
449 |
try: |
450 |
@@ -2133,7 +2120,7 @@ class binarytree: |
451 |
else: |
452 |
raise InvalidBinaryPackageFormat(binpkg_format) |
453 |
|
454 |
- return filename |
455 |
+ return (filename, build_id) |
456 |
|
457 |
def _is_specific_instance(self, cpv): |
458 |
specific = True |
459 |
@@ -2154,22 +2141,26 @@ class binarytree: |
460 |
max_build_id = x.build_id |
461 |
return max_build_id |
462 |
|
463 |
- def _allocate_filename(self, cpv): |
464 |
- try: |
465 |
- binpkg_format = cpv.binpkg_format |
466 |
- except AttributeError: |
467 |
- binpkg_format = self.settings.get( |
468 |
- "BINPKG_FORMAT", SUPPORTED_GENTOO_BINPKG_FORMATS[0] |
469 |
- ) |
470 |
+ def _allocate_filename(self, cpv, remote_binpkg_format=None): |
471 |
+ if remote_binpkg_format is None: |
472 |
+ try: |
473 |
+ binpkg_format = cpv.binpkg_format |
474 |
+ except AttributeError: |
475 |
+ binpkg_format = self.settings.get( |
476 |
+ "BINPKG_FORMAT", SUPPORTED_GENTOO_BINPKG_FORMATS[0] |
477 |
+ ) |
478 |
+ else: |
479 |
+ binpkg_format = remote_binpkg_format |
480 |
|
481 |
+ # Do not create a new placeholder to avoid overwriting existing binpkgs. |
482 |
if binpkg_format == "xpak": |
483 |
- return os.path.join(self.pkgdir, cpv + ".tbz2") |
484 |
+ return (os.path.join(self.pkgdir, cpv + ".tbz2"), None) |
485 |
elif binpkg_format == "gpkg": |
486 |
- return os.path.join(self.pkgdir, cpv + ".gpkg.tar") |
487 |
+ return (os.path.join(self.pkgdir, cpv + ".gpkg.tar"), None) |
488 |
else: |
489 |
raise InvalidBinaryPackageFormat(binpkg_format) |
490 |
|
491 |
- def _allocate_filename_multi(self, cpv): |
492 |
+ def _allocate_filename_multi(self, cpv, remote_binpkg_format=None): |
493 |
|
494 |
# First, get the max build_id found when _populate was |
495 |
# called. |
496 |
@@ -2181,29 +2172,39 @@ class binarytree: |
497 |
pf = catsplit(cpv)[1] |
498 |
build_id = max_build_id + 1 |
499 |
|
500 |
- try: |
501 |
- binpkg_format = cpv.binpkg_format |
502 |
- except AttributeError: |
503 |
- binpkg_format = self.settings.get( |
504 |
- "BINPKG_FORMAT", SUPPORTED_GENTOO_BINPKG_FORMATS[0] |
505 |
- ) |
506 |
+ if remote_binpkg_format is None: |
507 |
+ try: |
508 |
+ binpkg_format = cpv.binpkg_format |
509 |
+ except AttributeError: |
510 |
+ binpkg_format = self.settings.get( |
511 |
+ "BINPKG_FORMAT", SUPPORTED_GENTOO_BINPKG_FORMATS[0] |
512 |
+ ) |
513 |
+ else: |
514 |
+ binpkg_format = remote_binpkg_format |
515 |
|
516 |
if binpkg_format == "xpak": |
517 |
- filename_format = "%s-%s.xpak" |
518 |
+ binpkg_suffix = "xpak" |
519 |
elif binpkg_format == "gpkg": |
520 |
- filename_format = "%s-%s.gpkg.tar" |
521 |
+ binpkg_suffix = "gpkg.tar" |
522 |
else: |
523 |
raise InvalidBinaryPackageFormat(binpkg_format) |
524 |
|
525 |
while True: |
526 |
- filename = filename_format % ( |
527 |
- os.path.join(self.pkgdir, cpv.cp, pf), |
528 |
- build_id, |
529 |
+ filename = ( |
530 |
+ f"{os.path.join(self.pkgdir, cpv.cp, pf)}-{build_id}.{binpkg_suffix}" |
531 |
) |
532 |
if os.path.exists(filename): |
533 |
build_id += 1 |
534 |
else: |
535 |
- return filename |
536 |
+ try: |
537 |
+ # Avoid races |
538 |
+ ensure_dirs(os.path.dirname(filename)) |
539 |
+ with open(filename, "x") as f: |
540 |
+ pass |
541 |
+ except FileExistsError: |
542 |
+ build_id += 1 |
543 |
+ continue |
544 |
+ return (filename, build_id) |
545 |
|
546 |
@staticmethod |
547 |
def _parse_build_id(filename): |
548 |
|
549 |
diff --git a/lib/portage/package/ebuild/_config/special_env_vars.py b/lib/portage/package/ebuild/_config/special_env_vars.py |
550 |
index 04e4c5b9b..1de62e421 100644 |
551 |
--- a/lib/portage/package/ebuild/_config/special_env_vars.py |
552 |
+++ b/lib/portage/package/ebuild/_config/special_env_vars.py |
553 |
@@ -88,6 +88,7 @@ environ_whitelist += [ |
554 |
"BASH_FUNC____in_portage_iuse%%", |
555 |
"BINPKG_FORMAT", |
556 |
"BROOT", |
557 |
+ "BUILD_ID", |
558 |
"BUILD_PREFIX", |
559 |
"COLUMNS", |
560 |
"D", |
561 |
|
562 |
diff --git a/lib/portage/package/ebuild/doebuild.py b/lib/portage/package/ebuild/doebuild.py |
563 |
index 8ee9f73c6..d0d134b39 100644 |
564 |
--- a/lib/portage/package/ebuild/doebuild.py |
565 |
+++ b/lib/portage/package/ebuild/doebuild.py |
566 |
@@ -1463,7 +1463,8 @@ def doebuild( |
567 |
if retval == os.EX_OK: |
568 |
if mydo == "package" and bintree is not None: |
569 |
pkg = bintree.inject( |
570 |
- mysettings.mycpv, filename=mysettings["PORTAGE_BINPKG_TMPFILE"] |
571 |
+ mysettings.mycpv, |
572 |
+ current_pkg_path=mysettings["PORTAGE_BINPKG_TMPFILE"], |
573 |
) |
574 |
if pkg is not None: |
575 |
infoloc = os.path.join( |