25 # objects |
25 # objects |
26 |
26 |
27 class Reply(object): |
27 class Reply(object): |
28 """object to return values from API calls. |
28 """object to return values from API calls. |
29 """ |
29 """ |
30 def __init__(self, text=""): |
30 def __init__(self, text="", raptor=None): |
|
31 self._raptor = raptor |
31 self.text = text |
32 self.text = text |
|
33 |
|
34 def _getEvaluator(self, meaning): |
|
35 """ Note: Will pass on Evaluator constructor exceptions """ |
|
36 try: |
|
37 return self.__evaluator |
|
38 except AttributeError: |
|
39 # create an evaluator for the named configuration |
|
40 tmp = raptor_data.Alias("tmp") |
|
41 tmp.SetProperty("meaning", meaning) |
|
42 |
|
43 units = tmp.GenerateBuildUnits(self._raptor.cache) |
|
44 self.__evaluator = self._raptor.GetEvaluator(None, units[0]) |
|
45 return self.__evaluator |
32 |
46 |
33 def __str__(self): |
47 def __str__(self): |
34 name = type(self).__name__.lower() |
48 name = type(self).__name__.lower() |
35 |
49 |
36 string = "<" + name |
50 string = "<" + name |
37 children = [] |
51 children = [] |
38 longend = False |
52 longend = False |
39 |
53 |
40 for attribute,value in self.__dict__.items(): |
54 for attribute,value in self.__dict__.items(): |
41 if attribute != "text": |
55 if attribute != "text" and not attribute.startswith('_'): |
42 if isinstance(value, Reply): |
56 if isinstance(value, Reply): |
43 children.append(value) |
57 children.append(value) |
|
58 elif isinstance(value, list): |
|
59 for item in value: |
|
60 if isinstance(item, Reply): |
|
61 children.append(item) |
|
62 else: |
|
63 raise BadReply(str(item)+" is not a Reply object") |
44 else: |
64 else: |
45 string += " %s='%s'" % (attribute, value) |
65 if value != None: # skip attributes whose value is None |
|
66 string += " %s='%s'" % (attribute, value) |
46 |
67 |
47 if children or self.text: |
68 if children or self.text: |
48 string += ">" |
69 string += ">" |
49 longend = True |
70 longend = True |
50 |
71 |
51 if self.text: |
72 if self.text: |
52 string += self.text |
73 string += self.text |
|
74 children.sort() |
|
75 # Note mixing sortable and unsortable lists results in |
|
76 # sort not working, so if you really need your |
|
77 # children to come out in the right order, put them in |
|
78 # a list. This is only for niceness, where it works. |
53 |
79 |
54 if children: |
80 if children: |
55 string += "\n" |
81 string += "\n" |
56 |
82 |
57 for c in children: |
83 for c in children: |
58 string += str(c) |
84 clines = str(c).rstrip().split("\n") |
|
85 string += "".join(map(lambda l:" "+l+"\n",clines)) |
59 |
86 |
60 if longend: |
87 if longend: |
61 string += "</%s>\n" % name |
88 string += "</%s>\n" % name |
62 else: |
89 else: |
63 string += "/>\n" |
90 string += "/>\n" |
64 |
91 |
65 return string |
92 return string |
|
93 |
|
94 |
|
95 class BadReply(Exception): |
|
96 pass |
66 |
97 |
67 class Alias(Reply): |
98 class Alias(Reply): |
68 def __init__(self, name, meaning): |
99 def __init__(self, name, meaning): |
69 super(Alias,self).__init__() |
100 super(Alias,self).__init__() |
70 self.name = name |
101 self.name = name |
71 self.meaning = meaning |
102 self.meaning = meaning |
|
103 |
|
104 def __cmp__(self, other): |
|
105 """ Add __cmp__ to enable comparisons between two Alias objects based upon name.""" |
|
106 return cmp(self.name, other.name) |
72 |
107 |
73 class Config(Reply): |
108 class Config(Reply): |
74 def __init__(self, fullname, outputpath): |
109 def __init__(self, raptor, name, text = None): |
75 super(Config,self).__init__() |
110 """ Constructor to create a Config from a user-supplied name. |
76 self.fullname = fullname |
111 possibly including aliases (but not groups) |
77 self.outputpath = outputpath |
112 """ |
|
113 super(Config,self).__init__(text, raptor) |
|
114 |
|
115 self.query = name |
|
116 |
|
117 # Work out the real name |
|
118 names = name.split(".") |
|
119 if names[0] in self._raptor.cache.aliases: |
|
120 x = self._raptor.cache.FindNamedAlias(names[0]) |
|
121 |
|
122 if len(names) > 1: |
|
123 self.meaning = x.meaning + "." + ".".join(names[1:]) |
|
124 else: |
|
125 self.meaning = x.meaning |
|
126 |
|
127 elif names[0] in self._raptor.cache.variants: |
|
128 self.meaning = name |
|
129 |
|
130 else: |
|
131 raise BadQuery("'%s' is not an alias or a variant" % names[0]) |
|
132 |
|
133 def resolveOutputPath(self): |
|
134 """ Get the outputpath """ |
|
135 try: |
|
136 evaluator = self._getEvaluator(self.meaning) |
|
137 # This is messy as some configs construct the path inside the FLM |
|
138 # rather than talking it from the XML: usually because of some |
|
139 # conditional logic... but maybe some refactoring could avoid that. |
|
140 releasepath = evaluator.Get("RELEASEPATH") |
|
141 if not releasepath: |
|
142 raise BadQuery("could not get RELEASEPATH for config '%s'" % self.fullname) |
|
143 |
|
144 variantplatform = evaluator.Get("VARIANTPLATFORM") |
|
145 varianttype = evaluator.Get("VARIANTTYPE") |
|
146 featurevariantname = evaluator.Get("FEATUREVARIANTNAME") |
|
147 |
|
148 platform = evaluator.Get("TRADITIONAL_PLATFORM") |
|
149 |
|
150 if platform == "TOOLS2": |
|
151 self.outputpath = releasepath |
|
152 else: |
|
153 if not variantplatform: |
|
154 raise BadQuery("could not get VARIANTPLATFORM for config '%s'" % self.fullname) |
|
155 |
|
156 if featurevariantname: |
|
157 variantplatform += featurevariantname |
|
158 |
|
159 if not varianttype: |
|
160 raise BadQuery("could not get VARIANTTYPE for config '%s'" % self.fullname) |
|
161 |
|
162 self.outputpath = str(generic_path.Join(releasepath, variantplatform, varianttype)) |
|
163 except Exception, e: # Unable to determine output path |
|
164 self.text = str(e) |
|
165 |
|
166 def resolveMetadata(self): |
|
167 try: |
|
168 metadata = self.metadata |
|
169 except AttributeError: |
|
170 metadata = MetaData(self.meaning, self._raptor) |
|
171 self.metadata = metadata |
|
172 |
|
173 try: |
|
174 metadata.resolve() |
|
175 except Exception: |
|
176 # Evaluator exception hopefully - already handled |
|
177 self.metadata = None |
|
178 |
|
179 def resolveBuild(self): |
|
180 try: |
|
181 build = self.build |
|
182 except AttributeError: |
|
183 build = Build(self.meaning, self._raptor) |
|
184 self.build = build |
|
185 |
|
186 try: |
|
187 build.resolve() |
|
188 except Exception: |
|
189 # Evaluator exception, hopefully - already handled |
|
190 self.build = None |
|
191 |
|
192 def resolveTargettypes(self): |
|
193 try: |
|
194 build = self.build |
|
195 except AttributeError: |
|
196 build = Build(self.meaning, self._raptor) |
|
197 self.build = build |
|
198 |
|
199 try: |
|
200 build.resolveTargettypes() |
|
201 except Exception: |
|
202 # Evaluator exception hopefully - already handled |
|
203 self.build = None |
|
204 |
|
205 class MetaData(Reply): |
|
206 def __init__(self, meaning, raptor): |
|
207 super(MetaData,self).__init__("", raptor) |
|
208 self.__meaning = meaning |
|
209 |
|
210 def resolve(self): |
|
211 includepaths = [] |
|
212 preincludeheader = "" |
|
213 platmacros = [] |
|
214 |
|
215 evaluator = self._getEvaluator(self.__meaning) |
|
216 |
|
217 # Initialise data and metadata objects |
|
218 buildunits = raptor_data.GetBuildUnits([self.__meaning], self._raptor.cache, self._raptor) |
|
219 metareader = raptor_meta.MetaReader(self._raptor, buildunits) |
|
220 metadatafile = raptor_meta.MetaDataFile(generic_path.Path("bld.inf"), "cpp", [], None, self._raptor) |
|
221 |
|
222 # There is only one build platform here; obtain the pre-processing include paths, |
|
223 # OS pre-include file, compiler pre-include file and macros. |
|
224 includepaths = metadatafile.preparePreProcessorIncludePaths(metareader.BuildPlatforms[0]) |
|
225 preincludeheader = metareader.BuildPlatforms[0]['VARIANT_HRH'] |
|
226 |
|
227 # Macros arrive as a a list of strings, or a single string, containing definitions of the form "name" or "name=value". |
|
228 platmacrolist = metadatafile.preparePreProcessorMacros(metareader.BuildPlatforms[0]) |
|
229 platmacros.extend(map(lambda macrodef: [macrodef.partition("=")[0], macrodef.partition("=")[2]], platmacrolist)) |
|
230 |
|
231 # Add child elements to appropriate areas if they were calculated |
|
232 if len(includepaths) > 0: |
|
233 self.includepaths = map(lambda x: Include(str(x)), includepaths) |
|
234 |
|
235 if preincludeheader != "": |
|
236 self.preincludeheader = PreInclude(str(preincludeheader)) |
|
237 |
|
238 if len(platmacros): |
|
239 self.platmacros = map(lambda x: Macro(x[0],x[1]) if x[1] else Macro(x[0]), platmacros) |
|
240 |
|
241 class Build(Reply): |
|
242 def __init__(self, meaning, raptor): |
|
243 super(Build,self).__init__("", raptor) |
|
244 self.__meaning = meaning |
|
245 |
|
246 def resolve(self): |
|
247 compilerpreincludeheader = "" |
|
248 sourcemacros = [] |
|
249 |
|
250 evaluator = self._getEvaluator(self.__meaning) |
|
251 |
|
252 platform = evaluator.Get("TRADITIONAL_PLATFORM") |
|
253 |
|
254 # Compiler preinclude files may or may not be present, depending on the configuration. |
|
255 if evaluator.Get("PREINCLUDE"): |
|
256 compilerpreincludeheader = generic_path.Path(evaluator.Get("PREINCLUDE")) |
|
257 |
|
258 # Macros arrive as a a list of strings, or a single string, containing definitions of the form "name" or "name=value". |
|
259 # If required, we split to a list, and then processes the constituent parts of the macro. |
|
260 sourcemacrolist = evaluator.Get("CDEFS").split() |
|
261 sourcemacros.extend(map(lambda macrodef: [macrodef.partition("=")[0], macrodef.partition("=")[2]], sourcemacrolist)) |
|
262 |
|
263 if platform == "TOOLS2": |
|
264 # Source macros are determined in the FLM for tools2 builds, therefore we have to |
|
265 # mimic the logic here |
|
266 if 'win' in raptor.hostplatform or 'win32' in self.__meaning: |
|
267 sourcemacrolist = evaluator.Get("CDEFS.WIN32").split() |
|
268 else: |
|
269 sourcemacrolist = evaluator.Get("CDEFS.LINUX").split() |
|
270 sourcemacros.extend(map(lambda macrodef: [macrodef.partition("=")[0], macrodef.partition("=")[2]], sourcemacrolist)) |
|
271 |
|
272 if len(sourcemacros): |
|
273 self.sourcemacros = map(lambda x: Macro(x[0],x[1]) if x[1] else Macro(x[0]), sourcemacros) |
|
274 |
|
275 if compilerpreincludeheader: |
|
276 self.compilerpreincludeheader = PreInclude(str(compilerpreincludeheader)) |
|
277 |
|
278 def resolveTargettypes(self): |
|
279 evaluator = self._getEvaluator(self.__meaning) |
|
280 targettypes = evaluator.Get("TARGET_TYPES").split(' ') |
|
281 self.targettypes = [] |
|
282 for type in targettypes: |
|
283 self.targettypes.append(TargetType(type)) |
|
284 self.targettypes.sort() |
|
285 |
|
286 class TargetType(Reply): |
|
287 def __init__(self, name): |
|
288 super(TargetType,self).__init__() |
|
289 self.name = name |
|
290 |
|
291 def __cmp__(self, other): |
|
292 return cmp(self.name, other.name) |
78 |
293 |
79 class Product(Reply): |
294 class Product(Reply): |
80 def __init__(self, name): |
295 def __init__(self, name): |
81 super(Product,self).__init__() |
296 super(Product,self).__init__() |
82 self.name = name |
297 self.name = name |
|
298 |
|
299 def __cmp__(self, other): |
|
300 """ Add __cmp__ to enable comparisons between two Product objects based upon name.""" |
|
301 return cmp(self.name, other.name) |
|
302 |
|
303 class Include(Reply): |
|
304 def __init__(self, path): |
|
305 super(Include,self).__init__() |
|
306 self.path = path |
|
307 |
|
308 class PreInclude(Reply): |
|
309 def __init__(self, file): |
|
310 super(PreInclude,self).__init__() |
|
311 self.file = file |
|
312 |
|
313 class Macro(Reply): |
|
314 def __init__(self, name, value=None): |
|
315 super(Macro,self).__init__() |
|
316 self.name = name |
|
317 self.value = value |
83 |
318 |
84 import generic_path |
319 import generic_path |
85 import raptor |
320 import raptor |
86 import raptor_data |
321 import raptor_data |
|
322 import raptor_meta |
87 import re |
323 import re |
88 |
324 |
89 class Context(object): |
325 class Context(object): |
90 """object to contain state information for API calls. |
326 """object to contain state information for API calls. |
91 |
327 |
139 |
375 |
140 for a in self.__raptor.cache.aliases.values(): |
376 for a in self.__raptor.cache.aliases.values(): |
141 if type == ALL or a.type == type: |
377 if type == ALL or a.type == type: |
142 # copy the members we want to expose |
378 # copy the members we want to expose |
143 aliases.append( Alias(a.name, a.meaning) ) |
379 aliases.append( Alias(a.name, a.meaning) ) |
144 |
380 aliases.sort() |
145 return aliases |
381 return aliases |
146 |
382 |
147 def getconfig(self, name): |
383 def getconfig(self, name): |
148 """extract the values for a given configuration. |
384 """extract the values for a given configuration. |
149 |
385 |
150 'name' should be an alias or variant followed optionally by a |
386 'name' should be an alias or variant followed optionally by a |
151 dot-separated list of variants. For example "armv5_urel" or |
387 dot-separated list of variants. For example "armv5_urel" or |
152 "armv5_urel.savespace.vasco". |
388 "armv5_urel.savespace.vasco". |
153 """ |
389 """ |
154 names = name.split(".") |
390 |
155 if names[0] in self.__raptor.cache.aliases: |
391 config = Config(self.__raptor, name) |
156 x = self.__raptor.cache.FindNamedAlias(names[0]) |
392 config.resolveOutputPath() |
157 |
393 config.resolveTargettypes() |
158 if len(names) > 1: |
394 config.resolveMetadata() |
159 fullname = x.meaning + "." + ".".join(names[1:]) |
395 config.resolveBuild() |
160 else: |
396 return config |
161 fullname = x.meaning |
|
162 |
|
163 elif names[0] in self.__raptor.cache.variants: |
|
164 fullname = name |
|
165 |
|
166 else: |
|
167 raise BadQuery("'%s' is not an alias or a variant" % names[0]) |
|
168 |
|
169 # create an evaluator for the named configuration |
|
170 tmp = raptor_data.Alias("tmp") |
|
171 tmp.SetProperty("meaning", fullname) |
|
172 |
|
173 units = tmp.GenerateBuildUnits(self.__raptor.cache) |
|
174 evaluator = self.__raptor.GetEvaluator(None, units[0]) |
|
175 |
|
176 # get the outputpath |
|
177 # this is messy as some configs construct the path inside the FLM |
|
178 # rather than talking it from the XML: usually because of some |
|
179 # conditional logic... but maybe some refactoring could avoid that. |
|
180 releasepath = evaluator.Get("RELEASEPATH") |
|
181 if not releasepath: |
|
182 raise BadQuery("could not get RELEASEPATH for config '%s'" % name) |
|
183 |
|
184 variantplatform = evaluator.Get("VARIANTPLATFORM") |
|
185 varianttype = evaluator.Get("VARIANTTYPE") |
|
186 featurevariantname = evaluator.Get("FEATUREVARIANTNAME") |
|
187 |
|
188 platform = evaluator.Get("TRADITIONAL_PLATFORM") |
|
189 |
|
190 if platform == "TOOLS2": |
|
191 outputpath = releasepath |
|
192 else: |
|
193 if not variantplatform: |
|
194 raise BadQuery("could not get VARIANTPLATFORM for config '%s'" % name) |
|
195 |
|
196 if featurevariantname: |
|
197 variantplatform += featurevariantname |
|
198 |
|
199 if not varianttype: |
|
200 raise BadQuery("could not get VARIANTTYPE for config '%s'" % name) |
|
201 |
|
202 outputpath = str(generic_path.Join(releasepath, variantplatform, varianttype)) |
|
203 |
|
204 return Config(fullname, outputpath) |
|
205 |
397 |
206 def getproducts(self): |
398 def getproducts(self): |
207 """extract all product variants.""" |
399 """extract all product variants.""" |
208 |
400 |
209 variants = [] |
401 variants = [] |
210 |
402 |
211 for v in self.__raptor.cache.variants.values(): |
403 for v in self.__raptor.cache.variants.values(): |
212 if v.type == "product": |
404 if v.type == "product": |
213 # copy the members we want to expose |
405 # copy the members we want to expose |
214 variants.append( Product(v.name) ) |
406 variants.append( Product(v.name) ) |
215 |
407 variants.sort() |
216 return variants |
408 return variants |
217 |
409 |
218 class BadQuery(Exception): |
410 class BadQuery(Exception): |
219 pass |
411 pass |
220 |
412 |