Gentoo Archives: gentoo-commits

From: Zac Medico <zmedico@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:master commit in: pym/portage/package/ebuild/, pym/_emerge/
Date: Tue, 04 Apr 2017 03:20:35
Message-Id: 1491275969.285d5d038d8bb8a17d853816e156147c8c59f248.zmedico@gentoo
1 commit: 285d5d038d8bb8a17d853816e156147c8c59f248
2 Author: Zac Medico <zmedico <AT> gentoo <DOT> org>
3 AuthorDate: Mon Apr 3 00:40:55 2017 +0000
4 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org>
5 CommitDate: Tue Apr 4 03:19:29 2017 +0000
6 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=285d5d03
7
8 EbuildBuild: async spawn_nofetch in _fetchonly_exit (bug 614116)
9
10 Replace a synchronous spawn_nofetch call with an asynchronous one,
11 in order to avoid event loop recursion which is not compatible with
12 asyncio. This involves refactoring of spawn_nofetch to provide an
13 asynchronous interface.
14
15 X-Gentoo-bug: 614116
16 X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=614116
17 Acked-by: Brian Dolbec <dolsen <AT> gentoo.org>
18
19 pym/_emerge/EbuildBuild.py | 18 ++++-
20 pym/portage/package/ebuild/_spawn_nofetch.py | 106 +++++++++++++++++----------
21 2 files changed, 85 insertions(+), 39 deletions(-)
22
23 diff --git a/pym/_emerge/EbuildBuild.py b/pym/_emerge/EbuildBuild.py
24 index 11eb1c93e..48f470483 100644
25 --- a/pym/_emerge/EbuildBuild.py
26 +++ b/pym/_emerge/EbuildBuild.py
27 @@ -22,7 +22,7 @@ import portage
28 from portage import _encodings, _unicode_decode, _unicode_encode, os
29 from portage.package.ebuild.digestcheck import digestcheck
30 from portage.package.ebuild.doebuild import _check_temp_dir
31 -from portage.package.ebuild._spawn_nofetch import spawn_nofetch
32 +from portage.package.ebuild._spawn_nofetch import SpawnNofetchWithoutBuilddir
33
34 class EbuildBuild(CompositeTask):
35
36 @@ -165,8 +165,22 @@ class EbuildBuild(CompositeTask):
37 def _fetchonly_exit(self, fetcher):
38 self._final_exit(fetcher)
39 if self.returncode != os.EX_OK:
40 + self.returncode = None
41 portdb = self.pkg.root_config.trees[self._tree].dbapi
42 - spawn_nofetch(portdb, self._ebuild_path, settings=self.settings)
43 + self._start_task(SpawnNofetchWithoutBuilddir(
44 + background=self.background,
45 + portdb=portdb,
46 + ebuild_path=self._ebuild_path,
47 + scheduler=self.scheduler,
48 + settings=self.settings),
49 + self._nofetch_without_builddir_exit)
50 + return
51 +
52 + self.wait()
53 +
54 + def _nofetch_without_builddir_exit(self, nofetch):
55 + self._final_exit(nofetch)
56 + self.returncode = 1
57 self.wait()
58
59 def _pre_clean_exit(self, pre_clean_phase):
60
61 diff --git a/pym/portage/package/ebuild/_spawn_nofetch.py b/pym/portage/package/ebuild/_spawn_nofetch.py
62 index 0fc53c8ca..bbfd5b72b 100644
63 --- a/pym/portage/package/ebuild/_spawn_nofetch.py
64 +++ b/pym/portage/package/ebuild/_spawn_nofetch.py
65 @@ -14,11 +14,14 @@ from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
66 from portage.util._async.SchedulerInterface import SchedulerInterface
67 from portage.util._eventloop.EventLoop import EventLoop
68 from portage.util._eventloop.global_event_loop import global_event_loop
69 +from _emerge.CompositeTask import CompositeTask
70 from _emerge.EbuildPhase import EbuildPhase
71
72 -def spawn_nofetch(portdb, ebuild_path, settings=None, fd_pipes=None):
73 +
74 +class SpawnNofetchWithoutBuilddir(CompositeTask):
75 """
76 - This spawns pkg_nofetch if appropriate. The settings parameter
77 + This spawns pkg_nofetch if appropriate, while avoiding the
78 + need to lock a global build directory. The settings parameter
79 is useful only if setcpv has already been called in order
80 to cache metadata. It will be cloned internally, in order to
81 prevent any changes from interfering with the calling code.
82 @@ -40,33 +43,42 @@ def spawn_nofetch(portdb, ebuild_path, settings=None, fd_pipes=None):
83 to be displayed for problematic packages even though they do
84 not set RESTRICT=fetch (bug #336499).
85
86 - This function does nothing if the PORTAGE_PARALLEL_FETCHONLY
87 + This class does nothing if the PORTAGE_PARALLEL_FETCHONLY
88 variable is set in the config instance.
89 """
90 + __slots__ = ('ebuild_path', 'fd_pipes', 'portdb', 'settings',
91 + '_private_tmpdir')
92 +
93 + def _start(self):
94 + settings = self.settings
95 + if settings is None:
96 + settings = self.portdb.settings
97 +
98 + if 'PORTAGE_PARALLEL_FETCHONLY' in settings:
99 + # parallel-fetch mode
100 + self.returncode = os.EX_OK
101 + self._async_wait()
102 + return
103
104 - if settings is None:
105 - settings = config(clone=portdb.settings)
106 - else:
107 - settings = config(clone=settings)
108 -
109 - if 'PORTAGE_PARALLEL_FETCHONLY' in settings:
110 - return os.EX_OK
111 -
112 - # We must create our private PORTAGE_TMPDIR before calling
113 - # doebuild_environment(), since lots of variables such
114 - # as PORTAGE_BUILDDIR refer to paths inside PORTAGE_TMPDIR.
115 - portage_tmpdir = settings.get('PORTAGE_TMPDIR')
116 - if not portage_tmpdir or not os.access(portage_tmpdir, os.W_OK):
117 - portage_tmpdir = None
118 - private_tmpdir = tempfile.mkdtemp(dir=portage_tmpdir)
119 - settings['PORTAGE_TMPDIR'] = private_tmpdir
120 - settings.backup_changes('PORTAGE_TMPDIR')
121 - # private temp dir was just created, so it's not locked yet
122 - settings.pop('PORTAGE_BUILDDIR_LOCKED', None)
123 -
124 - try:
125 - doebuild_environment(ebuild_path, 'nofetch',
126 - settings=settings, db=portdb)
127 + # Prevent temporary config changes from interfering
128 + # with config instances that are reused.
129 + settings = self.settings = config(clone=settings)
130 +
131 + # We must create our private PORTAGE_TMPDIR before calling
132 + # doebuild_environment(), since lots of variables such
133 + # as PORTAGE_BUILDDIR refer to paths inside PORTAGE_TMPDIR.
134 + portage_tmpdir = settings.get('PORTAGE_TMPDIR')
135 + if not portage_tmpdir or not os.access(portage_tmpdir, os.W_OK):
136 + portage_tmpdir = None
137 + private_tmpdir = self._private_tmpdir = tempfile.mkdtemp(
138 + dir=portage_tmpdir)
139 + settings['PORTAGE_TMPDIR'] = private_tmpdir
140 + settings.backup_changes('PORTAGE_TMPDIR')
141 + # private temp dir was just created, so it's not locked yet
142 + settings.pop('PORTAGE_BUILDDIR_LOCKED', None)
143 +
144 + doebuild_environment(self.ebuild_path, 'nofetch',
145 + settings=settings, db=self.portdb)
146 restrict = settings['PORTAGE_RESTRICT'].split()
147 defined_phases = settings['DEFINED_PHASES'].split()
148 if not defined_phases:
149 @@ -76,18 +88,38 @@ def spawn_nofetch(portdb, ebuild_path, settings=None, fd_pipes=None):
150
151 if 'fetch' not in restrict and \
152 'nofetch' not in defined_phases:
153 - return os.EX_OK
154 + self.returncode = os.EX_OK
155 + self._async_wait()
156 + return
157
158 prepare_build_dirs(settings=settings)
159 - ebuild_phase = EbuildPhase(background=False,
160 +
161 + ebuild_phase = EbuildPhase(background=self.background,
162 phase='nofetch',
163 - scheduler=SchedulerInterface(portage._internal_caller and
164 + scheduler=self.scheduler,
165 + fd_pipes=self.fd_pipes, settings=settings)
166 +
167 + self._start_task(ebuild_phase, self._nofetch_exit)
168 +
169 + def _nofetch_exit(self, ebuild_phase):
170 + self._final_exit(ebuild_phase)
171 + elog_process(self.settings.mycpv, self.settings)
172 + shutil.rmtree(self._private_tmpdir)
173 + self._async_wait()
174 +
175 +
176 +def spawn_nofetch(portdb, ebuild_path, settings=None, fd_pipes=None):
177 + """
178 + Create a NofetchPrivateTmpdir instance, and execute it synchronously.
179 + This function must not be called from asynchronous code, since it will
180 + trigger event loop recursion which is incompatible with asyncio.
181 + """
182 + nofetch = SpawnNofetchWithoutBuilddir(background=False,
183 + portdb=portdb,
184 + ebuild_path=ebuild_path,
185 + scheduler=SchedulerInterface(portage._internal_caller and
186 global_event_loop() or EventLoop(main=False)),
187 - fd_pipes=fd_pipes, settings=settings)
188 - ebuild_phase.start()
189 - ebuild_phase.wait()
190 - elog_process(settings.mycpv, settings)
191 - finally:
192 - shutil.rmtree(private_tmpdir)
193 -
194 - return ebuild_phase.returncode
195 + fd_pipes=fd_pipes, settings=settings)
196 +
197 + nofetch.start()
198 + return nofetch.wait()