commit: 937d0156aa060bdba9095313dedbb62e0a993aea Author: Zac Medico <zmedico <AT> gentoo <DOT> org> AuthorDate: Wed Jun 6 01:52:59 2018 +0000 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> CommitDate: Wed Jun 6 02:09:55 2018 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=937d0156
CompositeTask: handle SIGINT/TERM cancelled futures (bug 657436) In order to avoid raising an unwanted CancelledError, make CompositeTask check for cancelled futures before attempting to call future.result(). The intention is only to handle failures triggered by SIGINT/TERM, since other types of expected failures should always be handled by catching the exception raised from future.result(). Bug: https://bugs.gentoo.org/657436 pym/_emerge/Binpkg.py | 10 +++++++++- pym/_emerge/BinpkgFetcher.py | 8 ++++++++ pym/_emerge/CompositeTask.py | 1 + pym/_emerge/EbuildBuild.py | 16 ++++++++++++++++ pym/_emerge/EbuildFetcher.py | 12 ++++++++++++ pym/_emerge/EbuildPhase.py | 4 ++++ pym/_emerge/PackageUninstall.py | 8 ++++++++ pym/portage/_emirrordist/FetchIterator.py | 10 ++++++++++ 8 files changed, 68 insertions(+), 1 deletion(-) diff --git a/pym/_emerge/Binpkg.py b/pym/_emerge/Binpkg.py index 2b67816e8..7791ec236 100644 --- a/pym/_emerge/Binpkg.py +++ b/pym/_emerge/Binpkg.py @@ -122,6 +122,10 @@ class Binpkg(CompositeTask): def _start_fetcher(self, lock_task=None): if lock_task is not None: self._assert_current(lock_task) + if lock_task.cancelled: + self._default_final_exit(lock_task) + return + lock_task.future.result() # Initialize PORTAGE_LOG_FILE (clean_log won't work without it). portage.prepare_build_dirs(self.settings["ROOT"], self.settings, 1) @@ -411,8 +415,12 @@ class Binpkg(CompositeTask): def _unlock_builddir_exit(self, unlock_task, returncode=None): self._assert_current(unlock_task) + if unlock_task.cancelled and returncode is not None: + self._default_final_exit(unlock_task) + return + # Normally, async_unlock should not raise an exception here. - unlock_task.future.result() + unlock_task.future.cancelled() or unlock_task.future.result() if returncode is not None: self.returncode = returncode self._async_wait() diff --git a/pym/_emerge/BinpkgFetcher.py b/pym/_emerge/BinpkgFetcher.py index 8e651a1c7..36d027de3 100644 --- a/pym/_emerge/BinpkgFetcher.py +++ b/pym/_emerge/BinpkgFetcher.py @@ -48,6 +48,10 @@ class BinpkgFetcher(CompositeTask): 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) @@ -65,6 +69,10 @@ class BinpkgFetcher(CompositeTask): 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 + unlock_task.future.result() self._current_task = None diff --git a/pym/_emerge/CompositeTask.py b/pym/_emerge/CompositeTask.py index 4662f0cf5..1edec4a17 100644 --- a/pym/_emerge/CompositeTask.py +++ b/pym/_emerge/CompositeTask.py @@ -69,6 +69,7 @@ class CompositeTask(AsynchronousTask): self._assert_current(task) if task.returncode != os.EX_OK: self.returncode = task.returncode + self.cancelled = task.cancelled self._current_task = None return task.returncode diff --git a/pym/_emerge/EbuildBuild.py b/pym/_emerge/EbuildBuild.py index d9f7f6da7..8d264dd1c 100644 --- a/pym/_emerge/EbuildBuild.py +++ b/pym/_emerge/EbuildBuild.py @@ -54,6 +54,10 @@ class EbuildBuild(CompositeTask): def _start_with_metadata(self, aux_get_task): self._assert_current(aux_get_task) + if aux_get_task.cancelled: + self._default_final_exit(aux_get_task) + return + pkg = self.pkg settings = self.settings root_config = pkg.root_config @@ -178,6 +182,10 @@ class EbuildBuild(CompositeTask): def _start_pre_clean(self, lock_task): self._assert_current(lock_task) + if lock_task.cancelled: + self._default_final_exit(lock_task) + return + lock_task.future.result() # Cleaning needs to happen before fetch, since the build dir # is used for log handling. @@ -235,6 +243,10 @@ class EbuildBuild(CompositeTask): def _start_fetch(self, fetcher, already_fetched_task): self._assert_current(already_fetched_task) + if already_fetched_task.cancelled: + self._default_final_exit(already_fetched_task) + return + try: already_fetched = already_fetched_task.future.result() except portage.exception.InvalidDependString as e: @@ -342,6 +354,10 @@ class EbuildBuild(CompositeTask): def _unlock_builddir_exit(self, unlock_task, returncode=None): self._assert_current(unlock_task) + if unlock_task.cancelled: + self._default_final_exit(unlock_task) + return + # Normally, async_unlock should not raise an exception here. unlock_task.future.result() if returncode is not None: diff --git a/pym/_emerge/EbuildFetcher.py b/pym/_emerge/EbuildFetcher.py index 3b30ebb59..ad5109c28 100644 --- a/pym/_emerge/EbuildFetcher.py +++ b/pym/_emerge/EbuildFetcher.py @@ -47,6 +47,10 @@ class EbuildFetcher(CompositeTask): def _start_fetch(self, uri_map_task): self._assert_current(uri_map_task) + if uri_map_task.cancelled: + self._default_final_exit(uri_map_task) + return + try: uri_map = uri_map_task.future.result() except portage.exception.InvalidDependString as e: @@ -71,6 +75,10 @@ class EbuildFetcher(CompositeTask): def _start_with_metadata(self, aux_get_task): self._assert_current(aux_get_task) + if aux_get_task.cancelled: + self._default_final_exit(aux_get_task) + return + self._fetcher_proc.src_uri, = aux_get_task.future.result() self._start_task(self._fetcher_proc, self._default_final_exit) @@ -85,6 +93,10 @@ class _EbuildFetcherProcess(ForkProcess): result = self.scheduler.create_future() def uri_map_done(uri_map_future): + if uri_map_future.cancelled(): + result.cancel() + return + if uri_map_future.exception() is not None or result.cancelled(): if not result.cancelled(): result.set_exception(uri_map_future.exception()) diff --git a/pym/_emerge/EbuildPhase.py b/pym/_emerge/EbuildPhase.py index d057dc45e..4104cefa7 100644 --- a/pym/_emerge/EbuildPhase.py +++ b/pym/_emerge/EbuildPhase.py @@ -211,6 +211,10 @@ class EbuildPhase(CompositeTask): def _ebuild_exit_unlocked(self, ebuild_process, 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 + # Normally, async_unlock should not raise an exception here. unlock_task.future.result() diff --git a/pym/_emerge/PackageUninstall.py b/pym/_emerge/PackageUninstall.py index 3fe1fb0a6..cb3413056 100644 --- a/pym/_emerge/PackageUninstall.py +++ b/pym/_emerge/PackageUninstall.py @@ -61,6 +61,10 @@ class PackageUninstall(CompositeTask): def _start_unmerge(self, lock_task): self._assert_current(lock_task) + if lock_task.cancelled: + self._default_final_exit(lock_task) + return + lock_task.future.result() portage.prepare_build_dirs( settings=self.settings, cleanup=True) @@ -112,6 +116,10 @@ class PackageUninstall(CompositeTask): def _unlock_builddir_exit(self, unlock_task, returncode=None): self._assert_current(unlock_task) + if unlock_task.cancelled: + self._default_final_exit(unlock_task) + return + # Normally, async_unlock should not raise an exception here. unlock_task.future.result() if returncode is not None: diff --git a/pym/portage/_emirrordist/FetchIterator.py b/pym/portage/_emirrordist/FetchIterator.py index 04d4da62b..4ad797502 100644 --- a/pym/portage/_emirrordist/FetchIterator.py +++ b/pym/portage/_emirrordist/FetchIterator.py @@ -135,11 +135,21 @@ def _async_fetch_tasks(config, hash_filter, repo_config, digests_future, cpv, if not gather_result.cancelled(): list(future.exception() for future in gather_result.result() if not future.cancelled()) + else: + result.cancel() if result.cancelled(): return aux_get_result, fetch_map_result = gather_result.result() + if aux_get_result.cancelled() or fetch_map_result.cancelled(): + # Cancel result after consuming any exceptions which + # are now irrelevant due to cancellation. + aux_get_result.cancelled() or aux_get_result.exception() + fetch_map_result.cancelled() or fetch_map_result.exception() + result.cancel() + return + try: restrict, = aux_get_result.result() except (PortageKeyError, PortageException) as e:
