diff options
author | Richard Purdie <richard@openedhand.com> | 2006-11-16 15:02:15 +0000 |
---|---|---|
committer | Richard Purdie <richard@openedhand.com> | 2006-11-16 15:02:15 +0000 |
commit | 306b7c7a9757ead077363074e7bbac2e5c03e7c5 (patch) | |
tree | 6935017a9af749c46816881c86258f514384ba1c /bitbake/lib | |
parent | 65930a38e415ae4a0182e1cea1be838e0ada50ee (diff) | |
download | openembedded-core-306b7c7a9757ead077363074e7bbac2e5c03e7c5.tar.gz openembedded-core-306b7c7a9757ead077363074e7bbac2e5c03e7c5.tar.bz2 openembedded-core-306b7c7a9757ead077363074e7bbac2e5c03e7c5.zip |
bitbake: Upgrade from 1.4 -> 1.7.4ish
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@863 311d38ba-8fff-0310-9ca6-ca027cbcb966
Diffstat (limited to 'bitbake/lib')
33 files changed, 3343 insertions, 1186 deletions
diff --git a/bitbake/lib/bb/COW.py b/bitbake/lib/bb/COW.py new file mode 100644 index 0000000000..826d435f98 --- /dev/null +++ b/bitbake/lib/bb/COW.py @@ -0,0 +1,305 @@ +# ex:ts=4:sw=4:sts=4:et +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +""" +This is a copy on write dictionary and set which abuses classes to try and be nice and fast. + +Please Note: + Be careful when using mutable types (ie Dict and Lists) - operations involving these are SLOW. + Assign a file to __warn__ to get warnings about slow operations. +""" + +from inspect import getmro + +import copy +import types, sets +types.ImmutableTypes = tuple([ \ + types.BooleanType, \ + types.ComplexType, \ + types.FloatType, \ + types.IntType, \ + types.LongType, \ + types.NoneType, \ + types.TupleType, \ + sets.ImmutableSet] + \ + list(types.StringTypes)) + +MUTABLE = "__mutable__" + +class COWMeta(type): + pass + +class COWDictMeta(COWMeta): + __warn__ = False + __hasmutable__ = False + __marker__ = tuple() + + def __str__(cls): + # FIXME: I have magic numbers! + return "<COWDict Level: %i Current Keys: %i>" % (cls.__count__, len(cls.__dict__) - 3) + __repr__ = __str__ + + def cow(cls): + class C(cls): + __count__ = cls.__count__ + 1 + return C + copy = cow + __call__ = cow + + def __setitem__(cls, key, value): + if not isinstance(value, types.ImmutableTypes): + if not isinstance(value, COWMeta): + cls.__hasmutable__ = True + key += MUTABLE + setattr(cls, key, value) + + def __getmutable__(cls, key, readonly=False): + nkey = key + MUTABLE + try: + return cls.__dict__[nkey] + except KeyError: + pass + + value = getattr(cls, nkey) + if readonly: + return value + + if not cls.__warn__ is False and not isinstance(value, COWMeta): + print >> cls.__warn__, "Warning: Doing a copy because %s is a mutable type." % key + try: + value = value.copy() + except AttributeError, e: + value = copy.copy(value) + setattr(cls, nkey, value) + return value + + __getmarker__ = [] + def __getreadonly__(cls, key, default=__getmarker__): + """\ + Get a value (even if mutable) which you promise not to change. + """ + return cls.__getitem__(key, default, True) + + def __getitem__(cls, key, default=__getmarker__, readonly=False): + try: + try: + value = getattr(cls, key) + except AttributeError: + value = cls.__getmutable__(key, readonly) + + # This is for values which have been deleted + if value is cls.__marker__: + raise AttributeError("key %s does not exist." % key) + + return value + except AttributeError, e: + if not default is cls.__getmarker__: + return default + + raise KeyError(str(e)) + + def __delitem__(cls, key): + cls.__setitem__(key, cls.__marker__) + + def __revertitem__(cls, key): + if not cls.__dict__.has_key(key): + key += MUTABLE + delattr(cls, key) + + def has_key(cls, key): + value = cls.__getreadonly__(key, cls.__marker__) + if value is cls.__marker__: + return False + return True + + def iter(cls, type, readonly=False): + for key in dir(cls): + if key.startswith("__"): + continue + + if key.endswith(MUTABLE): + key = key[:-len(MUTABLE)] + + if type == "keys": + yield key + + try: + if readonly: + value = cls.__getreadonly__(key) + else: + value = cls[key] + except KeyError: + continue + + if type == "values": + yield value + if type == "items": + yield (key, value) + raise StopIteration() + + def iterkeys(cls): + return cls.iter("keys") + def itervalues(cls, readonly=False): + if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False: + print >> cls.__warn__, "Warning: If you arn't going to change any of the values call with True." + return cls.iter("values", readonly) + def iteritems(cls, readonly=False): + if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False: + print >> cls.__warn__, "Warning: If you arn't going to change any of the values call with True." + return cls.iter("items", readonly) + +class COWSetMeta(COWDictMeta): + def __str__(cls): + # FIXME: I have magic numbers! + return "<COWSet Level: %i Current Keys: %i>" % (cls.__count__, len(cls.__dict__) -3) + __repr__ = __str__ + + def cow(cls): + class C(cls): + __count__ = cls.__count__ + 1 + return C + + def add(cls, value): + COWDictMeta.__setitem__(cls, repr(hash(value)), value) + + def remove(cls, value): + COWDictMeta.__delitem__(cls, repr(hash(value))) + + def __in__(cls, value): + return COWDictMeta.has_key(repr(hash(value))) + + def iterkeys(cls): + raise TypeError("sets don't have keys") + + def iteritems(cls): + raise TypeError("sets don't have 'items'") + +# These are the actual classes you use! +class COWDictBase(object): + __metaclass__ = COWDictMeta + __count__ = 0 + +class COWSetBase(object): + __metaclass__ = COWSetMeta + __count__ = 0 + +if __name__ == "__main__": + import sys + COWDictBase.__warn__ = sys.stderr + a = COWDictBase() + print "a", a + + a['a'] = 'a' + a['b'] = 'b' + a['dict'] = {} + + b = a.copy() + print "b", b + b['c'] = 'b' + + print + + print "a", a + for x in a.iteritems(): + print x + print "--" + print "b", b + for x in b.iteritems(): + print x + print + + b['dict']['a'] = 'b' + b['a'] = 'c' + + print "a", a + for x in a.iteritems(): + print x + print "--" + print "b", b + for x in b.iteritems(): + print x + print + + try: + b['dict2'] + except KeyError, e: + print "Okay!" + + a['set'] = COWSetBase() + a['set'].add("o1") + a['set'].add("o1") + a['set'].add("o2") + + print "a", a + for x in a['set'].itervalues(): + print x + print "--" + print "b", b + for x in b['set'].itervalues(): + print x + print + + b['set'].add('o3') + + print "a", a + for x in a['set'].itervalues(): + print x + print "--" + print "b", b + for x in b['set'].itervalues(): + print x + print + + a['set2'] = set() + a['set2'].add("o1") + a['set2'].add("o1") + a['set2'].add("o2") + + print "a", a + for x in a.iteritems(): + print x + print "--" + print "b", b + for x in b.iteritems(readonly=True): + print x + print + + del b['b'] + try: + print b['b'] + except KeyError: + print "Yay! deleted key raises error" + + if b.has_key('b'): + print "Boo!" + else: + print "Yay - has_key with delete works!" + + print "a", a + for x in a.iteritems(): + print x + print "--" + print "b", b + for x in b.iteritems(readonly=True): + print x + print + + b.__revertitem__('b') + + print "a", a + for x in a.iteritems(): + print x + print "--" + print "b", b + for x in b.iteritems(readonly=True): + print x + print + + b.__revertitem__('dict') + print "a", a + for x in a.iteritems(): + print x + print "--" + print "b", b + for x in b.iteritems(readonly=True): + print x + print diff --git a/bitbake/lib/bb/__init__.py b/bitbake/lib/bb/__init__.py index c3e7a16658..61eb5f3db8 100644 --- a/bitbake/lib/bb/__init__.py +++ b/bitbake/lib/bb/__init__.py @@ -23,7 +23,7 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. """ -__version__ = "1.4.3" +__version__ = "1.7.4" __all__ = [ @@ -63,24 +63,24 @@ __all__ = [ "manifest", "methodpool", "cache", + "runqueue", + "taskdata", + "providers", ] whitespace = '\t\n\x0b\x0c\r ' lowercase = 'abcdefghijklmnopqrstuvwxyz' -import sys, os, types, re, string +import sys, os, types, re, string, bb +from bb import msg #projectdir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0]))) projectdir = os.getcwd() -debug_level = 0 - if "BBDEBUG" in os.environ: level = int(os.environ["BBDEBUG"]) if level: - debug_level = level - else: - debug_level = 0 + bb.msg.set_debug_level(level) class VarExpandError(Exception): pass @@ -99,22 +99,17 @@ class MalformedUrl(Exception): ####################################################################### ####################################################################### -debug_prepend = '' - - def debug(lvl, *args): - if debug_level >= lvl: - print debug_prepend + 'DEBUG:', ''.join(args) + bb.msg.std_debug(lvl, ''.join(args)) def note(*args): - print debug_prepend + 'NOTE:', ''.join(args) + bb.msg.std_note(''.join(args)) def error(*args): - print debug_prepend + 'ERROR:', ''.join(args) + bb.msg.std_error(''.join(args)) def fatal(*args): - print debug_prepend + 'ERROR:', ''.join(args) - sys.exit(1) + bb.msg.std_fatal(''.join(args)) ####################################################################### diff --git a/bitbake/lib/bb/build.py b/bitbake/lib/bb/build.py index 8e169e002a..942bdc1a39 100644 --- a/bitbake/lib/bb/build.py +++ b/bitbake/lib/bb/build.py @@ -25,18 +25,9 @@ You should have received a copy of the GNU General Public License along with Based on functions from the base bb module, Copyright 2003 Holger Schurig """ -from bb import debug, data, fetch, fatal, error, note, event, mkdirhier, utils +from bb import data, fetch, event, mkdirhier, utils import bb, os -# data holds flags and function name for a given task -_task_data = data.init() - -# graph represents task interdependencies -_task_graph = bb.digraph() - -# stack represents execution order, excepting dependencies -_task_stack = [] - # events class FuncFailed(Exception): """Executed function failed""" @@ -76,13 +67,6 @@ class InvalidTask(TaskBase): # functions -def init(data): - global _task_data, _task_graph, _task_stack - _task_data = data.init() - _task_graph = bb.digraph() - _task_stack = [] - - def exec_func(func, d, dirs = None): """Execute an BB 'function'""" @@ -163,7 +147,7 @@ def exec_func_shell(func, d): f = open(runfile, "w") f.write("#!/bin/sh -e\n") - if bb.debug_level > 0: f.write("set -x\n") + if bb.msg.debug_level['default'] > 0: f.write("set -x\n") data.emit_env(f, d) f.write("cd %s\n" % os.getcwd()) @@ -171,18 +155,18 @@ def exec_func_shell(func, d): f.close() os.chmod(runfile, 0775) if not func: - error("Function not specified") + bb.msg.error(bb.msg.domain.Build, "Function not specified") raise FuncFailed() # open logs si = file('/dev/null', 'r') try: - if bb.debug_level > 0: + if bb.msg.debug_level['default'] > 0: so = os.popen("tee \"%s\"" % logfile, "w") else: so = file(logfile, 'w') except OSError, e: - bb.error("opening log file: %s" % e) + bb.msg.error(bb.msg.domain.Build, "opening log file: %s" % e) pass se = so @@ -205,7 +189,10 @@ def exec_func_shell(func, d): else: maybe_fakeroot = '' ret = os.system('%ssh -e %s' % (maybe_fakeroot, runfile)) - os.chdir(prevdir) + try: + os.chdir(prevdir) + except: + pass if not interact: # restore the backups @@ -224,14 +211,14 @@ def exec_func_shell(func, d): os.close(ose[0]) if ret==0: - if bb.debug_level > 0: + if bb.msg.debug_level['default'] > 0: os.remove(runfile) # os.remove(logfile) return else: - error("function %s failed" % func) + bb.msg.error(bb.msg.domain.Build, "function %s failed" % func) if data.getVar("BBINCLUDELOGS", d): - error("log data follows (%s)" % logfile) + bb.msg.error(bb.msg.domain.Build, "log data follows (%s)" % logfile) f = open(logfile, "r") while True: l = f.readline() @@ -241,7 +228,7 @@ def exec_func_shell(func, d): print '| %s' % l f.close() else: - error("see log in %s" % logfile) + bb.msg.error(bb.msg.domain.Build, "see log in %s" % logfile) raise FuncFailed( logfile ) @@ -281,7 +268,7 @@ def exec_task(task, d): return 1 try: - debug(1, "Executing task %s" % item) + 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) @@ -292,21 +279,63 @@ def exec_task(task, d): task_cache.append(item) data.setVar('_task_cache', task_cache, d) except FuncFailed, reason: - note( "Task failed: %s" % 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) - # execute - task_graph.walkdown(task, execute) + if data.getVarFlag(task, 'dontrundeps', d): + execute(None, task) + else: + task_graph.walkdown(task, execute) # make stamp, or cause event and raise exception if not data.getVarFlag(task, 'nostamp', d): mkstamp(task, d) +def stamp_is_current_cache(dataCache, file_name, task, checkdeps = 1): + """ + Check status of a given task's stamp. + Returns 0 if it is not current and needs updating. + Same as stamp_is_current but works against the dataCache instead of d + """ + task_graph = dataCache.task_queues[file_name] + + if not dataCache.stamp[file_name]: + return 0 + + stampfile = "%s.%s" % (dataCache.stamp[file_name], 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 'nostamp' in dataCache.task_deps[file_name] and task in dataCache.task_deps[file_name]['nostamp']: + return 1 + + if not stamp_is_current_cache(dataCache, file_name, task, 0): + return 0 + + depfile = "%s.%s" % (dataCache.stamp[file_name], task) + deptime = os.stat(depfile)[stat.ST_MTIME] + if deptime > tasktime: + return 0 + return 1 + + return task_graph.walkdown(task, checkStamp) def stamp_is_current(task, d, checkdeps = 1): - """Check status of a given task's stamp. returns 0 if it is not current and needs updating.""" + """ + Check status of a given task's stamp. + Returns 0 if it is not current and needs updating. + """ task_graph = data.getVar('_task_graph', d) if not task_graph: task_graph = bb.digraph() @@ -360,7 +389,6 @@ def mkstamp(task, d): f = open(stamp, "w") f.close() - def add_task(task, deps, d): task_graph = data.getVar('_task_graph', d) if not task_graph: @@ -374,6 +402,21 @@ def add_task(task, deps, d): # don't assume holding a reference data.setVar('_task_graph', task_graph, d) + task_deps = data.getVar('_task_deps', d) + if not task_deps: + task_deps = {} + def getTask(name): + deptask = data.getVarFlag(task, name, d) + if deptask: + if not name in task_deps: + task_deps[name] = {} + task_deps[name][task] = deptask + getTask('deptask') + getTask('rdeptask') + getTask('recrdeptask') + getTask('nostamp') + + data.setVar('_task_deps', task_deps, d) def remove_task(task, kill, d): """Remove an BB 'task'. @@ -399,6 +442,3 @@ def task_exists(task, d): task_graph = bb.digraph() data.setVar('_task_graph', task_graph, d) return task_graph.hasnode(task) - -def get_task_data(): - return _task_data diff --git a/bitbake/lib/bb/cache.py b/bitbake/lib/bb/cache.py index 921a9f7589..05c42518a7 100644 --- a/bitbake/lib/bb/cache.py +++ b/bitbake/lib/bb/cache.py @@ -33,15 +33,15 @@ Place, Suite 330, Boston, MA 02111-1307 USA. import os, re import bb.data import bb.utils +from sets import Set try: import cPickle as pickle except ImportError: import pickle - print "NOTE: 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__ = "123" -__cache_version__ = "124" # changes the __depends structure +__cache_version__ = "125" class Cache: """ @@ -58,14 +58,12 @@ class Cache: if self.cachedir in [None, '']: self.has_cache = False - if cooker.cb is not None: - print "NOTE: Not using a cache. Set CACHE = <directory> to enable." + bb.msg.note(1, bb.msg.domain.Cache, "Not using a cache. Set CACHE = <directory> to enable.") else: self.has_cache = True self.cachefile = os.path.join(self.cachedir,"bb_cache.dat") - if cooker.cb is not None: - print "NOTE: Using cache in '%s'" % self.cachedir + bb.msg.debug(1, bb.msg.domain.Cache, "Using cache in '%s'" % self.cachedir) try: os.stat( self.cachedir ) except OSError: @@ -80,7 +78,7 @@ class Cache: if version_data['BITBAKE_VER'] != bb.__version__: raise ValueError, 'Bitbake Version Mismatch' except (ValueError, KeyError): - bb.note("Invalid cache found, rebuilding...") + bb.msg.note(1, bb.msg.domain.Cache, "Invalid cache found, rebuilding...") self.depends_cache = {} if self.depends_cache: @@ -108,7 +106,7 @@ class Cache: if fn != self.data_fn: # We're trying to access data in the cache which doesn't exist # yet setData hasn't been called to setup the right access. Very bad. - bb.error("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)) result = bb.data.getVar(var, self.data, exp) self.depends_cache[fn][var] = result @@ -127,15 +125,15 @@ class Cache: self.getVar("__depends", fn, True) self.depends_cache[fn]["CACHETIMESTAMP"] = bb.parse.cached_mtime(fn) - def loadDataFull(self, fn, cooker): + def loadDataFull(self, fn, cfgData): """ Return a complete set of data for fn. To do this, we need to parse the file. """ - bb_data, skipped = self.load_bbfile(fn, cooker) + bb_data, skipped = self.load_bbfile(fn, cfgData) return bb_data - def loadData(self, fn, cooker): + def loadData(self, fn, cfgData): """ Load a subset of data for fn. If the cached data is valid we do nothing, @@ -148,7 +146,7 @@ class Cache: return True, True return True, False - bb_data, skipped = self.load_bbfile(fn, cooker) + bb_data, skipped = self.load_bbfile(fn, cfgData) self.setData(fn, bb_data) return False, skipped @@ -175,32 +173,36 @@ class Cache: # Check file still exists if self.mtime(fn) == 0: - bb.debug(2, "Cache: %s not longer exists" % fn) + bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s not longer exists" % fn) self.remove(fn) return False # File isn't in depends_cache if not fn in self.depends_cache: - bb.debug(2, "Cache: %s is not cached" % fn) + bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s is not cached" % fn) self.remove(fn) return False # Check the file's timestamp if bb.parse.cached_mtime(fn) > self.getVar("CACHETIMESTAMP", fn, True): - bb.debug(2, "Cache: %s changed" % fn) + bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s changed" % fn) self.remove(fn) return False # Check dependencies are still valid depends = self.getVar("__depends", fn, True) for f,old_mtime in depends: + # Check if file still exists + if self.mtime(f) == 0: + return False + new_mtime = bb.parse.cached_mtime(f) if (new_mtime > old_mtime): - bb.debug(2, "Cache: %s's dependency %s changed" % (fn, f)) + bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s's dependency %s changed" % (fn, f)) self.remove(fn) return False - bb.debug(2, "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: self.clean[fn] = "" @@ -220,7 +222,7 @@ class Cache: Remove a fn from the cache Called from the parser in error cases """ - bb.debug(1, "Removing %s from cache" % fn) + bb.msg.debug(1, bb.msg.domain.Cache, "Removing %s from cache" % fn) if fn in self.depends_cache: del self.depends_cache[fn] if fn in self.clean: @@ -229,7 +231,7 @@ class Cache: def sync(self): """ Save the cache - Called from the parser when complete (or exitting) + Called from the parser when complete (or exiting) """ if not self.has_cache: @@ -243,12 +245,103 @@ class Cache: p.dump([self.depends_cache, version_data]) def mtime(self, cachefile): - try: - return os.stat(cachefile)[8] - except OSError: - return 0 + return bb.parse.cached_mtime_noerror(cachefile) - def load_bbfile( self, bbfile , cooker): + def handle_data(self, file_name, cacheData): + """ + Save data we need into the cache + """ + + pn = self.getVar('PN', file_name, True) + pv = self.getVar('PV', file_name, True) + pr = self.getVar('PR', file_name, True) + dp = int(self.getVar('DEFAULT_PREFERENCE', file_name, True) or "0") + provides = Set([pn] + (self.getVar("PROVIDES", file_name, True) or "").split()) + depends = bb.utils.explode_deps(self.getVar("DEPENDS", file_name, True) or "") + packages = (self.getVar('PACKAGES', 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() + + cacheData.task_queues[file_name] = self.getVar("_task_graph", file_name, True) + cacheData.task_deps[file_name] = self.getVar("_task_deps", file_name, True) + + # build PackageName to FileName lookup table + if pn not in cacheData.pkg_pn: + cacheData.pkg_pn[pn] = [] + cacheData.pkg_pn[pn].append(file_name) + + cacheData.stamp[file_name] = self.getVar('STAMP', file_name, True) + + # build FileName to PackageName lookup table + cacheData.pkg_fn[file_name] = pn + cacheData.pkg_pvpr[file_name] = (pv,pr) + cacheData.pkg_dp[file_name] = dp + + # Build forward and reverse provider hashes + # Forward: virtual -> [filenames] + # Reverse: PN -> [virtuals] + if pn not in cacheData.pn_provides: + cacheData.pn_provides[pn] = Set() + cacheData.pn_provides[pn] |= provides + + for provide in provides: + if provide not in cacheData.providers: + cacheData.providers[provide] = [] + cacheData.providers[provide].append(file_name) + + cacheData.deps[file_name] = Set() + for dep in depends: + cacheData.all_depends.add(dep) + cacheData.deps[file_name].add(dep) + + # Build reverse hash for PACKAGES, so runtime dependencies + # can be be resolved (RDEPENDS, RRECOMMENDS etc.) + for package in packages: + if not package in cacheData.packages: + cacheData.packages[package] = [] + cacheData.packages[package].append(file_name) + rprovides += (self.getVar("RPROVIDES_%s" % package, file_name, 1) or "").split() + + for package in packages_dynamic: + if not package in cacheData.packages_dynamic: + cacheData.packages_dynamic[package] = [] + cacheData.packages_dynamic[package].append(file_name) + + for rprovide in rprovides: + if not rprovide in cacheData.rproviders: + cacheData.rproviders[rprovide] = [] + cacheData.rproviders[rprovide].append(file_name) + + # Build hash of runtime depends and rececommends + + def add_dep(deplist, deps): + for dep in deps: + if not dep in deplist: + deplist[dep] = "" + + if not file_name in cacheData.rundeps: + cacheData.rundeps[file_name] = {} + if not file_name in cacheData.runrecs: + cacheData.runrecs[file_name] = {} + + for package in packages + [pn]: + if not package in cacheData.rundeps[file_name]: + cacheData.rundeps[file_name][package] = {} + if not package in cacheData.runrecs[file_name]: + 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.runrecs[file_name][package], bb.utils.explode_deps(self.getVar('RRECOMMENDS', 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 "")) + + # Collect files we may need for possible world-dep + # calculations + if not self.getVar('BROKEN', file_name, True) and not self.getVar('EXCLUDE_FROM_WORLD', file_name, True): + cacheData.possible_world.append(file_name) + + + def load_bbfile( self, bbfile , config): """ Load and parse one .bb build file Return the data and whether parsing resulted in the file being skipped @@ -257,25 +350,15 @@ class Cache: import bb from bb import utils, data, parse, debug, event, fatal - topdir = data.getVar('TOPDIR', cooker.configuration.data) - if not topdir: - topdir = os.path.abspath(os.getcwd()) - # set topdir to here - data.setVar('TOPDIR', topdir, cooker.configuration) - bbfile = os.path.abspath(bbfile) - bbfile_loc = os.path.abspath(os.path.dirname(bbfile)) # expand tmpdir to include this topdir - data.setVar('TMPDIR', data.getVar('TMPDIR', cooker.configuration.data, 1) or "", cooker.configuration.data) - # set topdir to location of .bb file - topdir = bbfile_loc - #data.setVar('TOPDIR', topdir, cfg) - # go there + data.setVar('TMPDIR', data.getVar('TMPDIR', config, 1) or "", config) + bbfile_loc = os.path.abspath(os.path.dirname(bbfile)) oldpath = os.path.abspath(os.getcwd()) - if self.mtime(topdir): - os.chdir(topdir) - bb_data = data.init_db(cooker.configuration.data) + if self.mtime(bbfile_loc): + os.chdir(bbfile_loc) + bb_data = data.init_db(config) try: - parse.handle(bbfile, bb_data) # read .bb data + bb_data = parse.handle(bbfile, bb_data) # read .bb data os.chdir(oldpath) return bb_data, False except bb.parse.SkipPackage: @@ -304,3 +387,45 @@ def init(cooker): """ return Cache(cooker) + + +#============================================================================# +# CacheData +#============================================================================# +class CacheData: + """ + The data structures we compile from the cached data + """ + + def __init__(self): + """ + Direct cache variables + (from Cache.handle_data) + """ + self.providers = {} + self.rproviders = {} + self.packages = {} + self.packages_dynamic = {} + self.possible_world = [] + self.pkg_pn = {} + self.pkg_fn = {} + self.pkg_pvpr = {} + self.pkg_dp = {} + self.pn_provides = {} + self.all_depends = Set() + self.deps = {} + self.rundeps = {} + self.runrecs = {} + self.task_queues = {} + self.task_deps = {} + self.stamp = {} + self.preferred = {} + + """ + Indirect Cache variables + (set elsewhere) + """ + self.ignored_dependencies = [] + self.world_target = Set() + self.bbfile_priority = {} + self.bbfile_config_priorities = [] diff --git a/bitbake/lib/bb/data.py b/bitbake/lib/bb/data.py index 55d1cc9053..819dff9679 100644 --- a/bitbake/lib/bb/data.py +++ b/bitbake/lib/bb/data.py @@ -45,7 +45,8 @@ else: path = os.path.dirname(os.path.dirname(sys.argv[0])) sys.path.insert(0,path) -from bb import note, debug, data_smart +from bb import data_smart +import bb _dict_type = data_smart.DataSmart @@ -362,10 +363,12 @@ def emit_var(var, o=sys.__stdout__, d = init(), all=False): val.rstrip() if not val: return 0 + + varExpanded = expand(var, d) if getVarFlag(var, "func", d): # NOTE: should probably check for unbalanced {} within the var - o.write("%s() {\n%s\n}\n" % (var, val)) + o.write("%s() {\n%s\n}\n" % (varExpanded, val)) else: if getVarFlag(var, "export", d): o.write('export ') @@ -375,7 +378,7 @@ def emit_var(var, o=sys.__stdout__, d = init(), all=False): # if we're going to output this within doublequotes, # to a shell, we need to escape the quotes in the var alter = re.sub('"', '\\"', val.strip()) - o.write('%s="%s"\n' % (var, alter)) + o.write('%s="%s"\n' % (varExpanded, alter)) return 1 @@ -430,8 +433,38 @@ def update_data(d): >>> update_data(d) >>> print getVar('TEST', d) local + + CopyMonster: + >>> e = d.createCopy() + >>> setVar('TEST_foo', 'foo', e) + >>> update_data(e) + >>> print getVar('TEST', e) + local + + >>> setVar('OVERRIDES', 'arm:ramses:local:foo', e) + >>> update_data(e) + >>> print getVar('TEST', e) + foo + + >>> f = d.createCopy() + >>> setVar('TEST_moo', 'something', f) + >>> setVar('OVERRIDES', 'moo:arm:ramses:local:foo', e) + >>> update_data(e) + >>> print getVar('TEST', e) + foo + + + >>> h = init() + >>> setVar('SRC_URI', 'file://append.foo;patch=1 ', h) + >>> g = h.createCopy() + >>> setVar('SRC_URI_append_arm', 'file://other.foo;patch=1', g) + >>> setVar('OVERRIDES', 'arm:moo', g) + >>> update_data(g) + >>> print getVar('SRC_URI', g) + file://append.foo;patch=1 file://other.foo;patch=1 + """ - debug(2, "update_data()") + bb.msg.debug(2, bb.msg.domain.Data, "update_data()") # now ask the cookie monster for help #print "Cookie Monster" @@ -460,7 +493,7 @@ def update_data(d): l = len(o)+1 # see if one should even try - if not o in d._seen_overrides: + if not d._seen_overrides.has_key(o): continue vars = d._seen_overrides[o] @@ -469,10 +502,10 @@ def update_data(d): try: d[name] = d[var] except: - note ("Untracked delVar") + bb.msg.note(1, bb.msg.domain.Data, "Untracked delVar") # now on to the appends and prepends - if '_append' in d._special_values: + if d._special_values.has_key('_append'): appends = d._special_values['_append'] or [] for append in appends: for (a, o) in getVarFlag(append, '_append', d) or []: @@ -487,7 +520,7 @@ def update_data(d): setVar(append, sval, d) - if '_prepend' in d._special_values: + if d._special_values.has_key('_prepend'): prepends = d._special_values['_prepend'] or [] for prepend in prepends: diff --git a/bitbake/lib/bb/data_smart.py b/bitbake/lib/bb/data_smart.py index fbd4167fe4..054b852200 100644 --- a/bitbake/lib/bb/data_smart.py +++ b/bitbake/lib/bb/data_smart.py @@ -29,14 +29,12 @@ Based on functions from the base bb module, Copyright 2003 Holger Schurig """ import copy, os, re, sys, time, types -from bb import note, debug, error, fatal, utils, methodpool +import bb +from bb import utils, methodpool +from COW import COWDictBase from sets import Set +from new import classobj -try: - import cPickle as pickle -except ImportError: - import pickle - print "NOTE: Importing cPickle failed. Falling back to a very slow implementation." __setvar_keyword__ = ["_append","_prepend"] __setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend)(_(?P<add>.*))?') @@ -45,12 +43,14 @@ __expand_python_regexp__ = re.compile(r"\${@.+?}") class DataSmart: - def __init__(self): + def __init__(self, special = COWDictBase.copy(), seen = COWDictBase.copy() ): self.dict = {} # cookie monster tribute - self._special_values = {} - self._seen_overrides = {} + self._special_values = special + self._seen_overrides = seen + + self.expand_cache = {} def expand(self,s, varname): def var_sub(match): @@ -75,6 +75,9 @@ class DataSmart: if type(s) is not types.StringType: # sanity check return s + if varname and varname in self.expand_cache: + return self.expand_cache[varname] + while s.find('$') != -1: olds = s try: @@ -82,15 +85,20 @@ class DataSmart: s = __expand_python_regexp__.sub(python_sub, s) if s == olds: break if type(s) is not types.StringType: # sanity check - error('expansion of %s returned non-string %s' % (olds, s)) + bb.msg.error(bb.msg.domain.Data, 'expansion of %s returned non-string %s' % (olds, s)) except KeyboardInterrupt: raise except: - note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s)) + bb.msg.note(1, bb.msg.domain.Data, "%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s)) raise + + if varname: + self.expand_cache[varname] = s + return s def initVar(self, var): + self.expand_cache = {} if not var in self.dict: self.dict[var] = {} @@ -119,6 +127,7 @@ class DataSmart: self.initVar(var) def setVar(self,var,value): + self.expand_cache = {} match = __setvar_regexp__.match(var) if match and match.group("keyword") in __setvar_keyword__: base = match.group('base') @@ -128,6 +137,7 @@ class DataSmart: l.append([value, override]) self.setVarFlag(base, keyword, l) + # todo make sure keyword is not __doc__ or __module__ # pay the cookie monster try: self._special_values[keyword].add( base ) @@ -135,10 +145,6 @@ class DataSmart: self._special_values[keyword] = Set() self._special_values[keyword].add( base ) - # SRC_URI_append_simpad is both a flag and a override - #if not override in self._seen_overrides: - # self._seen_overrides[override] = Set() - #self._seen_overrides[override].add( base ) return if not var in self.dict: @@ -150,7 +156,7 @@ class DataSmart: # more cookies for the cookie monster if '_' in var: override = var[var.rfind('_')+1:] - if not override in self._seen_overrides: + if not self._seen_overrides.has_key(override): self._seen_overrides[override] = Set() self._seen_overrides[override].add( var ) @@ -165,6 +171,7 @@ class DataSmart: return value def delVar(self,var): + self.expand_cache = {} self.dict[var] = {} def setVarFlag(self,var,flag,flagvalue): @@ -234,10 +241,8 @@ class DataSmart: Create a copy of self by setting _data to self """ # we really want this to be a DataSmart... - data = DataSmart() + data = DataSmart(seen=self._seen_overrides.copy(), special=self._special_values.copy()) data.dict["_data"] = self.dict - data._seen_overrides = copy.deepcopy(self._seen_overrides) - data._special_values = copy.deepcopy(self._special_values) return data diff --git a/bitbake/lib/bb/fetch/__init__.py b/bitbake/lib/bb/fetch/__init__.py index 7ab0590765..24aebc41ca 100644 --- a/bitbake/lib/bb/fetch/__init__.py +++ b/bitbake/lib/bb/fetch/__init__.py @@ -38,13 +38,16 @@ class NoMethodError(Exception): class MissingParameterError(Exception): """Exception raised when a fetch method is missing a critical parameter in the url""" +class ParameterError(Exception): + """Exception raised when a url cannot be proccessed due to invalid parameters.""" + class MD5SumError(Exception): """Exception raised when a MD5SUM of a file does not match the expected one""" def uri_replace(uri, uri_find, uri_replace, d): -# bb.note("uri_replace: operating on %s" % uri) +# bb.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: operating on %s" % uri) if not uri or not uri_find or not uri_replace: - bb.debug(1, "uri_replace: passed an undefined value, not replacing") + bb.msg.debug(1, bb.msg.domain.Fetcher, "uri_replace: passed an undefined value, not replacing") uri_decoded = list(bb.decodeurl(uri)) uri_find_decoded = list(bb.decodeurl(uri_find)) uri_replace_decoded = list(bb.decodeurl(uri_replace)) @@ -62,9 +65,9 @@ def uri_replace(uri, uri_find, uri_replace, d): localfn = bb.fetch.localpath(uri, d) if localfn: result_decoded[loc] = os.path.dirname(result_decoded[loc]) + "/" + os.path.basename(bb.fetch.localpath(uri, d)) -# bb.note("uri_replace: matching %s against %s and replacing with %s" % (i, uri_decoded[loc], uri_replace_decoded[loc])) +# bb.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: matching %s against %s and replacing with %s" % (i, uri_decoded[loc], uri_replace_decoded[loc])) else: -# bb.note("uri_replace: no match") +# bb.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: no match") return uri # else: # for j in i.keys(): @@ -72,62 +75,94 @@ def uri_replace(uri, uri_find, uri_replace, d): return bb.encodeurl(result_decoded) methods = [] +urldata = {} def init(urls = [], d = None): if d == None: - bb.debug(2,"BUG init called with None as data object!!!") + bb.msg.debug(2, bb.msg.domain.Fetcher, "BUG init called with None as data object!!!") return for m in methods: m.urls = [] for u in urls: + ud = initdata(u, d) + if ud.method: + ud.method.urls.append(u) + +def initdata(url, d): + if url not in urldata: + ud = FetchData() + (ud.type, ud.host, ud.path, ud.user, ud.pswd, ud.parm) = bb.decodeurl(data.expand(url, d)) + ud.date = Fetch.getSRCDate(d) for m in methods: - m.data = d - if m.supports(u, d): - m.urls.append(u) + if m.supports(url, ud, d): + ud.localpath = m.localpath(url, ud, d) + ud.md5 = ud.localpath + '.md5' + # if user sets localpath for file, use it instead. + if "localpath" in ud.parm: + ud.localpath = ud.parm["localpath"] + ud.method = m + break + urldata[url] = ud + return urldata[url] def go(d): """Fetch all urls""" for m in methods: - if m.urls: - m.go(d) + for u in m.urls: + ud = urldata[u] + if ud.localfile and not m.forcefetch(u, ud, d) and os.path.exists(urldata[u].md5): + # File already present along with md5 stamp file + # Touch md5 file to show activity + os.utime(ud.md5, None) + continue + # RP - is olddir needed? + # olddir = os.path.abspath(os.getcwd()) + m.go(u, ud , d) + # os.chdir(olddir) + if ud.localfile and not m.forcefetch(u, ud, d): + Fetch.write_md5sum(u, ud, d) def localpaths(d): """Return a list of the local filenames, assuming successful fetch""" local = [] for m in methods: for u in m.urls: - local.append(m.localpath(u, d)) + local.append(urldata[u].localpath) return local def localpath(url, d): - for m in methods: - if m.supports(url, d): - return m.localpath(url, d) + ud = initdata(url, d) + if ud.method: + return ud.localpath return url +class FetchData(object): + """Class for fetcher variable store""" + def __init__(self): + self.localfile = "" + + class Fetch(object): """Base class for 'fetch'ing data""" def __init__(self, urls = []): self.urls = [] - for url in urls: - if self.supports(bb.decodeurl(url), d) is 1: - self.urls.append(url) - def supports(url, d): - """Check to see if this fetch class supports a given url. - Expects supplied url in list form, as outputted by bb.decodeurl(). + def supports(self, url, urldata, d): + """ + Check to see if this fetch class supports a given url. """ return 0 - supports = staticmethod(supports) - def localpath(url, d): - """Return the local filename of a given url assuming a successful fetch. + def localpath(self, url, urldata, d): + """ + Return the local filename of a given url assuming a successful fetch. + Can also setup variables in urldata for use in go (saving code duplication + and duplicate code execution) """ return url - localpath = staticmethod(localpath) def setUrls(self, urls): self.__urls = urls @@ -137,16 +172,17 @@ class Fetch(object): urls = property(getUrls, setUrls, None, "Urls property") - def setData(self, data): - self.__data = data - - def getData(self): - return self.__data - - data = property(getData, setData, None, "Data property") + def forcefetch(self, url, urldata, d): + """ + Force a fetch, even if localpath exists? + """ + return False - def go(self, urls = []): - """Fetch urls""" + def go(self, url, urldata, d): + """ + Fetch urls + Assumes localpath was called first + """ raise NoMethodError("Missing implementation for url") def getSRCDate(d): @@ -155,7 +191,12 @@ class Fetch(object): d the bb.data module """ - return data.getVar("SRCDATE", d, 1) or data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1 ) + pn = data.getVar("PN", d, 1) + + if pn: + return data.getVar("SRCDATE_%s" % pn, d, 1) or data.getVar("CVSDATE_%s" % pn, d, 1) or data.getVar("DATE", d, 1) + + return data.getVar("SRCDATE", d, 1) or data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1) getSRCDate = staticmethod(getSRCDate) def try_mirror(d, tarfn): @@ -168,6 +209,11 @@ class Fetch(object): d Is a bb.data instance tarfn is the name of the tarball """ + tarpath = os.path.join(data.getVar("DL_DIR", d, 1), tarfn) + if os.access(tarpath, os.R_OK): + bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists, skipping checkout." % tarfn) + return True + pn = data.getVar('PN', d, True) src_tarball_stash = None if pn: @@ -176,36 +222,45 @@ class Fetch(object): for stash in src_tarball_stash: fetchcmd = data.getVar("FETCHCOMMAND_mirror", d, True) or data.getVar("FETCHCOMMAND_wget", d, True) uri = stash + tarfn - bb.note("fetch " + uri) + bb.msg.note(1, bb.msg.domain.Fetcher, "fetch " + uri) fetchcmd = fetchcmd.replace("${URI}", uri) ret = os.system(fetchcmd) if ret == 0: - bb.note("Fetched %s from tarball stash, skipping checkout" % tarfn) + bb.msg.note(1, bb.msg.domain.Fetcher, "Fetched %s from tarball stash, skipping checkout" % tarfn) return True return False try_mirror = staticmethod(try_mirror) - def check_for_tarball(d, tarfn, dldir, date): + def verify_md5sum(ud, got_sum): """ - Check for a local copy then check the tarball stash. - Both checks are skipped if date == 'now'. - - d Is a bb.data instance - tarfn is the name of the tarball - date is the SRCDATE + Verify the md5sum we wanted with the one we got """ - if "now" != date: - dl = os.path.join(dldir, tarfn) - if os.access(dl, os.R_OK): - bb.debug(1, "%s already exists, skipping checkout." % tarfn) - return True - - # try to use the tarball stash - if Fetch.try_mirror(d, tarfn): - return True - return False - check_for_tarball = staticmethod(check_for_tarball) - + wanted_sum = None + if 'md5sum' in ud.parm: + wanted_sum = ud.parm['md5sum'] + if not wanted_sum: + return True + + return wanted_sum == got_sum + verify_md5sum = staticmethod(verify_md5sum) + + def write_md5sum(url, ud, d): + if bb.which(data.getVar('PATH', d), 'md5sum'): + try: + md5pipe = os.popen('md5sum ' + ud.localpath) + md5data = (md5pipe.readline().split() or [ "" ])[0] + md5pipe.close() + except OSError: + md5data = "" + + # verify the md5sum + if not Fetch.verify_md5sum(ud, md5data): + raise MD5SumError(url) + + md5out = file(ud.md5, 'w') + md5out.write(md5data) + md5out.close() + write_md5sum = staticmethod(write_md5sum) import cvs import git @@ -214,6 +269,7 @@ import svn import wget import svk import ssh +import perforce methods.append(cvs.Cvs()) methods.append(git.Git()) @@ -222,3 +278,4 @@ methods.append(svn.Svn()) methods.append(wget.Wget()) methods.append(svk.Svk()) methods.append(ssh.SSH()) +methods.append(perforce.Perforce()) diff --git a/bitbake/lib/bb/fetch/cvs.py b/bitbake/lib/bb/fetch/cvs.py index 0b2477560a..3bdac177eb 100644 --- a/bitbake/lib/bb/fetch/cvs.py +++ b/bitbake/lib/bb/fetch/cvs.py @@ -33,164 +33,119 @@ from bb.fetch import FetchError from bb.fetch import MissingParameterError class Cvs(Fetch): - """Class to fetch a module or modules from cvs repositories""" - def supports(url, d): - """Check to see if a given url can be fetched with cvs. - Expects supplied url in list form, as outputted by bb.decodeurl(). + """ + Class to fetch a module or modules from cvs repositories + """ + def supports(self, url, ud, d): """ - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d)) - return type in ['cvs', 'pserver'] - supports = staticmethod(supports) - - def localpath(url, d): - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d)) - if "localpath" in parm: -# if user overrides local path, use it. - return parm["localpath"] + Check to see if a given url can be fetched with cvs. + """ + return ud.type in ['cvs', 'pserver'] - if not "module" in parm: + def localpath(self, url, ud, d): + if not "module" in ud.parm: raise MissingParameterError("cvs method needs a 'module' parameter") - else: - module = parm["module"] - if 'tag' in parm: - tag = parm['tag'] - else: - tag = "" - if 'date' in parm: - date = parm['date'] - else: - if not tag: - date = Fetch.getSRCDate(d) - else: - date = "" + ud.module = ud.parm["module"] + + ud.tag = "" + if 'tag' in ud.parm: + ud.tag = ud.parm['tag'] + + # Override the default date in certain cases + if 'date' in ud.parm: + ud.date = ud.parm['date'] + elif ud.tag: + ud.date = "" + + ud.localfile = data.expand('%s_%s_%s_%s.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.tag, ud.date), d) + + return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile) - return os.path.join(data.getVar("DL_DIR", d, 1),data.expand('%s_%s_%s_%s.tar.gz' % ( module.replace('/', '.'), host, tag, date), d)) - localpath = staticmethod(localpath) + def forcefetch(self, url, ud, d): + if (ud.date == "now"): + return True + return False - def go(self, d, urls = []): - """Fetch urls""" - if not urls: - urls = self.urls + def go(self, loc, ud, d): + + # try to use the tarball stash + if not self.forcefetch(loc, ud, d) and Fetch.try_mirror(d, ud.localfile): + bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists or was mirrored, skipping cvs checkout." % ud.localpath) + return + + method = "pserver" + if "method" in ud.parm: + method = ud.parm["method"] + + localdir = ud.module + if "localdir" in ud.parm: + localdir = ud.parm["localdir"] + + cvs_rsh = None + if method == "ext": + if "rsh" in ud.parm: + cvs_rsh = ud.parm["rsh"] + + if method == "dir": + cvsroot = ud.path + else: + cvsroot = ":" + method + ":" + ud.user + if ud.pswd: + cvsroot += ":" + ud.pswd + cvsroot += "@" + ud.host + ":" + ud.path + + options = [] + if ud.date: + options.append("-D %s" % ud.date) + if ud.tag: + options.append("-r %s" % ud.tag) localdata = data.createCopy(d) data.setVar('OVERRIDES', "cvs:%s" % data.getVar('OVERRIDES', localdata), localdata) data.update_data(localdata) - for loc in urls: - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(loc, localdata)) - if not "module" in parm: - raise MissingParameterError("cvs method needs a 'module' parameter") - else: - module = parm["module"] - - dlfile = self.localpath(loc, localdata) - dldir = data.getVar('DL_DIR', localdata, 1) -# if local path contains the cvs -# module, consider the dir above it to be the -# download directory -# pos = dlfile.find(module) -# if pos: -# dldir = dlfile[:pos] -# else: -# dldir = os.path.dirname(dlfile) - -# setup cvs options - options = [] - if 'tag' in parm: - tag = parm['tag'] - else: - tag = "" - - if 'date' in parm: - date = parm['date'] - else: - if not tag: - date = Fetch.getSRCDate(d) - else: - date = "" - - if "method" in parm: - method = parm["method"] - else: - method = "pserver" - - if "localdir" in parm: - localdir = parm["localdir"] - else: - localdir = module - - cvs_rsh = None - if method == "ext": - if "rsh" in parm: - cvs_rsh = parm["rsh"] - - tarfn = data.expand('%s_%s_%s_%s.tar.gz' % (module.replace('/', '.'), host, tag, date), localdata) - data.setVar('TARFILES', dlfile, localdata) - data.setVar('TARFN', tarfn, localdata) - - if Fetch.check_for_tarball(d, tarfn, dldir, date): - continue - - if date: - options.append("-D %s" % date) - if tag: - options.append("-r %s" % tag) - - olddir = os.path.abspath(os.getcwd()) - os.chdir(data.expand(dldir, localdata)) - -# setup cvsroot - if method == "dir": - cvsroot = path - else: - cvsroot = ":" + method + ":" + user - if pswd: - cvsroot += ":" + pswd - cvsroot += "@" + host + ":" + path - - data.setVar('CVSROOT', cvsroot, localdata) - data.setVar('CVSCOOPTS', " ".join(options), localdata) - data.setVar('CVSMODULE', module, localdata) - cvscmd = data.getVar('FETCHCOMMAND', localdata, 1) - cvsupdatecmd = data.getVar('UPDATECOMMAND', localdata, 1) - - if cvs_rsh: - cvscmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvscmd) - cvsupdatecmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvsupdatecmd) - -# create module directory - bb.debug(2, "Fetch: checking for module directory") - pkg=data.expand('${PN}', d) - pkgdir=os.path.join(data.expand('${CVSDIR}', localdata), pkg) - moddir=os.path.join(pkgdir,localdir) - if os.access(os.path.join(moddir,'CVS'), os.R_OK): - bb.note("Update " + loc) -# update sources there - os.chdir(moddir) - myret = os.system(cvsupdatecmd) - else: - bb.note("Fetch " + loc) -# check out sources there - bb.mkdirhier(pkgdir) - os.chdir(pkgdir) - bb.debug(1, "Running %s" % cvscmd) - myret = os.system(cvscmd) - - if myret != 0 or not os.access(moddir, os.R_OK): - try: - os.rmdir(moddir) - except OSError: - pass - raise FetchError(module) - + data.setVar('CVSROOT', cvsroot, localdata) + data.setVar('CVSCOOPTS', " ".join(options), localdata) + data.setVar('CVSMODULE', ud.module, localdata) + cvscmd = data.getVar('FETCHCOMMAND', localdata, 1) + cvsupdatecmd = data.getVar('UPDATECOMMAND', localdata, 1) + + if cvs_rsh: + cvscmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvscmd) + cvsupdatecmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvsupdatecmd) + + # create module directory + bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: checking for module directory") + pkg = data.expand('${PN}', d) + pkgdir = os.path.join(data.expand('${CVSDIR}', localdata), pkg) + moddir = os.path.join(pkgdir,localdir) + if os.access(os.path.join(moddir,'CVS'), os.R_OK): + bb.msg.note(1, bb.msg.domain.Fetcher, "Update " + loc) + # update sources there os.chdir(moddir) - os.chdir('..') -# tar them up to a defined filename - myret = os.system("tar -czf %s %s" % (os.path.join(dldir,tarfn), os.path.basename(moddir))) - if myret != 0: - try: - os.unlink(tarfn) - except OSError: - pass - os.chdir(olddir) - del localdata + myret = os.system(cvsupdatecmd) + else: + bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc) + # check out sources there + bb.mkdirhier(pkgdir) + os.chdir(pkgdir) + bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % cvscmd) + myret = os.system(cvscmd) + + if myret != 0 or not os.access(moddir, os.R_OK): + try: + os.rmdir(moddir) + except OSError: + pass + raise FetchError(ud.module) + + os.chdir(moddir) + os.chdir('..') + # tar them up to a defined filename + myret = os.system("tar -czf %s %s" % (ud.localpath, os.path.basename(moddir))) + if myret != 0: + try: + os.unlink(ud.localpath) + except OSError: + pass + raise FetchError(ud.module) diff --git a/bitbake/lib/bb/fetch/git.py b/bitbake/lib/bb/fetch/git.py index 49235c141e..75a7629223 100644 --- a/bitbake/lib/bb/fetch/git.py +++ b/bitbake/lib/bb/fetch/git.py @@ -37,7 +37,7 @@ def prunedir(topdir): def rungitcmd(cmd,d): - bb.debug(1, "Running %s" % cmd) + bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % cmd) # Need to export PATH as git is likely to be in metadata paths # rather than host provided @@ -48,108 +48,80 @@ def rungitcmd(cmd,d): if myret != 0: raise FetchError("Git: %s failed" % pathcmd) -def gettag(parm): - if 'tag' in parm: - tag = parm['tag'] - else: - tag = "" - if not tag: - tag = "master" - - return tag - -def getprotocol(parm): - if 'protocol' in parm: - proto = parm['protocol'] - else: - proto = "" - if not proto: - proto = "rsync" - - return proto - -def localfile(url, d): - """Return the filename to cache the checkout in""" - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d)) - - #if user sets localpath for file, use it instead. - if "localpath" in parm: - return parm["localpath"] - - tag = gettag(parm) - - return data.expand('git_%s%s_%s.tar.gz' % (host, path.replace('/', '.'), tag), d) - class Git(Fetch): """Class to fetch a module or modules from git repositories""" - def supports(url, d): - """Check to see if a given url can be fetched with cvs. - Expects supplied url in list form, as outputted by bb.decodeurl(). + def supports(self, url, ud, d): + """ + Check to see if a given url can be fetched with cvs. """ - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d)) - return type in ['git'] - supports = staticmethod(supports) + return ud.type in ['git'] - def localpath(url, d): + def localpath(self, url, ud, d): - return os.path.join(data.getVar("DL_DIR", d, 1), localfile(url, d)) + ud.proto = "rsync" + if 'protocol' in ud.parm: + ud.proto = ud.parm['protocol'] - localpath = staticmethod(localpath) + ud.tag = "master" + if 'tag' in ud.parm: + ud.tag = ud.parm['tag'] - def go(self, d, urls = []): - """Fetch urls""" - if not urls: - urls = self.urls + ud.localfile = data.expand('git_%s%s_%s.tar.gz' % (ud.host, ud.path.replace('/', '.'), ud.tag), d) - for loc in urls: - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(loc, d)) + return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile) - tag = gettag(parm) - proto = getprotocol(parm) + def forcefetch(self, url, ud, d): + # tag=="master" must always update + if (ud.tag == "master"): + return True + return False - gitsrcname = '%s%s' % (host, path.replace('/', '.')) + def go(self, loc, ud, d): + """Fetch url""" - repofilename = 'git_%s.tar.gz' % (gitsrcname) - repofile = os.path.join(data.getVar("DL_DIR", d, 1), repofilename) - repodir = os.path.join(data.expand('${GITDIR}', d), gitsrcname) + if not self.forcefetch(loc, ud, d) and Fetch.try_mirror(d, ud.localfile): + bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists (or was stashed). Skipping git checkout." % ud.localpath) + return - coname = '%s' % (tag) - codir = os.path.join(repodir, coname) + gitsrcname = '%s%s' % (ud.host, ud.path.replace('/', '.')) - cofile = self.localpath(loc, d) + repofilename = 'git_%s.tar.gz' % (gitsrcname) + repofile = os.path.join(data.getVar("DL_DIR", d, 1), repofilename) + repodir = os.path.join(data.expand('${GITDIR}', d), gitsrcname) - # tag=="master" must always update - if (tag != "master") and Fetch.try_mirror(d, localfile(loc, d)): - bb.debug(1, "%s already exists (or was stashed). Skipping git checkout." % cofile) - continue + coname = '%s' % (ud.tag) + codir = os.path.join(repodir, coname) - if not os.path.exists(repodir): - if Fetch.try_mirror(d, repofilename): - bb.mkdirhier(repodir) - os.chdir(repodir) - rungitcmd("tar -xzf %s" % (repofile),d) - else: - rungitcmd("git clone -n %s://%s%s %s" % (proto, host, path, repodir),d) + if not os.path.exists(repodir): + if Fetch.try_mirror(d, repofilename): + bb.mkdirhier(repodir) + os.chdir(repodir) + rungitcmd("tar -xzf %s" % (repofile),d) + else: + rungitcmd("git clone -n %s://%s%s %s" % (ud.proto, ud.host, ud.path, repodir),d) - os.chdir(repodir) - rungitcmd("git pull %s://%s%s" % (proto, host, path),d) - rungitcmd("git pull --tags %s://%s%s" % (proto, host, path),d) - rungitcmd("git prune-packed", d) - # old method of downloading tags - #rungitcmd("rsync -a --verbose --stats --progress rsync://%s%s/ %s" % (host, path, os.path.join(repodir, ".git", "")),d) + os.chdir(repodir) + rungitcmd("git pull %s://%s%s" % (ud.proto, ud.host, ud.path),d) + rungitcmd("git pull --tags %s://%s%s" % (ud.proto, ud.host, ud.path),d) + rungitcmd("git prune-packed", d) + rungitcmd("git pack-redundant --all | xargs -r rm", d) + # Remove all but the .git directory + rungitcmd("rm * -Rf", d) + # old method of downloading tags + #rungitcmd("rsync -a --verbose --stats --progress rsync://%s%s/ %s" % (ud.host, ud.path, os.path.join(repodir, ".git", "")),d) - os.chdir(repodir) - bb.note("Creating tarball of git repository") - rungitcmd("tar -czf %s %s" % (repofile, os.path.join(".", ".git", "*") ),d) + os.chdir(repodir) + bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git repository") + rungitcmd("tar -czf %s %s" % (repofile, os.path.join(".", ".git", "*") ),d) - if os.path.exists(codir): - prunedir(codir) + if os.path.exists(codir): + prunedir(codir) - bb.mkdirhier(codir) - os.chdir(repodir) - rungitcmd("git read-tree %s" % (tag),d) - rungitcmd("git checkout-index -q -f --prefix=%s -a" % (os.path.join(codir, "git", "")),d) + bb.mkdirhier(codir) + os.chdir(repodir) + rungitcmd("git read-tree %s" % (ud.tag),d) + rungitcmd("git checkout-index -q -f --prefix=%s -a" % (os.path.join(codir, "git", "")),d) - os.chdir(codir) - bb.note("Creating tarball of git checkout") - rungitcmd("tar -czf %s %s" % (cofile, os.path.join(".", "*") ),d) + os.chdir(codir) + bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git checkout") + rungitcmd("tar -czf %s %s" % (ud.localpath, os.path.join(".", "*") ),d) diff --git a/bitbake/lib/bb/fetch/local.py b/bitbake/lib/bb/fetch/local.py index 51938f823e..5224976704 100644 --- a/bitbake/lib/bb/fetch/local.py +++ b/bitbake/lib/bb/fetch/local.py @@ -31,15 +31,13 @@ from bb import data from bb.fetch import Fetch class Local(Fetch): - def supports(url, d): - """Check to see if a given url can be fetched in the local filesystem. - Expects supplied url in list form, as outputted by bb.decodeurl(). + def supports(self, url, urldata, d): """ - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d)) - return type in ['file','patch'] - supports = staticmethod(supports) + Check to see if a given url can be fetched with cvs. + """ + return urldata.type in ['file','patch'] - def localpath(url, d): + def localpath(self, url, urldata, d): """Return the local filename of a given url assuming a successful fetch. """ path = url.split("://")[1] @@ -52,10 +50,10 @@ class Local(Fetch): filesdir = data.getVar('FILESDIR', d, 1) if filesdir: newpath = os.path.join(filesdir, path) + # We don't set localfile as for this fetcher the file is already local! return newpath - localpath = staticmethod(localpath) - def go(self, urls = []): + def go(self, url, urldata, d): """Fetch urls (no-op for Local method)""" -# no need to fetch local files, we'll deal with them in place. + # no need to fetch local files, we'll deal with them in place. return 1 diff --git a/bitbake/lib/bb/fetch/perforce.py b/bitbake/lib/bb/fetch/perforce.py new file mode 100644 index 0000000000..88acf69951 --- /dev/null +++ b/bitbake/lib/bb/fetch/perforce.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python +# ex:ts=4:sw=4:sts=4:et +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +""" +BitBake 'Fetch' implementations + +Classes for obtaining upstream sources for the +BitBake build tools. + +Copyright (C) 2003, 2004 Chris Larson + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +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., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA. + +Based on functions from the base bb module, Copyright 2003 Holger Schurig +""" + +import os, re +import bb +from bb import data +from bb.fetch import Fetch +from bb.fetch import FetchError +from bb.fetch import MissingParameterError + +class Perforce(Fetch): + def supports(self, url, ud, d): + return ud.type in ['p4'] + + def doparse(url,d): + parm=[] + path = url.split("://")[1] + delim = path.find("@"); + if delim != -1: + (user,pswd,host,port) = path.split('@')[0].split(":") + path = path.split('@')[1] + else: + (host,port) = data.getVar('P4PORT', d).split(':') + user = "" + pswd = "" + + if path.find(";") != -1: + keys=[] + values=[] + plist = path.split(';') + for item in plist: + if item.count('='): + (key,value) = item.split('=') + keys.append(key) + values.append(value) + + parm = dict(zip(keys,values)) + path = "//" + path.split(';')[0] + host += ":%s" % (port) + parm["cset"] = Perforce.getcset(d, path, host, user, pswd, parm) + + return host,path,user,pswd,parm + doparse = staticmethod(doparse) + + def getcset(d, depot,host,user,pswd,parm): + if "cset" in parm: + return parm["cset"]; + if user: + data.setVar('P4USER', user, d) + if pswd: + data.setVar('P4PASSWD', pswd, d) + if host: + data.setVar('P4PORT', host, d) + + p4date = data.getVar("P4DATE", d, 1) + if "revision" in parm: + depot += "#%s" % (parm["revision"]) + elif "label" in parm: + depot += "@%s" % (parm["label"]) + elif p4date: + depot += "@%s" % (p4date) + + p4cmd = data.getVar('FETCHCOMMAND_p4', d, 1) + bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s changes -m 1 %s" % (p4cmd, depot)) + p4file = os.popen("%s changes -m 1 %s" % (p4cmd,depot)) + cset = p4file.readline().strip() + bb.msg.debug(1, bb.msg.domain.Fetcher, "READ %s" % (cset)) + if not cset: + return -1 + + return cset.split(' ')[1] + getcset = staticmethod(getcset) + + def localpath(self, url, ud, d): + + (host,path,user,pswd,parm) = Perforce.doparse(url,d) + + # If a label is specified, we use that as our filename + + if "label" in parm: + ud.localfile = "%s.tar.gz" % (parm["label"]) + return os.path.join(data.getVar("DL_DIR", d, 1), ud.localfile) + + base = path + which = path.find('/...') + if which != -1: + base = path[:which] + + if base[0] == "/": + base = base[1:] + + cset = Perforce.getcset(d, path, host, user, pswd, parm) + + ud.localfile = data.expand('%s+%s+%s.tar.gz' % (host,base.replace('/', '.'), cset), d) + + return os.path.join(data.getVar("DL_DIR", d, 1), ud.localfile) + + def go(self, loc, ud, d): + """ + Fetch urls + """ + + # try to use the tarball stash + if not self.forcefetch(loc, ud, d) and Fetch.try_mirror(d, ud.localfile): + bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists or was mirrored, skipping perforce checkout." % ud.localpath) + return + + (host,depot,user,pswd,parm) = Perforce.doparse(loc, d) + + if depot.find('/...') != -1: + path = depot[:depot.find('/...')] + else: + path = depot + + if "module" in parm: + module = parm["module"] + else: + module = os.path.basename(path) + + localdata = data.createCopy(d) + data.setVar('OVERRIDES', "p4:%s" % data.getVar('OVERRIDES', localdata), localdata) + data.update_data(localdata) + + # Get the p4 command + if user: + data.setVar('P4USER', user, localdata) + + if pswd: + data.setVar('P4PASSWD', pswd, localdata) + + if host: + data.setVar('P4PORT', host, localdata) + + p4cmd = data.getVar('FETCHCOMMAND', localdata, 1) + + # create temp directory + bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: creating temporary directory") + bb.mkdirhier(data.expand('${WORKDIR}', localdata)) + data.setVar('TMPBASE', data.expand('${WORKDIR}/oep4.XXXXXX', localdata), localdata) + tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false") + tmpfile = tmppipe.readline().strip() + if not tmpfile: + bb.error("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.") + raise FetchError(module) + + if "label" in parm: + depot = "%s@%s" % (depot,parm["label"]) + else: + cset = Perforce.getcset(d, depot, host, user, pswd, parm) + depot = "%s@%s" % (depot,cset) + + os.chdir(tmpfile) + bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc) + bb.msg.note(1, bb.msg.domain.Fetcher, "%s files %s" % (p4cmd, depot)) + p4file = os.popen("%s files %s" % (p4cmd, depot)) + + if not p4file: + bb.error("Fetch: unable to get the P4 files from %s" % (depot)) + raise FetchError(module) + + count = 0 + + for file in p4file: + list = file.split() + + if list[2] == "delete": + continue + + dest = list[0][len(path)+1:] + where = dest.find("#") + + os.system("%s print -o %s/%s %s" % (p4cmd, module,dest[:where],list[0])) + count = count + 1 + + if count == 0: + bb.error("Fetch: No files gathered from the P4 fetch") + raise FetchError(module) + + myret = os.system("tar -czf %s %s" % (ud.localpath, module)) + if myret != 0: + try: + os.unlink(ud.localpath) + except OSError: + pass + raise FetchError(module) + # cleanup + os.system('rm -rf %s' % tmpfile) + + diff --git a/bitbake/lib/bb/fetch/ssh.py b/bitbake/lib/bb/fetch/ssh.py index 57874d5ba9..e5f69e33e7 100644 --- a/bitbake/lib/bb/fetch/ssh.py +++ b/bitbake/lib/bb/fetch/ssh.py @@ -64,59 +64,55 @@ __pattern__ = re.compile(r''' class SSH(Fetch): '''Class to fetch a module or modules via Secure Shell''' - def supports(self, url, d): + def supports(self, url, urldata, d): return __pattern__.match(url) != None - def localpath(self, url, d): + def localpath(self, url, urldata, d): m = __pattern__.match(url) path = m.group('path') host = m.group('host') - lpath = os.path.join(data.getVar('DL_DIR', d, 1), host, os.path.basename(path)) + lpath = os.path.join(data.getVar('DL_DIR', d, True), host, os.path.basename(path)) return lpath - def go(self, d, urls = []): - if not urls: - urls = self.urls - - for url in urls: - dldir = data.getVar('DL_DIR', d, 1) - - m = __pattern__.match(url) - path = m.group('path') - host = m.group('host') - port = m.group('port') - user = m.group('user') - password = m.group('pass') - - ldir = os.path.join(dldir, host) - lpath = os.path.join(ldir, os.path.basename(path)) - - if not os.path.exists(ldir): - os.makedirs(ldir) - - if port: - port = '-P %s' % port - else: - port = '' - - if user: - fr = user - if password: - fr += ':%s' % password - fr += '@%s' % host - else: - fr = host - fr += ':%s' % path - - - import commands - cmd = 'scp -B -r %s %s %s/' % ( - port, - commands.mkarg(fr), - commands.mkarg(ldir) - ) - - (exitstatus, output) = commands.getstatusoutput(cmd) - if exitstatus != 0: - print output - raise FetchError('Unable to fetch %s' % url) + def go(self, url, urldata, d): + dldir = data.getVar('DL_DIR', d, 1) + + m = __pattern__.match(url) + path = m.group('path') + host = m.group('host') + port = m.group('port') + user = m.group('user') + password = m.group('pass') + + ldir = os.path.join(dldir, host) + lpath = os.path.join(ldir, os.path.basename(path)) + + if not os.path.exists(ldir): + os.makedirs(ldir) + + if port: + port = '-P %s' % port + else: + port = '' + + if user: + fr = user + if password: + fr += ':%s' % password + fr += '@%s' % host + else: + fr = host + fr += ':%s' % path + + + import commands + cmd = 'scp -B -r %s %s %s/' % ( + port, + commands.mkarg(fr), + commands.mkarg(ldir) + ) + + (exitstatus, output) = commands.getstatusoutput(cmd) + if exitstatus != 0: + print output + raise FetchError('Unable to fetch %s' % url) diff --git a/bitbake/lib/bb/fetch/svk.py b/bitbake/lib/bb/fetch/svk.py index 19103213cd..29270ab3d8 100644 --- a/bitbake/lib/bb/fetch/svk.py +++ b/bitbake/lib/bb/fetch/svk.py @@ -42,112 +42,76 @@ from bb.fetch import MissingParameterError class Svk(Fetch): """Class to fetch a module or modules from svk repositories""" - def supports(url, d): - """Check to see if a given url can be fetched with svk. - Expects supplied url in list form, as outputted by bb.decodeurl(). + def supports(self, url, ud, d): """ - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d)) - return type in ['svk'] - supports = staticmethod(supports) - - def localpath(url, d): - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d)) - if "localpath" in parm: -# if user overrides local path, use it. - return parm["localpath"] + Check to see if a given url can be fetched with cvs. + """ + return ud.type in ['svk'] - if not "module" in parm: + def localpath(self, url, ud, d): + if not "module" in ud.parm: raise MissingParameterError("svk method needs a 'module' parameter") else: - module = parm["module"] - if 'rev' in parm: - revision = parm['rev'] - else: - revision = "" + ud.module = ud.parm["module"] + + ud.revision = "" + if 'rev' in ud.parm: + ud.revision = ud.parm['rev'] + + ud.localfile = data.expand('%s_%s_%s_%s_%s.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.path.replace('/', '.'), ud.revision, ud.date), d) - date = Fetch.getSRCDate(d) + return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile) - return os.path.join(data.getVar("DL_DIR", d, 1),data.expand('%s_%s_%s_%s_%s.tar.gz' % ( module.replace('/', '.'), host, path.replace('/', '.'), revision, date), d)) - localpath = staticmethod(localpath) + def forcefetch(self, url, ud, d): + if (ud.date == "now"): + return True + return False - def go(self, d, urls = []): + def go(self, loc, ud, d): """Fetch urls""" - if not urls: - urls = self.urls + if not self.forcefetch(loc, ud, d) and Fetch.try_mirror(d, ud.localfile): + return + + svkroot = ud.host + ud.path + + svkcmd = "svk co -r {%s} %s/%s" % (date, svkroot, ud.module) + + if ud.revision: + svkcmd = "svk co -r %s/%s" % (ud.revision, svkroot, ud.module) + + # create temp directory localdata = data.createCopy(d) - data.setVar('OVERRIDES', "svk:%s" % data.getVar('OVERRIDES', localdata), localdata) data.update_data(localdata) - - for loc in urls: - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(loc, localdata)) - if not "module" in parm: - raise MissingParameterError("svk method needs a 'module' parameter") - else: - module = parm["module"] - - dlfile = self.localpath(loc, localdata) - dldir = data.getVar('DL_DIR', localdata, 1) - -# setup svk options - options = [] - if 'rev' in parm: - revision = parm['rev'] - else: - revision = "" - - date = Fetch.getSRCDate(d) - tarfn = data.expand('%s_%s_%s_%s_%s.tar.gz' % (module.replace('/', '.'), host, path.replace('/', '.'), revision, date), localdata) - data.setVar('TARFILES', dlfile, localdata) - data.setVar('TARFN', tarfn, localdata) - - if Fetch.check_for_tarball(d, tarfn, dldir, date): - continue - - olddir = os.path.abspath(os.getcwd()) - os.chdir(data.expand(dldir, localdata)) - - svkroot = host + path - - data.setVar('SVKROOT', svkroot, localdata) - data.setVar('SVKCOOPTS', " ".join(options), localdata) - data.setVar('SVKMODULE', module, localdata) - svkcmd = "svk co -r {%s} %s/%s" % (date, svkroot, module) - - if revision: - svkcmd = "svk co -r %s/%s" % (revision, svkroot, module) - -# create temp directory - bb.debug(2, "Fetch: creating temporary directory") - bb.mkdirhier(data.expand('${WORKDIR}', localdata)) - data.setVar('TMPBASE', data.expand('${WORKDIR}/oesvk.XXXXXX', localdata), localdata) - tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false") - tmpfile = tmppipe.readline().strip() - if not tmpfile: - bb.error("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.") - raise FetchError(module) - -# check out sources there - os.chdir(tmpfile) - bb.note("Fetch " + loc) - bb.debug(1, "Running %s" % svkcmd) - myret = os.system(svkcmd) - if myret != 0: - try: - os.rmdir(tmpfile) - except OSError: - pass - raise FetchError(module) - - os.chdir(os.path.join(tmpfile, os.path.dirname(module))) -# tar them up to a defined filename - myret = os.system("tar -czf %s %s" % (os.path.join(dldir,tarfn), os.path.basename(module))) - if myret != 0: - try: - os.unlink(tarfn) - except OSError: - pass -# cleanup - os.system('rm -rf %s' % tmpfile) - os.chdir(olddir) - del localdata + bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: creating temporary directory") + bb.mkdirhier(data.expand('${WORKDIR}', localdata)) + data.setVar('TMPBASE', data.expand('${WORKDIR}/oesvk.XXXXXX', localdata), localdata) + tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false") + tmpfile = tmppipe.readline().strip() + if not tmpfile: + bb.msg.error(bb.msg.domain.Fetcher, "Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.") + raise FetchError(ud.module) + + # check out sources there + os.chdir(tmpfile) + bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc) + bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % svkcmd) + myret = os.system(svkcmd) + if myret != 0: + try: + os.rmdir(tmpfile) + except OSError: + pass + raise FetchError(ud.module) + + os.chdir(os.path.join(tmpfile, os.path.dirname(ud.module))) + # tar them up to a defined filename + myret = os.system("tar -czf %s %s" % (ud.localpath, os.path.basename(ud.module))) + if myret != 0: + try: + os.unlink(ud.localpath) + except OSError: + pass + raise FetchError(ud.module) + # cleanup + os.system('rm -rf %s' % tmpfile) diff --git a/bitbake/lib/bb/fetch/svn.py b/bitbake/lib/bb/fetch/svn.py index d1a959371b..b95de2a79b 100644 --- a/bitbake/lib/bb/fetch/svn.py +++ b/bitbake/lib/bb/fetch/svn.py @@ -26,6 +26,7 @@ Based on functions from the base bb module, Copyright 2003 Holger Schurig """ import os, re +import sys import bb from bb import data from bb.fetch import Fetch @@ -34,136 +35,98 @@ from bb.fetch import MissingParameterError class Svn(Fetch): """Class to fetch a module or modules from svn repositories""" - def supports(url, d): - """Check to see if a given url can be fetched with svn. - Expects supplied url in list form, as outputted by bb.decodeurl(). + def supports(self, url, ud, d): """ - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d)) - return type in ['svn'] - supports = staticmethod(supports) - - def localpath(url, d): - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d)) - if "localpath" in parm: -# if user overrides local path, use it. - return parm["localpath"] + Check to see if a given url can be fetched with svn. + """ + return ud.type in ['svn'] - if not "module" in parm: + def localpath(self, url, ud, d): + if not "module" in ud.parm: raise MissingParameterError("svn method needs a 'module' parameter") else: - module = parm["module"] - if 'rev' in parm: - revision = parm['rev'] - else: - revision = "" + ud.module = ud.parm["module"] + + ud.revision = "" + if 'rev' in ud.parm: + ud.revision = ud.parm['rev'] + + ud.localfile = data.expand('%s_%s_%s_%s_%s.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.path.replace('/', '.'), ud.revision, ud.date), d) + + return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile) - date = Fetch.getSRCDate(d) + def forcefetch(self, url, ud, d): + if (ud.date == "now"): + return True + return False - return os.path.join(data.getVar("DL_DIR", d, 1),data.expand('%s_%s_%s_%s_%s.tar.gz' % ( module.replace('/', '.'), host, path.replace('/', '.'), revision, date), d)) - localpath = staticmethod(localpath) + def go(self, loc, ud, d): + """Fetch url""" - def go(self, d, urls = []): - """Fetch urls""" - if not urls: - urls = self.urls + # try to use the tarball stash + if not self.forcefetch(loc, ud, d) and Fetch.try_mirror(d, ud.localfile): + bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists or was mirrored, skipping svn checkout." % ud.localpath) + return + + proto = "svn" + if "proto" in ud.parm: + proto = ud.parm["proto"] + + svn_rsh = None + if proto == "svn+ssh" and "rsh" in ud.parm: + svn_rsh = ud.parm["rsh"] + + svnroot = ud.host + ud.path + + # either use the revision, or SRCDATE in braces, or nothing for SRCDATE = "now" + options = [] + if ud.revision: + options.append("-r %s" % ud.revision) + elif ud.date != "now": + options.append("-r {%s}" % ud.date) localdata = data.createCopy(d) data.setVar('OVERRIDES', "svn:%s" % data.getVar('OVERRIDES', localdata), localdata) data.update_data(localdata) - for loc in urls: - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(loc, localdata)) - if not "module" in parm: - raise MissingParameterError("svn method needs a 'module' parameter") - else: - module = parm["module"] - - dlfile = self.localpath(loc, localdata) - dldir = data.getVar('DL_DIR', localdata, 1) -# if local path contains the svn -# module, consider the dir above it to be the -# download directory -# pos = dlfile.find(module) -# if pos: -# dldir = dlfile[:pos] -# else: -# dldir = os.path.dirname(dlfile) - -# setup svn options - options = [] - if 'rev' in parm: - revision = parm['rev'] - else: - revision = "" - - date = Fetch.getSRCDate(d) - - if "proto" in parm: - proto = parm["proto"] - else: - proto = "svn" - - svn_rsh = None - if proto == "svn+ssh" and "rsh" in parm: - svn_rsh = parm["rsh"] - - tarfn = data.expand('%s_%s_%s_%s_%s.tar.gz' % (module.replace('/', '.'), host, path.replace('/', '.'), revision, date), localdata) - data.setVar('TARFILES', dlfile, localdata) - data.setVar('TARFN', tarfn, localdata) - - if Fetch.check_for_tarball(d, tarfn, dldir, date): - continue - - olddir = os.path.abspath(os.getcwd()) - os.chdir(data.expand(dldir, localdata)) - - svnroot = host + path - - data.setVar('SVNROOT', svnroot, localdata) - data.setVar('SVNCOOPTS', " ".join(options), localdata) - data.setVar('SVNMODULE', module, localdata) - svncmd = data.getVar('FETCHCOMMAND', localdata, 1) - svncmd = "svn co -r {%s} %s://%s/%s" % (date, proto, svnroot, module) - - if revision: - svncmd = "svn co -r %s %s://%s/%s" % (revision, proto, svnroot, module) - elif date == "now": - svncmd = "svn co %s://%s/%s" % (proto, svnroot, module) - - if svn_rsh: - svncmd = "svn_RSH=\"%s\" %s" % (svn_rsh, svncmd) - -# create temp directory - bb.debug(2, "Fetch: creating temporary directory") - bb.mkdirhier(data.expand('${WORKDIR}', localdata)) - data.setVar('TMPBASE', data.expand('${WORKDIR}/oesvn.XXXXXX', localdata), localdata) - tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false") - tmpfile = tmppipe.readline().strip() - if not tmpfile: - bb.error("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.") - raise FetchError(module) - -# check out sources there - os.chdir(tmpfile) - bb.note("Fetch " + loc) - bb.debug(1, "Running %s" % svncmd) + data.setVar('SVNROOT', "%s://%s/%s" % (proto, svnroot, ud.module), localdata) + data.setVar('SVNCOOPTS', " ".join(options), localdata) + data.setVar('SVNMODULE', ud.module, localdata) + svncmd = data.getVar('FETCHCOMMAND', localdata, 1) + svnupcmd = data.getVar('UPDATECOMMAND', localdata, 1) + + if svn_rsh: + svncmd = "svn_RSH=\"%s\" %s" % (svn_rsh, svncmd) + svnupcmd = "svn_RSH=\"%s\" %s" % (svn_rsh, svnupcmd) + + pkg = data.expand('${PN}', d) + pkgdir = os.path.join(data.expand('${SVNDIR}', localdata), pkg) + moddir = os.path.join(pkgdir, ud.module) + bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: checking for module directory '" + moddir + "'") + + if os.access(os.path.join(moddir, '.svn'), os.R_OK): + bb.msg.note(1, bb.msg.domain.Fetcher, "Update " + loc) + # update sources there + os.chdir(moddir) + bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % svnupcmd) + myret = os.system(svnupcmd) + else: + bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc) + # check out sources there + bb.mkdirhier(pkgdir) + os.chdir(pkgdir) + bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % svncmd) myret = os.system(svncmd) - if myret != 0: - try: - os.rmdir(tmpfile) - except OSError: - pass - raise FetchError(module) - - os.chdir(os.path.join(tmpfile, os.path.dirname(module))) -# tar them up to a defined filename - myret = os.system("tar -czf %s %s" % (os.path.join(dldir,tarfn), os.path.basename(module))) - if myret != 0: - try: - os.unlink(tarfn) - except OSError: - pass -# cleanup - os.system('rm -rf %s' % tmpfile) - os.chdir(olddir) - del localdata + + if myret != 0: + raise FetchError(ud.module) + + os.chdir(pkgdir) + # tar them up to a defined filename + myret = os.system("tar -czf %s %s" % (ud.localpath, os.path.basename(ud.module))) + if myret != 0: + try: + os.unlink(ud.localpath) + except OSError: + pass + raise FetchError(ud.module) diff --git a/bitbake/lib/bb/fetch/wget.py b/bitbake/lib/bb/fetch/wget.py index e47a8859be..9c9c1675a1 100644 --- a/bitbake/lib/bb/fetch/wget.py +++ b/bitbake/lib/bb/fetch/wget.py @@ -30,138 +30,70 @@ import bb from bb import data from bb.fetch import Fetch from bb.fetch import FetchError -from bb.fetch import MD5SumError from bb.fetch import uri_replace class Wget(Fetch): """Class to fetch urls via 'wget'""" - def supports(url, d): - """Check to see if a given url can be fetched using wget. - Expects supplied url in list form, as outputted by bb.decodeurl(). + def supports(self, url, ud, d): """ - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d)) - return type in ['http','https','ftp'] - supports = staticmethod(supports) - - def localpath(url, d): -# strip off parameters - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d)) - if "localpath" in parm: -# if user overrides local path, use it. - return parm["localpath"] - url = bb.encodeurl([type, host, path, user, pswd, {}]) - - return os.path.join(data.getVar("DL_DIR", d), os.path.basename(url)) - localpath = staticmethod(localpath) - - def go(self, d, urls = []): + Check to see if a given url can be fetched with cvs. + """ + return ud.type in ['http','https','ftp'] + + def localpath(self, url, ud, d): + + url = bb.encodeurl([ud.type, ud.host, ud.path, ud.user, ud.pswd, {}]) + ud.basename = os.path.basename(ud.path) + ud.localfile = data.expand(os.path.basename(url), d) + + return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile) + + def go(self, uri, ud, d): """Fetch urls""" - def md5_sum(parm, d): - """ - Return the MD5SUM associated with the to be downloaded - file. - It can return None if no md5sum is associated - """ - try: - return parm['md5sum'] - except: - return None - - def verify_md5sum(wanted_sum, got_sum): - """ - Verify the md5sum we wanted with the one we got - """ - if not wanted_sum: - return True - - return wanted_sum == got_sum - - def fetch_uri(uri, basename, dl, md5, parm, d): - # the MD5 sum we want to verify - wanted_md5sum = md5_sum(parm, d) - if os.path.exists(dl): -# file exists, but we didnt complete it.. trying again.. + def fetch_uri(uri, ud, d): + if os.path.exists(ud.localpath): + # file exists, but we didnt complete it.. trying again.. fetchcmd = data.getVar("RESUMECOMMAND", d, 1) else: fetchcmd = data.getVar("FETCHCOMMAND", d, 1) - bb.note("fetch " + uri) + bb.msg.note(1, bb.msg.domain.Fetcher, "fetch " + uri) fetchcmd = fetchcmd.replace("${URI}", uri) - fetchcmd = fetchcmd.replace("${FILE}", basename) - bb.debug(2, "executing " + fetchcmd) + fetchcmd = fetchcmd.replace("${FILE}", ud.basename) + bb.msg.debug(2, bb.msg.domain.Fetcher, "executing " + fetchcmd) ret = os.system(fetchcmd) if ret != 0: return False # check if sourceforge did send us to the mirror page - dl_dir = data.getVar("DL_DIR", d, True) - if not os.path.exists(dl): - os.system("rm %s*" % dl) # FIXME shell quote it - bb.debug(2,"sourceforge.net send us to the mirror on %s" % basename) + if not os.path.exists(ud.localpath): + os.system("rm %s*" % ud.localpath) # FIXME shell quote it + bb.msg.debug(2, bb.msg.domain.Fetcher, "sourceforge.net send us to the mirror on %s" % ud.basename) return False -# supposedly complete.. write out md5sum - if bb.which(data.getVar('PATH', d), 'md5sum'): - try: - md5pipe = os.popen('md5sum ' + dl) - md5data = (md5pipe.readline().split() or [ "" ])[0] - md5pipe.close() - except OSError: - md5data = "" - - # verify the md5sum - if not verify_md5sum(wanted_md5sum, md5data): - raise MD5SumError(uri) - - md5out = file(md5, 'w') - md5out.write(md5data) - md5out.close() return True - if not urls: - urls = self.urls - localdata = data.createCopy(d) data.setVar('OVERRIDES', "wget:" + data.getVar('OVERRIDES', localdata), localdata) data.update_data(localdata) - for uri in urls: - completed = 0 - (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(uri, localdata)) - basename = os.path.basename(path) - dl = self.localpath(uri, d) - dl = data.expand(dl, localdata) - md5 = dl + '.md5' - - if os.path.exists(md5): -# complete, nothing to see here.. - continue - - premirrors = [ i.split() for i in (data.getVar('PREMIRRORS', localdata, 1) or "").split('\n') if i ] - for (find, replace) in premirrors: - newuri = uri_replace(uri, find, replace, d) - if newuri != uri: - if fetch_uri(newuri, basename, dl, md5, parm, localdata): - completed = 1 - break - - if completed: - continue - - if fetch_uri(uri, basename, dl, md5, parm, localdata): - continue - -# try mirrors - mirrors = [ i.split() for i in (data.getVar('MIRRORS', localdata, 1) or "").split('\n') if i ] - for (find, replace) in mirrors: - newuri = uri_replace(uri, find, replace, d) - if newuri != uri: - if fetch_uri(newuri, basename, dl, md5, parm, localdata): - completed = 1 - break - - if not completed: - raise FetchError(uri) - - del localdata + premirrors = [ i.split() for i in (data.getVar('PREMIRRORS', localdata, 1) or "").split('\n') if i ] + for (find, replace) in premirrors: + newuri = uri_replace(uri, find, replace, d) + if newuri != uri: + if fetch_uri(newuri, ud, localdata): + return + + if fetch_uri(uri, ud, localdata): + return + + # try mirrors + mirrors = [ i.split() for i in (data.getVar('MIRRORS', localdata, 1) or "").split('\n') if i ] + for (find, replace) in mirrors: + newuri = uri_replace(uri, find, replace, d) + if newuri != uri: + if fetch_uri(newuri, ud, localdata): + return + + raise FetchError(uri) diff --git a/bitbake/lib/bb/methodpool.py b/bitbake/lib/bb/methodpool.py index d7434ed33e..e14986bc19 100644 --- a/bitbake/lib/bb/methodpool.py +++ b/bitbake/lib/bb/methodpool.py @@ -61,9 +61,6 @@ def insert_method(modulename, code, fn): comp = better_compile(code, "<bb>", fn ) better_exec(comp, __builtins__, code, fn) - # hack hack hack XXX - return - # now some instrumentation code = comp.co_names for name in code: diff --git a/bitbake/lib/bb/msg.py b/bitbake/lib/bb/msg.py new file mode 100644 index 0000000000..473851cc72 --- /dev/null +++ b/bitbake/lib/bb/msg.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# ex:ts=4:sw=4:sts=4:et +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +""" +BitBake 'msg' implementation + +Message handling infrastructure for bitbake + +# Copyright (C) 2006 Richard Purdie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +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., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA. + +""" + +import sys, os, re, bb +from bb import utils + +debug_level = {} + +verbose = False + +domain = bb.utils.Enum( + 'Build', + 'Cache', + 'Collection', + 'Data', + 'Depends', + 'Fetcher', + 'Parsing', + 'Provider', + 'RunQueue', + 'TaskData', + 'Util') + +# +# Message control functions +# + +def set_debug_level(level): + bb.msg.debug_level = {} + for domain in bb.msg.domain: + bb.msg.debug_level[domain] = level + bb.msg.debug_level['default'] = level + +def set_verbose(level): + bb.msg.verbose = level + +def set_debug_domains(domains): + for domain in domains: + found = False + for ddomain in bb.msg.domain: + if domain == str(ddomain): + bb.msg.debug_level[ddomain] = bb.msg.debug_level[ddomain] + 1 + found = True + if not found: + std_warn("Logging domain %s is not valid, ignoring" % domain) + +# +# Message handling functions +# + +def debug(level, domain, msg, fn = None): + if debug_level[domain] >= level: + print 'DEBUG: ' + msg + +def note(level, domain, msg, fn = None): + if level == 1 or verbose or debug_level[domain] >= 1: + std_note(msg) + +def warn(domain, msg, fn = None): + std_warn(msg) + +def error(domain, msg, fn = None): + std_error(msg) + +def fatal(domain, msg, fn = None): + std_fatal(msg) + +# +# Compatibility functions for the original message interface +# +def std_debug(lvl, msg): + if debug_level['default'] >= lvl: + print 'DEBUG: ' + msg + +def std_note(msg): + print 'NOTE: ' + msg + +def std_warn(msg): + print 'WARNING: ' + msg + +def std_error(msg): + print 'ERROR: ' + msg + +def std_fatal(msg): + print 'ERROR: ' + msg + sys.exit(1) diff --git a/bitbake/lib/bb/parse/__init__.py b/bitbake/lib/bb/parse/__init__.py index 58e17d154a..70fdba03b4 100644 --- a/bitbake/lib/bb/parse/__init__.py +++ b/bitbake/lib/bb/parse/__init__.py @@ -37,11 +37,16 @@ class SkipPackage(Exception): __mtime_cache = {} def cached_mtime(f): if not __mtime_cache.has_key(f): - update_mtime(f) + __mtime_cache[f] = os.stat(f)[8] return __mtime_cache[f] -def update_mtime(f): - __mtime_cache[f] = os.stat(f)[8] +def cached_mtime_noerror(f): + if not __mtime_cache.has_key(f): + try: + __mtime_cache[f] = os.stat(f)[8] + except OSError: + return 0 + return __mtime_cache[f] def mark_dependency(d, f): if f.startswith('./'): diff --git a/bitbake/lib/bb/parse/parse_c/BBHandler.py b/bitbake/lib/bb/parse/parse_c/BBHandler.py index d9f48db17b..b430e1f4e5 100644 --- a/bitbake/lib/bb/parse/parse_c/BBHandler.py +++ b/bitbake/lib/bb/parse/parse_c/BBHandler.py @@ -5,33 +5,33 @@ Reads a .bb file and obtains its metadata (using a C++ parser) Copyright (C) 2006 Tim Robert Ansell - Copyright (C) 2006 Holger Hans Peter Freyther - + Copyright (C) 2006 Holger Hans Peter Freyther + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT - SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR - THE USE OR OTHER DEALINGS IN THE SOFTWARE. + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -import os +import os, sys # The Module we will use here import bb @@ -61,51 +61,126 @@ def supports(fn, data): return fn[-3:] == ".bb" or fn[-8:] == ".bbclass" or fn[-4:] == ".inc" or fn[-5:] == ".conf" def init(fn, data): - if not data.getVar('TOPDIR'): - bb.error('TOPDIR is not set') - if not data.getVar('BBPATH'): - bb.error('BBPATH is not set') + if not bb.data.getVar('TOPDIR', data): + bb.data.setVar('TOPDIR', os.getcwd(), data) + if not bb.data.getVar('BBPATH', data): + bb.data.setVar('BBPATH', os.path.join(sys.prefix, 'share', 'bitbake'), data) + +def handle_inherit(d): + """ + Handle inheriting of classes. This will load all default classes. + It could be faster, it could detect infinite loops but this is todo + Also this delayed loading of bb.parse could impose a penalty + """ + from bb.parse import handle + + files = (data.getVar('INHERIT', d, True) or "").split() + if not "base" in i: + files[0:0] = ["base"] + + __inherit_cache = data.getVar('__inherit_cache', d) or [] + for f in files: + file = data.expand(f, d) + if file[0] != "/" and file[-8:] != ".bbclass": + file = os.path.join('classes', '%s.bbclass' % file) + + if not file in __inherit_cache: + debug(2, "BB %s:%d: inheriting %s" % (fn, lineno, file)) + __inherit_cache.append( file ) + + try: + handle(file, d, True) + except IOError: + print "Failed to inherit %s" % file + data.setVar('__inherit_cache', __inherit_cache, d) def handle(fn, d, include): - print "" - print "fn: %s" % fn - print "data: %s" % d - print dir(d) - print d.getVar.__doc__ - print "include: %s" % include + from bb import data, parse + + (root, ext) = os.path.splitext(os.path.basename(fn)) + base_name = "%s%s" % (root,ext) + + # initialize with some data + init(fn,d) # check if we include or are the beginning + oldfile = None if include: - oldfile = d.getVar('FILE') - else: - #d.inheritFromOS() - oldfile = None + oldfile = d.getVar('FILE', False) + is_conf = False + elif ext == ".conf": + is_conf = True + data.inheritFromOS(d) # find the file if not os.path.isabs(fn): - bb.error("No Absolute FILE name") - abs_fn = bb.which(d.getVar('BBPATH'), fn) + abs_fn = bb.which(d.getVar('BBPATH', True), fn) else: abs_fn = fn # check if the file exists if not os.path.exists(abs_fn): - raise IOError("file '%(fn)' not found" % locals() ) + raise IOError("file '%(fn)s' not found" % locals() ) # now we know the file is around mark it as dep if include: parse.mark_dependency(d, abs_fn) + # manipulate the bbpath + if ext != ".bbclass" and ext != ".conf": + old_bb_path = data.getVar('BBPATH', d) + data.setVar('BBPATH', os.path.dirname(abs_fn) + (":%s" %old_bb_path) , d) + + # handle INHERITS and base inherit + if ext != ".bbclass" and ext != ".conf": + data.setVar('FILE', fn, d) + handle_interit(d) + # now parse this file - by defering it to C++ - parsefile(fn, d) + parsefile(abs_fn, d, is_conf) + + # Finish it up + if include == 0: + data.expandKeys(d) + data.update_data(d) + #### !!! XXX Finish it up by executing the anonfunc + # restore the original FILE if oldfile: d.setVar('FILE', oldfile) + # restore bbpath + if ext != ".bbclass" and ext != ".conf": + data.setVar('BBPATH', old_bb_path, d ) + + return d + +# Needed for BitBake files... +__pkgsplit_cache__={} +def vars_from_file(mypkg, d): + if not mypkg: + return (None, None, None) + if mypkg in __pkgsplit_cache__: + return __pkgsplit_cache__[mypkg] + + myfile = os.path.splitext(os.path.basename(mypkg)) + parts = myfile[0].split('_') + __pkgsplit_cache__[mypkg] = parts + exp = 3 - len(parts) + tmplist = [] + while exp != 0: + exp -= 1 + tmplist.append(None) + parts.extend(tmplist) + return parts + + + + # Inform bitbake that we are a parser # We need to define all three from bb.parse import handlers diff --git a/bitbake/lib/bb/parse/parse_c/Makefile b/bitbake/lib/bb/parse/parse_c/Makefile index 9eb7ce9d08..77daccb72d 100644 --- a/bitbake/lib/bb/parse/parse_c/Makefile +++ b/bitbake/lib/bb/parse/parse_c/Makefile @@ -1,6 +1,6 @@ -test: bitbakec.so - python test.py +buil: bitbakec.so + echo "Done" bitbakescanner.cc: bitbakescanner.l flex -t bitbakescanner.l > bitbakescanner.cc @@ -28,9 +28,9 @@ bitbakec.so: bitbakec.o bitbakeparser.o bitbakescanner.o g++ -shared -fPIC bitbakeparser.o bitbakescanner.o bitbakec.o -o bitbakec.so clean: - rm *.out - rm *.cc - rm bitbakec.c - rm bitbakec-processed.c - rm *.o - rm *.so + rm -f *.out + rm -f *.cc + rm -f bitbakec.c + rm -f bitbakec-processed.c + rm -f *.o + rm -f *.so diff --git a/bitbake/lib/bb/parse/parse_c/bitbakec.pyx b/bitbake/lib/bb/parse/parse_c/bitbakec.pyx index 362cc2021e..c666e9b6b1 100644 --- a/bitbake/lib/bb/parse/parse_c/bitbakec.pyx +++ b/bitbake/lib/bb/parse/parse_c/bitbakec.pyx @@ -6,96 +6,107 @@ cdef extern from "stdio.h": FILE *fopen(char*, char*) int fclose(FILE *fp) +cdef extern from "string.h": + int strlen(char*) cdef extern from "lexerc.h": ctypedef struct lex_t: void* parser void* scanner + char* name FILE* file + int config void* data int lineError int errorParse - cdef extern void parse(FILE*, object) + cdef extern int parse(FILE*, char*, object, int) -def parsefile(object file, object data): - print "parsefile: 1", file, data +def parsefile(object file, object data, object config): + #print "parsefile: 1", file, data # Open the file cdef FILE* f f = fopen(file, "r") - print "parsefile: 2 opening file" + #print "parsefile: 2 opening file" if (f == NULL): raise IOError("No such file %s." % file) - print "parsefile: 3 parse" - parse(f, data) + #print "parsefile: 3 parse" + parse(f, file, data, config) # Close the file - print "parsefile: 4 closing" fclose(f) - + cdef public void e_assign(lex_t* container, char* key, char* what): - print "e_assign", key, what + #print "e_assign", key, what + if what == NULL: + print "FUTURE Warning empty string: use \"\"" + what = "" + d = <object>container.data - d.setVar(key, what) + d.setVar(key, what) cdef public void e_export(lex_t* c, char* what): - print "e_export", what + #print "e_export", what #exp: # bb.data.setVarFlag(key, "export", 1, data) - d = <object>container.data - d.setVarFlag(key, "export", 1) + d = <object>c.data + d.setVarFlag(what, "export", 1) cdef public void e_immediate(lex_t* c, char* key, char* what): - print "e_immediate", key, what + #print "e_immediate", key, what #colon: # val = bb.data.expand(groupd["value"], data) d = <object>c.data - d.setVar(key, d.expand(what)) + d.setVar(key, d.expand(what,d)) cdef public void e_cond(lex_t* c, char* key, char* what): - print "e_cond", key, what + #print "e_cond", key, what #ques: # val = bb.data.getVar(key, data) # if val == None: # val = groupd["value"] + if what == NULL: + print "FUTURE warning: Use \"\" for", key + what = "" + d = <object>c.data - d.setVar(key, (d.getVar(key) or what)) + d.setVar(key, (d.getVar(key,False) or what)) cdef public void e_prepend(lex_t* c, char* key, char* what): - print "e_prepend", key, what + #print "e_prepend", key, what #prepend: # val = "%s %s" % (groupd["value"], (bb.data.getVar(key, data) or "")) d = <object>c.data - d.setVar(key, what + " " + (d.getVar(key) or "")) + d.setVar(key, what + " " + (d.getVar(key,0) or "")) cdef public void e_append(lex_t* c, char* key, char* what): - print "e_append", key, what + #print "e_append", key, what #append: # val = "%s %s" % ((bb.data.getVar(key, data) or ""), groupd["value"]) d = <object>c.data - d.setVar(key, (d.getVar(key) or "") + " " + what) + d.setVar(key, (d.getVar(key,0) or "") + " " + what) cdef public void e_precat(lex_t* c, char* key, char* what): - print "e_precat", key, what + #print "e_precat", key, what #predot: # val = "%s%s" % (groupd["value"], (bb.data.getVar(key, data) or "")) d = <object>c.data - d.setVar(key, what + (d.getVar(key) or "")) + d.setVar(key, what + (d.getVar(key,0) or "")) cdef public void e_postcat(lex_t* c, char* key, char* what): - print "e_postcat", key, what + #print "e_postcat", key, what #postdot: # val = "%s%s" % ((bb.data.getVar(key, data) or ""), groupd["value"]) d = <object>c.data - d.setVar(key, (d.getVar(key) or "") + what) + d.setVar(key, (d.getVar(key,0) or "") + what) -cdef public void e_addtask(lex_t* c, char* name, char* before, char* after): - print "e_addtask", name, before, after +cdef public int e_addtask(lex_t* c, char* name, char* before, char* after) except -1: + #print "e_addtask", name # func = m.group("func") # before = m.group("before") # after = m.group("after") @@ -112,69 +123,131 @@ cdef public void e_addtask(lex_t* c, char* name, char* before, char* after): # # set up things that depend on this func # data.setVarFlag(var, "postdeps", before.split(), d) # return - - do = "do_%s" % name + + if c.config == 1: + from bb.parse import ParseError + raise ParseError("No tasks allowed in config files") + return -1 + d = <object>c.data + do = "do_%s" % name d.setVarFlag(do, "task", 1) - if strlen(before) > 0: + if before != NULL and strlen(before) > 0: + #print "Before", before + d.setVarFlag(do, "postdeps", ("%s" % before).split()) + if after != NULL and strlen(after) > 0: + #print "After", after d.setVarFlag(do, "deps", ("%s" % after).split()) - if strlen(after) > 0: - d.setVarFlag(do, "deps", ("%s" % before).split()) + return 0 -cdef public void e_addhandler(lex_t* c, char* h): - print "e_addhandler", h +cdef public int e_addhandler(lex_t* c, char* h) except -1: + #print "e_addhandler", h # data.setVarFlag(h, "handler", 1, d) + if c.config == 1: + from bb.parse import ParseError + raise ParseError("No handlers allowed in config files") + return -1 + d = <object>c.data d.setVarFlag(h, "handler", 1) + return 0 + +cdef public int e_export_func(lex_t* c, char* function) except -1: + #print "e_export_func", function + if c.config == 1: + from bb.parse import ParseError + raise ParseError("No functions allowed in config files") + return -1 + + return 0 + +cdef public int e_inherit(lex_t* c, char* file) except -1: + #print "e_inherit", file -cdef public void e_export_func(lex_t* c, char* function): - print "e_export_func", function - pass + if c.config == 1: + from bb.parse import ParseError + raise ParseError("No inherits allowed in config files") + return -1 -cdef public void e_inherit(lex_t* c, char* file): - print "e_inherit", file - pass + return 0 cdef public void e_include(lex_t* c, char* file): - print "e_include", file + from bb.parse import handle d = <object>c.data - d.expand(file) - + try: - parsefile(file, d) + handle(d.expand(file,d), d, True) except IOError: - print "Could not include required file %s" % file + print "Could not include file", file -cdef public void e_require(lex_t* c, char* file): - print "e_require", file +cdef public int e_require(lex_t* c, char* file) except -1: + #print "e_require", file + from bb.parse import handle d = <object>c.data - d.expand(file) - + try: - parsefile(file, d) + handle(d.expand(file,d), d, True) except IOError: - raise CParseError("Could not include required file %s" % file) + print "ParseError", file + from bb.parse import ParseError + raise ParseError("Could not include required file %s" % file) + return -1 + + return 0 + +cdef public int e_proc(lex_t* c, char* key, char* what) except -1: + #print "e_proc", key, what + if c.config == 1: + from bb.parse import ParseError + raise ParseError("No inherits allowed in config files") + return -1 + + return 0 + +cdef public int e_proc_python(lex_t* c, char* key, char* what) except -1: + #print "e_proc_python" + if c.config == 1: + from bb.parse import ParseError + raise ParseError("No pythin allowed in config files") + return -1 + + if key != NULL: + pass + #print "Key", key + if what != NULL: + pass + #print "What", what + + return 0 + +cdef public int e_proc_fakeroot(lex_t* c, char* key, char* what) except -1: + #print "e_fakeroot", key, what + + if c.config == 1: + from bb.parse import ParseError + raise ParseError("No fakeroot allowed in config files") + return -1 + + return 0 + +cdef public int e_def(lex_t* c, char* a, char* b, char* d) except -1: + #print "e_def", a, b, d -cdef public void e_proc(lex_t* c, char* key, char* what): - print "e_proc", key, what - pass + if c.config == 1: + from bb.parse import ParseError + raise ParseError("No defs allowed in config files") + return -1 -cdef public void e_proc_python(lex_t* c, char* key, char* what): - print "e_proc_python", key, what - pass + return 0 -cdef public void e_proc_fakeroot(lex_t* c, char* key, char* what): - print "e_fakeroot", key, what - pass +cdef public int e_parse_error(lex_t* c) except -1: + print "e_parse_error", c.name, "line:", lineError, "parse:", errorParse -cdef public void e_def(lex_t* c, char* a, char* b, char* d): - print "e_def", key, what - pass -cdef public void e_parse_error(lex_t* c): - print "e_parse_error", "line:", lineError, "parse:", errorParse - raise CParseError("There was an parse error, sorry unable to give more information at the current time.") + from bb.parse import ParseError + raise ParseError("There was an parse error, sorry unable to give more information at the current time. File: %s Line: %d" % (c.name,lineError) ) + return -1 diff --git a/bitbake/lib/bb/parse/parse_c/bitbakeparser.cc b/bitbake/lib/bb/parse/parse_c/bitbakeparser.cc index ee9a901b70..9d9793f8df 100644 --- a/bitbake/lib/bb/parse/parse_c/bitbakeparser.cc +++ b/bitbake/lib/bb/parse/parse_c/bitbakeparser.cc @@ -128,51 +128,49 @@ typedef union { */ static const YYACTIONTYPE yy_action[] = { /* 0 */ 82, 3, 7, 8, 38, 22, 39, 24, 26, 32, - /* 10 */ 34, 28, 30, 128, 1, 40, 53, 70, 55, 5, - /* 20 */ 60, 65, 67, 2, 21, 36, 69, 77, 9, 7, - /* 30 */ 11, 6, 13, 15, 17, 19, 12, 52, 50, 4, - /* 40 */ 74, 42, 46, 59, 57, 10, 64, 62, 38, 14, - /* 50 */ 73, 16, 38, 38, 76, 81, 18, 20, 23, 25, - /* 60 */ 27, 29, 31, 33, 35, 37, 56, 51, 90, 54, - /* 70 */ 58, 71, 41, 43, 63, 45, 44, 47, 72, 48, - /* 80 */ 75, 78, 80, 61, 90, 49, 66, 90, 90, 68, - /* 90 */ 90, 90, 90, 90, 90, 79, + /* 10 */ 34, 28, 30, 2, 21, 40, 53, 70, 55, 44, + /* 20 */ 60, 65, 67, 128, 1, 36, 69, 77, 42, 46, + /* 30 */ 11, 66, 13, 15, 17, 19, 64, 62, 9, 7, + /* 40 */ 74, 38, 45, 81, 59, 57, 38, 38, 73, 76, + /* 50 */ 5, 68, 52, 50, 14, 31, 47, 71, 48, 10, + /* 60 */ 72, 33, 23, 49, 6, 41, 51, 78, 75, 16, + /* 70 */ 4, 54, 35, 25, 18, 80, 79, 56, 27, 37, + /* 80 */ 58, 12, 61, 29, 43, 63, 20, }; static const YYCODETYPE yy_lookahead[] = { /* 0 */ 0, 1, 2, 3, 23, 4, 25, 6, 7, 8, - /* 10 */ 9, 10, 11, 31, 32, 15, 16, 1, 18, 42, - /* 20 */ 20, 21, 22, 33, 34, 24, 26, 27, 1, 2, - /* 30 */ 4, 28, 6, 7, 8, 9, 5, 35, 36, 29, - /* 40 */ 24, 13, 14, 37, 38, 34, 39, 40, 23, 5, - /* 50 */ 25, 5, 23, 23, 25, 25, 5, 5, 5, 5, - /* 60 */ 5, 5, 5, 5, 5, 41, 17, 35, 43, 1, - /* 70 */ 37, 24, 12, 12, 39, 12, 14, 12, 41, 13, - /* 80 */ 41, 1, 41, 19, 43, 12, 19, 43, 43, 19, - /* 90 */ 43, 43, 43, 43, 43, 24, + /* 10 */ 9, 10, 11, 33, 34, 15, 16, 1, 18, 14, + /* 20 */ 20, 21, 22, 31, 32, 24, 26, 27, 13, 14, + /* 30 */ 4, 19, 6, 7, 8, 9, 39, 40, 1, 2, + /* 40 */ 24, 23, 12, 25, 37, 38, 23, 23, 25, 25, + /* 50 */ 42, 19, 35, 36, 5, 5, 12, 24, 13, 34, + /* 60 */ 41, 5, 5, 12, 28, 12, 35, 1, 41, 5, + /* 70 */ 29, 1, 5, 5, 5, 41, 24, 17, 5, 41, + /* 80 */ 37, 5, 19, 5, 12, 39, 5, }; #define YY_SHIFT_USE_DFLT (-20) static const signed char yy_shift_ofst[] = { - /* 0 */ -20, 0, -20, 10, -20, 3, -20, -20, 27, -20, - /* 10 */ 26, 31, -20, 44, -20, 46, -20, 51, -20, 52, - /* 20 */ -20, 1, 53, -20, 54, -20, 55, -20, 56, -20, - /* 30 */ 57, -20, 58, -20, 59, -20, -20, -19, -20, -20, - /* 40 */ 60, 28, 61, 62, 63, -20, 65, 66, 73, -20, - /* 50 */ 60, -20, -20, 68, -20, 49, -20, 49, -20, -20, - /* 60 */ 64, -20, 64, -20, -20, 67, -20, 70, -20, 16, - /* 70 */ 47, -20, 25, -20, -20, 29, -20, 80, 71, -20, - /* 80 */ 30, -20, + /* 0 */ -20, 0, -20, 41, -20, 36, -20, -20, 37, -20, + /* 10 */ 26, 76, -20, 49, -20, 64, -20, 69, -20, 81, + /* 20 */ -20, 1, 57, -20, 68, -20, 73, -20, 78, -20, + /* 30 */ 50, -20, 56, -20, 67, -20, -20, -19, -20, -20, + /* 40 */ 53, 15, 72, 5, 30, -20, 44, 45, 51, -20, + /* 50 */ 53, -20, -20, 70, -20, 60, -20, 60, -20, -20, + /* 60 */ 63, -20, 63, -20, -20, 12, -20, 32, -20, 16, + /* 70 */ 33, -20, 23, -20, -20, 24, -20, 66, 52, -20, + /* 80 */ 18, -20, }; -#define YY_REDUCE_USE_DFLT (-24) +#define YY_REDUCE_USE_DFLT (-21) static const signed char yy_reduce_ofst[] = { - /* 0 */ -18, -10, -24, -24, -23, -24, -24, -24, 11, -24, - /* 10 */ -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, - /* 20 */ -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, - /* 30 */ -24, -24, -24, -24, -24, -24, 24, -24, -24, -24, - /* 40 */ 2, -24, -24, -24, -24, -24, -24, -24, -24, -24, - /* 50 */ 32, -24, -24, -24, -24, 6, -24, 33, -24, -24, - /* 60 */ 7, -24, 35, -24, -24, -24, -24, -24, -24, -24, - /* 70 */ -24, 37, -24, -24, 39, -24, -24, -24, -24, 41, - /* 80 */ -24, -24, + /* 0 */ -8, -20, -21, -21, 8, -21, -21, -21, 25, -21, + /* 10 */ -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + /* 20 */ -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + /* 30 */ -21, -21, -21, -21, -21, -21, 38, -21, -21, -21, + /* 40 */ 17, -21, -21, -21, -21, -21, -21, -21, -21, -21, + /* 50 */ 31, -21, -21, -21, -21, 7, -21, 43, -21, -21, + /* 60 */ -3, -21, 46, -21, -21, -21, -21, -21, -21, -21, + /* 70 */ -21, 19, -21, -21, 27, -21, -21, -21, -21, 34, + /* 80 */ -21, -21, }; static const YYACTIONTYPE yy_default[] = { /* 0 */ 84, 127, 83, 85, 125, 126, 124, 86, 127, 85, @@ -420,7 +418,7 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ case 29: #line 50 "bitbakeparser.y" { (yypminor->yy0).release_this (); } -#line 425 "bitbakeparser.c" +#line 423 "bitbakeparser.c" break; default: break; /* If no destructor action specified: do nothing */ } @@ -694,7 +692,7 @@ static void yy_reduce( { yygotominor.yy0.assignString( (char*)yymsp[0].minor.yy0.string() ); yymsp[0].minor.yy0.assignString( 0 ); yymsp[0].minor.yy0.release_this(); } -#line 699 "bitbakeparser.c" +#line 697 "bitbakeparser.c" break; case 4: #line 64 "bitbakeparser.y" @@ -702,7 +700,7 @@ static void yy_reduce( yygotominor.yy0.assignString( (char*)yymsp[0].minor.yy0.string() ); yymsp[0].minor.yy0.assignString( 0 ); yymsp[0].minor.yy0.release_this(); } -#line 707 "bitbakeparser.c" +#line 705 "bitbakeparser.c" break; case 5: #line 70 "bitbakeparser.y" @@ -711,7 +709,7 @@ static void yy_reduce( yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(3,&yymsp[-3].minor); yy_destructor(4,&yymsp[-1].minor); } -#line 716 "bitbakeparser.c" +#line 714 "bitbakeparser.c" break; case 6: #line 74 "bitbakeparser.y" @@ -720,7 +718,7 @@ static void yy_reduce( yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(3,&yymsp[-3].minor); yy_destructor(6,&yymsp[-1].minor); } -#line 725 "bitbakeparser.c" +#line 723 "bitbakeparser.c" break; case 7: #line 78 "bitbakeparser.y" @@ -729,7 +727,7 @@ static void yy_reduce( yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(3,&yymsp[-3].minor); yy_destructor(7,&yymsp[-1].minor); } -#line 734 "bitbakeparser.c" +#line 732 "bitbakeparser.c" break; case 8: #line 82 "bitbakeparser.y" @@ -738,7 +736,7 @@ static void yy_reduce( yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(3,&yymsp[-3].minor); yy_destructor(8,&yymsp[-1].minor); } -#line 743 "bitbakeparser.c" +#line 741 "bitbakeparser.c" break; case 9: #line 86 "bitbakeparser.y" @@ -746,56 +744,56 @@ static void yy_reduce( yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(3,&yymsp[-3].minor); yy_destructor(9,&yymsp[-1].minor); } -#line 751 "bitbakeparser.c" +#line 749 "bitbakeparser.c" break; case 10: #line 90 "bitbakeparser.y" { e_assign( lex, yymsp[-2].minor.yy0.string(), yymsp[0].minor.yy0.string() ); yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(4,&yymsp[-1].minor); } -#line 758 "bitbakeparser.c" +#line 756 "bitbakeparser.c" break; case 11: #line 93 "bitbakeparser.y" { e_precat( lex, yymsp[-2].minor.yy0.string(), yymsp[0].minor.yy0.string() ); yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(6,&yymsp[-1].minor); } -#line 765 "bitbakeparser.c" +#line 763 "bitbakeparser.c" break; case 12: #line 96 "bitbakeparser.y" { e_postcat( lex, yymsp[-2].minor.yy0.string(), yymsp[0].minor.yy0.string() ); yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(7,&yymsp[-1].minor); } -#line 772 "bitbakeparser.c" +#line 770 "bitbakeparser.c" break; case 13: #line 99 "bitbakeparser.y" { e_prepend( lex, yymsp[-2].minor.yy0.string(), yymsp[0].minor.yy0.string() ); yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(10,&yymsp[-1].minor); } -#line 779 "bitbakeparser.c" +#line 777 "bitbakeparser.c" break; case 14: #line 102 "bitbakeparser.y" { e_append( lex, yymsp[-2].minor.yy0.string() , yymsp[0].minor.yy0.string() ); yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(11,&yymsp[-1].minor); } -#line 786 "bitbakeparser.c" +#line 784 "bitbakeparser.c" break; case 15: #line 105 "bitbakeparser.y" { e_immediate( lex, yymsp[-2].minor.yy0.string(), yymsp[0].minor.yy0.string() ); yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(8,&yymsp[-1].minor); } -#line 793 "bitbakeparser.c" +#line 791 "bitbakeparser.c" break; case 16: #line 108 "bitbakeparser.y" { e_cond( lex, yymsp[-2].minor.yy0.string(), yymsp[0].minor.yy0.string() ); yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(9,&yymsp[-1].minor); } -#line 800 "bitbakeparser.c" +#line 798 "bitbakeparser.c" break; case 17: #line 112 "bitbakeparser.y" @@ -803,7 +801,7 @@ static void yy_reduce( yymsp[-4].minor.yy0.release_this(); yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(13,&yymsp[-3].minor); yy_destructor(14,&yymsp[-1].minor); } -#line 808 "bitbakeparser.c" +#line 806 "bitbakeparser.c" break; case 18: #line 115 "bitbakeparser.y" @@ -811,55 +809,55 @@ static void yy_reduce( yymsp[-4].minor.yy0.release_this(); yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(14,&yymsp[-3].minor); yy_destructor(13,&yymsp[-1].minor); } -#line 816 "bitbakeparser.c" +#line 814 "bitbakeparser.c" break; case 19: #line 118 "bitbakeparser.y" { e_addtask( lex, yymsp[0].minor.yy0.string(), NULL, NULL); yymsp[0].minor.yy0.release_this();} -#line 822 "bitbakeparser.c" +#line 820 "bitbakeparser.c" break; case 20: #line 121 "bitbakeparser.y" { e_addtask( lex, yymsp[-2].minor.yy0.string(), yymsp[0].minor.yy0.string(), NULL); yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(13,&yymsp[-1].minor); } -#line 829 "bitbakeparser.c" +#line 827 "bitbakeparser.c" break; case 21: #line 124 "bitbakeparser.y" { e_addtask( lex, yymsp[-2].minor.yy0.string(), NULL, yymsp[0].minor.yy0.string()); yymsp[-2].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); yy_destructor(14,&yymsp[-1].minor); } -#line 836 "bitbakeparser.c" +#line 834 "bitbakeparser.c" break; case 25: #line 131 "bitbakeparser.y" { e_addhandler( lex, yymsp[0].minor.yy0.string()); yymsp[0].minor.yy0.release_this (); yy_destructor(16,&yymsp[-1].minor); } -#line 842 "bitbakeparser.c" +#line 840 "bitbakeparser.c" break; case 26: #line 133 "bitbakeparser.y" { e_export_func( lex, yymsp[0].minor.yy0.string()); yymsp[0].minor.yy0.release_this(); } -#line 847 "bitbakeparser.c" +#line 845 "bitbakeparser.c" break; case 30: #line 138 "bitbakeparser.y" { e_inherit( lex, yymsp[0].minor.yy0.string() ); yymsp[0].minor.yy0.release_this (); } -#line 852 "bitbakeparser.c" +#line 850 "bitbakeparser.c" break; case 34: #line 144 "bitbakeparser.y" { e_include( lex, yymsp[0].minor.yy0.string() ); yymsp[0].minor.yy0.release_this(); yy_destructor(21,&yymsp[-1].minor); } -#line 858 "bitbakeparser.c" +#line 856 "bitbakeparser.c" break; case 35: #line 147 "bitbakeparser.y" { e_require( lex, yymsp[0].minor.yy0.string() ); yymsp[0].minor.yy0.release_this(); yy_destructor(22,&yymsp[-1].minor); } -#line 864 "bitbakeparser.c" +#line 862 "bitbakeparser.c" break; case 36: #line 150 "bitbakeparser.y" @@ -868,12 +866,12 @@ static void yy_reduce( yymsp[-1].minor.yy0.release_this (); yymsp[0].minor.yy0.release_this (); } -#line 873 "bitbakeparser.c" +#line 871 "bitbakeparser.c" break; case 37: #line 155 "bitbakeparser.y" { yygotominor.yy0.assignString(0); } -#line 878 "bitbakeparser.c" +#line 876 "bitbakeparser.c" break; case 38: #line 157 "bitbakeparser.y" @@ -881,7 +879,7 @@ static void yy_reduce( yymsp[-3].minor.yy0.release_this(); yymsp[-1].minor.yy0.release_this(); yy_destructor(24,&yymsp[-2].minor); yy_destructor(25,&yymsp[0].minor); } -#line 886 "bitbakeparser.c" +#line 884 "bitbakeparser.c" break; case 39: #line 160 "bitbakeparser.y" @@ -890,7 +888,7 @@ static void yy_reduce( yy_destructor(24,&yymsp[-2].minor); yy_destructor(25,&yymsp[0].minor); } -#line 895 "bitbakeparser.c" +#line 893 "bitbakeparser.c" break; case 40: #line 163 "bitbakeparser.y" @@ -899,7 +897,7 @@ static void yy_reduce( yy_destructor(24,&yymsp[-2].minor); yy_destructor(25,&yymsp[0].minor); } -#line 904 "bitbakeparser.c" +#line 902 "bitbakeparser.c" break; case 41: #line 167 "bitbakeparser.y" @@ -908,7 +906,7 @@ static void yy_reduce( yy_destructor(24,&yymsp[-2].minor); yy_destructor(25,&yymsp[0].minor); } -#line 913 "bitbakeparser.c" +#line 911 "bitbakeparser.c" break; case 42: #line 171 "bitbakeparser.y" @@ -916,18 +914,18 @@ static void yy_reduce( yygotominor.yy0.assignString( token_t::concatString(yymsp[-1].minor.yy0.string(), yymsp[0].minor.yy0.string()) ); yymsp[-1].minor.yy0.release_this (); yymsp[0].minor.yy0.release_this (); } -#line 921 "bitbakeparser.c" +#line 919 "bitbakeparser.c" break; case 43: #line 175 "bitbakeparser.y" { yygotominor.yy0.assignString( 0 ); } -#line 926 "bitbakeparser.c" +#line 924 "bitbakeparser.c" break; case 44: #line 177 "bitbakeparser.y" { e_def( lex, yymsp[-2].minor.yy0.string(), yymsp[-1].minor.yy0.string(), yymsp[0].minor.yy0.string()); yymsp[-2].minor.yy0.release_this(); yymsp[-1].minor.yy0.release_this(); yymsp[0].minor.yy0.release_this(); } -#line 932 "bitbakeparser.c" +#line 930 "bitbakeparser.c" break; }; yygoto = yyRuleInfo[yyruleno].lhs; @@ -986,7 +984,7 @@ static void yy_syntax_error( #define TOKEN (yyminor.yy0) #line 52 "bitbakeparser.y" e_parse_error( lex ); -#line 992 "bitbakeparser.c" +#line 990 "bitbakeparser.c" bbparseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } @@ -1042,7 +1040,7 @@ void bbparse( /* (re)initialize the parser, if necessary */ yypParser = (yyParser*)yyp; if( yypParser->yyidx<0 ){ - /* if( yymajor==0 ) return; // not sure why this was here... */ + if( yymajor==0 ) return; yypParser->yyidx = 0; yypParser->yyerrcnt = -1; yypParser->yystack[0].stateno = 0; diff --git a/bitbake/lib/bb/parse/parse_c/bitbakescanner.cc b/bitbake/lib/bb/parse/parse_c/bitbakescanner.cc index 43dad12d39..acc13f7c34 100644 --- a/bitbake/lib/bb/parse/parse_c/bitbakescanner.cc +++ b/bitbake/lib/bb/parse/parse_c/bitbakescanner.cc @@ -8,7 +8,7 @@ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 31 +#define YY_FLEX_SUBMINOR_VERSION 33 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif @@ -30,7 +30,15 @@ /* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ -#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +#if __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + #include <inttypes.h> typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; @@ -153,6 +161,10 @@ int yylex_init (yyscan_t* scanner); #define YY_BUF_SIZE 16384 #endif +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; @@ -493,7 +505,7 @@ static yyconst flex_int32_t yy_ec[256] = static yyconst flex_int32_t yy_meta[59] = { 0, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, - 5, 6, 5, 5, 7, 8, 1, 7, 1, 9, + 5, 6, 5, 5, 5, 7, 1, 8, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 1, 11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, @@ -565,18 +577,18 @@ static yyconst flex_int16_t yy_base[847] = 2077, 2072, 2066, 2069, 2056, 2067, 1398, 1343, 1408, 1404, 643, 1409, 2071, 2066, 2060, 2063, 2050, 2061, 2065, 2060, 2054, 2057, 2044, 2055, 1420, 1445, 1413, 1447, 1453, 1454, - 2059, 2054, 2047, 2050, 2035, 2043, 1455, 1459, 1460, 1461, + 2059, 2053, 2047, 2049, 2032, 2043, 1455, 1459, 1460, 1461, 1462, 1463, 1471, 1436, 1430, 1192, 1433, 1479, 1482, 1492, - 1506, 1519, 1520, 1528, 2047, 2040, 2031, 0, 2034, 2019, - 2027, 1486, 1496, 1505, 1506, 1510, 1516, 1524, 2044, 2018, - 0, 0, 0, 0, 1281, 1517, 2043, 2042, 2039, 2035, - 2023, 1994, 2309, 2309, 2309, 2309, 2005, 1981, 0, 0, + 1506, 1519, 1520, 1528, 2046, 2037, 2031, 0, 2033, 2016, + 2027, 1486, 1496, 1505, 1506, 1510, 1516, 1524, 2043, 2015, + 0, 0, 0, 0, 1281, 1517, 2043, 2041, 2036, 2034, + 2024, 1995, 2309, 2309, 2309, 2309, 2005, 1981, 0, 0, 0, 0, 1538, 1528, 1530, 1534, 1537, 1540, 1981, 1957, 0, 0, 0, 0, 1557, 1558, 1559, 1560, 1561, 1563, - 1568, 1547, 1988, 1959, 1954, 1948, 1580, 1581, 1582, 1590, - 1592, 1594, 1923, 1863, 0, 0, 0, 0, 1598, 1599, - 1600, 1874, 1858, 1350, 1584, 1803, 1792, 1801, 1790, 1603, + 1568, 1547, 1988, 1959, 1955, 1948, 1580, 1581, 1582, 1590, + 1592, 1594, 1924, 1863, 0, 0, 0, 0, 1598, 1599, + 1600, 1875, 1859, 1350, 1584, 1803, 1792, 1801, 1790, 1603, 1601, 1799, 1788, 1604, 1602, 1610, 1609, 1643, 1644, 1797, 1786, 1611, 1630, 1800, 1773, 1010, 1606, 1798, 1771, 1795, @@ -593,8 +605,8 @@ static yyconst flex_int16_t yy_base[847] = 1768, 0, 742, 2309, 0, 1764, 0, 1778, 678, 1801, 0, 2309, 1835, 1847, 1859, 1871, 1883, 550, 1892, 1898, 1907, 1919, 1931, 1939, 1945, 1950, 1956, 1965, 1977, 1989, - 2001, 2013, 2025, 2033, 2039, 2042, 306, 304, 301, 2049, - 213, 2057, 136, 2065, 2073, 2081 + 2001, 2013, 2025, 2033, 2039, 2043, 306, 304, 301, 2050, + 213, 2058, 136, 2066, 2074, 2082 } ; static yyconst flex_int16_t yy_def[847] = @@ -903,14 +915,14 @@ static yyconst flex_int16_t yy_nxt[2368] = 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 155, 155, 155, 155, 155, 155, 155, - 155, 155, 155, 155, 155, 167, 167, 167, 705, 167, + 155, 155, 155, 155, 155, 167, 167, 167, 167, 705, - 167, 167, 177, 177, 704, 177, 177, 183, 701, 183, + 167, 167, 177, 177, 177, 704, 177, 183, 701, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 201, 201, 201, 201, 201, 201, 201, 201, 201, - 201, 201, 201, 209, 209, 700, 209, 209, 217, 217, - 238, 217, 217, 217, 223, 223, 238, 223, 223, 231, + 201, 201, 201, 209, 209, 209, 700, 209, 217, 217, + 238, 217, 217, 217, 223, 223, 223, 238, 223, 231, 231, 238, 231, 231, 231, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 256, @@ -919,13 +931,13 @@ static yyconst flex_int16_t yy_nxt[2368] = 256, 261, 693, 692, 261, 261, 261, 261, 261, 261, 261, 261, 261, 264, 264, 264, 264, 264, 264, 264, 264, 264, 264, 264, 264, 267, 689, 688, 267, 267, - 267, 267, 267, 267, 267, 267, 267, 284, 284, 687, - 284, 284, 292, 292, 292, 686, 292, 292, 292, 296, - 296, 184, 296, 418, 418, 184, 418, 418, 184, 184, - 418, 433, 433, 683, 433, 433, 682, 678, 433, 465, - 465, 677, 465, 465, 676, 675, 465, 500, 500, 674, - 500, 500, 673, 654, 500, 514, 514, 653, 514, 514, - 652, 651, 514, 650, 649, 642, 641, 640, 639, 638, + 267, 267, 267, 267, 267, 267, 267, 284, 284, 284, + 687, 284, 292, 292, 292, 292, 686, 292, 292, 296, + 184, 296, 184, 296, 418, 418, 418, 184, 418, 184, + 683, 418, 433, 433, 433, 682, 433, 678, 677, 433, + 465, 465, 465, 676, 465, 675, 674, 465, 500, 500, + 500, 673, 500, 654, 653, 500, 514, 514, 514, 652, + 514, 651, 650, 514, 649, 642, 641, 640, 639, 638, 637, 636, 635, 634, 633, 632, 631, 624, 623, 622, 621, 620, 619, 611, 610, 609, 608, 607, 606, 605, @@ -1167,14 +1179,14 @@ static yyconst flex_int16_t yy_chk[2368] = 815, 815, 815, 815, 815, 815, 815, 815, 815, 815, 815, 816, 816, 816, 816, 816, 816, 816, 816, 816, 816, 816, 816, 817, 817, 817, 817, 817, 817, 817, - 817, 817, 817, 817, 817, 819, 819, 819, 683, 819, + 817, 817, 817, 817, 817, 819, 819, 819, 819, 683, - 819, 819, 820, 820, 682, 820, 820, 821, 674, 821, + 819, 819, 820, 820, 820, 682, 820, 821, 674, 821, 821, 821, 821, 821, 821, 821, 821, 821, 821, 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, 823, 823, 823, 823, 823, 823, 823, 823, 823, - 823, 823, 823, 824, 824, 673, 824, 824, 825, 825, - 666, 825, 825, 825, 826, 826, 665, 826, 826, 827, + 823, 823, 823, 824, 824, 824, 673, 824, 825, 825, + 666, 825, 825, 825, 826, 826, 826, 665, 826, 827, 827, 664, 827, 827, 827, 828, 828, 828, 828, 828, 828, 828, 828, 828, 828, 828, 828, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 829, 830, @@ -1183,13 +1195,13 @@ static yyconst flex_int16_t yy_chk[2368] = 830, 831, 650, 649, 831, 831, 831, 831, 831, 831, 831, 831, 831, 832, 832, 832, 832, 832, 832, 832, 832, 832, 832, 832, 832, 833, 638, 637, 833, 833, - 833, 833, 833, 833, 833, 833, 833, 834, 834, 632, - 834, 834, 835, 835, 835, 631, 835, 835, 835, 836, - 836, 630, 836, 840, 840, 629, 840, 840, 628, 627, - 840, 842, 842, 620, 842, 842, 619, 611, 842, 844, - 844, 610, 844, 844, 609, 607, 844, 845, 845, 606, - 845, 845, 605, 586, 845, 846, 846, 585, 846, 846, - 584, 583, 846, 582, 581, 574, 573, 572, 571, 570, + 833, 833, 833, 833, 833, 833, 833, 834, 834, 834, + 632, 834, 835, 835, 835, 835, 631, 835, 835, 836, + 630, 836, 629, 836, 840, 840, 840, 628, 840, 627, + 620, 840, 842, 842, 842, 619, 842, 611, 610, 842, + 844, 844, 844, 609, 844, 607, 606, 844, 845, 845, + 845, 605, 845, 586, 585, 845, 846, 846, 846, 584, + 846, 583, 582, 846, 581, 574, 573, 572, 571, 570, 569, 568, 567, 566, 565, 564, 563, 556, 555, 554, 553, 552, 551, 541, 540, 539, 538, 536, 535, 534, @@ -1323,7 +1335,7 @@ int errorParse; enum { errorNone = 0, errorUnexpectedInput, - errorUnsupportedFeature, + errorUnsupportedFeature, }; } @@ -1351,7 +1363,7 @@ static const char* fixup_escapes (const char* sz); -#line 1355 "<stdout>" +#line 1367 "<stdout>" #define INITIAL 0 #define S_DEF 1 @@ -1587,11 +1599,11 @@ YY_DECL #line 164 "bitbakescanner.l" -#line 1591 "<stdout>" +#line 1603 "<stdout>" - if ( yyg->yy_init ) + if ( !yyg->yy_init ) { - yyg->yy_init = 0; + yyg->yy_init = 1; #ifdef YY_USER_INIT YY_USER_INIT; @@ -1972,7 +1984,7 @@ YY_RULE_SETUP #line 254 "bitbakescanner.l" ECHO; YY_BREAK -#line 1976 "<stdout>" +#line 1988 "<stdout>" case YY_END_OF_BUFFER: { @@ -2274,7 +2286,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { register int yy_is_jam; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ register char *yy_cp = yyg->yy_c_buf_p; register YY_CHAR yy_c = 1; @@ -2730,10 +2742,10 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscann * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ -YY_BUFFER_STATE yy_scan_string (yyconst char * yy_str , yyscan_t yyscanner) +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) { - return yy_scan_bytes(yy_str,strlen(yy_str) ,yyscanner); + return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will @@ -2743,7 +2755,7 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yy_str , yyscan_t yyscanner) * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ -YY_BUFFER_STATE yy_scan_bytes (yyconst char * bytes, int len , yyscan_t yyscanner) +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; @@ -2751,15 +2763,15 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * bytes, int len , yyscan_t yyscan int i; /* Get memory for full buffer, including space for trailing EOB's. */ - n = len + 2; + n = _yybytes_len + 2; buf = (char *) yyalloc(n ,yyscanner ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - for ( i = 0; i < len; ++i ) - buf[i] = bytes[i]; + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; - buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf,n ,yyscanner); if ( ! b ) @@ -2987,21 +2999,51 @@ void yyset_debug (int bdebug , yyscan_t yyscanner) /* Accessor methods for yylval and yylloc */ +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int yylex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + static int yy_init_globals (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Initialization is the same as for the non-reentrant scanner. - This function is called once per scanner lifetime. */ + * This function is called from yylex_destroy(), so don't allocate here. + */ yyg->yy_buffer_stack = 0; yyg->yy_buffer_stack_top = 0; yyg->yy_buffer_stack_max = 0; yyg->yy_c_buf_p = (char *) 0; - yyg->yy_init = 1; + yyg->yy_init = 0; yyg->yy_start = 0; + yyg->yy_start_stack_ptr = 0; yyg->yy_start_stack_depth = 0; - yyg->yy_start_stack = (int *) 0; + yyg->yy_start_stack = NULL; /* Defined in main.c */ #ifdef YY_STDINIT @@ -3018,33 +3060,6 @@ static int yy_init_globals (yyscan_t yyscanner) return 0; } -/* User-visible API */ - -/* yylex_init is special because it creates the scanner itself, so it is - * the ONLY reentrant function that doesn't take the scanner as the last argument. - * That's why we explicitly handle the declaration, instead of using our macros. - */ - -int yylex_init(yyscan_t* ptr_yy_globals) - -{ - if (ptr_yy_globals == NULL){ - errno = EINVAL; - return 1; - } - - *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); - - if (*ptr_yy_globals == NULL){ - errno = ENOMEM; - return 1; - } - - memset(*ptr_yy_globals,0,sizeof(struct yyguts_t)); - - return yy_init_globals ( *ptr_yy_globals ); -} - /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (yyscan_t yyscanner) { @@ -3065,8 +3080,13 @@ int yylex_destroy (yyscan_t yyscanner) yyfree(yyg->yy_start_stack ,yyscanner ); yyg->yy_start_stack = NULL; + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + /* Destroy the main struct (reentrant only). */ yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; return 0; } @@ -3078,7 +3098,6 @@ int yylex_destroy (yyscan_t yyscanner) static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) { register int i; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } @@ -3088,7 +3107,6 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yysca static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) { register int n; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; for ( n = 0; s[n]; ++n ) ; @@ -3120,18 +3138,6 @@ void yyfree (void * ptr , yyscan_t yyscanner) #define YYTABLES_NAME "yytables" -#undef YY_NEW_FILE -#undef YY_FLUSH_BUFFER -#undef yy_set_bol -#undef yy_new_buffer -#undef yy_set_interactive -#undef yytext_ptr -#undef YY_DO_BEFORE_ACTION - -#ifdef YY_DECL_IS_OURS -#undef YY_DECL_IS_OURS -#undef YY_DECL -#endif #line 254 "bitbakescanner.l" @@ -3148,47 +3154,49 @@ void lex_t::accept (int token, const char* sz) void lex_t::input (char *buf, int *result, int max_size) { - printf("lex_t::input %p %d\n", buf, max_size); + /* printf("lex_t::input %p %d\n", buf, max_size); */ *result = fread(buf, 1, max_size, file); - printf("lex_t::input result %d\n", *result); + /* printf("lex_t::input result %d\n", *result); */ } int lex_t::line ()const { - printf("lex_t::line\n"); + /* printf("lex_t::line\n"); */ return yyget_lineno (scanner); } extern "C" { - void parse (FILE* file, PyObject* data) + void parse (FILE* file, char* name, PyObject* data, int config) { - printf("parse bbparseAlloc\n"); + /* printf("parse bbparseAlloc\n"); */ void* parser = bbparseAlloc (malloc); yyscan_t scanner; lex_t lex; - printf("parse yylex_init\n"); + /* printf("parse yylex_init\n"); */ yylex_init (&scanner); lex.parser = parser; lex.scanner = scanner; lex.file = file; + lex.name = name; lex.data = data; + lex.config = config; lex.parse = bbparse; - printf("parse yyset_extra\n"); + /*printf("parse yyset_extra\n"); */ yyset_extra (&lex, scanner); - printf("parse yylex\n"); + /* printf("parse yylex\n"); */ int result = yylex (scanner); - - printf("parse result %d\n", result); + + /* printf("parse result %d\n", result); */ lex.accept (0); - printf("parse lex.accept\n"); + /* printf("parse lex.accept\n"); */ bbparseTrace (NULL, NULL); - printf("parse bbparseTrace\n"); + /* printf("parse bbparseTrace\n"); */ if (result != T_EOF) printf ("premature end of file\n"); diff --git a/bitbake/lib/bb/parse/parse_c/bitbakescanner.l b/bitbake/lib/bb/parse/parse_c/bitbakescanner.l index f69a7325c3..b6592f28e9 100644 --- a/bitbake/lib/bb/parse/parse_c/bitbakescanner.l +++ b/bitbake/lib/bb/parse/parse_c/bitbakescanner.l @@ -91,7 +91,7 @@ int errorParse; enum { errorNone = 0, errorUnexpectedInput, - errorUnsupportedFeature, + errorUnsupportedFeature, }; } @@ -142,7 +142,7 @@ SSTRING \'([^\n\r]|"\\\n")*\' VALUE ([^'" \t\n])|([^'" \t\n]([^\n]|(\\\n))*[^'" \t\n]) C_SS [a-zA-Z_] -C_SB [a-zA-Z0-9_+-.] +C_SB [a-zA-Z0-9_+-./] REF $\{{C_SS}{C_SB}*\} SYMBOL {C_SS}{C_SB}* VARIABLE $?{C_SS}({C_SB}*|{REF})*(\[[a-zA-Z0-9_]*\])? @@ -265,47 +265,49 @@ void lex_t::accept (int token, const char* sz) void lex_t::input (char *buf, int *result, int max_size) { - printf("lex_t::input %p %d\n", buf, max_size); + /* printf("lex_t::input %p %d\n", buf, max_size); */ *result = fread(buf, 1, max_size, file); - printf("lex_t::input result %d\n", *result); + /* printf("lex_t::input result %d\n", *result); */ } int lex_t::line ()const { - printf("lex_t::line\n"); + /* printf("lex_t::line\n"); */ return yyget_lineno (scanner); } extern "C" { - void parse (FILE* file, PyObject* data) + void parse (FILE* file, char* name, PyObject* data, int config) { - printf("parse bbparseAlloc\n"); + /* printf("parse bbparseAlloc\n"); */ void* parser = bbparseAlloc (malloc); yyscan_t scanner; lex_t lex; - printf("parse yylex_init\n"); + /* printf("parse yylex_init\n"); */ yylex_init (&scanner); lex.parser = parser; lex.scanner = scanner; lex.file = file; + lex.name = name; lex.data = data; + lex.config = config; lex.parse = bbparse; - printf("parse yyset_extra\n"); + /*printf("parse yyset_extra\n"); */ yyset_extra (&lex, scanner); - printf("parse yylex\n"); + /* printf("parse yylex\n"); */ int result = yylex (scanner); - - printf("parse result %d\n", result); + + /* printf("parse result %d\n", result); */ lex.accept (0); - printf("parse lex.accept\n"); + /* printf("parse lex.accept\n"); */ bbparseTrace (NULL, NULL); - printf("parse bbparseTrace\n"); + /* printf("parse bbparseTrace\n"); */ if (result != T_EOF) printf ("premature end of file\n"); diff --git a/bitbake/lib/bb/parse/parse_c/lexer.h b/bitbake/lib/bb/parse/parse_c/lexer.h index 651f3a8618..cb32be7037 100644 --- a/bitbake/lib/bb/parse/parse_c/lexer.h +++ b/bitbake/lib/bb/parse/parse_c/lexer.h @@ -27,13 +27,15 @@ THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "Python.h" extern "C" { - + struct lex_t { void* parser; void* scanner; - FILE* file; + FILE* file; + char *name; PyObject *data; - + int config; + void* (*parse)(void*, int, token_t, lex_t*); void accept(int token, const char* sz = NULL); diff --git a/bitbake/lib/bb/parse/parse_c/lexerc.h b/bitbake/lib/bb/parse/parse_c/lexerc.h index 0163a7d632..c8a19fb222 100644 --- a/bitbake/lib/bb/parse/parse_c/lexerc.h +++ b/bitbake/lib/bb/parse/parse_c/lexerc.h @@ -11,7 +11,9 @@ typedef struct { void *parser; void *scanner; FILE *file; + char *name; PyObject *data; + int config; } lex_t; #endif diff --git a/bitbake/lib/bb/parse/parse_py/BBHandler.py b/bitbake/lib/bb/parse/parse_py/BBHandler.py index c82090fec0..34f4d25996 100644 --- a/bitbake/lib/bb/parse/parse_py/BBHandler.py +++ b/bitbake/lib/bb/parse/parse_py/BBHandler.py @@ -23,7 +23,7 @@ import re, bb, os, sys, time import bb.fetch, bb.build, bb.utils -from bb import debug, data, fetch, fatal, methodpool +from bb import data, fetch, methodpool from ConfHandler import include, localpath, obtain, init from bb.parse import ParseError @@ -44,6 +44,13 @@ __bbpath_found__ = 0 __classname__ = "" classes = [ None, ] +# We need to indicate EOF to the feeder. This code is so messy that +# factoring it out to a close_parse_file method is out of question. +# We will use the IN_PYTHON_EOF as an indicator to just close the method +# +# The two parts using it are tightly integrated anyway +IN_PYTHON_EOF = -9999999999999 + __parsed_methods__ = methodpool.get_parsed_dict() def supports(fn, d): @@ -60,9 +67,9 @@ def inherit(files, d): file = os.path.join('classes', '%s.bbclass' % file) if not file in __inherit_cache.split(): - debug(2, "BB %s:%d: inheriting %s" % (fn, lineno, file)) + bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s:%d: inheriting %s" % (fn, lineno, file)) __inherit_cache += " %s" % file - include(fn, file, d) + include(fn, file, d, "inherit") data.setVar('__inherit_cache', __inherit_cache, d) @@ -75,9 +82,9 @@ def handle(fn, d, include = 0): __residue__ = [] if include == 0: - debug(2, "BB " + fn + ": handle(data)") + bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data)") else: - debug(2, "BB " + fn + ": handle(data, include)") + bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data, include)") (root, ext) = os.path.splitext(os.path.basename(fn)) base_name = "%s%s" % (root,ext) @@ -132,7 +139,7 @@ def handle(fn, d, include = 0): feeder(lineno, s, fn, base_name, d) if __inpython__: # add a blank line to close out any python definition - feeder(lineno + 1, "", fn, base_name, d) + feeder(IN_PYTHON_EOF, "", fn, base_name, d) if ext == ".bbclass": classes.remove(__classname__) else: @@ -152,7 +159,7 @@ def handle(fn, d, include = 0): if t: data.setVar('T', t, d) except Exception, e: - bb.debug(1, "executing anonymous function: %s" % e) + bb.msg.debug(1, bb.msg.domain.Parsing, "executing anonymous function: %s" % e) raise data.delVar("__anonqueue", d) data.delVar("__anonfunc", d) @@ -220,7 +227,7 @@ def feeder(lineno, s, fn, root, d): if __inpython__: m = __python_func_regexp__.match(s) - if m: + if m and lineno != IN_PYTHON_EOF: __body__.append(s) return else: @@ -240,6 +247,9 @@ def feeder(lineno, s, fn, root, d): __body__ = [] __inpython__ = False + if lineno == IN_PYTHON_EOF: + return + # fall through if s == '' or s[0] == '#': return # skip comments and empty lines @@ -374,7 +384,7 @@ def vars_from_file(mypkg, d): def set_additional_vars(file, d, include): """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}""" - debug(2,"BB %s: set_additional_vars" % file) + bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s: set_additional_vars" % file) src_uri = data.getVar('SRC_URI', d) if not src_uri: diff --git a/bitbake/lib/bb/parse/parse_py/ConfHandler.py b/bitbake/lib/bb/parse/parse_py/ConfHandler.py index 90978300af..4bc2bbc2b7 100644 --- a/bitbake/lib/bb/parse/parse_py/ConfHandler.py +++ b/bitbake/lib/bb/parse/parse_py/ConfHandler.py @@ -22,7 +22,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA.""" import re, bb.data, os, sys -from bb import debug, fatal from bb.parse import ParseError #__config_regexp__ = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}]+)\s*(?P<colon>:)?(?P<ques>\?)?=\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$") @@ -53,7 +52,7 @@ def localpath(fn, d): localfn = fn return localfn -def obtain(fn, data = bb.data.init()): +def obtain(fn, data): import sys, bb fn = bb.data.expand(fn, data) localfn = bb.data.expand(localpath(fn, data), data) @@ -61,30 +60,30 @@ def obtain(fn, data = bb.data.init()): if localfn != fn: dldir = bb.data.getVar('DL_DIR', data, 1) if not dldir: - debug(1, "obtain: DL_DIR not defined") + bb.msg.debug(1, bb.msg.domain.Parsing, "obtain: DL_DIR not defined") return localfn bb.mkdirhier(dldir) try: bb.fetch.init([fn]) except bb.fetch.NoMethodError: (type, value, traceback) = sys.exc_info() - debug(1, "obtain: no method: %s" % value) + bb.msg.debug(1, bb.msg.domain.Parsing, "obtain: no method: %s" % value) return localfn try: bb.fetch.go(data) except bb.fetch.MissingParameterError: (type, value, traceback) = sys.exc_info() - debug(1, "obtain: missing parameters: %s" % value) + bb.msg.debug(1, bb.msg.domain.Parsing, "obtain: missing parameters: %s" % value) return localfn except bb.fetch.FetchError: (type, value, traceback) = sys.exc_info() - debug(1, "obtain: failed: %s" % value) + bb.msg.debug(1, bb.msg.domain.Parsing, "obtain: failed: %s" % value) return localfn return localfn -def include(oldfn, fn, data = bb.data.init(), error_out = False): +def include(oldfn, fn, data, error_out): """ error_out If True a ParseError will be reaised if the to be included @@ -101,10 +100,10 @@ def include(oldfn, fn, data = bb.data.init(), error_out = False): ret = handle(fn, data, True) except IOError: if error_out: - raise ParseError("Could not include required file %(fn)s" % vars() ) - debug(2, "CONF file '%s' not found" % fn) + raise ParseError("Could not %(error_out)s file %(fn)s" % vars() ) + bb.msg.debug(2, bb.msg.domain.Parsing, "CONF file '%s' not found" % fn) -def handle(fn, data = bb.data.init(), include = 0): +def handle(fn, data, include = 0): if include: inc_string = "including" else: @@ -129,13 +128,13 @@ def handle(fn, data = bb.data.init(), include = 0): if os.access(currname, os.R_OK): f = open(currname, 'r') abs_fn = currname - debug(1, "CONF %s %s" % (inc_string, currname)) + bb.msg.debug(2, bb.msg.domain.Parsing, "CONF %s %s" % (inc_string, currname)) break if f is None: raise IOError("file '%s' not found" % fn) else: f = open(fn,'r') - debug(1, "CONF %s %s" % (inc_string,fn)) + bb.msg.debug(1, bb.msg.domain.Parsing, "CONF %s %s" % (inc_string,fn)) abs_fn = fn if include: @@ -161,7 +160,7 @@ def handle(fn, data = bb.data.init(), include = 0): bb.data.setVar('FILE', oldfile, data) return data -def feeder(lineno, s, fn, data = bb.data.init()): +def feeder(lineno, s, fn, data): m = __config_regexp__.match(s) if m: groupd = m.groupdict() @@ -185,7 +184,7 @@ def feeder(lineno, s, fn, data = bb.data.init()): else: val = groupd["value"] if 'flag' in groupd and groupd['flag'] != None: -# bb.note("setVarFlag(%s, %s, %s, data)" % (key, groupd['flag'], val)) + bb.msg.debug(3, bb.msg.domain.Parsing, "setVarFlag(%s, %s, %s, data)" % (key, groupd['flag'], val)) bb.data.setVarFlag(key, groupd['flag'], val, data) else: bb.data.setVar(key, val, data) @@ -194,14 +193,14 @@ def feeder(lineno, s, fn, data = bb.data.init()): m = __include_regexp__.match(s) if m: s = bb.data.expand(m.group(1), data) -# debug(2, "CONF %s:%d: including %s" % (fn, lineno, s)) - include(fn, s, data) + bb.msg.debug(3, bb.msg.domain.Parsing, "CONF %s:%d: including %s" % (fn, lineno, s)) + include(fn, s, data, False) return m = __require_regexp__.match(s) if m: s = bb.data.expand(m.group(1), data) - include(fn, s, data, True) + include(fn, s, data, "include required") return raise ParseError("%s:%d: unparsed line: '%s'" % (fn, lineno, s)); diff --git a/bitbake/lib/bb/providers.py b/bitbake/lib/bb/providers.py new file mode 100644 index 0000000000..3cb7cc1f07 --- /dev/null +++ b/bitbake/lib/bb/providers.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python +# ex:ts=4:sw=4:sts=4:et +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +# +# Copyright (C) 2003, 2004 Chris Larson +# Copyright (C) 2003, 2004 Phil Blundell +# Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer +# Copyright (C) 2005 Holger Hans Peter Freyther +# Copyright (C) 2005 ROAD GmbH +# Copyright (C) 2006 Richard Purdie +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# 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., 59 Temple +# Place, Suite 330, Boston, MA 02111-1307 USA. + +import os, re +from bb import data, utils +import bb + +class NoProvider(Exception): + """Exception raised when no provider of a build dependency can be found""" + +class NoRProvider(Exception): + """Exception raised when no provider of a runtime dependency can be found""" + +def findBestProvider(pn, cfgData, dataCache, pkg_pn = None, item = None): + """ + If there is a PREFERRED_VERSION, find the highest-priority bbfile + providing that version. If not, find the latest version provided by + an bbfile in the highest-priority set. + """ + if not pkg_pn: + pkg_pn = dataCache.pkg_pn + + files = pkg_pn[pn] + priorities = {} + for f in files: + priority = dataCache.bbfile_priority[f] + if priority not in priorities: + priorities[priority] = [] + priorities[priority].append(f) + p_list = priorities.keys() + p_list.sort(lambda a, b: a - b) + tmp_pn = [] + for p in p_list: + tmp_pn = [priorities[p]] + tmp_pn + + preferred_file = None + + localdata = data.createCopy(cfgData) + bb.data.setVar('OVERRIDES', "%s:%s" % (pn, data.getVar('OVERRIDES', localdata)), localdata) + bb.data.update_data(localdata) + + preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, localdata, True) + if preferred_v: + m = re.match('(.*)_(.*)', preferred_v) + if m: + preferred_v = m.group(1) + preferred_r = m.group(2) + else: + preferred_r = None + + for file_set in tmp_pn: + for f in file_set: + pv,pr = dataCache.pkg_pvpr[f] + if preferred_v == pv and (preferred_r == pr or preferred_r == None): + preferred_file = f + preferred_ver = (pv, pr) + break + if preferred_file: + break; + if preferred_r: + pv_str = '%s-%s' % (preferred_v, preferred_r) + else: + pv_str = preferred_v + itemstr = "" + if item: + itemstr = " (for item %s)" % item + if preferred_file is None: + bb.msg.note(1, bb.msg.domain.Provider, "preferred version %s of %s not available%s" % (pv_str, pn, itemstr)) + else: + bb.msg.debug(1, bb.msg.domain.Provider, "selecting %s as PREFERRED_VERSION %s of package %s%s" % (preferred_file, pv_str, pn, itemstr)) + + del localdata + + # get highest priority file set + files = tmp_pn[0] + latest = None + latest_p = 0 + latest_f = None + for file_name in files: + pv,pr = dataCache.pkg_pvpr[file_name] + dp = dataCache.pkg_dp[file_name] + + if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p): + latest = (pv, pr) + latest_f = file_name + latest_p = dp + if preferred_file is None: + preferred_file = latest_f + preferred_ver = latest + + return (latest,latest_f,preferred_ver, preferred_file) + +# +# RP - build_cache_fail needs to move elsewhere +# +def filterProviders(providers, item, cfgData, dataCache, build_cache_fail = {}): + """ + Take a list of providers and filter/reorder according to the + environment variables and previous build results + """ + eligible = [] + preferred_versions = {} + + # Collate providers by PN + pkg_pn = {} + for p in providers: + pn = dataCache.pkg_fn[p] + if pn not in pkg_pn: + pkg_pn[pn] = [] + pkg_pn[pn].append(p) + + bb.msg.debug(1, bb.msg.domain.Provider, "providers for %s are: %s" % (item, pkg_pn.keys())) + + for pn in pkg_pn.keys(): + preferred_versions[pn] = bb.providers.findBestProvider(pn, cfgData, dataCache, pkg_pn, item)[2:4] + eligible.append(preferred_versions[pn][1]) + + + for p in eligible: + if p in build_cache_fail: + bb.msg.debug(1, bb.msg.domain.Provider, "rejecting already-failed %s" % p) + eligible.remove(p) + + if len(eligible) == 0: + bb.msg.error(bb.msg.domain.Provider, "no eligible providers for %s" % item) + return 0 + + + # If pn == item, give it a slight default preference + # This means PREFERRED_PROVIDER_foobar defaults to foobar if available + for p in providers: + pn = dataCache.pkg_fn[p] + if pn != item: + continue + (newvers, fn) = preferred_versions[pn] + if not fn in eligible: + continue + eligible.remove(fn) + eligible = [fn] + eligible + + # look to see if one of them is already staged, or marked as preferred. + # if so, bump it to the head of the queue + for p in providers: + pn = dataCache.pkg_fn[p] + pv, pr = dataCache.pkg_pvpr[p] + + stamp = '%s.do_populate_staging' % dataCache.stamp[p] + if os.path.exists(stamp): + (newvers, fn) = preferred_versions[pn] + if not fn in eligible: + # package was made ineligible by already-failed check + continue + oldver = "%s-%s" % (pv, pr) + newver = '-'.join(newvers) + if (newver != oldver): + extra_chat = "%s (%s) already staged but upgrading to %s to satisfy %s" % (pn, oldver, newver, item) + else: + extra_chat = "Selecting already-staged %s (%s) to satisfy %s" % (pn, oldver, item) + + bb.msg.note(2, bb.msg.domain.Provider, "%s" % extra_chat) + eligible.remove(fn) + eligible = [fn] + eligible + break + + return eligible + +def getRuntimeProviders(dataCache, rdepend): + """ + Return any providers of runtime dependency + """ + rproviders = [] + + if rdepend in dataCache.rproviders: + rproviders += dataCache.rproviders[rdepend] + + if rdepend in dataCache.packages: + rproviders += dataCache.packages[rdepend] + + if rproviders: + return rproviders + + # Only search dynamic packages if we can't find anything in other variables + for pattern in dataCache.packages_dynamic: + regexp = re.compile(pattern) + if regexp.match(rdepend): + rproviders += dataCache.packages_dynamic[pattern] + + return rproviders diff --git a/bitbake/lib/bb/runqueue.py b/bitbake/lib/bb/runqueue.py new file mode 100644 index 0000000000..3dde9a9ffb --- /dev/null +++ b/bitbake/lib/bb/runqueue.py @@ -0,0 +1,491 @@ + #!/usr/bin/env python +# ex:ts=4:sw=4:sts=4:et +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +""" +BitBake 'RunQueue' implementation + +Handles preparation and execution of a queue of tasks + +Copyright (C) 2006 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 +""" + +from bb import msg, data, fetch, event, mkdirhier, utils +from sets import Set +import bb, os, sys + +class TaskFailure(Exception): + """Exception raised when a task in a runqueue fails""" + + def __init__(self, fnid, fn, taskname): + self.args = fnid, fn, taskname + +class RunQueue: + """ + BitBake Run Queue implementation + """ + def __init__(self): + self.reset_runqueue() + + def reset_runqueue(self): + self.runq_fnid = [] + self.runq_task = [] + self.runq_depends = [] + self.runq_revdeps = [] + self.runq_weight = [] + self.prio_map = [] + + def get_user_idstring(self, task, taskData): + fn = taskData.fn_index[self.runq_fnid[task]] + taskname = self.runq_task[task] + return "%s, %s" % (fn, taskname) + + def prepare_runqueue(self, cfgData, dataCache, taskData, targets): + """ + Turn a set of taskData into a RunQueue and compute data needed + to optimise the execution order. + targets is list of paired values - a provider name and the task to run + """ + + depends = [] + runq_weight1 = [] + runq_build = [] + runq_done = [] + + bb.msg.note(1, bb.msg.domain.RunQueue, "Preparing Runqueue") + + for task in range(len(taskData.tasks_name)): + fnid = taskData.tasks_fnid[task] + fn = taskData.fn_index[fnid] + task_deps = dataCache.task_deps[fn] + + if fnid not in taskData.failed_fnids: + + depends = taskData.tasks_tdepends[task] + + # Resolve Depends + if 'deptask' in task_deps and taskData.tasks_name[task] in task_deps['deptask']: + taskname = task_deps['deptask'][taskData.tasks_name[task]] + for depid in taskData.depids[fnid]: + if depid in taskData.build_targets: + depdata = taskData.build_targets[depid][0] + if depdata: + dep = taskData.fn_index[depdata] + depends.append(taskData.gettask_id(dep, taskname)) + + # Resolve Runtime Depends + if 'rdeptask' in task_deps and taskData.tasks_name[task] in task_deps['rdeptask']: + taskname = task_deps['rdeptask'][taskData.tasks_name[task]] + for depid in taskData.rdepids[fnid]: + if depid in taskData.run_targets: + depdata = taskData.run_targets[depid][0] + if depdata: + dep = taskData.fn_index[depdata] + depends.append(taskData.gettask_id(dep, taskname)) + + def add_recursive_build(depid): + """ + Add build depends of depid to depends + (if we've not see it before) + (calls itself recursively) + """ + if str(depid) in dep_seen: + return + dep_seen.append(depid) + if depid in taskData.build_targets: + depdata = taskData.build_targets[depid][0] + if depdata: + dep = taskData.fn_index[depdata] + taskid = taskData.gettask_id(dep, taskname) + depends.append(taskid) + fnid = taskData.tasks_fnid[taskid] + for nextdepid in taskData.depids[fnid]: + if nextdepid not in dep_seen: + add_recursive_build(nextdepid) + for nextdepid in taskData.rdepids[fnid]: + if nextdepid not in rdep_seen: + add_recursive_run(nextdepid) + + def add_recursive_run(rdepid): + """ + Add runtime depends of rdepid to depends + (if we've not see it before) + (calls itself recursively) + """ + if str(rdepid) in rdep_seen: + return + rdep_seen.append(rdepid) + if rdepid in taskData.run_targets: + depdata = taskData.run_targets[rdepid][0] + if depdata: + dep = taskData.fn_index[depdata] + taskid = taskData.gettask_id(dep, taskname) + depends.append(taskid) + fnid = taskData.tasks_fnid[taskid] + for nextdepid in taskData.depids[fnid]: + if nextdepid not in dep_seen: + add_recursive_build(nextdepid) + for nextdepid in taskData.rdepids[fnid]: + if nextdepid not in rdep_seen: + add_recursive_run(nextdepid) + + + # Resolve Recursive Runtime Depends + # Also includes all Build Depends (and their runtime depends) + if 'recrdeptask' in task_deps and taskData.tasks_name[task] in task_deps['recrdeptask']: + dep_seen = [] + rdep_seen = [] + taskname = task_deps['recrdeptask'][taskData.tasks_name[task]] + for depid in taskData.depids[fnid]: + add_recursive_build(depid) + for rdepid in taskData.rdepids[fnid]: + add_recursive_run(rdepid) + + #Prune self references + if task in depends: + newdep = [] + bb.msg.debug(2, bb.msg.domain.RunQueue, "Task %s (%s %s) contains self reference! %s" % (task, taskData.fn_index[taskData.tasks_fnid[task]], taskData.tasks_name[task], depends)) + for dep in depends: + if task != dep: + newdep.append(dep) + depends = newdep + + + self.runq_fnid.append(taskData.tasks_fnid[task]) + self.runq_task.append(taskData.tasks_name[task]) + self.runq_depends.append(Set(depends)) + self.runq_revdeps.append(Set()) + self.runq_weight.append(0) + + runq_weight1.append(0) + runq_build.append(0) + runq_done.append(0) + + bb.msg.note(2, bb.msg.domain.RunQueue, "Marking Active Tasks") + + def mark_active(listid, depth): + """ + Mark an item as active along with its depends + (calls itself recursively) + """ + + if runq_build[listid] == 1: + return + + runq_build[listid] = 1 + + depends = self.runq_depends[listid] + for depend in depends: + mark_active(depend, depth+1) + + for target in targets: + targetid = taskData.getbuild_id(target[0]) + if targetid in taskData.failed_deps: + continue + + if targetid not in taskData.build_targets: + continue + + fnid = taskData.build_targets[targetid][0] + if fnid in taskData.failed_fnids: + continue + + listid = taskData.tasks_lookup[fnid][target[1]] + + mark_active(listid, 1) + + # Prune inactive tasks + maps = [] + delcount = 0 + for listid in range(len(self.runq_fnid)): + if runq_build[listid-delcount] == 1: + maps.append(listid-delcount) + else: + del self.runq_fnid[listid-delcount] + del self.runq_task[listid-delcount] + del self.runq_depends[listid-delcount] + del self.runq_weight[listid-delcount] + del runq_weight1[listid-delcount] + del runq_build[listid-delcount] + del runq_done[listid-delcount] + del self.runq_revdeps[listid-delcount] + delcount = delcount + 1 + maps.append(-1) + + if len(self.runq_fnid) == 0: + if not taskData.abort: + bb.msg.note(1, bb.msg.domain.RunQueue, "All possible tasks have been run but build incomplete (--continue mode). See errors above for incomplete tasks.") + return + bb.msg.fatal(bb.msg.domain.RunQueue, "No active tasks and not in --continue mode?! Please report this bug.") + + bb.msg.note(2, bb.msg.domain.RunQueue, "Pruned %s inactive tasks, %s left" % (delcount, len(self.runq_fnid))) + + for listid in range(len(self.runq_fnid)): + newdeps = [] + origdeps = self.runq_depends[listid] + for origdep in origdeps: + if maps[origdep] == -1: + bb.msg.fatal(bb.msg.domain.RunQueue, "Invalid mapping - Should never happen!") + newdeps.append(maps[origdep]) + self.runq_depends[listid] = Set(newdeps) + + bb.msg.note(2, bb.msg.domain.RunQueue, "Assign Weightings") + + for listid in range(len(self.runq_fnid)): + for dep in self.runq_depends[listid]: + self.runq_revdeps[dep].add(listid) + + endpoints = [] + for listid in range(len(self.runq_fnid)): + revdeps = self.runq_revdeps[listid] + if len(revdeps) == 0: + runq_done[listid] = 1 + self.runq_weight[listid] = 1 + endpoints.append(listid) + for dep in revdeps: + if dep in self.runq_depends[listid]: + #self.dump_data(taskData) + bb.msg.fatal(bb.msg.domain.RunQueue, "Task %s (%s) has circular dependency on %s (%s)" % (taskData.fn_index[self.runq_fnid[dep]], self.runq_task[dep] , taskData.fn_index[self.runq_fnid[listid]], self.runq_task[listid])) + runq_weight1[listid] = len(revdeps) + + bb.msg.note(2, bb.msg.domain.RunQueue, "Compute totals (have %s endpoint(s))" % len(endpoints)) + + while 1: + next_points = [] + for listid in endpoints: + for revdep in self.runq_depends[listid]: + self.runq_weight[revdep] = self.runq_weight[revdep] + self.runq_weight[listid] + runq_weight1[revdep] = runq_weight1[revdep] - 1 + if runq_weight1[revdep] == 0: + next_points.append(revdep) + runq_done[revdep] = 1 + endpoints = next_points + if len(next_points) == 0: + break + + # Sanity Checks + for task in range(len(self.runq_fnid)): + if runq_done[task] == 0: + seen = [] + deps_seen = [] + def print_chain(taskid, finish): + seen.append(taskid) + for revdep in self.runq_revdeps[taskid]: + if runq_done[revdep] == 0 and revdep not in seen and not finish: + bb.msg.error(bb.msg.domain.RunQueue, "Task %s (%s) (depends: %s)" % (revdep, self.get_user_idstring(revdep, taskData), self.runq_depends[revdep])) + if revdep in deps_seen: + bb.msg.error(bb.msg.domain.RunQueue, "Chain ends at Task %s (%s)" % (revdep, self.get_user_idstring(revdep, taskData))) + finish = True + return + for dep in self.runq_depends[revdep]: + deps_seen.append(dep) + print_chain(revdep, finish) + print_chain(task, False) + bb.msg.fatal(bb.msg.domain.RunQueue, "Task %s (%s) not processed!\nThis is probably a circular dependency (the chain might be printed above)." % (task, self.get_user_idstring(task, taskData))) + if runq_weight1[task] != 0: + bb.msg.fatal(bb.msg.domain.RunQueue, "Task %s (%s) count not zero!" % (task, self.get_user_idstring(task, taskData))) + + # Make a weight sorted map + from copy import deepcopy + + sortweight = deepcopy(self.runq_weight) + sortweight.sort() + copyweight = deepcopy(self.runq_weight) + self.prio_map = [] + + for weight in sortweight: + idx = copyweight.index(weight) + self.prio_map.append(idx) + copyweight[idx] = -1 + self.prio_map.reverse() + + #self.dump_data(taskData) + + def execute_runqueue(self, cooker, cfgData, dataCache, taskData, runlist): + """ + Run the tasks in a queue prepared by prepare_runqueue + Upon failure, optionally try to recover the build using any alternate providers + (if the abort on failure configuration option isn't set) + """ + + failures = 0 + while 1: + try: + self.execute_runqueue_internal(cooker, cfgData, dataCache, taskData) + return failures + except bb.runqueue.TaskFailure, (fnid, taskData.fn_index[fnid], taskname): + if taskData.abort: + raise + taskData.fail_fnid(fnid) + self.reset_runqueue() + self.prepare_runqueue(cfgData, dataCache, taskData, runlist) + failures = failures + 1 + + def execute_runqueue_internal(self, cooker, cfgData, dataCache, taskData): + """ + Run the tasks in a queue prepared by prepare_runqueue + """ + + bb.msg.note(1, bb.msg.domain.RunQueue, "Executing runqueue") + + runq_buildable = [] + runq_running = [] + runq_complete = [] + active_builds = 0 + build_pids = {} + + if len(self.runq_fnid) == 0: + # nothing to do + return + + def get_next_task(data): + """ + Return the id of the highest priority task that is buildable + """ + for task1 in range(len(data.runq_fnid)): + task = data.prio_map[task1] + if runq_running[task] == 1: + continue + if runq_buildable[task] == 1: + return task + return None + + def task_complete(data, task): + """ + Mark a task as completed + Look at the reverse dependencies and mark any task with + completed dependencies as buildable + """ + runq_complete[task] = 1 + for revdep in data.runq_revdeps[task]: + if runq_running[revdep] == 1: + continue + if runq_buildable[revdep] == 1: + continue + alldeps = 1 + for dep in data.runq_depends[revdep]: + if runq_complete[dep] != 1: + alldeps = 0 + if alldeps == 1: + runq_buildable[revdep] = 1 + fn = taskData.fn_index[self.runq_fnid[revdep]] + taskname = self.runq_task[revdep] + bb.msg.debug(1, bb.msg.domain.RunQueue, "Marking task %s (%s, %s) as buildable" % (revdep, fn, taskname)) + + # Mark initial buildable tasks + for task in range(len(self.runq_fnid)): + runq_running.append(0) + runq_complete.append(0) + if len(self.runq_depends[task]) == 0: + runq_buildable.append(1) + else: + runq_buildable.append(0) + + + number_tasks = int(bb.data.getVar("BB_NUMBER_THREADS", cfgData) or 1) + + try: + while 1: + task = get_next_task(self) + if task is not None: + fn = taskData.fn_index[self.runq_fnid[task]] + taskname = self.runq_task[task] + + if bb.build.stamp_is_current_cache(dataCache, fn, taskname): + targetid = taskData.gettask_id(fn, taskname) + if not (targetid in taskData.external_targets and cooker.configuration.force): + bb.msg.debug(2, bb.msg.domain.RunQueue, "Stamp current task %s (%s)" % (task, self.get_user_idstring(task, taskData))) + runq_running[task] = 1 + task_complete(self, task) + continue + + bb.msg.debug(1, bb.msg.domain.RunQueue, "Running task %s (%s)" % (task, self.get_user_idstring(task, taskData))) + try: + pid = os.fork() + except OSError, e: + bb.msg.fatal(bb.msg.domain.RunQueue, "fork failed: %d (%s)" % (e.errno, e.strerror)) + if pid == 0: + cooker.configuration.cmd = taskname[3:] + try: + cooker.tryBuild(fn, False) + except bb.build.EventException: + bb.msg.error(bb.msg.domain.Build, "Build of " + fn + " " + taskname + " failed") + sys.exit(1) + except: + bb.msg.error(bb.msg.domain.Build, "Build of " + fn + " " + taskname + " failed") + raise + sys.exit(0) + build_pids[pid] = task + runq_running[task] = 1 + active_builds = active_builds + 1 + if active_builds < number_tasks: + continue + if active_builds > 0: + result = os.waitpid(-1, 0) + active_builds = active_builds - 1 + task = build_pids[result[0]] + if result[1] != 0: + bb.msg.error(bb.msg.domain.RunQueue, "Task %s (%s) failed" % (task, self.get_user_idstring(task, taskData))) + raise bb.runqueue.TaskFailure(self.runq_fnid[task], taskData.fn_index[self.runq_fnid[task]], self.runq_task[task]) + task_complete(self, task) + del build_pids[result[0]] + continue + break + except SystemExit: + raise + except: + bb.msg.error(bb.msg.domain.RunQueue, "Exception received") + while active_builds > 0: + bb.msg.note(1, bb.msg.domain.RunQueue, "Waiting for %s active tasks to finish" % active_builds) + tasknum = 1 + for k, v in build_pids.iteritems(): + bb.msg.note(1, bb.msg.domain.RunQueue, "%s: %s (%s)" % (tasknum, self.get_user_idstring(v, taskData), k)) + tasknum = tasknum + 1 + result = os.waitpid(-1, 0) + del build_pids[result[0]] + active_builds = active_builds - 1 + raise + + # Sanity Checks + for task in range(len(self.runq_fnid)): + if runq_buildable[task] == 0: + bb.msg.error(bb.msg.domain.RunQueue, "Task %s never buildable!" % task) + if runq_running[task] == 0: + bb.msg.error(bb.msg.domain.RunQueue, "Task %s never ran!" % task) + if runq_complete[task] == 0: + bb.msg.error(bb.msg.domain.RunQueue, "Task %s never completed!" % task) + + return 0 + + def dump_data(self, taskQueue): + """ + Dump some debug information on the internal data structures + """ + bb.msg.debug(3, bb.msg.domain.RunQueue, "run_tasks:") + for task in range(len(self.runq_fnid)): + bb.msg.debug(3, bb.msg.domain.RunQueue, " (%s)%s - %s: %s Deps %s RevDeps %s" % (task, + taskQueue.fn_index[self.runq_fnid[task]], + self.runq_task[task], + self.runq_weight[task], + self.runq_depends[task], + self.runq_revdeps[task])) + + bb.msg.debug(3, bb.msg.domain.RunQueue, "sorted_tasks:") + for task1 in range(len(self.runq_fnid)): + if task1 in self.prio_map: + task = self.prio_map[task1] + bb.msg.debug(3, bb.msg.domain.RunQueue, " (%s)%s - %s: %s Deps %s RevDeps %s" % (task, + taskQueue.fn_index[self.runq_fnid[task]], + self.runq_task[task], + self.runq_weight[task], + self.runq_depends[task], + self.runq_revdeps[task])) diff --git a/bitbake/lib/bb/shell.py b/bitbake/lib/bb/shell.py index 93ad00d1ed..760c371d90 100644 --- a/bitbake/lib/bb/shell.py +++ b/bitbake/lib/bb/shell.py @@ -56,9 +56,8 @@ try: set except NameError: from sets import Set as set -import sys, os, imp, readline, socket, httplib, urllib, commands, popen2, copy, shlex, Queue, fnmatch -imp.load_source( "bitbake", os.path.dirname( sys.argv[0] )+"/bitbake" ) -from bb import data, parse, build, fatal +import sys, os, readline, socket, httplib, urllib, commands, popen2, copy, shlex, Queue, fnmatch +from bb import data, parse, build, fatal, cache, taskdata, runqueue, providers as Providers __version__ = "0.5.3.1" __credits__ = """BitBake Shell Version %s (C) 2005 Michael 'Mickey' Lauer <mickey@Vanille.de> @@ -108,7 +107,7 @@ class BitBakeShellCommands: preferred = data.getVar( "PREFERRED_PROVIDER_%s" % item, cooker.configuration.data, 1 ) if not preferred: preferred = item try: - lv, lf, pv, pf = cooker.findBestProvider( preferred ) + lv, lf, pv, pf = Providers.findBestProvider(preferred, cooker.configuration.data, cooker.status, cooker.build_cache_fail) except KeyError: if item in cooker.status.providers: pf = cooker.status.providers[item][0] @@ -156,14 +155,39 @@ class BitBakeShellCommands: cooker.build_cache = [] cooker.build_cache_fail = [] - for name in names: - try: - cooker.buildProvider( name, data.getVar("BUILD_ALL_DEPS", cooker.configuration.data, True) ) - except build.EventException, e: - print "ERROR: Couldn't build '%s'" % name - global last_exception - last_exception = e - break + td = taskdata.TaskData(cooker.configuration.abort) + + try: + tasks = [] + for name in names: + td.add_provider(cooker.configuration.data, cooker.status, name) + providers = td.get_provider(name) + + if len(providers) == 0: + raise Providers.NoProvider + + tasks.append([name, "do_%s" % cooker.configuration.cmd]) + + td.add_unresolved(cooker.configuration.data, cooker.status) + + rq = runqueue.RunQueue() + rq.prepare_runqueue(cooker.configuration.data, cooker.status, td, tasks) + rq.execute_runqueue(cooker, cooker.configuration.data, cooker.status, td, tasks) + + except Providers.NoProvider: + print "ERROR: No Provider" + global last_exception + last_exception = Providers.NoProvider + + except runqueue.TaskFailure, (fnid, fn, taskname): + print "ERROR: '%s, %s' failed" % (fn, taskname) + global last_exception + last_exception = runqueue.TaskFailure + + except build.EventException, e: + print "ERROR: Couldn't build '%s'" % names + global last_exception + last_exception = e cooker.configuration.cmd = oldcmd @@ -233,7 +257,7 @@ class BitBakeShellCommands: item = data.getVar('PN', bbfile_data, 1) data.setVar( "_task_cache", [], bbfile_data ) # force try: - cooker.tryBuildPackage( os.path.abspath( bf ), item, bbfile_data ) + cooker.tryBuildPackage( os.path.abspath( bf ), item, cmd, bbfile_data, True ) except build.EventException, e: print "ERROR: Couldn't build '%s'" % name global last_exception @@ -255,8 +279,7 @@ class BitBakeShellCommands: def fileRebuild( self, params ): """Rebuild (clean & build) a .bb file""" - self.fileClean( params ) - self.fileBuild( params ) + self.fileBuild( params, "rebuild" ) fileRebuild.usage = "<bbfile>" def fileReparse( self, params ): @@ -265,14 +288,19 @@ class BitBakeShellCommands: print "SHELL: Parsing '%s'" % bbfile parse.update_mtime( bbfile ) cooker.bb_cache.cacheValidUpdate(bbfile) - fromCache = cooker.bb_cache.loadData(bbfile, cooker) + fromCache = cooker.bb_cache.loadData(bbfile, cooker.configuration.data) cooker.bb_cache.sync() - if False: #from Cache + if False: #fromCache: print "SHELL: File has not been updated, not reparsing" else: print "SHELL: Parsed" fileReparse.usage = "<bbfile>" + def abort( self, params ): + """Toggle abort task execution flag (see bitbake -k)""" + cooker.configuration.abort = not cooker.configuration.abort + print "SHELL: Abort Flag is now '%s'" % repr( cooker.configuration.abort ) + def force( self, params ): """Toggle force task execution flag (see bitbake -f)""" cooker.configuration.force = not cooker.configuration.force @@ -365,18 +393,14 @@ SRC_URI = "" new.usage = "<directory> <filename>" def pasteBin( self, params ): - """Send a command + output buffer to http://pastebin.com""" + """Send a command + output buffer to the pastebin at http://rafb.net/paste""" index = params[0] contents = self._shell.myout.buffer( int( index ) ) - status, error, location = sendToPastebin( contents ) - if status == 302: - print "SHELL: Pasted to %s" % location - else: - print "ERROR: %s %s" % ( status, error ) + sendToPastebin( "output of " + params[0], contents ) pasteBin.usage = "<index>" def pasteLog( self, params ): - """Send the last event exception error log (if there is one) to http://oe.pastebin.com""" + """Send the last event exception error log (if there is one) to http://rafb.net/paste""" if last_exception is None: print "SHELL: No Errors yet (Phew)..." else: @@ -387,12 +411,8 @@ SRC_URI = "" filename = filename.strip() print "SHELL: Pasting log file to pastebin..." - status, error, location = sendToPastebin( open( filename ).read() ) - - if status == 302: - print "SHELL: Pasted to %s" % location - else: - print "ERROR: %s %s" % ( status, error ) + file = open( filename ).read() + sendToPastebin( "contents of " + filename, file ) def patch( self, params ): """Execute 'patch' command on a providee""" @@ -401,12 +421,13 @@ SRC_URI = "" def parse( self, params ): """(Re-)parse .bb files and calculate the dependency graph""" - cooker.status = cooker.ParsingStatus() + cooker.status = cache.CacheData() ignore = data.getVar("ASSUME_PROVIDED", cooker.configuration.data, 1) or "" cooker.status.ignored_dependencies = set( ignore.split() ) cooker.handleCollections( data.getVar("BBFILE_COLLECTIONS", cooker.configuration.data, 1) ) - cooker.collect_bbfiles( cooker.myProgressCallback ) + (filelist, masked) = cooker.collect_bbfiles() + cooker.parse_bbfiles(filelist, masked, cooker.myProgressCallback) cooker.buildDepgraph() global parsed parsed = True @@ -434,7 +455,7 @@ SRC_URI = "" name, var = params bbfile = self._findProvider( name ) if bbfile is not None: - the_data = cooker.bb_cache.loadDataFull(bbfile, cooker) + the_data = cooker.bb_cache.loadDataFull(bbfile, cooker.configuration.data) value = the_data.getVar( var, 1 ) print value else: @@ -538,7 +559,8 @@ SRC_URI = "" if not preferred: preferred = item try: - lv, lf, pv, pf = cooker.findBestProvider( preferred ) + lv, lf, pv, pf = Providers.findBestProvider(preferred, cooker.configuration.data, cooker.status, +cooker.build_cache_fail) except KeyError: lv, lf, pv, pf = (None,)*4 @@ -565,24 +587,29 @@ def completeFilePath( bbfile ): return key return bbfile -def sendToPastebin( content ): +def sendToPastebin( desc, content ): """Send content to http://oe.pastebin.com""" mydata = {} - mydata["parent_pid"] = "" - mydata["format"] = "bash" - mydata["code2"] = content - mydata["paste"] = "Send" - mydata["poster"] = "%s@%s" % ( os.environ.get( "USER", "unknown" ), socket.gethostname() or "unknown" ) + mydata["lang"] = "Plain Text" + mydata["desc"] = desc + mydata["cvt_tabs"] = "No" + mydata["nick"] = "%s@%s" % ( os.environ.get( "USER", "unknown" ), socket.gethostname() or "unknown" ) + mydata["text"] = content params = urllib.urlencode( mydata ) headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"} - conn = httplib.HTTPConnection( "oe.pastebin.com:80" ) - conn.request("POST", "/", params, headers ) + host = "rafb.net" + conn = httplib.HTTPConnection( "%s:80" % host ) + conn.request("POST", "/paste/paste.php", params, headers ) response = conn.getresponse() conn.close() - return response.status, response.reason, response.getheader( "location" ) or "unknown" + if response.status == 302: + location = response.getheader( "location" ) or "unknown" + print "SHELL: Pasted to http://%s%s" % ( host, location ) + else: + print "ERROR: %s %s" % ( response.status, response.reason ) def completer( text, state ): """Return a possible readline completion""" diff --git a/bitbake/lib/bb/taskdata.py b/bitbake/lib/bb/taskdata.py new file mode 100644 index 0000000000..181bb5e35b --- /dev/null +++ b/bitbake/lib/bb/taskdata.py @@ -0,0 +1,558 @@ +#!/usr/bin/env python +# ex:ts=4:sw=4:sts=4:et +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +""" +BitBake 'TaskData' implementation + +Task data collection and handling + +Copyright (C) 2006 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 +""" + +from bb import data, fetch, event, mkdirhier, utils +import bb, os + +class TaskData: + """ + BitBake Task Data implementation + """ + def __init__(self, abort = True): + self.build_names_index = [] + self.run_names_index = [] + self.fn_index = [] + + self.build_targets = {} + self.run_targets = {} + + self.external_targets = [] + + self.tasks_fnid = [] + self.tasks_name = [] + self.tasks_tdepends = [] + # Cache to speed up task ID lookups + self.tasks_lookup = {} + + self.depids = {} + self.rdepids = {} + + self.consider_msgs_cache = [] + + self.failed_deps = [] + self.failed_rdeps = [] + self.failed_fnids = [] + + self.abort = abort + + def getbuild_id(self, name): + """ + Return an ID number for the build target name. + If it doesn't exist, create one. + """ + if not name in self.build_names_index: + self.build_names_index.append(name) + return len(self.build_names_index) - 1 + + return self.build_names_index.index(name) + + def getrun_id(self, name): + """ + Return an ID number for the run target name. + If it doesn't exist, create one. + """ + if not name in self.run_names_index: + self.run_names_index.append(name) + return len(self.run_names_index) - 1 + + return self.run_names_index.index(name) + + def getfn_id(self, name): + """ + Return an ID number for the filename. + If it doesn't exist, create one. + """ + if not name in self.fn_index: + self.fn_index.append(name) + return len(self.fn_index) - 1 + + return self.fn_index.index(name) + + def gettask_id(self, fn, task): + """ + Return an ID number for the task matching fn and task. + If it doesn't exist, create one. + """ + fnid = self.getfn_id(fn) + + if fnid in self.tasks_lookup: + if task in self.tasks_lookup[fnid]: + return self.tasks_lookup[fnid][task] + + self.tasks_name.append(task) + self.tasks_fnid.append(fnid) + self.tasks_tdepends.append([]) + + listid = len(self.tasks_name) - 1 + + if fnid not in self.tasks_lookup: + self.tasks_lookup[fnid] = {} + self.tasks_lookup[fnid][task] = listid + + return listid + + def add_tasks(self, fn, dataCache): + """ + Add tasks for a given fn to the database + """ + + task_graph = dataCache.task_queues[fn] + task_deps = dataCache.task_deps[fn] + + fnid = self.getfn_id(fn) + + if fnid in self.failed_fnids: + bb.msg.fatal(bb.msg.domain.TaskData, "Trying to re-add a failed file? Something is broken...") + + # Check if we've already seen this fn + if fnid in self.tasks_fnid: + return + + # Work out task dependencies + for task in task_graph.allnodes(): + parentids = [] + for dep in task_graph.getparents(task): + parentid = self.gettask_id(fn, dep) + parentids.append(parentid) + taskid = self.gettask_id(fn, task) + self.tasks_tdepends[taskid].extend(parentids) + + # Work out build dependencies + if not fnid in self.depids: + dependids = {} + for depend in dataCache.deps[fn]: + bb.msg.debug(2, bb.msg.domain.TaskData, "Added dependency %s for %s" % (depend, fn)) + dependids[self.getbuild_id(depend)] = None + self.depids[fnid] = dependids.keys() + + # Work out runtime dependencies + if not fnid in self.rdepids: + rdependids = {} + rdepends = dataCache.rundeps[fn] + rrecs = dataCache.runrecs[fn] + for package in rdepends: + for rdepend in rdepends[package]: + bb.msg.debug(2, bb.msg.domain.TaskData, "Added runtime dependency %s for %s" % (rdepend, fn)) + rdependids[self.getrun_id(rdepend)] = None + for package in rrecs: + for rdepend in rrecs[package]: + bb.msg.debug(2, bb.msg.domain.TaskData, "Added runtime recommendation %s for %s" % (rdepend, fn)) + rdependids[self.getrun_id(rdepend)] = None + self.rdepids[fnid] = rdependids.keys() + + for dep in self.depids[fnid]: + if dep in self.failed_deps: + self.fail_fnid(fnid) + return + for dep in self.rdepids[fnid]: + if dep in self.failed_rdeps: + self.fail_fnid(fnid) + return + + def have_build_target(self, target): + """ + Have we a build target matching this name? + """ + targetid = self.getbuild_id(target) + + if targetid in self.build_targets: + return True + return False + + def have_runtime_target(self, target): + """ + Have we a runtime target matching this name? + """ + targetid = self.getrun_id(target) + + if targetid in self.run_targets: + return True + return False + + def add_build_target(self, fn, item): + """ + Add a build target. + If already present, append the provider fn to the list + """ + targetid = self.getbuild_id(item) + fnid = self.getfn_id(fn) + + if targetid in self.build_targets: + if fnid in self.build_targets[targetid]: + return + self.build_targets[targetid].append(fnid) + return + self.build_targets[targetid] = [fnid] + + def add_runtime_target(self, fn, item): + """ + Add a runtime target. + If already present, append the provider fn to the list + """ + targetid = self.getrun_id(item) + fnid = self.getfn_id(fn) + + if targetid in self.run_targets: + if fnid in self.run_targets[targetid]: + return + self.run_targets[targetid].append(fnid) + return + self.run_targets[targetid] = [fnid] + + def mark_external_target(self, item): + """ + Mark a build target as being externally requested + """ + targetid = self.getbuild_id(item) + + if targetid not in self.external_targets: + self.external_targets.append(targetid) + + def get_unresolved_build_targets(self, dataCache): + """ + Return a list of build targets who's providers + are unknown. + """ + unresolved = [] + for target in self.build_names_index: + if target in dataCache.ignored_dependencies: + continue + if self.build_names_index.index(target) in self.failed_deps: + continue + if not self.have_build_target(target): + unresolved.append(target) + return unresolved + + def get_unresolved_run_targets(self, dataCache): + """ + Return a list of runtime targets who's providers + are unknown. + """ + unresolved = [] + for target in self.run_names_index: + if target in dataCache.ignored_dependencies: + continue + if self.run_names_index.index(target) in self.failed_rdeps: + continue + if not self.have_runtime_target(target): + unresolved.append(target) + return unresolved + + def get_provider(self, item): + """ + Return a list of providers of item + """ + targetid = self.getbuild_id(item) + + return self.build_targets[targetid] + + def get_dependees(self, itemid): + """ + Return a list of targets which depend on item + """ + dependees = [] + for fnid in self.depids: + if itemid in self.depids[fnid]: + dependees.append(fnid) + return dependees + + def get_dependees_str(self, item): + """ + Return a list of targets which depend on item as a user readable string + """ + itemid = self.getbuild_id(item) + dependees = [] + for fnid in self.depids: + if itemid in self.depids[fnid]: + dependees.append(self.fn_index[fnid]) + return dependees + + def get_rdependees(self, itemid): + """ + Return a list of targets which depend on runtime item + """ + dependees = [] + for fnid in self.rdepids: + if itemid in self.rdepids[fnid]: + dependees.append(fnid) + return dependees + + def get_rdependees_str(self, item): + """ + Return a list of targets which depend on runtime item as a user readable string + """ + itemid = self.getrun_id(item) + dependees = [] + for fnid in self.rdepids: + if itemid in self.rdepids[fnid]: + dependees.append(self.fn_index[fnid]) + return dependees + + def add_provider(self, cfgData, dataCache, item): + try: + self.add_provider_internal(cfgData, dataCache, item) + except bb.providers.NoProvider: + if self.abort: + bb.msg.error(bb.msg.domain.Provider, "No providers of build target %s (for %s)" % (item, self.get_dependees_str(item))) + raise + targetid = self.getbuild_id(item) + self.remove_buildtarget(targetid) + + self.mark_external_target(item) + + def add_provider_internal(self, cfgData, dataCache, item): + """ + Add the providers of item to the task data + Mark entries were specifically added externally as against dependencies + added internally during dependency resolution + """ + + if item in dataCache.ignored_dependencies: + return + + if not item in dataCache.providers: + bb.msg.debug(1, bb.msg.domain.Provider, "No providers of build target %s (for %s)" % (item, self.get_dependees_str(item))) + bb.event.fire(bb.event.NoProvider(item, cfgData)) + raise bb.providers.NoProvider(item) + + if self.have_build_target(item): + return + + all_p = dataCache.providers[item] + + eligible = bb.providers.filterProviders(all_p, item, cfgData, dataCache) + + for p in eligible: + fnid = self.getfn_id(p) + if fnid in self.failed_fnids: + eligible.remove(p) + + if not eligible: + bb.msg.debug(1, bb.msg.domain.Provider, "No providers of build target %s after filtering (for %s)" % (item, self.get_dependees_str(item))) + bb.event.fire(bb.event.NoProvider(item, cfgData)) + raise bb.providers.NoProvider(item) + + prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, cfgData, 1) + if prefervar: + dataCache.preferred[item] = prefervar + + discriminated = False + if item in dataCache.preferred: + for p in eligible: + pn = dataCache.pkg_fn[p] + if dataCache.preferred[item] == pn: + bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item)) + eligible.remove(p) + eligible = [p] + eligible + discriminated = True + break + + if len(eligible) > 1 and discriminated == False: + if item not in self.consider_msgs_cache: + providers_list = [] + for fn in eligible: + providers_list.append(dataCache.pkg_fn[fn]) + bb.msg.note(1, bb.msg.domain.Provider, "multiple providers are available for %s (%s);" % (item, ", ".join(providers_list))) + bb.msg.note(1, bb.msg.domain.Provider, "consider defining PREFERRED_PROVIDER_%s" % item) + bb.event.fire(bb.event.MultipleProviders(item,providers_list,cfgData)) + self.consider_msgs_cache.append(item) + + for fn in eligible: + fnid = self.getfn_id(fn) + if fnid in self.failed_fnids: + continue + bb.msg.debug(2, bb.msg.domain.Provider, "adding %s to satisfy %s" % (fn, item)) + self.add_build_target(fn, item) + self.add_tasks(fn, dataCache) + + + #item = dataCache.pkg_fn[fn] + + def add_rprovider(self, cfgData, dataCache, item): + """ + Add the runtime providers of item to the task data + (takes item names from RDEPENDS/PACKAGES namespace) + """ + + if item in dataCache.ignored_dependencies: + return + + if self.have_runtime_target(item): + return + + all_p = bb.providers.getRuntimeProviders(dataCache, item) + + if not all_p: + bb.msg.error(bb.msg.domain.Provider, "No providers of runtime build target %s (for %s)" % (item, self.get_rdependees_str(item))) + bb.event.fire(bb.event.NoProvider(item, cfgData, runtime=True)) + raise bb.providers.NoRProvider(item) + + eligible = bb.providers.filterProviders(all_p, item, cfgData, dataCache) + + for p in eligible: + fnid = self.getfn_id(p) + if fnid in self.failed_fnids: + eligible.remove(p) + + if not eligible: + bb.msg.error(bb.msg.domain.Provider, "No providers of runtime build target %s after filtering (for %s)" % (item, self.get_rdependees_str(item))) + bb.event.fire(bb.event.NoProvider(item, cfgData, runtime=True)) + raise bb.providers.NoRProvider(item) + + # Should use dataCache.preferred here? + preferred = [] + for p in eligible: + pn = dataCache.pkg_fn[p] + provides = dataCache.pn_provides[pn] + for provide in provides: + prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, cfgData, 1) + if prefervar == pn: + bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy runtime %s due to PREFERRED_PROVIDERS" % (pn, item)) + eligible.remove(p) + eligible = [p] + eligible + preferred.append(p) + + if len(eligible) > 1 and len(preferred) == 0: + if item not in self.consider_msgs_cache: + providers_list = [] + for fn in eligible: + providers_list.append(dataCache.pkg_fn[fn]) + bb.msg.note(2, bb.msg.domain.Provider, "multiple providers are available for runtime %s (%s);" % (item, ", ".join(providers_list))) + bb.msg.note(2, bb.msg.domain.Provider, "consider defining a PREFERRED_PROVIDER entry to match runtime %s" % item) + bb.event.fire(bb.event.MultipleProviders(item,providers_list, cfgData, runtime=True)) + self.consider_msgs_cache.append(item) + + if len(preferred) > 1: + if item not in self.consider_msgs_cache: + providers_list = [] + for fn in preferred: + providers_list.append(dataCache.pkg_fn[fn]) + bb.msg.note(2, bb.msg.domain.Provider, "multiple preferred providers are available for runtime %s (%s);" % (item, ", ".join(providers_list))) + bb.msg.note(2, bb.msg.domain.Provider, "consider defining only one PREFERRED_PROVIDER entry to match runtime %s" % item) + bb.event.fire(bb.event.MultipleProviders(item,providers_list, cfgData, runtime=True)) + self.consider_msgs_cache.append(item) + + # run through the list until we find one that we can build + for fn in eligible: + fnid = self.getfn_id(fn) + if fnid in self.failed_fnids: + continue + bb.msg.debug(2, bb.msg.domain.Provider, "adding %s to satisfy runtime %s" % (fn, item)) + self.add_runtime_target(fn, item) + self.add_tasks(fn, dataCache) + + def fail_fnid(self, fnid): + """ + Mark a file as failed (unbuildable) + Remove any references from build and runtime provider lists + """ + if fnid in self.failed_fnids: + return + bb.msg.debug(1, bb.msg.domain.Provider, "Removing failed file %s" % self.fn_index[fnid]) + self.failed_fnids.append(fnid) + for target in self.build_targets: + if fnid in self.build_targets[target]: + self.build_targets[target].remove(fnid) + if len(self.build_targets[target]) == 0: + self.remove_buildtarget(target) + for target in self.run_targets: + if fnid in self.run_targets[target]: + self.run_targets[target].remove(fnid) + if len(self.run_targets[target]) == 0: + self.remove_runtarget(target) + + def remove_buildtarget(self, targetid): + """ + Mark a build target as failed (unbuildable) + Trigger removal of any files that have this as a dependency + """ + bb.msg.debug(1, bb.msg.domain.Provider, "Removing failed build target %s" % self.build_names_index[targetid]) + self.failed_deps.append(targetid) + dependees = self.get_dependees(targetid) + for fnid in dependees: + self.fail_fnid(fnid) + if self.abort and targetid in self.external_targets: + bb.msg.error(bb.msg.domain.Provider, "No buildable providers available for required build target %s" % self.build_names_index[targetid]) + raise bb.providers.NoProvider + + def remove_runtarget(self, targetid): + """ + Mark a run target as failed (unbuildable) + Trigger removal of any files that have this as a dependency + """ + bb.msg.note(1, bb.msg.domain.Provider, "Removing failed runtime build target %s" % self.run_names_index[targetid]) + self.failed_rdeps.append(targetid) + dependees = self.get_rdependees(targetid) + for fnid in dependees: + self.fail_fnid(fnid) + + def add_unresolved(self, cfgData, dataCache): + """ + Resolve all unresolved build and runtime targets + """ + bb.msg.note(1, bb.msg.domain.TaskData, "Resolving missing task queue dependencies") + while 1: + added = 0 + for target in self.get_unresolved_build_targets(dataCache): + try: + self.add_provider_internal(cfgData, dataCache, target) + added = added + 1 + except bb.providers.NoProvider: + targetid = self.getbuild_id(target) + if self.abort and targetid in self.external_targets: + raise + self.remove_buildtarget(targetid) + for target in self.get_unresolved_run_targets(dataCache): + try: + self.add_rprovider(cfgData, dataCache, target) + added = added + 1 + except bb.providers.NoRProvider: + self.remove_runtarget(self.getrun_id(target)) + bb.msg.debug(1, bb.msg.domain.TaskData, "Resolved " + str(added) + " extra dependecies") + if added == 0: + break + + def dump_data(self): + """ + Dump some debug information on the internal data structures + """ + bb.msg.debug(3, bb.msg.domain.TaskData, "build_names:") + bb.msg.debug(3, bb.msg.domain.TaskData, ", ".join(self.build_names_index)) + bb.msg.debug(3, bb.msg.domain.TaskData, "run_names:") + bb.msg.debug(3, bb.msg.domain.TaskData, ", ".join(self.run_names_index)) + bb.msg.debug(3, bb.msg.domain.TaskData, "build_targets:") + for target in self.build_targets.keys(): + bb.msg.debug(3, bb.msg.domain.TaskData, " %s: %s" % (self.build_names_index[target], self.build_targets[target])) + bb.msg.debug(3, bb.msg.domain.TaskData, "run_targets:") + for target in self.run_targets.keys(): + bb.msg.debug(3, bb.msg.domain.TaskData, " %s: %s" % (self.run_names_index[target], self.run_targets[target])) + bb.msg.debug(3, bb.msg.domain.TaskData, "tasks:") + for task in range(len(self.tasks_name)): + bb.msg.debug(3, bb.msg.domain.TaskData, " (%s)%s - %s: %s" % ( + task, + self.fn_index[self.tasks_fnid[task]], + self.tasks_name[task], + self.tasks_tdepends[task])) + bb.msg.debug(3, bb.msg.domain.TaskData, "runtime ids (per fn):") + for fnid in self.rdepids: + bb.msg.debug(3, bb.msg.domain.TaskData, " %s %s: %s" % (fnid, self.fn_index[fnid], self.rdepids[fnid])) + + diff --git a/bitbake/lib/bb/utils.py b/bitbake/lib/bb/utils.py index 5b3cb38d81..d7383f44b2 100644 --- a/bitbake/lib/bb/utils.py +++ b/bitbake/lib/bb/utils.py @@ -103,11 +103,11 @@ def _print_trace(body, line): import bb # print the environment of the method - bb.error("Printing the environment of the function") + bb.msg.error(bb.msg.domain.Util, "Printing the environment of the function") min_line = max(1,line-4) max_line = min(line+4,len(body)-1) for i in range(min_line,max_line+1): - bb.error("\t%.4d:%s" % (i, body[i-1]) ) + bb.msg.error(bb.msg.domain.Util, "\t%.4d:%s" % (i, body[i-1]) ) def better_compile(text, file, realfile): @@ -122,9 +122,9 @@ def better_compile(text, file, realfile): # split the text into lines again body = text.split('\n') - bb.error("Error in compiling: ", realfile) - bb.error("The lines resulting into this error were:") - bb.error("\t%d:%s:'%s'" % (e.lineno, e.__class__.__name__, body[e.lineno-1])) + bb.msg.error(bb.msg.domain.Util, "Error in compiling: ", realfile) + bb.msg.error(bb.msg.domain.Util, "The lines resulting into this error were:") + bb.msg.error(bb.msg.domain.Util, "\t%d:%s:'%s'" % (e.lineno, e.__class__.__name__, body[e.lineno-1])) _print_trace(body, e.lineno) @@ -147,8 +147,8 @@ def better_exec(code, context, text, realfile): raise # print the Header of the Error Message - bb.error("Error in executing: ", realfile) - bb.error("Exception:%s Message:%s" % (t,value) ) + bb.msg.error(bb.msg.domain.Util, "Error in executing: ", realfile) + bb.msg.error(bb.msg.domain.Util, "Exception:%s Message:%s" % (t,value) ) # let us find the line number now while tb.tb_next: @@ -160,3 +160,43 @@ def better_exec(code, context, text, realfile): _print_trace( text.split('\n'), line ) raise + +def Enum(*names): + """ + A simple class to give Enum support + """ + + assert names, "Empty enums are not supported" + + class EnumClass(object): + __slots__ = names + def __iter__(self): return iter(constants) + def __len__(self): return len(constants) + def __getitem__(self, i): return constants[i] + def __repr__(self): return 'Enum' + str(names) + def __str__(self): return 'enum ' + str(constants) + + class EnumValue(object): + __slots__ = ('__value') + def __init__(self, value): self.__value = value + Value = property(lambda self: self.__value) + EnumType = property(lambda self: EnumType) + def __hash__(self): return hash(self.__value) + def __cmp__(self, other): + # C fans might want to remove the following assertion + # to make all enums comparable by ordinal value {;)) + assert self.EnumType is other.EnumType, "Only values from the same enum are comparable" + return cmp(self.__value, other.__value) + def __invert__(self): return constants[maximum - self.__value] + def __nonzero__(self): return bool(self.__value) + def __repr__(self): return str(names[self.__value]) + + maximum = len(names) - 1 + constants = [None] * len(names) + for i, each in enumerate(names): + val = EnumValue(i) + setattr(EnumClass, each, val) + constants[i] = val + constants = tuple(constants) + EnumType = EnumClass() + return EnumType |