blob: b494f84a0a768aa03246e416d5d3c272360c4765 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001"""
2BitBake 'Command' module
3
4Provide an interface to interact with the bitbake server through 'commands'
5"""
6
7# Copyright (C) 2006-2007 Richard Purdie
8#
Brad Bishopc342db32019-05-15 21:57:59 -04009# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010#
Patrick Williamsc124f4f2015-09-15 14:41:29 -050011
12"""
13The bitbake server takes 'commands' from its UI/commandline.
14Commands are either synchronous or asynchronous.
15Async commands return data to the client in the form of events.
16Sync commands must only return data through the function return value
17and must not trigger events, directly or indirectly.
18Commands are queued in a CommandQueue
19"""
20
Brad Bishop6e60e8b2018-02-01 10:27:11 -050021from collections import OrderedDict, defaultdict
22
Andrew Geisslerc926e172021-05-07 16:11:35 -050023import io
Patrick Williamsc124f4f2015-09-15 14:41:29 -050024import bb.event
25import bb.cooker
Brad Bishop6e60e8b2018-02-01 10:27:11 -050026import bb.remotedata
27
28class DataStoreConnectionHandle(object):
29 def __init__(self, dsindex=0):
30 self.dsindex = dsindex
Patrick Williamsc124f4f2015-09-15 14:41:29 -050031
32class CommandCompleted(bb.event.Event):
33 pass
34
35class CommandExit(bb.event.Event):
36 def __init__(self, exitcode):
37 bb.event.Event.__init__(self)
38 self.exitcode = int(exitcode)
39
40class CommandFailed(CommandExit):
41 def __init__(self, message):
42 self.error = message
43 CommandExit.__init__(self, 1)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050044 def __str__(self):
45 return "Command execution failed: %s" % self.error
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046
47class CommandError(Exception):
48 pass
49
50class Command:
51 """
52 A queue of asynchronous commands for bitbake
53 """
Andrew Geissler517393d2023-01-13 08:55:19 -060054 def __init__(self, cooker, process_server):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050055 self.cooker = cooker
56 self.cmds_sync = CommandsSync()
57 self.cmds_async = CommandsAsync()
Andrew Geisslerc9f78652020-09-18 14:11:35 -050058 self.remotedatastores = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -050059
Andrew Geissler517393d2023-01-13 08:55:19 -060060 self.process_server = process_server
61 # Access with locking using process_server.{get/set/clear}_async_cmd()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050062 self.currentAsyncCommand = None
63
Andrew Geissler517393d2023-01-13 08:55:19 -060064 def runCommand(self, commandline, process_server, ro_only=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050065 command = commandline.pop(0)
Andrew Geisslerc9f78652020-09-18 14:11:35 -050066
67 # Ensure cooker is ready for commands
Andrew Geissler5082cc72023-09-11 08:41:39 -040068 if command not in ["updateConfig", "setFeatures", "ping"]:
Patrick Williams213cb262021-08-07 19:21:33 -050069 try:
70 self.cooker.init_configdata()
71 if not self.remotedatastores:
72 self.remotedatastores = bb.remotedata.RemoteDatastores(self.cooker)
73 except (Exception, SystemExit) as exc:
74 import traceback
75 if isinstance(exc, bb.BBHandledException):
76 # We need to start returning real exceptions here. Until we do, we can't
77 # tell if an exception is an instance of bb.BBHandledException
78 return None, "bb.BBHandledException()\n" + traceback.format_exc()
79 return None, traceback.format_exc()
Andrew Geisslerc9f78652020-09-18 14:11:35 -050080
Patrick Williamsc124f4f2015-09-15 14:41:29 -050081 if hasattr(CommandsSync, command):
82 # Can run synchronous commands straight away
83 command_method = getattr(self.cmds_sync, command)
84 if ro_only:
Andrew Geissler82c905d2020-04-13 13:39:40 -050085 if not hasattr(command_method, 'readonly') or not getattr(command_method, 'readonly'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050086 return None, "Not able to execute not readonly commands in readonly mode"
87 try:
Andrew Geissler5082cc72023-09-11 08:41:39 -040088 if command != "ping":
89 self.cooker.process_inotify_updates_apply()
Brad Bishopd7bf8c12018-02-25 22:55:05 -050090 if getattr(command_method, 'needconfig', True):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050091 self.cooker.updateCacheSync()
92 result = command_method(self, commandline)
93 except CommandError as exc:
94 return None, exc.args[0]
Andrew Geisslerf0343792020-11-18 10:42:21 -060095 except (Exception, SystemExit) as exc:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050096 import traceback
Andrew Geisslerf0343792020-11-18 10:42:21 -060097 if isinstance(exc, bb.BBHandledException):
98 # We need to start returning real exceptions here. Until we do, we can't
99 # tell if an exception is an instance of bb.BBHandledException
100 return None, "bb.BBHandledException()\n" + traceback.format_exc()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500101 return None, traceback.format_exc()
102 else:
103 return result, None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500104 if command not in CommandsAsync.__dict__:
105 return None, "No such command"
Andrew Geissler517393d2023-01-13 08:55:19 -0600106 if not process_server.set_async_cmd((command, commandline)):
107 return None, "Busy (%s in progress)" % self.process_server.get_async_cmd()[0]
108 self.cooker.idleCallBackRegister(self.runAsyncCommand, process_server)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500109 return True, None
110
Andrew Geissler517393d2023-01-13 08:55:19 -0600111 def runAsyncCommand(self, _, process_server, halt):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500112 try:
Andrew Geissler517393d2023-01-13 08:55:19 -0600113 self.cooker.process_inotify_updates_apply()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500114 if self.cooker.state in (bb.cooker.state.error, bb.cooker.state.shutdown, bb.cooker.state.forceshutdown):
115 # updateCache will trigger a shutdown of the parser
116 # and then raise BBHandledException triggering an exit
117 self.cooker.updateCache()
Andrew Geissler517393d2023-01-13 08:55:19 -0600118 return bb.server.process.idleFinish("Cooker in error state")
119 cmd = process_server.get_async_cmd()
120 if cmd is not None:
121 (command, options) = cmd
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500122 commandmethod = getattr(CommandsAsync, command)
123 needcache = getattr( commandmethod, "needcache" )
124 if needcache and self.cooker.state != bb.cooker.state.running:
125 self.cooker.updateCache()
126 return True
127 else:
128 commandmethod(self.cmds_async, self, options)
129 return False
130 else:
Andrew Geissler517393d2023-01-13 08:55:19 -0600131 return bb.server.process.idleFinish("Nothing to do, no async command?")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500132 except KeyboardInterrupt as exc:
Andrew Geissler517393d2023-01-13 08:55:19 -0600133 return bb.server.process.idleFinish("Interrupted")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500134 except SystemExit as exc:
135 arg = exc.args[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600136 if isinstance(arg, str):
Andrew Geissler517393d2023-01-13 08:55:19 -0600137 return bb.server.process.idleFinish(arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500138 else:
Andrew Geissler517393d2023-01-13 08:55:19 -0600139 return bb.server.process.idleFinish("Exited with %s" % arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500140 except Exception as exc:
141 import traceback
142 if isinstance(exc, bb.BBHandledException):
Andrew Geissler517393d2023-01-13 08:55:19 -0600143 return bb.server.process.idleFinish("")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500144 else:
Andrew Geissler517393d2023-01-13 08:55:19 -0600145 return bb.server.process.idleFinish(traceback.format_exc())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500146
147 def finishAsyncCommand(self, msg=None, code=None):
148 if msg or msg == "":
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500149 bb.event.fire(CommandFailed(msg), self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500150 elif code:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500151 bb.event.fire(CommandExit(code), self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500152 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500153 bb.event.fire(CommandCompleted(), self.cooker.data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500154 self.cooker.finishcommand()
Andrew Geissler517393d2023-01-13 08:55:19 -0600155 self.process_server.clear_async_cmd()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500156
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500157 def reset(self):
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500158 if self.remotedatastores:
159 self.remotedatastores = bb.remotedata.RemoteDatastores(self.cooker)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500160
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500161class CommandsSync:
162 """
163 A class of synchronous commands
164 These should run quickly so as not to hurt interactive performance.
165 These must not influence any running synchronous command.
166 """
167
Andrew Geissler517393d2023-01-13 08:55:19 -0600168 def ping(self, command, params):
169 """
170 Allow a UI to check the server is still alive
171 """
172 return "Still alive!"
Andrew Geissler5082cc72023-09-11 08:41:39 -0400173 ping.needconfig = False
174 ping.readonly = True
Andrew Geissler517393d2023-01-13 08:55:19 -0600175
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500176 def stateShutdown(self, command, params):
177 """
178 Trigger cooker 'shutdown' mode
179 """
180 command.cooker.shutdown(False)
181
182 def stateForceShutdown(self, command, params):
183 """
184 Stop the cooker
185 """
186 command.cooker.shutdown(True)
187
188 def getAllKeysWithFlags(self, command, params):
189 """
190 Returns a dump of the global state. Call with
191 variable flags to be retrieved as params.
192 """
193 flaglist = params[0]
194 return command.cooker.getAllKeysWithFlags(flaglist)
195 getAllKeysWithFlags.readonly = True
196
197 def getVariable(self, command, params):
198 """
199 Read the value of a variable from data
200 """
201 varname = params[0]
202 expand = True
203 if len(params) > 1:
204 expand = (params[1] == "True")
205
206 return command.cooker.data.getVar(varname, expand)
207 getVariable.readonly = True
208
209 def setVariable(self, command, params):
210 """
211 Set the value of variable in data
212 """
213 varname = params[0]
214 value = str(params[1])
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500215 command.cooker.extraconfigdata[varname] = value
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500216 command.cooker.data.setVar(varname, value)
217
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500218 def getSetVariable(self, command, params):
219 """
220 Read the value of a variable from data and set it into the datastore
221 which effectively expands and locks the value.
222 """
223 varname = params[0]
224 result = self.getVariable(command, params)
225 command.cooker.data.setVar(varname, result)
226 return result
227
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500228 def setConfig(self, command, params):
229 """
230 Set the value of variable in configuration
231 """
232 varname = params[0]
233 value = str(params[1])
234 setattr(command.cooker.configuration, varname, value)
235
236 def enableDataTracking(self, command, params):
237 """
238 Enable history tracking for variables
239 """
240 command.cooker.enableDataTracking()
241
242 def disableDataTracking(self, command, params):
243 """
244 Disable history tracking for variables
245 """
246 command.cooker.disableDataTracking()
247
248 def setPrePostConfFiles(self, command, params):
249 prefiles = params[0].split()
250 postfiles = params[1].split()
251 command.cooker.configuration.prefile = prefiles
252 command.cooker.configuration.postfile = postfiles
253 setPrePostConfFiles.needconfig = False
254
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500255 def matchFile(self, command, params):
256 fMatch = params[0]
Andrew Geissler5a43b432020-06-13 10:46:56 -0500257 try:
258 mc = params[0]
259 except IndexError:
260 mc = ''
261 return command.cooker.matchFile(fMatch, mc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500262 matchFile.needconfig = False
263
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500264 def getUIHandlerNum(self, command, params):
265 return bb.event.get_uihandler()
266 getUIHandlerNum.needconfig = False
267 getUIHandlerNum.readonly = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500268
269 def setEventMask(self, command, params):
270 handlerNum = params[0]
271 llevel = params[1]
272 debug_domains = params[2]
273 mask = params[3]
274 return bb.event.set_UIHmask(handlerNum, llevel, debug_domains, mask)
275 setEventMask.needconfig = False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500276 setEventMask.readonly = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500277
278 def setFeatures(self, command, params):
279 """
280 Set the cooker features to include the passed list of features
281 """
282 features = params[0]
283 command.cooker.setFeatures(features)
284 setFeatures.needconfig = False
285 # although we change the internal state of the cooker, this is transparent since
286 # we always take and leave the cooker in state.initial
287 setFeatures.readonly = True
288
289 def updateConfig(self, command, params):
290 options = params[0]
291 environment = params[1]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500292 cmdline = params[2]
293 command.cooker.updateConfigOpts(options, environment, cmdline)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500294 updateConfig.needconfig = False
295
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500296 def parseConfiguration(self, command, params):
297 """Instruct bitbake to parse its configuration
298 NOTE: it is only necessary to call this if you aren't calling any normal action
299 (otherwise parsing is taken care of automatically)
300 """
301 command.cooker.parseConfiguration()
302 parseConfiguration.needconfig = False
303
304 def getLayerPriorities(self, command, params):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500305 command.cooker.parseConfiguration()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500306 ret = []
307 # regex objects cannot be marshalled by xmlrpc
308 for collection, pattern, regex, pri in command.cooker.bbfile_config_priorities:
309 ret.append((collection, pattern, regex.pattern, pri))
310 return ret
311 getLayerPriorities.readonly = True
312
313 def getRecipes(self, command, params):
314 try:
315 mc = params[0]
316 except IndexError:
317 mc = ''
318 return list(command.cooker.recipecaches[mc].pkg_pn.items())
319 getRecipes.readonly = True
320
321 def getRecipeDepends(self, command, params):
322 try:
323 mc = params[0]
324 except IndexError:
325 mc = ''
326 return list(command.cooker.recipecaches[mc].deps.items())
327 getRecipeDepends.readonly = True
328
329 def getRecipeVersions(self, command, params):
330 try:
331 mc = params[0]
332 except IndexError:
333 mc = ''
334 return command.cooker.recipecaches[mc].pkg_pepvpr
335 getRecipeVersions.readonly = True
336
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500337 def getRecipeProvides(self, command, params):
338 try:
339 mc = params[0]
340 except IndexError:
341 mc = ''
342 return command.cooker.recipecaches[mc].fn_provides
343 getRecipeProvides.readonly = True
344
345 def getRecipePackages(self, command, params):
346 try:
347 mc = params[0]
348 except IndexError:
349 mc = ''
350 return command.cooker.recipecaches[mc].packages
351 getRecipePackages.readonly = True
352
353 def getRecipePackagesDynamic(self, command, params):
354 try:
355 mc = params[0]
356 except IndexError:
357 mc = ''
358 return command.cooker.recipecaches[mc].packages_dynamic
359 getRecipePackagesDynamic.readonly = True
360
361 def getRProviders(self, command, params):
362 try:
363 mc = params[0]
364 except IndexError:
365 mc = ''
366 return command.cooker.recipecaches[mc].rproviders
367 getRProviders.readonly = True
368
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500369 def getRuntimeDepends(self, command, params):
370 ret = []
371 try:
372 mc = params[0]
373 except IndexError:
374 mc = ''
375 rundeps = command.cooker.recipecaches[mc].rundeps
376 for key, value in rundeps.items():
377 if isinstance(value, defaultdict):
378 value = dict(value)
379 ret.append((key, value))
380 return ret
381 getRuntimeDepends.readonly = True
382
383 def getRuntimeRecommends(self, command, params):
384 ret = []
385 try:
386 mc = params[0]
387 except IndexError:
388 mc = ''
389 runrecs = command.cooker.recipecaches[mc].runrecs
390 for key, value in runrecs.items():
391 if isinstance(value, defaultdict):
392 value = dict(value)
393 ret.append((key, value))
394 return ret
395 getRuntimeRecommends.readonly = True
396
397 def getRecipeInherits(self, command, params):
398 try:
399 mc = params[0]
400 except IndexError:
401 mc = ''
402 return command.cooker.recipecaches[mc].inherits
403 getRecipeInherits.readonly = True
404
405 def getBbFilePriority(self, command, params):
406 try:
407 mc = params[0]
408 except IndexError:
409 mc = ''
410 return command.cooker.recipecaches[mc].bbfile_priority
411 getBbFilePriority.readonly = True
412
413 def getDefaultPreference(self, command, params):
414 try:
415 mc = params[0]
416 except IndexError:
417 mc = ''
418 return command.cooker.recipecaches[mc].pkg_dp
419 getDefaultPreference.readonly = True
420
421 def getSkippedRecipes(self, command, params):
422 # Return list sorted by reverse priority order
423 import bb.cache
Andrew Geissler5a43b432020-06-13 10:46:56 -0500424 def sortkey(x):
425 vfn, _ = x
426 realfn, _, mc = bb.cache.virtualfn2realfn(vfn)
Andrew Geisslerb7d28612020-07-24 16:15:54 -0500427 return (-command.cooker.collections[mc].calc_bbfile_priority(realfn)[0], vfn)
Andrew Geissler5a43b432020-06-13 10:46:56 -0500428
429 skipdict = OrderedDict(sorted(command.cooker.skiplist.items(), key=sortkey))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500430 return list(skipdict.items())
431 getSkippedRecipes.readonly = True
432
433 def getOverlayedRecipes(self, command, params):
Andrew Geissler5a43b432020-06-13 10:46:56 -0500434 try:
435 mc = params[0]
436 except IndexError:
437 mc = ''
438 return list(command.cooker.collections[mc].overlayed.items())
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500439 getOverlayedRecipes.readonly = True
440
441 def getFileAppends(self, command, params):
442 fn = params[0]
Andrew Geissler5a43b432020-06-13 10:46:56 -0500443 try:
444 mc = params[1]
445 except IndexError:
446 mc = ''
447 return command.cooker.collections[mc].get_file_appends(fn)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500448 getFileAppends.readonly = True
449
450 def getAllAppends(self, command, params):
Andrew Geissler5a43b432020-06-13 10:46:56 -0500451 try:
452 mc = params[0]
453 except IndexError:
454 mc = ''
455 return command.cooker.collections[mc].bbappends
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500456 getAllAppends.readonly = True
457
458 def findProviders(self, command, params):
Andrew Geissler82c905d2020-04-13 13:39:40 -0500459 try:
460 mc = params[0]
461 except IndexError:
462 mc = ''
463 return command.cooker.findProviders(mc)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500464 findProviders.readonly = True
465
466 def findBestProvider(self, command, params):
Andrew Geissler5a43b432020-06-13 10:46:56 -0500467 (mc, pn) = bb.runqueue.split_mc(params[0])
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500468 return command.cooker.findBestProvider(pn, mc)
469 findBestProvider.readonly = True
470
471 def allProviders(self, command, params):
472 try:
473 mc = params[0]
474 except IndexError:
475 mc = ''
476 return list(bb.providers.allProviders(command.cooker.recipecaches[mc]).items())
477 allProviders.readonly = True
478
479 def getRuntimeProviders(self, command, params):
480 rprovide = params[0]
481 try:
482 mc = params[1]
483 except IndexError:
484 mc = ''
485 all_p = bb.providers.getRuntimeProviders(command.cooker.recipecaches[mc], rprovide)
486 if all_p:
487 best = bb.providers.filterProvidersRunTime(all_p, rprovide,
488 command.cooker.data,
489 command.cooker.recipecaches[mc])[0][0]
490 else:
491 best = None
492 return all_p, best
493 getRuntimeProviders.readonly = True
494
Andrew Geissler82c905d2020-04-13 13:39:40 -0500495 def dataStoreConnectorCmd(self, command, params):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500496 dsindex = params[0]
Andrew Geissler82c905d2020-04-13 13:39:40 -0500497 method = params[1]
498 args = params[2]
499 kwargs = params[3]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500500
Andrew Geissler82c905d2020-04-13 13:39:40 -0500501 d = command.remotedatastores[dsindex]
502 ret = getattr(d, method)(*args, **kwargs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500503
Andrew Geissler82c905d2020-04-13 13:39:40 -0500504 if isinstance(ret, bb.data_smart.DataSmart):
505 idx = command.remotedatastores.store(ret)
506 return DataStoreConnectionHandle(idx)
507
508 return ret
509
510 def dataStoreConnectorVarHistCmd(self, command, params):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500511 dsindex = params[0]
Andrew Geissler82c905d2020-04-13 13:39:40 -0500512 method = params[1]
513 args = params[2]
514 kwargs = params[3]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500515
Andrew Geissler82c905d2020-04-13 13:39:40 -0500516 d = command.remotedatastores[dsindex].varhistory
517 return getattr(d, method)(*args, **kwargs)
518
Andrew Geisslerc926e172021-05-07 16:11:35 -0500519 def dataStoreConnectorVarHistCmdEmit(self, command, params):
520 dsindex = params[0]
521 var = params[1]
522 oval = params[2]
523 val = params[3]
524 d = command.remotedatastores[params[4]]
525
526 o = io.StringIO()
527 command.remotedatastores[dsindex].varhistory.emit(var, oval, val, o, d)
528 return o.getvalue()
529
Andrew Geissler82c905d2020-04-13 13:39:40 -0500530 def dataStoreConnectorIncHistCmd(self, command, params):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500531 dsindex = params[0]
Andrew Geissler82c905d2020-04-13 13:39:40 -0500532 method = params[1]
533 args = params[2]
534 kwargs = params[3]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500535
Andrew Geissler82c905d2020-04-13 13:39:40 -0500536 d = command.remotedatastores[dsindex].inchistory
537 return getattr(d, method)(*args, **kwargs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500538
539 def dataStoreConnectorRelease(self, command, params):
540 dsindex = params[0]
541 if dsindex <= 0:
542 raise CommandError('dataStoreConnectorRelease: invalid index %d' % dsindex)
543 command.remotedatastores.release(dsindex)
544
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500545 def parseRecipeFile(self, command, params):
546 """
547 Parse the specified recipe file (with or without bbappends)
548 and return a datastore object representing the environment
549 for the recipe.
550 """
551 fn = params[0]
Andrew Geissler5a43b432020-06-13 10:46:56 -0500552 mc = bb.runqueue.mc_from_tid(fn)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500553 appends = params[1]
554 appendlist = params[2]
555 if len(params) > 3:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500556 config_data = command.remotedatastores[params[3]]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500557 else:
558 config_data = None
559
560 if appends:
561 if appendlist is not None:
562 appendfiles = appendlist
563 else:
Andrew Geissler5a43b432020-06-13 10:46:56 -0500564 appendfiles = command.cooker.collections[mc].get_file_appends(fn)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500565 else:
566 appendfiles = []
Patrick Williamse760df82023-05-26 11:10:49 -0500567 layername = command.cooker.collections[mc].calc_bbfile_priority(fn)[2]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500568 # We are calling bb.cache locally here rather than on the server,
569 # but that's OK because it doesn't actually need anything from
570 # the server barring the global datastore (which we have a remote
571 # version of)
572 if config_data:
573 # We have to use a different function here if we're passing in a datastore
574 # NOTE: we took a copy above, so we don't do it here again
Patrick Williamse760df82023-05-26 11:10:49 -0500575 envdata = command.cooker.databuilder._parse_recipe(config_data, fn, appendfiles, mc, layername)['']
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500576 else:
577 # Use the standard path
Patrick Williamse760df82023-05-26 11:10:49 -0500578 envdata = command.cooker.databuilder.parseRecipe(fn, appendfiles, layername)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500579 idx = command.remotedatastores.store(envdata)
580 return DataStoreConnectionHandle(idx)
581 parseRecipeFile.readonly = True
582
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500583class CommandsAsync:
584 """
585 A class of asynchronous commands
586 These functions communicate via generated events.
587 Any function that requires metadata parsing should be here.
588 """
589
590 def buildFile(self, command, params):
591 """
592 Build a single specified .bb file
593 """
594 bfile = params[0]
595 task = params[1]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500596 if len(params) > 2:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500597 internal = params[2]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500598 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500599 internal = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500600
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500601 if internal:
602 command.cooker.buildFileInternal(bfile, task, fireevents=False, quietlog=True)
603 else:
604 command.cooker.buildFile(bfile, task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500605 buildFile.needcache = False
606
607 def buildTargets(self, command, params):
608 """
609 Build a set of targets
610 """
611 pkgs_to_build = params[0]
612 task = params[1]
613
614 command.cooker.buildTargets(pkgs_to_build, task)
615 buildTargets.needcache = True
616
617 def generateDepTreeEvent(self, command, params):
618 """
619 Generate an event containing the dependency information
620 """
621 pkgs_to_build = params[0]
622 task = params[1]
623
624 command.cooker.generateDepTreeEvent(pkgs_to_build, task)
625 command.finishAsyncCommand()
626 generateDepTreeEvent.needcache = True
627
628 def generateDotGraph(self, command, params):
629 """
630 Dump dependency information to disk as .dot files
631 """
632 pkgs_to_build = params[0]
633 task = params[1]
634
635 command.cooker.generateDotGraphFiles(pkgs_to_build, task)
636 command.finishAsyncCommand()
637 generateDotGraph.needcache = True
638
639 def generateTargetsTree(self, command, params):
640 """
641 Generate a tree of buildable targets.
642 If klass is provided ensure all recipes that inherit the class are
643 included in the package list.
644 If pkg_list provided use that list (plus any extras brought in by
645 klass) rather than generating a tree for all packages.
646 """
647 klass = params[0]
648 pkg_list = params[1]
649
650 command.cooker.generateTargetsTree(klass, pkg_list)
651 command.finishAsyncCommand()
652 generateTargetsTree.needcache = True
653
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500654 def findConfigFiles(self, command, params):
655 """
656 Find config files which provide appropriate values
657 for the passed configuration variable. i.e. MACHINE
658 """
659 varname = params[0]
660
661 command.cooker.findConfigFiles(varname)
662 command.finishAsyncCommand()
663 findConfigFiles.needcache = False
664
665 def findFilesMatchingInDir(self, command, params):
666 """
667 Find implementation files matching the specified pattern
668 in the requested subdirectory of a BBPATH
669 """
670 pattern = params[0]
671 directory = params[1]
672
673 command.cooker.findFilesMatchingInDir(pattern, directory)
674 command.finishAsyncCommand()
675 findFilesMatchingInDir.needcache = False
676
Patrick Williams93c203f2021-10-06 16:15:23 -0500677 def testCookerCommandEvent(self, command, params):
678 """
679 Dummy command used by OEQA selftest to test tinfoil without IO
680 """
681 pattern = params[0]
682
683 command.cooker.testCookerCommandEvent(pattern)
684 command.finishAsyncCommand()
685 testCookerCommandEvent.needcache = False
686
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500687 def findConfigFilePath(self, command, params):
688 """
689 Find the path of the requested configuration file
690 """
691 configfile = params[0]
692
693 command.cooker.findConfigFilePath(configfile)
694 command.finishAsyncCommand()
695 findConfigFilePath.needcache = False
696
697 def showVersions(self, command, params):
698 """
699 Show the currently selected versions
700 """
701 command.cooker.showVersions()
702 command.finishAsyncCommand()
703 showVersions.needcache = True
704
705 def showEnvironmentTarget(self, command, params):
706 """
707 Print the environment of a target recipe
708 (needs the cache to work out which recipe to use)
709 """
710 pkg = params[0]
711
712 command.cooker.showEnvironment(None, pkg)
713 command.finishAsyncCommand()
714 showEnvironmentTarget.needcache = True
715
716 def showEnvironment(self, command, params):
717 """
718 Print the standard environment
719 or if specified the environment for a specified recipe
720 """
721 bfile = params[0]
722
723 command.cooker.showEnvironment(bfile)
724 command.finishAsyncCommand()
725 showEnvironment.needcache = False
726
727 def parseFiles(self, command, params):
728 """
729 Parse the .bb files
730 """
731 command.cooker.updateCache()
732 command.finishAsyncCommand()
733 parseFiles.needcache = True
734
735 def compareRevisions(self, command, params):
736 """
737 Parse the .bb files
738 """
739 if bb.fetch.fetcher_compare_revisions(command.cooker.data):
740 command.finishAsyncCommand(code=1)
741 else:
742 command.finishAsyncCommand()
743 compareRevisions.needcache = True
744
745 def triggerEvent(self, command, params):
746 """
747 Trigger a certain event
748 """
749 event = params[0]
750 bb.event.fire(eval(event), command.cooker.data)
Andrew Geissler517393d2023-01-13 08:55:19 -0600751 process_server.clear_async_cmd()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500752 triggerEvent.needcache = False
753
754 def resetCooker(self, command, params):
755 """
756 Reset the cooker to its initial state, thus forcing a reparse for
757 any async command that has the needcache property set to True
758 """
759 command.cooker.reset()
760 command.finishAsyncCommand()
761 resetCooker.needcache = False
762
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500763 def clientComplete(self, command, params):
764 """
765 Do the right thing when the controlling client exits
766 """
767 command.cooker.clientComplete()
768 command.finishAsyncCommand()
769 clientComplete.needcache = False
770
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500771 def findSigInfo(self, command, params):
772 """
773 Find signature info files via the signature generator
774 """
Andrew Geissler635e0e42020-08-21 15:58:33 -0500775 (mc, pn) = bb.runqueue.split_mc(params[0])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500776 taskname = params[1]
777 sigs = params[2]
Andrew Geissler635e0e42020-08-21 15:58:33 -0500778 res = bb.siggen.find_siginfo(pn, taskname, sigs, command.cooker.databuilder.mcdata[mc])
779 bb.event.fire(bb.event.FindSigInfoResult(res), command.cooker.databuilder.mcdata[mc])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500780 command.finishAsyncCommand()
781 findSigInfo.needcache = False