command.py 26 KB

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