summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/command.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/command.py')
-rw-r--r--bitbake/lib/bb/command.py813
1 files changed, 0 insertions, 813 deletions
diff --git a/bitbake/lib/bb/command.py b/bitbake/lib/bb/command.py
deleted file mode 100644
index 59a979ee90..0000000000
--- a/bitbake/lib/bb/command.py
+++ /dev/null
@@ -1,813 +0,0 @@
1"""
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# SPDX-License-Identifier: GPL-2.0-only
10#
11
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
21from collections import OrderedDict, defaultdict
22
23import io
24import bb.event
25import bb.cooker
26import bb.remotedata
27import bb.parse
28
29class DataStoreConnectionHandle(object):
30 def __init__(self, dsindex=0):
31 self.dsindex = dsindex
32
33class CommandCompleted(bb.event.Event):
34 pass
35
36class CommandExit(bb.event.Event):
37 def __init__(self, exitcode):
38 bb.event.Event.__init__(self)
39 self.exitcode = int(exitcode)
40
41class CommandFailed(CommandExit):
42 def __init__(self, message):
43 self.error = message
44 CommandExit.__init__(self, 1)
45 def __str__(self):
46 return "Command execution failed: %s" % self.error
47
48class CommandError(Exception):
49 pass
50
51class Command:
52 """
53 A queue of asynchronous commands for bitbake
54 """
55 def __init__(self, cooker, process_server):
56 self.cooker = cooker
57 self.cmds_sync = CommandsSync()
58 self.cmds_async = CommandsAsync()
59 self.remotedatastores = None
60
61 self.process_server = process_server
62 # Access with locking using process_server.{get/set/clear}_async_cmd()
63 self.currentAsyncCommand = None
64
65 def runCommand(self, commandline, process_server, ro_only=False):
66 command = commandline.pop(0)
67
68 # Ensure cooker is ready for commands
69 if command not in ["updateConfig", "setFeatures", "ping"]:
70 try:
71 self.cooker.init_configdata()
72 if not self.remotedatastores:
73 self.remotedatastores = bb.remotedata.RemoteDatastores(self.cooker)
74 except (Exception, SystemExit) as exc:
75 import traceback
76 if isinstance(exc, bb.BBHandledException):
77 # We need to start returning real exceptions here. Until we do, we can't
78 # tell if an exception is an instance of bb.BBHandledException
79 return None, "bb.BBHandledException()\n" + traceback.format_exc()
80 return None, traceback.format_exc()
81
82 if hasattr(CommandsSync, command):
83 # Can run synchronous commands straight away
84 command_method = getattr(self.cmds_sync, command)
85 if ro_only:
86 if not hasattr(command_method, 'readonly') or not getattr(command_method, 'readonly'):
87 return None, "Not able to execute not readonly commands in readonly mode"
88 try:
89 if getattr(command_method, 'needconfig', True):
90 self.cooker.updateCacheSync()
91 result = command_method(self, commandline)
92 except CommandError as exc:
93 return None, exc.args[0]
94 except (Exception, SystemExit) as exc:
95 import traceback
96 if isinstance(exc, bb.BBHandledException):
97 # We need to start returning real exceptions here. Until we do, we can't
98 # tell if an exception is an instance of bb.BBHandledException
99 return None, "bb.BBHandledException()\n" + traceback.format_exc()
100 return None, traceback.format_exc()
101 else:
102 return result, None
103 if command not in CommandsAsync.__dict__:
104 return None, "No such command"
105 if not process_server.set_async_cmd((command, commandline)):
106 return None, "Busy (%s in progress)" % self.process_server.get_async_cmd()[0]
107 self.cooker.idleCallBackRegister(self.runAsyncCommand, process_server)
108 return True, None
109
110 def runAsyncCommand(self, _, process_server, halt):
111 try:
112 if self.cooker.state in (bb.cooker.State.ERROR, bb.cooker.State.SHUTDOWN, bb.cooker.State.FORCE_SHUTDOWN):
113 # updateCache will trigger a shutdown of the parser
114 # and then raise BBHandledException triggering an exit
115 self.cooker.updateCache()
116 return bb.server.process.idleFinish("Cooker in error state")
117 cmd = process_server.get_async_cmd()
118 if cmd is not None:
119 (command, options) = cmd
120 commandmethod = getattr(CommandsAsync, command)
121 needcache = getattr( commandmethod, "needcache" )
122 if needcache and self.cooker.state != bb.cooker.State.RUNNING:
123 self.cooker.updateCache()
124 return True
125 else:
126 commandmethod(self.cmds_async, self, options)
127 return False
128 else:
129 return bb.server.process.idleFinish("Nothing to do, no async command?")
130 except KeyboardInterrupt as exc:
131 return bb.server.process.idleFinish("Interrupted")
132 except SystemExit as exc:
133 arg = exc.args[0]
134 if isinstance(arg, str):
135 return bb.server.process.idleFinish(arg)
136 else:
137 return bb.server.process.idleFinish("Exited with %s" % arg)
138 except Exception as exc:
139 import traceback
140 if isinstance(exc, bb.BBHandledException):
141 return bb.server.process.idleFinish("")
142 else:
143 return bb.server.process.idleFinish(traceback.format_exc())
144
145 def finishAsyncCommand(self, msg=None, code=None):
146 self.cooker.finishcommand()
147 self.process_server.clear_async_cmd()
148 if msg or msg == "":
149 bb.event.fire(CommandFailed(msg), self.cooker.data)
150 elif code:
151 bb.event.fire(CommandExit(code), self.cooker.data)
152 else:
153 bb.event.fire(CommandCompleted(), self.cooker.data)
154
155 def reset(self):
156 if self.remotedatastores:
157 self.remotedatastores = bb.remotedata.RemoteDatastores(self.cooker)
158
159class CommandsSync:
160 """
161 A class of synchronous commands
162 These should run quickly so as not to hurt interactive performance.
163 These must not influence any running synchronous command.
164 """
165
166 def ping(self, command, params):
167 """
168 Allow a UI to check the server is still alive
169 """
170 return "Still alive!"
171 ping.needconfig = False
172 ping.readonly = True
173
174 def stateShutdown(self, command, params):
175 """
176 Trigger cooker 'shutdown' mode
177 """
178 command.cooker.shutdown(False)
179
180 def stateForceShutdown(self, command, params):
181 """
182 Stop the cooker
183 """
184 command.cooker.shutdown(True)
185
186 def getAllKeysWithFlags(self, command, params):
187 """
188 Returns a dump of the global state. Call with
189 variable flags to be retrieved as params.
190 """
191 flaglist = params[0]
192 return command.cooker.getAllKeysWithFlags(flaglist)
193 getAllKeysWithFlags.readonly = True
194
195 def getVariable(self, command, params):
196 """
197 Read the value of a variable from data
198 """
199 varname = params[0]
200 expand = True
201 if len(params) > 1:
202 expand = (params[1] == "True")
203
204 return command.cooker.data.getVar(varname, expand)
205 getVariable.readonly = True
206
207 def setVariable(self, command, params):
208 """
209 Set the value of variable in data
210 """
211 varname = params[0]
212 value = str(params[1])
213 command.cooker.extraconfigdata[varname] = value
214 command.cooker.data.setVar(varname, value)
215
216 def getSetVariable(self, command, params):
217 """
218 Read the value of a variable from data and set it into the datastore
219 which effectively expands and locks the value.
220 """
221 varname = params[0]
222 result = self.getVariable(command, params)
223 command.cooker.data.setVar(varname, result)
224 return result
225
226 def setConfig(self, command, params):
227 """
228 Set the value of variable in configuration
229 """
230 varname = params[0]
231 value = str(params[1])
232 setattr(command.cooker.configuration, varname, value)
233
234 def enableDataTracking(self, command, params):
235 """
236 Enable history tracking for variables
237 """
238 command.cooker.enableDataTracking()
239
240 def disableDataTracking(self, command, params):
241 """
242 Disable history tracking for variables
243 """
244 command.cooker.disableDataTracking()
245
246 def setPrePostConfFiles(self, command, params):
247 prefiles = params[0].split()
248 postfiles = params[1].split()
249 command.cooker.configuration.prefile = prefiles
250 command.cooker.configuration.postfile = postfiles
251 setPrePostConfFiles.needconfig = False
252
253 def matchFile(self, command, params):
254 fMatch = params[0]
255 try:
256 mc = params[0]
257 except IndexError:
258 mc = ''
259 return command.cooker.matchFile(fMatch, mc)
260 matchFile.needconfig = False
261
262 def getUIHandlerNum(self, command, params):
263 return bb.event.get_uihandler()
264 getUIHandlerNum.needconfig = False
265 getUIHandlerNum.readonly = True
266
267 def setEventMask(self, command, params):
268 handlerNum = params[0]
269 llevel = params[1]
270 debug_domains = params[2]
271 mask = params[3]
272 return bb.event.set_UIHmask(handlerNum, llevel, debug_domains, mask)
273 setEventMask.needconfig = False
274 setEventMask.readonly = True
275
276 def setFeatures(self, command, params):
277 """
278 Set the cooker features to include the passed list of features
279 """
280 features = params[0]
281 command.cooker.setFeatures(features)
282 setFeatures.needconfig = False
283 # although we change the internal state of the cooker, this is transparent since
284 # we always take and leave the cooker in state.initial
285 setFeatures.readonly = True
286
287 def updateConfig(self, command, params):
288 options = params[0]
289 environment = params[1]
290 cmdline = params[2]
291 command.cooker.updateConfigOpts(options, environment, cmdline)
292 updateConfig.needconfig = False
293
294 def parseConfiguration(self, command, params):
295 """Instruct bitbake to parse its configuration
296 NOTE: it is only necessary to call this if you aren't calling any normal action
297 (otherwise parsing is taken care of automatically)
298 """
299 command.cooker.parseConfiguration()
300 parseConfiguration.needconfig = False
301
302 def getLayerPriorities(self, command, params):
303 command.cooker.parseConfiguration()
304 ret = []
305 # regex objects cannot be marshalled by xmlrpc
306 for collection, pattern, regex, pri in command.cooker.bbfile_config_priorities:
307 ret.append((collection, pattern, regex.pattern, pri))
308 return ret
309 getLayerPriorities.readonly = True
310
311 def revalidateCaches(self, command, params):
312 """Called by UI clients when metadata may have changed"""
313 command.cooker.revalidateCaches()
314 revalidateCaches.needconfig = False
315
316 def getRecipes(self, command, params):
317 try:
318 mc = params[0]
319 except IndexError:
320 mc = ''
321 return list(command.cooker.recipecaches[mc].pkg_pn.items())
322 getRecipes.readonly = True
323
324 def getRecipeDepends(self, command, params):
325 try:
326 mc = params[0]
327 except IndexError:
328 mc = ''
329 return list(command.cooker.recipecaches[mc].deps.items())
330 getRecipeDepends.readonly = True
331
332 def getRecipeVersions(self, command, params):
333 try:
334 mc = params[0]
335 except IndexError:
336 mc = ''
337 return command.cooker.recipecaches[mc].pkg_pepvpr
338 getRecipeVersions.readonly = True
339
340 def getRecipeProvides(self, command, params):
341 try:
342 mc = params[0]
343 except IndexError:
344 mc = ''
345 return command.cooker.recipecaches[mc].fn_provides
346 getRecipeProvides.readonly = True
347
348 def getRecipePackages(self, command, params):
349 try:
350 mc = params[0]
351 except IndexError:
352 mc = ''
353 return command.cooker.recipecaches[mc].packages
354 getRecipePackages.readonly = True
355
356 def getRecipePackagesDynamic(self, command, params):
357 try:
358 mc = params[0]
359 except IndexError:
360 mc = ''
361 return command.cooker.recipecaches[mc].packages_dynamic
362 getRecipePackagesDynamic.readonly = True
363
364 def getRProviders(self, command, params):
365 try:
366 mc = params[0]
367 except IndexError:
368 mc = ''
369 return command.cooker.recipecaches[mc].rproviders
370 getRProviders.readonly = True
371
372 def getRuntimeDepends(self, command, params):
373 ret = []
374 try:
375 mc = params[0]
376 except IndexError:
377 mc = ''
378 rundeps = command.cooker.recipecaches[mc].rundeps
379 for key, value in rundeps.items():
380 if isinstance(value, defaultdict):
381 value = dict(value)
382 ret.append((key, value))
383 return ret
384 getRuntimeDepends.readonly = True
385
386 def getRuntimeRecommends(self, command, params):
387 ret = []
388 try:
389 mc = params[0]
390 except IndexError:
391 mc = ''
392 runrecs = command.cooker.recipecaches[mc].runrecs
393 for key, value in runrecs.items():
394 if isinstance(value, defaultdict):
395 value = dict(value)
396 ret.append((key, value))
397 return ret
398 getRuntimeRecommends.readonly = True
399
400 def getRecipeInherits(self, command, params):
401 try:
402 mc = params[0]
403 except IndexError:
404 mc = ''
405 return command.cooker.recipecaches[mc].inherits
406 getRecipeInherits.readonly = True
407
408 def getBbFilePriority(self, command, params):
409 try:
410 mc = params[0]
411 except IndexError:
412 mc = ''
413 return command.cooker.recipecaches[mc].bbfile_priority
414 getBbFilePriority.readonly = True
415
416 def getDefaultPreference(self, command, params):
417 try:
418 mc = params[0]
419 except IndexError:
420 mc = ''
421 return command.cooker.recipecaches[mc].pkg_dp
422 getDefaultPreference.readonly = True
423
424
425 def getSkippedRecipes(self, command, params):
426 """
427 Get the map of skipped recipes for the specified multiconfig/mc name (`params[0]`).
428
429 Invoked by `bb.tinfoil.Tinfoil.get_skipped_recipes`
430
431 :param command: Internally used parameter.
432 :param params: Parameter array. params[0] is multiconfig/mc name. If not given, then default mc '' is assumed.
433 :return: Dict whose keys are virtualfns and values are `bb.cooker.SkippedPackage`
434 """
435 try:
436 mc = params[0]
437 except IndexError:
438 mc = ''
439
440 # Return list sorted by reverse priority order
441 import bb.cache
442 def sortkey(x):
443 vfn, _ = x
444 realfn, _, item_mc = bb.cache.virtualfn2realfn(vfn)
445 return -command.cooker.collections[item_mc].calc_bbfile_priority(realfn)[0], vfn
446
447 skipdict = OrderedDict(sorted(command.cooker.skiplist_by_mc[mc].items(), key=sortkey))
448 return list(skipdict.items())
449 getSkippedRecipes.readonly = True
450
451 def getOverlayedRecipes(self, command, params):
452 try:
453 mc = params[0]
454 except IndexError:
455 mc = ''
456 return list(command.cooker.collections[mc].overlayed.items())
457 getOverlayedRecipes.readonly = True
458
459 def getFileAppends(self, command, params):
460 fn = params[0]
461 try:
462 mc = params[1]
463 except IndexError:
464 mc = ''
465 return command.cooker.collections[mc].get_file_appends(fn)
466 getFileAppends.readonly = True
467
468 def getAllAppends(self, command, params):
469 try:
470 mc = params[0]
471 except IndexError:
472 mc = ''
473 return command.cooker.collections[mc].bbappends
474 getAllAppends.readonly = True
475
476 def findProviders(self, command, params):
477 try:
478 mc = params[0]
479 except IndexError:
480 mc = ''
481 return command.cooker.findProviders(mc)
482 findProviders.readonly = True
483
484 def findBestProvider(self, command, params):
485 (mc, pn) = bb.runqueue.split_mc(params[0])
486 return command.cooker.findBestProvider(pn, mc)
487 findBestProvider.readonly = True
488
489 def allProviders(self, command, params):
490 try:
491 mc = params[0]
492 except IndexError:
493 mc = ''
494 return list(bb.providers.allProviders(command.cooker.recipecaches[mc]).items())
495 allProviders.readonly = True
496
497 def getRuntimeProviders(self, command, params):
498 rprovide = params[0]
499 try:
500 mc = params[1]
501 except IndexError:
502 mc = ''
503 all_p = bb.providers.getRuntimeProviders(command.cooker.recipecaches[mc], rprovide)
504 if all_p:
505 best = bb.providers.filterProvidersRunTime(all_p, rprovide,
506 command.cooker.data,
507 command.cooker.recipecaches[mc])[0][0]
508 else:
509 best = None
510 return all_p, best
511 getRuntimeProviders.readonly = True
512
513 def dataStoreConnectorCmd(self, command, params):
514 dsindex = params[0]
515 method = params[1]
516 args = params[2]
517 kwargs = params[3]
518
519 d = command.remotedatastores[dsindex]
520 ret = getattr(d, method)(*args, **kwargs)
521
522 if isinstance(ret, bb.data_smart.DataSmart):
523 idx = command.remotedatastores.store(ret)
524 return DataStoreConnectionHandle(idx)
525
526 return ret
527
528 def dataStoreConnectorVarHistCmd(self, command, params):
529 dsindex = params[0]
530 method = params[1]
531 args = params[2]
532 kwargs = params[3]
533
534 d = command.remotedatastores[dsindex].varhistory
535 return getattr(d, method)(*args, **kwargs)
536
537 def dataStoreConnectorVarHistCmdEmit(self, command, params):
538 dsindex = params[0]
539 var = params[1]
540 oval = params[2]
541 val = params[3]
542 d = command.remotedatastores[params[4]]
543
544 o = io.StringIO()
545 command.remotedatastores[dsindex].varhistory.emit(var, oval, val, o, d)
546 return o.getvalue()
547
548 def dataStoreConnectorIncHistCmd(self, command, params):
549 dsindex = params[0]
550 method = params[1]
551 args = params[2]
552 kwargs = params[3]
553
554 d = command.remotedatastores[dsindex].inchistory
555 return getattr(d, method)(*args, **kwargs)
556
557 def dataStoreConnectorRelease(self, command, params):
558 dsindex = params[0]
559 if dsindex <= 0:
560 raise CommandError('dataStoreConnectorRelease: invalid index %d' % dsindex)
561 command.remotedatastores.release(dsindex)
562
563 def parseRecipeFile(self, command, params):
564 """
565 Parse the specified recipe file (with or without bbappends)
566 and return a datastore object representing the environment
567 for the recipe.
568 """
569 virtualfn = params[0]
570 (fn, cls, mc) = bb.cache.virtualfn2realfn(virtualfn)
571 appends = params[1]
572 appendlist = params[2]
573 if len(params) > 3:
574 config_data = command.remotedatastores[params[3]]
575 else:
576 config_data = None
577
578 if appends:
579 if appendlist is not None:
580 appendfiles = appendlist
581 else:
582 appendfiles = command.cooker.collections[mc].get_file_appends(fn)
583 else:
584 appendfiles = []
585 layername = command.cooker.collections[mc].calc_bbfile_priority(fn)[2]
586 # We are calling bb.cache locally here rather than on the server,
587 # but that's OK because it doesn't actually need anything from
588 # the server barring the global datastore (which we have a remote
589 # version of)
590 if config_data:
591 # We have to use a different function here if we're passing in a datastore
592 # NOTE: we took a copy above, so we don't do it here again
593 envdata = command.cooker.databuilder._parse_recipe(config_data, fn, appendfiles, mc, layername)[cls]
594 else:
595 # Use the standard path
596 envdata = command.cooker.databuilder.parseRecipe(virtualfn, appendfiles, layername)
597 idx = command.remotedatastores.store(envdata)
598 return DataStoreConnectionHandle(idx)
599 parseRecipeFile.readonly = True
600
601 def finalizeData(self, command, params):
602 newdata = command.cooker.data.createCopy()
603 bb.data.expandKeys(newdata)
604 bb.parse.ast.runAnonFuncs(newdata)
605 idx = command.remotedatastores.store(newdata)
606 return DataStoreConnectionHandle(idx)
607
608class CommandsAsync:
609 """
610 A class of asynchronous commands
611 These functions communicate via generated events.
612 Any function that requires metadata parsing should be here.
613 """
614
615 def buildFile(self, command, params):
616 """
617 Build a single specified .bb file
618 """
619 bfile = params[0]
620 task = params[1]
621 if len(params) > 2:
622 internal = params[2]
623 else:
624 internal = False
625
626 if internal:
627 command.cooker.buildFileInternal(bfile, task, fireevents=False, quietlog=True)
628 else:
629 command.cooker.buildFile(bfile, task)
630 buildFile.needcache = False
631
632 def buildTargets(self, command, params):
633 """
634 Build a set of targets
635 """
636 pkgs_to_build = params[0]
637 task = params[1]
638
639 command.cooker.buildTargets(pkgs_to_build, task)
640 buildTargets.needcache = True
641
642 def generateDepTreeEvent(self, command, params):
643 """
644 Generate an event containing the dependency information
645 """
646 pkgs_to_build = params[0]
647 task = params[1]
648
649 command.cooker.generateDepTreeEvent(pkgs_to_build, task)
650 command.finishAsyncCommand()
651 generateDepTreeEvent.needcache = True
652
653 def generateDotGraph(self, command, params):
654 """
655 Dump dependency information to disk as .dot files
656 """
657 pkgs_to_build = params[0]
658 task = params[1]
659
660 command.cooker.generateDotGraphFiles(pkgs_to_build, task)
661 command.finishAsyncCommand()
662 generateDotGraph.needcache = True
663
664 def generateTargetsTree(self, command, params):
665 """
666 Generate a tree of buildable targets.
667 If klass is provided ensure all recipes that inherit the class are
668 included in the package list.
669 If pkg_list provided use that list (plus any extras brought in by
670 klass) rather than generating a tree for all packages.
671 """
672 klass = params[0]
673 pkg_list = params[1]
674
675 command.cooker.generateTargetsTree(klass, pkg_list)
676 command.finishAsyncCommand()
677 generateTargetsTree.needcache = True
678
679 def findConfigFiles(self, command, params):
680 """
681 Find config files which provide appropriate values
682 for the passed configuration variable. i.e. MACHINE
683 """
684 varname = params[0]
685
686 command.cooker.findConfigFiles(varname)
687 command.finishAsyncCommand()
688 findConfigFiles.needcache = False
689
690 def findFilesMatchingInDir(self, command, params):
691 """
692 Find implementation files matching the specified pattern
693 in the requested subdirectory of a BBPATH
694 """
695 pattern = params[0]
696 directory = params[1]
697
698 command.cooker.findFilesMatchingInDir(pattern, directory)
699 command.finishAsyncCommand()
700 findFilesMatchingInDir.needcache = False
701
702 def testCookerCommandEvent(self, command, params):
703 """
704 Dummy command used by OEQA selftest to test tinfoil without IO
705 """
706 pattern = params[0]
707
708 command.cooker.testCookerCommandEvent(pattern)
709 command.finishAsyncCommand()
710 testCookerCommandEvent.needcache = False
711
712 def findConfigFilePath(self, command, params):
713 """
714 Find the path of the requested configuration file
715 """
716 configfile = params[0]
717
718 command.cooker.findConfigFilePath(configfile)
719 command.finishAsyncCommand()
720 findConfigFilePath.needcache = False
721
722 def showVersions(self, command, params):
723 """
724 Show the currently selected versions
725 """
726 command.cooker.showVersions()
727 command.finishAsyncCommand()
728 showVersions.needcache = True
729
730 def showEnvironmentTarget(self, command, params):
731 """
732 Print the environment of a target recipe
733 (needs the cache to work out which recipe to use)
734 """
735 pkg = params[0]
736
737 command.cooker.showEnvironment(None, pkg)
738 command.finishAsyncCommand()
739 showEnvironmentTarget.needcache = True
740
741 def showEnvironment(self, command, params):
742 """
743 Print the standard environment
744 or if specified the environment for a specified recipe
745 """
746 bfile = params[0]
747
748 command.cooker.showEnvironment(bfile)
749 command.finishAsyncCommand()
750 showEnvironment.needcache = False
751
752 def parseFiles(self, command, params):
753 """
754 Parse the .bb files
755 """
756 command.cooker.updateCache()
757 command.finishAsyncCommand()
758 parseFiles.needcache = True
759
760 def compareRevisions(self, command, params):
761 """
762 Parse the .bb files
763 """
764 if bb.fetch.fetcher_compare_revisions(command.cooker.data):
765 command.finishAsyncCommand(code=1)
766 else:
767 command.finishAsyncCommand()
768 compareRevisions.needcache = True
769
770 def triggerEvent(self, command, params):
771 """
772 Trigger a certain event
773 """
774 event = params[0]
775 bb.event.fire(eval(event), command.cooker.data)
776 process_server.clear_async_cmd()
777 triggerEvent.needcache = False
778
779 def resetCooker(self, command, params):
780 """
781 Reset the cooker to its initial state, thus forcing a reparse for
782 any async command that has the needcache property set to True
783 """
784 command.cooker.reset()
785 command.finishAsyncCommand()
786 resetCooker.needcache = False
787
788 def clientComplete(self, command, params):
789 """
790 Do the right thing when the controlling client exits
791 """
792 command.cooker.clientComplete()
793 command.finishAsyncCommand()
794 clientComplete.needcache = False
795
796 def findSigInfo(self, command, params):
797 """
798 Find signature info files via the signature generator
799 """
800 (mc, pn) = bb.runqueue.split_mc(params[0])
801 taskname = params[1]
802 sigs = params[2]
803 bb.siggen.check_siggen_version(bb.siggen)
804 res = bb.siggen.find_siginfo(pn, taskname, sigs, command.cooker.databuilder.mcdata[mc])
805 bb.event.fire(bb.event.FindSigInfoResult(res), command.cooker.databuilder.mcdata[mc])
806 command.finishAsyncCommand()
807 findSigInfo.needcache = False
808
809 def getTaskSignatures(self, command, params):
810 res = command.cooker.getTaskSignatures(params[0], params[1])
811 bb.event.fire(bb.event.GetTaskSignatureResult(res), command.cooker.data)
812 command.finishAsyncCommand()
813 getTaskSignatures.needcache = True