aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/_emerge/BinpkgFetcher.py')
-rw-r--r--lib/_emerge/BinpkgFetcher.py149
1 files changed, 101 insertions, 48 deletions
diff --git a/lib/_emerge/BinpkgFetcher.py b/lib/_emerge/BinpkgFetcher.py
index de3dd42ed..587e4a57a 100644
--- a/lib/_emerge/BinpkgFetcher.py
+++ b/lib/_emerge/BinpkgFetcher.py
@@ -1,8 +1,6 @@
-# Copyright 1999-2020 Gentoo Authors
+# Copyright 1999-2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
-import functools
-
from _emerge.AsynchronousLock import AsynchronousLock
from _emerge.CompositeTask import CompositeTask
from _emerge.SpawnProcess import SpawnProcess
@@ -11,20 +9,52 @@ import stat
import sys
import portage
from portage import os
+from portage.binpkg import get_binpkg_format
+from portage.exception import FileNotFound
from portage.util._async.AsyncTaskFuture import AsyncTaskFuture
+from portage.util._async.FileCopier import FileCopier
from portage.util._pty import _create_pty_or_pipe
class BinpkgFetcher(CompositeTask):
-
- __slots__ = ("pkg", "pretend", "logfile", "pkg_path")
+ __slots__ = ("pkg", "pretend", "logfile", "pkg_path", "pkg_allocated_path")
def __init__(self, **kwargs):
CompositeTask.__init__(self, **kwargs)
+
pkg = self.pkg
- self.pkg_path = pkg.root_config.trees["bintree"].getname(pkg.cpv) + ".partial"
+ bintree = pkg.root_config.trees["bintree"]
+ instance_key = bintree.dbapi._instance_key(pkg.cpv)
+
+ binpkg_path = bintree._remotepkgs[instance_key].get("PATH")
+ if not binpkg_path:
+ raise FileNotFound(
+ f"PATH not found in the binpkg index, the binhost's portage is probably out of date."
+ )
+ binpkg_format = get_binpkg_format(binpkg_path)
+
+ self.pkg_allocated_path = pkg.root_config.trees["bintree"].getname(
+ pkg.cpv, allocate_new=True, remote_binpkg_format=binpkg_format
+ )
+ self.pkg_path = self.pkg_allocated_path + ".partial"
def _start(self):
+ self._start_task(
+ AsyncTaskFuture(future=self._main(), scheduler=self.scheduler),
+ self._main_exit,
+ )
+
+ async def _main(self) -> int:
+ """
+ Main coroutine which saves the binary package to self.pkg_path
+ and returns the exit status of the fetcher or copier.
+
+ @rtype: int
+ @return: Exit status of fetcher or copier.
+ """
+ pkg = self.pkg
+ bintree = pkg.root_config.trees["bintree"]
+
fetcher = _BinpkgFetcherProcess(
background=self.background,
logfile=self.logfile,
@@ -37,51 +67,71 @@ class BinpkgFetcher(CompositeTask):
if not self.pretend:
portage.util.ensure_dirs(os.path.dirname(self.pkg_path))
if "distlocks" in self.pkg.root_config.settings.features:
- self._start_task(
- AsyncTaskFuture(future=fetcher.async_lock()),
- functools.partial(self._start_locked, fetcher),
- )
- return
+ await fetcher.async_lock()
+
+ try:
+ if bintree._remote_has_index:
+ remote_metadata = bintree._remotepkgs[
+ bintree.dbapi._instance_key(pkg.cpv)
+ ]
+ rel_uri = remote_metadata.get("PATH")
+ if not rel_uri:
+ # Assume that the remote index is out of date. No path should
+ # never happen in new portage versions.
+ rel_uri = pkg.cpv + ".tbz2"
+ remote_base_uri = remote_metadata["BASE_URI"]
+ uri = remote_base_uri.rstrip("/") + "/" + rel_uri.lstrip("/")
+ else:
+ raise FileNotFound("Binary packages index not found")
- self._start_task(fetcher, self._fetcher_exit)
+ uri_parsed = urllib_parse_urlparse(uri)
- def _start_locked(self, fetcher, lock_task):
- self._assert_current(lock_task)
- if lock_task.cancelled:
- self._default_final_exit(lock_task)
- return
-
- lock_task.future.result()
- self._start_task(fetcher, self._fetcher_exit)
-
- def _fetcher_exit(self, fetcher):
- self._assert_current(fetcher)
- if not self.pretend and fetcher.returncode == os.EX_OK:
- fetcher.sync_timestamp()
- if fetcher.locked:
- self._start_task(
- AsyncTaskFuture(future=fetcher.async_unlock()),
- functools.partial(self._fetcher_exit_unlocked, fetcher),
- )
- else:
- self._fetcher_exit_unlocked(fetcher)
+ copier = None
+ if not self.pretend and uri_parsed.scheme in ("", "file"):
+ copier = FileCopier(
+ src_path=uri_parsed.path,
+ dest_path=self.pkg_path,
+ scheduler=self.scheduler,
+ )
+ copier.start()
+ try:
+ await copier.async_wait()
+ copier.future.result()
+ except FileNotFoundError:
+ await self.scheduler.async_output(
+ f"!!! File not found: {uri_parsed.path}\n",
+ log_file=self.logfile,
+ background=self.background,
+ )
+ finally:
+ if copier.isAlive():
+ copier.cancel()
+ if copier.returncode == os.EX_OK:
+ fetcher.sync_timestamp()
+ else:
+ fetcher.start()
+ try:
+ await fetcher.async_wait()
+ finally:
+ if fetcher.isAlive():
+ fetcher.cancel()
- def _fetcher_exit_unlocked(self, fetcher, unlock_task=None):
- if unlock_task is not None:
- self._assert_current(unlock_task)
- if unlock_task.cancelled:
- self._default_final_exit(unlock_task)
- return
+ if not self.pretend and fetcher.returncode == os.EX_OK:
+ fetcher.sync_timestamp()
+ finally:
+ if fetcher.locked:
+ await fetcher.async_unlock()
- unlock_task.future.result()
+ return fetcher.returncode if copier is None else copier.returncode
- self._current_task = None
- self.returncode = fetcher.returncode
- self._async_wait()
+ def _main_exit(self, main_task):
+ if not main_task.cancelled:
+ # Use the fetcher or copier returncode.
+ main_task.returncode = main_task.future.result()
+ self._default_final_exit(main_task)
class _BinpkgFetcherProcess(SpawnProcess):
-
__slots__ = ("pkg", "pretend", "locked", "pkg_path", "_lock_obj")
def _start(self):
@@ -108,16 +158,18 @@ class _BinpkgFetcherProcess(SpawnProcess):
remote_metadata = bintree._remotepkgs[bintree.dbapi._instance_key(pkg.cpv)]
rel_uri = remote_metadata.get("PATH")
if not rel_uri:
+ # Assume that the remote index is out of date. No path should
+ # never happen in new portage versions.
rel_uri = pkg.cpv + ".tbz2"
remote_base_uri = remote_metadata["BASE_URI"]
uri = remote_base_uri.rstrip("/") + "/" + rel_uri.lstrip("/")
fetchcommand = remote_metadata.get("FETCHCOMMAND")
resumecommand = remote_metadata.get("RESUMECOMMAND")
else:
- uri = settings["PORTAGE_BINHOST"].rstrip("/") + "/" + pkg.pf + ".tbz2"
+ raise FileNotFound("Binary packages index not found")
if pretend:
- portage.writemsg_stdout("\n%s\n" % uri, noiselevel=-1)
+ portage.writemsg_stdout(f"\n{uri}\n", noiselevel=-1)
self.returncode = os.EX_OK
self._async_wait()
return
@@ -181,7 +233,9 @@ class _BinpkgFetcherProcess(SpawnProcess):
stdout_pipe = None
if not self.background:
stdout_pipe = fd_pipes.get(1)
- got_pty, master_fd, slave_fd = _create_pty_or_pipe(copy_term_size=stdout_pipe)
+ self._pty_ready, master_fd, slave_fd = _create_pty_or_pipe(
+ copy_term_size=stdout_pipe
+ )
return (master_fd, slave_fd)
def sync_timestamp(self):
@@ -228,8 +282,7 @@ class _BinpkgFetcherProcess(SpawnProcess):
else:
result.set_exception(
AssertionError(
- "AsynchronousLock failed with returncode %s"
- % (async_lock.returncode,)
+ f"AsynchronousLock failed with returncode {async_lock.returncode}"
)
)