Add a portdbapi.async_fetch_map method which is identical to the
existing portdbapi.getFetchMap method, but returns a future. This
will be used by EbuildFetcher in order to avoid event loop recursion.

Bug: https://bugs.gentoo.org/653810
---
 pym/portage/dbapi/porttree.py | 75 +++++++++++++++++++++++++++++++++----------
 1 file changed, 58 insertions(+), 17 deletions(-)

diff --git a/pym/portage/dbapi/porttree.py b/pym/portage/dbapi/porttree.py
index 951e5760a..3cd929963 100644
--- a/pym/portage/dbapi/porttree.py
+++ b/pym/portage/dbapi/porttree.py
@@ -728,25 +728,66 @@ class portdbapi(dbapi):
                        URIs.
                @rtype: dict
                """
+               loop = self._event_loop
+               return loop.run_until_complete(
+                       self.async_fetch_map(mypkg, useflags=useflags,
+                               mytree=mytree, loop=loop))
 
-               try:
-                       eapi, myuris = self.aux_get(mypkg,
-                               ["EAPI", "SRC_URI"], mytree=mytree)
-               except KeyError:
-                       # Convert this to an InvalidDependString exception 
since callers
-                       # already handle it.
-                       raise portage.exception.InvalidDependString(
-                               "getFetchMap(): aux_get() error reading 
"+mypkg+"; aborting.")
+       def async_fetch_map(self, mypkg, useflags=None, mytree=None, loop=None):
+               """
+               Asynchronous form of getFetchMap.
 
-               if not eapi_is_supported(eapi):
-                       # Convert this to an InvalidDependString exception
-                       # since callers already handle it.
-                       raise portage.exception.InvalidDependString(
-                               "getFetchMap(): '%s' has unsupported EAPI: 
'%s'" % \
-                               (mypkg, eapi))
-
-               return _parse_uri_map(mypkg, {'EAPI':eapi,'SRC_URI':myuris},
-                       use=useflags)
+               @param mypkg: cpv for an ebuild
+               @type mypkg: String
+               @param useflags: a collection of enabled USE flags, for 
evaluation of
+                       conditionals
+               @type useflags: set, or None to enable all conditionals
+               @param mytree: The canonical path of the tree in which the 
ebuild
+                       is located, or None for automatic lookup
+               @type mypkg: String
+               @param loop: event loop (defaults to global event loop)
+               @type loop: EventLoop
+               @return: A future that results in a dict which maps each file 
name to
+                       a set of alternative URIs.
+               @rtype: asyncio.Future (or compatible)
+               """
+               loop = loop or global_event_loop()
+               loop = getattr(loop, '_asyncio_wrapper', loop)
+               result = loop.create_future()
+
+               def aux_get_done(aux_get_future):
+                       if result.cancelled():
+                               return
+                       if aux_get_future.exception() is not None:
+                               if isinstance(future.exception(), 
PortageKeyError):
+                                       # Convert this to an 
InvalidDependString exception since
+                                       # callers already handle it.
+                                       
result.set_exception(portage.exception.InvalidDependString(
+                                               "getFetchMap(): aux_get() error 
reading "
+                                               + mypkg + "; aborting."))
+                               else:
+                                       result.set_exception(future.exception())
+                               return
+
+                       eapi, myuris = aux_get_future.result()
+
+                       if not eapi_is_supported(eapi):
+                               # Convert this to an InvalidDependString 
exception
+                               # since callers already handle it.
+                               
result.set_exception(portage.exception.InvalidDependString(
+                                       "getFetchMap(): '%s' has unsupported 
EAPI: '%s'" % \
+                                       (mypkg, eapi)))
+                               return
+
+                       result.set_result(_parse_uri_map(mypkg,
+                               {'EAPI':eapi,'SRC_URI':myuris}, use=useflags))
+
+               aux_get_future = self.async_aux_get(
+                       mypkg, ["EAPI", "SRC_URI"], mytree=mytree)
+               result.add_done_callback(lambda result:
+                       aux_get_future.cancel() if result.cancelled() else None)
+               aux_get_future.add_done_callback(aux_get_done)
+               return result
 
        def getfetchsizes(self, mypkg, useflags=None, debug=0, myrepo=None):
                # returns a filename:size dictionnary of remaining downloads
-- 
2.13.6


Reply via email to