commit:     67663e586320347e604727aef006bfe027bcd470
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon Feb 12 02:10:52 2024 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Mon Feb 12 13:57:42 2024 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=67663e58

EbuildBuild: Execute EbuildFetchonly in subprocess

Execute EbuildFetchonly in a subprocess since it needs to
run the event loop itself (even for pretend mode since it
may need to fetch mirror layouts as reported in bug 702154).

Also remove obsolete loop.is_running() case in doebuild
related to bug 601252, since it will fail if a mirror
layout file needs to be fetched, so we should just assume
that the event loop is not running.

Set fetched = 2 for listonly (pretend) mode in the fetch
function so that EbuildFetchonly will properly report
success for this mode.

Pass ebuild_path to EbuildFetchonly, and also remove
setcpv call from EbuildFetchonly since it's called earlier
in EbuildBuild.

Bug: https://bugs.gentoo.org/924287
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/_emerge/EbuildBuild.py             | 39 +++++++++++++++++-----------------
 lib/_emerge/EbuildFetchonly.py         | 10 +++------
 lib/portage/package/ebuild/doebuild.py | 30 ++++++++------------------
 lib/portage/package/ebuild/fetch.py    |  1 +
 4 files changed, 33 insertions(+), 47 deletions(-)

diff --git a/lib/_emerge/EbuildBuild.py b/lib/_emerge/EbuildBuild.py
index 81cbfdc085..d4a4c6dacb 100644
--- a/lib/_emerge/EbuildBuild.py
+++ b/lib/_emerge/EbuildBuild.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2020 Gentoo Authors
+# Copyright 1999-2024 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 import functools
@@ -22,6 +22,7 @@ from portage.package.ebuild.digestcheck import digestcheck
 from portage.package.ebuild.doebuild import _check_temp_dir
 from portage.package.ebuild._spawn_nofetch import SpawnNofetchWithoutBuilddir
 from portage.util._async.AsyncTaskFuture import AsyncTaskFuture
+from portage.util.futures.executor.fork import ForkExecutor
 from portage.util.path import first_existing
 
 
@@ -152,29 +153,25 @@ class EbuildBuild(CompositeTask):
         if opts.fetchonly:
             if opts.pretend:
                 fetcher = EbuildFetchonly(
+                    ebuild_path=self._ebuild_path,
                     fetch_all=opts.fetch_all_uri,
                     pkg=pkg,
                     pretend=opts.pretend,
                     settings=settings,
                 )
