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/
Date: Wed, 30 May 2012 16:10:30
Message-Id: 1338389668.efc87322e3016a5178feb579b468ff44d8cc0b04.dywi@gentoo
1 commit: efc87322e3016a5178feb579b468ff44d8cc0b04
2 Author: Andre Erdmann <dywi <AT> mailerd <DOT> de>
3 AuthorDate: Wed May 30 14:54:28 2012 +0000
4 Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
5 CommitDate: Wed May 30 14:54:28 2012 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=efc87322
7
8 roverlay, ebuildjob: status code and dep resolve logic
9 modified: ebuildjob.py
10
11 ---
12 roverlay/ebuildjob.py | 260 ++++++++++++++++++++++++++++++++++---------------
13 1 files changed, 181 insertions(+), 79 deletions(-)
14
15 diff --git a/roverlay/ebuildjob.py b/roverlay/ebuildjob.py
16 index 171150c..d45dfdf 100644
17 --- a/roverlay/ebuildjob.py
18 +++ b/roverlay/ebuildjob.py
19 @@ -6,11 +6,42 @@ from roverlay.fileio import DescriptionReader
20 from roverlay.ebuild import Ebuild
21
22 class EbuildJob:
23 - STATUS_LIST = [ 'INIT', 'BUSY', 'WAIT', 'SUCCESS', 'FAIL' ]
24 - STATUS_MAP = dict ( ( name, code ) for code, name in enumerate ( STATUS_LIST ) )
25 + # move this to const / config
26 + DEPENDENCY_FIELDS = {
27 + 'R_SUGGESTS' : [ 'Suggests' ],
28 + 'DEPENDS' : ['Depends', 'Imports' ],
29 + 'RDEPENDS' : [ 'LinkingTo', 'SystemRequirements' ]
30 + }
31 +
32 + ##
33 +
34 +
35 + STATUS_LIST = [ 'INIT', 'BUSY', 'WAIT_RESOLVE', 'SUCCESS', 'FAIL' ]
36 +
37 + # status 'jump' control
38 + # FAIL is always allowed, S -> S has to be explicitly allowed
39 + STATUS_BRANCHMAP = dict (
40 + INIT = [ 'BUSY' ],
41 + BUSY = [ 'BUSY', 'WAIT_RESOLVE', 'SUCCESS' ],
42 + WAIT_RESOLVE = [ 'BUSY' ],
43 + SUCCESS = [],
44 + FAIL = [],
45 + )
46
47 @classmethod
48 def __init__ ( self, package_file, dep_resolver=None ):
49 + """Initializes an EbuildJob, which creates an ebuild for an R package.
50 +
51 + arguments:
52 + * package_file -- path to the R package file
53 + * dep_resolver -- dependency resolver
54 + """
55 +
56 + """Note:
57 + it is intended to run this job as thread, that's why it has its own
58 + dep resolver 'communication channel', status codes etc.
59 + """
60 +
61 self.package_file = package_file
62 self.dep_resolver = dep_resolver
63 # get description reader from args?
64 @@ -18,44 +49,10 @@ class EbuildJob:
65
66 self.ebuild = None
67
68 - self._status = 0 # todo
69 + self.status = 'INIT'
70
71 # --- end of __init__ (...) ---
72
73 - @staticmethod
74 - def get_statuscode ( status_id ):
75 - if status_id == 'ALL':
76 - return EbuildJob.STATUS_LIST
77 - elif isinstance ( status_id, int ):
78 - if status_id > 0 and status_id < len ( STATUS_LIST ):
79 - return EbuildJob.STATUS_LIST [status_id]
80 - elif status_id in EbuildJob.STATUS_MAP:
81 - return EbuildJob.STATUS_MAP [status_id]
82 -
83 - return None
84 -
85 - # --- end of get_statuscode (...) ---
86 -
87 - @classmethod
88 - def status ( self, expected_status=None ):
89 - """Returns the current status of this job or a bool that indicates
90 - whether to current status matches the expected one.
91 -
92 - arguments:
93 - * expected_status -- if not None: check if this job's state is expected_status
94 - """
95 - if expected_status:
96 - if isinstance ( expected_status, int ):
97 - return bool ( self._status == expected_status )
98 - elif expected_status in EbuildJob.STATUS_MAP:
99 - return bool ( self._status == EbuildJob.STATUS_MAP [expected_status] )
100 - else:
101 - return False
102 -
103 - return self._status
104 -
105 - # --- end of status (...) ---
106 -
107 @classmethod
108 def get_ebuild ( self ):
109 """Returns the Ebuild that is created by this object. Note that you should
110 @@ -68,73 +65,178 @@ class EbuildJob:
111 # --- end of get_ebuild (...) ---
112
113 @classmethod
114 - def _set_status ( self, new_status ):
115 - self._status = EbuildJob.get_statuscode ( new_status )
116 - return True
117 + def get_status ( self, expected_status=None ):
118 + """Returns the current status of this job or a bool that indicates
119 + whether to current status matches the expected one.
120
121 - # --- end of _set_status (...) ---
122 + arguments:
123 + * expected_status -- if not None: check if this job's state is expected_status
124 + """
125 + if not expected_status is None:
126 + return bool ( self.status == expected_status )
127 + else:
128 + return self.status
129 +
130 + # --- end of get_status (...) ---
131 +
132 + @classmethod
133 + def done_success ( self ):
134 + """Returns True if this has been successfully finished."""
135 + return get_status ( 'SUCCESS' )
136 +
137 + # --- end of done_success (...) ---
138
139
140 @classmethod
141 def run ( self ):
142 """Tells this EbuildJob to run. This means that it reads the package file,
143 - resolves dependencies (TODO) and creates an Ebuild object that is ready
144 - to be written into a file.
145 + resolves dependencies using its resolver (TODO) and creates
146 + an Ebuild object that is ready to be written into a file.
147 """
148
149 - # check status
150 - if not self.status ( 'INIT' ):
151 - return
152 + # TODO move hardcoded entries to config/const
153
154 - if not self._set_status ( 'BUSY' ):
155 - return False
156 + try:
157
158 - read_data = self.description_reader.readfile ( self.package_file )
159 + # set status or return
160 + if not self._set_status ( 'BUSY', True ): return
161
162 - if read_data is None:
163 - # set status accordingly
164 - self._set_status ( 'FAIL' )
165 - return False
166 + read_data = self.description_reader.readfile ( self.package_file )
167
168 - fileinfo = read_data ['fileinfo']
169 - desc = read_data ['description_data']
170 + if read_data is None:
171 + # set status accordingly
172 + self._set_status ( 'FAIL' )
173 + return
174
175 - ebuild = Ebuild()
176 + fileinfo = read_data ['fileinfo']
177 + desc = read_data ['description_data']
178
179 - have_description = False
180 + ebuild = Ebuild()
181
182 - print ( str ( desc ) )
183 + have_description = False
184
185 - if 'Title' in desc:
186 - have_description = True
187 - ebuild.add ( 'DESCRIPTION', desc ['Title'] )
188 + if 'Title' in desc:
189 + ebuild.add ( 'DESCRIPTION', desc ['Title'] )
190 + have_description = True
191
192 - if 'Description' in desc:
193 - have_description = True
194 - ebuild.add ( 'DESCRIPTION', ( '// ' if have_description else '' ) + desc ['Description'] )
195 + if 'Description' in desc:
196 + ebuild.add ( 'DESCRIPTION', ( '// ' if have_description else '' ) + desc ['Description'] )
197 + #have_description=True
198
199 - if not have_description:
200 - ebuild.add ( 'DESCRIPTION', '<none>' )
201 - del have_description
202
203 - # origin is todo (sync module knows the package origin)
204 - ebuild.add ( 'PKG_ORIGIN', 'CRAN' )
205 + # origin is todo (sync module knows the package origin)
206 + ebuild.add ( 'PKG_ORIGIN', 'CRAN' )
207
208 - ebuild.add ( 'PKG_FILE', fileinfo ['package_file'] )
209 + ebuild.add ( 'PKG_FILE', fileinfo ['package_file'] )
210
211 - ebuild.add ( 'ebuild_header', [ '# test header' ], False )
212 + ebuild.add ( 'ebuild_header',
213 + [ '# test header, first line\n',
214 + '# test header, second line\n\n\n\n',
215 + '#third\n\n#fifth' ],
216 + False
217 + )
218
219 - ## have to resolve deps here
220 + if self.dep_resolver and self.dep_resolver.enabled():
221
222 - # enter status that allows transferring ebuild -> self.ebuild
223 - if self._set_status ( 'WAIT' ):
224 - # finalize self.ebuild: forced text creation + make it readonly
225 + # collect depdencies from desc and add them to the resolver
226 + raw_depends = dict ()
227 +
228 + dep_type = field = None
229 +
230 + for dep_type in EbuildJob.DEPENDENCY_FIELDS.keys():
231 +
232 + raw_depends [dep_type] = []
233 +
234 + for field in EbuildJob.DEPENDENCY_FIELDS [dep_type]:
235 +
236 + if field in desc:
237 + if isinstance ( desc [field], list ):
238 + raw_depends.extend ( desc [field] )
239 + self.dep_resolver.add_dependencies ( desc [field] )
240 +
241 + else:
242 + raw_depends.append ( desc [field] )
243 + self.dep_resolver.add_depency ( desc [field] )
244 +
245 + del field, dep_type
246 +
247 +
248 + while not self.dep_resolver.done():
249 +
250 + if not self._set_status ( 'WAIT_RESOLVE' ): return
251 +
252 + # tell the resolver to run (again)
253 + self.dep_resolver.run()
254 +
255 + if not self._set_status ( 'BUSY' ): return
256 +
257 + if self.dep_resolver.satisfy_request():
258 +
259 + dep_type = dep_str = dep = None
260 +
261 + # dependencies resolved, add them to the ebuild
262 + for dep_type in raw_depends.keys():
263 +
264 + for dep_str in raw_depends [dep_type]:
265 + # lookup (str) should return a str here
266 + dep = self.dep_resolver.lookup ( dep_str )
267 + if dep is None:
268 + raise Exception (
269 + "dep_resolver is broken: lookup() returns None but satisfy_request() says ok."
270 + )
271 + else:
272 + # add depencies in append mode
273 + dep = self.dep_resolver.lookup ( dep_str )
274 + ebuild.add ( dep_type,
275 + self.dep_resolver.lookup ( dep_str ),
276 + True
277 + )
278 +
279 + del dep, dep_str, dep_type
280 +
281 + # tell the dep resolver that we're done here
282 + self.dep_resolver.close()
283 +
284 + else:
285 + # ebuild is not creatable, set status to FAIL and close dep resolver
286 + self._set_status ( 'FAIL' )
287 + self.dep_resolver.close()
288 + return
289 +
290 + ## finalize self.ebuild: forced text creation + make it readonly
291 if ebuild.prepare ( True, True ):
292 self.ebuild = ebuild
293 - return self._set_status ( 'SUCCESS' )
294 -
295 - self._set_status ( 'FAIL' )
296 - return False
297 + return None
298 + else:
299 + return None
300
301 + except Exception as any_exception:
302 + # any exception means failure
303 + self.status = 'FAIL'
304 + raise
305
306 # --- end of run (...) ---
307 +
308 + @classmethod
309 + def _set_status ( self, new_status, ignore_invalid=False ):
310 + """Changes the status of this job. May refuse to do that if invalid change
311 + requested (e.g. 'FAIL' -> 'SUCCESS').
312 +
313 + arguments:
314 + new_status --
315 + """
316 +
317 + if new_status == 'FAIL':
318 + # always allowed
319 + self.status = new_status
320 +
321 + if new_status and new_status in EbuildJob.STATUS_LIST:
322 + # check if jumping from self.status to new_status is allowed
323 + if new_status in EbuildJob.STATUS_BRANCHMAP [self.status]:
324 + self.status = new_status
325 + return True
326 +
327 + # default return
328 + return False
329 +
330 + # --- end of _set_status (...) ---