bitbake-dev: Turn parsing into a server idle callback allowing the client to interrupt parsing and improving user interactvity. Also now specify whether async commands need the cache or not
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
This commit is contained in:
parent
67d169aa1c
commit
433f50435e
|
@ -57,16 +57,18 @@ class Command:
|
||||||
async_cmds[command] = (method)
|
async_cmds[command] = (method)
|
||||||
|
|
||||||
def runCommand(self, commandline):
|
def runCommand(self, commandline):
|
||||||
|
bb.debug("Running command %s" % commandline)
|
||||||
try:
|
try:
|
||||||
command = commandline.pop(0)
|
command = commandline.pop(0)
|
||||||
if command in CommandsSync.__dict__:
|
if command in CommandsSync.__dict__:
|
||||||
# Can run online commands straight away
|
# Can run synchronous commands straight away
|
||||||
return getattr(CommandsSync, command)(self.cmds_sync, self, commandline)
|
return getattr(CommandsSync, command)(self.cmds_sync, self, commandline)
|
||||||
if self.currentAsyncCommand is not None:
|
if self.currentAsyncCommand is not None:
|
||||||
return "Busy (%s in progress)" % self.currentAsyncCommand[0]
|
return "Busy (%s in progress)" % self.currentAsyncCommand[0]
|
||||||
if command not in CommandsAsync.__dict__:
|
if command not in CommandsAsync.__dict__:
|
||||||
return "No such command"
|
return "No such command"
|
||||||
self.currentAsyncCommand = (command, commandline)
|
self.currentAsyncCommand = (command, commandline)
|
||||||
|
self.cooker.server.register_idle_function(self.cooker.runCommands, self.cooker)
|
||||||
return True
|
return True
|
||||||
except:
|
except:
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -76,10 +78,20 @@ class Command:
|
||||||
try:
|
try:
|
||||||
if self.currentAsyncCommand is not None:
|
if self.currentAsyncCommand is not None:
|
||||||
(command, options) = self.currentAsyncCommand
|
(command, options) = self.currentAsyncCommand
|
||||||
getattr(CommandsAsync, command)(self.cmds_async, self, options)
|
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:
|
except:
|
||||||
import traceback
|
import traceback
|
||||||
self.finishAsyncCommand(traceback.format_exc())
|
self.finishAsyncCommand(traceback.format_exc())
|
||||||
|
return False
|
||||||
|
|
||||||
def finishAsyncCommand(self, error = None):
|
def finishAsyncCommand(self, error = None):
|
||||||
if error:
|
if error:
|
||||||
|
@ -149,6 +161,7 @@ class CommandsAsync:
|
||||||
task = params[1]
|
task = params[1]
|
||||||
|
|
||||||
command.cooker.buildFile(bfile, task)
|
command.cooker.buildFile(bfile, task)
|
||||||
|
buildFile.needcache = False
|
||||||
|
|
||||||
def buildTargets(self, command, params):
|
def buildTargets(self, command, params):
|
||||||
"""
|
"""
|
||||||
|
@ -158,6 +171,7 @@ class CommandsAsync:
|
||||||
task = params[1]
|
task = params[1]
|
||||||
|
|
||||||
command.cooker.buildTargets(pkgs_to_build, task)
|
command.cooker.buildTargets(pkgs_to_build, task)
|
||||||
|
buildTargets.needcache = True
|
||||||
|
|
||||||
def generateDepTreeEvent(self, command, params):
|
def generateDepTreeEvent(self, command, params):
|
||||||
"""
|
"""
|
||||||
|
@ -168,6 +182,7 @@ class CommandsAsync:
|
||||||
|
|
||||||
command.cooker.generateDepTreeEvent(pkgs_to_build, task)
|
command.cooker.generateDepTreeEvent(pkgs_to_build, task)
|
||||||
command.finishAsyncCommand()
|
command.finishAsyncCommand()
|
||||||
|
generateDepTreeEvent.needcache = True
|
||||||
|
|
||||||
def generateDotGraph(self, command, params):
|
def generateDotGraph(self, command, params):
|
||||||
"""
|
"""
|
||||||
|
@ -178,6 +193,7 @@ class CommandsAsync:
|
||||||
|
|
||||||
command.cooker.generateDotGraphFiles(pkgs_to_build, task)
|
command.cooker.generateDotGraphFiles(pkgs_to_build, task)
|
||||||
command.finishAsyncCommand()
|
command.finishAsyncCommand()
|
||||||
|
generateDotGraph.needcache = True
|
||||||
|
|
||||||
def showVersions(self, command, params):
|
def showVersions(self, command, params):
|
||||||
"""
|
"""
|
||||||
|
@ -185,6 +201,7 @@ class CommandsAsync:
|
||||||
"""
|
"""
|
||||||
command.cooker.showVersions()
|
command.cooker.showVersions()
|
||||||
command.finishAsyncCommand()
|
command.finishAsyncCommand()
|
||||||
|
showVersions.needcache = True
|
||||||
|
|
||||||
def showEnvironment(self, command, params):
|
def showEnvironment(self, command, params):
|
||||||
"""
|
"""
|
||||||
|
@ -195,6 +212,7 @@ class CommandsAsync:
|
||||||
|
|
||||||
command.cooker.showEnvironment(bfile, pkg)
|
command.cooker.showEnvironment(bfile, pkg)
|
||||||
command.finishAsyncCommand()
|
command.finishAsyncCommand()
|
||||||
|
showEnvironment.needcache = True
|
||||||
|
|
||||||
def parseFiles(self, command, params):
|
def parseFiles(self, command, params):
|
||||||
"""
|
"""
|
||||||
|
@ -202,6 +220,7 @@ class CommandsAsync:
|
||||||
"""
|
"""
|
||||||
command.cooker.updateCache()
|
command.cooker.updateCache()
|
||||||
command.finishAsyncCommand()
|
command.finishAsyncCommand()
|
||||||
|
parseFiles.needcache = True
|
||||||
|
|
||||||
#
|
#
|
||||||
# Events
|
# Events
|
||||||
|
|
|
@ -46,7 +46,8 @@ class NothingToBuild(Exception):
|
||||||
|
|
||||||
# Different states cooker can be in
|
# Different states cooker can be in
|
||||||
cookerClean = 1
|
cookerClean = 1
|
||||||
cookerParsed = 2
|
cookerParsing = 2
|
||||||
|
cookerParsed = 3
|
||||||
|
|
||||||
# Different action states the cooker can be in
|
# Different action states the cooker can be in
|
||||||
cookerRun = 1 # Cooker is running normally
|
cookerRun = 1 # Cooker is running normally
|
||||||
|
@ -116,10 +117,8 @@ class BBCooker:
|
||||||
termios.tcsetattr(fd, termios.TCSANOW, tcattr)
|
termios.tcsetattr(fd, termios.TCSANOW, tcattr)
|
||||||
|
|
||||||
self.command = bb.command.Command(self)
|
self.command = bb.command.Command(self)
|
||||||
self.cookerIdle = True
|
|
||||||
self.cookerState = cookerClean
|
self.cookerState = cookerClean
|
||||||
self.cookerAction = cookerRun
|
self.cookerAction = cookerRun
|
||||||
self.server.register_idle_function(self.runCommands, self)
|
|
||||||
|
|
||||||
def parseConfiguration(self):
|
def parseConfiguration(self):
|
||||||
|
|
||||||
|
@ -172,11 +171,8 @@ class BBCooker:
|
||||||
This is done by the idle handler so it runs in true context rather than
|
This is done by the idle handler so it runs in true context rather than
|
||||||
tied to any UI.
|
tied to any UI.
|
||||||
"""
|
"""
|
||||||
if self.cookerIdle and not abort:
|
|
||||||
self.command.runAsyncCommand()
|
|
||||||
|
|
||||||
# Always reschedule
|
return self.command.runAsyncCommand()
|
||||||
return True
|
|
||||||
|
|
||||||
def tryBuildPackage(self, fn, item, task, the_data):
|
def tryBuildPackage(self, fn, item, task, the_data):
|
||||||
"""
|
"""
|
||||||
|
@ -675,12 +671,11 @@ class BBCooker:
|
||||||
failures = failures + 1
|
failures = failures + 1
|
||||||
retval = False
|
retval = False
|
||||||
if not retval:
|
if not retval:
|
||||||
self.cookerIdle = True
|
|
||||||
self.command.finishAsyncCommand()
|
self.command.finishAsyncCommand()
|
||||||
bb.event.fire(bb.event.BuildCompleted(buildname, targets, self.configuration.event_data, failures))
|
bb.event.fire(bb.event.BuildCompleted(buildname, targets, self.configuration.event_data, failures))
|
||||||
return retval
|
return False
|
||||||
|
return 0.5
|
||||||
|
|
||||||
self.cookerIdle = False
|
|
||||||
self.server.register_idle_function(buildFileIdle, rq)
|
self.server.register_idle_function(buildFileIdle, rq)
|
||||||
|
|
||||||
def buildTargets(self, targets, task):
|
def buildTargets(self, targets, task):
|
||||||
|
@ -712,10 +707,10 @@ class BBCooker:
|
||||||
failures = failures + 1
|
failures = failures + 1
|
||||||
retval = False
|
retval = False
|
||||||
if not retval:
|
if not retval:
|
||||||
self.cookerIdle = True
|
|
||||||
self.command.finishAsyncCommand()
|
self.command.finishAsyncCommand()
|
||||||
bb.event.fire(bb.event.BuildCompleted(buildname, targets, self.configuration.event_data, failures))
|
bb.event.fire(bb.event.BuildCompleted(buildname, targets, self.configuration.event_data, failures))
|
||||||
return retval
|
return None
|
||||||
|
return 0.5
|
||||||
|
|
||||||
self.buildSetVars()
|
self.buildSetVars()
|
||||||
|
|
||||||
|
@ -736,47 +731,54 @@ class BBCooker:
|
||||||
|
|
||||||
rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist)
|
rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist)
|
||||||
|
|
||||||
self.cookerIdle = False
|
|
||||||
self.server.register_idle_function(buildTargetsIdle, rq)
|
self.server.register_idle_function(buildTargetsIdle, rq)
|
||||||
|
|
||||||
def updateCache(self):
|
def updateCache(self):
|
||||||
|
|
||||||
self.parseConfiguration ()
|
|
||||||
if self.cookerState == cookerParsed:
|
if self.cookerState == cookerParsed:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Import Psyco if available and not disabled
|
if self.cookerState != cookerParsing:
|
||||||
import platform
|
|
||||||
if platform.machine() in ['i386', 'i486', 'i586', 'i686']:
|
self.parseConfiguration ()
|
||||||
if not self.configuration.disable_psyco:
|
|
||||||
try:
|
# Import Psyco if available and not disabled
|
||||||
import psyco
|
import platform
|
||||||
except ImportError:
|
if platform.machine() in ['i386', 'i486', 'i586', 'i686']:
|
||||||
bb.msg.note(1, bb.msg.domain.Collection, "Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
|
if not self.configuration.disable_psyco:
|
||||||
|
try:
|
||||||
|
import psyco
|
||||||
|
except ImportError:
|
||||||
|
bb.msg.note(1, bb.msg.domain.Collection, "Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
|
||||||
|
else:
|
||||||
|
psyco.bind( CookerParser.parse_next )
|
||||||
else:
|
else:
|
||||||
psyco.bind( self.parse_bbfiles )
|
bb.msg.note(1, bb.msg.domain.Collection, "You have disabled Psyco. This decreases performance.")
|
||||||
else:
|
|
||||||
bb.msg.note(1, bb.msg.domain.Collection, "You have disabled Psyco. This decreases performance.")
|
|
||||||
|
|
||||||
self.status = bb.cache.CacheData()
|
self.status = bb.cache.CacheData()
|
||||||
|
|
||||||
ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
|
ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
|
||||||
self.status.ignored_dependencies = set(ignore.split())
|
self.status.ignored_dependencies = set(ignore.split())
|
||||||
|
|
||||||
|
for dep in self.configuration.extra_assume_provided:
|
||||||
|
self.status.ignored_dependencies.add(dep)
|
||||||
|
|
||||||
|
self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
|
||||||
|
|
||||||
for dep in self.configuration.extra_assume_provided:
|
bb.msg.debug(1, bb.msg.domain.Collection, "collecting .bb files")
|
||||||
self.status.ignored_dependencies.add(dep)
|
(filelist, masked) = self.collect_bbfiles()
|
||||||
|
bb.data.renameVar("__depends", "__base_depends", self.configuration.data)
|
||||||
|
|
||||||
self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
|
self.parser = CookerParser(self, filelist, masked)
|
||||||
|
self.cookerState = cookerParsing
|
||||||
|
|
||||||
bb.msg.debug(1, bb.msg.domain.Collection, "collecting .bb files")
|
if not self.parser.parse_next():
|
||||||
(filelist, masked) = self.collect_bbfiles()
|
bb.msg.debug(1, bb.msg.domain.Collection, "parsing complete")
|
||||||
bb.data.renameVar("__depends", "__base_depends", self.configuration.data)
|
self.buildDepgraph()
|
||||||
self.parse_bbfiles(filelist, masked)
|
self.cookerState = cookerParsed
|
||||||
bb.msg.debug(1, bb.msg.domain.Collection, "parsing complete")
|
return None
|
||||||
|
|
||||||
self.buildDepgraph()
|
return 0.00001
|
||||||
|
|
||||||
self.cookerState = cookerParsed
|
|
||||||
|
|
||||||
def checkPackages(self, pkgs_to_build):
|
def checkPackages(self, pkgs_to_build):
|
||||||
|
|
||||||
|
@ -861,57 +863,6 @@ class BBCooker:
|
||||||
|
|
||||||
return (finalfiles, masked)
|
return (finalfiles, masked)
|
||||||
|
|
||||||
def parse_bbfiles(self, filelist, masked):
|
|
||||||
parsed, cached, skipped, error, total = 0, 0, 0, 0, len(filelist)
|
|
||||||
for i in xrange(total):
|
|
||||||
f = filelist[i]
|
|
||||||
|
|
||||||
#bb.msg.debug(1, bb.msg.domain.Collection, "parsing %s" % f)
|
|
||||||
|
|
||||||
# read a file's metadata
|
|
||||||
try:
|
|
||||||
fromCache, skip = self.bb_cache.loadData(f, self.configuration.data, self.status)
|
|
||||||
if skip:
|
|
||||||
skipped += 1
|
|
||||||
bb.msg.debug(2, bb.msg.domain.Collection, "skipping %s" % f)
|
|
||||||
self.bb_cache.skip(f)
|
|
||||||
continue
|
|
||||||
elif fromCache: cached += 1
|
|
||||||
else: parsed += 1
|
|
||||||
|
|
||||||
# Disabled by RP as was no longer functional
|
|
||||||
# allow metadata files to add items to BBFILES
|
|
||||||
#data.update_data(self.pkgdata[f])
|
|
||||||
#addbbfiles = self.bb_cache.getVar('BBFILES', f, False) or None
|
|
||||||
#if addbbfiles:
|
|
||||||
# for aof in addbbfiles.split():
|
|
||||||
# if not files.count(aof):
|
|
||||||
# if not os.path.isabs(aof):
|
|
||||||
# aof = os.path.join(os.path.dirname(f),aof)
|
|
||||||
# files.append(aof)
|
|
||||||
|
|
||||||
except IOError, e:
|
|
||||||
error += 1
|
|
||||||
self.bb_cache.remove(f)
|
|
||||||
bb.msg.error(bb.msg.domain.Collection, "opening %s: %s" % (f, e))
|
|
||||||
pass
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
self.bb_cache.sync()
|
|
||||||
raise
|
|
||||||
except Exception, e:
|
|
||||||
error += 1
|
|
||||||
self.bb_cache.remove(f)
|
|
||||||
bb.msg.error(bb.msg.domain.Collection, "%s while parsing %s" % (e, f))
|
|
||||||
except:
|
|
||||||
self.bb_cache.remove(f)
|
|
||||||
raise
|
|
||||||
finally:
|
|
||||||
bb.event.fire(bb.event.ParseProgress(self.configuration.event_data, cached, parsed, skipped, masked, error, total))
|
|
||||||
|
|
||||||
self.bb_cache.sync()
|
|
||||||
if error > 0:
|
|
||||||
raise ParsingErrorsFound
|
|
||||||
|
|
||||||
def serve(self):
|
def serve(self):
|
||||||
|
|
||||||
# Empty the environment. The environment will be populated as
|
# Empty the environment. The environment will be populated as
|
||||||
|
@ -955,3 +906,63 @@ class CookerExit(bb.event.Event):
|
||||||
def __init__(self, d):
|
def __init__(self, d):
|
||||||
bb.event.Event.__init__(self, d)
|
bb.event.Event.__init__(self, d)
|
||||||
|
|
||||||
|
|
||||||
|
class CookerParser:
|
||||||
|
def __init__(self, cooker, filelist, masked):
|
||||||
|
# Internal data
|
||||||
|
self.filelist = filelist
|
||||||
|
self.cooker = cooker
|
||||||
|
|
||||||
|
# Accounting statistics
|
||||||
|
self.parsed = 0
|
||||||
|
self.cached = 0
|
||||||
|
self.skipped = 0
|
||||||
|
self.error = 0
|
||||||
|
self.masked = masked
|
||||||
|
self.total = len(filelist)
|
||||||
|
|
||||||
|
# Pointer to the next file to parse
|
||||||
|
self.pointer = 0
|
||||||
|
|
||||||
|
def parse_next(self):
|
||||||
|
print "Pointer %d" % self.pointer
|
||||||
|
f = self.filelist[self.pointer]
|
||||||
|
cooker = self.cooker
|
||||||
|
|
||||||
|
try:
|
||||||
|
fromCache, skip = cooker.bb_cache.loadData(f, cooker.configuration.data, cooker.status)
|
||||||
|
if skip:
|
||||||
|
self.skipped += 1
|
||||||
|
bb.msg.debug(2, bb.msg.domain.Collection, "skipping %s" % f)
|
||||||
|
cooker.bb_cache.skip(f)
|
||||||
|
elif fromCache: self.cached += 1
|
||||||
|
else: self.parsed += 1
|
||||||
|
|
||||||
|
except IOError, e:
|
||||||
|
self.error += 1
|
||||||
|
cooker.bb_cache.remove(f)
|
||||||
|
bb.msg.error(bb.msg.domain.Collection, "opening %s: %s" % (f, e))
|
||||||
|
pass
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
cooker.bb_cache.remove(f)
|
||||||
|
cooker.bb_cache.sync()
|
||||||
|
raise
|
||||||
|
except Exception, e:
|
||||||
|
self.error += 1
|
||||||
|
cooker.bb_cache.remove(f)
|
||||||
|
bb.msg.error(bb.msg.domain.Collection, "%s while parsing %s" % (e, f))
|
||||||
|
except:
|
||||||
|
cooker.bb_cache.remove(f)
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
bb.event.fire(bb.event.ParseProgress(cooker.configuration.event_data, self.cached, self.parsed, self.skipped, self.masked, self.error, self.total))
|
||||||
|
|
||||||
|
self.pointer += 1
|
||||||
|
|
||||||
|
if self.pointer >= self.total:
|
||||||
|
cooker.bb_cache.sync()
|
||||||
|
if self.error > 0:
|
||||||
|
raise ParsingErrorsFound
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue