command.py 26 KB

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