From c7e52d0466211907d20cdbc04f1e90e7da626694 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Mon, 17 Feb 2020 15:39:12 -0800 Subject: [PATCH] EbuildPhase: add _async_start coroutine Convert the _start method to an _async_start coroutine, since eventually this method will need to be a coroutine in order to write messages to the build log as discussed in bug 709746. Also convert SequentialTaskQueue to use the async_start method, which is now required in order to start EbuildPhase instances. Bug: https://bugs.gentoo.org/709746 Signed-off-by: Zac Medico --- lib/_emerge/EbuildPhase.py | 21 +++++++++++---------- lib/_emerge/SequentialTaskQueue.py | 20 ++++++++++++++++---- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/lib/_emerge/EbuildPhase.py b/lib/_emerge/EbuildPhase.py index 234a273a09..63d0746da3 100644 --- a/lib/_emerge/EbuildPhase.py +++ b/lib/_emerge/EbuildPhase.py @@ -23,7 +23,7 @@ ) from portage.package.ebuild.prepare_build_dirs import (_prepare_workdir, _prepare_fake_distdir, _prepare_fake_filesdir) -from portage.util.futures.compat_coroutine import coroutine +from portage.util.futures.compat_coroutine import coroutine, coroutine_return from portage.util import writemsg from portage.util._async.AsyncTaskFuture import AsyncTaskFuture from portage.util.futures.executor.fork import ForkExecutor @@ -69,6 +69,10 @@ class EbuildPhase(CompositeTask): _locked_phases = ("setup", "preinst", "postinst", "prerm", "postrm") def _start(self): + self.scheduler.run_until_complete(self._async_start()) + + @coroutine + def _async_start(self): need_builddir = self.phase not in EbuildProcess._phases_without_builddir @@ -138,20 +142,17 @@ def _start(self): env_extractor = BinpkgEnvExtractor(background=self.background, scheduler=self.scheduler, settings=self.settings) if env_extractor.saved_env_exists(): - self._start_task(env_extractor, self._env_extractor_exit) - return + self._current_task = env_extractor + yield env_extractor.async_start() + yield env_extractor.async_wait() + if self._default_exit(env_extractor) != os.EX_OK: + self._async_wait() + coroutine_return() # If the environment.bz2 doesn't exist, then ebuild.sh will # source the ebuild as a fallback. self._start_lock() - def _env_extractor_exit(self, env_extractor): - if self._default_exit(env_extractor) != os.EX_OK: - self.wait() - return - - self._start_lock() - def _start_lock(self): if (self.phase in self._locked_phases and "ebuild-locks" in self.settings.features): diff --git a/lib/_emerge/SequentialTaskQueue.py b/lib/_emerge/SequentialTaskQueue.py index 80908936c7..a4555275f0 100644 --- a/lib/_emerge/SequentialTaskQueue.py +++ b/lib/_emerge/SequentialTaskQueue.py @@ -1,9 +1,12 @@ -# Copyright 1999-2012 Gentoo Foundation +# Copyright 1999-2020 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 from collections import deque +import functools import sys +from portage.util.futures import asyncio +from portage.util.futures.compat_coroutine import coroutine from portage.util.SlotObject import SlotObject class SequentialTaskQueue(SlotObject): @@ -41,18 +44,27 @@ def schedule(self): cancelled = getattr(task, "cancelled", None) if not cancelled: self.running_tasks.add(task) - task.addExitListener(self._task_exit) - task.start() + future = asyncio.ensure_future(self._task_coroutine(task), loop=task.scheduler) + future.add_done_callback(functools.partial(self._task_exit, task)) finally: self._scheduling = False - def _task_exit(self, task): + @coroutine + def _task_coroutine(self, task): + yield task.async_start() + yield task.async_wait() + + def _task_exit(self, task, future): """ Since we can always rely on exit listeners being called, the set of running tasks is always pruned automatically and there is never any need to actively prune it. """ self.running_tasks.remove(task) + try: + future.result() + except asyncio.CancelledError: + self.clear() if self._task_queue: self.schedule()