diff options
Diffstat (limited to 'lib/_emerge/BinpkgFetcher.py')
-rw-r--r-- | lib/_emerge/BinpkgFetcher.py | 149 |
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}" ) ) |