2008-09-30 15:08:33 +00:00
|
|
|
"""
|
|
|
|
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.
|
2008-10-23 13:28:11 +00:00
|
|
|
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
|
2008-09-30 15:08:33 +00:00
|
|
|
and must not trigger events, directly or indirectly.
|
|
|
|
Commands are queued in a CommandQueue
|
|
|
|
"""
|
|
|
|
|
|
|
|
import bb
|
|
|
|
|
2008-10-23 13:28:11 +00:00
|
|
|
async_cmds = {}
|
|
|
|
sync_cmds = {}
|
2008-09-30 15:08:33 +00:00
|
|
|
|
|
|
|
class Command:
|
|
|
|
"""
|
2008-10-23 13:28:11 +00:00
|
|
|
A queue of asynchronous commands for bitbake
|
2008-09-30 15:08:33 +00:00
|
|
|
"""
|
|
|
|
def __init__(self, cooker):
|
|
|
|
|
|
|
|
self.cooker = cooker
|
2008-10-23 13:28:11 +00:00
|
|
|
self.cmds_sync = CommandsSync()
|
|
|
|
self.cmds_async = CommandsAsync()
|
2008-09-30 15:08:33 +00:00
|
|
|
|
|
|
|
# FIXME Add lock for this
|
2008-10-23 13:28:11 +00:00
|
|
|
self.currentAsyncCommand = None
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2008-10-23 13:28:11 +00:00
|
|
|
for attr in CommandsSync.__dict__:
|
2008-09-30 15:08:33 +00:00
|
|
|
command = attr[:].lower()
|
2008-10-23 13:28:11 +00:00
|
|
|
method = getattr(CommandsSync, attr)
|
|
|
|
sync_cmds[command] = (method)
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2008-10-23 13:28:11 +00:00
|
|
|
for attr in CommandsAsync.__dict__:
|
2008-09-30 15:08:33 +00:00
|
|
|
command = attr[:].lower()
|
2008-10-23 13:28:11 +00:00
|
|
|
method = getattr(CommandsAsync, attr)
|
|
|
|
async_cmds[command] = (method)
|
2008-09-30 15:08:33 +00:00
|
|
|
|
|
|
|
def runCommand(self, commandline):
|
|
|
|
try:
|
|
|
|
command = commandline.pop(0)
|
2008-10-23 13:28:11 +00:00
|
|
|
if command in CommandsSync.__dict__:
|
2009-07-08 21:46:09 +00:00
|
|
|
# Can run synchronous commands straight away
|
2008-10-23 13:28:11 +00:00
|
|
|
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__:
|
2008-09-30 15:08:33 +00:00
|
|
|
return "No such command"
|
2008-10-23 13:28:11 +00:00
|
|
|
self.currentAsyncCommand = (command, commandline)
|
2009-07-08 21:46:09 +00:00
|
|
|
self.cooker.server.register_idle_function(self.cooker.runCommands, self.cooker)
|
2008-09-30 15:08:33 +00:00
|
|
|
return True
|
|
|
|
except:
|
|
|
|
import traceback
|
|
|
|
return traceback.format_exc()
|
|
|
|
|
2008-10-23 13:28:11 +00:00
|
|
|
def runAsyncCommand(self):
|
2008-09-30 15:08:33 +00:00
|
|
|
try:
|
2008-10-23 13:28:11 +00:00
|
|
|
if self.currentAsyncCommand is not None:
|
|
|
|
(command, options) = self.currentAsyncCommand
|
2009-07-08 21:46:09 +00:00
|
|
|
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
|
2008-09-30 15:08:33 +00:00
|
|
|
except:
|
|
|
|
import traceback
|
2008-10-23 13:28:11 +00:00
|
|
|
self.finishAsyncCommand(traceback.format_exc())
|
2009-07-08 21:46:09 +00:00
|
|
|
return False
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2008-10-23 13:28:11 +00:00
|
|
|
def finishAsyncCommand(self, error = None):
|
2008-09-30 15:08:33 +00:00
|
|
|
if error:
|
2010-01-19 14:48:19 +00:00
|
|
|
bb.event.fire(bb.command.CookerCommandFailed(error), self.cooker.configuration.event_data)
|
2008-09-30 15:08:33 +00:00
|
|
|
else:
|
2010-01-19 14:48:19 +00:00
|
|
|
bb.event.fire(bb.command.CookerCommandCompleted(), self.cooker.configuration.event_data)
|
2008-10-23 13:28:11 +00:00
|
|
|
self.currentAsyncCommand = None
|
2008-09-30 15:08:33 +00:00
|
|
|
|
|
|
|
|
2008-10-23 13:28:11 +00:00
|
|
|
class CommandsSync:
|
2008-09-30 15:08:33 +00:00
|
|
|
"""
|
2008-10-23 13:28:11 +00:00
|
|
|
A class of synchronous commands
|
2008-09-30 15:08:33 +00:00
|
|
|
These should run quickly so as not to hurt interactive performance.
|
2008-10-23 13:28:11 +00:00
|
|
|
These must not influence any running synchronous command.
|
2008-09-30 15:08:33 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2008-10-23 13:58:36 +00:00
|
|
|
def getVariable(self, command, params):
|
2008-09-30 15:08:33 +00:00
|
|
|
"""
|
|
|
|
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)
|
|
|
|
|
2008-10-24 13:44:30 +00:00
|
|
|
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)
|
|
|
|
|
|
|
|
|
2008-10-23 13:28:11 +00:00
|
|
|
class CommandsAsync:
|
2008-09-30 15:08:33 +00:00
|
|
|
"""
|
2008-10-23 13:28:11 +00:00
|
|
|
A class of asynchronous commands
|
2008-09-30 15:08:33 +00:00
|
|
|
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)
|
2009-07-08 21:46:09 +00:00
|
|
|
buildFile.needcache = False
|
2008-09-30 15:08:33 +00:00
|
|
|
|
|
|
|
def buildTargets(self, command, params):
|
|
|
|
"""
|
|
|
|
Build a set of targets
|
|
|
|
"""
|
|
|
|
pkgs_to_build = params[0]
|
2008-10-24 15:22:19 +00:00
|
|
|
task = params[1]
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2008-10-24 15:22:19 +00:00
|
|
|
command.cooker.buildTargets(pkgs_to_build, task)
|
2009-07-08 21:46:09 +00:00
|
|
|
buildTargets.needcache = True
|
2008-09-30 15:08:33 +00:00
|
|
|
|
|
|
|
def generateDepTreeEvent(self, command, params):
|
|
|
|
"""
|
|
|
|
Generate an event containing the dependency information
|
|
|
|
"""
|
|
|
|
pkgs_to_build = params[0]
|
2008-10-24 16:22:20 +00:00
|
|
|
task = params[1]
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2008-10-24 16:22:20 +00:00
|
|
|
command.cooker.generateDepTreeEvent(pkgs_to_build, task)
|
2008-10-23 13:28:11 +00:00
|
|
|
command.finishAsyncCommand()
|
2009-07-08 21:46:09 +00:00
|
|
|
generateDepTreeEvent.needcache = True
|
2008-09-30 15:08:33 +00:00
|
|
|
|
|
|
|
def generateDotGraph(self, command, params):
|
|
|
|
"""
|
|
|
|
Dump dependency information to disk as .dot files
|
|
|
|
"""
|
|
|
|
pkgs_to_build = params[0]
|
2008-10-24 16:22:20 +00:00
|
|
|
task = params[1]
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2008-10-24 16:22:20 +00:00
|
|
|
command.cooker.generateDotGraphFiles(pkgs_to_build, task)
|
2008-10-23 13:28:11 +00:00
|
|
|
command.finishAsyncCommand()
|
2009-07-08 21:46:09 +00:00
|
|
|
generateDotGraph.needcache = True
|
2008-09-30 15:08:33 +00:00
|
|
|
|
|
|
|
def showVersions(self, command, params):
|
|
|
|
"""
|
|
|
|
Show the currently selected versions
|
|
|
|
"""
|
|
|
|
command.cooker.showVersions()
|
2008-10-23 13:28:11 +00:00
|
|
|
command.finishAsyncCommand()
|
2009-07-08 21:46:09 +00:00
|
|
|
showVersions.needcache = True
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2009-07-23 18:51:56 +00:00
|
|
|
def showEnvironmentTarget(self, command, params):
|
2008-09-30 15:08:33 +00:00
|
|
|
"""
|
2009-07-23 18:51:56 +00:00
|
|
|
Print the environment of a target recipe
|
|
|
|
(needs the cache to work out which recipe to use)
|
2008-09-30 15:08:33 +00:00
|
|
|
"""
|
2009-07-23 18:51:56 +00:00
|
|
|
pkg = params[0]
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2009-07-23 18:51:56 +00:00
|
|
|
command.cooker.showEnvironment(None, pkg)
|
2008-10-23 13:28:11 +00:00
|
|
|
command.finishAsyncCommand()
|
2009-07-23 18:51:56 +00:00
|
|
|
showEnvironmentTarget.needcache = True
|
2009-07-23 18:42:04 +00:00
|
|
|
|
|
|
|
def showEnvironment(self, command, params):
|
|
|
|
"""
|
|
|
|
Print the standard environment
|
2009-07-23 18:51:56 +00:00
|
|
|
or if specified the environment for a specified recipe
|
2009-07-23 18:42:04 +00:00
|
|
|
"""
|
2009-07-23 18:51:56 +00:00
|
|
|
bfile = params[0]
|
2009-07-23 18:42:04 +00:00
|
|
|
|
2009-07-23 18:51:56 +00:00
|
|
|
command.cooker.showEnvironment(bfile)
|
2009-07-23 18:42:04 +00:00
|
|
|
command.finishAsyncCommand()
|
|
|
|
showEnvironment.needcache = False
|
2008-09-30 15:08:33 +00:00
|
|
|
|
|
|
|
def parseFiles(self, command, params):
|
|
|
|
"""
|
|
|
|
Parse the .bb files
|
|
|
|
"""
|
|
|
|
command.cooker.updateCache()
|
2008-10-23 13:28:11 +00:00
|
|
|
command.finishAsyncCommand()
|
2009-07-08 21:46:09 +00:00
|
|
|
parseFiles.needcache = True
|
2008-09-30 15:08:33 +00:00
|
|
|
|
2009-07-29 13:33:14 +00:00
|
|
|
def compareRevisions(self, command, params):
|
|
|
|
"""
|
|
|
|
Parse the .bb files
|
|
|
|
"""
|
|
|
|
command.cooker.compareRevisions()
|
|
|
|
command.finishAsyncCommand()
|
|
|
|
compareRevisions.needcache = True
|
|
|
|
|
2008-09-30 15:08:33 +00:00
|
|
|
#
|
|
|
|
# Events
|
|
|
|
#
|
|
|
|
class CookerCommandCompleted(bb.event.Event):
|
|
|
|
"""
|
|
|
|
Cooker command completed
|
|
|
|
"""
|
2010-01-19 14:48:19 +00:00
|
|
|
def __init__(self):
|
|
|
|
bb.event.Event.__init__(self)
|
2008-09-30 15:08:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
class CookerCommandFailed(bb.event.Event):
|
|
|
|
"""
|
|
|
|
Cooker command completed
|
|
|
|
"""
|
2010-01-19 14:48:19 +00:00
|
|
|
def __init__(self, error):
|
|
|
|
bb.event.Event.__init__(self)
|
2008-09-30 15:08:33 +00:00
|
|
|
self.error = error
|
2009-07-29 13:33:14 +00:00
|
|
|
|
|
|
|
class CookerCommandSetExitCode(bb.event.Event):
|
|
|
|
"""
|
|
|
|
Set the exit code for a cooker command
|
|
|
|
"""
|
2010-01-19 14:48:19 +00:00
|
|
|
def __init__(self, exitcode):
|
|
|
|
bb.event.Event.__init__(self)
|
2009-07-29 13:33:14 +00:00
|
|
|
self.exitcode = int(exitcode)
|
|
|
|
|
|
|
|
|
|
|
|
|