bitbake: Update to bitbake 1.8 branch head

git-svn-id: https://svn.o-hand.com/repos/poky/trunk@3892 311d38ba-8fff-0310-9ca6-ca027cbcb966
This commit is contained in:
Richard Purdie 2008-03-03 22:01:45 +00:00
parent e88b475378
commit ab191d21e2
13 changed files with 357 additions and 468 deletions

View File

@ -1,6 +1,26 @@
Changes in BitBake 1.8.x: Changes in BitBake 1.8.x:
- Fix exit code for build failures in --continue mode - Fix exit code for build failures in --continue mode
- Fix git branch tags fetching - Fix git branch tags fetching
- Change parseConfigurationFile so it works on real data, not a copy
- Handle 'base' inherit and all other INHERITs from parseConfigurationFile
instead of BBHandler
- Fix getVarFlags bug in data_smart
- Optmise cache handling by more quickly detecting an invalid cache, only
saving the cache when its changed, moving the cache validity check into
the parsing loop and factoring some getVar calls outside a for loop
- Cooker: Remove a debug message from the parsing loop to lower overhead
- Convert build.py exec_task to use getVarFlags
- Update shell to use cooker.buildFile
- Add StampUpdate event
- Convert -b option to use taskdata/runqueue
- Remove digraph and switch to new stamp checking code. exec_task no longer
honours dependencies
- Make fetcher timestamp updating non-fatal when permissions don't allow
updates
- Add BB_SCHEDULER variable/option ("completion" or "speed") controlling
the way bitbake schedules tasks
- Add BB_STAMP_POLICY variable/option ("perfile" or "full") controlling
how extensively stamps are looked at for validity
Changes in BitBake 1.8.10: Changes in BitBake 1.8.10:
- Psyco is available only for x86 - do not use it on other architectures. - Psyco is available only for x86 - do not use it on other architectures.

View File

@ -46,7 +46,6 @@ __all__ = [
"pkgcmp", "pkgcmp",
"dep_parenreduce", "dep_parenreduce",
"dep_opconvert", "dep_opconvert",
"digraph",
# fetch # fetch
"decodeurl", "decodeurl",
@ -1128,184 +1127,6 @@ def dep_opconvert(mysplit, myuse):
mypos += 1 mypos += 1
return newsplit return newsplit
class digraph:
"""beautiful directed graph object"""
def __init__(self):
self.dict={}
#okeys = keys, in order they were added (to optimize firstzero() ordering)
self.okeys=[]
self.__callback_cache=[]
def __str__(self):
str = ""
for key in self.okeys:
str += "%s:\t%s\n" % (key, self.dict[key][1])
return str
def addnode(self,mykey,myparent):
if not mykey in self.dict:
self.okeys.append(mykey)
if myparent==None:
self.dict[mykey]=[0,[]]
else:
self.dict[mykey]=[0,[myparent]]
self.dict[myparent][0]=self.dict[myparent][0]+1
return
if myparent and (not myparent in self.dict[mykey][1]):
self.dict[mykey][1].append(myparent)
self.dict[myparent][0]=self.dict[myparent][0]+1
def delnode(self,mykey, ref = 1):
"""Delete a node
If ref is 1, remove references to this node from other nodes.
If ref is 2, remove nodes that reference this node."""
if not mykey in self.dict:
return
for x in self.dict[mykey][1]:
self.dict[x][0]=self.dict[x][0]-1
del self.dict[mykey]
while 1:
try:
self.okeys.remove(mykey)
except ValueError:
break
if ref:
__kill = []
for k in self.okeys:
if mykey in self.dict[k][1]:
if ref == 1 or ref == 2:
self.dict[k][1].remove(mykey)
if ref == 2:
__kill.append(k)
for l in __kill:
self.delnode(l, ref)
def allnodes(self):
"returns all nodes in the dictionary"
keys = self.dict.keys()
ret = []
for key in keys:
ret.append(key)
ret.sort()
return ret
def firstzero(self):
"returns first node with zero references, or NULL if no such node exists"
for x in self.okeys:
if self.dict[x][0]==0:
return x
return None
def firstnonzero(self):
"returns first node with nonzero references, or NULL if no such node exists"
for x in self.okeys:
if self.dict[x][0]!=0:
return x
return None
def allzeros(self):
"returns all nodes with zero references, or NULL if no such node exists"
zerolist = []
for x in self.dict.keys():
if self.dict[x][0]==0:
zerolist.append(x)
return zerolist
def hasallzeros(self):
"returns 0/1, Are all nodes zeros? 1 : 0"
zerolist = []
for x in self.dict.keys():
if self.dict[x][0]!=0:
return 0
return 1
def empty(self):
if len(self.dict)==0:
return 1
return 0
def hasnode(self,mynode):
return mynode in self.dict
def getparents(self, item):
if not self.hasnode(item):
return []
parents = self.dict[item][1]
ret = []
for parent in parents:
ret.append(parent)
ret.sort()
return ret
def getchildren(self, item):
if not self.hasnode(item):
return []
children = [i for i in self.okeys if item in self.getparents(i)]
return children
def walkdown(self, item, callback, debug = None, usecache = False):
if not self.hasnode(item):
return 0
if usecache:
if self.__callback_cache.count(item):
if debug:
print "hit cache for item: %s" % item
return 1
parents = self.getparents(item)
children = self.getchildren(item)
for p in parents:
if p in children:
# print "%s is both parent and child of %s" % (p, item)
if usecache:
self.__callback_cache.append(p)
ret = callback(self, p)
if ret == 0:
return 0
continue
if item == p:
print "eek, i'm my own parent!"
return 0
if debug:
print "item: %s, p: %s" % (item, p)
ret = self.walkdown(p, callback, debug, usecache)
if ret == 0:
return 0
if usecache:
self.__callback_cache.append(item)
return callback(self, item)
def walkup(self, item, callback):
if not self.hasnode(item):
return 0
parents = self.getparents(item)
children = self.getchildren(item)
for c in children:
if c in parents:
ret = callback(self, item)
if ret == 0:
return 0
continue
if item == c:
print "eek, i'm my own child!"
return 0
ret = self.walkup(c, callback)
if ret == 0:
return 0
return callback(self, item)
def copy(self):
mygraph=digraph()
for x in self.dict.keys():
mygraph.dict[x]=self.dict[x][:]
mygraph.okeys=self.okeys[:]
return mygraph
if __name__ == "__main__": if __name__ == "__main__":
import doctest, bb import doctest, bb
doctest.testmod(bb) doctest.testmod(bb)

View File

@ -74,12 +74,21 @@ def exec_func(func, d, dirs = None):
if not body: if not body:
return return
cleandirs = (data.expand(data.getVarFlag(func, 'cleandirs', d), d) or "").split() flags = data.getVarFlags(func, d)
for item in ['deps', 'check', 'interactive', 'python', 'cleandirs', 'dirs', 'lockfiles', 'fakeroot']:
if not item in flags:
flags[item] = None
ispython = flags['python']
cleandirs = (data.expand(flags['cleandirs'], d) or "").split()
for cdir in cleandirs: for cdir in cleandirs:
os.system("rm -rf %s" % cdir) os.system("rm -rf %s" % cdir)
if not dirs: if dirs:
dirs = (data.expand(data.getVarFlag(func, 'dirs', d), d) or "").split() dirs = data.expand(dirs, d)
else:
dirs = (data.expand(flags['dirs'], d) or "").split()
for adir in dirs: for adir in dirs:
mkdirhier(adir) mkdirhier(adir)
@ -88,24 +97,22 @@ def exec_func(func, d, dirs = None):
else: else:
adir = data.getVar('B', d, 1) adir = data.getVar('B', d, 1)
adir = data.expand(adir, d)
try: try:
prevdir = os.getcwd() prevdir = os.getcwd()
except OSError: except OSError:
prevdir = data.expand('${TOPDIR}', d) prevdir = data.getVar('TOPDIR', d, True)
if adir and os.access(adir, os.F_OK): if adir and os.access(adir, os.F_OK):
os.chdir(adir) os.chdir(adir)
locks = [] locks = []
lockfiles = (data.expand(data.getVarFlag(func, 'lockfiles', d), d) or "").split() lockfiles = (data.expand(flags['lockfiles'], d) or "").split()
for lock in lockfiles: for lock in lockfiles:
locks.append(bb.utils.lockfile(lock)) locks.append(bb.utils.lockfile(lock))
if data.getVarFlag(func, "python", d): if flags['python']:
exec_func_python(func, d) exec_func_python(func, d)
else: else:
exec_func_shell(func, d) exec_func_shell(func, d, flags)
for lock in locks: for lock in locks:
bb.utils.unlockfile(lock) bb.utils.unlockfile(lock)
@ -117,19 +124,20 @@ def exec_func_python(func, d):
"""Execute a python BB 'function'""" """Execute a python BB 'function'"""
import re, os import re, os
bbfile = bb.data.getVar('FILE', d, 1)
tmp = "def " + func + "():\n%s" % data.getVar(func, d) tmp = "def " + func + "():\n%s" % data.getVar(func, d)
tmp += '\n' + func + '()' tmp += '\n' + func + '()'
comp = utils.better_compile(tmp, func, bb.data.getVar('FILE', d, 1) ) comp = utils.better_compile(tmp, func, bbfile)
prevdir = os.getcwd() prevdir = os.getcwd()
g = {} # globals g = {} # globals
g['bb'] = bb g['bb'] = bb
g['os'] = os g['os'] = os
g['d'] = d g['d'] = d
utils.better_exec(comp,g,tmp, bb.data.getVar('FILE',d,1)) utils.better_exec(comp, g, tmp, bbfile)
if os.path.exists(prevdir): if os.path.exists(prevdir):
os.chdir(prevdir) os.chdir(prevdir)
def exec_func_shell(func, d): def exec_func_shell(func, d, flags):
"""Execute a shell BB 'function' Returns true if execution was successful. """Execute a shell BB 'function' Returns true if execution was successful.
For this, it creates a bash shell script in the tmp dectory, writes the local For this, it creates a bash shell script in the tmp dectory, writes the local
@ -141,9 +149,9 @@ def exec_func_shell(func, d):
""" """
import sys import sys
deps = data.getVarFlag(func, 'deps', d) deps = flags['deps']
check = data.getVarFlag(func, 'check', d) check = flags['check']
interact = data.getVarFlag(func, 'interactive', d) interact = flags['interactive']
if check in globals(): if check in globals():
if globals()[check](func, deps): if globals()[check](func, deps):
return return
@ -195,7 +203,7 @@ def exec_func_shell(func, d):
# execute function # execute function
prevdir = os.getcwd() prevdir = os.getcwd()
if data.getVarFlag(func, "fakeroot", d): if flags['fakeroot']:
maybe_fakeroot = "PATH=\"%s\" fakeroot " % bb.data.getVar("PATH", d, 1) maybe_fakeroot = "PATH=\"%s\" fakeroot " % bb.data.getVar("PATH", d, 1)
else: else:
maybe_fakeroot = '' maybe_fakeroot = ''
@ -255,72 +263,29 @@ def exec_task(task, d):
a function is that a task exists in the task digraph, and therefore a function is that a task exists in the task digraph, and therefore
has dependencies amongst other tasks.""" has dependencies amongst other tasks."""
# check if the task is in the graph.. # Check whther this is a valid task
task_graph = data.getVar('_task_graph', d) if not data.getVarFlag(task, 'task', d):
if not task_graph: raise EventException("No such task", InvalidTask(task, d))
task_graph = bb.digraph()
data.setVar('_task_graph', task_graph, d)
task_cache = data.getVar('_task_cache', d)
if not task_cache:
task_cache = []
data.setVar('_task_cache', task_cache, d)
if not task_graph.hasnode(task):
raise EventException("Missing node in task graph", InvalidTask(task, d))
# check whether this task needs executing.. try:
if stamp_is_current(task, d): bb.msg.debug(1, bb.msg.domain.Build, "Executing task %s" % task)
return 1 old_overrides = data.getVar('OVERRIDES', d, 0)
localdata = data.createCopy(d)
# follow digraph path up, then execute our way back down data.setVar('OVERRIDES', 'task_%s:%s' % (task, old_overrides), localdata)
def execute(graph, item): data.update_data(localdata)
if data.getVarFlag(item, 'task', d): event.fire(TaskStarted(task, localdata))
if item in task_cache: exec_func(task, localdata)
return 1 event.fire(TaskSucceeded(task, localdata))
except FuncFailed, reason:
if task != item: bb.msg.note(1, bb.msg.domain.Build, "Task failed: %s" % reason )
# deeper than toplevel, exec w/ deps failedevent = TaskFailed(task, d)
exec_task(item, d) event.fire(failedevent)
return 1 raise EventException("Function failed in task: %s" % reason, failedevent)
try:
bb.msg.debug(1, bb.msg.domain.Build, "Executing task %s" % item)
old_overrides = data.getVar('OVERRIDES', d, 0)
localdata = data.createCopy(d)
data.setVar('OVERRIDES', 'task_%s:%s' % (item, old_overrides), localdata)
data.update_data(localdata)
event.fire(TaskStarted(item, localdata))
exec_func(item, localdata)
event.fire(TaskSucceeded(item, localdata))
task_cache.append(item)
data.setVar('_task_cache', task_cache, d)
except FuncFailed, reason:
bb.msg.note(1, bb.msg.domain.Build, "Task failed: %s" % reason )
failedevent = TaskFailed(item, d)
event.fire(failedevent)
raise EventException("Function failed in task: %s" % reason, failedevent)
if data.getVarFlag(task, 'dontrundeps', d):
execute(None, task)
else:
task_graph.walkdown(task, execute)
# make stamp, or cause event and raise exception # make stamp, or cause event and raise exception
if not data.getVarFlag(task, 'nostamp', d) and not data.getVarFlag(task, 'selfstamp', d): if not data.getVarFlag(task, 'nostamp', d) and not data.getVarFlag(task, 'selfstamp', d):
make_stamp(task, d) make_stamp(task, d)
def extract_stamp_data(d, fn):
"""
Extracts stamp data from d which is either a data dictonary (fn unset)
or a dataCache entry (fn set).
"""
if fn:
return (d.task_queues[fn], d.stamp[fn], d.task_deps[fn])
task_graph = data.getVar('_task_graph', d)
if not task_graph:
task_graph = bb.digraph()
data.setVar('_task_graph', task_graph, d)
return (task_graph, data.getVar('STAMP', d, 1), None)
def extract_stamp(d, fn): def extract_stamp(d, fn):
""" """
Extracts stamp format which is either a data dictonary (fn unset) Extracts stamp format which is either a data dictonary (fn unset)
@ -330,49 +295,6 @@ def extract_stamp(d, fn):
return d.stamp[fn] return d.stamp[fn]
return data.getVar('STAMP', d, 1) return data.getVar('STAMP', d, 1)
def stamp_is_current(task, d, file_name = None, checkdeps = 1):
"""
Check status of a given task's stamp.
Returns 0 if it is not current and needs updating.
(d can be a data dict or dataCache)
"""
(task_graph, stampfn, taskdep) = extract_stamp_data(d, file_name)
if not stampfn:
return 0
stampfile = "%s.%s" % (stampfn, task)
if not os.access(stampfile, os.F_OK):
return 0
if checkdeps == 0:
return 1
import stat
tasktime = os.stat(stampfile)[stat.ST_MTIME]
_deps = []
def checkStamp(graph, task):
# check for existance
if file_name:
if 'nostamp' in taskdep and task in taskdep['nostamp']:
return 1
else:
if data.getVarFlag(task, 'nostamp', d):
return 1
if not stamp_is_current(task, d, file_name, 0 ):
return 0
depfile = "%s.%s" % (stampfn, task)
deptime = os.stat(depfile)[stat.ST_MTIME]
if deptime > tasktime:
return 0
return 1
return task_graph.walkdown(task, checkStamp)
def stamp_internal(task, d, file_name): def stamp_internal(task, d, file_name):
""" """
Internal stamp helper function Internal stamp helper function
@ -409,40 +331,39 @@ def del_stamp(task, d, file_name = None):
stamp_internal(task, d, file_name) stamp_internal(task, d, file_name)
def add_tasks(tasklist, d): def add_tasks(tasklist, d):
task_graph = data.getVar('_task_graph', d)
task_deps = data.getVar('_task_deps', d) task_deps = data.getVar('_task_deps', d)
if not task_graph:
task_graph = bb.digraph()
if not task_deps: if not task_deps:
task_deps = {} task_deps = {}
if not 'tasks' in task_deps:
task_deps['tasks'] = []
if not 'parents' in task_deps:
task_deps['parents'] = {}
for task in tasklist: for task in tasklist:
deps = tasklist[task]
task = data.expand(task, d) task = data.expand(task, d)
data.setVarFlag(task, 'task', 1, d) data.setVarFlag(task, 'task', 1, d)
task_graph.addnode(task, None)
for dep in deps: if not task in task_deps['tasks']:
dep = data.expand(dep, d) task_deps['tasks'].append(task)
if not task_graph.hasnode(dep):
task_graph.addnode(dep, None)
task_graph.addnode(task, dep)
flags = data.getVarFlags(task, d) flags = data.getVarFlags(task, d)
def getTask(name): def getTask(name):
if not name in task_deps:
task_deps[name] = {}
if name in flags: if name in flags:
deptask = data.expand(flags[name], d) deptask = data.expand(flags[name], d)
if not name in task_deps:
task_deps[name] = {}
task_deps[name][task] = deptask task_deps[name][task] = deptask
getTask('depends') getTask('depends')
getTask('deptask') getTask('deptask')
getTask('rdeptask') getTask('rdeptask')
getTask('recrdeptask') getTask('recrdeptask')
getTask('nostamp') getTask('nostamp')
task_deps['parents'][task] = []
for dep in flags['deps']:
dep = data.expand(dep, d)
task_deps['parents'][task].append(dep)
# don't assume holding a reference # don't assume holding a reference
data.setVar('_task_graph', task_graph, d)
data.setVar('_task_deps', task_deps, d) data.setVar('_task_deps', task_deps, d)
def remove_task(task, kill, d): def remove_task(task, kill, d):
@ -450,22 +371,5 @@ def remove_task(task, kill, d):
If kill is 1, also remove tasks that depend on this task.""" If kill is 1, also remove tasks that depend on this task."""
task_graph = data.getVar('_task_graph', d)
if not task_graph:
task_graph = bb.digraph()
if not task_graph.hasnode(task):
return
data.delVarFlag(task, 'task', d) data.delVarFlag(task, 'task', d)
ref = 1
if kill == 1:
ref = 2
task_graph.delnode(task, ref)
data.setVar('_task_graph', task_graph, d)
def task_exists(task, d):
task_graph = data.getVar('_task_graph', d)
if not task_graph:
task_graph = bb.digraph()
data.setVar('_task_graph', task_graph, d)
return task_graph.hasnode(task)

View File

@ -39,7 +39,7 @@ except ImportError:
import pickle import pickle
bb.msg.note(1, bb.msg.domain.Cache, "Importing cPickle failed. Falling back to a very slow implementation.") bb.msg.note(1, bb.msg.domain.Cache, "Importing cPickle failed. Falling back to a very slow implementation.")
__cache_version__ = "127" __cache_version__ = "128"
class Cache: class Cache:
""" """
@ -50,9 +50,11 @@ class Cache:
self.cachedir = bb.data.getVar("CACHE", cooker.configuration.data, True) self.cachedir = bb.data.getVar("CACHE", cooker.configuration.data, True)
self.clean = {} self.clean = {}
self.checked = {}
self.depends_cache = {} self.depends_cache = {}
self.data = None self.data = None
self.data_fn = None self.data_fn = None
self.cacheclean = True
if self.cachedir in [None, '']: if self.cachedir in [None, '']:
self.has_cache = False self.has_cache = False
@ -67,9 +69,20 @@ class Cache:
except OSError: except OSError:
bb.mkdirhier( self.cachedir ) bb.mkdirhier( self.cachedir )
if self.has_cache and (self.mtime(self.cachefile)): if not self.has_cache:
return
# If any of configuration.data's dependencies are newer than the
# cache there isn't even any point in loading it...
newest_mtime = 0
deps = bb.data.getVar("__depends", cooker.configuration.data, True)
for f,old_mtime in deps:
if old_mtime > newest_mtime:
newest_mtime = old_mtime
if self.mtime(self.cachefile) >= newest_mtime:
try: try:
p = pickle.Unpickler( file(self.cachefile,"rb")) p = pickle.Unpickler(file(self.cachefile, "rb"))
self.depends_cache, version_data = p.load() self.depends_cache, version_data = p.load()
if version_data['CACHE_VER'] != __cache_version__: if version_data['CACHE_VER'] != __cache_version__:
raise ValueError, 'Cache Version Mismatch' raise ValueError, 'Cache Version Mismatch'
@ -81,11 +94,8 @@ class Cache:
except (ValueError, KeyError): except (ValueError, KeyError):
bb.msg.note(1, bb.msg.domain.Cache, "Invalid cache found, rebuilding...") bb.msg.note(1, bb.msg.domain.Cache, "Invalid cache found, rebuilding...")
self.depends_cache = {} self.depends_cache = {}
else:
if self.depends_cache: bb.msg.note(1, bb.msg.domain.Cache, "Out of date cache found, rebuilding...")
for fn in self.depends_cache.keys():
self.clean[fn] = ""
self.cacheValidUpdate(fn)
def getVar(self, var, fn, exp = 0): def getVar(self, var, fn, exp = 0):
""" """
@ -97,7 +107,6 @@ class Cache:
2. We're learning what data to cache - serve from data 2. We're learning what data to cache - serve from data
backend but add a copy of the data to the cache. backend but add a copy of the data to the cache.
""" """
if fn in self.clean: if fn in self.clean:
return self.depends_cache[fn][var] return self.depends_cache[fn][var]
@ -109,6 +118,7 @@ class Cache:
# yet setData hasn't been called to setup the right access. Very bad. # yet setData hasn't been called to setup the right access. Very bad.
bb.msg.error(bb.msg.domain.Cache, "Parsing error data_fn %s and fn %s don't match" % (self.data_fn, fn)) bb.msg.error(bb.msg.domain.Cache, "Parsing error data_fn %s and fn %s don't match" % (self.data_fn, fn))
self.cacheclean = False
result = bb.data.getVar(var, self.data, exp) result = bb.data.getVar(var, self.data, exp)
self.depends_cache[fn][var] = result self.depends_cache[fn][var] = result
return result return result
@ -131,6 +141,8 @@ class Cache:
Return a complete set of data for fn. Return a complete set of data for fn.
To do this, we need to parse the file. To do this, we need to parse the file.
""" """
bb.msg.debug(1, bb.msg.domain.Cache, "Parsing %s (full)" % fn)
bb_data, skipped = self.load_bbfile(fn, cfgData) bb_data, skipped = self.load_bbfile(fn, cfgData)
return bb_data return bb_data
@ -142,11 +154,15 @@ class Cache:
to record the variables accessed. to record the variables accessed.
Return the cache status and whether the file was skipped when parsed Return the cache status and whether the file was skipped when parsed
""" """
if fn not in self.checked:
self.cacheValidUpdate(fn)
if self.cacheValid(fn): if self.cacheValid(fn):
if "SKIPPED" in self.depends_cache[fn]: if "SKIPPED" in self.depends_cache[fn]:
return True, True return True, True
return True, False return True, False
bb.msg.debug(1, bb.msg.domain.Cache, "Parsing %s" % fn)
bb_data, skipped = self.load_bbfile(fn, cfgData) bb_data, skipped = self.load_bbfile(fn, cfgData)
self.setData(fn, bb_data) self.setData(fn, bb_data)
return False, skipped return False, skipped
@ -172,11 +188,10 @@ class Cache:
if not self.has_cache: if not self.has_cache:
return False return False
# Check file still exists self.checked[fn] = ""
if self.mtime(fn) == 0:
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s not longer exists" % fn) # Pretend we're clean so getVar works
self.remove(fn) self.clean[fn] = ""
return False
# File isn't in depends_cache # File isn't in depends_cache
if not fn in self.depends_cache: if not fn in self.depends_cache:
@ -184,6 +199,12 @@ class Cache:
self.remove(fn) self.remove(fn)
return False return False
# Check file still exists
if self.mtime(fn) == 0:
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s not longer exists" % fn)
self.remove(fn)
return False
# Check the file's timestamp # Check the file's timestamp
if bb.parse.cached_mtime(fn) > self.getVar("CACHETIMESTAMP", fn, True): if bb.parse.cached_mtime(fn) > self.getVar("CACHETIMESTAMP", fn, True):
bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s changed" % fn) bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s changed" % fn)
@ -195,6 +216,7 @@ class Cache:
for f,old_mtime in depends: for f,old_mtime in depends:
# Check if file still exists # Check if file still exists
if self.mtime(f) == 0: if self.mtime(f) == 0:
self.remove(fn)
return False return False
new_mtime = bb.parse.cached_mtime(f) new_mtime = bb.parse.cached_mtime(f)
@ -203,7 +225,7 @@ class Cache:
self.remove(fn) self.remove(fn)
return False return False
bb.msg.debug(2, bb.msg.domain.Cache, "Depends Cache: %s is clean" % fn) #bb.msg.debug(2, bb.msg.domain.Cache, "Depends Cache: %s is clean" % fn)
if not fn in self.clean: if not fn in self.clean:
self.clean[fn] = "" self.clean[fn] = ""
@ -238,6 +260,10 @@ class Cache:
if not self.has_cache: if not self.has_cache:
return return
if self.cacheclean:
bb.msg.note(1, bb.msg.domain.Cache, "Cache is clean, not saving.")
return
version_data = {} version_data = {}
version_data['CACHE_VER'] = __cache_version__ version_data['CACHE_VER'] = __cache_version__
version_data['BITBAKE_VER'] = bb.__version__ version_data['BITBAKE_VER'] = bb.__version__
@ -264,7 +290,6 @@ class Cache:
packages_dynamic = (self.getVar('PACKAGES_DYNAMIC', file_name, True) or "").split() packages_dynamic = (self.getVar('PACKAGES_DYNAMIC', file_name, True) or "").split()
rprovides = (self.getVar("RPROVIDES", file_name, True) or "").split() rprovides = (self.getVar("RPROVIDES", file_name, True) or "").split()
cacheData.task_queues[file_name] = self.getVar("_task_graph", file_name, True)
cacheData.task_deps[file_name] = self.getVar("_task_deps", file_name, True) cacheData.task_deps[file_name] = self.getVar("_task_deps", file_name, True)
# build PackageName to FileName lookup table # build PackageName to FileName lookup table
@ -328,14 +353,16 @@ class Cache:
if not file_name in cacheData.runrecs: if not file_name in cacheData.runrecs:
cacheData.runrecs[file_name] = {} cacheData.runrecs[file_name] = {}
rdepends = bb.utils.explode_deps(self.getVar('RDEPENDS', file_name, True) or "")
rrecommends = bb.utils.explode_deps(self.getVar('RRECOMMENDS', file_name, True) or "")
for package in packages + [pn]: for package in packages + [pn]:
if not package in cacheData.rundeps[file_name]: if not package in cacheData.rundeps[file_name]:
cacheData.rundeps[file_name][package] = {} cacheData.rundeps[file_name][package] = {}
if not package in cacheData.runrecs[file_name]: if not package in cacheData.runrecs[file_name]:
cacheData.runrecs[file_name][package] = {} cacheData.runrecs[file_name][package] = {}
add_dep(cacheData.rundeps[file_name][package], bb.utils.explode_deps(self.getVar('RDEPENDS', file_name, True) or "")) add_dep(cacheData.rundeps[file_name][package], rdepends)
add_dep(cacheData.runrecs[file_name][package], bb.utils.explode_deps(self.getVar('RRECOMMENDS', file_name, True) or "")) add_dep(cacheData.runrecs[file_name][package], rrecommends)
add_dep(cacheData.rundeps[file_name][package], bb.utils.explode_deps(self.getVar("RDEPENDS_%s" % package, file_name, True) or "")) add_dep(cacheData.rundeps[file_name][package], bb.utils.explode_deps(self.getVar("RDEPENDS_%s" % package, file_name, True) or ""))
add_dep(cacheData.runrecs[file_name][package], bb.utils.explode_deps(self.getVar("RRECOMMENDS_%s" % package, file_name, True) or "")) add_dep(cacheData.runrecs[file_name][package], bb.utils.explode_deps(self.getVar("RRECOMMENDS_%s" % package, file_name, True) or ""))

View File

@ -97,14 +97,12 @@ class BBCooker:
bb.msg.note(2, bb.msg.domain.Build, "Renice to %s " % os.nice(nice)) bb.msg.note(2, bb.msg.domain.Build, "Renice to %s " % os.nice(nice))
def tryBuildPackage(self, fn, item, task, the_data, build_depends): def tryBuildPackage(self, fn, item, task, the_data):
""" """
Build one task of a package, optionally build following task depends Build one task of a package, optionally build following task depends
""" """
bb.event.fire(bb.event.PkgStarted(item, the_data)) bb.event.fire(bb.event.PkgStarted(item, the_data))
try: try:
if not build_depends:
bb.data.setVarFlag('do_%s' % task, 'dontrundeps', 1, the_data)
if not self.configuration.dry_run: if not self.configuration.dry_run:
bb.build.exec_task('do_%s' % task, the_data) bb.build.exec_task('do_%s' % task, the_data)
bb.event.fire(bb.event.PkgSucceeded(item, the_data)) bb.event.fire(bb.event.PkgSucceeded(item, the_data))
@ -119,21 +117,20 @@ class BBCooker:
bb.event.fire(bb.event.PkgFailed(item, the_data)) bb.event.fire(bb.event.PkgFailed(item, the_data))
raise raise
def tryBuild( self, fn, build_depends): def tryBuild(self, fn):
""" """
Build a provider and its dependencies. Build a provider and its dependencies.
build_depends is a list of previous build dependencies (not runtime) build_depends is a list of previous build dependencies (not runtime)
If build_depends is empty, we're dealing with a runtime depends If build_depends is empty, we're dealing with a runtime depends
""" """
the_data = self.bb_cache.loadDataFull(fn, self.configuration.data) the_data = self.bb_cache.loadDataFull(fn, self.configuration.data)
item = self.status.pkg_fn[fn] item = self.status.pkg_fn[fn]
if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data): #if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data):
return True # return True
return self.tryBuildPackage(fn, item, self.configuration.cmd, the_data, build_depends) return self.tryBuildPackage(fn, item, self.configuration.cmd, the_data)
def showVersions(self): def showVersions(self):
pkg_pn = self.status.pkg_pn pkg_pn = self.status.pkg_pn
@ -184,6 +181,8 @@ class BBCooker:
self.cb = None self.cb = None
self.bb_cache = bb.cache.init(self) self.bb_cache = bb.cache.init(self)
fn = self.matchFile(buildfile) fn = self.matchFile(buildfile)
if not fn:
sys.exit(1)
elif len(pkgs_to_build) == 1: elif len(pkgs_to_build) == 1:
self.updateCache() self.updateCache()
@ -220,7 +219,7 @@ class BBCooker:
except Exception, e: except Exception, e:
bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e) bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e)
# emit the metadata which isnt valid shell # emit the metadata which isnt valid shell
data.expandKeys( envdata ) data.expandKeys( envdata )
for e in envdata.keys(): for e in envdata.keys():
if data.getVarFlag( e, 'python', envdata ): if data.getVarFlag( e, 'python', envdata ):
sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, envdata, 1))) sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, envdata, 1)))
@ -273,7 +272,7 @@ class BBCooker:
if fnid not in seen_fnids: if fnid not in seen_fnids:
seen_fnids.append(fnid) seen_fnids.append(fnid)
packages = [] packages = []
print >> depends_file, '"%s" [label="%s %s\\n%s"]' % (pn, pn, version, fn) print >> depends_file, '"%s" [label="%s %s\\n%s"]' % (pn, pn, version, fn)
for depend in self.status.deps[fn]: for depend in self.status.deps[fn]:
print >> depends_file, '"%s" -> "%s"' % (pn, depend) print >> depends_file, '"%s" -> "%s"' % (pn, depend)
rdepends = self.status.rundeps[fn] rdepends = self.status.rundeps[fn]
@ -387,19 +386,15 @@ class BBCooker:
try: try:
self.configuration.data = bb.parse.handle( afile, self.configuration.data ) self.configuration.data = bb.parse.handle( afile, self.configuration.data )
# Add the handlers we inherited by INHERIT # Handle any INHERITs and inherit the base class
# we need to do this manually as it is not guranteed inherits = ["base"] + (bb.data.getVar('INHERIT', self.configuration.data, True ) or "").split()
# we will pick up these classes... as we only INHERIT
# on .inc and .bb files but not on .conf
data = bb.data.createCopy( self.configuration.data )
inherits = ["base"] + (bb.data.getVar('INHERIT', data, True ) or "").split()
for inherit in inherits: for inherit in inherits:
data = bb.parse.handle( os.path.join('classes', '%s.bbclass' % inherit ), data, True ) self.configuration.data = bb.parse.handle(os.path.join('classes', '%s.bbclass' % inherit), self.configuration.data, True )
# FIXME: This assumes that we included at least one .inc file # Nomally we only register event handlers at the end of parsing .bb files
for var in bb.data.keys(data): # We register any handlers we've found so far here...
if bb.data.getVarFlag(var, 'handler', data): for var in data.getVar('__BBHANDLERS', self.configuration.data) or []:
bb.event.register(var,bb.data.getVar(var, data)) bb.event.register(var,bb.data.getVar(var, self.configuration.data))
bb.fetch.fetcher_init(self.configuration.data) bb.fetch.fetcher_init(self.configuration.data)
@ -463,30 +458,62 @@ class BBCooker:
bb.msg.error(bb.msg.domain.Parsing, "Unable to match %s (%s matches found):" % (buildfile, len(matches))) bb.msg.error(bb.msg.domain.Parsing, "Unable to match %s (%s matches found):" % (buildfile, len(matches)))
for f in matches: for f in matches:
bb.msg.error(bb.msg.domain.Parsing, " %s" % f) bb.msg.error(bb.msg.domain.Parsing, " %s" % f)
sys.exit(1) return False
return matches[0] return matches[0]
def buildFile(self, buildfile): def buildFile(self, buildfile):
""" """
Build the file matching regexp buildfile Build the file matching regexp buildfile
""" """
bf = self.matchFile(buildfile) # Make sure our target is a fully qualified filename
fn = self.matchFile(buildfile)
if not fn:
return False
bbfile_data = bb.parse.handle(bf, self.configuration.data) # Load data into the cache for fn
self.bb_cache = bb.cache.init(self)
self.bb_cache.loadData(fn, self.configuration.data)
# Parse the loaded cache data
self.status = bb.cache.CacheData()
self.bb_cache.handle_data(fn, self.status)
# Tweak some variables
item = self.bb_cache.getVar('PN', fn, True)
self.status.ignored_dependencies = Set()
self.status.bbfile_priority[fn] = 1
# Remove external dependencies
self.status.task_deps[fn]['depends'] = {}
self.status.deps[fn] = []
self.status.rundeps[fn] = []
self.status.runrecs[fn] = []
# Remove stamp for target if force mode active # Remove stamp for target if force mode active
if self.configuration.force: if self.configuration.force:
bb.msg.note(2, bb.msg.domain.RunQueue, "Remove stamp %s, %s" % (self.configuration.cmd, bf)) bb.msg.note(2, bb.msg.domain.RunQueue, "Remove stamp %s, %s" % (self.configuration.cmd, fn))
bb.build.del_stamp('do_%s' % self.configuration.cmd, bbfile_data) bb.build.del_stamp('do_%s' % self.configuration.cmd, bbfile_data)
item = bb.data.getVar('PN', bbfile_data, 1) # Setup taskdata structure
try: taskdata = bb.taskdata.TaskData(self.configuration.abort)
self.tryBuildPackage(bf, item, self.configuration.cmd, bbfile_data, True) taskdata.add_provider(self.configuration.data, self.status, item)
except bb.build.EventException:
bb.msg.error(bb.msg.domain.Build, "Build of '%s' failed" % item )
sys.exit(0) buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
bb.event.fire(bb.event.BuildStarted(buildname, [item], self.configuration.event_data))
# Execute the runqueue
runlist = [[item, "do_%s" % self.configuration.cmd]]
rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist)
rq.prepare_runqueue()
try:
failures = rq.execute_runqueue()
except runqueue.TaskFailure, fnids:
for fnid in fnids:
bb.msg.error(bb.msg.domain.Build, "'%s' failed" % taskdata.fn_index[fnid])
return False
bb.event.fire(bb.event.BuildCompleted(buildname, [item], self.configuration.event_data, failures))
return True
def buildTargets(self, targets): def buildTargets(self, targets):
""" """
@ -568,7 +595,9 @@ class BBCooker:
self.interactiveMode() self.interactiveMode()
if self.configuration.buildfile is not None: if self.configuration.buildfile is not None:
return self.buildFile(self.configuration.buildfile) if not self.buildFile(self.configuration.buildfile):
sys.exit(1)
sys.exit(0)
# initialise the parsing status now we know we will need deps # initialise the parsing status now we know we will need deps
self.updateCache() self.updateCache()
@ -676,7 +705,7 @@ class BBCooker:
for i in xrange( len( filelist ) ): for i in xrange( len( filelist ) ):
f = filelist[i] f = filelist[i]
bb.msg.debug(1, bb.msg.domain.Collection, "parsing %s" % f) #bb.msg.debug(1, bb.msg.domain.Collection, "parsing %s" % f)
# read a file's metadata # read a file's metadata
try: try:

View File

@ -232,10 +232,10 @@ class DataSmart:
flags = {} flags = {}
if local_var: if local_var:
for i in self.dict[var].keys(): for i in local_var.keys():
if i == "content": if i == "content":
continue continue
flags[i] = self.dict[var][i] flags[i] = local_var[i]
if len(flags) == 0: if len(flags) == 0:
return None return None

View File

@ -127,6 +127,23 @@ def getName(e):
class ConfigParsed(Event): class ConfigParsed(Event):
"""Configuration Parsing Complete""" """Configuration Parsing Complete"""
class StampUpdate(Event):
"""Trigger for any adjustment of the stamp files to happen"""
def __init__(self, targets, stampfns, d):
self._targets = targets
self._stampfns = stampfns
Event.__init__(self, d)
def getStampPrefix(self):
return self._stampfns
def getTargets(self):
return self._targets
stampPrefix = property(getStampPrefix)
targets = property(getTargets)
class PkgBase(Event): class PkgBase(Event):
"""Base class for package events""" """Base class for package events"""

View File

@ -139,13 +139,21 @@ def go(d):
if not m.forcefetch(u, ud, d) and os.path.exists(ud.md5): if not m.forcefetch(u, ud, d) and os.path.exists(ud.md5):
# File already present along with md5 stamp file # File already present along with md5 stamp file
# Touch md5 file to show activity # Touch md5 file to show activity
os.utime(ud.md5, None) try:
os.utime(ud.md5, None)
except:
# Errors aren't fatal here
pass
continue continue
lf = bb.utils.lockfile(ud.lockfile) lf = bb.utils.lockfile(ud.lockfile)
if not m.forcefetch(u, ud, d) and os.path.exists(ud.md5): if not m.forcefetch(u, ud, d) and os.path.exists(ud.md5):
# If someone else fetched this before we got the lock, # If someone else fetched this before we got the lock,
# notice and don't try again # notice and don't try again
os.utime(ud.md5, None) try:
os.utime(ud.md5, None)
except:
# Errors aren't fatal here
pass
bb.utils.unlockfile(lf) bb.utils.unlockfile(lf)
continue continue
m.go(u, ud, d) m.go(u, ud, d)

View File

@ -95,6 +95,10 @@ def handle(fn, d, include = 0):
if ext == ".bbclass": if ext == ".bbclass":
__classname__ = root __classname__ = root
classes.append(__classname__) classes.append(__classname__)
__inherit_cache = data.getVar('__inherit_cache', d) or []
if not fn in __inherit_cache:
__inherit_cache.append(fn)
data.setVar('__inherit_cache', __inherit_cache, d)
if include != 0: if include != 0:
oldfile = data.getVar('FILE', d) oldfile = data.getVar('FILE', d)
@ -126,10 +130,6 @@ def handle(fn, d, include = 0):
if ext != ".bbclass": if ext != ".bbclass":
data.setVar('FILE', fn, d) data.setVar('FILE', fn, d)
i = (data.getVar("INHERIT", d, 1) or "").split()
if not "base" in i and __classname__ != "base":
i[0:0] = ["base"]
inherit(i, d)
lineno = 0 lineno = 0
while 1: while 1:
@ -171,33 +171,12 @@ def handle(fn, d, include = 0):
all_handlers = {} all_handlers = {}
for var in data.getVar('__BBHANDLERS', d) or []: for var in data.getVar('__BBHANDLERS', d) or []:
# try to add the handler # try to add the handler
# if we added it remember the choiche
handler = data.getVar(var,d) handler = data.getVar(var,d)
if bb.event.register(var,handler) == bb.event.Registered: bb.event.register(var, handler)
all_handlers[var] = handler
tasklist = {}
for var in data.getVar('__BBTASKS', d) or []:
if var not in tasklist:
tasklist[var] = []
deps = data.getVarFlag(var, 'deps', d) or []
for p in deps:
if p not in tasklist[var]:
tasklist[var].append(p)
postdeps = data.getVarFlag(var, 'postdeps', d) or []
for p in postdeps:
if p not in tasklist:
tasklist[p] = []
if var not in tasklist[p]:
tasklist[p].append(var)
tasklist = data.getVar('__BBTASKS', d) or []
bb.build.add_tasks(tasklist, d) bb.build.add_tasks(tasklist, d)
# now add the handlers
if not len(all_handlers) == 0:
data.setVar('__all_handlers__', all_handlers, d)
bbpath.pop(0) bbpath.pop(0)
if oldfile: if oldfile:
bb.data.setVar("FILE", oldfile, d) bb.data.setVar("FILE", oldfile, d)
@ -342,15 +321,23 @@ def feeder(lineno, s, fn, root, d):
data.setVarFlag(var, "task", 1, d) data.setVarFlag(var, "task", 1, d)
bbtasks = data.getVar('__BBTASKS', d) or [] bbtasks = data.getVar('__BBTASKS', d) or []
bbtasks.append(var) if not var in bbtasks:
bbtasks.append(var)
data.setVar('__BBTASKS', bbtasks, d) data.setVar('__BBTASKS', bbtasks, d)
existing = data.getVarFlag(var, "deps", d) or []
if after is not None: if after is not None:
# set up deps for function # set up deps for function
data.setVarFlag(var, "deps", after.split(), d) for entry in after.split():
if entry not in existing:
existing.append(entry)
data.setVarFlag(var, "deps", existing, d)
if before is not None: if before is not None:
# set up things that depend on this func # set up things that depend on this func
data.setVarFlag(var, "postdeps", before.split(), d) for entry in before.split():
existing = data.getVarFlag(entry, "deps", d) or []
if var not in existing:
data.setVarFlag(entry, "deps", [var] + existing, d)
return return
m = __addhandler_regexp__.match(s) m = __addhandler_regexp__.match(s)

