diff options
Diffstat (limited to 'import-layers/yocto-poky/bitbake/lib/bb/command.py')
-rw-r--r-- | import-layers/yocto-poky/bitbake/lib/bb/command.py | 765 |
1 files changed, 0 insertions, 765 deletions
diff --git a/import-layers/yocto-poky/bitbake/lib/bb/command.py b/import-layers/yocto-poky/bitbake/lib/bb/command.py deleted file mode 100644 index 6c966e3db..000000000 --- a/import-layers/yocto-poky/bitbake/lib/bb/command.py +++ /dev/null @@ -1,765 +0,0 @@ -""" -BitBake 'Command' module - -Provide an interface to interact with the bitbake server through 'commands' -""" - -# Copyright (C) 2006-2007 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -""" -The bitbake server takes 'commands' from its UI/commandline. -Commands are either synchronous or asynchronous. -Async commands return data to the client in the form of events. -Sync commands must only return data through the function return value -and must not trigger events, directly or indirectly. -Commands are queued in a CommandQueue -""" - -from collections import OrderedDict, defaultdict - -import bb.event -import bb.cooker -import bb.remotedata - -class DataStoreConnectionHandle(object): - def __init__(self, dsindex=0): - self.dsindex = dsindex - -class CommandCompleted(bb.event.Event): - pass - -class CommandExit(bb.event.Event): - def __init__(self, exitcode): - bb.event.Event.__init__(self) - self.exitcode = int(exitcode) - -class CommandFailed(CommandExit): - def __init__(self, message): - self.error = message - CommandExit.__init__(self, 1) - def __str__(self): - return "Command execution failed: %s" % self.error - -class CommandError(Exception): - pass - -class Command: - """ - A queue of asynchronous commands for bitbake - """ - def __init__(self, cooker): - self.cooker = cooker - self.cmds_sync = CommandsSync() - self.cmds_async = CommandsAsync() - self.remotedatastores = bb.remotedata.RemoteDatastores(cooker) - - # FIXME Add lock for this - self.currentAsyncCommand = None - - def runCommand(self, commandline, ro_only = False): - command = commandline.pop(0) - if hasattr(CommandsSync, command): - # Can run synchronous commands straight away - command_method = getattr(self.cmds_sync, command) - if ro_only: - if not hasattr(command_method, 'readonly') or False == getattr(command_method, 'readonly'): - return None, "Not able to execute not readonly commands in readonly mode" - try: - self.cooker.process_inotify_updates() - if getattr(command_method, 'needconfig', True): - self.cooker.updateCacheSync() - result = command_method(self, commandline) - except CommandError as exc: - return None, exc.args[0] - except (Exception, SystemExit): - import traceback - return None, traceback.format_exc() - else: - return result, None - if self.currentAsyncCommand is not None: - return None, "Busy (%s in progress)" % self.currentAsyncCommand[0] - if command not in CommandsAsync.__dict__: - return None, "No such command" - self.currentAsyncCommand = (command, commandline) - self.cooker.configuration.server_register_idlecallback(self.cooker.runCommands, self.cooker) - return True, None - - def runAsyncCommand(self): - try: - self.cooker.process_inotify_updates() - if self.cooker.state in (bb.cooker.state.error, bb.cooker.state.shutdown, bb.cooker.state.forceshutdown): - # updateCache will trigger a shutdown of the parser - # and then raise BBHandledException triggering an exit - self.cooker.updateCache() - return False - if self.currentAsyncCommand is not None: - (command, options) = self.currentAsyncCommand - commandmethod = getattr(CommandsAsync, command) - needcache = getattr( commandmethod, "needcache" ) - if needcache and self.cooker.state != bb.cooker.state.running: - self.cooker.updateCache() - return True - else: - commandmethod(self.cmds_async, self, options) - return False - else: - return False - except KeyboardInterrupt as exc: - self.finishAsyncCommand("Interrupted") - return False - except SystemExit as exc: - arg = exc.args[0] - if isinstance(arg, str): - self.finishAsyncCommand(arg) - else: - self.finishAsyncCommand("Exited with %s" % arg) - return False - except Exception as exc: - import traceback - if isinstance(exc, bb.BBHandledException): - self.finishAsyncCommand("") - else: - self.finishAsyncCommand(traceback.format_exc()) - return False - - def finishAsyncCommand(self, msg=None, code=None): - if msg or msg == "": - bb.event.fire(CommandFailed(msg), self.cooker.data) - elif code: - bb.event.fire(CommandExit(code), self.cooker.data) - else: - bb.event.fire(CommandCompleted(), self.cooker.data) - self.currentAsyncCommand = None - self.cooker.finishcommand() - - def reset(self): - self.remotedatastores = bb.remotedata.RemoteDatastores(self.cooker) - -def split_mc_pn(pn): - if pn.startswith("multiconfig:"): - _, mc, pn = pn.split(":", 2) - return (mc, pn) - return ('', pn) - -class CommandsSync: - """ - A class of synchronous commands - These should run quickly so as not to hurt interactive performance. - These must not influence any running synchronous command. - """ - - def stateShutdown(self, command, params): - """ - Trigger cooker 'shutdown' mode - """ - command.cooker.shutdown(False) - - def stateForceShutdown(self, command, params): - """ - Stop the cooker - """ - command.cooker.shutdown(True) - - def getAllKeysWithFlags(self, command, params): - """ - Returns a dump of the global state. Call with - variable flags to be retrieved as params. - """ - flaglist = params[0] - return command.cooker.getAllKeysWithFlags(flaglist) - getAllKeysWithFlags.readonly = True - - def getVariable(self, command, params): - """ - Read the value of a variable from data - """ - varname = params[0] - expand = True - if len(params) > 1: - expand = (params[1] == "True") - - return command.cooker.data.getVar(varname, expand) - getVariable.readonly = True - - def setVariable(self, command, params): - """ - Set the value of variable in data - """ - varname = params[0] - value = str(params[1]) - command.cooker.extraconfigdata[varname] = value - command.cooker.data.setVar(varname, value) - - def getSetVariable(self, command, params): - """ - Read the value of a variable from data and set it into the datastore - which effectively expands and locks the value. - """ - varname = params[0] - result = self.getVariable(command, params) - command.cooker.data.setVar(varname, result) - return result - - def setConfig(self, command, params): - """ - Set the value of variable in configuration - """ - varname = params[0] - value = str(params[1]) - setattr(command.cooker.configuration, varname, value) - - def enableDataTracking(self, command, params): - """ - Enable history tracking for variables - """ - command.cooker.enableDataTracking() - - def disableDataTracking(self, command, params): - """ - Disable history tracking for variables - """ - command.cooker.disableDataTracking() - - def setPrePostConfFiles(self, command, params): - prefiles = params[0].split() - postfiles = params[1].split() - command.cooker.configuration.prefile = prefiles - command.cooker.configuration.postfile = postfiles - setPrePostConfFiles.needconfig = False - - def matchFile(self, command, params): - fMatch = params[0] - return command.cooker.matchFile(fMatch) - matchFile.needconfig = False - - def getUIHandlerNum(self, command, params): - return bb.event.get_uihandler() - getUIHandlerNum.needconfig = False - getUIHandlerNum.readonly = True - - def setEventMask(self, command, params): - handlerNum = params[0] - llevel = params[1] - debug_domains = params[2] - mask = params[3] - return bb.event.set_UIHmask(handlerNum, llevel, debug_domains, mask) - setEventMask.needconfig = False - setEventMask.readonly = True - - def setFeatures(self, command, params): - """ - Set the cooker features to include the passed list of features - """ - features = params[0] - command.cooker.setFeatures(features) - setFeatures.needconfig = False - # although we change the internal state of the cooker, this is transparent since - # we always take and leave the cooker in state.initial - setFeatures.readonly = True - - def updateConfig(self, command, params): - options = params[0] - environment = params[1] - cmdline = params[2] - command.cooker.updateConfigOpts(options, environment, cmdline) - updateConfig.needconfig = False - - def parseConfiguration(self, command, params): - """Instruct bitbake to parse its configuration - NOTE: it is only necessary to call this if you aren't calling any normal action - (otherwise parsing is taken care of automatically) - """ - command.cooker.parseConfiguration() - parseConfiguration.needconfig = False - - def getLayerPriorities(self, command, params): - command.cooker.parseConfiguration() - ret = [] - # regex objects cannot be marshalled by xmlrpc - for collection, pattern, regex, pri in command.cooker.bbfile_config_priorities: - ret.append((collection, pattern, regex.pattern, pri)) - return ret - getLayerPriorities.readonly = True - - def getRecipes(self, command, params): - try: - mc = params[0] - except IndexError: - mc = '' - return list(command.cooker.recipecaches[mc].pkg_pn.items()) - getRecipes.readonly = True - - def getRecipeDepends(self, command, params): - try: - mc = params[0] - except IndexError: - mc = '' - return list(command.cooker.recipecaches[mc].deps.items()) - getRecipeDepends.readonly = True - - def getRecipeVersions(self, command, params): - try: - mc = params[0] - except IndexError: - mc = '' - return command.cooker.recipecaches[mc].pkg_pepvpr - getRecipeVersions.readonly = True - - def getRecipeProvides(self, command, params): - try: - mc = params[0] - except IndexError: - mc = '' - return command.cooker.recipecaches[mc].fn_provides - getRecipeProvides.readonly = True - - def getRecipePackages(self, command, params): - try: - mc = params[0] - except IndexError: - mc = '' - return command.cooker.recipecaches[mc].packages - getRecipePackages.readonly = True - - def getRecipePackagesDynamic(self, command, params): - try: - mc = params[0] - except IndexError: - mc = '' - return command.cooker.recipecaches[mc].packages_dynamic - getRecipePackagesDynamic.readonly = True - - def getRProviders(self, command, params): - try: - mc = params[0] - except IndexError: - mc = '' - return command.cooker.recipecaches[mc].rproviders - getRProviders.readonly = True - - def getRuntimeDepends(self, command, params): - ret = [] - try: - mc = params[0] - except IndexError: - mc = '' - rundeps = command.cooker.recipecaches[mc].rundeps - for key, value in rundeps.items(): - if isinstance(value, defaultdict): - value = dict(value) - ret.append((key, value)) - return ret - getRuntimeDepends.readonly = True - - def getRuntimeRecommends(self, command, params): - ret = [] - try: - mc = params[0] - except IndexError: - mc = '' - runrecs = command.cooker.recipecaches[mc].runrecs - for key, value in runrecs.items(): - if isinstance(value, defaultdict): - value = dict(value) - ret.append((key, value)) - return ret - getRuntimeRecommends.readonly = True - - def getRecipeInherits(self, command, params): - try: - mc = params[0] - except IndexError: - mc = '' - return command.cooker.recipecaches[mc].inherits - getRecipeInherits.readonly = True - - def getBbFilePriority(self, command, params): - try: - mc = params[0] - except IndexError: - mc = '' - return command.cooker.recipecaches[mc].bbfile_priority - getBbFilePriority.readonly = True - - def getDefaultPreference(self, command, params): - try: - mc = params[0] - except IndexError: - mc = '' - return command.cooker.recipecaches[mc].pkg_dp - getDefaultPreference.readonly = True - - def getSkippedRecipes(self, command, params): - # Return list sorted by reverse priority order - import bb.cache - skipdict = OrderedDict(sorted(command.cooker.skiplist.items(), - key=lambda x: (-command.cooker.collection.calc_bbfile_priority(bb.cache.virtualfn2realfn(x[0])[0]), x[0]))) - return list(skipdict.items()) - getSkippedRecipes.readonly = True - - def getOverlayedRecipes(self, command, params): - return list(command.cooker.collection.overlayed.items()) - getOverlayedRecipes.readonly = True - - def getFileAppends(self, command, params): - fn = params[0] - return command.cooker.collection.get_file_appends(fn) - getFileAppends.readonly = True - - def getAllAppends(self, command, params): - return command.cooker.collection.bbappends - getAllAppends.readonly = True - - def findProviders(self, command, params): - return command.cooker.findProviders() - findProviders.readonly = True - - def findBestProvider(self, command, params): - (mc, pn) = split_mc_pn(params[0]) - return command.cooker.findBestProvider(pn, mc) - findBestProvider.readonly = True - - def allProviders(self, command, params): - try: - mc = params[0] - except IndexError: - mc = '' - return list(bb.providers.allProviders(command.cooker.recipecaches[mc]).items()) - allProviders.readonly = True - - def getRuntimeProviders(self, command, params): - rprovide = params[0] - try: - mc = params[1] - except IndexError: - mc = '' - all_p = bb.providers.getRuntimeProviders(command.cooker.recipecaches[mc], rprovide) - if all_p: - best = bb.providers.filterProvidersRunTime(all_p, rprovide, - command.cooker.data, - command.cooker.recipecaches[mc])[0][0] - else: - best = None - return all_p, best - getRuntimeProviders.readonly = True - - def dataStoreConnectorFindVar(self, command, params): - dsindex = params[0] - name = params[1] - datastore = command.remotedatastores[dsindex] - value, overridedata = datastore._findVar(name) - - if value: - content = value.get('_content', None) - if isinstance(content, bb.data_smart.DataSmart): - # Value is a datastore (e.g. BB_ORIGENV) - need to handle this carefully - idx = command.remotedatastores.check_store(content, True) - return {'_content': DataStoreConnectionHandle(idx), - '_connector_origtype': 'DataStoreConnectionHandle', - '_connector_overrides': overridedata} - elif isinstance(content, set): - return {'_content': list(content), - '_connector_origtype': 'set', - '_connector_overrides': overridedata} - else: - value['_connector_overrides'] = overridedata - else: - value = {} - value['_connector_overrides'] = overridedata - return value - dataStoreConnectorFindVar.readonly = True - - def dataStoreConnectorGetKeys(self, command, params): - dsindex = params[0] - datastore = command.remotedatastores[dsindex] - return list(datastore.keys()) - dataStoreConnectorGetKeys.readonly = True - - def dataStoreConnectorGetVarHistory(self, command, params): - dsindex = params[0] - name = params[1] - datastore = command.remotedatastores[dsindex] - return datastore.varhistory.variable(name) - dataStoreConnectorGetVarHistory.readonly = True - - def dataStoreConnectorExpandPythonRef(self, command, params): - config_data_dict = params[0] - varname = params[1] - expr = params[2] - - config_data = command.remotedatastores.receive_datastore(config_data_dict) - - varparse = bb.data_smart.VariableParse(varname, config_data) - return varparse.python_sub(expr) - - def dataStoreConnectorRelease(self, command, params): - dsindex = params[0] - if dsindex <= 0: - raise CommandError('dataStoreConnectorRelease: invalid index %d' % dsindex) - command.remotedatastores.release(dsindex) - - def dataStoreConnectorSetVarFlag(self, command, params): - dsindex = params[0] - name = params[1] - flag = params[2] - value = params[3] - datastore = command.remotedatastores[dsindex] - datastore.setVarFlag(name, flag, value) - - def dataStoreConnectorDelVar(self, command, params): - dsindex = params[0] - name = params[1] - datastore = command.remotedatastores[dsindex] - if len(params) > 2: - flag = params[2] - datastore.delVarFlag(name, flag) - else: - datastore.delVar(name) - - def dataStoreConnectorRenameVar(self, command, params): - dsindex = params[0] - name = params[1] - newname = params[2] - datastore = command.remotedatastores[dsindex] - datastore.renameVar(name, newname) - - def parseRecipeFile(self, command, params): - """ - Parse the specified recipe file (with or without bbappends) - and return a datastore object representing the environment - for the recipe. - """ - fn = params[0] - appends = params[1] - appendlist = params[2] - if len(params) > 3: - config_data_dict = params[3] - config_data = command.remotedatastores.receive_datastore(config_data_dict) - else: - config_data = None - - if appends: - if appendlist is not None: - appendfiles = appendlist - else: - appendfiles = command.cooker.collection.get_file_appends(fn) - else: - appendfiles = [] - # We are calling bb.cache locally here rather than on the server, - # but that's OK because it doesn't actually need anything from - # the server barring the global datastore (which we have a remote - # version of) - if config_data: - # We have to use a different function here if we're passing in a datastore - # NOTE: we took a copy above, so we don't do it here again - envdata = bb.cache.parse_recipe(config_data, fn, appendfiles)[''] - else: - # Use the standard path - parser = bb.cache.NoCache(command.cooker.databuilder) - envdata = parser.loadDataFull(fn, appendfiles) - idx = command.remotedatastores.store(envdata) - return DataStoreConnectionHandle(idx) - parseRecipeFile.readonly = True - -class CommandsAsync: - """ - A class of asynchronous commands - These functions communicate via generated events. - Any function that requires metadata parsing should be here. - """ - - def buildFile(self, command, params): - """ - Build a single specified .bb file - """ - bfile = params[0] - task = params[1] - if len(params) > 2: - internal = params[2] - else: - internal = False - - if internal: - command.cooker.buildFileInternal(bfile, task, fireevents=False, quietlog=True) - else: - command.cooker.buildFile(bfile, task) - buildFile.needcache = False - - def buildTargets(self, command, params): - """ - Build a set of targets - """ - pkgs_to_build = params[0] - task = params[1] - - command.cooker.buildTargets(pkgs_to_build, task) - buildTargets.needcache = True - - def generateDepTreeEvent(self, command, params): - """ - Generate an event containing the dependency information - """ - pkgs_to_build = params[0] - task = params[1] - - command.cooker.generateDepTreeEvent(pkgs_to_build, task) - command.finishAsyncCommand() - generateDepTreeEvent.needcache = True - - def generateDotGraph(self, command, params): - """ - Dump dependency information to disk as .dot files - """ - pkgs_to_build = params[0] - task = params[1] - - command.cooker.generateDotGraphFiles(pkgs_to_build, task) - command.finishAsyncCommand() - generateDotGraph.needcache = True - - def generateTargetsTree(self, command, params): - """ - Generate a tree of buildable targets. - If klass is provided ensure all recipes that inherit the class are - included in the package list. - If pkg_list provided use that list (plus any extras brought in by - klass) rather than generating a tree for all packages. - """ - klass = params[0] - pkg_list = params[1] - - command.cooker.generateTargetsTree(klass, pkg_list) - command.finishAsyncCommand() - generateTargetsTree.needcache = True - - def findConfigFiles(self, command, params): - """ - Find config files which provide appropriate values - for the passed configuration variable. i.e. MACHINE - """ - varname = params[0] - - command.cooker.findConfigFiles(varname) - command.finishAsyncCommand() - findConfigFiles.needcache = False - - def findFilesMatchingInDir(self, command, params): - """ - Find implementation files matching the specified pattern - in the requested subdirectory of a BBPATH - """ - pattern = params[0] - directory = params[1] - - command.cooker.findFilesMatchingInDir(pattern, directory) - command.finishAsyncCommand() - findFilesMatchingInDir.needcache = False - - def findConfigFilePath(self, command, params): - """ - Find the path of the requested configuration file - """ - configfile = params[0] - - command.cooker.findConfigFilePath(configfile) - command.finishAsyncCommand() - findConfigFilePath.needcache = False - - def showVersions(self, command, params): - """ - Show the currently selected versions - """ - command.cooker.showVersions() - command.finishAsyncCommand() - showVersions.needcache = True - - def showEnvironmentTarget(self, command, params): - """ - Print the environment of a target recipe - (needs the cache to work out which recipe to use) - """ - pkg = params[0] - - command.cooker.showEnvironment(None, pkg) - command.finishAsyncCommand() - showEnvironmentTarget.needcache = True - - def showEnvironment(self, command, params): - """ - Print the standard environment - or if specified the environment for a specified recipe - """ - bfile = params[0] - - command.cooker.showEnvironment(bfile) - command.finishAsyncCommand() - showEnvironment.needcache = False - - def parseFiles(self, command, params): - """ - Parse the .bb files - """ - command.cooker.updateCache() - command.finishAsyncCommand() - parseFiles.needcache = True - - def compareRevisions(self, command, params): - """ - Parse the .bb files - """ - if bb.fetch.fetcher_compare_revisions(command.cooker.data): - command.finishAsyncCommand(code=1) - else: - command.finishAsyncCommand() - compareRevisions.needcache = True - - def triggerEvent(self, command, params): - """ - Trigger a certain event - """ - event = params[0] - bb.event.fire(eval(event), command.cooker.data) - command.currentAsyncCommand = None - triggerEvent.needcache = False - - def resetCooker(self, command, params): - """ - Reset the cooker to its initial state, thus forcing a reparse for - any async command that has the needcache property set to True - """ - command.cooker.reset() - command.finishAsyncCommand() - resetCooker.needcache = False - - def clientComplete(self, command, params): - """ - Do the right thing when the controlling client exits - """ - command.cooker.clientComplete() - command.finishAsyncCommand() - clientComplete.needcache = False - - def findSigInfo(self, command, params): - """ - Find signature info files via the signature generator - """ - pn = params[0] - taskname = params[1] - sigs = params[2] - res = bb.siggen.find_siginfo(pn, taskname, sigs, command.cooker.data) - bb.event.fire(bb.event.FindSigInfoResult(res), command.cooker.data) - command.finishAsyncCommand() - findSigInfo.needcache = False |