In order to avoid event loop recursion, convert the
_BinpkgFetcherProcess.lock() method to an async_lock
method for use by BinpkgFetcher.

Bug: https://bugs.gentoo.org/614110
---
 pym/_emerge/BinpkgFetcher.py | 53 +++++++++++++++++++++++++++-----------------
 1 file changed, 33 insertions(+), 20 deletions(-)

diff --git a/pym/_emerge/BinpkgFetcher.py b/pym/_emerge/BinpkgFetcher.py
index 5ca7a45cf..2bbc0a26f 100644
--- a/pym/_emerge/BinpkgFetcher.py
+++ b/pym/_emerge/BinpkgFetcher.py
@@ -32,11 +32,24 @@ class BinpkgFetcher(CompositeTask):
                        pkg.cpv) + ".partial"
 
        def _start(self):
-               self._start_task(
-                       _BinpkgFetcherProcess(background=self.background,
-                               logfile=self.logfile, pkg=self.pkg, 
pkg_path=self.pkg_path,
-                               pretend=self.pretend, scheduler=self.scheduler),
-                       self._fetcher_exit)
+               fetcher = _BinpkgFetcherProcess(background=self.background,
+                       logfile=self.logfile, pkg=self.pkg, 
pkg_path=self.pkg_path,
+                       pretend=self.pretend, scheduler=self.scheduler)
+
+               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
+
+               self._start_task(fetcher, self._fetcher_exit)
+
+       def _start_locked(self, fetcher, lock_task):
+               self._assert_current(lock_task)
+               lock_task.future.result()
+               self._start_task(fetcher, self._fetcher_exit)
 
        def _fetcher_exit(self, fetcher):
                self._assert_current(fetcher)
@@ -68,13 +81,8 @@ class _BinpkgFetcherProcess(SpawnProcess):
                pretend = self.pretend
                bintree = pkg.root_config.trees["bintree"]
                settings = bintree.settings
-               use_locks = "distlocks" in settings.features
                pkg_path = self.pkg_path
 
-               if not pretend:
-                       portage.util.ensure_dirs(os.path.dirname(pkg_path))
-                       if use_locks:
-                               self.lock()
                exists = os.path.exists(pkg_path)
                resume = exists and os.path.basename(pkg_path) in 
bintree.invalids
                if not (pretend or resume):
@@ -184,7 +192,7 @@ class _BinpkgFetcherProcess(SpawnProcess):
                                                                except OSError:
                                                                        pass
 
-       def lock(self):
+       def async_lock(self):
                """
                This raises an AlreadyLocked exception if lock() is called
                while a lock is already held. In order to avoid this, call
@@ -194,17 +202,22 @@ class _BinpkgFetcherProcess(SpawnProcess):
                if self._lock_obj is not None:
                        raise self.AlreadyLocked((self._lock_obj,))
 
-               async_lock = AsynchronousLock(path=self.pkg_path,
-                       scheduler=self.scheduler)
-               async_lock.start()
+               result = self.scheduler.create_future()
 
-               if async_lock.wait() != os.EX_OK:
-                       # TODO: Use CompositeTask for better handling, like in 
EbuildPhase.
-                       raise AssertionError("AsynchronousLock failed with 
returncode %s" \
-                               % (async_lock.returncode,))
+               def acquired_lock(async_lock):
+                       if async_lock.wait() == os.EX_OK:
+                               self.locked = True
+                               result.set_result(None)
+                       else:
+                               result.set_exception(AssertionError(
+                                       "AsynchronousLock failed with 
returncode %s"
+                                       % (async_lock.returncode,)))
 
-               self._lock_obj = async_lock
-               self.locked = True
+               self._lock_obj = AsynchronousLock(path=self.pkg_path,
+                       scheduler=self.scheduler)
+               self._lock_obj.addExitListener(acquired_lock)
+               self._lock_obj.start()
+               return result
 
        class AlreadyLocked(portage.exception.PortageException):
                pass
-- 
2.13.6


Reply via email to