View File

@ -26,6 +26,7 @@ from bb import msg, data, event, mkdirhier, utils
from sets import Set from sets import Set
import bb, os, sys import bb, os, sys
import signal import signal
import stat
class TaskFailure(Exception): class TaskFailure(Exception):
"""Exception raised when a task in a runqueue fails""" """Exception raised when a task in a runqueue fails"""
@ -45,11 +46,11 @@ class RunQueueStats:
def taskFailed(self): def taskFailed(self):
self.failed = self.failed + 1 self.failed = self.failed + 1
def taskCompleted(self): def taskCompleted(self, number = 1):
self.completed = self.completed + 1 self.completed = self.completed + number
def taskSkipped(self): def taskSkipped(self, number = 1):
self.skipped = self.skipped + 1 self.skipped = self.skipped + number
class RunQueueScheduler: class RunQueueScheduler:
""" """
@ -144,8 +145,11 @@ class RunQueue:
self.taskData = taskData self.taskData = taskData
self.targets = targets self.targets = targets
self.number_tasks = int(bb.data.getVar("BB_NUMBER_THREADS", cfgData) or 1) self.cfgdata = cfgData
self.multi_provider_whitelist = (bb.data.getVar("MULTI_PROVIDER_WHITELIST", cfgData) or "").split() self.number_tasks = int(bb.data.getVar("BB_NUMBER_THREADS", cfgData, 1) or 1)
self.multi_provider_whitelist = (bb.data.getVar("MULTI_PROVIDER_WHITELIST", cfgData, 1) or "").split()
self.scheduler = bb.data.getVar("BB_SCHEDULER", cfgData, 1) or "speed"
self.stamppolicy = bb.data.getVar("BB_STAMP_POLICY", cfgData, 1) or "perfile"
def reset_runqueue(self): def reset_runqueue(self):
@ -512,6 +516,7 @@ class RunQueue:
for depend in depends: for depend in depends:
mark_active(depend, depth+1) mark_active(depend, depth+1)
self.target_pairs = []
for target in self.targets: for target in self.targets:
targetid = taskData.getbuild_id(target[0]) targetid = taskData.getbuild_id(target[0])
@ -522,10 +527,11 @@ class RunQueue:
continue continue
fnid = taskData.build_targets[targetid][0] fnid = taskData.build_targets[targetid][0]
fn = taskData.fn_index[fnid]
self.target_pairs.append((fn, target[1]))
# Remove stamps for targets if force mode active # Remove stamps for targets if force mode active
if self.cooker.configuration.force: if self.cooker.configuration.force:
fn = taskData.fn_index[fnid]
bb.msg.note(2, bb.msg.domain.RunQueue, "Remove stamp %s, %s" % (target[1], fn)) bb.msg.note(2, bb.msg.domain.RunQueue, "Remove stamp %s, %s" % (target[1], fn))
bb.build.del_stamp(target[1], self.dataCache, fn) bb.build.del_stamp(target[1], self.dataCache, fn)
@ -608,10 +614,11 @@ class RunQueue:
self.runq_weight = self.calculate_task_weights(endpoints) self.runq_weight = self.calculate_task_weights(endpoints)
# Decide what order to execute the tasks in, pick a scheduler # Decide what order to execute the tasks in, pick a scheduler
# FIXME - Allow user selection
#self.sched = RunQueueScheduler(self) #self.sched = RunQueueScheduler(self)
self.sched = RunQueueSchedulerSpeed(self) if self.scheduler == "completion":
#self.sched = RunQueueSchedulerCompletion(self) self.sched = RunQueueSchedulerCompletion(self)
else:
self.sched = RunQueueSchedulerSpeed(self)
# Sanity Check - Check for multiple tasks building the same provider # Sanity Check - Check for multiple tasks building the same provider
prov_list = {} prov_list = {}
@ -636,6 +643,93 @@ class RunQueue:
#self.dump_data(taskData) #self.dump_data(taskData)
def check_stamps(self):
unchecked = {}
current = []
notcurrent = []
buildable = []
if self.stamppolicy == "perfile":
fulldeptree = False
else:
fulldeptree = True
for task in range(len(self.runq_fnid)):
unchecked[task] = ""
if len(self.runq_depends[task]) == 0:
buildable.append(task)
for task in range(len(self.runq_fnid)):
if task not in unchecked:
continue
fn = self.taskData.fn_index[self.runq_fnid[task]]
taskname = self.runq_task[task]
stampfile = "%s.%s" % (self.dataCache.stamp[fn], taskname)
# If the stamp is missing its not current
if not os.access(stampfile, os.F_OK):
del unchecked[task]
notcurrent.append(task)
continue
# If its a 'nostamp' task, it's not current
taskdep = self.dataCache.task_deps[fn]
if 'nostamp' in taskdep and task in taskdep['nostamp']:
del unchecked[task]
notcurrent.append(task)
continue
while (len(buildable) > 0):
nextbuildable = []
for task in buildable:
if task in unchecked:
fn = self.taskData.fn_index[self.runq_fnid[task]]
taskname = self.runq_task[task]
stampfile = "%s.%s" % (self.dataCache.stamp[fn], taskname)
iscurrent = True
t1 = os.stat(stampfile)[stat.ST_MTIME]
for dep in self.runq_depends[task]:
if iscurrent:
fn2 = self.taskData.fn_index[self.runq_fnid[dep]]
taskname2 = self.runq_task[dep]
stampfile2 = "%s.%s" % (self.dataCache.stamp[fn2], taskname2)
if fulldeptree or fn == fn2:
if dep in notcurrent:
iscurrent = False
else:
t2 = os.stat(stampfile2)[stat.ST_MTIME]
if t1 < t2:
iscurrent = False
del unchecked[task]
if iscurrent:
current.append(task)
else:
notcurrent.append(task)
for revdep in self.runq_revdeps[task]:
alldeps = 1
for dep in self.runq_depends[revdep]:
if dep in unchecked:
alldeps = 0
if alldeps == 1:
if revdep in unchecked:
nextbuildable.append(revdep)
buildable = nextbuildable
#for task in range(len(self.runq_fnid)):
# fn = self.taskData.fn_index[self.runq_fnid[task]]
# taskname = self.runq_task[task]
# print "%s %s.%s" % (task, taskname, fn)
#print "Unchecked: %s" % unchecked
#print "Current: %s" % current
#print "Not current: %s" % notcurrent
if len(unchecked) > 0:
bb.fatal("check_stamps fatal internal error")
return current
def execute_runqueue(self): def execute_runqueue(self):
""" """
Run the tasks in a queue prepared by prepare_runqueue Run the tasks in a queue prepared by prepare_runqueue
@ -721,18 +815,13 @@ class RunQueue:
def sigint_handler(signum, frame): def sigint_handler(signum, frame):
raise KeyboardInterrupt raise KeyboardInterrupt
# RP - this code allows tasks to run out of the correct order - disabled, FIXME event.fire(bb.event.StampUpdate(self.target_pairs, self.dataCache.stamp, self.cfgdata))
# Find any tasks with current stamps and remove them from the queue
#for task1 in range(len(self.runq_fnid)): # Find out which tasks have current stamps which we can skip when the
# task = self.prio_map[task1] # time comes
# fn = self.taskData.fn_index[self.runq_fnid[task]] currentstamps = self.check_stamps()
# taskname = self.runq_task[task] self.stats.taskSkipped(len(currentstamps))
# if bb.build.stamp_is_current(taskname, self.dataCache, fn): self.stats.taskCompleted(len(currentstamps))
# bb.msg.debug(2, bb.msg.domain.RunQueue, "Stamp current task %s (%s)" % (task, self.get_user_idstring(task)))
# self.runq_running[task] = 1
# self.task_complete(task)
# self.stats.taskCompleted()
# self.stats.taskSkipped()
while True: while True:
task = self.sched.next() task = self.sched.next()
@ -740,12 +829,13 @@ class RunQueue:
fn = self.taskData.fn_index[self.runq_fnid[task]] fn = self.taskData.fn_index[self.runq_fnid[task]]
taskname = self.runq_task[task] taskname = self.runq_task[task]
if bb.build.stamp_is_current(taskname, self.dataCache, fn): if task in currentstamps:
#if bb.build.stamp_is_current(taskname, self.dataCache, fn):
bb.msg.debug(2, bb.msg.domain.RunQueue, "Stamp current task %s (%s)" % (task, self.get_user_idstring(task))) bb.msg.debug(2, bb.msg.domain.RunQueue, "Stamp current task %s (%s)" % (task, self.get_user_idstring(task)))
self.runq_running[task] = 1 self.runq_running[task] = 1
self.task_complete(task) self.task_complete(task)
self.stats.taskCompleted() #self.stats.taskCompleted()
self.stats.taskSkipped() #self.stats.taskSkipped()
continue continue
bb.msg.note(1, bb.msg.domain.RunQueue, "Running task %d of %d (ID: %s, %s)" % (self.stats.completed + self.active_builds + 1, len(self.runq_fnid), task, self.get_user_idstring(task))) bb.msg.note(1, bb.msg.domain.RunQueue, "Running task %d of %d (ID: %s, %s)" % (self.stats.completed + self.active_builds + 1, len(self.runq_fnid), task, self.get_user_idstring(task)))
@ -764,7 +854,7 @@ class RunQueue:
os.dup2(newsi, sys.stdin.fileno()) os.dup2(newsi, sys.stdin.fileno())
self.cooker.configuration.cmd = taskname[3:] self.cooker.configuration.cmd = taskname[3:]
try: try:
self.cooker.tryBuild(fn, False) self.cooker.tryBuild(fn)
except bb.build.EventException: except bb.build.EventException:
bb.msg.error(bb.msg.domain.Build, "Build of " + fn + " " + taskname + " failed") bb.msg.error(bb.msg.domain.Build, "Build of " + fn + " " + taskname + " failed")
sys.exit(1) sys.exit(1)

