Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH 1/2] portdbapi: add async_aux_get method (bug 648790)
Date: Mon, 26 Feb 2018 01:52:51
Message-Id: 20180226015001.30049-1-zmedico@gentoo.org
1 Add async_aux_get method that returns a Future and otherwise
2 behaves identically to aux_get. Use async_aux_get to implement
3 the synchronous aux_get method.
4
5 Bug: https://bugs.gentoo.org/648790
6 ---
7 pym/portage/dbapi/porttree.py | 91 +++++++++++++++++++++++++++++++++----------
8 1 file changed, 70 insertions(+), 21 deletions(-)
9
10 diff --git a/pym/portage/dbapi/porttree.py b/pym/portage/dbapi/porttree.py
11 index f5979d2d0..abcd47238 100644
12 --- a/pym/portage/dbapi/porttree.py
13 +++ b/pym/portage/dbapi/porttree.py
14 @@ -45,6 +45,7 @@ import traceback
15 import warnings
16 import errno
17 import collections
18 +import functools
19
20 try:
21 from urllib.parse import urlparse
22 @@ -577,11 +578,46 @@ class portdbapi(dbapi):
23 "stub code for returning auxilliary db information, such as SLOT, DEPEND, etc."
24 'input: "sys-apps/foo-1.0",["SLOT","DEPEND","HOMEPAGE"]'
25 'return: ["0",">=sys-libs/bar-1.0","http://www.foo.com"] or raise PortageKeyError if error'
26 + # For external API consumers, self._event_loop returns a new event
27 + # loop on each access, so a local reference is needed in order
28 + # to avoid instantiating more than one.
29 + loop = self._event_loop
30 + return loop.run_until_complete(
31 + self.async_aux_get(mycpv, mylist, mytree=mytree,
32 + myrepo=myrepo, loop=loop))
33 +
34 + def async_aux_get(self, mycpv, mylist, mytree=None, myrepo=None, loop=None):
35 + """
36 + Asynchronous form form of aux_get.
37 +
38 + @param mycpv: cpv for an ebuild
39 + @type mycpv: str
40 + @param mylist: list of metadata keys
41 + @type mylist: list
42 + @param mytree: The canonical path of the tree in which the ebuild
43 + is located, or None for automatic lookup
44 + @type mytree: str
45 + @param myrepo: name of the repo in which the ebuild is located,
46 + or None for automatic lookup
47 + @type myrepo: str
48 + @param loop: event loop (defaults to global event loop)
49 + @type loop: EventLoop
50 + @return: list of metadata values
51 + @rtype: asyncio.Future (or compatible)
52 + """
53 + # Don't default to self._event_loop here, since that creates a
54 + # local event loop for thread safety, and that could easily lead
55 + # to simultaneous instantiation of multiple event loops here.
56 + # Callers of this method certainly want the same event loop to
57 + # be used for all calls.
58 + loop = loop or global_event_loop()
59 + future = loop.create_future()
60 cache_me = False
61 if myrepo is not None:
62 mytree = self.treemap.get(myrepo)
63 if mytree is None:
64 - raise PortageKeyError(myrepo)
65 + future.set_exception(PortageKeyError(myrepo))
66 + return future
67
68 if mytree is not None and len(self.porttrees) == 1 \
69 and mytree == self.porttrees[0]:
70 @@ -596,43 +632,56 @@ class portdbapi(dbapi):
71 mylist).difference(self._aux_cache_keys):
72 aux_cache = self._aux_cache.get(mycpv)
73 if aux_cache is not None:
74 - return [aux_cache.get(x, "") for x in mylist]
75 + future.set_result([aux_cache.get(x, "") for x in mylist])
76 + return future
77 cache_me = True
78
79 try:
80 cat, pkg = mycpv.split("/", 1)
81 except ValueError:
82 # Missing slash. Can't find ebuild so raise PortageKeyError.
83 - raise PortageKeyError(mycpv)
84 + future.set_exception(PortageKeyError(mycpv))
85 + return future
86
87 myebuild, mylocation = self.findname2(mycpv, mytree)
88
89 if not myebuild:
90 writemsg("!!! aux_get(): %s\n" % \
91 _("ebuild not found for '%s'") % mycpv, noiselevel=1)
92 - raise PortageKeyError(mycpv)
93 + future.set_exception(PortageKeyError(mycpv))
94 + return future
95
96 mydata, ebuild_hash = self._pull_valid_cache(mycpv, myebuild, mylocation)
97 - doregen = mydata is None
98 -
99 - if doregen:
100 - if myebuild in self._broken_ebuilds:
101 - raise PortageKeyError(mycpv)
102 -
103 - proc = EbuildMetadataPhase(cpv=mycpv,
104 - ebuild_hash=ebuild_hash, portdb=self,
105 - repo_path=mylocation, scheduler=self._event_loop,
106 - settings=self.doebuild_settings)
107 -
108 - proc.start()
109 - proc.wait()
110
111 + if mydata is not None:
112 + self._aux_get_return(
113 + future, mycpv, mylist, myebuild, ebuild_hash,
114 + mydata, mylocation, cache_me, None)
115 + return future
116 +
117 + if myebuild in self._broken_ebuilds:
118 + future.set_exception(PortageKeyError(mycpv))
119 + return future
120 +
121 + proc = EbuildMetadataPhase(cpv=mycpv,
122 + ebuild_hash=ebuild_hash, portdb=self,
123 + repo_path=mylocation, scheduler=loop,
124 + settings=self.doebuild_settings)
125 +
126 + proc.addExitListener(functools.partial(self._aux_get_return,
127 + future, mycpv, mylist, myebuild, ebuild_hash, mydata, mylocation,
128 + cache_me))
129 + proc.start()
130 + return future
131 +
132 + def _aux_get_return(self, future, mycpv, mylist, myebuild, ebuild_hash,
133 + mydata, mylocation, cache_me, proc):
134 + if proc is not None:
135 if proc.returncode != os.EX_OK:
136 self._broken_ebuilds.add(myebuild)
137 - raise PortageKeyError(mycpv)
138 -
139 + future.set_exception(PortageKeyError(mycpv))
140 + return
141 mydata = proc.metadata
142 -
143 mydata["repository"] = self.repositories.get_name_for_location(mylocation)
144 mydata["_mtime_"] = ebuild_hash.mtime
145 eapi = mydata.get("EAPI")
146 @@ -651,7 +700,7 @@ class portdbapi(dbapi):
147 aux_cache[x] = mydata.get(x, "")
148 self._aux_cache[mycpv] = aux_cache
149
150 - return returnme
151 + future.set_result(returnme)
152
153 def getFetchMap(self, mypkg, useflags=None, mytree=None):
154 """
155 --
156 2.13.6

Replies