Gentoo Archives: gentoo-commits

From: "André Erdmann" <dywi@×××××××.de>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/depres/
Date: Tue, 05 Jun 2012 17:30:43
Message-Id: 1338916839.f65931ef830da61d738dab1dcc9f5588cc260243.dywi@gentoo
1 commit: f65931ef830da61d738dab1dcc9f5588cc260243
2 Author: André Erdmann <dywi <AT> mailerd <DOT> de>
3 AuthorDate: Tue Jun 5 17:20:39 2012 +0000
4 Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
5 CommitDate: Tue Jun 5 17:20:39 2012 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=f65931ef
7
8 dependency resolution
9
10 * added simple rule reader
11 * started with the dependency resolver
12
13 ---
14 roverlay/depres/depresolver.py | 78 +++++++++++++++++++++++++++---
15 roverlay/depres/deprule.py | 103 +++++++++++++++++++++++++++++++++-------
16 roverlay/depres/rulereader.py | 88 ++++++++++++++++++++++++++++++++++
17 3 files changed, 245 insertions(+), 24 deletions(-)
18
19 diff --git a/roverlay/depres/__init__.py b/roverlay/depres/__init__.py
20 new file mode 100644
21 index 0000000..e69de29
22
23 diff --git a/roverlay/depres/depresolver.py b/roverlay/depres/depresolver.py
24 index 7d7c5e6..ebb88cd 100644
25 --- a/roverlay/depres/depresolver.py
26 +++ b/roverlay/depres/depresolver.py
27 @@ -2,22 +2,55 @@
28 # Copyright 2006-2012 Gentoo Foundation
29 # Distributed under the terms of the GNU General Public License v2
30
31 +
32 class DependencyResolver:
33
34 def __init__ ( self ):
35 - self.channels = dict()
36 - self.listeners = dict()
37 + self.logger = None
38 + self.channels = list ()
39 + self.listeners = list ()
40 +
41 +
42 + def _report_event ( self, event, pkg_env=None, **extra ):
43 + """Reports an event to the log, channels and listeners."""
44 + pass
45 +
46 +
47 + def set_logmask ( self, logmask ):
48 + """Sets the logmask for this DependencyResolver which can be used to
49 + filter events that would normally go into the log file.
50 + Useful if a listener module reports such events in an extra file.
51 +
52 + arguments:
53 + * logmask -- new logmask
54 + """
55 + pass
56
57
58 - def get_listener ():
59 + def add_listener ( self ):
60 + """Adds a listener, which listens to events such as
61 + "dependency is unresolvable". Possible use cases include redirecting
62 + such events into a file for further parsing.
63 +
64 + arguments:
65 + * listener_type
66 + """
67 new_listener = DependencyResolverListener()
68 # register the new listener
69 self.listeners [new_listener.ident] = new_listener
70 return new_listener
71
72 - def get_channel ( readonly=False ):
73 - # ... TODO
74 - pass
75 + def get_channel ( self, readonly=False ):
76 + """Returns a communication channel to the DependencyResolver.
77 + This channel can be used to _talk_, e.g. queue dependencies for resolution
78 + and collect the results later.
79 +
80 + arguments:
81 + * readonly -- whether this channel has write access or not
82 + """
83 + new channel = DependencyResolverChannel ( self )
84 + self.channels [new_channel.ident] = new_channel
85 + return new_channel
86
87
88
89 @@ -26,8 +59,39 @@ class DependencyResolverListener:
90 def __init__ ( self ):
91 self.ident = id ( self )
92
93 + def notify ( event_type, pkg_env=None, **extra ):
94 + """Notify this listener about an event."""
95 + pass
96 +
97 +
98 class DependencyResolverChannel ( DependencyResolverListener ):
99
100 def __init__ ( self, main_resolver, *args ):
101 - super ( DependencyResolverChannel, self ) . __init__ ( args )
102 + super ( DependencyResolverChannel, self ) . __init__ ()
103 self._depres_master = main_resolver
104 +
105 + def close ( self ):
106 + """Closes this channel."""
107 + pass
108 +
109 +
110 +class EbuildJobChannel ( DependencyResolverChannel ):
111 + def __init__ ( self, main_resolver, *args ):
112 + super ( EbuildJobChannel, self ) . __init__ ( main_resolver )
113 +
114 +
115 + def done ( self ):
116 + pass
117 +
118 + def add_dependency ( self, dep_str ):
119 + pass
120 +
121 + def add_dependencies ( self, dep_list ):
122 + pass
123 +
124 + def satisfy_request ( self ):
125 + pass
126 +
127 + def lookup ( self, dep_str ):
128 + return None
129 +
130
131 diff --git a/roverlay/depres/deprule.py b/roverlay/depres/deprule.py
132 index 3a82cbe..b5d1116 100644
133 --- a/roverlay/depres/deprule.py
134 +++ b/roverlay/depres/deprule.py
135 @@ -4,20 +4,20 @@
136
137 class DependencyRule:
138 def __init__ ( self ):
139 - pass
140 + self.max_score = 1000
141
142 - def matches ( pkg_env ):
143 - return False
144 + def matches ( dep_str ):
145 + return 0
146
147 class SimpleDependencyRule ( DependencyRule ):
148
149 def __init__ ( self, resolving_package, dep_str=None, priority=100 ):
150 - super ( SimpleDependencyRule, self ) . __init__ ( self )
151 + super ( SimpleDependencyRule, self ) . __init__ ( )
152 self.dep_alias = set ()
153 if dep_str:
154 self.dep_alias.add ( dep_str )
155
156 - self.package = resolving_package
157 + self.resolving_package = resolving_package
158
159 self.priority = priority
160 # --- end of __init__ (...) ---
161 @@ -26,35 +26,104 @@ class SimpleDependencyRule ( DependencyRule ):
162 self.dep_alias.add ( dep_str )
163 # --- end of add_resolved (...) ---
164
165 - def matches ( self, pkg_env, lowercase=True ):
166 + def matches ( self, dep_str, lowercase=True ):
167 if lowercase:
168 - lower_dep_str = pkg_env.dep_str
169 + lower_dep_str = dep_str
170 for alias in self.dep_alias:
171 if alias.lower() == lower_dep_str:
172 - return True
173 - elif pkg_env.dep_str in self.dep_alias:
174 - return True
175 + return self.max_score
176 + elif dep_str in self.dep_alias:
177 + return self.max_score
178
179 - return False
180 + return 0
181 # --- end of matches (...) ---
182
183 + def get_dep ( self ):
184 + return self.resolving_package
185 +
186 + def export_rule ( self ):
187 + pass
188 +
189 class DependencyRulePool:
190
191 - def __init__ ( self ):
192 - self.rules = list ()
193 - self._priofunc = lambda x : x.priority
194 + def __init__ ( self, name ):
195 + self.rules = list ()
196 + self.name = name
197 + self.priority = 0
198 # --- end of __init__ (...) ---
199
200 - def _sort_rules ( self ):
201 - self.rules.sort ( key=self._priofunc )
202 + def sort ( self ):
203 + self.rules.sort ( key=lambda rule : rule.priority )
204 +
205 + priority_sum = 0
206 + for r in self.rules:
207 + priority_sum += r.priority
208 +
209 + self.priority = int ( priority_sum / len ( self.rules ) ) if len ( self.rules ) else 0
210 +
211 return None
212 # --- end of _sort_rules (...) ---
213
214 def add ( self, rule ):
215 if issubclass ( rule, DependencyRule ):
216 - self.rules.add ( rule )
217 + self.rules.append ( rule )
218 else:
219 raise Exception ( "bad usage (dependency rule expected)." )
220
221 return None
222 # --- end of add (...) ---
223 +
224 + def matches ( self, dep_str, skip_matches=0 ):
225 + """Tries to find a match in this dependency rule pool.
226 + The first match is immediatly returned unless skip_matches is != 0, in
227 + which case the first (>0) / last (<0) skip_matches matches are skipped.
228 +
229 + arguments:
230 + * dep_str -- dependency to look up
231 + * skip_matches --
232 + """
233 +
234 + if abs ( skip_matches ) >= len ( self.rules ):
235 + # all matches ignored; cannot expect a result in this case - abort now
236 + pass
237 +
238 + else:
239 + skipped = 0
240 + order = range ( len ( self.rules ) )
241 +
242 + if skip_matches < 1:
243 + skip_matches *= -1
244 + order.reverse()
245 +
246 + for index in order:
247 + score = self.rules [index].matches ( dep_str )
248 + if score:
249 + if skipped < skip_matches:
250 + skipped += 1
251 + else:
252 + return score, self.rules [index].get_dep ()
253 +
254 +
255 + return 0, None
256 +
257 +
258 +class SimpleDependencyRulePool ( DependencyRulePool )
259 +
260 + def __init__ ( self, name ):
261 + super ( SimpleDependencyRulePool, self ) . __init__ ( name )
262 + # --- end of __init__ (...) ---
263 +
264 + def add ( self, rile ):
265 + if isinstance ( rule, SimpleDependencyRule ):
266 + self.rules.append ( rule )
267 + else:
268 + raise Exception ( "bad usage (simple dependency rule expected)." )
269 + # --- end of add (...) ---
270 +
271 + def export_rules ( self, fh ):
272 + for rule in self.rules:
273 + to_write = fh.export_rule()
274 + if isinstance ( to_write, str ):
275 + fh.write ( to_write )
276 + else:
277 + fh.writelines ( to_write )
278
279 diff --git a/roverlay/depres/rulereader.py b/roverlay/depres/rulereader.py
280 new file mode 100644
281 index 0000000..6998cb2
282 --- /dev/null
283 +++ b/roverlay/depres/rulereader.py
284 @@ -0,0 +1,88 @@
285 +
286 +import re
287 +import logging
288 +
289 +from roverlay.depres.deprule import SimpleDependencyRule
290 +
291 +class SimpleDependencyRuleReader:
292 +
293 + one_line_separator = re.compile ( '\s+::\s+' )
294 + multiline_start = '{'
295 + multiline_stop = '}'
296 + comment_chars = list ( '#;' )
297 +
298 +
299 + def __init__ ( self ):
300 + pass
301 + # --- end of __init__ (...) ---
302 +
303 + def read_file ( self, filepath ):
304 + """Reads a file that contains SimpleDescriptionRules.
305 +
306 + arguments:
307 + * filepath -- file to read
308 + """
309 +
310 + lineno = 0
311 +
312 + try:
313 + logging.debug ( "Reading simple dependency rule file " + filepath + "." )
314 + fh = open ( filepath, 'r' )
315 +
316 + next_rule = None
317 + rules = list ()f
318 +
319 + for line in fh.readlines():
320 + lineno += 1
321 + line = line.strip()
322 +
323 + if not line:
324 + pass
325 +
326 + elif not next_rule is None:
327 + # in a multiline rule
328 + if line [0] == SimpleDependencyRuleReader.multiline_stop:
329 + # end of a multiline rule
330 + rules.append ( next_rule )
331 + next_rule = None
332 + else:
333 + # new resolved str
334 + next_rule.add_resolved ( line )
335 +
336 + elif line [0] in SimpleDependencyRuleReader.comment_chars:
337 + # comment
338 + pass
339 +
340 + elif line [-1] == SimpleDependencyRuleReader.multiline_start:
341 + # start of multiline rule
342 + next_rule = SimpleDependencyRule ( line [:-1].rstrip(), None, 100 )
343 +
344 + else:
345 + # one line rule?
346 + rule_str = SimpleDependencyRuleReader.one_line_separator.split ( line, 1 )
347 +
348 + if len ( rule_str ) == 2:
349 + rules.append (
350 + SimpleDependencyRule ( rule_str [0], rule_str [1], 90 )
351 + )
352 + else:
353 + logging.error (
354 + "In " + filepath + ", line " + str ( lineno ) + ": cannot use this line."
355 + )
356 + # ---
357 +
358 + if fh: fh.close ()
359 +
360 + logging.info ( filepath + ": read " + str ( len ( rules ) ) + " dependency rules." )
361 +
362 + return rules
363 +
364 + except IOError as ioerr:
365 + if lineno:
366 + logging.error ( "Failed to read file " + filepath + " after " + str ( lineno ) " lines."
367 + else:
368 + logging.error ( "Could not read file " + filepath + "." )
369 + raise
370 +
371 + # --- end of read_file (...) ---
372 +