diff options
Diffstat (limited to 'bitbake/lib/bb/command.py')
-rw-r--r-- | bitbake/lib/bb/command.py | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/bitbake/lib/bb/command.py b/bitbake/lib/bb/command.py new file mode 100644 index 0000000000..2bb5365c0c --- /dev/null +++ b/bitbake/lib/bb/command.py @@ -0,0 +1,271 @@ +""" +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 +""" + +import bb + +async_cmds = {} +sync_cmds = {} + +class Command: + """ + A queue of asynchronous commands for bitbake + """ + def __init__(self, cooker): + + self.cooker = cooker + self.cmds_sync = CommandsSync() + self.cmds_async = CommandsAsync() + + # FIXME Add lock for this + self.currentAsyncCommand = None + + for attr in CommandsSync.__dict__: + command = attr[:].lower() + method = getattr(CommandsSync, attr) + sync_cmds[command] = (method) + + for attr in CommandsAsync.__dict__: + command = attr[:].lower() + method = getattr(CommandsAsync, attr) + async_cmds[command] = (method) + + def runCommand(self, commandline): + try: + command = commandline.pop(0) + if command in CommandsSync.__dict__: + # Can run synchronous commands straight away + return getattr(CommandsSync, command)(self.cmds_sync, self, commandline) + if self.currentAsyncCommand is not None: + return "Busy (%s in progress)" % self.currentAsyncCommand[0] + if command not in CommandsAsync.__dict__: + return "No such command" + self.currentAsyncCommand = (command, commandline) + self.cooker.server.register_idle_function(self.cooker.runCommands, self.cooker) + return True + except: + import traceback + return traceback.format_exc() + + def runAsyncCommand(self): + try: + if self.currentAsyncCommand is not None: + (command, options) = self.currentAsyncCommand + commandmethod = getattr(CommandsAsync, command) + needcache = getattr( commandmethod, "needcache" ) + if needcache and self.cooker.cookerState != bb.cooker.cookerParsed: + self.cooker.updateCache() + return True + else: + commandmethod(self.cmds_async, self, options) + return False + else: + return False + except: + import traceback + self.finishAsyncCommand(traceback.format_exc()) + return False + + def finishAsyncCommand(self, error = None): + if error: + bb.event.fire(bb.command.CookerCommandFailed(error), self.cooker.configuration.event_data) + else: + bb.event.fire(bb.command.CookerCommandCompleted(), self.cooker.configuration.event_data) + self.currentAsyncCommand = None + + +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.cookerAction = bb.cooker.cookerShutdown + + def stateStop(self, command, params): + """ + Stop the cooker + """ + command.cooker.cookerAction = bb.cooker.cookerStop + + def getCmdLineAction(self, command, params): + """ + Get any command parsed from the commandline + """ + return command.cooker.commandlineAction + + def getVariable(self, command, params): + """ + Read the value of a variable from configuration.data + """ + varname = params[0] + expand = True + if len(params) > 1: + expand = params[1] + + return bb.data.getVar(varname, command.cooker.configuration.data, expand) + + def setVariable(self, command, params): + """ + Set the value of variable in configuration.data + """ + varname = params[0] + value = params[1] + bb.data.setVar(varname, value, command.cooker.configuration.data) + + +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] + + 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 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 + """ + command.cooker.compareRevisions() + command.finishAsyncCommand() + compareRevisions.needcache = True + +# +# Events +# +class CookerCommandCompleted(bb.event.Event): + """ + Cooker command completed + """ + def __init__(self): + bb.event.Event.__init__(self) + + +class CookerCommandFailed(bb.event.Event): + """ + Cooker command completed + """ + def __init__(self, error): + bb.event.Event.__init__(self) + self.error = error + +class CookerCommandSetExitCode(bb.event.Event): + """ + Set the exit code for a cooker command + """ + def __init__(self, exitcode): + bb.event.Event.__init__(self) + self.exitcode = int(exitcode) + + + |