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