View File

@ -243,27 +243,13 @@ class BitBakeShellCommands:
oldcmd = cooker.configuration.cmd oldcmd = cooker.configuration.cmd
cooker.configuration.cmd = cmd cooker.configuration.cmd = cmd
thisdata = data.createCopy(cooker.configuration.data)
data.update_data(thisdata)
data.expandKeys(thisdata)
try: try:
bbfile_data = parse.handle( bf, thisdata ) cooker.buildFile(bf)
except parse.ParseError: except parse.ParseError:
print "ERROR: Unable to open or parse '%s'" % bf print "ERROR: Unable to open or parse '%s'" % bf
else: except build.EventException, e:
# Remove stamp for target if force mode active print "ERROR: Couldn't build '%s'" % name
if cooker.configuration.force: last_exception = e
bb.msg.note(2, bb.msg.domain.RunQueue, "Remove stamp %s, %s" % (cmd, bf))
bb.build.del_stamp('do_%s' % cmd, bbfile_data)
item = data.getVar('PN', bbfile_data, 1)
data.setVar( "_task_cache", [], bbfile_data ) # force
try:
cooker.tryBuildPackage( os.path.abspath( bf ), item, cmd, bbfile_data, True )
except build.EventException, e:
print "ERROR: Couldn't build '%s'" % name
last_exception = e
cooker.configuration.cmd = oldcmd cooker.configuration.cmd = oldcmd
fileBuild.usage = "<bbfile>" fileBuild.usage = "<bbfile>"
@ -586,6 +572,7 @@ SRC_URI = ""
def completeFilePath( bbfile ): def completeFilePath( bbfile ):
"""Get the complete bbfile path""" """Get the complete bbfile path"""
if not cooker.status: return bbfile
if not cooker.status.pkg_fn: return bbfile if not cooker.status.pkg_fn: return bbfile
for key in cooker.status.pkg_fn.keys(): for key in cooker.status.pkg_fn.keys():
if key.endswith( bbfile ): if key.endswith( bbfile ):