-                retval = fetcher.execute()
-                if retval == os.EX_OK:
-                    self._current_task = None
-                    self.returncode = os.EX_OK
-                    self._async_wait()
-                else:
-                    # For pretend mode, the convention it to execute
-                    # pkg_nofetch and return a successful exitcode.
-                    self._start_task(
-                        SpawnNofetchWithoutBuilddir(
-                            background=self.background,
-                            
portdb=self.pkg.root_config.trees[self._tree].dbapi,
-                            ebuild_path=self._ebuild_path,
-                            scheduler=self.scheduler,
-                            settings=self.settings,
+                # Execute EbuildFetchonly in a subprocess since it needs to
+                # run the event loop itself (even for pretend mode since it
+                # may need to fetch mirror layouts as reported in bug 702154).
+                self._start_task(
+                    AsyncTaskFuture(
+                        background=self.background,
+                        scheduler=self.scheduler,
+                        future=self.scheduler.run_in_executor(
+                            ForkExecutor(loop=self.scheduler), fetcher.execute
                         ),
-                        self._default_final_exit,
-                    )
+                    ),
+                    self._fetchonly_exit,
+                )
                 return
 
             quiet_setting = settings.get("PORTAGE_QUIET", False)
@@ -241,8 +238,12 @@ class EbuildBuild(CompositeTask):
         self._start_task(pre_clean_phase, self._pre_clean_exit)
 
     def _fetchonly_exit(self, fetcher):
+        if not fetcher.cancelled and isinstance(fetcher, AsyncTaskFuture):
+            # Set returncode from EbuildFetchonly.execute() result, since
+            # it can fail if it can't resolve a mirror for a file.
+            fetcher.returncode = fetcher.future.result()
         self._final_exit(fetcher)
-        if self.returncode != os.EX_OK:
+        if not self.cancelled and self.returncode != os.EX_OK:
             self.returncode = None
             portdb = self.pkg.root_config.trees[self._tree].dbapi
             self._start_task(

diff --git a/lib/_emerge/EbuildFetchonly.py b/lib/_emerge/EbuildFetchonly.py
index e887dd858d..c806122bea 100644
--- a/lib/_emerge/EbuildFetchonly.py
+++ b/lib/_emerge/EbuildFetchonly.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2012 Gentoo Foundation
+# Copyright 1999-2024 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 import portage
@@ -8,20 +8,16 @@ from portage.util.SlotObject import SlotObject
 
 
 class EbuildFetchonly(SlotObject):
-    __slots__ = ("fetch_all", "pkg", "pretend", "settings")
+    __slots__ = ("ebuild_path", "fetch_all", "pkg", "pretend", "settings")
 
     def execute(self):
         settings = self.settings
         pkg = self.pkg
         portdb = pkg.root_config.trees["porttree"].dbapi
-        ebuild_path = portdb.findname(pkg.cpv, myrepo=pkg.repo)
-        if ebuild_path is None:
-            raise AssertionError(f"ebuild not found for '{pkg.cpv}'")
-        settings.setcpv(pkg)
         debug = settings.get("PORTAGE_DEBUG") == "1"
 
         rval = portage.doebuild(
-            ebuild_path,
+            self.ebuild_path,
             "fetch",
             settings=settings,
             debug=debug,

diff --git a/lib/portage/package/ebuild/doebuild.py 
b/lib/portage/package/ebuild/doebuild.py
index 1c89af5ac8..4cf155e033 100644
--- a/lib/portage/package/ebuild/doebuild.py
+++ b/lib/portage/package/ebuild/doebuild.py
@@ -1334,32 +1334,20 @@ def doebuild(
                 dist_digests = mf.getTypeDigests("DIST")
 
             loop = asyncio._safe_loop()
-            if loop.is_running():
-                # Called by EbuildFetchonly for emerge --pretend --fetchonly.
-                success = fetch(
+            success = loop.run_until_complete(
+                loop.run_in_executor(
+                    ForkExecutor(loop=loop),
+                    _fetch_subprocess,
                     fetchme,
                     mysettings,
-                    listonly=listonly,
-                    fetchonly=fetchonly,
-                    allow_missing_digests=False,
-                    digests=dist_digests,
-                )
-            else:
-                success = loop.run_until_complete(
-                    loop.run_in_executor(
-                        ForkExecutor(loop=loop),
-                        _fetch_subprocess,
-                        fetchme,
-                        mysettings,
-                        listonly,
-                        dist_digests,
-                        fetchonly,
-                    )
+                    listonly,
+                    dist_digests,
+                    fetchonly,
                 )
+            )
             if not success:
                 # Since listonly mode is called by emerge --pretend in an
-                # asynchronous context, spawn_nofetch would trigger event loop
-                # recursion here, therefore delegate execution of pkg_nofetch
+                # asynchronous context, execution of pkg_nofetch is delegated
                 # to the caller (bug 657360).
                 if not listonly:
                     spawn_nofetch(

diff --git a/lib/portage/package/ebuild/fetch.py 
b/lib/portage/package/ebuild/fetch.py
index 5f970fe62d..bfa0c2b275 100644
--- a/lib/portage/package/ebuild/fetch.py
+++ b/lib/portage/package/ebuild/fetch.py
@@ -1562,6 +1562,7 @@ def fetch(
                 tried_locations.add(loc)
                 if listonly:
                     writemsg_stdout(loc + " ", noiselevel=-1)
+                    fetched = 2
                     continue
                 # allow different fetchcommands per protocol
                 protocol = loc[0 : loc.find("://")]

Reply via email to