Gentoo Archives: gentoo-commits

From: "André Erdmann" <dywi@×××××××.de>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/interface/
Date: Tue, 02 Jul 2013 21:09:34
Message-Id: 1372799011.0e181458fcfaf0bd1eaf993a47d09befa6d19fa6.dywi@gentoo
1 commit: 0e181458fcfaf0bd1eaf993a47d09befa6d19fa6
2 Author: André Erdmann <dywi <AT> mailerd <DOT> de>
3 AuthorDate: Tue Jul 2 21:03:31 2013 +0000
4 Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
5 CommitDate: Tue Jul 2 21:03:31 2013 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=0e181458
7
8 roverlay/interface: access subsystems more easily
9
10 roverlay/interface provides abstraction layers for certain roverlay modules.
11 Currently, it supports dependency resolution only.
12
13 ---
14 roverlay/interface/__init__.py | 0
15 roverlay/interface/depres.py | 249 +++++++++++++++++++++++++++++++++++++++++
16 roverlay/interface/generic.py | 75 +++++++++++++
17 roverlay/interface/root.py | 62 ++++++++++
18 4 files changed, 386 insertions(+)
19
20 diff --git a/roverlay/interface/__init__.py b/roverlay/interface/__init__.py
21 new file mode 100644
22 index 0000000..e69de29
23
24 diff --git a/roverlay/interface/depres.py b/roverlay/interface/depres.py
25 new file mode 100644
26 index 0000000..d416312
27 --- /dev/null
28 +++ b/roverlay/interface/depres.py
29 @@ -0,0 +1,249 @@
30 +# R overlay --
31 +# -*- coding: utf-8 -*-
32 +# Copyright (C) 2013 André Erdmann <dywi@×××××××.de>
33 +# Distributed under the terms of the GNU General Public License;
34 +# either version 2 of the License, or (at your option) any later version.
35 +
36 +#import weakref
37 +
38 +import roverlay.interface.generic
39 +
40 +
41 +import roverlay.depres.channels
42 +import roverlay.depres.depresolver
43 +import roverlay.depres.deptype
44 +import roverlay.depres.simpledeprule.pool
45 +import roverlay.depres.simpledeprule.rules
46 +import roverlay.depres.simpledeprule.rulemaker
47 +
48 +DEFAULT_DEPTYPE = roverlay.depres.deptype.ALL
49 +
50 +class RuleSyntaxException ( Exception ):
51 + pass
52 +
53 +class DepresInterface ( roverlay.interface.generic.RoverlaySubInterface ):
54 +
55 + def __init__ ( self, parent_interface ):
56 + super ( DepresInterface, self ).__init__ (
57 + parent_interface=parent_interface
58 + )
59 +
60 + # set up the resolver
61 + self._resolver = roverlay.depres.depresolver.DependencyResolver (
62 + err_queue=self.err_queue
63 + )
64 + ## log everything
65 + self._resolver.set_logmask ( -1 )
66 + ## disable passing events to listeners
67 + self._resolver.set_listenermask ( 0 )
68 +
69 + # dependency rule pools (a set of rules) are organized in a FIFO
70 + # structure that allows to create and delete new pools at runtime
71 + self._poolstack = self._resolver.static_rule_pools
72 + self._pool_id = -1
73 +
74 + self._parser = roverlay.depres.simpledeprule.rulemaker.SimpleRuleMaker()
75 + # --- end of __init__ (...) ---
76 +
77 + @property
78 + def resolver ( self ):
79 + return self._resolver
80 +
81 + @property
82 + def parser ( self ):
83 + return self._parser
84 +
85 + @property
86 + def poolstack ( self ):
87 + return self._poolstack
88 +
89 + @property
90 + def pool_id ( self ):
91 + return self._pool_id
92 +
93 + def _update_resolver ( self ):
94 + # sort() should be called on a per-pool basis
95 + self._resolver._reset_unresolvable()
96 + # --- end of _update_resolver (...) ---
97 +
98 + def close ( self ):
99 + super ( DepresInterface, self ).close()
100 + self._resolver.close()
101 + # --- end of close (...) ---
102 +
103 + def update ( self ):
104 + super ( DepresInterface, self ).update()
105 + if self._poolstack:
106 + self._poolstack[-1].sort()
107 + self._update_resolver()
108 + # --- end of update (...) ---
109 +
110 + def has_pool ( self ):
111 + return self._poolstack
112 + # --- end of has_pool (...) ---
113 +
114 + def has_nonempty_pool ( self ):
115 + return self._poolstack and not self._poolstack[-1].empty()
116 + # --- end of has_nonempty_pool (...) ---
117 +
118 + def get_pool ( self ):
119 + if self._poolstack:
120 + return self._poolstack[-1]
121 + else:
122 + return self.get_new_pool ( force=True )
123 + # --- end of get_pool (...) ---
124 +
125 + def get_new_pool ( self, force=False, with_deptype=DEFAULT_DEPTYPE ):
126 + if force or not self._poolstack or not self._poolstack[-1].empty():
127 + self._pool_id += 1
128 + try:
129 + pool = roverlay.depres.simpledeprule.pool.SimpleDependencyRulePool (
130 + "pool" + str ( self._pool_id ),
131 + deptype_mask=DEFAULT_DEPTYPE
132 + )
133 + self.poolstack.append ( pool )
134 + except:
135 + self._pool_id -= 1
136 + raise
137 +
138 + self._update_resolver()
139 + # -- end if force or ...
140 + return self._poolstack[-1]
141 + # --- end of get_new_pool (...) ---
142 +
143 + def discard_pool ( self ):
144 + try:
145 + self._poolstack.pop()
146 + self._pool_id -= 1
147 + assert self._pool_id >= -1
148 + return True
149 + except AssertionError:
150 + raise
151 + except:
152 + return False
153 + # --- end of discard_pool (...) ---
154 +
155 + def discard_pools ( self, count ):
156 + for i in range ( count ):
157 + if not self.discard_pool():
158 + return i
159 + else:
160 + return count
161 + # --- end of discard_pools (...) ---
162 +
163 + def discard_empty_pools ( self ):
164 + removed = 0
165 + while self._poolstack and self._poolstack[-1].empty():
166 + if self.discard_pool():
167 + removed += 1
168 + else:
169 + raise AssertionError (
170 + "discard_pool() should succeed if topmost pool exists."
171 + )
172 + return removed
173 + # --- end of discard_empty_pools (...) ---
174 +
175 + def load_rules_from_config ( self ):
176 + return self.load_rule_files (
177 + self.config.get_or_fail ( "DEPRES.simple_rules.files" )
178 + )
179 + # --- end of load_rules_from_config (...) ---
180 +
181 + def load_rule_files ( self, files_or_dirs ):
182 + return self._resolver.get_reader().read ( files_or_dirs )
183 + # --- end of load_rule_files (...) ---
184 +
185 + def add_rule ( self, rule_str ):
186 + if not self._parser.add ( rule_str ):
187 + raise RuleSyntaxException ( rule_str )
188 + return True
189 + # --- end of add_rule (...) ---
190 +
191 + def add_rules ( self, *rule_str_list ):
192 + for rule_str in rule_str_list:
193 + self.add_rule ( rule_str )
194 + return True
195 + # --- end of add_rules (...) ---
196 +
197 + def add_rule_list ( self, rule_str_list ):
198 + for rule_str in rule_str_list:
199 + self.add_rule ( rule_str )
200 + return True
201 + # --- end of add_rule_list (...) ---
202 +
203 + def compile_rules ( self, new_pool=False ):
204 + rules = self._parser.done()
205 + destpool = self.get_new_pool() if new_pool else self.get_pool()
206 +
207 + try:
208 + # FIXME/COULDFIX: deptypes not supported here
209 + for deptype, rule in rules:
210 + destpool.rules.append ( rule )
211 +
212 + if destpool.empty():
213 + self.discard_empty_pools()
214 + else:
215 + destpool.sort()
216 + self._update_resolver()
217 + return True
218 + except:
219 + if new_pool:
220 + # this could discard (previosly) empty pools, too
221 + # (side-effect of "optimizations" in get_new_pool())
222 + #
223 + self.discard_pool()
224 + raise
225 + # --- end of compile_rules (...) ---
226 +
227 + def add_immediate_rule ( self, rule_str ):
228 + return self.add_rule ( rule_str ) and self.compile_rules()
229 + # --- end of add_immediate_rule (...) ---
230 +
231 + def visualize_pool ( self ):
232 + if self._poolstack:
233 + return '\n'.join (
234 + '\n'.join ( rule.export_rule() )
235 + for rule in self._poolstack[-1].rules
236 + )
237 + else:
238 + return ""
239 + # --- end of visualize_pool (...) ---
240 +
241 + def get_channel ( self, channel_name="channel" ):
242 + channel = roverlay.depres.channels.EbuildJobChannel (
243 + err_queue=self.err_queue, name=channel_name
244 + )
245 + self._resolver.register_channel ( channel )
246 + return channel
247 + # --- end of get_channel (...) ---
248 +
249 + def do_resolve ( self, deps, with_deptype=DEFAULT_DEPTYPE ):
250 + channel = self.get_channel()
251 + # FIXME/COULDFIX: once again, hardcoded deptype
252 + try:
253 + channel.add_dependencies ( deps, with_deptype )
254 +
255 + channel_result = channel.satisfy_request (
256 + close_if_unresolvable=False,
257 + preserve_order=True
258 + )
259 + finally:
260 + channel.close()
261 +
262 + return channel_result
263 + # --- end of do_resolve (...) ---
264 +
265 + def resolve ( self, *deps, **kw ):
266 + result = self.do_resolve ( deps, **kw )
267 + return None if result is None else result [0]
268 + # --- end of resolve (...) ---
269 +
270 + def can_resolve ( self, *deps, **kw ):
271 + return self.do_resolve ( deps, **kw ) is not None
272 + # --- end of can_resolve (...) ---
273 +
274 + def cannot_resolve ( self, *deps, **kw ):
275 + return self.do_resolve ( deps, **kw ) is None
276 + # --- end of cannot_resolve (...) ---
277 +
278 +# --- end of DepresInterface ---
279
280 diff --git a/roverlay/interface/generic.py b/roverlay/interface/generic.py
281 new file mode 100644
282 index 0000000..08806ea
283 --- /dev/null
284 +++ b/roverlay/interface/generic.py
285 @@ -0,0 +1,75 @@
286 +# R overlay --
287 +# -*- coding: utf-8 -*-
288 +# Copyright (C) 2013 André Erdmann <dywi@×××××××.de>
289 +# Distributed under the terms of the GNU General Public License;
290 +# either version 2 of the License, or (at your option) any later version.
291 +
292 +#import weakref
293 +
294 +class RoverlayInterface ( object ):
295 +
296 + def __init__ ( self ):
297 + super ( RoverlayInterface, self ).__init__()
298 + self._interfaces = dict()
299 + # --- end of __init__ (...) ---
300 +
301 + def close_interfaces ( self ):
302 + if hasattr ( self, '_interfaces' ):
303 + for iface in self._interfaces.values():
304 + iface.close()
305 + # --- end of close_interfaces (...) ---
306 +
307 + def close ( self ):
308 + self.close_interfaces()
309 + # --- end of close (...) ---
310 +
311 + def update ( self ):
312 + pass
313 + # --- end of update (...) ---
314 +
315 + def attach_interface ( self, name, interface, close_detached=True ):
316 + if name in self._interfaces:
317 + self.detach ( name, close=close_detached )
318 +
319 + self._interfaces [name] = interface
320 + return interface
321 + # --- end of attach_interface (...) ---
322 +
323 + def detach_interface ( self, name, close=False ):
324 + detached = self._interfaces [name]
325 + if close:
326 + detached.close()
327 + return True
328 + else:
329 + return detached
330 + # --- end of detach_interface (...) ---
331 +
332 + def get_interface ( self, name ):
333 + return self._interfaces [name]
334 + # --- end of get_interface (...) ---
335 +
336 + def has_interface ( self, name ):
337 + return name and name in self._interfaces
338 + # --- end of has_interface (...) ---
339 +
340 + def __getattr__ ( self, name ):
341 + if name [-10:] == '_interface':
342 + iface_name = name [:-10]
343 + if iface_name and iface_name in self._interfaces:
344 + return self._interfaces [iface_name]
345 +
346 + raise AttributeError ( name )
347 + # --- end of __getattr__ (...) ---
348 +
349 +# --- end of RoverlayInterface ---
350 +
351 +class RoverlaySubInterface ( RoverlayInterface ):
352 +
353 + def __init__ ( self, parent_interface ):
354 + super ( RoverlaySubInterface, self ).__init__()
355 + # weakref? (would require to explicitly keep "parent" instances around)
356 + self.parent = parent_interface
357 + self.err_queue = parent_interface.err_queue
358 + self.config = parent_interface.config
359 + self.logger = parent_interface.logger
360 + # --- end of __init__ (...) ---
361
362 diff --git a/roverlay/interface/root.py b/roverlay/interface/root.py
363 new file mode 100644
364 index 0000000..d500582
365 --- /dev/null
366 +++ b/roverlay/interface/root.py
367 @@ -0,0 +1,62 @@
368 +# R overlay --
369 +# -*- coding: utf-8 -*-
370 +# Copyright (C) 2013 André Erdmann <dywi@×××××××.de>
371 +# Distributed under the terms of the GNU General Public License;
372 +# either version 2 of the License, or (at your option) any later version.
373 +
374 +import logging
375 +
376 +import roverlay
377 +import roverlay.errorqueue
378 +
379 +import roverlay.interface.generic
380 +
381 +# does nothing if already initialized
382 +roverlay.setup_initial_logger()
383 +
384 +class RootInterface ( roverlay.interface.generic.RoverlayInterface ):
385 +
386 + SPAWN_MAP = dict()
387 +
388 + @classmethod
389 + def register_interface ( my_cls, name, cls, force=False ):
390 + if name and ( force or name not in my_cls.SPAWN_MAP ):
391 + my_cls.SPAWN_MAP [name] = cls
392 + return True
393 + else:
394 + return False
395 + # --- end of register_interface (...) ---
396 +
397 + def __init__ ( self,
398 + config_file=None, config=None, additional_config=None
399 + ):
400 + super ( RootInterface, self ).__init__()
401 + self.parent = None
402 + self.err_queue = roverlay.errorqueue.ErrorQueue()
403 +
404 + if config is not None:
405 + self.config = config
406 + elif config_file is not None:
407 + self.config = roverlay.load_config_file (
408 + config_file, extraconf=additional_config
409 + )
410 + else:
411 + raise Exception ( "config, config_file?" )
412 +
413 + self.logger = logging.getLogger ( self.__class__.__name__ )
414 + # --- end of __init__ (...) ---
415 +
416 + def spawn_interface ( self, name ):
417 + if self.has_interface ( name ):
418 + return self.get_interface ( name )
419 + else:
420 + iface_cls = self.SPAWN_MAP.get ( name, None )
421 + if iface_cls is None:
422 + raise Exception (
423 + "unknown interface identifier {!r}".format ( name )
424 + )
425 + else:
426 + return self.attach_interface (
427 + name, iface_cls ( parent_interface=self )
428 + )
429 + # --- end of spawn_interface (...) ---