Gentoo Archives: gentoo-commits

From: Brian Dolbec <dolsen@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:repoman commit in: pym/repoman/modules/scan/ebuild/, pym/repoman/, ...
Date: Mon, 25 Apr 2016 15:32:45
Message-Id: 1461598133.93428acb8af7f5b90fb6a3ce5a21ee0e2110a4f5.dolsen@gentoo
1 commit: 93428acb8af7f5b90fb6a3ce5a21ee0e2110a4f5
2 Author: Zac Medico <zmedico <AT> gentoo <DOT> org>
3 AuthorDate: Sat Apr 16 20:24:06 2016 +0000
4 Commit: Brian Dolbec <dolsen <AT> gentoo <DOT> org>
5 CommitDate: Mon Apr 25 15:28:53 2016 +0000
6 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=93428acb
7
8 repoman: replace Fuse with Future
9
10 Replace Fuse with Future, which is similar more generic. The
11 code ends up being slightly more verbose, but more flexible.
12 The Future class will be useful elsewhere, including the
13 EventLoop class.
14
15 pym/portage/util/futures.py | 118 ++++++++++++++++++++++++++++
16 pym/repoman/fuse.py | 68 ----------------
17 pym/repoman/main.py | 12 ++-
18 pym/repoman/modules/scan/ebuild/ebuild.py | 10 ++-
19 pym/repoman/modules/scan/ebuild/isebuild.py | 25 ++++--
20 pym/repoman/modules/scan/metadata/unused.py | 10 ++-
21 pym/repoman/scanner.py | 4 +-
22 7 files changed, 164 insertions(+), 83 deletions(-)
23
24 diff --git a/pym/portage/util/futures.py b/pym/portage/util/futures.py
25 new file mode 100644
26 index 0000000..c648f10
27 --- /dev/null
28 +++ b/pym/portage/util/futures.py
29 @@ -0,0 +1,118 @@
30 +# Copyright 2016 Gentoo Foundation
31 +# Distributed under the terms of the GNU General Public License v2
32 +#
33 +# For compatibility with python versions which do not have the
34 +# asyncio module (Python 3.3 and earlier), this module provides a
35 +# subset of the asyncio.futures.Futures interface.
36 +
37 +from __future__ import unicode_literals
38 +
39 +__all__ = (
40 + 'CancelledError',
41 + 'Future',
42 + 'InvalidStateError',
43 +)
44 +
45 +try:
46 + from asyncio import (
47 + CancelledError,
48 + Future,
49 + InvalidStateError,
50 + )
51 +except ImportError:
52 +
53 + from portage.exception import PortageException
54 +
55 + _PENDING = 'PENDING'
56 + _CANCELLED = 'CANCELLED'
57 + _FINISHED = 'FINISHED'
58 +
59 + class Error(PortageException):
60 + pass
61 +
62 + class CancelledError(Error):
63 + def __init__(self):
64 + Error.__init__(self, "cancelled")
65 +
66 + class InvalidStateError(Error):
67 + pass
68 +
69 + class Future(object):
70 +
71 + # Class variables serving as defaults for instance variables.
72 + _state = _PENDING
73 + _result = None
74 + _exception = None
75 +
76 + def cancel(self):
77 + """Cancel the future and schedule callbacks.
78 +
79 + If the future is already done or cancelled, return False. Otherwise,
80 + change the future's state to cancelled, schedule the callbacks and
81 + return True.
82 + """
83 + if self._state != _PENDING:
84 + return False
85 + self._state = _CANCELLED
86 + return True
87 +
88 + def done(self):
89 + """Return True if the future is done.
90 +
91 + Done means either that a result / exception are available, or that the
92 + future was cancelled.
93 + """
94 + return self._state != _PENDING
95 +
96 + def result(self):
97 + """Return the result this future represents.
98 +
99 + If the future has been cancelled, raises CancelledError. If the
100 + future's result isn't yet available, raises InvalidStateError. If
101 + the future is done and has an exception set, this exception is raised.
102 + """
103 + if self._state == _CANCELLED:
104 + raise CancelledError()
105 + if self._state != _FINISHED:
106 + raise InvalidStateError('Result is not ready.')
107 + if self._exception is not None:
108 + raise self._exception
109 + return self._result
110 +
111 + def exception(self):
112 + """Return the exception that was set on this future.
113 +
114 + The exception (or None if no exception was set) is returned only if
115 + the future is done. If the future has been cancelled, raises
116 + CancelledError. If the future isn't done yet, raises
117 + InvalidStateError.
118 + """
119 + if self._state == _CANCELLED:
120 + raise CancelledError
121 + if self._state != _FINISHED:
122 + raise InvalidStateError('Exception is not set.')
123 + return self._exception
124 +
125 + def set_result(self, result):
126 + """Mark the future done and set its result.
127 +
128 + If the future is already done when this method is called, raises
129 + InvalidStateError.
130 + """
131 + if self._state != _PENDING:
132 + raise InvalidStateError('{}: {!r}'.format(self._state, self))
133 + self._result = result
134 + self._state = _FINISHED
135 +
136 + def set_exception(self, exception):
137 + """Mark the future done and set an exception.
138 +
139 + If the future is already done when this method is called, raises
140 + InvalidStateError.
141 + """
142 + if self._state != _PENDING:
143 + raise InvalidStateError('{}: {!r}'.format(self._state, self))
144 + if isinstance(exception, type):
145 + exception = exception()
146 + self._exception = exception
147 + self._state = _FINISHED
148
149 diff --git a/pym/repoman/fuse.py b/pym/repoman/fuse.py
150 deleted file mode 100644
151 index ac864fd..0000000
152 --- a/pym/repoman/fuse.py
153 +++ /dev/null
154 @@ -1,68 +0,0 @@
155 -
156 -'''
157 -fuse.py
158 -
159 -A tiny one-time-fuse class that uses a boolean to mimic the property of
160 -an electrical fuse. IT's good (True) until it is popped (bad, False).
161 -It is not resetable.
162 -'''
163 -
164 -
165 -class Fuse(object):
166 - '''A One time fuse style boolean instance'''
167 -
168 - __slots__ = ('_state')
169 -
170 - def __init__(self):
171 - self._state = True
172 -
173 - def pop(self):
174 - '''Blow's the fuse state (makes it False)'''
175 - self._state = False
176 -
177 - def __repr__(self):
178 - '''x.__repr__() <==> repr(x)'''
179 - return repr(self._state>0)
180 -
181 - def __str__(self):
182 - '''x.__str__() <==> str(x)'''
183 - return ['False', 'True'][self._state]
184 -
185 - def __bool__(self):
186 - '''self != 0'''
187 - return self._state != 0
188 -
189 - def __nonzero__(self):
190 - '''self != 0'''
191 - return self._state != 0
192 -
193 - def __abs__(self):
194 - '''x.__abs__() <==> abs(x)'''
195 - return [0, 1] [self._state]
196 -
197 - def __int__(self):
198 - '''int(self)'''
199 - return [0, 1][self._state]
200 -
201 - def __eq__(self, value):
202 - '''Return self==value.'''
203 - return self._state == value
204 -
205 - def __ne__(self, value):
206 - '''Return self!=value.'''
207 - return self._state != value
208 -
209 - def __ge__(self, value):
210 - '''Return self>=value.'''
211 - return self._state >= value
212 -
213 - def __gt__(self, value):
214 - return self._state > value
215 -
216 - def __le__(self, value):
217 - '''Return self<=value.'''
218 - return self._state <= value
219 -
220 - def __lt__(self, value):
221 - '''Return self<value.'''
222 - return self._state < value
223
224 diff --git a/pym/repoman/main.py b/pym/repoman/main.py
225 index 2ccda99..62c3c2c 100755
226 --- a/pym/repoman/main.py
227 +++ b/pym/repoman/main.py
228 @@ -22,10 +22,13 @@ import portage.repository.config
229 from portage.output import create_color_func, nocolor
230 from portage.output import ConsoleStyleFile, StyleWriter
231 from portage.util import formatter
232 +from portage.util.futures import (
233 + Future,
234 + InvalidStateError,
235 +)
236
237 from repoman.actions import Actions
238 from repoman.argparser import parse_args
239 -from repoman.fuse import Fuse
240 from repoman.qa_data import (
241 format_qa_output, format_qa_output_column, qahelp,
242 qawarnings, qacats)
243 @@ -76,7 +79,7 @@ def repoman_main(argv):
244 # Set this to False when an extraordinary issue (generally
245 # something other than a QA issue) makes it impossible to
246 # commit (like if Manifest generation fails).
247 - can_force = Fuse()
248 + can_force = Future()
249
250 portdir, portdir_overlay, mydir = utilities.FindPortdir(repoman_settings)
251 if portdir is None:
252 @@ -171,6 +174,11 @@ def repoman_main(argv):
253 qa_output = qa_output.getvalue()
254 qa_output = qa_output.splitlines(True)
255
256 + try:
257 + can_force = can_force.result()
258 + except InvalidStateError:
259 + can_force = True
260 +
261 # output the results
262 actions = Actions(repo_settings, options, scanner, vcs_settings)
263 if actions.inform(can_force, result):
264
265 diff --git a/pym/repoman/modules/scan/ebuild/ebuild.py b/pym/repoman/modules/scan/ebuild/ebuild.py
266 index 540411f..67eee3f 100644
267 --- a/pym/repoman/modules/scan/ebuild/ebuild.py
268 +++ b/pym/repoman/modules/scan/ebuild/ebuild.py
269 @@ -8,6 +8,7 @@ from repoman.modules.scan.scanbase import ScanBase
270 # import our initialized portage instance
271 from repoman._portage import portage
272 from portage import os
273 +from portage.util.futures import InvalidStateError
274
275 pv_toolong_re = re.compile(r'[0-9]{19,}')
276
277 @@ -127,15 +128,18 @@ class Ebuild(ScanBase):
278 def pkg_invalid(self, **kwargs):
279 '''Sets some pkg info and checks for invalid packages
280
281 - @param validity_fuse: Fuse instance
282 + @param validity_future: Future instance
283 @returns: dictionary, including {pkg object}
284 '''
285 - fuse = kwargs.get('validity_fuse')
286 + fuse = kwargs.get('validity_future')
287 if self.pkg.invalid:
288 for k, msgs in self.pkg.invalid.items():
289 for msg in msgs:
290 self.qatracker.add_error(k, "%s: %s" % (self.relative_path, msg))
291 - fuse.pop()
292 + try:
293 + fuse.set_result(False)
294 + except InvalidStateError:
295 + pass
296 return {'continue': True, 'pkg': self.pkg}
297 return {'continue': False, 'pkg': self.pkg}
298
299
300 diff --git a/pym/repoman/modules/scan/ebuild/isebuild.py b/pym/repoman/modules/scan/ebuild/isebuild.py
301 index 514d23e..a8870c7 100644
302 --- a/pym/repoman/modules/scan/ebuild/isebuild.py
303 +++ b/pym/repoman/modules/scan/ebuild/isebuild.py
304 @@ -9,6 +9,7 @@ from _emerge.RootConfig import RootConfig
305 from repoman._portage import portage
306
307 from portage import os
308 +from portage.util.futures import InvalidStateError
309
310 from repoman.qa_data import no_exec, allvars
311 from repoman.modules.scan.scanbase import ScanBase
312 @@ -35,13 +36,13 @@ class IsEbuild(ScanBase):
313 @param checkdirlist: list of files in the current package directory
314 @param checkdir: current package directory path
315 @param xpkg: current package directory being checked
316 - @param validity_fuse: Fuse instance
317 + @param validity_future: Future instance
318 @returns: dictionary, including {pkgs, can_force}
319 '''
320 checkdirlist = kwargs.get('checkdirlist')
321 checkdir = kwargs.get('checkdir')
322 xpkg = kwargs.get('xpkg')
323 - fuse = kwargs.get('validity_fuse')
324 + fuse = kwargs.get('validity_future')
325 can_force = kwargs.get('can_force')
326 self.continue_ = False
327 ebuildlist = []
328 @@ -64,15 +65,24 @@ class IsEbuild(ScanBase):
329 try:
330 myaux = dict(zip(allvars, self.portdb.aux_get(cpv, allvars)))
331 except KeyError:
332 - fuse.pop()
333 + try:
334 + fuse.set_result(False)
335 + except InvalidStateError:
336 + pass
337 self.qatracker.add_error("ebuild.syntax", os.path.join(xpkg, y))
338 continue
339 except IOError:
340 - fuse.pop()
341 + try:
342 + fuse.set_result(False)
343 + except InvalidStateError:
344 + pass
345 self.qatracker.add_error("ebuild.output", os.path.join(xpkg, y))
346 continue
347 if not portage.eapi_is_supported(myaux["EAPI"]):
348 - fuse.pop()
349 + try:
350 + fuse.set_result(False)
351 + except InvalidStateError:
352 + pass
353 self.qatracker.add_error("EAPI.unsupported", os.path.join(xpkg, y))
354 continue
355 pkgs[pf] = Package(
356 @@ -86,7 +96,10 @@ class IsEbuild(ScanBase):
357 # metadata leads to false positives for several checks, and false
358 # positives confuse users.
359 self.continue_ = True
360 - can_force.pop()
361 + try:
362 + fuse.set_result(False)
363 + except InvalidStateError:
364 + pass
365
366 return {'continue': self.continue_, 'pkgs': pkgs}
367
368
369 diff --git a/pym/repoman/modules/scan/metadata/unused.py b/pym/repoman/modules/scan/metadata/unused.py
370 index a58a614..a6ff589 100644
371 --- a/pym/repoman/modules/scan/metadata/unused.py
372 +++ b/pym/repoman/modules/scan/metadata/unused.py
373 @@ -1,6 +1,8 @@
374
375 from repoman.modules.scan.scanbase import ScanBase
376
377 +from portage.util.futures import InvalidStateError
378 +
379
380 class UnusedCheck(ScanBase):
381 '''Checks and reports any un-used metadata.xml use flag descriptions'''
382 @@ -18,14 +20,18 @@ class UnusedCheck(ScanBase):
383 @param xpkg: the pacakge being checked
384 @param muselist: use flag list
385 @param used_useflags: use flag list
386 - @param validity_fuse: Fuse instance
387 + @param validity_future: Future instance
388 '''
389 xpkg = kwargs.get('xpkg')
390 muselist = kwargs.get('muselist')
391 used_useflags = kwargs.get('used_useflags')
392 + try:
393 + valid_state = kwargs['validity_future'].result()
394 + except InvalidStateError:
395 + valid_state = True
396 # check if there are unused local USE-descriptions in metadata.xml
397 # (unless there are any invalids, to avoid noise)
398 - if kwargs.get('validity_fuse'):
399 + if valid_state:
400 for myflag in muselist.difference(used_useflags):
401 self.qatracker.add_error(
402 "metadata.warning",
403
404 diff --git a/pym/repoman/scanner.py b/pym/repoman/scanner.py
405 index a9f56e9..e9a8e20 100644
406 --- a/pym/repoman/scanner.py
407 +++ b/pym/repoman/scanner.py
408 @@ -9,7 +9,7 @@ import portage
409 from portage import normalize_path
410 from portage import os
411 from portage.output import green
412 -from repoman.fuse import Fuse
413 +from portage.util.futures import Future
414 from repoman.modules.commit import repochecks
415 from repoman.profile import check_profiles, dev_profile_keywords, setup_profile
416 from repoman.repos import repo_metadata
417 @@ -232,7 +232,7 @@ class Scanner(object):
418 'repolevel': self.repolevel,
419 'catdir': catdir,
420 'pkgdir': pkgdir,
421 - 'validity_fuse': Fuse()
422 + 'validity_future': Future()
423 }
424 # need to set it up for ==> self.modules or some other ordered list
425 for mod in ['Manifests', 'IsEbuild', 'KeywordChecks', 'FileChecks',