blob: f530cf844ba66b8c9624d4ba1aa673bc32592513 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001"""
2BitBake 'Command' module
3
4Provide an interface to interact with the bitbake server through 'commands'
5"""
6
7# Copyright (C) 2006-2007 Richard Purdie
8#
Brad Bishopc342db32019-05-15 21:57:59 -04009# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010#
Patrick Williamsc124f4f2015-09-15 14:41:29 -050011
12"""
13The bitbake server takes 'commands' from its UI/commandline.
14Commands are either synchronous or asynchronous.
15Async commands return data to the client in the form of events.
16Sync commands must only return data through the function return value
17and must not trigger events, directly or indirectly.
18Commands are queued in a CommandQueue
19"""
20
Brad Bishop6e60e8b2018-02-01 10:27:11 -050021from collections import OrderedDict, defaultdict
22
Andrew Geisslerc926e172021-05-07 16:11:35 -050023import io
Patrick Williamsc124f4f2015-09-15 14:41:29 -050024import bb.event
25import bb.cooker
Brad Bishop6e60e8b2018-02-01 10:27:11 -050026import bb.remotedata
27
28class DataStoreConnectionHandle(object):
29 def __init__(self, dsindex=0):
30 self.dsindex = dsindex
Patrick Williamsc124f4f2015-09-15 14:41:29 -050031
32class CommandCompleted(bb.event.Event):
33 pass
34
35class CommandExit(bb.event.Event):
36 def __init__(self, exitcode):
37 bb.event.Event.__init__(self)
38 self.exitcode = int(exitcode)
39
40class CommandFailed(CommandExit):
41 def __init__(self, message):
42 self.error = message
43 CommandExit.__init__(self, 1)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050044 def __str__(self):
45 return "Command execution failed: %s" % self.error
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046
47class CommandError(Exception):
48 pass
49
50class Command:
51 """
52 A queue of asynchronous commands for bitbake
53 """
54 def __init__(self, cooker):
55 self.cooker = cooker
56 self.cmds_sync = CommandsSync()
57 self.cmds_async = CommandsAsync()
Andrew Geisslerc9f78652020-09-18 14:11:35 -050058 self.remotedatastores = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -050059
60 # FIXME Add lock for this
61 self.currentAsyncCommand = None
62
63 def runCommand(self, commandline, ro_only = False):
64 command = commandline.pop(0)
Andrew Geisslerc9f78652020-09-18 14:11:35 -050065
66 # Ensure cooker is ready for commands
67 if command != "updateConfig" and command != "setFeatures":
68 self.cooker.init_configdata()
69 if not self.remotedatastores:
70 self.remotedatastores = bb.remotedata.RemoteDatastores(self.cooker)
71
Patrick Williamsc124f4f2015-09-15 14:41:29 -050072 if hasattr(CommandsSync, command):
73 # Can run synchronous commands straight away
74 command_method = getattr(self.cmds_sync, command)
75 if ro_only:
Andrew Geissler82c905d2020-04-13 13:39:40 -050076 if not hasattr(command_method, 'readonly') or not getattr(command_method, 'readonly'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050077 return None, "Not able to execute not readonly commands in readonly mode"
78 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -050079 self.cooker.process_inotify_updates()
80 if getattr(command_method, 'needconfig', True):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050081 self.cooker.updateCacheSync()
82 result = command_method(self, commandline)
83 except CommandError as exc:
84 return None, exc.args[0]
Andrew Geisslerf0343792020-11-18 10:42:21 -060085 except (Exception, SystemExit) as exc:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050086 import traceback
Andrew Geisslerf0343792020-11-18 10:42:21 -060087 if isinstance(exc, bb.BBHandledException):
88 # We need to start returning real exceptions here. Until we do, we can't
89 # tell if an exception is an instance of bb.BBHandledException
90 return None, "bb.BBHandledException()\n" + traceback.format_exc()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050091 return None, traceback.format_exc()
92 else:
93 return result, None
94 if self.currentAsyncCommand is not None:
95 return None, "Busy (%s in progress)" % self.currentAsyncCommand[0]
96 if command not in CommandsAsync.__dict__:
97 return None, "No such command"
98 self.currentAsyncCommand = (command, commandline)
Andrew Geissler635e0e42020-08-21 15:58:33 -050099 self.cooker.idleCallBackRegister(self.cooker.runCommands, self.cooker)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500100 return True, None
101
102 def runAsyncCommand(self):
103 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500104 self.cooker.process_inotify_updates()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500105 if self.cooker.state in (bb.cooker.state.error, bb.cooker.state.shutdown, bb.cooker.state.forceshutdown):
106 # updateCache will trigger a shutdown of the parser
107 # and then raise BBHandledException triggering an exit
108 self.cooker.updateCache()
109 return False
110 if self.currentAsyncCommand is not None:
111 (command, options) = self.currentAsyncCommand
112 commandmethod = getattr(CommandsAsync, command)
113 needcache = getattr( commandmethod, "needcache" )
114 if needcache and self.cooker.state != bb.cooker.state.running:
115 self.cooker.updateCache()
116 return True
117 else:
118 commandmethod(self.cmds_async, self, options)
119 return False
120 else:
121 return False
122 except KeyboardInterrupt as exc:
123 self.finishAsyncCommand("Interrupted")
124 return False
125 except SystemExit as exc:
126 arg = exc.args[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600127 if isinstance(arg, str):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500128 self.finishAsyncCommand(arg)
129 else:
130 self.finishAsyncCommand("Exited with %s" % arg)
131 return False
132 except Exception as exc:
133 import traceback
134 if isinstance(exc, bb.BBHandledException):
135 self.finishAsyncCommand("")
136 else:
137 self.finishAsyncCommand(traceback.format_exc())
138 return False
139
140 def finishAsyncCommand(self, msg=None, code=None):
141 if msg or msg == "":
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500142 bb.event.fire(CommandFailed(msg), self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500143 elif code:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500144 bb.event.fire(CommandExit(code), self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500145 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500146 bb.event.fire(CommandCompleted(), self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500147 self.currentAsyncCommand = None
148 self.cooker.finishcommand()
149
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500150 def reset(self):
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500151 if self.remotedatastores:
152 self.remotedatastores = bb.remotedata.RemoteDatastores(self.cooker)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500153
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500154class CommandsSync:
155 """
156 A class of synchronous commands
157 These should run quickly so as not to hurt interactive performance.
158 These must not influence any running synchronous command.
159 """
160
161 def stateShutdown(self, command, params):
162 """
163 Trigger cooker 'shutdown' mode
164 """
165 command.cooker.shutdown(False)
166
167 def stateForceShutdown(self, command, params):
168 """
169 Stop the cooker
170 """
171 command.cooker.shutdown(True)
172
173 def getAllKeysWithFlags(self, command, params):
174 """
175 Returns a dump of the global state. Call with
176 variable flags to be retrieved as params.
177 """
178 flaglist = params[0]
179 return command.cooker.getAllKeysWithFlags(flaglist)
180 getAllKeysWithFlags.readonly = True
181
182 def getVariable(self, command, params):
183 """
184 Read the value of a variable from data
185 """
186 varname = params[0]
187 expand = True
188 if len(params) > 1:
189 expand = (params[1] == "True")
190
191 return command.cooker.data.getVar(varname, expand)
192 getVariable.readonly = True
193
194 def setVariable(self, command, params):
195 """
196 Set the value of variable in data
197 """
198 varname = params[0]
199 value = str(params[1])
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500200 command.cooker.extraconfigdata[varname] = value
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500201 command.cooker.data.setVar(varname, value)
202
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500203 def getSetVariable(self, command, params):
204 """
205 Read the value of a variable from data and set it into the datastore
206 which effectively expands and locks the value.
207 """
208 varname = params[0]
209 result = self.getVariable(command, params)
210 command.cooker.data.setVar(varname, result)
211 return result
212
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500213 def setConfig(self, command, params):
214 """
215 Set the value of variable in configuration
216 """
217 varname = params[0]
218 value = str(params[1])
219 setattr(command.cooker.configuration, varname, value)
220
221 def enableDataTracking(self, command, params):
222 """
223 Enable history tracking for variables
224 """
225 command.cooker.enableDataTracking()
226
227 def disableDataTracking(self, command, params):
228 """
229 Disable history tracking for variables
230 """
231 command.cooker.disableDataTracking()
232
233 def setPrePostConfFiles(self, command, params):
234 prefiles = params[0].split()
235 postfiles = params[1].split()
236 command.cooker.configuration.prefile = prefiles
237 command.cooker.configuration.postfile = postfiles
238 setPrePostConfFiles.needconfig = False
239
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500240 def matchFile(self, command, params):
241 fMatch = params[0]
Andrew Geissler5a43b432020-06-13 10:46:56 -0500242 try:
243 mc = params[0]
244 except IndexError:
245 mc = ''
246 return command.cooker.matchFile(fMatch, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500247 matchFile.needconfig = False
248
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500249 def getUIHandlerNum(self, command, params):
250 return bb.event.get_uihandler()
251 getUIHandlerNum.needconfig = False
252 getUIHandlerNum.readonly = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500253
254 def setEventMask(self, command, params):
255 handlerNum = params[0]
256 llevel = params[1]
257 debug_domains = params[2]
258 mask = params[3]
259 return bb.event.set_UIHmask(handlerNum, llevel, debug_domains, mask)
260 setEventMask.needconfig = False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500261 setEventMask.readonly = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500262
263 def setFeatures(self, command, params):
264 """
265 Set the cooker features to include the passed list of features
266 """
267 features = params[0]
268 command.cooker.setFeatures(features)
269 setFeatures.needconfig = False
270 # although we change the internal state of the cooker, this is transparent since
271 # we always take and leave the cooker in state.initial
272 setFeatures.readonly = True
273
274 def updateConfig(self, command, params):
275 options = params[0]
276 environment = params[1]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500277 cmdline = params[2]
278 command.cooker.updateConfigOpts(options, environment, cmdline)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500279 updateConfig.needconfig = False
280
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500281 def parseConfiguration(self, command, params):
282 """Instruct bitbake to parse its configuration
283 NOTE: it is only necessary to call this if you aren't calling any normal action
284 (otherwise parsing is taken care of automatically)
285 """
286 command.cooker.parseConfiguration()
287 parseConfiguration.needconfig = False
288
289 def getLayerPriorities(self, command, params):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500290 command.cooker.parseConfiguration()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500291 ret = []
292 # regex objects cannot be marshalled by xmlrpc
293 for collection, pattern, regex, pri in command.cooker.bbfile_config_priorities:
294 ret.append((collection, pattern, regex.pattern, pri))
295 return ret
296 getLayerPriorities.readonly = True
297
298 def getRecipes(self, command, params):
299 try:
300 mc = params[0]
301 except IndexError:
302 mc = ''
303 return list(command.cooker.recipecaches[mc].pkg_pn.items())
304 getRecipes.readonly = True
305
306 def getRecipeDepends(self, command, params):
307 try:
308 mc = params[0]
309 except IndexError:
310 mc = ''
311 return list(command.cooker.recipecaches[mc].deps.items())
312 getRecipeDepends.readonly = True
313
314 def getRecipeVersions(self, command, params):
315 try:
316 mc = params[0]
317 except IndexError:
318 mc = ''
319 return command.cooker.recipecaches[mc].pkg_pepvpr
320 getRecipeVersions.readonly = True
321
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500322 def getRecipeProvides(self, command, params):
323 try:
324 mc = params[0]
325 except IndexError:
326 mc = ''
327 return command.cooker.recipecaches[mc].fn_provides
328 getRecipeProvides.readonly = True
329
330 def getRecipePackages(self, command, params):
331 try:
332 mc = params[0]
333 except IndexError:
334 mc = ''
335 return command.cooker.recipecaches[mc].packages
336 getRecipePackages.readonly = True
337
338 def getRecipePackagesDynamic(self, command, params):
339 try:
340 mc = params[0]
341 except IndexError:
342 mc = ''
343 return command.cooker.recipecaches[mc].packages_dynamic
344 getRecipePackagesDynamic.readonly = True
345
346 def getRProviders(self, command, params):
347 try:
348 mc = params[0]
349 except IndexError:
350 mc = ''
351 return command.cooker.recipecaches[mc].rproviders
352 getRProviders.readonly = True
353
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500354 def getRuntimeDepends(self, command, params):
355 ret = []
356 try:
357 mc = params[0]
358 except IndexError:
359 mc = ''
360 rundeps = command.cooker.recipecaches[mc].rundeps
361 for key, value in rundeps.items():
362 if isinstance(value, defaultdict):
363 value = dict(value)
364 ret.append((key, value))
365 return ret
366 getRuntimeDepends.readonly = True
367
368 def getRuntimeRecommends(self, command, params):
369 ret = []
370 try:
371 mc = params[0]
372 except IndexError:
373 mc = ''
374 runrecs = command.cooker.recipecaches[mc].runrecs
375 for key, value in runrecs.items():
376 if isinstance(value, defaultdict):
377 value = dict(value)
378 ret.append((key, value))
379 return ret
380 getRuntimeRecommends.readonly = True
381
382 def getRecipeInherits(self, command, params):
383 try:
384 mc = params[0]
385 except IndexError:
386 mc = ''
387 return command.cooker.recipecaches[mc].inherits
388 getRecipeInherits.readonly = True
389
390 def getBbFilePriority(self, command, params):
391 try:
392 mc = params[0]
393 except IndexError:
394 mc = ''
395 return command.cooker.recipecaches[mc].bbfile_priority
396 getBbFilePriority.readonly = True
397
398 def getDefaultPreference(self, command, params):
399 try:
400 mc = params[0]
401 except IndexError:
402 mc = ''
403 return command.cooker.recipecaches[mc].pkg_dp
404 getDefaultPreference.readonly = True
405
406 def getSkippedRecipes(self, command, params):
407 # Return list sorted by reverse priority order
408 import bb.cache
Andrew Geissler5a43b432020-06-13 10:46:56 -0500409 def sortkey(x):
410 vfn, _ = x
411 realfn, _, mc = bb.cache.virtualfn2realfn(vfn)
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500412 return (-command.cooker.collections[mc].calc_bbfile_priority(realfn)[0], vfn)
Andrew Geissler5a43b432020-06-13 10:46:56 -0500413
414 skipdict = OrderedDict(sorted(command.cooker.skiplist.items(), key=sortkey))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500415 return list(skipdict.items())
416 getSkippedRecipes.readonly = True
417
418 def getOverlayedRecipes(self, command, params):
Andrew Geissler5a43b432020-06-13 10:46:56 -0500419 try:
420 mc = params[0]
421 except IndexError:
422 mc = ''
423 return list(command.cooker.collections[mc].overlayed.items())
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500424 getOverlayedRecipes.readonly = True
425
426 def getFileAppends(self, command, params):
427 fn = params[0]
Andrew Geissler5a43b432020-06-13 10:46:56 -0500428 try:
429 mc = params[1]
430 except IndexError:
431 mc = ''
432 return command.cooker.collections[mc].get_file_appends(fn)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500433 getFileAppends.readonly = True
434
435 def getAllAppends(self, command, params):
Andrew Geissler5a43b432020-06-13 10:46:56 -0500436 try:
437 mc = params[0]
438 except IndexError:
439 mc = ''
440 return command.cooker.collections[mc].bbappends
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500441 getAllAppends.readonly = True
442
443 def findProviders(self, command, params):
Andrew Geissler82c905d2020-04-13 13:39:40 -0500444 try:
445 mc = params[0]
446 except IndexError:
447 mc = ''
448 return command.cooker.findProviders(mc)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500449 findProviders.readonly = True
450
451 def findBestProvider(self, command, params):
Andrew Geissler5a43b432020-06-13 10:46:56 -0500452 (mc, pn) = bb.runqueue.split_mc(params[0])
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500453 return command.cooker.findBestProvider(pn, mc)
454 findBestProvider.readonly = True
455
456 def allProviders(self, command, params):
457 try:
458 mc = params[0]
459 except IndexError:
460 mc = ''
461 return list(bb.providers.allProviders(command.cooker.recipecaches[mc]).items())
462 allProviders.readonly = True
463
464 def getRuntimeProviders(self, command, params):
465 rprovide = params[0]
466 try:
467 mc = params[1]
468 except IndexError:
469 mc = ''
470 all_p = bb.providers.getRuntimeProviders(command.cooker.recipecaches[mc], rprovide)
471 if all_p:
472 best = bb.providers.filterProvidersRunTime(all_p, rprovide,
473 command.cooker.data,
474 command.cooker.recipecaches[mc])[0][0]
475 else:
476 best = None
477 return all_p, best
478 getRuntimeProviders.readonly = True
479
Andrew Geissler82c905d2020-04-13 13:39:40 -0500480 def dataStoreConnectorCmd(self, command, params):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500481 dsindex = params[0]
Andrew Geissler82c905d2020-04-13 13:39:40 -0500482 method = params[1]
483 args = params[2]
484 kwargs = params[3]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500485
Andrew Geissler82c905d2020-04-13 13:39:40 -0500486 d = command.remotedatastores[dsindex]
487 ret = getattr(d, method)(*args, **kwargs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500488
Andrew Geissler82c905d2020-04-13 13:39:40 -0500489 if isinstance(ret, bb.data_smart.DataSmart):
490 idx = command.remotedatastores.store(ret)
491 return DataStoreConnectionHandle(idx)
492
493 return ret
494
495 def dataStoreConnectorVarHistCmd(self, command, params):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500496 dsindex = params[0]
Andrew Geissler82c905d2020-04-13 13:39:40 -0500497 method = params[1]
498 args = params[2]
499 kwargs = params[3]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500500
Andrew Geissler82c905d2020-04-13 13:39:40 -0500501 d = command.remotedatastores[dsindex].varhistory
502 return getattr(d, method)(*args, **kwargs)
503
Andrew Geisslerc926e172021-05-07 16:11:35 -0500504 def dataStoreConnectorVarHistCmdEmit(self, command, params):
505 dsindex = params[0]
506 var = params[1]
507 oval = params[2]
508 val = params[3]
509 d = command.remotedatastores[params[4]]
510
511 o = io.StringIO()
512 command.remotedatastores[dsindex].varhistory.emit(var, oval, val, o, d)
513 return o.getvalue()
514
Andrew Geissler82c905d2020-04-13 13:39:40 -0500515 def dataStoreConnectorIncHistCmd(self, command, params):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500516 dsindex = params[0]
Andrew Geissler82c905d2020-04-13 13:39:40 -0500517 method = params[1]
518 args = params[2]
519 kwargs = params[3]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500520
Andrew Geissler82c905d2020-04-13 13:39:40 -0500521 d = command.remotedatastores[dsindex].inchistory
522 return getattr(d, method)(*args, **kwargs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500523
524 def dataStoreConnectorRelease(self, command, params):
525 dsindex = params[0]
526 if dsindex <= 0:
527 raise CommandError('dataStoreConnectorRelease: invalid index %d' % dsindex)
528 command.remotedatastores.release(dsindex)
529
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500530 def parseRecipeFile(self, command, params):
531 """
532 Parse the specified recipe file (with or without bbappends)
533 and return a datastore object representing the environment
534 for the recipe.
535 """
536 fn = params[0]
Andrew Geissler5a43b432020-06-13 10:46:56 -0500537 mc = bb.runqueue.mc_from_tid(fn)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500538 appends = params[1]
539 appendlist = params[2]
540 if len(params) > 3:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500541 config_data = command.remotedatastores[params[3]]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500542 else:
543 config_data = None
544
545 if appends:
546 if appendlist is not None:
547 appendfiles = appendlist
548 else:
Andrew Geissler5a43b432020-06-13 10:46:56 -0500549 appendfiles = command.cooker.collections[mc].get_file_appends(fn)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500550 else:
551 appendfiles = []
552 # We are calling bb.cache locally here rather than on the server,
553 # but that's OK because it doesn't actually need anything from
554 # the server barring the global datastore (which we have a remote
555 # version of)
556 if config_data:
557 # We have to use a different function here if we're passing in a datastore
558 # NOTE: we took a copy above, so we don't do it here again
Andrew Geissler5a43b432020-06-13 10:46:56 -0500559 envdata = bb.cache.parse_recipe(config_data, fn, appendfiles, mc)['']
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500560 else:
561 # Use the standard path
562 parser = bb.cache.NoCache(command.cooker.databuilder)
563 envdata = parser.loadDataFull(fn, appendfiles)
564 idx = command.remotedatastores.store(envdata)
565 return DataStoreConnectionHandle(idx)
566 parseRecipeFile.readonly = True
567
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500568class CommandsAsync:
569 """
570 A class of asynchronous commands
571 These functions communicate via generated events.
572 Any function that requires metadata parsing should be here.
573 """
574
575 def buildFile(self, command, params):
576 """
577 Build a single specified .bb file
578 """
579 bfile = params[0]
580 task = params[1]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500581 if len(params) > 2:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500582 internal = params[2]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500583 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500584 internal = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500585
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500586 if internal:
587 command.cooker.buildFileInternal(bfile, task, fireevents=False, quietlog=True)
588 else:
589 command.cooker.buildFile(bfile, task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500590 buildFile.needcache = False
591
592 def buildTargets(self, command, params):
593 """
594 Build a set of targets
595 """
596 pkgs_to_build = params[0]
597 task = params[1]
598
599 command.cooker.buildTargets(pkgs_to_build, task)
600 buildTargets.needcache = True
601
602 def generateDepTreeEvent(self, command, params):
603 """
604 Generate an event containing the dependency information
605 """
606 pkgs_to_build = params[0]
607 task = params[1]
608
609 command.cooker.generateDepTreeEvent(pkgs_to_build, task)
610 command.finishAsyncCommand()
611 generateDepTreeEvent.needcache = True
612
613 def generateDotGraph(self, command, params):
614 """
615 Dump dependency information to disk as .dot files
616 """
617 pkgs_to_build = params[0]
618 task = params[1]
619
620 command.cooker.generateDotGraphFiles(pkgs_to_build, task)
621 command.finishAsyncCommand()
622 generateDotGraph.needcache = True
623
624 def generateTargetsTree(self, command, params):
625 """
626 Generate a tree of buildable targets.
627 If klass is provided ensure all recipes that inherit the class are
628 included in the package list.
629 If pkg_list provided use that list (plus any extras brought in by
630 klass) rather than generating a tree for all packages.
631 """
632 klass = params[0]
633 pkg_list = params[1]
634
635 command.cooker.generateTargetsTree(klass, pkg_list)
636 command.finishAsyncCommand()
637 generateTargetsTree.needcache = True
638
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500639 def findConfigFiles(self, command, params):
640 """
641 Find config files which provide appropriate values
642 for the passed configuration variable. i.e. MACHINE
643 """
644 varname = params[0]
645
646 command.cooker.findConfigFiles(varname)
647 command.finishAsyncCommand()
648 findConfigFiles.needcache = False
649
650 def findFilesMatchingInDir(self, command, params):
651 """
652 Find implementation files matching the specified pattern
653 in the requested subdirectory of a BBPATH
654 """
655 pattern = params[0]
656 directory = params[1]
657
658 command.cooker.findFilesMatchingInDir(pattern, directory)
659 command.finishAsyncCommand()
660 findFilesMatchingInDir.needcache = False
661
662 def findConfigFilePath(self, command, params):
663 """
664 Find the path of the requested configuration file
665 """
666 configfile = params[0]
667
668 command.cooker.findConfigFilePath(configfile)
669 command.finishAsyncCommand()
670 findConfigFilePath.needcache = False
671
672 def showVersions(self, command, params):
673 """
674 Show the currently selected versions
675 """
676 command.cooker.showVersions()
677 command.finishAsyncCommand()
678 showVersions.needcache = True
679
680 def showEnvironmentTarget(self, command, params):
681 """
682 Print the environment of a target recipe
683 (needs the cache to work out which recipe to use)
684 """
685 pkg = params[0]
686
687 command.cooker.showEnvironment(None, pkg)
688 command.finishAsyncCommand()
689 showEnvironmentTarget.needcache = True
690
691 def showEnvironment(self, command, params):
692 """
693 Print the standard environment
694 or if specified the environment for a specified recipe
695 """
696 bfile = params[0]
697
698 command.cooker.showEnvironment(bfile)
699 command.finishAsyncCommand()
700 showEnvironment.needcache = False
701
702 def parseFiles(self, command, params):
703 """
704 Parse the .bb files
705 """
706 command.cooker.updateCache()
707 command.finishAsyncCommand()
708 parseFiles.needcache = True
709
710 def compareRevisions(self, command, params):
711 """
712 Parse the .bb files
713 """
714 if bb.fetch.fetcher_compare_revisions(command.cooker.data):
715 command.finishAsyncCommand(code=1)
716 else:
717 command.finishAsyncCommand()
718 compareRevisions.needcache = True
719
720 def triggerEvent(self, command, params):
721 """
722 Trigger a certain event
723 """
724 event = params[0]
725 bb.event.fire(eval(event), command.cooker.data)
726 command.currentAsyncCommand = None
727 triggerEvent.needcache = False
728
729 def resetCooker(self, command, params):
730 """
731 Reset the cooker to its initial state, thus forcing a reparse for
732 any async command that has the needcache property set to True
733 """
734 command.cooker.reset()
735 command.finishAsyncCommand()
736 resetCooker.needcache = False
737
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500738 def clientComplete(self, command, params):
739 """
740 Do the right thing when the controlling client exits
741 """
742 command.cooker.clientComplete()
743 command.finishAsyncCommand()
744 clientComplete.needcache = False
745
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500746 def findSigInfo(self, command, params):
747 """
748 Find signature info files via the signature generator
749 """
Andrew Geissler635e0e42020-08-21 15:58:33 -0500750 (mc, pn) = bb.runqueue.split_mc(params[0])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500751 taskname = params[1]
752 sigs = params[2]
Andrew Geissler635e0e42020-08-21 15:58:33 -0500753 res = bb.siggen.find_siginfo(pn, taskname, sigs, command.cooker.databuilder.mcdata[mc])
754 bb.event.fire(bb.event.FindSigInfoResult(res), command.cooker.databuilder.mcdata[mc])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500755 command.finishAsyncCommand()
756 findSigInfo.needcache = False