blob: 378f389b3acb93141537e1202e670bd301250fc1 [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
Patrick Williamsc124f4f2015-09-15 14:41:29 -050023import bb.event
24import bb.cooker
Brad Bishop6e60e8b2018-02-01 10:27:11 -050025import bb.remotedata
26
27class DataStoreConnectionHandle(object):
28 def __init__(self, dsindex=0):
29 self.dsindex = dsindex
Patrick Williamsc124f4f2015-09-15 14:41:29 -050030
31class CommandCompleted(bb.event.Event):
32 pass
33
34class CommandExit(bb.event.Event):
35 def __init__(self, exitcode):
36 bb.event.Event.__init__(self)
37 self.exitcode = int(exitcode)
38
39class CommandFailed(CommandExit):
40 def __init__(self, message):
41 self.error = message
42 CommandExit.__init__(self, 1)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050043 def __str__(self):
44 return "Command execution failed: %s" % self.error
Patrick Williamsc124f4f2015-09-15 14:41:29 -050045
46class CommandError(Exception):
47 pass
48
49class Command:
50 """
51 A queue of asynchronous commands for bitbake
52 """
53 def __init__(self, cooker):
54 self.cooker = cooker
55 self.cmds_sync = CommandsSync()
56 self.cmds_async = CommandsAsync()
Brad Bishop6e60e8b2018-02-01 10:27:11 -050057 self.remotedatastores = bb.remotedata.RemoteDatastores(cooker)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050058
59 # FIXME Add lock for this
60 self.currentAsyncCommand = None
61
62 def runCommand(self, commandline, ro_only = False):
63 command = commandline.pop(0)
64 if hasattr(CommandsSync, command):
65 # Can run synchronous commands straight away
66 command_method = getattr(self.cmds_sync, command)
67 if ro_only:
68 if not hasattr(command_method, 'readonly') or False == getattr(command_method, 'readonly'):
69 return None, "Not able to execute not readonly commands in readonly mode"
70 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -050071 self.cooker.process_inotify_updates()
72 if getattr(command_method, 'needconfig', True):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050073 self.cooker.updateCacheSync()
74 result = command_method(self, commandline)
75 except CommandError as exc:
76 return None, exc.args[0]
77 except (Exception, SystemExit):
78 import traceback
79 return None, traceback.format_exc()
80 else:
81 return result, None
82 if self.currentAsyncCommand is not None:
83 return None, "Busy (%s in progress)" % self.currentAsyncCommand[0]
84 if command not in CommandsAsync.__dict__:
85 return None, "No such command"
86 self.currentAsyncCommand = (command, commandline)
87 self.cooker.configuration.server_register_idlecallback(self.cooker.runCommands, self.cooker)
88 return True, None
89
90 def runAsyncCommand(self):
91 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -050092 self.cooker.process_inotify_updates()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050093 if self.cooker.state in (bb.cooker.state.error, bb.cooker.state.shutdown, bb.cooker.state.forceshutdown):
94 # updateCache will trigger a shutdown of the parser
95 # and then raise BBHandledException triggering an exit
96 self.cooker.updateCache()
97 return False
98 if self.currentAsyncCommand is not None:
99 (command, options) = self.currentAsyncCommand
100 commandmethod = getattr(CommandsAsync, command)
101 needcache = getattr( commandmethod, "needcache" )
102 if needcache and self.cooker.state != bb.cooker.state.running:
103 self.cooker.updateCache()
104 return True
105 else:
106 commandmethod(self.cmds_async, self, options)
107 return False
108 else:
109 return False
110 except KeyboardInterrupt as exc:
111 self.finishAsyncCommand("Interrupted")
112 return False
113 except SystemExit as exc:
114 arg = exc.args[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600115 if isinstance(arg, str):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500116 self.finishAsyncCommand(arg)
117 else:
118 self.finishAsyncCommand("Exited with %s" % arg)
119 return False
120 except Exception as exc:
121 import traceback
122 if isinstance(exc, bb.BBHandledException):
123 self.finishAsyncCommand("")
124 else:
125 self.finishAsyncCommand(traceback.format_exc())
126 return False
127
128 def finishAsyncCommand(self, msg=None, code=None):
129 if msg or msg == "":
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500130 bb.event.fire(CommandFailed(msg), self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500131 elif code:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500132 bb.event.fire(CommandExit(code), self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500133 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500134 bb.event.fire(CommandCompleted(), self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500135 self.currentAsyncCommand = None
136 self.cooker.finishcommand()
137
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500138 def reset(self):
139 self.remotedatastores = bb.remotedata.RemoteDatastores(self.cooker)
140
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500141def split_mc_pn(pn):
142 if pn.startswith("multiconfig:"):
143 _, mc, pn = pn.split(":", 2)
144 return (mc, pn)
145 return ('', pn)
146
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500147class CommandsSync:
148 """
149 A class of synchronous commands
150 These should run quickly so as not to hurt interactive performance.
151 These must not influence any running synchronous command.
152 """
153
154 def stateShutdown(self, command, params):
155 """
156 Trigger cooker 'shutdown' mode
157 """
158 command.cooker.shutdown(False)
159
160 def stateForceShutdown(self, command, params):
161 """
162 Stop the cooker
163 """
164 command.cooker.shutdown(True)
165
166 def getAllKeysWithFlags(self, command, params):
167 """
168 Returns a dump of the global state. Call with
169 variable flags to be retrieved as params.
170 """
171 flaglist = params[0]
172 return command.cooker.getAllKeysWithFlags(flaglist)
173 getAllKeysWithFlags.readonly = True
174
175 def getVariable(self, command, params):
176 """
177 Read the value of a variable from data
178 """
179 varname = params[0]
180 expand = True
181 if len(params) > 1:
182 expand = (params[1] == "True")
183
184 return command.cooker.data.getVar(varname, expand)
185 getVariable.readonly = True
186
187 def setVariable(self, command, params):
188 """
189 Set the value of variable in data
190 """
191 varname = params[0]
192 value = str(params[1])
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500193 command.cooker.extraconfigdata[varname] = value
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500194 command.cooker.data.setVar(varname, value)
195
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500196 def getSetVariable(self, command, params):
197 """
198 Read the value of a variable from data and set it into the datastore
199 which effectively expands and locks the value.
200 """
201 varname = params[0]
202 result = self.getVariable(command, params)
203 command.cooker.data.setVar(varname, result)
204 return result
205
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500206 def setConfig(self, command, params):
207 """
208 Set the value of variable in configuration
209 """
210 varname = params[0]
211 value = str(params[1])
212 setattr(command.cooker.configuration, varname, value)
213
214 def enableDataTracking(self, command, params):
215 """
216 Enable history tracking for variables
217 """
218 command.cooker.enableDataTracking()
219
220 def disableDataTracking(self, command, params):
221 """
222 Disable history tracking for variables
223 """
224 command.cooker.disableDataTracking()
225
226 def setPrePostConfFiles(self, command, params):
227 prefiles = params[0].split()
228 postfiles = params[1].split()
229 command.cooker.configuration.prefile = prefiles
230 command.cooker.configuration.postfile = postfiles
231 setPrePostConfFiles.needconfig = False
232
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500233 def matchFile(self, command, params):
234 fMatch = params[0]
235 return command.cooker.matchFile(fMatch)
236 matchFile.needconfig = False
237
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500238 def getUIHandlerNum(self, command, params):
239 return bb.event.get_uihandler()
240 getUIHandlerNum.needconfig = False
241 getUIHandlerNum.readonly = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500242
243 def setEventMask(self, command, params):
244 handlerNum = params[0]
245 llevel = params[1]
246 debug_domains = params[2]
247 mask = params[3]
248 return bb.event.set_UIHmask(handlerNum, llevel, debug_domains, mask)
249 setEventMask.needconfig = False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500250 setEventMask.readonly = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500251
252 def setFeatures(self, command, params):
253 """
254 Set the cooker features to include the passed list of features
255 """
256 features = params[0]
257 command.cooker.setFeatures(features)
258 setFeatures.needconfig = False
259 # although we change the internal state of the cooker, this is transparent since
260 # we always take and leave the cooker in state.initial
261 setFeatures.readonly = True
262
263 def updateConfig(self, command, params):
264 options = params[0]
265 environment = params[1]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500266 cmdline = params[2]
267 command.cooker.updateConfigOpts(options, environment, cmdline)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500268 updateConfig.needconfig = False
269
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500270 def parseConfiguration(self, command, params):
271 """Instruct bitbake to parse its configuration
272 NOTE: it is only necessary to call this if you aren't calling any normal action
273 (otherwise parsing is taken care of automatically)
274 """
275 command.cooker.parseConfiguration()
276 parseConfiguration.needconfig = False
277
278 def getLayerPriorities(self, command, params):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500279 command.cooker.parseConfiguration()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500280 ret = []
281 # regex objects cannot be marshalled by xmlrpc
282 for collection, pattern, regex, pri in command.cooker.bbfile_config_priorities:
283 ret.append((collection, pattern, regex.pattern, pri))
284 return ret
285 getLayerPriorities.readonly = True
286
287 def getRecipes(self, command, params):
288 try:
289 mc = params[0]
290 except IndexError:
291 mc = ''
292 return list(command.cooker.recipecaches[mc].pkg_pn.items())
293 getRecipes.readonly = True
294
295 def getRecipeDepends(self, command, params):
296 try:
297 mc = params[0]
298 except IndexError:
299 mc = ''
300 return list(command.cooker.recipecaches[mc].deps.items())
301 getRecipeDepends.readonly = True
302
303 def getRecipeVersions(self, command, params):
304 try:
305 mc = params[0]
306 except IndexError:
307 mc = ''
308 return command.cooker.recipecaches[mc].pkg_pepvpr
309 getRecipeVersions.readonly = True
310
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500311 def getRecipeProvides(self, command, params):
312 try:
313 mc = params[0]
314 except IndexError:
315 mc = ''
316 return command.cooker.recipecaches[mc].fn_provides
317 getRecipeProvides.readonly = True
318
319 def getRecipePackages(self, command, params):
320 try:
321 mc = params[0]
322 except IndexError:
323 mc = ''
324 return command.cooker.recipecaches[mc].packages
325 getRecipePackages.readonly = True
326
327 def getRecipePackagesDynamic(self, command, params):
328 try:
329 mc = params[0]
330 except IndexError:
331 mc = ''
332 return command.cooker.recipecaches[mc].packages_dynamic
333 getRecipePackagesDynamic.readonly = True
334
335 def getRProviders(self, command, params):
336 try:
337 mc = params[0]
338 except IndexError:
339 mc = ''
340 return command.cooker.recipecaches[mc].rproviders
341 getRProviders.readonly = True
342
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500343 def getRuntimeDepends(self, command, params):
344 ret = []
345 try:
346 mc = params[0]
347 except IndexError:
348 mc = ''
349 rundeps = command.cooker.recipecaches[mc].rundeps
350 for key, value in rundeps.items():
351 if isinstance(value, defaultdict):
352 value = dict(value)
353 ret.append((key, value))
354 return ret
355 getRuntimeDepends.readonly = True
356
357 def getRuntimeRecommends(self, command, params):
358 ret = []
359 try:
360 mc = params[0]
361 except IndexError:
362 mc = ''
363 runrecs = command.cooker.recipecaches[mc].runrecs
364 for key, value in runrecs.items():
365 if isinstance(value, defaultdict):
366 value = dict(value)
367 ret.append((key, value))
368 return ret
369 getRuntimeRecommends.readonly = True
370
371 def getRecipeInherits(self, command, params):
372 try:
373 mc = params[0]
374 except IndexError:
375 mc = ''
376 return command.cooker.recipecaches[mc].inherits
377 getRecipeInherits.readonly = True
378
379 def getBbFilePriority(self, command, params):
380 try:
381 mc = params[0]
382 except IndexError:
383 mc = ''
384 return command.cooker.recipecaches[mc].bbfile_priority
385 getBbFilePriority.readonly = True
386
387 def getDefaultPreference(self, command, params):
388 try:
389 mc = params[0]
390 except IndexError:
391 mc = ''
392 return command.cooker.recipecaches[mc].pkg_dp
393 getDefaultPreference.readonly = True
394
395 def getSkippedRecipes(self, command, params):
396 # Return list sorted by reverse priority order
397 import bb.cache
398 skipdict = OrderedDict(sorted(command.cooker.skiplist.items(),
399 key=lambda x: (-command.cooker.collection.calc_bbfile_priority(bb.cache.virtualfn2realfn(x[0])[0]), x[0])))
400 return list(skipdict.items())
401 getSkippedRecipes.readonly = True
402
403 def getOverlayedRecipes(self, command, params):
404 return list(command.cooker.collection.overlayed.items())
405 getOverlayedRecipes.readonly = True
406
407 def getFileAppends(self, command, params):
408 fn = params[0]
409 return command.cooker.collection.get_file_appends(fn)
410 getFileAppends.readonly = True
411
412 def getAllAppends(self, command, params):
413 return command.cooker.collection.bbappends
414 getAllAppends.readonly = True
415
416 def findProviders(self, command, params):
417 return command.cooker.findProviders()
418 findProviders.readonly = True
419
420 def findBestProvider(self, command, params):
421 (mc, pn) = split_mc_pn(params[0])
422 return command.cooker.findBestProvider(pn, mc)
423 findBestProvider.readonly = True
424
425 def allProviders(self, command, params):
426 try:
427 mc = params[0]
428 except IndexError:
429 mc = ''
430 return list(bb.providers.allProviders(command.cooker.recipecaches[mc]).items())
431 allProviders.readonly = True
432
433 def getRuntimeProviders(self, command, params):
434 rprovide = params[0]
435 try:
436 mc = params[1]
437 except IndexError:
438 mc = ''
439 all_p = bb.providers.getRuntimeProviders(command.cooker.recipecaches[mc], rprovide)
440 if all_p:
441 best = bb.providers.filterProvidersRunTime(all_p, rprovide,
442 command.cooker.data,
443 command.cooker.recipecaches[mc])[0][0]
444 else:
445 best = None
446 return all_p, best
447 getRuntimeProviders.readonly = True
448
449 def dataStoreConnectorFindVar(self, command, params):
450 dsindex = params[0]
451 name = params[1]
452 datastore = command.remotedatastores[dsindex]
453 value, overridedata = datastore._findVar(name)
454
455 if value:
456 content = value.get('_content', None)
457 if isinstance(content, bb.data_smart.DataSmart):
458 # Value is a datastore (e.g. BB_ORIGENV) - need to handle this carefully
459 idx = command.remotedatastores.check_store(content, True)
460 return {'_content': DataStoreConnectionHandle(idx),
461 '_connector_origtype': 'DataStoreConnectionHandle',
462 '_connector_overrides': overridedata}
463 elif isinstance(content, set):
464 return {'_content': list(content),
465 '_connector_origtype': 'set',
466 '_connector_overrides': overridedata}
467 else:
468 value['_connector_overrides'] = overridedata
469 else:
470 value = {}
471 value['_connector_overrides'] = overridedata
472 return value
473 dataStoreConnectorFindVar.readonly = True
474
475 def dataStoreConnectorGetKeys(self, command, params):
476 dsindex = params[0]
477 datastore = command.remotedatastores[dsindex]
478 return list(datastore.keys())
479 dataStoreConnectorGetKeys.readonly = True
480
481 def dataStoreConnectorGetVarHistory(self, command, params):
482 dsindex = params[0]
483 name = params[1]
484 datastore = command.remotedatastores[dsindex]
485 return datastore.varhistory.variable(name)
486 dataStoreConnectorGetVarHistory.readonly = True
487
488 def dataStoreConnectorExpandPythonRef(self, command, params):
489 config_data_dict = params[0]
490 varname = params[1]
491 expr = params[2]
492
493 config_data = command.remotedatastores.receive_datastore(config_data_dict)
494
495 varparse = bb.data_smart.VariableParse(varname, config_data)
496 return varparse.python_sub(expr)
497
498 def dataStoreConnectorRelease(self, command, params):
499 dsindex = params[0]
500 if dsindex <= 0:
501 raise CommandError('dataStoreConnectorRelease: invalid index %d' % dsindex)
502 command.remotedatastores.release(dsindex)
503
504 def dataStoreConnectorSetVarFlag(self, command, params):
505 dsindex = params[0]
506 name = params[1]
507 flag = params[2]
508 value = params[3]
509 datastore = command.remotedatastores[dsindex]
510 datastore.setVarFlag(name, flag, value)
511
512 def dataStoreConnectorDelVar(self, command, params):
513 dsindex = params[0]
514 name = params[1]
515 datastore = command.remotedatastores[dsindex]
516 if len(params) > 2:
517 flag = params[2]
518 datastore.delVarFlag(name, flag)
519 else:
520 datastore.delVar(name)
521
522 def dataStoreConnectorRenameVar(self, command, params):
523 dsindex = params[0]
524 name = params[1]
525 newname = params[2]
526 datastore = command.remotedatastores[dsindex]
527 datastore.renameVar(name, newname)
528
529 def parseRecipeFile(self, command, params):
530 """
531 Parse the specified recipe file (with or without bbappends)
532 and return a datastore object representing the environment
533 for the recipe.
534 """
535 fn = params[0]
536 appends = params[1]
537 appendlist = params[2]
538 if len(params) > 3:
539 config_data_dict = params[3]
540 config_data = command.remotedatastores.receive_datastore(config_data_dict)
541 else:
542 config_data = None
543
544 if appends:
545 if appendlist is not None:
546 appendfiles = appendlist
547 else:
548 appendfiles = command.cooker.collection.get_file_appends(fn)
549 else:
550 appendfiles = []
551 # We are calling bb.cache locally here rather than on the server,
552 # but that's OK because it doesn't actually need anything from
553 # the server barring the global datastore (which we have a remote
554 # version of)
555 if config_data:
556 # We have to use a different function here if we're passing in a datastore
557 # NOTE: we took a copy above, so we don't do it here again
558 envdata = bb.cache.parse_recipe(config_data, fn, appendfiles)['']
559 else:
560 # Use the standard path
561 parser = bb.cache.NoCache(command.cooker.databuilder)
562 envdata = parser.loadDataFull(fn, appendfiles)
563 idx = command.remotedatastores.store(envdata)
564 return DataStoreConnectionHandle(idx)
565 parseRecipeFile.readonly = True
566
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500567class CommandsAsync:
568 """
569 A class of asynchronous commands
570 These functions communicate via generated events.
571 Any function that requires metadata parsing should be here.
572 """
573
574 def buildFile(self, command, params):
575 """
576 Build a single specified .bb file
577 """
578 bfile = params[0]
579 task = params[1]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500580 if len(params) > 2:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500581 internal = params[2]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500582 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500583 internal = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500584
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500585 if internal:
586 command.cooker.buildFileInternal(bfile, task, fireevents=False, quietlog=True)
587 else:
588 command.cooker.buildFile(bfile, task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500589 buildFile.needcache = False
590
591 def buildTargets(self, command, params):
592 """
593 Build a set of targets
594 """
595 pkgs_to_build = params[0]
596 task = params[1]
597
598 command.cooker.buildTargets(pkgs_to_build, task)
599 buildTargets.needcache = True
600
601 def generateDepTreeEvent(self, command, params):
602 """
603 Generate an event containing the dependency information
604 """
605 pkgs_to_build = params[0]
606 task = params[1]
607
608 command.cooker.generateDepTreeEvent(pkgs_to_build, task)
609 command.finishAsyncCommand()
610 generateDepTreeEvent.needcache = True
611
612 def generateDotGraph(self, command, params):
613 """
614 Dump dependency information to disk as .dot files
615 """
616 pkgs_to_build = params[0]
617 task = params[1]
618
619 command.cooker.generateDotGraphFiles(pkgs_to_build, task)
620 command.finishAsyncCommand()
621 generateDotGraph.needcache = True
622
623 def generateTargetsTree(self, command, params):
624 """
625 Generate a tree of buildable targets.
626 If klass is provided ensure all recipes that inherit the class are
627 included in the package list.
628 If pkg_list provided use that list (plus any extras brought in by
629 klass) rather than generating a tree for all packages.
630 """
631 klass = params[0]
632 pkg_list = params[1]
633
634 command.cooker.generateTargetsTree(klass, pkg_list)
635 command.finishAsyncCommand()
636 generateTargetsTree.needcache = True
637
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500638 def findConfigFiles(self, command, params):
639 """
640 Find config files which provide appropriate values
641 for the passed configuration variable. i.e. MACHINE
642 """
643 varname = params[0]
644
645 command.cooker.findConfigFiles(varname)
646 command.finishAsyncCommand()
647 findConfigFiles.needcache = False
648
649 def findFilesMatchingInDir(self, command, params):
650 """
651 Find implementation files matching the specified pattern
652 in the requested subdirectory of a BBPATH
653 """
654 pattern = params[0]
655 directory = params[1]
656
657 command.cooker.findFilesMatchingInDir(pattern, directory)
658 command.finishAsyncCommand()
659 findFilesMatchingInDir.needcache = False
660
661 def findConfigFilePath(self, command, params):
662 """
663 Find the path of the requested configuration file
664 """
665 configfile = params[0]
666
667 command.cooker.findConfigFilePath(configfile)
668 command.finishAsyncCommand()
669 findConfigFilePath.needcache = False
670
671 def showVersions(self, command, params):
672 """
673 Show the currently selected versions
674 """
675 command.cooker.showVersions()
676 command.finishAsyncCommand()
677 showVersions.needcache = True
678
679 def showEnvironmentTarget(self, command, params):
680 """
681 Print the environment of a target recipe
682 (needs the cache to work out which recipe to use)
683 """
684 pkg = params[0]
685
686 command.cooker.showEnvironment(None, pkg)
687 command.finishAsyncCommand()
688 showEnvironmentTarget.needcache = True
689
690 def showEnvironment(self, command, params):
691 """
692 Print the standard environment
693 or if specified the environment for a specified recipe
694 """
695 bfile = params[0]
696
697 command.cooker.showEnvironment(bfile)
698 command.finishAsyncCommand()
699 showEnvironment.needcache = False
700
701 def parseFiles(self, command, params):
702 """
703 Parse the .bb files
704 """
705 command.cooker.updateCache()
706 command.finishAsyncCommand()
707 parseFiles.needcache = True
708
709 def compareRevisions(self, command, params):
710 """
711 Parse the .bb files
712 """
713 if bb.fetch.fetcher_compare_revisions(command.cooker.data):
714 command.finishAsyncCommand(code=1)
715 else:
716 command.finishAsyncCommand()
717 compareRevisions.needcache = True
718
719 def triggerEvent(self, command, params):
720 """
721 Trigger a certain event
722 """
723 event = params[0]
724 bb.event.fire(eval(event), command.cooker.data)
725 command.currentAsyncCommand = None
726 triggerEvent.needcache = False
727
728 def resetCooker(self, command, params):
729 """
730 Reset the cooker to its initial state, thus forcing a reparse for
731 any async command that has the needcache property set to True
732 """
733 command.cooker.reset()
734 command.finishAsyncCommand()
735 resetCooker.needcache = False
736
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500737 def clientComplete(self, command, params):
738 """
739 Do the right thing when the controlling client exits
740 """
741 command.cooker.clientComplete()
742 command.finishAsyncCommand()
743 clientComplete.needcache = False
744
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500745 def findSigInfo(self, command, params):
746 """
747 Find signature info files via the signature generator
748 """
749 pn = params[0]
750 taskname = params[1]
751 sigs = params[2]
752 res = bb.siggen.find_siginfo(pn, taskname, sigs, command.cooker.data)
753 bb.event.fire(bb.event.FindSigInfoResult(res), command.cooker.data)
754 command.finishAsyncCommand()
755 findSigInfo.needcache = False