View File

@ -124,7 +124,6 @@ class TaskData:
Add tasks for a given fn to the database Add tasks for a given fn to the database
""" """
task_graph = dataCache.task_queues[fn]
task_deps = dataCache.task_deps[fn] task_deps = dataCache.task_deps[fn]
fnid = self.getfn_id(fn) fnid = self.getfn_id(fn)
@ -136,11 +135,11 @@ class TaskData:
if fnid in self.tasks_fnid: if fnid in self.tasks_fnid:
return return
for task in task_graph.allnodes(): for task in task_deps['tasks']:
# Work out task dependencies # Work out task dependencies
parentids = [] parentids = []
for dep in task_graph.getparents(task): for dep in task_deps['parents'][task]:
parentid = self.gettask_id(fn, dep) parentid = self.gettask_id(fn, dep)
parentids.append(parentid) parentids.append(parentid)
taskid = self.gettask_id(fn, task) taskid = self.gettask_id(fn, task)

View File

@ -85,11 +85,11 @@ def explode_deps(s):
for i in l: for i in l:
if i[0] == '(': if i[0] == '(':
flag = True flag = True
j = [] #j = []
if flag: if not flag:
j.append(i)
else:
r.append(i) r.append(i)
#else:
# j.append(i)
if flag and i.endswith(')'): if flag and i.endswith(')'):
flag = False flag = False
# Ignore version # Ignore version