diff options
Diffstat (limited to 'bitbake-dev/lib/bb')
50 files changed, 0 insertions, 15020 deletions
diff --git a/bitbake-dev/lib/bb/COW.py b/bitbake-dev/lib/bb/COW.py deleted file mode 100644 index ca206cf4b4..0000000000 --- a/bitbake-dev/lib/bb/COW.py +++ /dev/null @@ -1,318 +0,0 @@ -# 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. -# -# Copyright (C) 2006 Tim Amsell -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -#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. -# - -import copy -import types -types.ImmutableTypes = tuple([ \ - types.BooleanType, \ - types.ComplexType, \ - types.FloatType, \ - types.IntType, \ - types.LongType, \ - types.NoneType, \ - types.TupleType, \ - frozenset] + \ - 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-dev/lib/bb/__init__.py b/bitbake-dev/lib/bb/__init__.py deleted file mode 100644 index f2f8f656d8..0000000000 --- a/bitbake-dev/lib/bb/__init__.py +++ /dev/null @@ -1,1134 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -# -# BitBake Build System Python Library -# -# Copyright (C) 2003 Holger Schurig -# Copyright (C) 2003, 2004 Chris Larson -# -# Based on Gentoo's portage.py. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -__version__ = "1.9.0" - -__all__ = [ - - "debug", - "note", - "error", - "fatal", - - "mkdirhier", - "movefile", - - "tokenize", - "evaluate", - "flatten", - "relparse", - "ververify", - "isjustname", - "isspecific", - "pkgsplit", - "catpkgsplit", - "vercmp", - "pkgcmp", - "dep_parenreduce", - "dep_opconvert", - -# fetch - "decodeurl", - "encodeurl", - -# modules - "parse", - "data", - "command", - "event", - "build", - "fetch", - "manifest", - "methodpool", - "cache", - "runqueue", - "taskdata", - "providers", - ] - -whitespace = '\t\n\x0b\x0c\r ' -lowercase = 'abcdefghijklmnopqrstuvwxyz' - -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() - -if "BBDEBUG" in os.environ: - level = int(os.environ["BBDEBUG"]) - if level: - bb.msg.set_debug_level(level) - -class VarExpandError(Exception): - pass - -class MalformedUrl(Exception): - """Exception raised when encountering an invalid url""" - - -####################################################################### -####################################################################### -# -# SECTION: Debug -# -# PURPOSE: little functions to make yourself known -# -####################################################################### -####################################################################### - -def plain(*args): - bb.msg.warn(''.join(args)) - -def debug(lvl, *args): - bb.msg.debug(lvl, None, ''.join(args)) - -def note(*args): - bb.msg.note(1, None, ''.join(args)) - -def warn(*args): - bb.msg.warn(1, None, ''.join(args)) - -def error(*args): - bb.msg.error(None, ''.join(args)) - -def fatal(*args): - bb.msg.fatal(None, ''.join(args)) - - -####################################################################### -####################################################################### -# -# SECTION: File -# -# PURPOSE: Basic file and directory tree related functions -# -####################################################################### -####################################################################### - -def mkdirhier(dir): - """Create a directory like 'mkdir -p', but does not complain if - directory already exists like os.makedirs - """ - - debug(3, "mkdirhier(%s)" % dir) - try: - os.makedirs(dir) - debug(2, "created " + dir) - except OSError, e: - if e.errno != 17: raise e - - -####################################################################### - -import stat - -def movefile(src,dest,newmtime=None,sstat=None): - """Moves a file from src to dest, preserving all permissions and - attributes; mtime will be preserved even when moving across - filesystems. Returns true on success and false on failure. Move is - atomic. - """ - - #print "movefile("+src+","+dest+","+str(newmtime)+","+str(sstat)+")" - try: - if not sstat: - sstat=os.lstat(src) - except Exception, e: - print "movefile: Stating source file failed...", e - return None - - destexists=1 - try: - dstat=os.lstat(dest) - except: - dstat=os.lstat(os.path.dirname(dest)) - destexists=0 - - if destexists: - if stat.S_ISLNK(dstat[stat.ST_MODE]): - try: - os.unlink(dest) - destexists=0 - except Exception, e: - pass - - if stat.S_ISLNK(sstat[stat.ST_MODE]): - try: - target=os.readlink(src) - if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]): - os.unlink(dest) - os.symlink(target,dest) - #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) - os.unlink(src) - return os.lstat(dest) - except Exception, e: - print "movefile: failed to properly create symlink:", dest, "->", target, e - return None - - renamefailed=1 - if sstat[stat.ST_DEV]==dstat[stat.ST_DEV]: - try: - ret=os.rename(src,dest) - renamefailed=0 - except Exception, e: - import errno - if e[0]!=errno.EXDEV: - # Some random error. - print "movefile: Failed to move", src, "to", dest, e - return None - # Invalid cross-device-link 'bind' mounted or actually Cross-Device - - if renamefailed: - didcopy=0 - if stat.S_ISREG(sstat[stat.ST_MODE]): - try: # For safety copy then move it over. - shutil.copyfile(src,dest+"#new") - os.rename(dest+"#new",dest) - didcopy=1 - except Exception, e: - print 'movefile: copy', src, '->', dest, 'failed.', e - return None - else: - #we don't yet handle special, so we need to fall back to /bin/mv - a=getstatusoutput("/bin/mv -f "+"'"+src+"' '"+dest+"'") - if a[0]!=0: - print "movefile: Failed to move special file:" + src + "' to '" + dest + "'", a - return None # failure - try: - if didcopy: - missingos.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) - os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown - os.unlink(src) - except Exception, e: - print "movefile: Failed to chown/chmod/unlink", dest, e - return None - - if newmtime: - os.utime(dest,(newmtime,newmtime)) - else: - os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME])) - newmtime=sstat[stat.ST_MTIME] - return newmtime - -def copyfile(src,dest,newmtime=None,sstat=None): - """ - Copies a file from src to dest, preserving all permissions and - attributes; mtime will be preserved even when moving across - filesystems. Returns true on success and false on failure. - """ - import os, stat, shutil - - #print "copyfile("+src+","+dest+","+str(newmtime)+","+str(sstat)+")" - try: - if not sstat: - sstat=os.lstat(src) - except Exception, e: - print "copyfile: Stating source file failed...", e - return False - - destexists=1 - try: - dstat=os.lstat(dest) - except: - dstat=os.lstat(os.path.dirname(dest)) - destexists=0 - - if destexists: - if stat.S_ISLNK(dstat[stat.ST_MODE]): - try: - os.unlink(dest) - destexists=0 - except Exception, e: - pass - - if stat.S_ISLNK(sstat[stat.ST_MODE]): - try: - target=os.readlink(src) - if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]): - os.unlink(dest) - os.symlink(target,dest) - #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) - return os.lstat(dest) - except Exception, e: - print "copyfile: failed to properly create symlink:", dest, "->", target, e - return False - - if stat.S_ISREG(sstat[stat.ST_MODE]): - try: # For safety copy then move it over. - shutil.copyfile(src,dest+"#new") - os.rename(dest+"#new",dest) - except Exception, e: - print 'copyfile: copy', src, '->', dest, 'failed.', e - return False - else: - #we don't yet handle special, so we need to fall back to /bin/mv - a=getstatusoutput("/bin/cp -f "+"'"+src+"' '"+dest+"'") - if a[0]!=0: - print "copyfile: Failed to copy special file:" + src + "' to '" + dest + "'", a - return False # failure - try: - os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) - os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown - except Exception, e: - print "copyfile: Failed to chown/chmod/unlink", dest, e - return False - - if newmtime: - os.utime(dest,(newmtime,newmtime)) - else: - os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME])) - newmtime=sstat[stat.ST_MTIME] - return newmtime - -####################################################################### -####################################################################### -# -# SECTION: Download -# -# PURPOSE: Download via HTTP, FTP, CVS, BITKEEPER, handling of MD5-signatures -# and mirrors -# -####################################################################### -####################################################################### - -def decodeurl(url): - """Decodes an URL into the tokens (scheme, network location, path, - user, password, parameters). - - >>> decodeurl("http://www.google.com/index.html") - ('http', 'www.google.com', '/index.html', '', '', {}) - - CVS url with username, host and cvsroot. The cvs module to check out is in the - parameters: - - >>> decodeurl("cvs://anoncvs@cvs.handhelds.org/cvs;module=familiar/dist/ipkg") - ('cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', '', {'module': 'familiar/dist/ipkg'}) - - Dito, but this time the username has a password part. And we also request a special tag - to check out. - - >>> decodeurl("cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;module=familiar/dist/ipkg;tag=V0-99-81") - ('cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', 'anonymous', {'tag': 'V0-99-81', 'module': 'familiar/dist/ipkg'}) - """ - - m = re.compile('(?P<type>[^:]*)://((?P<user>.+)@)?(?P<location>[^;]+)(;(?P<parm>.*))?').match(url) - if not m: - raise MalformedUrl(url) - - type = m.group('type') - location = m.group('location') - if not location: - raise MalformedUrl(url) - user = m.group('user') - parm = m.group('parm') - - locidx = location.find('/') - if locidx != -1: - host = location[:locidx] - path = location[locidx:] - else: - host = "" - path = location - if user: - m = re.compile('(?P<user>[^:]+)(:?(?P<pswd>.*))').match(user) - if m: - user = m.group('user') - pswd = m.group('pswd') - else: - user = '' - pswd = '' - - p = {} - if parm: - for s in parm.split(';'): - s1,s2 = s.split('=') - p[s1] = s2 - - return (type, host, path, user, pswd, p) - -####################################################################### - -def encodeurl(decoded): - """Encodes a URL from tokens (scheme, network location, path, - user, password, parameters). - - >>> encodeurl(['http', 'www.google.com', '/index.html', '', '', {}]) - 'http://www.google.com/index.html' - - CVS with username, host and cvsroot. The cvs module to check out is in the - parameters: - - >>> encodeurl(['cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', '', {'module': 'familiar/dist/ipkg'}]) - 'cvs://anoncvs@cvs.handhelds.org/cvs;module=familiar/dist/ipkg' - - Dito, but this time the username has a password part. And we also request a special tag - to check out. - - >>> encodeurl(['cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', 'anonymous', {'tag': 'V0-99-81', 'module': 'familiar/dist/ipkg'}]) - 'cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;tag=V0-99-81;module=familiar/dist/ipkg' - """ - - (type, host, path, user, pswd, p) = decoded - - if not type or not path: - fatal("invalid or missing parameters for url encoding") - url = '%s://' % type - if user: - url += "%s" % user - if pswd: - url += ":%s" % pswd - url += "@" - if host: - url += "%s" % host - url += "%s" % path - if p: - for parm in p.keys(): - url += ";%s=%s" % (parm, p[parm]) - - return url - -####################################################################### - -def which(path, item, direction = 0): - """ - Locate a file in a PATH - """ - - paths = (path or "").split(':') - if direction != 0: - paths.reverse() - - for p in (path or "").split(':'): - next = os.path.join(p, item) - if os.path.exists(next): - return next - - return "" - -####################################################################### - - - - -####################################################################### -####################################################################### -# -# SECTION: Dependency -# -# PURPOSE: Compare build & run dependencies -# -####################################################################### -####################################################################### - -def tokenize(mystring): - """Breaks a string like 'foo? (bar) oni? (blah (blah))' into (possibly embedded) lists: - - >>> tokenize("x") - ['x'] - >>> tokenize("x y") - ['x', 'y'] - >>> tokenize("(x y)") - [['x', 'y']] - >>> tokenize("(x y) b c") - [['x', 'y'], 'b', 'c'] - >>> tokenize("foo? (bar) oni? (blah (blah))") - ['foo?', ['bar'], 'oni?', ['blah', ['blah']]] - >>> tokenize("sys-apps/linux-headers nls? (sys-devel/gettext)") - ['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']] - """ - - newtokens = [] - curlist = newtokens - prevlists = [] - level = 0 - accum = "" - for x in mystring: - if x=="(": - if accum: - curlist.append(accum) - accum="" - prevlists.append(curlist) - curlist=[] - level=level+1 - elif x==")": - if accum: - curlist.append(accum) - accum="" - if level==0: - print "!!! tokenizer: Unmatched left parenthesis in:\n'"+mystring+"'" - return None - newlist=curlist - curlist=prevlists.pop() - curlist.append(newlist) - level=level-1 - elif x in whitespace: - if accum: - curlist.append(accum) - accum="" - else: - accum=accum+x - if accum: - curlist.append(accum) - if (level!=0): - print "!!! tokenizer: Exiting with unterminated parenthesis in:\n'"+mystring+"'" - return None - return newtokens - - -####################################################################### - -def evaluate(tokens,mydefines,allon=0): - """Removes tokens based on whether conditional definitions exist or not. - Recognizes ! - - >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {}) - ['sys-apps/linux-headers'] - - Negate the flag: - - >>> evaluate(['sys-apps/linux-headers', '!nls?', ['sys-devel/gettext']], {}) - ['sys-apps/linux-headers', ['sys-devel/gettext']] - - Define 'nls': - - >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {"nls":1}) - ['sys-apps/linux-headers', ['sys-devel/gettext']] - - Turn allon on: - - >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {}, True) - ['sys-apps/linux-headers', ['sys-devel/gettext']] - """ - - if tokens == None: - return None - mytokens = tokens + [] # this copies the list - pos = 0 - while pos < len(mytokens): - if type(mytokens[pos]) == types.ListType: - evaluate(mytokens[pos], mydefines) - if not len(mytokens[pos]): - del mytokens[pos] - continue - elif mytokens[pos][-1] == "?": - cur = mytokens[pos][:-1] - del mytokens[pos] - if allon: - if cur[0] == "!": - del mytokens[pos] - else: - if cur[0] == "!": - if (cur[1:] in mydefines) and (pos < len(mytokens)): - del mytokens[pos] - continue - elif (cur not in mydefines) and (pos < len(mytokens)): - del mytokens[pos] - continue - pos = pos + 1 - return mytokens - - -####################################################################### - -def flatten(mytokens): - """Converts nested arrays into a flat arrays: - - >>> flatten([1,[2,3]]) - [1, 2, 3] - >>> flatten(['sys-apps/linux-headers', ['sys-devel/gettext']]) - ['sys-apps/linux-headers', 'sys-devel/gettext'] - """ - - newlist=[] - for x in mytokens: - if type(x)==types.ListType: - newlist.extend(flatten(x)) - else: - newlist.append(x) - return newlist - - -####################################################################### - -_package_weights_ = {"pre":-2,"p":0,"alpha":-4,"beta":-3,"rc":-1} # dicts are unordered -_package_ends_ = ["pre", "p", "alpha", "beta", "rc", "cvs", "bk", "HEAD" ] # so we need ordered list - -def relparse(myver): - """Parses the last elements of a version number into a triplet, that can - later be compared: - - >>> relparse('1.2_pre3') - [1.2, -2, 3.0] - >>> relparse('1.2b') - [1.2, 98, 0] - >>> relparse('1.2') - [1.2, 0, 0] - """ - - number = 0 - p1 = 0 - p2 = 0 - mynewver = myver.split('_') - if len(mynewver)==2: - # an _package_weights_ - number = float(mynewver[0]) - match = 0 - for x in _package_ends_: - elen = len(x) - if mynewver[1][:elen] == x: - match = 1 - p1 = _package_weights_[x] - try: - p2 = float(mynewver[1][elen:]) - except: - p2 = 0 - break - if not match: - # normal number or number with letter at end - divider = len(myver)-1 - if myver[divider:] not in "1234567890": - # letter at end - p1 = ord(myver[divider:]) - number = float(myver[0:divider]) - else: - number = float(myver) - else: - # normal number or number with letter at end - divider = len(myver)-1 - if myver[divider:] not in "1234567890": - #letter at end - p1 = ord(myver[divider:]) - number = float(myver[0:divider]) - else: - number = float(myver) - return [number,p1,p2] - - -####################################################################### - -__ververify_cache__ = {} - -def ververify(myorigval,silent=1): - """Returns 1 if given a valid version string, els 0. Valid versions are in the format - - <v1>.<v2>...<vx>[a-z,_{_package_weights_}[vy]] - - >>> ververify('2.4.20') - 1 - >>> ververify('2.4..20') # two dots - 0 - >>> ververify('2.x.20') # 'x' is not numeric - 0 - >>> ververify('2.4.20a') - 1 - >>> ververify('2.4.20cvs') # only one trailing letter - 0 - >>> ververify('1a') - 1 - >>> ververify('test_a') # no version at all - 0 - >>> ververify('2.4.20_beta1') - 1 - >>> ververify('2.4.20_beta') - 1 - >>> ververify('2.4.20_wrongext') # _wrongext is no valid trailer - 0 - """ - - # Lookup the cache first - try: - return __ververify_cache__[myorigval] - except KeyError: - pass - - if len(myorigval) == 0: - if not silent: - error("package version is empty") - __ververify_cache__[myorigval] = 0 - return 0 - myval = myorigval.split('.') - if len(myval)==0: - if not silent: - error("package name has empty version string") - __ververify_cache__[myorigval] = 0 - return 0 - # all but the last version must be a numeric - for x in myval[:-1]: - if not len(x): - if not silent: - error("package version has two points in a row") - __ververify_cache__[myorigval] = 0 - return 0 - try: - foo = int(x) - except: - if not silent: - error("package version contains non-numeric '"+x+"'") - __ververify_cache__[myorigval] = 0 - return 0 - if not len(myval[-1]): - if not silent: - error("package version has trailing dot") - __ververify_cache__[myorigval] = 0 - return 0 - try: - foo = int(myval[-1]) - __ververify_cache__[myorigval] = 1 - return 1 - except: - pass - - # ok, our last component is not a plain number or blank, let's continue - if myval[-1][-1] in lowercase: - try: - foo = int(myval[-1][:-1]) - return 1 - __ververify_cache__[myorigval] = 1 - # 1a, 2.0b, etc. - except: - pass - # ok, maybe we have a 1_alpha or 1_beta2; let's see - ep=string.split(myval[-1],"_") - if len(ep)!= 2: - if not silent: - error("package version has more than one letter at then end") - __ververify_cache__[myorigval] = 0 - return 0 - try: - foo = string.atoi(ep[0]) - except: - # this needs to be numeric, i.e. the "1" in "1_alpha" - if not silent: - error("package version must have numeric part before the '_'") - __ververify_cache__[myorigval] = 0 - return 0 - - for mye in _package_ends_: - if ep[1][0:len(mye)] == mye: - if len(mye) == len(ep[1]): - # no trailing numeric is ok - __ververify_cache__[myorigval] = 1 - return 1 - else: - try: - foo = string.atoi(ep[1][len(mye):]) - __ververify_cache__[myorigval] = 1 - return 1 - except: - # if no _package_weights_ work, *then* we return 0 - pass - if not silent: - error("package version extension after '_' is invalid") - __ververify_cache__[myorigval] = 0 - return 0 - - -def isjustname(mypkg): - myparts = string.split(mypkg,'-') - for x in myparts: - if ververify(x): - return 0 - return 1 - - -_isspecific_cache_={} - -def isspecific(mypkg): - "now supports packages with no category" - try: - return __isspecific_cache__[mypkg] - except: - pass - - mysplit = string.split(mypkg,"/") - if not isjustname(mysplit[-1]): - __isspecific_cache__[mypkg] = 1 - return 1 - __isspecific_cache__[mypkg] = 0 - return 0 - - -####################################################################### - -__pkgsplit_cache__={} - -def pkgsplit(mypkg, silent=1): - - """This function can be used as a package verification function. If - it is a valid name, pkgsplit will return a list containing: - [pkgname, pkgversion(norev), pkgrev ]. - - >>> pkgsplit('') - >>> pkgsplit('x') - >>> pkgsplit('x-') - >>> pkgsplit('-1') - >>> pkgsplit('glibc-1.2-8.9-r7') - >>> pkgsplit('glibc-2.2.5-r7') - ['glibc', '2.2.5', 'r7'] - >>> pkgsplit('foo-1.2-1') - >>> pkgsplit('Mesa-3.0') - ['Mesa', '3.0', 'r0'] - """ - - try: - return __pkgsplit_cache__[mypkg] - except KeyError: - pass - - myparts = string.split(mypkg,'-') - if len(myparts) < 2: - if not silent: - error("package name without name or version part") - __pkgsplit_cache__[mypkg] = None - return None - for x in myparts: - if len(x) == 0: - if not silent: - error("package name with empty name or version part") - __pkgsplit_cache__[mypkg] = None - return None - # verify rev - revok = 0 - myrev = myparts[-1] - ververify(myrev, silent) - if len(myrev) and myrev[0] == "r": - try: - string.atoi(myrev[1:]) - revok = 1 - except: - pass - if revok: - if ververify(myparts[-2]): - if len(myparts) == 2: - __pkgsplit_cache__[mypkg] = None - return None - else: - for x in myparts[:-2]: - if ververify(x): - __pkgsplit_cache__[mypkg]=None - return None - # names can't have versiony looking parts - myval=[string.join(myparts[:-2],"-"),myparts[-2],myparts[-1]] - __pkgsplit_cache__[mypkg]=myval - return myval - else: - __pkgsplit_cache__[mypkg] = None - return None - - elif ververify(myparts[-1],silent): - if len(myparts)==1: - if not silent: - print "!!! Name error in",mypkg+": missing name part." - __pkgsplit_cache__[mypkg]=None - return None - else: - for x in myparts[:-1]: - if ververify(x): - if not silent: error("package name has multiple version parts") - __pkgsplit_cache__[mypkg] = None - return None - myval = [string.join(myparts[:-1],"-"), myparts[-1],"r0"] - __pkgsplit_cache__[mypkg] = myval - return myval - else: - __pkgsplit_cache__[mypkg] = None - return None - - -####################################################################### - -__catpkgsplit_cache__ = {} - -def catpkgsplit(mydata,silent=1): - """returns [cat, pkgname, version, rev ] - - >>> catpkgsplit('sys-libs/glibc-1.2-r7') - ['sys-libs', 'glibc', '1.2', 'r7'] - >>> catpkgsplit('glibc-1.2-r7') - [None, 'glibc', '1.2', 'r7'] - """ - - try: - return __catpkgsplit_cache__[mydata] - except KeyError: - pass - - cat = os.path.basename(os.path.dirname(mydata)) - mydata = os.path.join(cat, os.path.basename(mydata)) - if mydata[-3:] == '.bb': - mydata = mydata[:-3] - - mysplit = mydata.split("/") - p_split = None - splitlen = len(mysplit) - if splitlen == 1: - retval = [None] - p_split = pkgsplit(mydata,silent) - else: - retval = [mysplit[splitlen - 2]] - p_split = pkgsplit(mysplit[splitlen - 1],silent) - if not p_split: - __catpkgsplit_cache__[mydata] = None - return None - retval.extend(p_split) - __catpkgsplit_cache__[mydata] = retval - return retval - - -####################################################################### - -__vercmp_cache__ = {} - -def vercmp(val1,val2): - """This takes two version strings and returns an integer to tell you whether - the versions are the same, val1>val2 or val2>val1. - - >>> vercmp('1', '2') - -1.0 - >>> vercmp('2', '1') - 1.0 - >>> vercmp('1', '1.0') - 0 - >>> vercmp('1', '1.1') - -1.0 - >>> vercmp('1.1', '1_p2') - 1.0 - """ - - # quick short-circuit - if val1 == val2: - return 0 - valkey = val1+" "+val2 - - # cache lookup - try: - return __vercmp_cache__[valkey] - try: - return - __vercmp_cache__[val2+" "+val1] - except KeyError: - pass - except KeyError: - pass - - # consider 1_p2 vc 1.1 - # after expansion will become (1_p2,0) vc (1,1) - # then 1_p2 is compared with 1 before 0 is compared with 1 - # to solve the bug we need to convert it to (1,0_p2) - # by splitting _prepart part and adding it back _after_expansion - - val1_prepart = val2_prepart = '' - if val1.count('_'): - val1, val1_prepart = val1.split('_', 1) - if val2.count('_'): - val2, val2_prepart = val2.split('_', 1) - - # replace '-' by '.' - # FIXME: Is it needed? can val1/2 contain '-'? - - val1 = string.split(val1,'-') - if len(val1) == 2: - val1[0] = val1[0] +"."+ val1[1] - val2 = string.split(val2,'-') - if len(val2) == 2: - val2[0] = val2[0] +"."+ val2[1] - - val1 = string.split(val1[0],'.') - val2 = string.split(val2[0],'.') - - # add back decimal point so that .03 does not become "3" ! - for x in range(1,len(val1)): - if val1[x][0] == '0' : - val1[x] = '.' + val1[x] - for x in range(1,len(val2)): - if val2[x][0] == '0' : - val2[x] = '.' + val2[x] - - # extend varion numbers - if len(val2) < len(val1): - val2.extend(["0"]*(len(val1)-len(val2))) - elif len(val1) < len(val2): - val1.extend(["0"]*(len(val2)-len(val1))) - - # add back _prepart tails - if val1_prepart: - val1[-1] += '_' + val1_prepart - if val2_prepart: - val2[-1] += '_' + val2_prepart - # The above code will extend version numbers out so they - # have the same number of digits. - for x in range(0,len(val1)): - cmp1 = relparse(val1[x]) - cmp2 = relparse(val2[x]) - for y in range(0,3): - myret = cmp1[y] - cmp2[y] - if myret != 0: - __vercmp_cache__[valkey] = myret - return myret - __vercmp_cache__[valkey] = 0 - return 0 - - -####################################################################### - -def pkgcmp(pkg1,pkg2): - """ Compares two packages, which should have been split via - pkgsplit(). if the return value val is less than zero, then pkg2 is - newer than pkg1, zero if equal and positive if older. - - >>> pkgcmp(['glibc', '2.2.5', 'r7'], ['glibc', '2.2.5', 'r7']) - 0 - >>> pkgcmp(['glibc', '2.2.5', 'r4'], ['glibc', '2.2.5', 'r7']) - -1 - >>> pkgcmp(['glibc', '2.2.5', 'r7'], ['glibc', '2.2.5', 'r2']) - 1 - """ - - mycmp = vercmp(pkg1[1],pkg2[1]) - if mycmp > 0: - return 1 - if mycmp < 0: - return -1 - r1=string.atoi(pkg1[2][1:]) - r2=string.atoi(pkg2[2][1:]) - if r1 > r2: - return 1 - if r2 > r1: - return -1 - return 0 - - -####################################################################### - -def dep_parenreduce(mysplit, mypos=0): - """Accepts a list of strings, and converts '(' and ')' surrounded items to sub-lists: - - >>> dep_parenreduce(['']) - [''] - >>> dep_parenreduce(['1', '2', '3']) - ['1', '2', '3'] - >>> dep_parenreduce(['1', '(', '2', '3', ')', '4']) - ['1', ['2', '3'], '4'] - """ - - while mypos < len(mysplit): - if mysplit[mypos] == "(": - firstpos = mypos - mypos = mypos + 1 - while mypos < len(mysplit): - if mysplit[mypos] == ")": - mysplit[firstpos:mypos+1] = [mysplit[firstpos+1:mypos]] - mypos = firstpos - break - elif mysplit[mypos] == "(": - # recurse - mysplit = dep_parenreduce(mysplit,mypos) - mypos = mypos + 1 - mypos = mypos + 1 - return mysplit - - -def dep_opconvert(mysplit, myuse): - "Does dependency operator conversion" - - mypos = 0 - newsplit = [] - while mypos < len(mysplit): - if type(mysplit[mypos]) == types.ListType: - newsplit.append(dep_opconvert(mysplit[mypos],myuse)) - mypos += 1 - elif mysplit[mypos] == ")": - # mismatched paren, error - return None - elif mysplit[mypos]=="||": - if ((mypos+1)>=len(mysplit)) or (type(mysplit[mypos+1])!=types.ListType): - # || must be followed by paren'd list - return None - try: - mynew = dep_opconvert(mysplit[mypos+1],myuse) - except Exception, e: - error("unable to satisfy OR dependancy: " + string.join(mysplit," || ")) - raise e - mynew[0:0] = ["||"] - newsplit.append(mynew) - mypos += 2 - elif mysplit[mypos][-1] == "?": - # use clause, i.e "gnome? ( foo bar )" - # this is a quick and dirty hack so that repoman can enable all USE vars: - if (len(myuse) == 1) and (myuse[0] == "*"): - # enable it even if it's ! (for repoman) but kill it if it's - # an arch variable that isn't for this arch. XXX Sparc64? - if (mysplit[mypos][:-1] not in settings.usemask) or \ - (mysplit[mypos][:-1]==settings["ARCH"]): - enabled=1 - else: - enabled=0 - else: - if mysplit[mypos][0] == "!": - myusevar = mysplit[mypos][1:-1] - enabled = not myusevar in myuse - #if myusevar in myuse: - # enabled = 0 - #else: - # enabled = 1 - else: - myusevar=mysplit[mypos][:-1] - enabled = myusevar in myuse - #if myusevar in myuse: - # enabled=1 - #else: - # enabled=0 - if (mypos +2 < len(mysplit)) and (mysplit[mypos+2] == ":"): - # colon mode - if enabled: - # choose the first option - if type(mysplit[mypos+1]) == types.ListType: - newsplit.append(dep_opconvert(mysplit[mypos+1],myuse)) - else: - newsplit.append(mysplit[mypos+1]) - else: - # choose the alternate option - if type(mysplit[mypos+1]) == types.ListType: - newsplit.append(dep_opconvert(mysplit[mypos+3],myuse)) - else: - newsplit.append(mysplit[mypos+3]) - mypos += 4 - else: - # normal use mode - if enabled: - if type(mysplit[mypos+1]) == types.ListType: - newsplit.append(dep_opconvert(mysplit[mypos+1],myuse)) - else: - newsplit.append(mysplit[mypos+1]) - # otherwise, continue - mypos += 2 - else: - # normal item - newsplit.append(mysplit[mypos]) - mypos += 1 - return newsplit - -if __name__ == "__main__": - import doctest, bb - bb.msg.set_debug_level(0) - doctest.testmod(bb) diff --git a/bitbake-dev/lib/bb/build.py b/bitbake-dev/lib/bb/build.py deleted file mode 100644 index 6d80b4b549..0000000000 --- a/bitbake-dev/lib/bb/build.py +++ /dev/null @@ -1,394 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -# -# BitBake 'Build' implementation -# -# Core code for function execution and task handling in the -# BitBake build tools. -# -# Copyright (C) 2003, 2004 Chris Larson -# -# Based on Gentoo's portage.py. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -#Based on functions from the base bb module, Copyright 2003 Holger Schurig - -from bb import data, event, mkdirhier, utils -import bb, os, sys - -# When we execute a python function we'd like certain things -# in all namespaces, hence we add them to __builtins__ -# If we do not do this and use the exec globals, they will -# not be available to subfunctions. -__builtins__['bb'] = bb -__builtins__['os'] = os - -# events -class FuncFailed(Exception): - """ - Executed function failed - First parameter a message - Second paramter is a logfile (optional) - """ - -class EventException(Exception): - """Exception which is associated with an Event.""" - - def __init__(self, msg, event): - self.args = msg, event - -class TaskBase(event.Event): - """Base class for task events""" - - def __init__(self, t, d ): - self._task = t - self._package = bb.data.getVar("PF", d, 1) - event.Event.__init__(self) - self._message = "package %s: task %s: %s" % (bb.data.getVar("PF", d, 1), t, bb.event.getName(self)[4:]) - - def getTask(self): - return self._task - - def setTask(self, task): - self._task = task - - task = property(getTask, setTask, None, "task property") - -class TaskStarted(TaskBase): - """Task execution started""" - -class TaskSucceeded(TaskBase): - """Task execution completed""" - -class TaskFailed(TaskBase): - """Task execution failed""" - def __init__(self, msg, logfile, t, d ): - self.logfile = logfile - self.msg = msg - TaskBase.__init__(self, t, d) - -class InvalidTask(TaskBase): - """Invalid Task""" - -# functions - -def exec_func(func, d, dirs = None): - """Execute an BB 'function'""" - - body = data.getVar(func, d) - if not body: - return - - flags = data.getVarFlags(func, d) - for item in ['deps', 'check', 'interactive', 'python', 'cleandirs', 'dirs', 'lockfiles', 'fakeroot']: - if not item in flags: - flags[item] = None - - ispython = flags['python'] - - cleandirs = (data.expand(flags['cleandirs'], d) or "").split() - for cdir in cleandirs: - os.system("rm -rf %s" % cdir) - - if dirs: - dirs = data.expand(dirs, d) - else: - dirs = (data.expand(flags['dirs'], d) or "").split() - for adir in dirs: - mkdirhier(adir) - - if len(dirs) > 0: - adir = dirs[-1] - else: - adir = data.getVar('B', d, 1) - - # Save current directory - try: - prevdir = os.getcwd() - except OSError: - prevdir = data.getVar('TOPDIR', d, True) - - # Setup logfiles - t = data.getVar('T', d, 1) - if not t: - bb.msg.fatal(bb.msg.domain.Build, "T not set") - mkdirhier(t) - # Gross hack, FIXME - import random - logfile = "%s/log.%s.%s.%s" % (t, func, str(os.getpid()),random.random()) - runfile = "%s/run.%s.%s" % (t, func, str(os.getpid())) - - # Change to correct directory (if specified) - if adir and os.access(adir, os.F_OK): - os.chdir(adir) - - # Handle logfiles - si = file('/dev/null', 'r') - try: - if bb.msg.debug_level['default'] > 0 or ispython: - so = os.popen("tee \"%s\"" % logfile, "w") - else: - so = file(logfile, 'w') - except OSError, e: - bb.msg.error(bb.msg.domain.Build, "opening log file: %s" % e) - pass - - se = so - - # Dup the existing fds so we dont lose them - osi = [os.dup(sys.stdin.fileno()), sys.stdin.fileno()] - oso = [os.dup(sys.stdout.fileno()), sys.stdout.fileno()] - ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()] - - # Replace those fds with our own - os.dup2(si.fileno(), osi[1]) - os.dup2(so.fileno(), oso[1]) - os.dup2(se.fileno(), ose[1]) - - locks = [] - lockfiles = (data.expand(flags['lockfiles'], d) or "").split() - for lock in lockfiles: - locks.append(bb.utils.lockfile(lock)) - - try: - # Run the function - if ispython: - exec_func_python(func, d, runfile, logfile) - else: - exec_func_shell(func, d, runfile, logfile, flags) - - # Restore original directory - try: - os.chdir(prevdir) - except: - pass - - finally: - - # Unlock any lockfiles - for lock in locks: - bb.utils.unlockfile(lock) - - # Restore the backup fds - os.dup2(osi[0], osi[1]) - os.dup2(oso[0], oso[1]) - os.dup2(ose[0], ose[1]) - - # Close our logs - si.close() - so.close() - se.close() - - if os.path.exists(logfile) and os.path.getsize(logfile) == 0: - bb.msg.debug(2, bb.msg.domain.Build, "Zero size logfile %s, removing" % logfile) - os.remove(logfile) - - # Close the backup fds - os.close(osi[0]) - os.close(oso[0]) - os.close(ose[0]) - -def exec_func_python(func, d, runfile, logfile): - """Execute a python BB 'function'""" - import re, os - - bbfile = bb.data.getVar('FILE', d, 1) - tmp = "def " + func + "():\n%s" % data.getVar(func, d) - tmp += '\n' + func + '()' - - f = open(runfile, "w") - f.write(tmp) - comp = utils.better_compile(tmp, func, bbfile) - g = {} # globals - g['d'] = d - try: - utils.better_exec(comp, g, tmp, bbfile) - except: - (t,value,tb) = sys.exc_info() - - if t in [bb.parse.SkipPackage, bb.build.FuncFailed]: - raise - bb.msg.error(bb.msg.domain.Build, "Function %s failed" % func) - raise FuncFailed("function %s failed" % func, logfile) - -def exec_func_shell(func, d, runfile, logfile, flags): - """Execute a shell BB 'function' Returns true if execution was successful. - - For this, it creates a bash shell script in the tmp dectory, writes the local - data into it and finally executes. The output of the shell will end in a log file and stdout. - - Note on directory behavior. The 'dirs' varflag should contain a list - of the directories you need created prior to execution. The last - item in the list is where we will chdir/cd to. - """ - - deps = flags['deps'] - check = flags['check'] - if check in globals(): - if globals()[check](func, deps): - return - - f = open(runfile, "w") - f.write("#!/bin/sh -e\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()) - if func: f.write("%s\n" % func) - f.close() - os.chmod(runfile, 0775) - if not func: - bb.msg.error(bb.msg.domain.Build, "Function not specified") - raise FuncFailed("Function not specified for exec_func_shell") - - # execute function - if flags['fakeroot']: - maybe_fakeroot = "PATH=\"%s\" fakeroot " % bb.data.getVar("PATH", d, 1) - else: - maybe_fakeroot = '' - lang_environment = "LC_ALL=C " - ret = os.system('%s%ssh -e %s' % (lang_environment, maybe_fakeroot, runfile)) - - if ret == 0: - return - - bb.msg.error(bb.msg.domain.Build, "Function %s failed" % func) - raise FuncFailed("function %s failed" % func, logfile) - - -def exec_task(task, d): - """Execute an BB 'task' - - The primary difference between executing a task versus executing - a function is that a task exists in the task digraph, and therefore - has dependencies amongst other tasks.""" - - # Check whther this is a valid task - if not data.getVarFlag(task, 'task', d): - raise EventException("No such task", InvalidTask(task, d)) - - try: - bb.msg.debug(1, bb.msg.domain.Build, "Executing task %s" % task) - old_overrides = data.getVar('OVERRIDES', d, 0) - localdata = data.createCopy(d) - data.setVar('OVERRIDES', 'task-%s:%s' % (task[3:], old_overrides), localdata) - data.update_data(localdata) - data.expandKeys(localdata) - event.fire(TaskStarted(task, localdata), localdata) - exec_func(task, localdata) - event.fire(TaskSucceeded(task, localdata), localdata) - except FuncFailed, message: - # Try to extract the optional logfile - try: - (msg, logfile) = message - except: - logfile = None - msg = message - bb.msg.note(1, bb.msg.domain.Build, "Task failed: %s" % message ) - failedevent = TaskFailed(msg, logfile, task, d) - event.fire(failedevent, d) - raise EventException("Function failed in task: %s" % message, failedevent) - - # make stamp, or cause event and raise exception - if not data.getVarFlag(task, 'nostamp', d) and not data.getVarFlag(task, 'selfstamp', d): - make_stamp(task, d) - -def extract_stamp(d, fn): - """ - Extracts stamp format which is either a data dictonary (fn unset) - or a dataCache entry (fn set). - """ - if fn: - return d.stamp[fn] - return data.getVar('STAMP', d, 1) - -def stamp_internal(task, d, file_name): - """ - Internal stamp helper function - Removes any stamp for the given task - Makes sure the stamp directory exists - Returns the stamp path+filename - """ - stamp = extract_stamp(d, file_name) - if not stamp: - return - stamp = "%s.%s" % (stamp, task) - mkdirhier(os.path.dirname(stamp)) - # Remove the file and recreate to force timestamp - # change on broken NFS filesystems - if os.access(stamp, os.F_OK): - os.remove(stamp) - return stamp - -def make_stamp(task, d, file_name = None): - """ - Creates/updates a stamp for a given task - (d can be a data dict or dataCache) - """ - stamp = stamp_internal(task, d, file_name) - if stamp: - f = open(stamp, "w") - f.close() - -def del_stamp(task, d, file_name = None): - """ - Removes a stamp for a given task - (d can be a data dict or dataCache) - """ - stamp_internal(task, d, file_name) - -def add_tasks(tasklist, d): - task_deps = data.getVar('_task_deps', d) - if not task_deps: - task_deps = {} - if not 'tasks' in task_deps: - task_deps['tasks'] = [] - if not 'parents' in task_deps: - task_deps['parents'] = {} - - for task in tasklist: - task = data.expand(task, d) - data.setVarFlag(task, 'task', 1, d) - - if not task in task_deps['tasks']: - task_deps['tasks'].append(task) - - flags = data.getVarFlags(task, d) - def getTask(name): - if not name in task_deps: - task_deps[name] = {} - if name in flags: - deptask = data.expand(flags[name], d) - task_deps[name][task] = deptask - getTask('depends') - getTask('deptask') - getTask('rdeptask') - getTask('recrdeptask') - getTask('nostamp') - task_deps['parents'][task] = [] - for dep in flags['deps']: - dep = data.expand(dep, d) - task_deps['parents'][task].append(dep) - - # don't assume holding a reference - data.setVar('_task_deps', task_deps, d) - -def remove_task(task, kill, d): - """Remove an BB 'task'. - - If kill is 1, also remove tasks that depend on this task.""" - - data.delVarFlag(task, 'task', d) - diff --git a/bitbake-dev/lib/bb/cache.py b/bitbake-dev/lib/bb/cache.py deleted file mode 100644 index 2f1b8fa601..0000000000 --- a/bitbake-dev/lib/bb/cache.py +++ /dev/null @@ -1,533 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -# -# BitBake 'Event' implementation -# -# Caching of bitbake variables before task execution - -# Copyright (C) 2006 Richard Purdie - -# but small sections based on code from bin/bitbake: -# 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 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - -import os, re -import bb.data -import bb.utils - -try: - import cPickle as pickle -except ImportError: - import pickle - bb.msg.note(1, bb.msg.domain.Cache, "Importing cPickle failed. Falling back to a very slow implementation.") - -__cache_version__ = "130" - -class Cache: - """ - BitBake Cache implementation - """ - def __init__(self, cooker): - - - self.cachedir = bb.data.getVar("CACHE", cooker.configuration.data, True) - self.clean = {} - self.checked = {} - self.depends_cache = {} - self.data = None - self.data_fn = None - self.cacheclean = True - - if self.cachedir in [None, '']: - self.has_cache = False - bb.msg.note(1, bb.msg.domain.Cache, "Not using a cache. Set CACHE = <directory> to enable.") - return - - self.has_cache = True - self.cachefile = os.path.join(self.cachedir,"bb_cache.dat") - - bb.msg.debug(1, bb.msg.domain.Cache, "Using cache in '%s'" % self.cachedir) - try: - os.stat( self.cachedir ) - except OSError: - bb.mkdirhier( self.cachedir ) - - # If any of configuration.data's dependencies are newer than the - # cache there isn't even any point in loading it... - newest_mtime = 0 - deps = bb.data.getVar("__depends", cooker.configuration.data, True) - for f,old_mtime in deps: - if old_mtime > newest_mtime: - newest_mtime = old_mtime - - if bb.parse.cached_mtime_noerror(self.cachefile) >= newest_mtime: - try: - p = pickle.Unpickler(file(self.cachefile, "rb")) - self.depends_cache, version_data = p.load() - if version_data['CACHE_VER'] != __cache_version__: - raise ValueError, 'Cache Version Mismatch' - if version_data['BITBAKE_VER'] != bb.__version__: - raise ValueError, 'Bitbake Version Mismatch' - except EOFError: - bb.msg.note(1, bb.msg.domain.Cache, "Truncated cache found, rebuilding...") - self.depends_cache = {} - except: - bb.msg.note(1, bb.msg.domain.Cache, "Invalid cache found, rebuilding...") - self.depends_cache = {} - else: - try: - os.stat( self.cachefile ) - bb.msg.note(1, bb.msg.domain.Cache, "Out of date cache found, rebuilding...") - except OSError: - pass - - def getVar(self, var, fn, exp = 0): - """ - Gets the value of a variable - (similar to getVar in the data class) - - There are two scenarios: - 1. We have cached data - serve from depends_cache[fn] - 2. We're learning what data to cache - serve from data - backend but add a copy of the data to the cache. - """ - if fn in self.clean: - return self.depends_cache[fn][var] - - if not fn in self.depends_cache: - self.depends_cache[fn] = {} - - 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.msg.error(bb.msg.domain.Cache, "Parsing error data_fn %s and fn %s don't match" % (self.data_fn, fn)) - - self.cacheclean = False - result = bb.data.getVar(var, self.data, exp) - self.depends_cache[fn][var] = result - return result - - def setData(self, virtualfn, fn, data): - """ - Called to prime bb_cache ready to learn which variables to cache. - Will be followed by calls to self.getVar which aren't cached - but can be fulfilled from self.data. - """ - self.data_fn = virtualfn - self.data = data - - # Make sure __depends makes the depends_cache - # If we're a virtual class we need to make sure all our depends are appended - # to the depends of fn. - depends = self.getVar("__depends", virtualfn, True) or [] - if "__depends" not in self.depends_cache[fn] or not self.depends_cache[fn]["__depends"]: - self.depends_cache[fn]["__depends"] = depends - for dep in depends: - if dep not in self.depends_cache[fn]["__depends"]: - self.depends_cache[fn]["__depends"].append(dep) - - # Make sure BBCLASSEXTEND always makes the cache too - self.getVar('BBCLASSEXTEND', virtualfn, True) - - self.depends_cache[virtualfn]["CACHETIMESTAMP"] = bb.parse.cached_mtime(fn) - - def virtualfn2realfn(self, virtualfn): - """ - Convert a virtual file name to a real one + the associated subclass keyword - """ - - fn = virtualfn - cls = "" - if virtualfn.startswith('virtual:'): - cls = virtualfn.split(':', 2)[1] - fn = virtualfn.replace('virtual:' + cls + ':', '') - #bb.msg.debug(2, bb.msg.domain.Cache, "virtualfn2realfn %s to %s %s" % (virtualfn, fn, cls)) - return (fn, cls) - - def realfn2virtual(self, realfn, cls): - """ - Convert a real filename + the associated subclass keyword to a virtual filename - """ - if cls == "": - #bb.msg.debug(2, bb.msg.domain.Cache, "realfn2virtual %s and '%s' to %s" % (realfn, cls, realfn)) - return realfn - #bb.msg.debug(2, bb.msg.domain.Cache, "realfn2virtual %s and %s to %s" % (realfn, cls, "virtual:" + cls + ":" + realfn)) - return "virtual:" + cls + ":" + realfn - - def loadDataFull(self, virtualfn, cfgData): - """ - Return a complete set of data for fn. - To do this, we need to parse the file. - """ - - (fn, cls) = self.virtualfn2realfn(virtualfn) - - bb.msg.debug(1, bb.msg.domain.Cache, "Parsing %s (full)" % fn) - - bb_data = self.load_bbfile(fn, cfgData) - return bb_data[cls] - - def loadData(self, fn, cfgData, cacheData): - """ - Load a subset of data for fn. - If the cached data is valid we do nothing, - To do this, we need to parse the file and set the system - to record the variables accessed. - Return the cache status and whether the file was skipped when parsed - """ - skipped = 0 - virtuals = 0 - - if fn not in self.checked: - self.cacheValidUpdate(fn) - - if self.cacheValid(fn): - multi = self.getVar('BBCLASSEXTEND', fn, True) - for cls in (multi or "").split() + [""]: - virtualfn = self.realfn2virtual(fn, cls) - if self.depends_cache[virtualfn]["__SKIPPED"]: - skipped += 1 - bb.msg.debug(1, bb.msg.domain.Cache, "Skipping %s" % virtualfn) - continue - self.handle_data(virtualfn, cacheData) - virtuals += 1 - return True, skipped, virtuals - - bb.msg.debug(1, bb.msg.domain.Cache, "Parsing %s" % fn) - - bb_data = self.load_bbfile(fn, cfgData) - - for data in bb_data: - virtualfn = self.realfn2virtual(fn, data) - self.setData(virtualfn, fn, bb_data[data]) - if self.getVar("__SKIPPED", virtualfn, True): - skipped += 1 - bb.msg.debug(1, bb.msg.domain.Cache, "Skipping %s" % virtualfn) - else: - self.handle_data(virtualfn, cacheData) - virtuals += 1 - return False, skipped, virtuals - - - def cacheValid(self, fn): - """ - Is the cache valid for fn? - Fast version, no timestamps checked. - """ - # Is cache enabled? - if not self.has_cache: - return False - if fn in self.clean: - return True - return False - - def cacheValidUpdate(self, fn): - """ - Is the cache valid for fn? - Make thorough (slower) checks including timestamps. - """ - # Is cache enabled? - if not self.has_cache: - return False - - self.checked[fn] = "" - - # Pretend we're clean so getVar works - self.clean[fn] = "" - - # File isn't in depends_cache - if not fn in self.depends_cache: - bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s is not cached" % fn) - self.remove(fn) - return False - - mtime = bb.parse.cached_mtime_noerror(fn) - - # Check file still exists - if mtime == 0: - bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s not longer exists" % fn) - self.remove(fn) - return False - - # Check the file's timestamp - if mtime != self.getVar("CACHETIMESTAMP", fn, True): - 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) - if depends: - for f,old_mtime in depends: - fmtime = bb.parse.cached_mtime_noerror(f) - # Check if file still exists - if old_mtime != 0 and fmtime == 0: - self.remove(fn) - return False - - if (fmtime != old_mtime): - bb.msg.debug(2, bb.msg.domain.Cache, "Cache: %s's dependency %s changed" % (fn, f)) - self.remove(fn) - return False - - #bb.msg.debug(2, bb.msg.domain.Cache, "Depends Cache: %s is clean" % fn) - if not fn in self.clean: - self.clean[fn] = "" - - # Mark extended class data as clean too - multi = self.getVar('BBCLASSEXTEND', fn, True) - for cls in (multi or "").split(): - virtualfn = self.realfn2virtual(fn, cls) - self.clean[virtualfn] = "" - - return True - - def remove(self, fn): - """ - Remove a fn from the cache - Called from the parser in error cases - """ - 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: - del self.clean[fn] - - def sync(self): - """ - Save the cache - Called from the parser when complete (or exiting) - """ - import copy - - if not self.has_cache: - return - - if self.cacheclean: - bb.msg.note(1, bb.msg.domain.Cache, "Cache is clean, not saving.") - return - - version_data = {} - version_data['CACHE_VER'] = __cache_version__ - version_data['BITBAKE_VER'] = bb.__version__ - - cache_data = copy.deepcopy(self.depends_cache) - for fn in self.depends_cache: - if '__BB_DONT_CACHE' in self.depends_cache[fn] and self.depends_cache[fn]['__BB_DONT_CACHE']: - bb.msg.debug(2, bb.msg.domain.Cache, "Not caching %s, marked as not cacheable" % fn) - del cache_data[fn] - elif 'PV' in self.depends_cache[fn] and 'SRCREVINACTION' in self.depends_cache[fn]['PV']: - bb.msg.error(bb.msg.domain.Cache, "Not caching %s as it had SRCREVINACTION in PV. Please report this bug" % fn) - del cache_data[fn] - - p = pickle.Pickler(file(self.cachefile, "wb" ), -1 ) - p.dump([cache_data, version_data]) - - def mtime(self, cachefile): - return bb.parse.cached_mtime_noerror(cachefile) - - def handle_data(self, file_name, cacheData): - """ - Save data we need into the cache - """ - - pn = self.getVar('PN', file_name, True) - pe = self.getVar('PE', file_name, True) or "0" - pv = self.getVar('PV', file_name, True) - if 'SRCREVINACTION' in pv: - bb.note("Found SRCREVINACTION in PV (%s) or %s. Please report this bug." % (pv, file_name)) - pr = self.getVar('PR', file_name, True) - dp = int(self.getVar('DEFAULT_PREFERENCE', file_name, True) or "0") - 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_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_pepvpr[file_name] = (pe,pv,pr) - cacheData.pkg_dp[file_name] = dp - - provides = [pn] - for provide in (self.getVar("PROVIDES", file_name, True) or "").split(): - if provide not in provides: - provides.append(provide) - - # Build forward and reverse provider hashes - # Forward: virtual -> [filenames] - # Reverse: PN -> [virtuals] - if pn not in cacheData.pn_provides: - cacheData.pn_provides[pn] = [] - - cacheData.fn_provides[file_name] = provides - for provide in provides: - if provide not in cacheData.providers: - cacheData.providers[provide] = [] - cacheData.providers[provide].append(file_name) - if not provide in cacheData.pn_provides[pn]: - cacheData.pn_provides[pn].append(provide) - - cacheData.deps[file_name] = [] - for dep in depends: - if not dep in cacheData.deps[file_name]: - cacheData.deps[file_name].append(dep) - if not dep in cacheData.all_depends: - cacheData.all_depends.append(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 - - if not file_name in cacheData.rundeps: - cacheData.rundeps[file_name] = {} - if not file_name in cacheData.runrecs: - cacheData.runrecs[file_name] = {} - - rdepends = self.getVar('RDEPENDS', file_name, True) or "" - rrecommends = self.getVar('RRECOMMENDS', file_name, True) or "" - 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] = [] - - cacheData.rundeps[file_name][package] = rdepends + " " + (self.getVar("RDEPENDS_%s" % package, file_name, True) or "") - cacheData.runrecs[file_name][package] = rrecommends + " " + (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) - - # Touch this to make sure its in the cache - self.getVar('__BB_DONT_CACHE', file_name, True) - self.getVar('BBCLASSEXTEND', file_name, True) - - 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 - """ - - import bb - from bb import utils, data, parse, debug, event, fatal - - # expand tmpdir to include this topdir - 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 bb.parse.cached_mtime_noerror(bbfile_loc): - os.chdir(bbfile_loc) - bb_data = data.init_db(config) - try: - bb_data = parse.handle(bbfile, bb_data) # read .bb data - os.chdir(oldpath) - return bb_data - except: - os.chdir(oldpath) - raise - -def init(cooker): - """ - The Objective: Cache the minimum amount of data possible yet get to the - stage of building packages (i.e. tryBuild) without reparsing any .bb files. - - To do this, we intercept getVar calls and only cache the variables we see - being accessed. We rely on the cache getVar calls being made for all - variables bitbake might need to use to reach this stage. For each cached - file we need to track: - - * Its mtime - * The mtimes of all its dependencies - * Whether it caused a parse.SkipPackage exception - - Files causing parsing errors are evicted from the cache. - - """ - 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_pepvpr = {} - self.pkg_dp = {} - self.pn_provides = {} - self.fn_provides = {} - self.all_depends = [] - 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-dev/lib/bb/command.py b/bitbake-dev/lib/bb/command.py deleted file mode 100644 index 2bb5365c0c..0000000000 --- a/bitbake-dev/lib/bb/command.py +++ /dev/null @@ -1,271 +0,0 @@ -""" -BitBake 'Command' module - -Provide an interface to interact with the bitbake server through 'commands' -""" - -# Copyright (C) 2006-2007 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -""" -The bitbake server takes 'commands' from its UI/commandline. -Commands are either synchronous or asynchronous. -Async commands return data to the client in the form of events. -Sync commands must only return data through the function return value -and must not trigger events, directly or indirectly. -Commands are queued in a CommandQueue -""" - -import bb - -async_cmds = {} -sync_cmds = {} - -class Command: - """ - A queue of asynchronous commands for bitbake - """ - def __init__(self, cooker): - - self.cooker = cooker - self.cmds_sync = CommandsSync() - self.cmds_async = CommandsAsync() - - # FIXME Add lock for this - self.currentAsyncCommand = None - - for attr in CommandsSync.__dict__: - command = attr[:].lower() - method = getattr(CommandsSync, attr) - sync_cmds[command] = (method) - - for attr in CommandsAsync.__dict__: - command = attr[:].lower() - method = getattr(CommandsAsync, attr) - async_cmds[command] = (method) - - def runCommand(self, commandline): - try: - command = commandline.pop(0) - if command in CommandsSync.__dict__: - # Can run synchronous commands straight away - return getattr(CommandsSync, command)(self.cmds_sync, self, commandline) - if self.currentAsyncCommand is not None: - return "Busy (%s in progress)" % self.currentAsyncCommand[0] - if command not in CommandsAsync.__dict__: - return "No such command" - self.currentAsyncCommand = (command, commandline) - self.cooker.server.register_idle_function(self.cooker.runCommands, self.cooker) - return True - except: - import traceback - return traceback.format_exc() - - def runAsyncCommand(self): - try: - if self.currentAsyncCommand is not None: - (command, options) = self.currentAsyncCommand - commandmethod = getattr(CommandsAsync, command) - needcache = getattr( commandmethod, "needcache" ) - if needcache and self.cooker.cookerState != bb.cooker.cookerParsed: - self.cooker.updateCache() - return True - else: - commandmethod(self.cmds_async, self, options) - return False - else: - return False - except: - import traceback - self.finishAsyncCommand(traceback.format_exc()) - return False - - def finishAsyncCommand(self, error = None): - if error: - bb.event.fire(bb.command.CookerCommandFailed(error), self.cooker.configuration.event_data) - else: - bb.event.fire(bb.command.CookerCommandCompleted(), self.cooker.configuration.event_data) - self.currentAsyncCommand = None - - -class CommandsSync: - """ - A class of synchronous commands - These should run quickly so as not to hurt interactive performance. - These must not influence any running synchronous command. - """ - - def stateShutdown(self, command, params): - """ - Trigger cooker 'shutdown' mode - """ - command.cooker.cookerAction = bb.cooker.cookerShutdown - - def stateStop(self, command, params): - """ - Stop the cooker - """ - command.cooker.cookerAction = bb.cooker.cookerStop - - def getCmdLineAction(self, command, params): - """ - Get any command parsed from the commandline - """ - return command.cooker.commandlineAction - - def getVariable(self, command, params): - """ - Read the value of a variable from configuration.data - """ - varname = params[0] - expand = True - if len(params) > 1: - expand = params[1] - - return bb.data.getVar(varname, command.cooker.configuration.data, expand) - - def setVariable(self, command, params): - """ - Set the value of variable in configuration.data - """ - varname = params[0] - value = params[1] - bb.data.setVar(varname, value, command.cooker.configuration.data) - - -class CommandsAsync: - """ - A class of asynchronous commands - These functions communicate via generated events. - Any function that requires metadata parsing should be here. - """ - - def buildFile(self, command, params): - """ - Build a single specified .bb file - """ - bfile = params[0] - task = params[1] - - command.cooker.buildFile(bfile, task) - buildFile.needcache = False - - def buildTargets(self, command, params): - """ - Build a set of targets - """ - pkgs_to_build = params[0] - task = params[1] - - command.cooker.buildTargets(pkgs_to_build, task) - buildTargets.needcache = True - - def generateDepTreeEvent(self, command, params): - """ - Generate an event containing the dependency information - """ - pkgs_to_build = params[0] - task = params[1] - - command.cooker.generateDepTreeEvent(pkgs_to_build, task) - command.finishAsyncCommand() - generateDepTreeEvent.needcache = True - - def generateDotGraph(self, command, params): - """ - Dump dependency information to disk as .dot files - """ - pkgs_to_build = params[0] - task = params[1] - - command.cooker.generateDotGraphFiles(pkgs_to_build, task) - command.finishAsyncCommand() - generateDotGraph.needcache = True - - def showVersions(self, command, params): - """ - Show the currently selected versions - """ - command.cooker.showVersions() - command.finishAsyncCommand() - showVersions.needcache = True - - def showEnvironmentTarget(self, command, params): - """ - Print the environment of a target recipe - (needs the cache to work out which recipe to use) - """ - pkg = params[0] - - command.cooker.showEnvironment(None, pkg) - command.finishAsyncCommand() - showEnvironmentTarget.needcache = True - - def showEnvironment(self, command, params): - """ - Print the standard environment - or if specified the environment for a specified recipe - """ - bfile = params[0] - - command.cooker.showEnvironment(bfile) - command.finishAsyncCommand() - showEnvironment.needcache = False - - def parseFiles(self, command, params): - """ - Parse the .bb files - """ - command.cooker.updateCache() - command.finishAsyncCommand() - parseFiles.needcache = True - - def compareRevisions(self, command, params): - """ - Parse the .bb files - """ - command.cooker.compareRevisions() - command.finishAsyncCommand() - compareRevisions.needcache = True - -# -# Events -# -class CookerCommandCompleted(bb.event.Event): - """ - Cooker command completed - """ - def __init__(self): - bb.event.Event.__init__(self) - - -class CookerCommandFailed(bb.event.Event): - """ - Cooker command completed - """ - def __init__(self, error): - bb.event.Event.__init__(self) - self.error = error - -class CookerCommandSetExitCode(bb.event.Event): - """ - Set the exit code for a cooker command - """ - def __init__(self, exitcode): - bb.event.Event.__init__(self) - self.exitcode = int(exitcode) - - - diff --git a/bitbake-dev/lib/bb/cooker.py b/bitbake-dev/lib/bb/cooker.py deleted file mode 100644 index 8036d7e9d5..0000000000 --- a/bitbake-dev/lib/bb/cooker.py +++ /dev/null @@ -1,978 +0,0 @@ -#!/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 - 2007 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import sys, os, getopt, glob, copy, os.path, re, time -import bb -from bb import utils, data, parse, event, cache, providers, taskdata, runqueue -from bb import command -import bb.server.xmlrpc -import itertools, sre_constants - -class MultipleMatches(Exception): - """ - Exception raised when multiple file matches are found - """ - -class ParsingErrorsFound(Exception): - """ - Exception raised when parsing errors are found - """ - -class NothingToBuild(Exception): - """ - Exception raised when there is nothing to build - """ - - -# Different states cooker can be in -cookerClean = 1 -cookerParsing = 2 -cookerParsed = 3 - -# Different action states the cooker can be in -cookerRun = 1 # Cooker is running normally -cookerShutdown = 2 # Active tasks should be brought to a controlled stop -cookerStop = 3 # Stop, now! - -#============================================================================# -# BBCooker -#============================================================================# -class BBCooker: - """ - Manages one bitbake build run - """ - - def __init__(self, configuration, server): - self.status = None - - self.cache = None - self.bb_cache = None - - self.server = server.BitBakeServer(self) - - self.configuration = configuration - - if self.configuration.verbose: - bb.msg.set_verbose(True) - - if self.configuration.debug: - bb.msg.set_debug_level(self.configuration.debug) - else: - bb.msg.set_debug_level(0) - - if self.configuration.debug_domains: - bb.msg.set_debug_domains(self.configuration.debug_domains) - - self.configuration.data = bb.data.init() - - bb.data.inheritFromOS(self.configuration.data) - - for f in self.configuration.file: - self.parseConfigurationFile( f ) - - self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) ) - - if not self.configuration.cmd: - self.configuration.cmd = bb.data.getVar("BB_DEFAULT_TASK", self.configuration.data, True) or "build" - - bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, True) - if bbpkgs and len(self.configuration.pkgs_to_build) == 0: - self.configuration.pkgs_to_build.extend(bbpkgs.split()) - - # - # Special updated configuration we use for firing events - # - self.configuration.event_data = bb.data.createCopy(self.configuration.data) - bb.data.update_data(self.configuration.event_data) - - # TOSTOP must not be set or our children will hang when they output - fd = sys.stdout.fileno() - if os.isatty(fd): - import termios - tcattr = termios.tcgetattr(fd) - if tcattr[3] & termios.TOSTOP: - bb.msg.note(1, bb.msg.domain.Build, "The terminal had the TOSTOP bit set, clearing...") - tcattr[3] = tcattr[3] & ~termios.TOSTOP - termios.tcsetattr(fd, termios.TCSANOW, tcattr) - - self.command = bb.command.Command(self) - self.cookerState = cookerClean - self.cookerAction = cookerRun - - def parseConfiguration(self): - - - # Change nice level if we're asked to - nice = bb.data.getVar("BB_NICE_LEVEL", self.configuration.data, True) - if nice: - curnice = os.nice(0) - nice = int(nice) - curnice - bb.msg.note(2, bb.msg.domain.Build, "Renice to %s " % os.nice(nice)) - - def parseCommandLine(self): - # Parse any commandline into actions - if self.configuration.show_environment: - self.commandlineAction = None - - if 'world' in self.configuration.pkgs_to_build: - bb.error("'world' is not a valid target for --environment.") - elif len(self.configuration.pkgs_to_build) > 1: - bb.error("Only one target can be used with the --environment option.") - elif self.configuration.buildfile and len(self.configuration.pkgs_to_build) > 0: - bb.error("No target should be used with the --environment and --buildfile options.") - elif len(self.configuration.pkgs_to_build) > 0: - self.commandlineAction = ["showEnvironmentTarget", self.configuration.pkgs_to_build] - else: - self.commandlineAction = ["showEnvironment", self.configuration.buildfile] - elif self.configuration.buildfile is not None: - self.commandlineAction = ["buildFile", self.configuration.buildfile, self.configuration.cmd] - elif self.configuration.revisions_changed: - self.commandlineAction = ["compareRevisions"] - elif self.configuration.show_versions: - self.commandlineAction = ["showVersions"] - elif self.configuration.parse_only: - self.commandlineAction = ["parseFiles"] - # FIXME - implement - #elif self.configuration.interactive: - # self.interactiveMode() - elif self.configuration.dot_graph: - if self.configuration.pkgs_to_build: - self.commandlineAction = ["generateDotGraph", self.configuration.pkgs_to_build, self.configuration.cmd] - else: - self.commandlineAction = None - bb.error("Please specify a package name for dependency graph generation.") - else: - if self.configuration.pkgs_to_build: - self.commandlineAction = ["buildTargets", self.configuration.pkgs_to_build, self.configuration.cmd] - else: - self.commandlineAction = None - bb.error("Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.") - - def runCommands(self, server, data, abort): - """ - Run any queued asynchronous command - This is done by the idle handler so it runs in true context rather than - tied to any UI. - """ - - return self.command.runAsyncCommand() - - def tryBuildPackage(self, fn, item, task, the_data): - """ - Build one task of a package, optionally build following task depends - """ - try: - if not self.configuration.dry_run: - bb.build.exec_task('do_%s' % task, the_data) - return True - except bb.build.FuncFailed: - bb.msg.error(bb.msg.domain.Build, "task stack execution failed") - raise - except bb.build.EventException, e: - event = e.args[1] - bb.msg.error(bb.msg.domain.Build, "%s event exception, aborting" % bb.event.getName(event)) - raise - - def tryBuild(self, fn, task): - """ - Build a provider and its dependencies. - build_depends is a list of previous build dependencies (not runtime) - If build_depends is empty, we're dealing with a runtime depends - """ - - the_data = self.bb_cache.loadDataFull(fn, self.configuration.data) - - item = self.status.pkg_fn[fn] - - #if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data): - # return True - - return self.tryBuildPackage(fn, item, task, the_data) - - def showVersions(self): - - # Need files parsed - self.updateCache() - - pkg_pn = self.status.pkg_pn - preferred_versions = {} - latest_versions = {} - - # Sort by priority - for pn in pkg_pn.keys(): - (last_ver,last_file,pref_ver,pref_file) = bb.providers.findBestProvider(pn, self.configuration.data, self.status) - preferred_versions[pn] = (pref_ver, pref_file) - latest_versions[pn] = (last_ver, last_file) - - pkg_list = pkg_pn.keys() - pkg_list.sort() - - bb.msg.plain("%-35s %25s %25s" % ("Package Name", "Latest Version", "Preferred Version")) - bb.msg.plain("%-35s %25s %25s\n" % ("============", "==============", "=================")) - - for p in pkg_list: - pref = preferred_versions[p] - latest = latest_versions[p] - - prefstr = pref[0][0] + ":" + pref[0][1] + '-' + pref[0][2] - lateststr = latest[0][0] + ":" + latest[0][1] + "-" + latest[0][2] - - if pref == latest: - prefstr = "" - - bb.msg.plain("%-35s %25s %25s" % (p, lateststr, prefstr)) - - def compareRevisions(self): - ret = bb.fetch.fetcher_compare_revisons(self.configuration.data) - bb.event.fire(bb.command.CookerCommandSetExitCode(ret), self.configuration.event_data) - - def showEnvironment(self, buildfile = None, pkgs_to_build = []): - """ - Show the outer or per-package environment - """ - fn = None - envdata = None - - if buildfile: - self.cb = None - self.bb_cache = bb.cache.init(self) - fn = self.matchFile(buildfile) - elif len(pkgs_to_build) == 1: - self.updateCache() - - localdata = data.createCopy(self.configuration.data) - bb.data.update_data(localdata) - bb.data.expandKeys(localdata) - - taskdata = bb.taskdata.TaskData(self.configuration.abort) - taskdata.add_provider(localdata, self.status, pkgs_to_build[0]) - taskdata.add_unresolved(localdata, self.status) - - targetid = taskdata.getbuild_id(pkgs_to_build[0]) - fnid = taskdata.build_targets[targetid][0] - fn = taskdata.fn_index[fnid] - else: - envdata = self.configuration.data - - if fn: - try: - envdata = self.bb_cache.loadDataFull(fn, self.configuration.data) - except IOError, e: - bb.msg.error(bb.msg.domain.Parsing, "Unable to read %s: %s" % (fn, e)) - raise - except Exception, e: - bb.msg.error(bb.msg.domain.Parsing, "%s" % e) - raise - - class dummywrite: - def __init__(self): - self.writebuf = "" - def write(self, output): - self.writebuf = self.writebuf + output - - # emit variables and shell functions - try: - data.update_data(envdata) - wb = dummywrite() - data.emit_env(wb, envdata, True) - bb.msg.plain(wb.writebuf) - except Exception, e: - bb.msg.fatal(bb.msg.domain.Parsing, "%s" % e) - # emit the metadata which isnt valid shell - data.expandKeys(envdata) - for e in envdata.keys(): - if data.getVarFlag( e, 'python', envdata ): - bb.msg.plain("\npython %s () {\n%s}\n" % (e, data.getVar(e, envdata, 1))) - - def generateDepTreeData(self, pkgs_to_build, task): - """ - Create a dependency tree of pkgs_to_build, returning the data. - """ - - # Need files parsed - self.updateCache() - - # If we are told to do the None task then query the default task - if (task == None): - task = self.configuration.cmd - - pkgs_to_build = self.checkPackages(pkgs_to_build) - - localdata = data.createCopy(self.configuration.data) - bb.data.update_data(localdata) - bb.data.expandKeys(localdata) - taskdata = bb.taskdata.TaskData(self.configuration.abort) - - runlist = [] - for k in pkgs_to_build: - taskdata.add_provider(localdata, self.status, k) - runlist.append([k, "do_%s" % task]) - taskdata.add_unresolved(localdata, self.status) - - rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist) - rq.prepare_runqueue() - - seen_fnids = [] - depend_tree = {} - depend_tree["depends"] = {} - depend_tree["tdepends"] = {} - depend_tree["pn"] = {} - depend_tree["rdepends-pn"] = {} - depend_tree["packages"] = {} - depend_tree["rdepends-pkg"] = {} - depend_tree["rrecs-pkg"] = {} - - for task in range(len(rq.runq_fnid)): - taskname = rq.runq_task[task] - fnid = rq.runq_fnid[task] - fn = taskdata.fn_index[fnid] - pn = self.status.pkg_fn[fn] - version = "%s:%s-%s" % self.status.pkg_pepvpr[fn] - if pn not in depend_tree["pn"]: - depend_tree["pn"][pn] = {} - depend_tree["pn"][pn]["filename"] = fn - depend_tree["pn"][pn]["version"] = version - for dep in rq.runq_depends[task]: - depfn = taskdata.fn_index[rq.runq_fnid[dep]] - deppn = self.status.pkg_fn[depfn] - dotname = "%s.%s" % (pn, rq.runq_task[task]) - if not dotname in depend_tree["tdepends"]: - depend_tree["tdepends"][dotname] = [] - depend_tree["tdepends"][dotname].append("%s.%s" % (deppn, rq.runq_task[dep])) - if fnid not in seen_fnids: - seen_fnids.append(fnid) - packages = [] - - depend_tree["depends"][pn] = [] - for dep in taskdata.depids[fnid]: - depend_tree["depends"][pn].append(taskdata.build_names_index[dep]) - - depend_tree["rdepends-pn"][pn] = [] - for rdep in taskdata.rdepids[fnid]: - depend_tree["rdepends-pn"][pn].append(taskdata.run_names_index[rdep]) - - rdepends = self.status.rundeps[fn] - for package in rdepends: - depend_tree["rdepends-pkg"][package] = [] - for rdepend in rdepends[package]: - depend_tree["rdepends-pkg"][package].append(rdepend) - packages.append(package) - - rrecs = self.status.runrecs[fn] - for package in rrecs: - depend_tree["rrecs-pkg"][package] = [] - for rdepend in rrecs[package]: - depend_tree["rrecs-pkg"][package].append(rdepend) - if not package in packages: - packages.append(package) - - for package in packages: - if package not in depend_tree["packages"]: - depend_tree["packages"][package] = {} - depend_tree["packages"][package]["pn"] = pn - depend_tree["packages"][package]["filename"] = fn - depend_tree["packages"][package]["version"] = version - - return depend_tree - - - def generateDepTreeEvent(self, pkgs_to_build, task): - """ - Create a task dependency graph of pkgs_to_build. - Generate an event with the result - """ - depgraph = self.generateDepTreeData(pkgs_to_build, task) - bb.event.fire(bb.event.DepTreeGenerated(depgraph), self.configuration.data) - - def generateDotGraphFiles(self, pkgs_to_build, task): - """ - Create a task dependency graph of pkgs_to_build. - Save the result to a set of .dot files. - """ - - depgraph = self.generateDepTreeData(pkgs_to_build, task) - - # Prints a flattened form of package-depends below where subpackages of a package are merged into the main pn - depends_file = file('pn-depends.dot', 'w' ) - print >> depends_file, "digraph depends {" - for pn in depgraph["pn"]: - fn = depgraph["pn"][pn]["filename"] - version = depgraph["pn"][pn]["version"] - print >> depends_file, '"%s" [label="%s %s\\n%s"]' % (pn, pn, version, fn) - for pn in depgraph["depends"]: - for depend in depgraph["depends"][pn]: - print >> depends_file, '"%s" -> "%s"' % (pn, depend) - for pn in depgraph["rdepends-pn"]: - for rdepend in depgraph["rdepends-pn"][pn]: - print >> depends_file, '"%s" -> "%s" [style=dashed]' % (pn, rdepend) - print >> depends_file, "}" - bb.msg.plain("PN dependencies saved to 'pn-depends.dot'") - - depends_file = file('package-depends.dot', 'w' ) - print >> depends_file, "digraph depends {" - for package in depgraph["packages"]: - pn = depgraph["packages"][package]["pn"] - fn = depgraph["packages"][package]["filename"] - version = depgraph["packages"][package]["version"] - if package == pn: - print >> depends_file, '"%s" [label="%s %s\\n%s"]' % (pn, pn, version, fn) - else: - print >> depends_file, '"%s" [label="%s(%s) %s\\n%s"]' % (package, package, pn, version, fn) - for depend in depgraph["depends"][pn]: - print >> depends_file, '"%s" -> "%s"' % (package, depend) - for package in depgraph["rdepends-pkg"]: - for rdepend in depgraph["rdepends-pkg"][package]: - print >> depends_file, '"%s" -> "%s" [style=dashed]' % (package, rdepend) - for package in depgraph["rrecs-pkg"]: - for rdepend in depgraph["rrecs-pkg"][package]: - print >> depends_file, '"%s" -> "%s" [style=dashed]' % (package, rdepend) - print >> depends_file, "}" - bb.msg.plain("Package dependencies saved to 'package-depends.dot'") - - tdepends_file = file('task-depends.dot', 'w' ) - print >> tdepends_file, "digraph depends {" - for task in depgraph["tdepends"]: - (pn, taskname) = task.rsplit(".", 1) - fn = depgraph["pn"][pn]["filename"] - version = depgraph["pn"][pn]["version"] - print >> tdepends_file, '"%s.%s" [label="%s %s\\n%s\\n%s"]' % (pn, taskname, pn, taskname, version, fn) - for dep in depgraph["tdepends"][task]: - print >> tdepends_file, '"%s" -> "%s"' % (task, dep) - print >> tdepends_file, "}" - bb.msg.plain("Task dependencies saved to 'task-depends.dot'") - - def buildDepgraph( self ): - all_depends = self.status.all_depends - pn_provides = self.status.pn_provides - - localdata = data.createCopy(self.configuration.data) - bb.data.update_data(localdata) - bb.data.expandKeys(localdata) - - def calc_bbfile_priority(filename): - for (regex, pri) in self.status.bbfile_config_priorities: - if regex.match(filename): - return pri - return 0 - - # Handle PREFERRED_PROVIDERS - for p in (bb.data.getVar('PREFERRED_PROVIDERS', localdata, 1) or "").split(): - try: - (providee, provider) = p.split(':') - except: - bb.msg.fatal(bb.msg.domain.Provider, "Malformed option in PREFERRED_PROVIDERS variable: %s" % p) - continue - if providee in self.status.preferred and self.status.preferred[providee] != provider: - bb.msg.error(bb.msg.domain.Provider, "conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.status.preferred[providee])) - self.status.preferred[providee] = provider - - # Calculate priorities for each file - for p in self.status.pkg_fn.keys(): - self.status.bbfile_priority[p] = calc_bbfile_priority(p) - - def buildWorldTargetList(self): - """ - Build package list for "bitbake world" - """ - all_depends = self.status.all_depends - pn_provides = self.status.pn_provides - bb.msg.debug(1, bb.msg.domain.Parsing, "collating packages for \"world\"") - for f in self.status.possible_world: - terminal = True - pn = self.status.pkg_fn[f] - - for p in pn_provides[pn]: - if p.startswith('virtual/'): - bb.msg.debug(2, bb.msg.domain.Parsing, "World build skipping %s due to %s provider starting with virtual/" % (f, p)) - terminal = False - break - for pf in self.status.providers[p]: - if self.status.pkg_fn[pf] != pn: - bb.msg.debug(2, bb.msg.domain.Parsing, "World build skipping %s due to both us and %s providing %s" % (f, pf, p)) - terminal = False - break - if terminal: - self.status.world_target.add(pn) - - # drop reference count now - self.status.possible_world = None - self.status.all_depends = None - - def interactiveMode( self ): - """Drop off into a shell""" - try: - from bb import shell - except ImportError, details: - bb.msg.fatal(bb.msg.domain.Parsing, "Sorry, shell not available (%s)" % details ) - else: - shell.start( self ) - - def parseConfigurationFile( self, afile ): - try: - self.configuration.data = bb.parse.handle( afile, self.configuration.data ) - - # Handle any INHERITs and inherit the base class - inherits = ["base"] + (bb.data.getVar('INHERIT', self.configuration.data, True ) or "").split() - for inherit in inherits: - self.configuration.data = bb.parse.handle(os.path.join('classes', '%s.bbclass' % inherit), self.configuration.data, True ) - - # Nomally we only register event handlers at the end of parsing .bb files - # We register any handlers we've found so far here... - for var in data.getVar('__BBHANDLERS', self.configuration.data) or []: - bb.event.register(var,bb.data.getVar(var, self.configuration.data)) - - bb.fetch.fetcher_init(self.configuration.data) - - bb.event.fire(bb.event.ConfigParsed(), self.configuration.data) - - except IOError, e: - bb.msg.fatal(bb.msg.domain.Parsing, "Error when parsing %s: %s" % (afile, str(e))) - except bb.parse.ParseError, details: - bb.msg.fatal(bb.msg.domain.Parsing, "Unable to parse %s (%s)" % (afile, details) ) - - def handleCollections( self, collections ): - """Handle collections""" - if collections: - collection_list = collections.split() - for c in collection_list: - regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1) - if regex == None: - bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PATTERN_%s not defined" % c) - continue - priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1) - if priority == None: - bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PRIORITY_%s not defined" % c) - continue - try: - cre = re.compile(regex) - except re.error: - bb.msg.error(bb.msg.domain.Parsing, "BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex)) - continue - try: - pri = int(priority) - self.status.bbfile_config_priorities.append((cre, pri)) - except ValueError: - bb.msg.error(bb.msg.domain.Parsing, "invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority)) - - def buildSetVars(self): - """ - Setup any variables needed before starting a build - """ - if not bb.data.getVar("BUILDNAME", self.configuration.data): - bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data) - bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()), self.configuration.data) - - def matchFiles(self, buildfile): - """ - Find the .bb files which match the expression in 'buildfile'. - """ - - bf = os.path.abspath(buildfile) - try: - os.stat(bf) - return [bf] - except OSError: - (filelist, masked) = self.collect_bbfiles() - regexp = re.compile(buildfile) - matches = [] - for f in filelist: - if regexp.search(f) and os.path.isfile(f): - bf = f - matches.append(f) - return matches - - def matchFile(self, buildfile): - """ - Find the .bb file which matches the expression in 'buildfile'. - Raise an error if multiple files - """ - matches = self.matchFiles(buildfile) - if len(matches) != 1: - bb.msg.error(bb.msg.domain.Parsing, "Unable to match %s (%s matches found):" % (buildfile, len(matches))) - for f in matches: - bb.msg.error(bb.msg.domain.Parsing, " %s" % f) - raise MultipleMatches - return matches[0] - - def buildFile(self, buildfile, task): - """ - Build the file matching regexp buildfile - """ - - # Parse the configuration here. We need to do it explicitly here since - # buildFile() doesn't use the cache - self.parseConfiguration() - - # If we are told to do the None task then query the default task - if (task == None): - task = self.configuration.cmd - - fn = self.matchFile(buildfile) - self.buildSetVars() - - # Load data into the cache for fn and parse the loaded cache data - self.bb_cache = bb.cache.init(self) - self.status = bb.cache.CacheData() - self.bb_cache.loadData(fn, self.configuration.data, self.status) - - # Tweak some variables - item = self.bb_cache.getVar('PN', fn, True) - self.status.ignored_dependencies = set() - self.status.bbfile_priority[fn] = 1 - - # Remove external dependencies - self.status.task_deps[fn]['depends'] = {} - self.status.deps[fn] = [] - self.status.rundeps[fn] = [] - self.status.runrecs[fn] = [] - - # Remove stamp for target if force mode active - if self.configuration.force: - bb.msg.note(2, bb.msg.domain.RunQueue, "Remove stamp %s, %s" % (task, fn)) - bb.build.del_stamp('do_%s' % task, self.status, fn) - - # Setup taskdata structure - taskdata = bb.taskdata.TaskData(self.configuration.abort) - taskdata.add_provider(self.configuration.data, self.status, item) - - buildname = bb.data.getVar("BUILDNAME", self.configuration.data) - bb.event.fire(bb.event.BuildStarted(buildname, [item]), self.configuration.event_data) - - # Execute the runqueue - runlist = [[item, "do_%s" % task]] - - rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist) - - def buildFileIdle(server, rq, abort): - - if abort or self.cookerAction == cookerStop: - rq.finish_runqueue(True) - elif self.cookerAction == cookerShutdown: - rq.finish_runqueue(False) - failures = 0 - try: - retval = rq.execute_runqueue() - except runqueue.TaskFailure, fnids: - for fnid in fnids: - bb.msg.error(bb.msg.domain.Build, "'%s' failed" % taskdata.fn_index[fnid]) - failures = failures + 1 - retval = False - if not retval: - self.command.finishAsyncCommand() - bb.event.fire(bb.event.BuildCompleted(buildname, item, failures), self.configuration.event_data) - return False - return 0.5 - - self.server.register_idle_function(buildFileIdle, rq) - - def buildTargets(self, targets, task): - """ - Attempt to build the targets specified - """ - - # Need files parsed - self.updateCache() - - # If we are told to do the NULL task then query the default task - if (task == None): - task = self.configuration.cmd - - targets = self.checkPackages(targets) - - def buildTargetsIdle(server, rq, abort): - - if abort or self.cookerAction == cookerStop: - rq.finish_runqueue(True) - elif self.cookerAction == cookerShutdown: - rq.finish_runqueue(False) - failures = 0 - try: - retval = rq.execute_runqueue() - except runqueue.TaskFailure, fnids: - for fnid in fnids: - bb.msg.error(bb.msg.domain.Build, "'%s' failed" % taskdata.fn_index[fnid]) - failures = failures + 1 - retval = False - if not retval: - self.command.finishAsyncCommand() - bb.event.fire(bb.event.BuildCompleted(buildname, targets, failures), self.configuration.event_data) - return None - return 0.5 - - self.buildSetVars() - - buildname = bb.data.getVar("BUILDNAME", self.configuration.data) - bb.event.fire(bb.event.BuildStarted(buildname, targets), self.configuration.event_data) - - localdata = data.createCopy(self.configuration.data) - bb.data.update_data(localdata) - bb.data.expandKeys(localdata) - - taskdata = bb.taskdata.TaskData(self.configuration.abort) - - runlist = [] - for k in targets: - taskdata.add_provider(localdata, self.status, k) - runlist.append([k, "do_%s" % task]) - taskdata.add_unresolved(localdata, self.status) - - rq = bb.runqueue.RunQueue(self, self.configuration.data, self.status, taskdata, runlist) - - self.server.register_idle_function(buildTargetsIdle, rq) - - def updateCache(self): - - if self.cookerState == cookerParsed: - return - - if self.cookerState != cookerParsing: - - self.parseConfiguration () - - # Import Psyco if available and not disabled - import platform - if platform.machine() in ['i386', 'i486', 'i586', 'i686']: - if not self.configuration.disable_psyco: - try: - import psyco - except ImportError: - bb.msg.note(1, bb.msg.domain.Collection, "Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.") - else: - psyco.bind( CookerParser.parse_next ) - else: - bb.msg.note(1, bb.msg.domain.Collection, "You have disabled Psyco. This decreases performance.") - - self.status = bb.cache.CacheData() - - ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or "" - self.status.ignored_dependencies = set(ignore.split()) - - for dep in self.configuration.extra_assume_provided: - self.status.ignored_dependencies.add(dep) - - self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) ) - - bb.msg.debug(1, bb.msg.domain.Collection, "collecting .bb files") - (filelist, masked) = self.collect_bbfiles() - bb.data.renameVar("__depends", "__base_depends", self.configuration.data) - - self.parser = CookerParser(self, filelist, masked) - self.cookerState = cookerParsing - - if not self.parser.parse_next(): - bb.msg.debug(1, bb.msg.domain.Collection, "parsing complete") - self.buildDepgraph() - self.cookerState = cookerParsed - return None - - return True - - def checkPackages(self, pkgs_to_build): - - if len(pkgs_to_build) == 0: - raise NothingToBuild - - if 'world' in pkgs_to_build: - self.buildWorldTargetList() - pkgs_to_build.remove('world') - for t in self.status.world_target: - pkgs_to_build.append(t) - - return pkgs_to_build - - def get_bbfiles( self, path = os.getcwd() ): - """Get list of default .bb files by reading out the current directory""" - contents = os.listdir(path) - bbfiles = [] - for f in contents: - (root, ext) = os.path.splitext(f) - if ext == ".bb": - bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f))) - return bbfiles - - def find_bbfiles( self, path ): - """Find all the .bb files in a directory""" - from os.path import join - - found = [] - for dir, dirs, files in os.walk(path): - for ignored in ('SCCS', 'CVS', '.svn'): - if ignored in dirs: - dirs.remove(ignored) - found += [join(dir,f) for f in files if f.endswith('.bb')] - - return found - - def collect_bbfiles( self ): - """Collect all available .bb build files""" - parsed, cached, skipped, masked = 0, 0, 0, 0 - self.bb_cache = bb.cache.init(self) - - files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split() - data.setVar("BBFILES", " ".join(files), self.configuration.data) - - if not len(files): - files = self.get_bbfiles() - - if not len(files): - bb.msg.error(bb.msg.domain.Collection, "no files to build.") - - newfiles = [] - for f in files: - if os.path.isdir(f): - dirfiles = self.find_bbfiles(f) - if dirfiles: - newfiles += dirfiles - continue - else: - globbed = glob.glob(f) - if not globbed and os.path.exists(f): - globbed = [f] - newfiles += globbed - - bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) - - if not bbmask: - return (newfiles, 0) - - try: - bbmask_compiled = re.compile(bbmask) - except sre_constants.error: - bb.msg.fatal(bb.msg.domain.Collection, "BBMASK is not a valid regular expression.") - - finalfiles = [] - for f in newfiles: - if bbmask_compiled.search(f): - bb.msg.debug(1, bb.msg.domain.Collection, "skipping masked file %s" % f) - masked += 1 - continue - finalfiles.append(f) - - return (finalfiles, masked) - - def serve(self): - - # Empty the environment. The environment will be populated as - # necessary from the data store. - bb.utils.empty_environment() - - if self.configuration.profile: - try: - import cProfile as profile - except: - import profile - - profile.runctx("self.server.serve_forever()", globals(), locals(), "profile.log") - - # Redirect stdout to capture profile information - pout = open('profile.log.processed', 'w') - so = sys.stdout.fileno() - os.dup2(pout.fileno(), so) - - import pstats - p = pstats.Stats('profile.log') - p.sort_stats('time') - p.print_stats() - p.print_callers() - p.sort_stats('cumulative') - p.print_stats() - - os.dup2(so, pout.fileno()) - pout.flush() - pout.close() - else: - self.server.serve_forever() - - bb.event.fire(CookerExit(), self.configuration.event_data) - -class CookerExit(bb.event.Event): - """ - Notify clients of the Cooker shutdown - """ - - def __init__(self): - bb.event.Event.__init__(self) - -class CookerParser: - def __init__(self, cooker, filelist, masked): - # Internal data - self.filelist = filelist - self.cooker = cooker - - # Accounting statistics - self.parsed = 0 - self.cached = 0 - self.error = 0 - self.masked = masked - self.total = len(filelist) - - self.skipped = 0 - self.virtuals = 0 - - # Pointer to the next file to parse - self.pointer = 0 - - def parse_next(self): - if self.pointer < len(self.filelist): - f = self.filelist[self.pointer] - cooker = self.cooker - - try: - fromCache, skipped, virtuals = cooker.bb_cache.loadData(f, cooker.configuration.data, cooker.status) - if fromCache: - self.cached += 1 - else: - self.parsed += 1 - - self.skipped += skipped - self.virtuals += virtuals - - except IOError, e: - self.error += 1 - cooker.bb_cache.remove(f) - bb.msg.error(bb.msg.domain.Collection, "opening %s: %s" % (f, e)) - pass - except KeyboardInterrupt: - cooker.bb_cache.remove(f) - cooker.bb_cache.sync() - raise - except Exception, e: - self.error += 1 - cooker.bb_cache.remove(f) - bb.msg.error(bb.msg.domain.Collection, "%s while parsing %s" % (e, f)) - except: - cooker.bb_cache.remove(f) - raise - finally: - bb.event.fire(bb.event.ParseProgress(self.cached, self.parsed, self.skipped, self.masked, self.virtuals, self.error, self.total), cooker.configuration.event_data) - - self.pointer += 1 - - if self.pointer >= self.total: - cooker.bb_cache.sync() - if self.error > 0: - raise ParsingErrorsFound - return False - return True - diff --git a/bitbake-dev/lib/bb/daemonize.py b/bitbake-dev/lib/bb/daemonize.py deleted file mode 100644 index 1a8bb379f4..0000000000 --- a/bitbake-dev/lib/bb/daemonize.py +++ /dev/null @@ -1,191 +0,0 @@ -"""
-Python Deamonizing helper
-
-Configurable daemon behaviors:
-
- 1.) The current working directory set to the "/" directory.
- 2.) The current file creation mode mask set to 0.
- 3.) Close all open files (1024).
- 4.) Redirect standard I/O streams to "/dev/null".
-
-A failed call to fork() now raises an exception.
-
-References:
- 1) Advanced Programming in the Unix Environment: W. Richard Stevens
- 2) Unix Programming Frequently Asked Questions:
- http://www.erlenstar.demon.co.uk/unix/faq_toc.html
-
-Modified to allow a function to be daemonized and return for
-bitbake use by Richard Purdie
-"""
-
-__author__ = "Chad J. Schroeder"
-__copyright__ = "Copyright (C) 2005 Chad J. Schroeder"
-__version__ = "0.2"
-
-# Standard Python modules.
-import os # Miscellaneous OS interfaces.
-import sys # System-specific parameters and functions.
-
-# Default daemon parameters.
-# File mode creation mask of the daemon.
-# For BitBake's children, we do want to inherit the parent umask.
-UMASK = None
-
-# Default maximum for the number of available file descriptors.
-MAXFD = 1024
-
-# The standard I/O file descriptors are redirected to /dev/null by default.
-if (hasattr(os, "devnull")):
- REDIRECT_TO = os.devnull
-else:
- REDIRECT_TO = "/dev/null"
-
-def createDaemon(function, logfile):
- """
- Detach a process from the controlling terminal and run it in the
- background as a daemon, returning control to the caller.
- """
-
- try:
- # Fork a child process so the parent can exit. This returns control to
- # the command-line or shell. It also guarantees that the child will not
- # be a process group leader, since the child receives a new process ID
- # and inherits the parent's process group ID. This step is required
- # to insure that the next call to os.setsid is successful.
- pid = os.fork()
- except OSError, e:
- raise Exception, "%s [%d]" % (e.strerror, e.errno)
-
- if (pid == 0): # The first child.
- # To become the session leader of this new session and the process group
- # leader of the new process group, we call os.setsid(). The process is
- # also guaranteed not to have a controlling terminal.
- os.setsid()
-
- # Is ignoring SIGHUP necessary?
- #
- # It's often suggested that the SIGHUP signal should be ignored before
- # the second fork to avoid premature termination of the process. The
- # reason is that when the first child terminates, all processes, e.g.
- # the second child, in the orphaned group will be sent a SIGHUP.
- #
- # "However, as part of the session management system, there are exactly
- # two cases where SIGHUP is sent on the death of a process:
- #
- # 1) When the process that dies is the session leader of a session that
- # is attached to a terminal device, SIGHUP is sent to all processes
- # in the foreground process group of that terminal device.
- # 2) When the death of a process causes a process group to become
- # orphaned, and one or more processes in the orphaned group are
- # stopped, then SIGHUP and SIGCONT are sent to all members of the
- # orphaned group." [2]
- #
- # The first case can be ignored since the child is guaranteed not to have
- # a controlling terminal. The second case isn't so easy to dismiss.
- # The process group is orphaned when the first child terminates and
- # POSIX.1 requires that every STOPPED process in an orphaned process
- # group be sent a SIGHUP signal followed by a SIGCONT signal. Since the
- # second child is not STOPPED though, we can safely forego ignoring the
- # SIGHUP signal. In any case, there are no ill-effects if it is ignored.
- #
- # import signal # Set handlers for asynchronous events.
- # signal.signal(signal.SIGHUP, signal.SIG_IGN)
-
- try:
- # Fork a second child and exit immediately to prevent zombies. This
- # causes the second child process to be orphaned, making the init
- # process responsible for its cleanup. And, since the first child is
- # a session leader without a controlling terminal, it's possible for
- # it to acquire one by opening a terminal in the future (System V-
- # based systems). This second fork guarantees that the child is no
- # longer a session leader, preventing the daemon from ever acquiring
- # a controlling terminal.
- pid = os.fork() # Fork a second child.
- except OSError, e:
- raise Exception, "%s [%d]" % (e.strerror, e.errno)
-
- if (pid == 0): # The second child.
- # We probably don't want the file mode creation mask inherited from
- # the parent, so we give the child complete control over permissions.
- if UMASK is not None:
- os.umask(UMASK)
- else:
- # Parent (the first child) of the second child.
- os._exit(0)
- else:
- # exit() or _exit()?
- # _exit is like exit(), but it doesn't call any functions registered
- # with atexit (and on_exit) or any registered signal handlers. It also
- # closes any open file descriptors. Using exit() may cause all stdio
- # streams to be flushed twice and any temporary files may be unexpectedly
- # removed. It's therefore recommended that child branches of a fork()
- # and the parent branch(es) of a daemon use _exit().
- return
-
- # Close all open file descriptors. This prevents the child from keeping
- # open any file descriptors inherited from the parent. There is a variety
- # of methods to accomplish this task. Three are listed below.
- #
- # Try the system configuration variable, SC_OPEN_MAX, to obtain the maximum
- # number of open file descriptors to close. If it doesn't exists, use
- # the default value (configurable).
- #
- # try:
- # maxfd = os.sysconf("SC_OPEN_MAX")
- # except (AttributeError, ValueError):
- # maxfd = MAXFD
- #
- # OR
- #
- # if (os.sysconf_names.has_key("SC_OPEN_MAX")):
- # maxfd = os.sysconf("SC_OPEN_MAX")
- # else:
- # maxfd = MAXFD
- #
- # OR
- #
- # Use the getrlimit method to retrieve the maximum file descriptor number
- # that can be opened by this process. If there is not limit on the
- # resource, use the default value.
- #
- import resource # Resource usage information.
- maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
- if (maxfd == resource.RLIM_INFINITY):
- maxfd = MAXFD
-
- # Iterate through and close all file descriptors.
-# for fd in range(0, maxfd):
-# try:
-# os.close(fd)
-# except OSError: # ERROR, fd wasn't open to begin with (ignored)
-# pass
-
- # Redirect the standard I/O file descriptors to the specified file. Since
- # the daemon has no controlling terminal, most daemons redirect stdin,
- # stdout, and stderr to /dev/null. This is done to prevent side-effects
- # from reads and writes to the standard I/O file descriptors.
-
- # This call to open is guaranteed to return the lowest file descriptor,
- # which will be 0 (stdin), since it was closed above.
-# os.open(REDIRECT_TO, os.O_RDWR) # standard input (0)
-
- # Duplicate standard input to standard output and standard error.
-# os.dup2(0, 1) # standard output (1)
-# os.dup2(0, 2) # standard error (2)
-
-
- si = file('/dev/null', 'r')
- so = file(logfile, 'w')
- se = so
-
-
- # Replace those fds with our own
- os.dup2(si.fileno(), sys.stdin.fileno())
- os.dup2(so.fileno(), sys.stdout.fileno())
- os.dup2(se.fileno(), sys.stderr.fileno())
-
- function()
-
- os._exit(0)
-
diff --git a/bitbake-dev/lib/bb/data.py b/bitbake-dev/lib/bb/data.py deleted file mode 100644 index d3058b9a1d..0000000000 --- a/bitbake-dev/lib/bb/data.py +++ /dev/null @@ -1,562 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -""" -BitBake 'Data' implementations - -Functions for interacting with the data structure used by the -BitBake build tools. - -The expandData and update_data are the most expensive -operations. At night the cookie monster came by and -suggested 'give me cookies on setting the variables and -things will work out'. Taking this suggestion into account -applying the skills from the not yet passed 'Entwurf und -Analyse von Algorithmen' lecture and the cookie -monster seems to be right. We will track setVar more carefully -to have faster update_data and expandKeys operations. - -This is a treade-off between speed and memory again but -the speed is more critical here. -""" - -# Copyright (C) 2003, 2004 Chris Larson -# Copyright (C) 2005 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 version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -#Based on functions from the base bb module, Copyright 2003 Holger Schurig - -import sys, os, re, types -if sys.argv[0][-5:] == "pydoc": - path = os.path.dirname(os.path.dirname(sys.argv[1])) -else: - path = os.path.dirname(os.path.dirname(sys.argv[0])) -sys.path.insert(0,path) - -from bb import data_smart -import bb - -_dict_type = data_smart.DataSmart - -def init(): - return _dict_type() - -def init_db(parent = None): - if parent: - return parent.createCopy() - else: - return _dict_type() - -def createCopy(source): - """Link the source set to the destination - If one does not find the value in the destination set, - search will go on to the source set to get the value. - Value from source are copy-on-write. i.e. any try to - modify one of them will end up putting the modified value - in the destination set. - """ - return source.createCopy() - -def initVar(var, d): - """Non-destructive var init for data structure""" - d.initVar(var) - - -def setVar(var, value, d): - """Set a variable to a given value - - Example: - >>> d = init() - >>> setVar('TEST', 'testcontents', d) - >>> print getVar('TEST', d) - testcontents - """ - d.setVar(var,value) - - -def getVar(var, d, exp = 0): - """Gets the value of a variable - - Example: - >>> d = init() - >>> setVar('TEST', 'testcontents', d) - >>> print getVar('TEST', d) - testcontents - """ - return d.getVar(var,exp) - - -def renameVar(key, newkey, d): - """Renames a variable from key to newkey - - Example: - >>> d = init() - >>> setVar('TEST', 'testcontents', d) - >>> renameVar('TEST', 'TEST2', d) - >>> print getVar('TEST2', d) - testcontents - """ - d.renameVar(key, newkey) - -def delVar(var, d): - """Removes a variable from the data set - - Example: - >>> d = init() - >>> setVar('TEST', 'testcontents', d) - >>> print getVar('TEST', d) - testcontents - >>> delVar('TEST', d) - >>> print getVar('TEST', d) - None - """ - d.delVar(var) - -def setVarFlag(var, flag, flagvalue, d): - """Set a flag for a given variable to a given value - - Example: - >>> d = init() - >>> setVarFlag('TEST', 'python', 1, d) - >>> print getVarFlag('TEST', 'python', d) - 1 - """ - d.setVarFlag(var,flag,flagvalue) - -def getVarFlag(var, flag, d): - """Gets given flag from given var - - Example: - >>> d = init() - >>> setVarFlag('TEST', 'python', 1, d) - >>> print getVarFlag('TEST', 'python', d) - 1 - """ - return d.getVarFlag(var,flag) - -def delVarFlag(var, flag, d): - """Removes a given flag from the variable's flags - - Example: - >>> d = init() - >>> setVarFlag('TEST', 'testflag', 1, d) - >>> print getVarFlag('TEST', 'testflag', d) - 1 - >>> delVarFlag('TEST', 'testflag', d) - >>> print getVarFlag('TEST', 'testflag', d) - None - - """ - d.delVarFlag(var,flag) - -def setVarFlags(var, flags, d): - """Set the flags for a given variable - - Note: - setVarFlags will not clear previous - flags. Think of this method as - addVarFlags - - Example: - >>> d = init() - >>> myflags = {} - >>> myflags['test'] = 'blah' - >>> setVarFlags('TEST', myflags, d) - >>> print getVarFlag('TEST', 'test', d) - blah - """ - d.setVarFlags(var,flags) - -def getVarFlags(var, d): - """Gets a variable's flags - - Example: - >>> d = init() - >>> setVarFlag('TEST', 'test', 'blah', d) - >>> print getVarFlags('TEST', d)['test'] - blah - """ - return d.getVarFlags(var) - -def delVarFlags(var, d): - """Removes a variable's flags - - Example: - >>> data = init() - >>> setVarFlag('TEST', 'testflag', 1, data) - >>> print getVarFlag('TEST', 'testflag', data) - 1 - >>> delVarFlags('TEST', data) - >>> print getVarFlags('TEST', data) - None - - """ - d.delVarFlags(var) - -def keys(d): - """Return a list of keys in d - - Example: - >>> d = init() - >>> setVar('TEST', 1, d) - >>> setVar('MOO' , 2, d) - >>> setVarFlag('TEST', 'test', 1, d) - >>> keys(d) - ['TEST', 'MOO'] - """ - return d.keys() - -def getData(d): - """Returns the data object used""" - return d - -def setData(newData, d): - """Sets the data object to the supplied value""" - d = newData - - -## -## Cookie Monsters' query functions -## -def _get_override_vars(d, override): - """ - Internal!!! - - Get the Names of Variables that have a specific - override. This function returns a iterable - Set or an empty list - """ - return [] - -def _get_var_flags_triple(d): - """ - Internal!!! - - """ - return [] - -__expand_var_regexp__ = re.compile(r"\${[^{}]+}") -__expand_python_regexp__ = re.compile(r"\${@.+?}") - -def expand(s, d, varname = None): - """Variable expansion using the data store. - - Example: - Standard expansion: - >>> d = init() - >>> setVar('A', 'sshd', d) - >>> print expand('/usr/bin/${A}', d) - /usr/bin/sshd - - Python expansion: - >>> d = init() - >>> print expand('result: ${@37 * 72}', d) - result: 2664 - - Shell expansion: - >>> d = init() - >>> print expand('${TARGET_MOO}', d) - ${TARGET_MOO} - >>> setVar('TARGET_MOO', 'yupp', d) - >>> print expand('${TARGET_MOO}',d) - yupp - >>> setVar('SRC_URI', 'http://somebug.${TARGET_MOO}', d) - >>> delVar('TARGET_MOO', d) - >>> print expand('${SRC_URI}', d) - http://somebug.${TARGET_MOO} - """ - return d.expand(s, varname) - -def expandKeys(alterdata, readdata = None): - if readdata == None: - readdata = alterdata - - todolist = {} - for key in keys(alterdata): - if not '${' in key: - continue - - ekey = expand(key, readdata) - if key == ekey: - continue - todolist[key] = ekey - - # These two for loops are split for performance to maximise the - # usefulness of the expand cache - - for key in todolist: - ekey = todolist[key] - renameVar(key, ekey, alterdata) - -def expandData(alterdata, readdata = None): - """For each variable in alterdata, expand it, and update the var contents. - Replacements use data from readdata. - - Example: - >>> a=init() - >>> b=init() - >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a) - >>> setVar("DL_DIR", "/path/to/whatever", b) - >>> expandData(a, b) - >>> print getVar("dlmsg", a) - dl_dir is /path/to/whatever - """ - if readdata == None: - readdata = alterdata - - for key in keys(alterdata): - val = getVar(key, alterdata) - if type(val) is not types.StringType: - continue - expanded = expand(val, readdata) -# print "key is %s, val is %s, expanded is %s" % (key, val, expanded) - if val != expanded: - setVar(key, expanded, alterdata) - -def inheritFromOS(d): - """Inherit variables from the environment.""" - for s in os.environ.keys(): - try: - setVar(s, os.environ[s], d) - setVarFlag(s, "export", True, d) - except TypeError: - pass - -def emit_var(var, o=sys.__stdout__, d = init(), all=False): - """Emit a variable to be sourced by a shell.""" - if getVarFlag(var, "python", d): - return 0 - - export = getVarFlag(var, "export", d) - unexport = getVarFlag(var, "unexport", d) - func = getVarFlag(var, "func", d) - if not all and not export and not unexport and not func: - return 0 - - try: - if all: - oval = getVar(var, d, 0) - val = getVar(var, d, 1) - except KeyboardInterrupt: - raise - except: - excname = str(sys.exc_info()[0]) - if excname == "bb.build.FuncFailed": - raise - o.write('# expansion of %s threw %s\n' % (var, excname)) - return 0 - - if all: - o.write('# %s=%s\n' % (var, oval)) - - if type(val) is not types.StringType: - return 0 - - if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all: - return 0 - - varExpanded = expand(var, d) - - if unexport: - o.write('unset %s\n' % varExpanded) - return 1 - - val.rstrip() - if not val: - return 0 - - if func: - # NOTE: should probably check for unbalanced {} within the var - o.write("%s() {\n%s\n}\n" % (varExpanded, val)) - return 1 - - if export: - o.write('export ') - - # 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' % (varExpanded, alter)) - return 1 - - -def emit_env(o=sys.__stdout__, d = init(), all=False): - """Emits all items in the data store in a format such that it can be sourced by a shell.""" - - env = keys(d) - - for e in env: - if getVarFlag(e, "func", d): - continue - emit_var(e, o, d, all) and o.write('\n') - - for e in env: - if not getVarFlag(e, "func", d): - continue - emit_var(e, o, d) and o.write('\n') - -def update_data(d): - """Modifies the environment vars according to local overrides and commands. - Examples: - Appending to a variable: - >>> d = init() - >>> setVar('TEST', 'this is a', d) - >>> setVar('TEST_append', ' test', d) - >>> setVar('TEST_append', ' of the emergency broadcast system.', d) - >>> update_data(d) - >>> print getVar('TEST', d) - this is a test of the emergency broadcast system. - - Prepending to a variable: - >>> setVar('TEST', 'virtual/libc', d) - >>> setVar('TEST_prepend', 'virtual/tmake ', d) - >>> setVar('TEST_prepend', 'virtual/patcher ', d) - >>> update_data(d) - >>> print getVar('TEST', d) - virtual/patcher virtual/tmake virtual/libc - - Overrides: - >>> setVar('TEST_arm', 'target', d) - >>> setVar('TEST_ramses', 'machine', d) - >>> setVar('TEST_local', 'local', d) - >>> setVar('OVERRIDES', 'arm', d) - - >>> setVar('TEST', 'original', d) - >>> update_data(d) - >>> print getVar('TEST', d) - target - - >>> setVar('OVERRIDES', 'arm:ramses:local', d) - >>> setVar('TEST', 'original', 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 - - """ - bb.msg.debug(2, bb.msg.domain.Data, "update_data()") - - # now ask the cookie monster for help - #print "Cookie Monster" - #print "Append/Prepend %s" % d._special_values - #print "Overrides %s" % d._seen_overrides - - overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or [] - - # - # Well let us see what breaks here. We used to iterate - # over each variable and apply the override and then - # do the line expanding. - # If we have bad luck - which we will have - the keys - # where in some order that is so important for this - # method which we don't have anymore. - # Anyway we will fix that and write test cases this - # time. - - # - # First we apply all overrides - # Then we will handle _append and _prepend - # - - for o in overrides: - # calculate '_'+override - l = len(o)+1 - - # see if one should even try - if not d._seen_overrides.has_key(o): - continue - - vars = d._seen_overrides[o] - for var in vars: - name = var[:-l] - try: - d[name] = d[var] - except: - bb.msg.note(1, bb.msg.domain.Data, "Untracked delVar") - - # now on to the appends and prepends - 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 []: - # maybe the OVERRIDE was not yet added so keep the append - if (o and o in overrides) or not o: - delVarFlag(append, '_append', d) - if o and not o in overrides: - continue - - sval = getVar(append,d) or "" - sval+=a - setVar(append, sval, d) - - - if d._special_values.has_key('_prepend'): - prepends = d._special_values['_prepend'] or [] - - for prepend in prepends: - for (a, o) in getVarFlag(prepend, '_prepend', d) or []: - # maybe the OVERRIDE was not yet added so keep the prepend - if (o and o in overrides) or not o: - delVarFlag(prepend, '_prepend', d) - if o and not o in overrides: - continue - - sval = a + (getVar(prepend,d) or "") - setVar(prepend, sval, d) - - -def inherits_class(klass, d): - val = getVar('__inherit_cache', d) or [] - if os.path.join('classes', '%s.bbclass' % klass) in val: - return True - return False - -def _test(): - """Start a doctest run on this module""" - import doctest - import bb - from bb import data - bb.msg.set_debug_level(0) - doctest.testmod(data) - -if __name__ == "__main__": - _test() diff --git a/bitbake-dev/lib/bb/data_smart.py b/bitbake-dev/lib/bb/data_smart.py deleted file mode 100644 index 988d5c3578..0000000000 --- a/bitbake-dev/lib/bb/data_smart.py +++ /dev/null @@ -1,289 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -""" -BitBake Smart Dictionary Implementation - -Functions for interacting with the data structure used by the -BitBake build tools. - -""" - -# Copyright (C) 2003, 2004 Chris Larson -# Copyright (C) 2004, 2005 Seb Frankengul -# Copyright (C) 2005, 2006 Holger Hans Peter Freyther -# Copyright (C) 2005 Uli Luckas -# Copyright (C) 2005 ROAD GmbH -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# Based on functions from the base bb module, Copyright 2003 Holger Schurig - -import copy, os, re, sys, time, types -import bb -from bb import utils, methodpool -from COW import COWDictBase -from new import classobj - - -__setvar_keyword__ = ["_append","_prepend"] -__setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend)(_(?P<add>.*))?') -__expand_var_regexp__ = re.compile(r"\${[^{}]+}") -__expand_python_regexp__ = re.compile(r"\${@.+?}") - - -class DataSmart: - def __init__(self, special = COWDictBase.copy(), seen = COWDictBase.copy() ): - self.dict = {} - - # cookie monster tribute - self._special_values = special - self._seen_overrides = seen - - self.expand_cache = {} - - def expand(self,s, varname): - def var_sub(match): - key = match.group()[2:-1] - if varname and key: - if varname == key: - raise Exception("variable %s references itself!" % varname) - var = self.getVar(key, 1) - if var is not None: - return var - else: - return match.group() - - def python_sub(match): - import bb - code = match.group()[3:-1] - locals()['d'] = self - s = eval(code) - if type(s) == types.IntType: s = str(s) - return s - - 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: - s = __expand_var_regexp__.sub(var_sub, s) - s = __expand_python_regexp__.sub(python_sub, s) - if s == olds: break - if type(s) is not types.StringType: # sanity check - bb.msg.error(bb.msg.domain.Data, 'expansion of %s returned non-string %s' % (olds, s)) - except KeyboardInterrupt: - raise - except: - 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] = {} - - def _findVar(self,var): - _dest = self.dict - - while (_dest and var not in _dest): - if not "_data" in _dest: - _dest = None - break - _dest = _dest["_data"] - - if _dest and var in _dest: - return _dest[var] - return None - - def _makeShadowCopy(self, var): - if var in self.dict: - return - - local_var = self._findVar(var) - - if local_var: - self.dict[var] = copy.copy(local_var) - else: - 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') - keyword = match.group("keyword") - override = match.group('add') - l = self.getVarFlag(base, keyword) or [] - 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 ) - except: - self._special_values[keyword] = set() - self._special_values[keyword].add( base ) - - return - - if not var in self.dict: - self._makeShadowCopy(var) - - # more cookies for the cookie monster - if '_' in var: - override = var[var.rfind('_')+1:] - if not self._seen_overrides.has_key(override): - self._seen_overrides[override] = set() - self._seen_overrides[override].add( var ) - - # setting var - self.dict[var]["content"] = value - - def getVar(self,var,exp): - value = self.getVarFlag(var,"content") - - if exp and value: - return self.expand(value,var) - return value - - def renameVar(self, key, newkey): - """ - Rename the variable key to newkey - """ - val = self.getVar(key, 0) - if val is not None: - self.setVar(newkey, val) - - for i in ('_append', '_prepend'): - src = self.getVarFlag(key, i) - if src is None: - continue - - dest = self.getVarFlag(newkey, i) or [] - dest.extend(src) - self.setVarFlag(newkey, i, dest) - - if self._special_values.has_key(i) and key in self._special_values[i]: - self._special_values[i].remove(key) - self._special_values[i].add(newkey) - - self.delVar(key) - - def delVar(self,var): - self.expand_cache = {} - self.dict[var] = {} - - def setVarFlag(self,var,flag,flagvalue): - if not var in self.dict: - self._makeShadowCopy(var) - self.dict[var][flag] = flagvalue - - def getVarFlag(self,var,flag): - local_var = self._findVar(var) - if local_var: - if flag in local_var: - return copy.copy(local_var[flag]) - return None - - def delVarFlag(self,var,flag): - local_var = self._findVar(var) - if not local_var: - return - if not var in self.dict: - self._makeShadowCopy(var) - - if var in self.dict and flag in self.dict[var]: - del self.dict[var][flag] - - def setVarFlags(self,var,flags): - if not var in self.dict: - self._makeShadowCopy(var) - - for i in flags.keys(): - if i == "content": - continue - self.dict[var][i] = flags[i] - - def getVarFlags(self,var): - local_var = self._findVar(var) - flags = {} - - if local_var: - for i in local_var.keys(): - if i == "content": - continue - flags[i] = local_var[i] - - if len(flags) == 0: - return None - return flags - - - def delVarFlags(self,var): - if not var in self.dict: - self._makeShadowCopy(var) - - if var in self.dict: - content = None - - # try to save the content - if "content" in self.dict[var]: - content = self.dict[var]["content"] - self.dict[var] = {} - self.dict[var]["content"] = content - else: - del self.dict[var] - - - def createCopy(self): - """ - Create a copy of self by setting _data to self - """ - # we really want this to be a DataSmart... - data = DataSmart(seen=self._seen_overrides.copy(), special=self._special_values.copy()) - data.dict["_data"] = self.dict - - return data - - # Dictionary Methods - def keys(self): - def _keys(d, mykey): - if "_data" in d: - _keys(d["_data"],mykey) - - for key in d.keys(): - if key != "_data": - mykey[key] = None - keytab = {} - _keys(self.dict,keytab) - return keytab.keys() - - def __getitem__(self,item): - #print "Warning deprecated" - return self.getVar(item, False) - - def __setitem__(self,var,data): - #print "Warning deprecated" - self.setVar(var,data) - - diff --git a/bitbake-dev/lib/bb/event.py b/bitbake-dev/lib/bb/event.py deleted file mode 100644 index 7251d78715..0000000000 --- a/bitbake-dev/lib/bb/event.py +++ /dev/null @@ -1,275 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -""" -BitBake 'Event' implementation - -Classes and functions for manipulating 'events' in 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 version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import os, re -import bb.utils -import pickle - -# This is the pid for which we should generate the event. This is set when -# the runqueue forks off. -worker_pid = 0 -worker_pipe = None - -class Event: - """Base class for events""" - - def __init__(self): - self.pid = worker_pid - -NotHandled = 0 -Handled = 1 - -Registered = 10 -AlreadyRegistered = 14 - -# Internal -_handlers = {} -_ui_handlers = {} -_ui_handler_seq = 0 - -def fire(event, d): - """Fire off an Event""" - - if worker_pid != 0: - worker_fire(event, d) - return - - for handler in _handlers: - h = _handlers[handler] - event.data = d - if type(h).__name__ == "code": - exec(h) - tmpHandler(event) - else: - h(event) - del event.data - - errors = [] - for h in _ui_handlers: - #print "Sending event %s" % event - try: - # We use pickle here since it better handles object instances - # which xmlrpc's marshaller does not. Events *must* be serializable - # by pickle. - _ui_handlers[h].event.send((pickle.dumps(event))) - except: - errors.append(h) - for h in errors: - del _ui_handlers[h] - -def worker_fire(event, d): - data = "<event>" + pickle.dumps(event) + "</event>" - if os.write(worker_pipe, data) != len (data): - print "Error sending event to server (short write)" - -def fire_from_worker(event, d): - if not event.startswith("<event>") or not event.endswith("</event>"): - print "Error, not an event" - return - event = pickle.loads(event[7:-8]) - bb.event.fire(event, d) - -def register(name, handler): - """Register an Event handler""" - - # already registered - if name in _handlers: - return AlreadyRegistered - - if handler is not None: - # handle string containing python code - if type(handler).__name__ == "str": - tmp = "def tmpHandler(e):\n%s" % handler - comp = bb.utils.better_compile(tmp, "tmpHandler(e)", "bb.event._registerCode") - _handlers[name] = comp - else: - _handlers[name] = handler - - return Registered - -def remove(name, handler): - """Remove an Event handler""" - _handlers.pop(name) - -def register_UIHhandler(handler): - bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1 - _ui_handlers[_ui_handler_seq] = handler - return _ui_handler_seq - -def unregister_UIHhandler(handlerNum): - if handlerNum in _ui_handlers: - del _ui_handlers[handlerNum] - return - -def getName(e): - """Returns the name of a class or class instance""" - if getattr(e, "__name__", None) == None: - return e.__class__.__name__ - else: - return e.__name__ - -class ConfigParsed(Event): - """Configuration Parsing Complete""" - -class RecipeParsed(Event): - """ Recipe Parsing Complete """ - - def __init__(self, fn): - self.fn = fn - Event.__init__(self) - -class StampUpdate(Event): - """Trigger for any adjustment of the stamp files to happen""" - - def __init__(self, targets, stampfns): - self._targets = targets - self._stampfns = stampfns - Event.__init__(self) - - def getStampPrefix(self): - return self._stampfns - - def getTargets(self): - return self._targets - - stampPrefix = property(getStampPrefix) - targets = property(getTargets) - -class BuildBase(Event): - """Base class for bbmake run events""" - - def __init__(self, n, p, failures = 0): - self._name = n - self._pkgs = p - Event.__init__(self) - self._failures = failures - - def getPkgs(self): - return self._pkgs - - def setPkgs(self, pkgs): - self._pkgs = pkgs - - def getName(self): - return self._name - - def setName(self, name): - self._name = name - - def getCfg(self): - return self.data - - def setCfg(self, cfg): - self.data = cfg - - def getFailures(self): - """ - Return the number of failed packages - """ - return self._failures - - pkgs = property(getPkgs, setPkgs, None, "pkgs property") - name = property(getName, setName, None, "name property") - cfg = property(getCfg, setCfg, None, "cfg property") - - - - - -class BuildStarted(BuildBase): - """bbmake build run started""" - - -class BuildCompleted(BuildBase): - """bbmake build run completed""" - - - - -class NoProvider(Event): - """No Provider for an Event""" - - def __init__(self, item, runtime=False): - Event.__init__(self) - self._item = item - self._runtime = runtime - - def getItem(self): - return self._item - - def isRuntime(self): - return self._runtime - -class MultipleProviders(Event): - """Multiple Providers""" - - def __init__(self, item, candidates, runtime = False): - Event.__init__(self) - self._item = item - self._candidates = candidates - self._is_runtime = runtime - - def isRuntime(self): - """ - Is this a runtime issue? - """ - return self._is_runtime - - def getItem(self): - """ - The name for the to be build item - """ - return self._item - - def getCandidates(self): - """ - Get the possible Candidates for a PROVIDER. - """ - return self._candidates - -class ParseProgress(Event): - """ - Parsing Progress Event - """ - - def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total): - Event.__init__(self) - self.cached = cached - self.parsed = parsed - self.skipped = skipped - self.virtuals = virtuals - self.masked = masked - self.errors = errors - self.sofar = cached + parsed - self.total = total - -class DepTreeGenerated(Event): - """ - Event when a dependency tree has been generated - """ - - def __init__(self, depgraph): - Event.__init__(self) - self._depgraph = depgraph - diff --git a/bitbake-dev/lib/bb/fetch/__init__.py b/bitbake-dev/lib/bb/fetch/__init__.py deleted file mode 100644 index ab4658bc3b..0000000000 --- a/bitbake-dev/lib/bb/fetch/__init__.py +++ /dev/null @@ -1,640 +0,0 @@ -# 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 version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Based on functions from the base bb module, Copyright 2003 Holger Schurig - -import os, re -import bb -from bb import data -from bb import persist_data - -class FetchError(Exception): - """Exception raised when a download fails""" - -class NoMethodError(Exception): - """Exception raised when there is no method to obtain a supplied url or set of urls""" - -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""" - -class InvalidSRCREV(Exception): - """Exception raised when an invalid SRCREV is encountered""" - -def uri_replace(uri, uri_find, uri_replace, d): -# 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.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)) - result_decoded = ['','','','','',{}] - for i in uri_find_decoded: - loc = uri_find_decoded.index(i) - result_decoded[loc] = uri_decoded[loc] - import types - if type(i) == types.StringType: - if (re.match(i, uri_decoded[loc])): - result_decoded[loc] = re.sub(i, uri_replace_decoded[loc], uri_decoded[loc]) - if uri_find_decoded.index(i) == 2: - if 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.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.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: no match") - return uri -# else: -# for j in i.keys(): -# FIXME: apply replacements against options - return bb.encodeurl(result_decoded) - -methods = [] -urldata_cache = {} -saved_headrevs = {} - -def fetcher_init(d): - """ - Called to initilize the fetchers once the configuration data is known - Calls before this must not hit the cache. - """ - pd = persist_data.PersistData(d) - # When to drop SCM head revisions controled by user policy - srcrev_policy = bb.data.getVar('BB_SRCREV_POLICY', d, 1) or "clear" - if srcrev_policy == "cache": - bb.msg.debug(1, bb.msg.domain.Fetcher, "Keeping SRCREV cache due to cache policy of: %s" % srcrev_policy) - elif srcrev_policy == "clear": - bb.msg.debug(1, bb.msg.domain.Fetcher, "Clearing SRCREV cache due to cache policy of: %s" % srcrev_policy) - try: - bb.fetch.saved_headrevs = pd.getKeyValues("BB_URI_HEADREVS") - except: - pass - pd.delDomain("BB_URI_HEADREVS") - else: - bb.msg.fatal(bb.msg.domain.Fetcher, "Invalid SRCREV cache policy of: %s" % srcrev_policy) - - for m in methods: - if hasattr(m, "init"): - m.init(d) - - # Make sure our domains exist - pd.addDomain("BB_URI_HEADREVS") - pd.addDomain("BB_URI_LOCALCOUNT") - -def fetcher_compare_revisons(d): - """ - Compare the revisions in the persistant cache with current values and - return true/false on whether they've changed. - """ - - pd = persist_data.PersistData(d) - data = pd.getKeyValues("BB_URI_HEADREVS") - data2 = bb.fetch.saved_headrevs - - changed = False - for key in data: - if key not in data2 or data2[key] != data[key]: - bb.msg.debug(1, bb.msg.domain.Fetcher, "%s changed" % key) - changed = True - return True - else: - bb.msg.debug(2, bb.msg.domain.Fetcher, "%s did not change" % key) - return False - -# Function call order is usually: -# 1. init -# 2. go -# 3. localpaths -# localpath can be called at any time - -def init(urls, d, setup = True): - urldata = {} - fn = bb.data.getVar('FILE', d, 1) - if fn in urldata_cache: - urldata = urldata_cache[fn] - - for url in urls: - if url not in urldata: - urldata[url] = FetchData(url, d) - - if setup: - for url in urldata: - if not urldata[url].setup: - urldata[url].setup_localpath(d) - - urldata_cache[fn] = urldata - return urldata - -def go(d, urls = None): - """ - Fetch all urls - init must have previously been called - """ - if not urls: - urls = d.getVar("SRC_URI", 1).split() - urldata = init(urls, d, True) - - for u in urls: - ud = urldata[u] - m = ud.method - if ud.localfile: - if not m.forcefetch(u, ud, d) and os.path.exists(ud.md5): - # File already present along with md5 stamp file - # Touch md5 file to show activity - try: - os.utime(ud.md5, None) - except: - # Errors aren't fatal here - pass - continue - lf = bb.utils.lockfile(ud.lockfile) - if not m.forcefetch(u, ud, d) and os.path.exists(ud.md5): - # If someone else fetched this before we got the lock, - # notice and don't try again - try: - os.utime(ud.md5, None) - except: - # Errors aren't fatal here - pass - bb.utils.unlockfile(lf) - continue - m.go(u, ud, d) - if ud.localfile: - if not m.forcefetch(u, ud, d): - Fetch.write_md5sum(u, ud, d) - bb.utils.unlockfile(lf) - - -def checkstatus(d): - """ - Check all urls exist upstream - init must have previously been called - """ - urldata = init([], d, True) - - for u in urldata: - ud = urldata[u] - m = ud.method - bb.msg.note(1, bb.msg.domain.Fetcher, "Testing URL %s" % u) - ret = m.checkstatus(u, ud, d) - if not ret: - bb.msg.fatal(bb.msg.domain.Fetcher, "URL %s doesn't work" % u) - -def localpaths(d): - """ - Return a list of the local filenames, assuming successful fetch - """ - local = [] - urldata = init([], d, True) - - for u in urldata: - ud = urldata[u] - local.append(ud.localpath) - - return local - -srcrev_internal_call = False - -def get_srcrev(d): - """ - Return the version string for the current package - (usually to be used as PV) - Most packages usually only have one SCM so we just pass on the call. - In the multi SCM case, we build a value based on SRCREV_FORMAT which must - have been set. - """ - - # - # Ugly code alert. localpath in the fetchers will try to evaluate SRCREV which - # could translate into a call to here. If it does, we need to catch this - # and provide some way so it knows get_srcrev is active instead of being - # some number etc. hence the srcrev_internal_call tracking and the magic - # "SRCREVINACTION" return value. - # - # Neater solutions welcome! - # - if bb.fetch.srcrev_internal_call: - return "SRCREVINACTION" - - scms = [] - - # Only call setup_localpath on URIs which suppports_srcrev() - urldata = init(bb.data.getVar('SRC_URI', d, 1).split(), d, False) - for u in urldata: - ud = urldata[u] - if ud.method.suppports_srcrev(): - if not ud.setup: - ud.setup_localpath(d) - scms.append(u) - - if len(scms) == 0: - bb.msg.error(bb.msg.domain.Fetcher, "SRCREV was used yet no valid SCM was found in SRC_URI") - raise ParameterError - - bb.data.setVar('__BB_DONT_CACHE','1', d) - - if len(scms) == 1: - return urldata[scms[0]].method.sortable_revision(scms[0], urldata[scms[0]], d) - - # - # Mutiple SCMs are in SRC_URI so we resort to SRCREV_FORMAT - # - format = bb.data.getVar('SRCREV_FORMAT', d, 1) - if not format: - bb.msg.error(bb.msg.domain.Fetcher, "The SRCREV_FORMAT variable must be set when multiple SCMs are used.") - raise ParameterError - - for scm in scms: - if 'name' in urldata[scm].parm: - name = urldata[scm].parm["name"] - rev = urldata[scm].method.sortable_revision(scm, urldata[scm], d) - format = format.replace(name, rev) - - return format - -def localpath(url, d, cache = True): - """ - Called from the parser with cache=False since the cache isn't ready - at this point. Also called from classed in OE e.g. patch.bbclass - """ - ud = init([url], d) - if ud[url].method: - return ud[url].localpath - return url - -def runfetchcmd(cmd, d, quiet = False): - """ - Run cmd returning the command output - Raise an error if interrupted or cmd fails - Optionally echo command output to stdout - """ - - # Need to export PATH as binary could be in metadata paths - # rather than host provided - # Also include some other variables. - # FIXME: Should really include all export varaiables? - exportvars = ['PATH', 'GIT_PROXY_COMMAND', 'GIT_PROXY_HOST', 'GIT_PROXY_PORT', 'GIT_CONFIG', 'http_proxy', 'ftp_proxy', 'SSH_AUTH_SOCK', 'SSH_AGENT_PID', 'HOME'] - - for var in exportvars: - val = data.getVar(var, d, True) - if val: - cmd = 'export ' + var + '=%s; %s' % (val, cmd) - - bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % cmd) - - # redirect stderr to stdout - stdout_handle = os.popen(cmd + " 2>&1", "r") - output = "" - - while 1: - line = stdout_handle.readline() - if not line: - break - if not quiet: - print line, - output += line - - status = stdout_handle.close() or 0 - signal = status >> 8 - exitstatus = status & 0xff - - if signal: - raise FetchError("Fetch command %s failed with signal %s, output:\n%s" % (cmd, signal, output)) - elif status != 0: - raise FetchError("Fetch command %s failed with exit code %s, output:\n%s" % (cmd, status, output)) - - return output - -class FetchData(object): - """ - A class which represents the fetcher state for a given URI. - """ - def __init__(self, url, d): - self.localfile = "" - (self.type, self.host, self.path, self.user, self.pswd, self.parm) = bb.decodeurl(data.expand(url, d)) - self.date = Fetch.getSRCDate(self, d) - self.url = url - if not self.user and "user" in self.parm: - self.user = self.parm["user"] - if not self.pswd and "pswd" in self.parm: - self.pswd = self.parm["pswd"] - self.setup = False - for m in methods: - if m.supports(url, self, d): - self.method = m - return - raise NoMethodError("Missing implementation for url %s" % url) - - def setup_localpath(self, d): - self.setup = True - if "localpath" in self.parm: - # if user sets localpath for file, use it instead. - self.localpath = self.parm["localpath"] - else: - try: - bb.fetch.srcrev_internal_call = True - self.localpath = self.method.localpath(self.url, self, d) - finally: - bb.fetch.srcrev_internal_call = False - # We have to clear data's internal caches since the cached value of SRCREV is now wrong. - # Horrible... - bb.data.delVar("ISHOULDNEVEREXIST", d) - self.md5 = self.localpath + '.md5' - self.lockfile = self.localpath + '.lock' - - -class Fetch(object): - """Base class for 'fetch'ing data""" - - def __init__(self, urls = []): - self.urls = [] - - def supports(self, url, urldata, d): - """ - Check to see if this fetch class supports a given url. - """ - return 0 - - 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 - - def setUrls(self, urls): - self.__urls = urls - - def getUrls(self): - return self.__urls - - urls = property(getUrls, setUrls, None, "Urls property") - - def forcefetch(self, url, urldata, d): - """ - Force a fetch, even if localpath exists? - """ - return False - - def suppports_srcrev(self): - """ - The fetcher supports auto source revisions (SRCREV) - """ - return False - - def go(self, url, urldata, d): - """ - Fetch urls - Assumes localpath was called first - """ - raise NoMethodError("Missing implementation for url") - - def checkstatus(self, url, urldata, d): - """ - Check the status of a URL - Assumes localpath was called first - """ - bb.msg.note(1, bb.msg.domain.Fetcher, "URL %s could not be checked for status since no method exists." % url) - return True - - def getSRCDate(urldata, d): - """ - Return the SRC Date for the component - - d the bb.data module - """ - if "srcdate" in urldata.parm: - return urldata.parm['srcdate'] - - 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("SRCDATE", d, 1) or data.getVar("CVSDATE", 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 srcrev_internal_helper(ud, d): - """ - Return: - a) a source revision if specified - b) True if auto srcrev is in action - c) False otherwise - """ - - if 'rev' in ud.parm: - return ud.parm['rev'] - - if 'tag' in ud.parm: - return ud.parm['tag'] - - rev = None - if 'name' in ud.parm: - pn = data.getVar("PN", d, 1) - rev = data.getVar("SRCREV_pn-" + pn + "_" + ud.parm['name'], d, 1) - if not rev: - rev = data.getVar("SRCREV", d, 1) - if rev == "INVALID": - raise InvalidSRCREV("Please set SRCREV to a valid value") - if not rev: - return False - if rev is "SRCREVINACTION": - return True - return rev - - srcrev_internal_helper = staticmethod(srcrev_internal_helper) - - def localcount_internal_helper(ud, d): - """ - Return: - a) a locked localcount if specified - b) None otherwise - """ - - localcount= None - if 'name' in ud.parm: - pn = data.getVar("PN", d, 1) - localcount = data.getVar("LOCALCOUNT_" + ud.parm['name'], d, 1) - if not localcount: - localcount = data.getVar("LOCALCOUNT", d, 1) - return localcount - - localcount_internal_helper = staticmethod(localcount_internal_helper) - - def try_mirror(d, tarfn): - """ - Try to use a mirrored version of the sources. We do this - to avoid massive loads on foreign cvs and svn servers. - This method will be used by the different fetcher - implementations. - - 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: - src_tarball_stash = (data.getVar('SRC_TARBALL_STASH_%s' % pn, d, True) or data.getVar('CVS_TARBALL_STASH_%s' % pn, d, True) or data.getVar('SRC_TARBALL_STASH', d, True) or data.getVar('CVS_TARBALL_STASH', d, True) or "").split() - - ld = d.createCopy() - for stash in src_tarball_stash: - url = stash + tarfn - try: - ud = FetchData(url, ld) - except bb.fetch.NoMethodError: - bb.msg.debug(1, bb.msg.domain.Fetcher, "No method for %s" % url) - continue - - ud.setup_localpath(ld) - - try: - ud.method.go(url, ud, ld) - return True - except (bb.fetch.MissingParameterError, - bb.fetch.FetchError, - bb.fetch.MD5SumError): - import sys - (type, value, traceback) = sys.exc_info() - bb.msg.debug(2, bb.msg.domain.Fetcher, "Tarball stash fetch failure: %s" % value) - return False - try_mirror = staticmethod(try_mirror) - - def verify_md5sum(ud, got_sum): - """ - Verify the md5sum we wanted with the one we got - """ - 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): - md5data = bb.utils.md5_file(ud.localpath) - # 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) - - def latest_revision(self, url, ud, d): - """ - Look in the cache for the latest revision, if not present ask the SCM. - """ - if not hasattr(self, "_latest_revision"): - raise ParameterError - - pd = persist_data.PersistData(d) - key = self.generate_revision_key(url, ud, d) - rev = pd.getValue("BB_URI_HEADREVS", key) - if rev != None: - return str(rev) - - rev = self._latest_revision(url, ud, d) - pd.setValue("BB_URI_HEADREVS", key, rev) - return rev - - def sortable_revision(self, url, ud, d): - """ - - """ - if hasattr(self, "_sortable_revision"): - return self._sortable_revision(url, ud, d) - - pd = persist_data.PersistData(d) - key = self.generate_revision_key(url, ud, d) - - latest_rev = self._build_revision(url, ud, d) - last_rev = pd.getValue("BB_URI_LOCALCOUNT", key + "_rev") - uselocalcount = bb.data.getVar("BB_LOCALCOUNT_OVERRIDE", d, True) or False - count = None - if uselocalcount: - count = Fetch.localcount_internal_helper(ud, d) - if count is None: - count = pd.getValue("BB_URI_LOCALCOUNT", key + "_count") - - if last_rev == latest_rev: - return str(count + "+" + latest_rev) - - buildindex_provided = hasattr(self, "_sortable_buildindex") - if buildindex_provided: - count = self._sortable_buildindex(url, ud, d, latest_rev) - - if count is None: - count = "0" - elif uselocalcount or buildindex_provided: - count = str(count) - else: - count = str(int(count) + 1) - - pd.setValue("BB_URI_LOCALCOUNT", key + "_rev", latest_rev) - pd.setValue("BB_URI_LOCALCOUNT", key + "_count", count) - - return str(count + "+" + latest_rev) - - def generate_revision_key(self, url, ud, d): - key = self._revision_key(url, ud, d) - return "%s-%s" % (key, bb.data.getVar("PN", d, True) or "") - -import cvs -import git -import local -import svn -import wget -import svk -import ssh -import perforce -import bzr -import hg -import osc - -methods.append(local.Local()) -methods.append(wget.Wget()) -methods.append(svn.Svn()) -methods.append(git.Git()) -methods.append(cvs.Cvs()) -methods.append(svk.Svk()) -methods.append(ssh.SSH()) -methods.append(perforce.Perforce()) -methods.append(bzr.Bzr()) -methods.append(hg.Hg()) -methods.append(osc.Osc()) diff --git a/bitbake-dev/lib/bb/fetch/bzr.py b/bitbake-dev/lib/bb/fetch/bzr.py deleted file mode 100644 index b27fb63d07..0000000000 --- a/bitbake-dev/lib/bb/fetch/bzr.py +++ /dev/null @@ -1,153 +0,0 @@ -""" -BitBake 'Fetch' implementation for bzr. - -""" - -# Copyright (C) 2007 Ross Burton -# Copyright (C) 2007 Richard Purdie -# -# 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 version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import os -import sys -import bb -from bb import data -from bb.fetch import Fetch -from bb.fetch import FetchError -from bb.fetch import runfetchcmd - -class Bzr(Fetch): - def supports(self, url, ud, d): - return ud.type in ['bzr'] - - def localpath (self, url, ud, d): - - # Create paths to bzr checkouts - relpath = ud.path - if relpath.startswith('/'): - # Remove leading slash as os.path.join can't cope - relpath = relpath[1:] - ud.pkgdir = os.path.join(data.expand('${BZRDIR}', d), ud.host, relpath) - - revision = Fetch.srcrev_internal_helper(ud, d) - if revision is True: - ud.revision = self.latest_revision(url, ud, d) - elif revision: - ud.revision = revision - - if not ud.revision: - ud.revision = self.latest_revision(url, ud, d) - - ud.localfile = data.expand('bzr_%s_%s_%s.tar.gz' % (ud.host, ud.path.replace('/', '.'), ud.revision), d) - - return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile) - - def _buildbzrcommand(self, ud, d, command): - """ - Build up an bzr commandline based on ud - command is "fetch", "update", "revno" - """ - - basecmd = data.expand('${FETCHCMD_bzr}', d) - - proto = "http" - if "proto" in ud.parm: - proto = ud.parm["proto"] - - bzrroot = ud.host + ud.path - - options = [] - - if command is "revno": - bzrcmd = "%s revno %s %s://%s" % (basecmd, " ".join(options), proto, bzrroot) - else: - if ud.revision: - options.append("-r %s" % ud.revision) - - if command is "fetch": - bzrcmd = "%s co %s %s://%s" % (basecmd, " ".join(options), proto, bzrroot) - elif command is "update": - bzrcmd = "%s pull %s --overwrite" % (basecmd, " ".join(options)) - else: - raise FetchError("Invalid bzr command %s" % command) - - return bzrcmd - - def go(self, loc, ud, d): - """Fetch url""" - - # try to use the tarball stash - if Fetch.try_mirror(d, ud.localfile): - bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists or was mirrored, skipping bzr checkout." % ud.localpath) - return - - if os.access(os.path.join(ud.pkgdir, os.path.basename(ud.pkgdir), '.bzr'), os.R_OK): - bzrcmd = self._buildbzrcommand(ud, d, "update") - bb.msg.debug(1, bb.msg.domain.Fetcher, "BZR Update %s" % loc) - os.chdir(os.path.join (ud.pkgdir, os.path.basename(ud.path))) - runfetchcmd(bzrcmd, d) - else: - os.system("rm -rf %s" % os.path.join(ud.pkgdir, os.path.basename(ud.pkgdir))) - bzrcmd = self._buildbzrcommand(ud, d, "fetch") - bb.msg.debug(1, bb.msg.domain.Fetcher, "BZR Checkout %s" % loc) - bb.mkdirhier(ud.pkgdir) - os.chdir(ud.pkgdir) - bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % bzrcmd) - runfetchcmd(bzrcmd, d) - - os.chdir(ud.pkgdir) - # tar them up to a defined filename - try: - runfetchcmd("tar -czf %s %s" % (ud.localpath, os.path.basename(ud.pkgdir)), d) - except: - t, v, tb = sys.exc_info() - try: - os.unlink(ud.localpath) - except OSError: - pass - raise t, v, tb - - def suppports_srcrev(self): - return True - - def _revision_key(self, url, ud, d): - """ - Return a unique key for the url - """ - return "bzr:" + ud.pkgdir - - def _latest_revision(self, url, ud, d): - """ - Return the latest upstream revision number - """ - bb.msg.debug(2, bb.msg.domain.Fetcher, "BZR fetcher hitting network for %s" % url) - - output = runfetchcmd(self._buildbzrcommand(ud, d, "revno"), d, True) - - return output.strip() - - def _sortable_revision(self, url, ud, d): - """ - Return a sortable revision number which in our case is the revision number - """ - - return self._build_revision(url, ud, d) - - def _build_revision(self, url, ud, d): - return ud.revision - diff --git a/bitbake-dev/lib/bb/fetch/cvs.py b/bitbake-dev/lib/bb/fetch/cvs.py deleted file mode 100644 index 90a006500e..0000000000 --- a/bitbake-dev/lib/bb/fetch/cvs.py +++ /dev/null @@ -1,182 +0,0 @@ -# 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 version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -#Based on functions from the base bb module, Copyright 2003 Holger Schurig -# - -import os -import bb -from bb import data -from bb.fetch import Fetch -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(self, url, ud, d): - """ - Check to see if a given url can be fetched with cvs. - """ - return ud.type in ['cvs'] - - def localpath(self, url, ud, d): - if not "module" in ud.parm: - raise MissingParameterError("cvs method needs a 'module' parameter") - 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 = "" - - norecurse = '' - if 'norecurse' in ud.parm: - norecurse = '_norecurse' - - fullpath = '' - if 'fullpath' in ud.parm: - fullpath = '_fullpath' - - ud.localfile = data.expand('%s_%s_%s_%s%s%s.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.tag, ud.date, norecurse, fullpath), d) - - return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile) - - def forcefetch(self, url, ud, d): - if (ud.date == "now"): - return True - return False - - 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_port = "" - if "port" in ud.parm: - cvs_port = ud.parm["port"] - - 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 - cvsproxyhost = data.getVar('CVS_PROXY_HOST', d, True) - if cvsproxyhost: - cvsroot += ";proxy=" + cvsproxyhost - cvsproxyport = data.getVar('CVS_PROXY_PORT', d, True) - if cvsproxyport: - cvsroot += ";proxyport=" + cvsproxyport - cvsroot += ":" + ud.user - if ud.pswd: - cvsroot += ":" + ud.pswd - cvsroot += "@" + ud.host + ":" + cvs_port + ud.path - - options = [] - if 'norecurse' in ud.parm: - options.append("-l") - if ud.date: - # treat YYYYMMDDHHMM specially for CVS - if len(ud.date) == 12: - options.append("-D \"%s %s:%s UTC\"" % (ud.date[0:8], ud.date[8:10], ud.date[10:12])) - else: - options.append("-D \"%s UTC\"" % 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) - - 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) - 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) - - # tar them up to a defined filename - if 'fullpath' in ud.parm: - os.chdir(pkgdir) - myret = os.system("tar -czf %s %s" % (ud.localpath, localdir)) - else: - os.chdir(moddir) - os.chdir('..') - 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-dev/lib/bb/fetch/git.py b/bitbake-dev/lib/bb/fetch/git.py deleted file mode 100644 index 0e68325db9..0000000000 --- a/bitbake-dev/lib/bb/fetch/git.py +++ /dev/null @@ -1,216 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -""" -BitBake 'Fetch' git implementation - -""" - -#Copyright (C) 2005 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import os -import bb -from bb import data -from bb.fetch import Fetch -from bb.fetch import runfetchcmd - -class Git(Fetch): - """Class to fetch a module or modules from git repositories""" - def init(self, d): - # - # Only enable _sortable revision if the key is set - # - if bb.data.getVar("BB_GIT_CLONE_FOR_SRCREV", d, True): - self._sortable_buildindex = self._sortable_buildindex_disabled - def supports(self, url, ud, d): - """ - Check to see if a given url can be fetched with git. - """ - return ud.type in ['git'] - - def localpath(self, url, ud, d): - - if 'protocol' in ud.parm: - ud.proto = ud.parm['protocol'] - elif not ud.host: - ud.proto = 'file' - else: - ud.proto = "rsync" - - ud.branch = ud.parm.get("branch", "master") - - gitsrcname = '%s%s' % (ud.host, ud.path.replace('/', '.')) - ud.mirrortarball = 'git_%s.tar.gz' % (gitsrcname) - ud.clonedir = os.path.join(data.expand('${GITDIR}', d), gitsrcname) - - tag = Fetch.srcrev_internal_helper(ud, d) - if tag is True: - ud.tag = self.latest_revision(url, ud, d) - elif tag: - ud.tag = tag - - if not ud.tag or ud.tag == "master": - ud.tag = self.latest_revision(url, ud, d) - - subdir = ud.parm.get("subpath", "") - if subdir != "": - if subdir.endswith("/"): - subdir = subdir[:-1] - subdirpath = os.path.join(ud.path, subdir); - else: - subdirpath = ud.path; - - if 'fullclone' in ud.parm: - ud.localfile = ud.mirrortarball - else: - ud.localfile = data.expand('git_%s%s_%s.tar.gz' % (ud.host, subdirpath.replace('/', '.'), ud.tag), d) - - return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile) - - def go(self, loc, ud, d): - """Fetch url""" - - if 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 - - if ud.user: - username = ud.user + '@' - else: - username = "" - - repofile = os.path.join(data.getVar("DL_DIR", d, 1), ud.mirrortarball) - - coname = '%s' % (ud.tag) - codir = os.path.join(ud.clonedir, coname) - - if not os.path.exists(ud.clonedir): - if Fetch.try_mirror(d, ud.mirrortarball): - bb.mkdirhier(ud.clonedir) - os.chdir(ud.clonedir) - runfetchcmd("tar -xzf %s" % (repofile), d) - else: - runfetchcmd("git clone -n %s://%s%s%s %s" % (ud.proto, username, ud.host, ud.path, ud.clonedir), d) - - os.chdir(ud.clonedir) - # Remove all but the .git directory - if not self._contains_ref(ud.tag, d): - runfetchcmd("rm * -Rf", d) - runfetchcmd("git fetch %s://%s%s%s %s" % (ud.proto, username, ud.host, ud.path, ud.branch), d) - runfetchcmd("git fetch --tags %s://%s%s%s" % (ud.proto, username, ud.host, ud.path), d) - runfetchcmd("git prune-packed", d) - runfetchcmd("git pack-redundant --all | xargs -r rm", d) - - os.chdir(ud.clonedir) - mirror_tarballs = data.getVar("BB_GENERATE_MIRROR_TARBALLS", d, True) - if mirror_tarballs != "0" or 'fullclone' in ud.parm: - bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git repository") - runfetchcmd("tar -czf %s %s" % (repofile, os.path.join(".", ".git", "*") ), d) - - if 'fullclone' in ud.parm: - return - - if os.path.exists(codir): - bb.utils.prunedir(codir) - - subdir = ud.parm.get("subpath", "") - if subdir != "": - if subdir.endswith("/"): - subdirbase = os.path.basename(subdir[:-1]) - else: - subdirbase = os.path.basename(subdir) - else: - subdirbase = "" - - if subdir != "": - readpathspec = ":%s" % (subdir) - codir = os.path.join(codir, "git") - coprefix = os.path.join(codir, subdirbase, "") - else: - readpathspec = "" - coprefix = os.path.join(codir, "git", "") - - bb.mkdirhier(codir) - os.chdir(ud.clonedir) - runfetchcmd("git read-tree %s%s" % (ud.tag, readpathspec), d) - runfetchcmd("git checkout-index -q -f --prefix=%s -a" % (coprefix), d) - - os.chdir(codir) - bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git checkout") - runfetchcmd("tar -czf %s %s" % (ud.localpath, os.path.join(".", "*") ), d) - - os.chdir(ud.clonedir) - bb.utils.prunedir(codir) - - def suppports_srcrev(self): - return True - - def _contains_ref(self, tag, d): - output = runfetchcmd("git log --pretty=oneline -n 1 %s -- 2> /dev/null | wc -l" % tag, d, quiet=True) - return output.split()[0] != "0" - - def _revision_key(self, url, ud, d): - """ - Return a unique key for the url - """ - return "git:" + ud.host + ud.path.replace('/', '.') - - def _latest_revision(self, url, ud, d): - """ - Compute the HEAD revision for the url - """ - if ud.user: - username = ud.user + '@' - else: - username = "" - - cmd = "git ls-remote %s://%s%s%s %s" % (ud.proto, username, ud.host, ud.path, ud.branch) - output = runfetchcmd(cmd, d, True) - if not output: - raise bb.fetch.FetchError("Fetch command %s gave empty output\n" % (cmd)) - return output.split()[0] - - def _build_revision(self, url, ud, d): - return ud.tag - - def _sortable_buildindex_disabled(self, url, ud, d, rev): - """ - Return a suitable buildindex for the revision specified. This is done by counting revisions - using "git rev-list" which may or may not work in different circumstances. - """ - - cwd = os.getcwd() - - # Check if we have the rev already - - if not os.path.exists(ud.clonedir): - print "no repo" - self.go(None, ud, d) - if not os.path.exists(ud.clonedir): - bb.msg.error(bb.msg.domain.Fetcher, "GIT repository for %s doesn't exist in %s, cannot get sortable buildnumber, using old value" % (url, ud.clonedir)) - return None - - - os.chdir(ud.clonedir) - if not self._contains_ref(rev, d): - self.go(None, ud, d) - - output = runfetchcmd("git rev-list %s -- 2> /dev/null | wc -l" % rev, d, quiet=True) - os.chdir(cwd) - - buildindex = "%s" % output.split()[0] - bb.msg.debug(1, bb.msg.domain.Fetcher, "GIT repository for %s in %s is returning %s revisions in rev-list before %s" % (url, repodir, buildindex, rev)) - return buildindex - diff --git a/bitbake-dev/lib/bb/fetch/hg.py b/bitbake-dev/lib/bb/fetch/hg.py deleted file mode 100644 index 08cb61fc28..0000000000 --- a/bitbake-dev/lib/bb/fetch/hg.py +++ /dev/null @@ -1,178 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -""" -BitBake 'Fetch' implementation for mercurial DRCS (hg). - -""" - -# Copyright (C) 2003, 2004 Chris Larson -# Copyright (C) 2004 Marcin Juszkiewicz -# Copyright (C) 2007 Robert Schuster -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Based on functions from the base bb module, Copyright 2003 Holger Schurig - -import os -import sys -import bb -from bb import data -from bb.fetch import Fetch -from bb.fetch import FetchError -from bb.fetch import MissingParameterError -from bb.fetch import runfetchcmd - -class Hg(Fetch): - """Class to fetch a from mercurial repositories""" - def supports(self, url, ud, d): - """ - Check to see if a given url can be fetched with mercurial. - """ - return ud.type in ['hg'] - - def localpath(self, url, ud, d): - if not "module" in ud.parm: - raise MissingParameterError("hg method needs a 'module' parameter") - - ud.module = ud.parm["module"] - - # Create paths to mercurial checkouts - relpath = ud.path - if relpath.startswith('/'): - # Remove leading slash as os.path.join can't cope - relpath = relpath[1:] - ud.pkgdir = os.path.join(data.expand('${HGDIR}', d), ud.host, relpath) - ud.moddir = os.path.join(ud.pkgdir, ud.module) - - if 'rev' in ud.parm: - ud.revision = ud.parm['rev'] - else: - tag = Fetch.srcrev_internal_helper(ud, d) - if tag is True: - ud.revision = self.latest_revision(url, ud, d) - elif tag: - ud.revision = tag - else: - ud.revision = self.latest_revision(url, ud, d) - - ud.localfile = data.expand('%s_%s_%s_%s.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.path.replace('/', '.'), ud.revision), d) - - return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile) - - def _buildhgcommand(self, ud, d, command): - """ - Build up an hg commandline based on ud - command is "fetch", "update", "info" - """ - - basecmd = data.expand('${FETCHCMD_hg}', d) - - proto = "http" - if "proto" in ud.parm: - proto = ud.parm["proto"] - - host = ud.host - if proto == "file": - host = "/" - ud.host = "localhost" - - if not ud.user: - hgroot = host + ud.path - else: - hgroot = ud.user + "@" + host + ud.path - - if command is "info": - return "%s identify -i %s://%s/%s" % (basecmd, proto, hgroot, ud.module) - - options = []; - if ud.revision: - options.append("-r %s" % ud.revision) - - if command is "fetch": - cmd = "%s clone %s %s://%s/%s %s" % (basecmd, " ".join(options), proto, hgroot, ud.module, ud.module) - elif command is "pull": - # do not pass options list; limiting pull to rev causes the local - # repo not to contain it and immediately following "update" command - # will crash - cmd = "%s pull" % (basecmd) - elif command is "update": - cmd = "%s update -C %s" % (basecmd, " ".join(options)) - else: - raise FetchError("Invalid hg command %s" % command) - - return cmd - - def go(self, loc, ud, d): - """Fetch url""" - - # try to use the tarball stash - if Fetch.try_mirror(d, ud.localfile): - bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists or was mirrored, skipping hg checkout." % ud.localpath) - return - - bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: checking for module directory '" + ud.moddir + "'") - - if os.access(os.path.join(ud.moddir, '.hg'), os.R_OK): - updatecmd = self._buildhgcommand(ud, d, "pull") - bb.msg.note(1, bb.msg.domain.Fetcher, "Update " + loc) - # update sources there - os.chdir(ud.moddir) - bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % updatecmd) - runfetchcmd(updatecmd, d) - - else: - fetchcmd = self._buildhgcommand(ud, d, "fetch") - bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc) - # check out sources there - bb.mkdirhier(ud.pkgdir) - os.chdir(ud.pkgdir) - bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % fetchcmd) - runfetchcmd(fetchcmd, d) - - # Even when we clone (fetch), we still need to update as hg's clone - # won't checkout the specified revision if its on a branch - updatecmd = self._buildhgcommand(ud, d, "update") - bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % updatecmd) - runfetchcmd(updatecmd, d) - - os.chdir(ud.pkgdir) - try: - runfetchcmd("tar -czf %s %s" % (ud.localpath, ud.module), d) - except: - t, v, tb = sys.exc_info() - try: - os.unlink(ud.localpath) - except OSError: - pass - raise t, v, tb - - def suppports_srcrev(self): - return True - - def _latest_revision(self, url, ud, d): - """ - Compute tip revision for the url - """ - output = runfetchcmd(self._buildhgcommand(ud, d, "info"), d) - return output.strip() - - def _build_revision(self, url, ud, d): - return ud.revision - - def _revision_key(self, url, ud, d): - """ - Return a unique key for the url - """ - return "hg:" + ud.moddir - diff --git a/bitbake-dev/lib/bb/fetch/local.py b/bitbake-dev/lib/bb/fetch/local.py deleted file mode 100644 index f9bdf589cb..0000000000 --- a/bitbake-dev/lib/bb/fetch/local.py +++ /dev/null @@ -1,72 +0,0 @@ -# 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 version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Based on functions from the base bb module, Copyright 2003 Holger Schurig - -import os -import bb -from bb import data -from bb.fetch import Fetch - -class Local(Fetch): - def supports(self, url, urldata, d): - """ - Check to see if a given url represents a local fetch. - """ - return urldata.type in ['file'] - - def localpath(self, url, urldata, d): - """ - Return the local filename of a given url assuming a successful fetch. - """ - path = url.split("://")[1] - path = path.split(";")[0] - newpath = path - if path[0] != "/": - filespath = data.getVar('FILESPATH', d, 1) - if filespath: - newpath = bb.which(filespath, path) - if not newpath: - 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 - - 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. - return 1 - - def checkstatus(self, url, urldata, d): - """ - Check the status of the url - """ - if urldata.localpath.find("*") != -1: - bb.msg.note(1, bb.msg.domain.Fetcher, "URL %s looks like a glob and was therefore not checked." % url) - return True - if os.path.exists(urldata.localpath): - return True - return False diff --git a/bitbake-dev/lib/bb/fetch/osc.py b/bitbake-dev/lib/bb/fetch/osc.py deleted file mode 100644 index 2c34caf6c9..0000000000 --- a/bitbake-dev/lib/bb/fetch/osc.py +++ /dev/null @@ -1,155 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -""" -Bitbake "Fetch" implementation for osc (Opensuse build service client). -Based on the svn "Fetch" implementation. - -""" - -import os -import sys -import bb -from bb import data -from bb.fetch import Fetch -from bb.fetch import FetchError -from bb.fetch import MissingParameterError -from bb.fetch import runfetchcmd - -class Osc(Fetch): - """Class to fetch a module or modules from Opensuse build server - repositories.""" - - def supports(self, url, ud, d): - """ - Check to see if a given url can be fetched with osc. - """ - return ud.type in ['osc'] - - def localpath(self, url, ud, d): - if not "module" in ud.parm: - raise MissingParameterError("osc method needs a 'module' parameter.") - - ud.module = ud.parm["module"] - - # Create paths to osc checkouts - relpath = ud.path - if relpath.startswith('/'): - # Remove leading slash as os.path.join can't cope - relpath = relpath[1:] - ud.pkgdir = os.path.join(data.expand('${OSCDIR}', d), ud.host) - ud.moddir = os.path.join(ud.pkgdir, relpath, ud.module) - - if 'rev' in ud.parm: - ud.revision = ud.parm['rev'] - else: - pv = data.getVar("PV", d, 0) - rev = Fetch.srcrev_internal_helper(ud, d) - if rev and rev != True: - ud.revision = rev - else: - ud.revision = "" - - ud.localfile = data.expand('%s_%s_%s.tar.gz' % (ud.module.replace('/', '.'), ud.path.replace('/', '.'), ud.revision), d) - - return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile) - - def _buildosccommand(self, ud, d, command): - """ - Build up an ocs commandline based on ud - command is "fetch", "update", "info" - """ - - basecmd = data.expand('${FETCHCMD_osc}', d) - - proto = "ocs" - if "proto" in ud.parm: - proto = ud.parm["proto"] - - options = [] - - config = "-c %s" % self.generate_config(ud, d) - - if ud.revision: - options.append("-r %s" % ud.revision) - - coroot = ud.path - if coroot.startswith('/'): - # Remove leading slash as os.path.join can't cope - coroot= coroot[1:] - - if command is "fetch": - osccmd = "%s %s co %s/%s %s" % (basecmd, config, coroot, ud.module, " ".join(options)) - elif command is "update": - osccmd = "%s %s up %s" % (basecmd, config, " ".join(options)) - else: - raise FetchError("Invalid osc command %s" % command) - - return osccmd - - def go(self, loc, ud, d): - """ - Fetch url - """ - - # Try to use the tarball stash - if Fetch.try_mirror(d, ud.localfile): - bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists or was mirrored, skipping osc checkout." % ud.localpath) - return - - bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: checking for module directory '" + ud.moddir + "'") - - if os.access(os.path.join(data.expand('${OSCDIR}', d), ud.path, ud.module), os.R_OK): - oscupdatecmd = self._buildosccommand(ud, d, "update") - bb.msg.note(1, bb.msg.domain.Fetcher, "Update "+ loc) - # update sources there - os.chdir(ud.moddir) - bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % oscupdatecmd) - runfetchcmd(oscupdatecmd, d) - else: - oscfetchcmd = self._buildosccommand(ud, d, "fetch") - bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc) - # check out sources there - bb.mkdirhier(ud.pkgdir) - os.chdir(ud.pkgdir) - bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % oscfetchcmd) - runfetchcmd(oscfetchcmd, d) - - os.chdir(os.path.join(ud.pkgdir + ud.path)) - # tar them up to a defined filename - try: - runfetchcmd("tar -czf %s %s" % (ud.localpath, ud.module), d) - except: - t, v, tb = sys.exc_info() - try: - os.unlink(ud.localpath) - except OSError: - pass - raise t, v, tb - - def supports_srcrev(self): - return False - - def generate_config(self, ud, d): - """ - Generate a .oscrc to be used for this run. - """ - - config_path = "%s/oscrc" % data.expand('${OSCDIR}', d) - if (os.path.exists(config_path)): - os.remove(config_path) - - f = open(config_path, 'w') - f.write("[general]\n") - f.write("apisrv = %s\n" % ud.host) - f.write("scheme = http\n") - f.write("su-wrapper = su -c\n") - f.write("build-root = %s\n" % data.expand('${WORKDIR}', d)) - f.write("urllist = http://moblin-obs.jf.intel.com:8888/build/%(project)s/%(repository)s/%(buildarch)s/:full/%(name)s.rpm\n") - f.write("extra-pkgs = gzip\n") - f.write("\n") - f.write("[%s]\n" % ud.host) - f.write("user = %s\n" % ud.parm["user"]) - f.write("pass = %s\n" % ud.parm["pswd"]) - f.close() - - return config_path diff --git a/bitbake-dev/lib/bb/fetch/perforce.py b/bitbake-dev/lib/bb/fetch/perforce.py deleted file mode 100644 index 394f5a2253..0000000000 --- a/bitbake-dev/lib/bb/fetch/perforce.py +++ /dev/null @@ -1,214 +0,0 @@ -# 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 version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Based on functions from the base bb module, Copyright 2003 Holger Schurig - -import os -import bb -from bb import data -from bb.fetch import Fetch -from bb.fetch import FetchError - -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): - p4opt = "" - if "cset" in parm: - return parm["cset"]; - if user: - p4opt += " -u %s" % (user) - if pswd: - p4opt += " -P %s" % (pswd) - if host: - p4opt += " -p %s" % (host) - - 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%s changes -m 1 %s" % (p4cmd, p4opt, depot)) - p4file = os.popen("%s%s changes -m 1 %s" % (p4cmd, p4opt, 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 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 - p4opt = "" - if user: - p4opt += " -u %s" % (user) - - if pswd: - p4opt += " -P %s" % (pswd) - - if host: - p4opt += " -p %s" % (host) - - 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%s files %s" % (p4cmd, p4opt, depot)) - p4file = os.popen("%s%s files %s" % (p4cmd, p4opt, 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%s print -o %s/%s %s" % (p4cmd, p4opt, 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-dev/lib/bb/fetch/ssh.py b/bitbake-dev/lib/bb/fetch/ssh.py deleted file mode 100644 index 68e6fdb1df..0000000000 --- a/bitbake-dev/lib/bb/fetch/ssh.py +++ /dev/null @@ -1,118 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -''' -BitBake 'Fetch' implementations - -This implementation is for Secure Shell (SSH), and attempts to comply with the -IETF secsh internet draft: - http://tools.ietf.org/wg/secsh/draft-ietf-secsh-scp-sftp-ssh-uri/ - - Currently does not support the sftp parameters, as this uses scp - Also does not support the 'fingerprint' connection parameter. - -''' - -# Copyright (C) 2006 OpenedHand Ltd. -# -# -# Based in part on svk.py: -# Copyright (C) 2006 Holger Hans Peter Freyther -# Based on svn.py: -# Copyright (C) 2003, 2004 Chris Larson -# Based on functions from the base bb module: -# Copyright 2003 Holger Schurig -# -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import re, os -from bb import data -from bb.fetch import Fetch -from bb.fetch import FetchError - - -__pattern__ = re.compile(r''' - \s* # Skip leading whitespace - ssh:// # scheme - ( # Optional username/password block - (?P<user>\S+) # username - (:(?P<pass>\S+))? # colon followed by the password (optional) - )? - (?P<cparam>(;[^;]+)*)? # connection parameters block (optional) - @ - (?P<host>\S+?) # non-greedy match of the host - (:(?P<port>[0-9]+))? # colon followed by the port (optional) - / - (?P<path>[^;]+) # path on the remote system, may be absolute or relative, - # and may include the use of '~' to reference the remote home - # directory - (?P<sparam>(;[^;]+)*)? # parameters block (optional) - $ -''', re.VERBOSE) - -class SSH(Fetch): - '''Class to fetch a module or modules via Secure Shell''' - - def supports(self, url, urldata, d): - return __pattern__.match(url) != None - - 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, True), host, os.path.basename(path)) - return lpath - - 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-dev/lib/bb/fetch/svk.py b/bitbake-dev/lib/bb/fetch/svk.py deleted file mode 100644 index 120dad9d4e..0000000000 --- a/bitbake-dev/lib/bb/fetch/svk.py +++ /dev/null @@ -1,109 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -""" -BitBake 'Fetch' implementations - -This implementation is for svk. It is based on the svn implementation - -""" - -# Copyright (C) 2006 Holger Hans Peter Freyther -# 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 version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Based on functions from the base bb module, Copyright 2003 Holger Schurig - -import os -import bb -from bb import data -from bb.fetch import Fetch -from bb.fetch import FetchError -from bb.fetch import MissingParameterError - -class Svk(Fetch): - """Class to fetch a module or modules from svk repositories""" - def supports(self, url, ud, d): - """ - Check to see if a given url can be fetched with svk. - """ - return ud.type in ['svk'] - - def localpath(self, url, ud, d): - if not "module" in ud.parm: - raise MissingParameterError("svk method needs a 'module' parameter") - else: - 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) - - def forcefetch(self, url, ud, d): - if (ud.date == "now"): - return True - return False - - def go(self, loc, ud, d): - """Fetch 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" % (ud.date, svkroot, ud.module) - - if ud.revision: - svkcmd = "svk co -r %s %s/%s" % (ud.revision, svkroot, ud.module) - - # create temp directory - localdata = data.createCopy(d) - data.update_data(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-dev/lib/bb/fetch/svn.py b/bitbake-dev/lib/bb/fetch/svn.py deleted file mode 100644 index eef9862a84..0000000000 --- a/bitbake-dev/lib/bb/fetch/svn.py +++ /dev/null @@ -1,206 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -""" -BitBake 'Fetch' implementation for svn. - -""" - -# Copyright (C) 2003, 2004 Chris Larson -# Copyright (C) 2004 Marcin Juszkiewicz -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Based on functions from the base bb module, Copyright 2003 Holger Schurig - -import os -import sys -import bb -from bb import data -from bb.fetch import Fetch -from bb.fetch import FetchError -from bb.fetch import MissingParameterError -from bb.fetch import runfetchcmd - -class Svn(Fetch): - """Class to fetch a module or modules from svn repositories""" - def supports(self, url, ud, d): - """ - Check to see if a given url can be fetched with svn. - """ - return ud.type in ['svn'] - - def localpath(self, url, ud, d): - if not "module" in ud.parm: - raise MissingParameterError("svn method needs a 'module' parameter") - - ud.module = ud.parm["module"] - - # Create paths to svn checkouts - relpath = ud.path - if relpath.startswith('/'): - # Remove leading slash as os.path.join can't cope - relpath = relpath[1:] - ud.pkgdir = os.path.join(data.expand('${SVNDIR}', d), ud.host, relpath) - ud.moddir = os.path.join(ud.pkgdir, ud.module) - - if 'rev' in ud.parm: - ud.date = "" - ud.revision = ud.parm['rev'] - elif 'date' in ud.date: - ud.date = ud.parm['date'] - ud.revision = "" - else: - # - # ***Nasty hack*** - # If DATE in unexpanded PV, use ud.date (which is set from SRCDATE) - # Should warn people to switch to SRCREV here - # - pv = data.getVar("PV", d, 0) - if "DATE" in pv: - ud.revision = "" - else: - rev = Fetch.srcrev_internal_helper(ud, d) - if rev is True: - ud.revision = self.latest_revision(url, ud, d) - ud.date = "" - elif rev: - ud.revision = rev - ud.date = "" - else: - ud.revision = "" - - 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) - - def _buildsvncommand(self, ud, d, command): - """ - Build up an svn commandline based on ud - command is "fetch", "update", "info" - """ - - basecmd = data.expand('${FETCHCMD_svn}', d) - - 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, - options = [] - - if ud.user: - options.append("--username %s" % ud.user) - - if ud.pswd: - options.append("--password %s" % ud.pswd) - - if command is "info": - svncmd = "%s info %s %s://%s/%s/" % (basecmd, " ".join(options), proto, svnroot, ud.module) - else: - suffix = "" - if ud.revision: - options.append("-r %s" % ud.revision) - suffix = "@%s" % (ud.revision) - elif ud.date: - options.append("-r {%s}" % ud.date) - - if command is "fetch": - svncmd = "%s co %s %s://%s/%s%s %s" % (basecmd, " ".join(options), proto, svnroot, ud.module, suffix, ud.module) - elif command is "update": - svncmd = "%s update %s" % (basecmd, " ".join(options)) - else: - raise FetchError("Invalid svn command %s" % command) - - if svn_rsh: - svncmd = "svn_RSH=\"%s\" %s" % (svn_rsh, svncmd) - - return svncmd - - def go(self, loc, ud, d): - """Fetch url""" - - # try to use the tarball stash - if 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 - - bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: checking for module directory '" + ud.moddir + "'") - - if os.access(os.path.join(ud.moddir, '.svn'), os.R_OK): - svnupdatecmd = self._buildsvncommand(ud, d, "update") - bb.msg.note(1, bb.msg.domain.Fetcher, "Update " + loc) - # update sources there - os.chdir(ud.moddir) - bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % svnupdatecmd) - runfetchcmd(svnupdatecmd, d) - else: - svnfetchcmd = self._buildsvncommand(ud, d, "fetch") - bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc) - # check out sources there - bb.mkdirhier(ud.pkgdir) - os.chdir(ud.pkgdir) - bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % svnfetchcmd) - runfetchcmd(svnfetchcmd, d) - - os.chdir(ud.pkgdir) - # tar them up to a defined filename - try: - runfetchcmd("tar -czf %s %s" % (ud.localpath, ud.module), d) - except: - t, v, tb = sys.exc_info() - try: - os.unlink(ud.localpath) - except OSError: - pass - raise t, v, tb - - def suppports_srcrev(self): - return True - - def _revision_key(self, url, ud, d): - """ - Return a unique key for the url - """ - return "svn:" + ud.moddir - - def _latest_revision(self, url, ud, d): - """ - Return the latest upstream revision number - """ - bb.msg.debug(2, bb.msg.domain.Fetcher, "SVN fetcher hitting network for %s" % url) - - output = runfetchcmd("LANG=C LC_ALL=C " + self._buildsvncommand(ud, d, "info"), d, True) - - revision = None - for line in output.splitlines(): - if "Last Changed Rev" in line: - revision = line.split(":")[1].strip() - - return revision - - def _sortable_revision(self, url, ud, d): - """ - Return a sortable revision number which in our case is the revision number - """ - - return self._build_revision(url, ud, d) - - def _build_revision(self, url, ud, d): - return ud.revision diff --git a/bitbake-dev/lib/bb/fetch/wget.py b/bitbake-dev/lib/bb/fetch/wget.py deleted file mode 100644 index fd93c7ec46..0000000000 --- a/bitbake-dev/lib/bb/fetch/wget.py +++ /dev/null @@ -1,130 +0,0 @@ -# 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 version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Based on functions from the base bb module, Copyright 2003 Holger Schurig - -import os -import bb -from bb import data -from bb.fetch import Fetch -from bb.fetch import FetchError -from bb.fetch import uri_replace - -class Wget(Fetch): - """Class to fetch urls via 'wget'""" - def supports(self, url, ud, d): - """ - Check to see if a given url can be fetched with wget. - """ - 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, checkonly = False): - """Fetch urls""" - - def fetch_uri(uri, ud, d): - if checkonly: - fetchcmd = data.getVar("CHECKCOMMAND", d, 1) - elif 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) - - uri = uri.split(";")[0] - uri_decoded = list(bb.decodeurl(uri)) - uri_type = uri_decoded[0] - uri_host = uri_decoded[1] - - bb.msg.note(1, bb.msg.domain.Fetcher, "fetch " + uri) - fetchcmd = fetchcmd.replace("${URI}", uri.split(";")[0]) - fetchcmd = fetchcmd.replace("${FILE}", ud.basename) - httpproxy = None - ftpproxy = None - if uri_type == 'http': - httpproxy = data.getVar("HTTP_PROXY", d, True) - httpproxy_ignore = (data.getVar("HTTP_PROXY_IGNORE", d, True) or "").split() - for p in httpproxy_ignore: - if uri_host.endswith(p): - httpproxy = None - break - if uri_type == 'ftp': - ftpproxy = data.getVar("FTP_PROXY", d, True) - ftpproxy_ignore = (data.getVar("HTTP_PROXY_IGNORE", d, True) or "").split() - for p in ftpproxy_ignore: - if uri_host.endswith(p): - ftpproxy = None - break - if httpproxy: - fetchcmd = "http_proxy=" + httpproxy + " " + fetchcmd - if ftpproxy: - fetchcmd = "ftp_proxy=" + ftpproxy + " " + fetchcmd - bb.msg.debug(2, bb.msg.domain.Fetcher, "executing " + fetchcmd) - ret = os.system(fetchcmd) - if ret != 0: - return False - - # Sanity check since wget can pretend it succeed when it didn't - # Also, this used to happen if sourceforge sent us to the mirror page - if not os.path.exists(ud.localpath) and not checkonly: - bb.msg.debug(2, bb.msg.domain.Fetcher, "The fetch command for %s returned success but %s doesn't exist?..." % (uri, ud.localpath)) - return False - - return True - - localdata = data.createCopy(d) - data.setVar('OVERRIDES', "wget:" + data.getVar('OVERRIDES', localdata), localdata) - data.update_data(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 True - - if fetch_uri(uri, ud, localdata): - return True - - # 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 True - - raise FetchError(uri) - - - def checkstatus(self, uri, ud, d): - return self.go(uri, ud, d, True) diff --git a/bitbake-dev/lib/bb/manifest.py b/bitbake-dev/lib/bb/manifest.py deleted file mode 100644 index 4e4b7d98ec..0000000000 --- a/bitbake-dev/lib/bb/manifest.py +++ /dev/null @@ -1,144 +0,0 @@ -# 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 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import os, sys -import bb, bb.data - -def getfields(line): - fields = {} - fieldmap = ( "pkg", "src", "dest", "type", "mode", "uid", "gid", "major", "minor", "start", "inc", "count" ) - for f in xrange(len(fieldmap)): - fields[fieldmap[f]] = None - - if not line: - return None - - splitline = line.split() - if not len(splitline): - return None - - try: - for f in xrange(len(fieldmap)): - if splitline[f] == '-': - continue - fields[fieldmap[f]] = splitline[f] - except IndexError: - pass - return fields - -def parse (mfile, d): - manifest = [] - while 1: - line = mfile.readline() - if not line: - break - if line.startswith("#"): - continue - fields = getfields(line) - if not fields: - continue - manifest.append(fields) - return manifest - -def emit (func, manifest, d): -#str = "%s () {\n" % func - str = "" - for line in manifest: - emittedline = emit_line(func, line, d) - if not emittedline: - continue - str += emittedline + "\n" -# str += "}\n" - return str - -def mangle (func, line, d): - import copy - newline = copy.copy(line) - src = bb.data.expand(newline["src"], d) - - if src: - if not os.path.isabs(src): - src = "${WORKDIR}/" + src - - dest = newline["dest"] - if not dest: - return - - if dest.startswith("/"): - dest = dest[1:] - - if func is "do_install": - dest = "${D}/" + dest - - elif func is "do_populate": - dest = "${WORKDIR}/install/" + newline["pkg"] + "/" + dest - - elif func is "do_stage": - varmap = {} - varmap["${bindir}"] = "${STAGING_DIR}/${HOST_SYS}/bin" - varmap["${libdir}"] = "${STAGING_DIR}/${HOST_SYS}/lib" - varmap["${includedir}"] = "${STAGING_DIR}/${HOST_SYS}/include" - varmap["${datadir}"] = "${STAGING_DATADIR}" - - matched = 0 - for key in varmap.keys(): - if dest.startswith(key): - dest = varmap[key] + "/" + dest[len(key):] - matched = 1 - if not matched: - newline = None - return - else: - newline = None - return - - newline["src"] = src - newline["dest"] = dest - return newline - -def emit_line (func, line, d): - import copy - newline = copy.deepcopy(line) - newline = mangle(func, newline, d) - if not newline: - return None - - str = "" - type = newline["type"] - mode = newline["mode"] - src = newline["src"] - dest = newline["dest"] - if type is "d": - str = "install -d " - if mode: - str += "-m %s " % mode - str += dest - elif type is "f": - if not src: - return None - if dest.endswith("/"): - str = "install -d " - str += dest + "\n" - str += "install " - else: - str = "install -D " - if mode: - str += "-m %s " % mode - str += src + " " + dest - del newline - return str diff --git a/bitbake-dev/lib/bb/methodpool.py b/bitbake-dev/lib/bb/methodpool.py deleted file mode 100644 index f43c4a0580..0000000000 --- a/bitbake-dev/lib/bb/methodpool.py +++ /dev/null @@ -1,84 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -# -# -# 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 version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - -""" - What is a method pool? - - BitBake has a global method scope where .bb, .inc and .bbclass - files can install methods. These methods are parsed from strings. - To avoid recompiling and executing these string we introduce - a method pool to do this task. - - This pool will be used to compile and execute the functions. It - will be smart enough to -""" - -from bb.utils import better_compile, better_exec -from bb import error - -# A dict of modules we have handled -# it is the number of .bbclasses + x in size -_parsed_methods = { } -_parsed_fns = { } - -def insert_method(modulename, code, fn): - """ - Add code of a module should be added. The methods - will be simply added, no checking will be done - """ - comp = better_compile(code, "<bb>", fn ) - better_exec(comp, __builtins__, code, fn) - - # now some instrumentation - code = comp.co_names - for name in code: - if name in ['None', 'False']: - continue - elif name in _parsed_fns and not _parsed_fns[name] == modulename: - error( "Error Method already seen: %s in' %s' now in '%s'" % (name, _parsed_fns[name], modulename)) - else: - _parsed_fns[name] = modulename - -def check_insert_method(modulename, code, fn): - """ - Add the code if it wasnt added before. The module - name will be used for that - - Variables: - @modulename a short name e.g. base.bbclass - @code The actual python code - @fn The filename from the outer file - """ - if not modulename in _parsed_methods: - return insert_method(modulename, code, fn) - _parsed_methods[modulename] = 1 - -def parsed_module(modulename): - """ - Inform me file xyz was parsed - """ - return modulename in _parsed_methods - - -def get_parsed_dict(): - """ - shortcut - """ - return _parsed_methods diff --git a/bitbake-dev/lib/bb/msg.py b/bitbake-dev/lib/bb/msg.py deleted file mode 100644 index 3fcf7091be..0000000000 --- a/bitbake-dev/lib/bb/msg.py +++ /dev/null @@ -1,125 +0,0 @@ -# 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 version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import sys, bb -from bb import event - -debug_level = {} - -verbose = False - -domain = bb.utils.Enum( - 'Build', - 'Cache', - 'Collection', - 'Data', - 'Depends', - 'Fetcher', - 'Parsing', - 'PersistData', - 'Provider', - 'RunQueue', - 'TaskData', - 'Util') - - -class MsgBase(bb.event.Event): - """Base class for messages""" - - def __init__(self, msg): - self._message = msg - event.Event.__init__(self) - -class MsgDebug(MsgBase): - """Debug Message""" - -class MsgNote(MsgBase): - """Note Message""" - -class MsgWarn(MsgBase): - """Warning Message""" - -class MsgError(MsgBase): - """Error Message""" - -class MsgFatal(MsgBase): - """Fatal Message""" - -class MsgPlain(MsgBase): - """General output""" - -# -# 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: - bb.msg.warn(None, "Logging domain %s is not valid, ignoring" % domain) - -# -# Message handling functions -# - -def debug(level, domain, msg, fn = None): - if not domain: - domain = 'default' - if debug_level[domain] >= level: - bb.event.fire(MsgDebug(msg), None) - -def note(level, domain, msg, fn = None): - if not domain: - domain = 'default' - if level == 1 or verbose or debug_level[domain] >= 1: - bb.event.fire(MsgNote(msg), None) - -def warn(domain, msg, fn = None): - bb.event.fire(MsgWarn(msg), None) - -def error(domain, msg, fn = None): - bb.event.fire(MsgError(msg), None) - print 'ERROR: ' + msg - -def fatal(domain, msg, fn = None): - bb.event.fire(MsgFatal(msg), None) - print 'FATAL: ' + msg - sys.exit(1) - -def plain(msg, fn = None): - bb.event.fire(MsgPlain(msg), None) - diff --git a/bitbake-dev/lib/bb/parse/__init__.py b/bitbake-dev/lib/bb/parse/__init__.py deleted file mode 100644 index 5dd96c4136..0000000000 --- a/bitbake-dev/lib/bb/parse/__init__.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -BitBake Parsers - -File parsers for the BitBake build tools. - -""" - - -# Copyright (C) 2003, 2004 Chris Larson -# Copyright (C) 2003, 2004 Phil Blundell -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Based on functions from the base bb module, Copyright 2003 Holger Schurig - -__all__ = [ 'ParseError', 'SkipPackage', 'cached_mtime', 'mark_dependency', - 'supports', 'handle', 'init' ] -handlers = [] - -import bb, os - -class ParseError(Exception): - """Exception raised when parsing fails""" - -class SkipPackage(Exception): - """Exception raised to skip this package""" - -__mtime_cache = {} -def cached_mtime(f): - if not __mtime_cache.has_key(f): - __mtime_cache[f] = os.stat(f)[8] - return __mtime_cache[f] - -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 update_mtime(f): - __mtime_cache[f] = os.stat(f)[8] - return __mtime_cache[f] - -def mark_dependency(d, f): - if f.startswith('./'): - f = "%s/%s" % (os.getcwd(), f[2:]) - deps = bb.data.getVar('__depends', d) or [] - deps.append( (f, cached_mtime(f)) ) - bb.data.setVar('__depends', deps, d) - -def supports(fn, data): - """Returns true if we have a handler for this file, false otherwise""" - for h in handlers: - if h['supports'](fn, data): - return 1 - return 0 - -def handle(fn, data, include = 0): - """Call the handler that is appropriate for this file""" - for h in handlers: - if h['supports'](fn, data): - return h['handle'](fn, data, include) - raise ParseError("%s is not a BitBake file" % fn) - -def init(fn, data): - for h in handlers: - if h['supports'](fn): - return h['init'](data) - - -from parse_py import __version__, ConfHandler, BBHandler diff --git a/bitbake-dev/lib/bb/parse/parse_py/BBHandler.py b/bitbake-dev/lib/bb/parse/parse_py/BBHandler.py deleted file mode 100644 index 86fa18ebd2..0000000000 --- a/bitbake-dev/lib/bb/parse/parse_py/BBHandler.py +++ /dev/null @@ -1,410 +0,0 @@ -#!/usr/bin/env python -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -""" - class for handling .bb files - - Reads a .bb file and obtains its metadata - -""" - - -# Copyright (C) 2003, 2004 Chris Larson -# Copyright (C) 2003, 2004 Phil Blundell -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import re, bb, os, sys, time, string -import bb.fetch, bb.build, bb.utils -from bb import data, fetch, methodpool - -from ConfHandler import include, localpath, obtain, init -from bb.parse import ParseError - -__func_start_regexp__ = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" ) -__inherit_regexp__ = re.compile( r"inherit\s+(.+)" ) -__export_func_regexp__ = re.compile( r"EXPORT_FUNCTIONS\s+(.+)" ) -__addtask_regexp__ = re.compile("addtask\s+(?P<func>\w+)\s*((before\s*(?P<before>((.*(?=after))|(.*))))|(after\s*(?P<after>((.*(?=before))|(.*)))))*") -__addhandler_regexp__ = re.compile( r"addhandler\s+(.+)" ) -__def_regexp__ = re.compile( r"def\s+(\w+).*:" ) -__python_func_regexp__ = re.compile( r"(\s+.*)|(^$)" ) -__word__ = re.compile(r"\S+") - -__infunc__ = "" -__inpython__ = False -__body__ = [] -__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): - localfn = localpath(fn, d) - return localfn[-3:] == ".bb" or localfn[-8:] == ".bbclass" or localfn[-4:] == ".inc" - -def inherit(files, d): - __inherit_cache = data.getVar('__inherit_cache', d) or [] - fn = "" - lineno = 0 - files = data.expand(files, d) - for file in files: - if file[0] != "/" and file[-8:] != ".bbclass": - file = os.path.join('classes', '%s.bbclass' % file) - - if not file in __inherit_cache: - bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s:%d: inheriting %s" % (fn, lineno, file)) - __inherit_cache.append( file ) - data.setVar('__inherit_cache', __inherit_cache, d) - include(fn, file, d, "inherit") - __inherit_cache = data.getVar('__inherit_cache', d) or [] - - -def finalise(fn, d): - data.expandKeys(d) - data.update_data(d) - anonqueue = data.getVar("__anonqueue", d, 1) or [] - body = [x['content'] for x in anonqueue] - flag = { 'python' : 1, 'func' : 1 } - data.setVar("__anonfunc", "\n".join(body), d) - data.setVarFlags("__anonfunc", flag, d) - from bb import build - try: - t = data.getVar('T', d) - data.setVar('T', '${TMPDIR}/anonfunc/', d) - anonfuncs = data.getVar('__BBANONFUNCS', d) or [] - code = "" - for f in anonfuncs: - code = code + " %s(d)\n" % f - data.setVar("__anonfunc", code, d) - build.exec_func("__anonfunc", d) - data.delVar('T', d) - if t: - data.setVar('T', t, d) - except Exception, e: - bb.msg.debug(1, bb.msg.domain.Parsing, "Exception when executing anonymous function: %s" % e) - raise - data.delVar("__anonqueue", d) - data.delVar("__anonfunc", d) - data.update_data(d) - - all_handlers = {} - for var in data.getVar('__BBHANDLERS', d) or []: - # try to add the handler - handler = data.getVar(var,d) - bb.event.register(var, handler) - - tasklist = data.getVar('__BBTASKS', d) or [] - bb.build.add_tasks(tasklist, d) - - bb.event.fire(bb.event.RecipeParsed(fn), d) - - -def handle(fn, d, include = 0): - global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __residue__ - __body__ = [] - __infunc__ = "" - __classname__ = "" - __residue__ = [] - - if include == 0: - bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data)") - else: - 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) - init(d) - - if ext == ".bbclass": - __classname__ = root - classes.append(__classname__) - __inherit_cache = data.getVar('__inherit_cache', d) or [] - if not fn in __inherit_cache: - __inherit_cache.append(fn) - data.setVar('__inherit_cache', __inherit_cache, d) - - if include != 0: - oldfile = data.getVar('FILE', d) - else: - oldfile = None - - fn = obtain(fn, d) - bbpath = (data.getVar('BBPATH', d, 1) or '').split(':') - if not os.path.isabs(fn): - f = None - for p in bbpath: - j = os.path.join(p, fn) - if os.access(j, os.R_OK): - abs_fn = j - f = open(j, 'r') - break - if f is None: - raise IOError("file %s not found" % fn) - else: - f = open(fn,'r') - abs_fn = fn - - if include: - bb.parse.mark_dependency(d, abs_fn) - - if ext != ".bbclass": - data.setVar('FILE', fn, d) - - lineno = 0 - while 1: - lineno = lineno + 1 - s = f.readline() - if not s: break - s = s.rstrip() - feeder(lineno, s, fn, base_name, d) - if __inpython__: - # add a blank line to close out any python definition - feeder(IN_PYTHON_EOF, "", fn, base_name, d) - if ext == ".bbclass": - classes.remove(__classname__) - else: - if include == 0: - multi = data.getVar('BBCLASSEXTEND', d, 1) - if multi: - based = bb.data.createCopy(d) - else: - based = d - try: - finalise(fn, based) - except bb.parse.SkipPackage: - bb.data.setVar("__SKIPPED", True, based) - darray = {"": based} - - for cls in (multi or "").split(): - pn = data.getVar('PN', d, True) - based = bb.data.createCopy(d) - data.setVar('PN', pn + '-' + cls, based) - inherit([cls], based) - try: - finalise(fn, based) - except bb.parse.SkipPackage: - bb.data.setVar("__SKIPPED", True, based) - darray[cls] = based - return darray - - bbpath.pop(0) - if oldfile: - bb.data.setVar("FILE", oldfile, d) - - # we have parsed the bb class now - if ext == ".bbclass" or ext == ".inc": - __parsed_methods__[base_name] = 1 - - return d - -def feeder(lineno, s, fn, root, d): - global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__,__infunc__, __body__, classes, bb, __residue__ - if __infunc__: - if s == '}': - __body__.append('') - if __infunc__ == "__anonymous": - funcname = ("__anon_%s_%s" % (lineno, fn.translate(string.maketrans('/.+-', '____')))) - if not funcname in methodpool._parsed_fns: - text = "def %s(d):\n" % (funcname) + '\n'.join(__body__) - methodpool.insert_method(funcname, text, fn) - anonfuncs = data.getVar('__BBANONFUNCS', d) or [] - anonfuncs.append(funcname) - data.setVar('__BBANONFUNCS', anonfuncs, d) - else: - data.setVarFlag(__infunc__, "func", 1, d) - data.setVar(__infunc__, '\n'.join(__body__), d) - __infunc__ = "" - __body__ = [] - else: - __body__.append(s) - return - - if __inpython__: - m = __python_func_regexp__.match(s) - if m and lineno != IN_PYTHON_EOF: - __body__.append(s) - return - else: - # Note we will add root to parsedmethods after having parse - # 'this' file. This means we will not parse methods from - # bb classes twice - if not root in __parsed_methods__: - text = '\n'.join(__body__) - methodpool.insert_method( root, text, fn ) - __body__ = [] - __inpython__ = False - - if lineno == IN_PYTHON_EOF: - return - -# fall through - - if s == '' or s[0] == '#': return # skip comments and empty lines - - if s[-1] == '\\': - __residue__.append(s[:-1]) - return - - s = "".join(__residue__) + s - __residue__ = [] - - m = __func_start_regexp__.match(s) - if m: - __infunc__ = m.group("func") or "__anonymous" - key = __infunc__ - if data.getVar(key, d): -# clean up old version of this piece of metadata, as its -# flags could cause problems - data.setVarFlag(key, 'python', None, d) - data.setVarFlag(key, 'fakeroot', None, d) - if m.group("py") is not None: - data.setVarFlag(key, "python", "1", d) - else: - data.delVarFlag(key, "python", d) - if m.group("fr") is not None: - data.setVarFlag(key, "fakeroot", "1", d) - else: - data.delVarFlag(key, "fakeroot", d) - return - - m = __def_regexp__.match(s) - if m: - __body__.append(s) - __inpython__ = True - return - - m = __export_func_regexp__.match(s) - if m: - fns = m.group(1) - n = __word__.findall(fns) - for f in n: - allvars = [] - allvars.append(f) - allvars.append(classes[-1] + "_" + f) - - vars = [[ allvars[0], allvars[1] ]] - if len(classes) > 1 and classes[-2] is not None: - allvars.append(classes[-2] + "_" + f) - vars = [] - vars.append([allvars[2], allvars[1]]) - vars.append([allvars[0], allvars[2]]) - - for (var, calledvar) in vars: - if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d): - continue - - if data.getVar(var, d): - data.setVarFlag(var, 'python', None, d) - data.setVarFlag(var, 'func', None, d) - - for flag in [ "func", "python" ]: - if data.getVarFlag(calledvar, flag, d): - data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d) - for flag in [ "dirs" ]: - if data.getVarFlag(var, flag, d): - data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d) - - if data.getVarFlag(calledvar, "python", d): - data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d) - else: - data.setVar(var, "\t" + calledvar + "\n", d) - data.setVarFlag(var, 'export_func', '1', d) - - return - - m = __addtask_regexp__.match(s) - if m: - func = m.group("func") - before = m.group("before") - after = m.group("after") - if func is None: - return - if func[:3] != "do_": - var = "do_" + func - - data.setVarFlag(var, "task", 1, d) - - bbtasks = data.getVar('__BBTASKS', d) or [] - if not var in bbtasks: - bbtasks.append(var) - data.setVar('__BBTASKS', bbtasks, d) - - existing = data.getVarFlag(var, "deps", d) or [] - if after is not None: - # set up deps for function - for entry in after.split(): - if entry not in existing: - existing.append(entry) - data.setVarFlag(var, "deps", existing, d) - if before is not None: - # set up things that depend on this func - for entry in before.split(): - existing = data.getVarFlag(entry, "deps", d) or [] - if var not in existing: - data.setVarFlag(entry, "deps", [var] + existing, d) - return - - m = __addhandler_regexp__.match(s) - if m: - fns = m.group(1) - hs = __word__.findall(fns) - bbhands = data.getVar('__BBHANDLERS', d) or [] - for h in hs: - bbhands.append(h) - data.setVarFlag(h, "handler", 1, d) - data.setVar('__BBHANDLERS', bbhands, d) - return - - m = __inherit_regexp__.match(s) - if m: - - files = m.group(1) - n = __word__.findall(files) - inherit(n, d) - return - - from bb.parse import ConfHandler - return ConfHandler.feeder(lineno, s, fn, d) - -__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 - if len(parts) > 3: - raise ParseError("Unable to generate default variables from the filename: %s (too many underscores)" % mypkg) - exp = 3 - len(parts) - tmplist = [] - while exp != 0: - exp -= 1 - tmplist.append(None) - parts.extend(tmplist) - return parts - -# Add us to the handlers list -from bb.parse import handlers -handlers.append({'supports': supports, 'handle': handle, 'init': init}) -del handlers diff --git a/bitbake-dev/lib/bb/parse/parse_py/ConfHandler.py b/bitbake-dev/lib/bb/parse/parse_py/ConfHandler.py deleted file mode 100644 index 23316ada58..0000000000 --- a/bitbake-dev/lib/bb/parse/parse_py/ConfHandler.py +++ /dev/null @@ -1,241 +0,0 @@ -#!/usr/bin/env python -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -""" - class for handling configuration data files - - Reads a .conf file and obtains its metadata - -""" - -# Copyright (C) 2003, 2004 Chris Larson -# Copyright (C) 2003, 2004 Phil Blundell -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import re, bb.data, os, sys -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)$") -__config_regexp__ = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}/]+)(\[(?P<flag>[a-zA-Z0-9\-_+.]+)\])?\s*((?P<colon>:=)|(?P<ques>\?=)|(?P<append>\+=)|(?P<prepend>=\+)|(?P<predot>=\.)|(?P<postdot>\.=)|=)\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$") -__include_regexp__ = re.compile( r"include\s+(.+)" ) -__require_regexp__ = re.compile( r"require\s+(.+)" ) -__export_regexp__ = re.compile( r"export\s+(.+)" ) - -def init(data): - topdir = bb.data.getVar('TOPDIR', data) - if not topdir: - topdir = os.getcwd() - bb.data.setVar('TOPDIR', topdir, data) - if not bb.data.getVar('BBPATH', data): - from pkg_resources import Requirement, resource_filename - bitbake = Requirement.parse("bitbake") - datadir = resource_filename(bitbake, "../share/bitbake") - basedir = resource_filename(bitbake, "..") - bb.data.setVar('BBPATH', '%s:%s:%s' % (topdir, datadir, basedir), data) - - -def supports(fn, d): - return localpath(fn, d)[-5:] == ".conf" - -def localpath(fn, d): - if os.path.exists(fn): - return fn - - if "://" not in fn: - return fn - - localfn = None - try: - localfn = bb.fetch.localpath(fn, d, False) - except bb.MalformedUrl: - pass - - if not localfn: - return fn - return localfn - -def obtain(fn, data): - import sys, bb - fn = bb.data.expand(fn, data) - localfn = bb.data.expand(localpath(fn, data), data) - - if localfn != fn: - dldir = bb.data.getVar('DL_DIR', data, 1) - if not dldir: - bb.msg.debug(1, bb.msg.domain.Parsing, "obtain: DL_DIR not defined") - return localfn - bb.mkdirhier(dldir) - try: - bb.fetch.init([fn], data) - except bb.fetch.NoMethodError: - (type, value, traceback) = sys.exc_info() - 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() - 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() - bb.msg.debug(1, bb.msg.domain.Parsing, "obtain: failed: %s" % value) - return localfn - return localfn - - -def include(oldfn, fn, data, error_out): - """ - - error_out If True a ParseError will be reaised if the to be included - """ - if oldfn == fn: # prevent infinate recursion - return None - - import bb - fn = bb.data.expand(fn, data) - oldfn = bb.data.expand(oldfn, data) - - if not os.path.isabs(fn): - dname = os.path.dirname(oldfn) - bbpath = "%s:%s" % (dname, bb.data.getVar("BBPATH", data, 1)) - abs_fn = bb.which(bbpath, fn) - if abs_fn: - fn = abs_fn - - from bb.parse import handle - try: - ret = handle(fn, data, True) - except IOError: - if error_out: - 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, include = 0): - if include: - inc_string = "including" - else: - inc_string = "reading" - init(data) - - if include == 0: - oldfile = None - else: - oldfile = bb.data.getVar('FILE', data) - - fn = obtain(fn, data) - if not os.path.isabs(fn): - f = None - bbpath = bb.data.getVar("BBPATH", data, 1) or [] - for p in bbpath.split(":"): - currname = os.path.join(p, fn) - if os.access(currname, os.R_OK): - f = open(currname, 'r') - abs_fn = 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') - bb.msg.debug(1, bb.msg.domain.Parsing, "CONF %s %s" % (inc_string,fn)) - abs_fn = fn - - if include: - bb.parse.mark_dependency(data, abs_fn) - - lineno = 0 - bb.data.setVar('FILE', fn, data) - while 1: - lineno = lineno + 1 - s = f.readline() - if not s: break - w = s.strip() - if not w: continue # skip empty lines - s = s.rstrip() - if s[0] == '#': continue # skip comments - while s[-1] == '\\': - s2 = f.readline()[:-1].strip() - lineno = lineno + 1 - s = s[:-1] + s2 - feeder(lineno, s, fn, data) - - if oldfile: - bb.data.setVar('FILE', oldfile, data) - return data - -def feeder(lineno, s, fn, data): - def getFunc(groupd, key, data): - if 'flag' in groupd and groupd['flag'] != None: - return bb.data.getVarFlag(key, groupd['flag'], data) - else: - return bb.data.getVar(key, data) - - m = __config_regexp__.match(s) - if m: - groupd = m.groupdict() - key = groupd["var"] - if "exp" in groupd and groupd["exp"] != None: - bb.data.setVarFlag(key, "export", 1, data) - if "ques" in groupd and groupd["ques"] != None: - val = getFunc(groupd, key, data) - if val == None: - val = groupd["value"] - elif "colon" in groupd and groupd["colon"] != None: - e = data.createCopy() - bb.data.update_data(e) - val = bb.data.expand(groupd["value"], e) - elif "append" in groupd and groupd["append"] != None: - val = "%s %s" % ((getFunc(groupd, key, data) or ""), groupd["value"]) - elif "prepend" in groupd and groupd["prepend"] != None: - val = "%s %s" % (groupd["value"], (getFunc(groupd, key, data) or "")) - elif "postdot" in groupd and groupd["postdot"] != None: - val = "%s%s" % ((getFunc(groupd, key, data) or ""), groupd["value"]) - elif "predot" in groupd and groupd["predot"] != None: - val = "%s%s" % (groupd["value"], (getFunc(groupd, key, data) or "")) - else: - val = groupd["value"] - if 'flag' in groupd and groupd['flag'] != None: - 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) - return - - m = __include_regexp__.match(s) - if m: - s = bb.data.expand(m.group(1), 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, "include required") - return - - m = __export_regexp__.match(s) - if m: - bb.data.setVarFlag(m.group(1), "export", 1, data) - return - - raise ParseError("%s:%d: unparsed line: '%s'" % (fn, lineno, s)); - -# Add us to the handlers list -from bb.parse import handlers -handlers.append({'supports': supports, 'handle': handle, 'init': init}) -del handlers diff --git a/bitbake-dev/lib/bb/parse/parse_py/__init__.py b/bitbake-dev/lib/bb/parse/parse_py/__init__.py deleted file mode 100644 index 9e0e00adda..0000000000 --- a/bitbake-dev/lib/bb/parse/parse_py/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -""" -BitBake Parsers - -File parsers for the BitBake build tools. - -""" - -# Copyright (C) 2003, 2004 Chris Larson -# Copyright (C) 2003, 2004 Phil Blundell -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Based on functions from the base bb module, Copyright 2003 Holger Schurig -__version__ = '1.0' - -__all__ = [ 'ConfHandler', 'BBHandler'] - -import ConfHandler -import BBHandler diff --git a/bitbake-dev/lib/bb/persist_data.py b/bitbake-dev/lib/bb/persist_data.py deleted file mode 100644 index bc4045fe85..0000000000 --- a/bitbake-dev/lib/bb/persist_data.py +++ /dev/null @@ -1,121 +0,0 @@ -# BitBake Persistent Data Store -# -# Copyright (C) 2007 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import bb, os - -try: - import sqlite3 -except ImportError: - try: - from pysqlite2 import dbapi2 as sqlite3 - except ImportError: - bb.msg.fatal(bb.msg.domain.PersistData, "Importing sqlite3 and pysqlite2 failed, please install one of them. Python 2.5 or a 'python-pysqlite2' like package is likely to be what you need.") - -sqlversion = sqlite3.sqlite_version_info -if sqlversion[0] < 3 or (sqlversion[0] == 3 and sqlversion[1] < 3): - bb.msg.fatal(bb.msg.domain.PersistData, "sqlite3 version 3.3.0 or later is required.") - -class PersistData: - """ - BitBake Persistent Data Store - - Used to store data in a central location such that other threads/tasks can - access them at some future date. - - The "domain" is used as a key to isolate each data pool and in this - implementation corresponds to an SQL table. The SQL table consists of a - simple key and value pair. - - Why sqlite? It handles all the locking issues for us. - """ - def __init__(self, d): - self.cachedir = bb.data.getVar("PERSISTENT_DIR", d, True) or bb.data.getVar("CACHE", d, True) - if self.cachedir in [None, '']: - bb.msg.fatal(bb.msg.domain.PersistData, "Please set the 'PERSISTENT_DIR' or 'CACHE' variable.") - try: - os.stat(self.cachedir) - except OSError: - bb.mkdirhier(self.cachedir) - - self.cachefile = os.path.join(self.cachedir,"bb_persist_data.sqlite3") - bb.msg.debug(1, bb.msg.domain.PersistData, "Using '%s' as the persistent data cache" % self.cachefile) - - self.connection = sqlite3.connect(self.cachefile, timeout=5, isolation_level=None) - - def addDomain(self, domain): - """ - Should be called before any domain is used - Creates it if it doesn't exist. - """ - self.connection.execute("CREATE TABLE IF NOT EXISTS %s(key TEXT, value TEXT);" % domain) - - def delDomain(self, domain): - """ - Removes a domain and all the data it contains - """ - self.connection.execute("DROP TABLE IF EXISTS %s;" % domain) - - def getKeyValues(self, domain): - """ - Return a list of key + value pairs for a domain - """ - ret = {} - data = self.connection.execute("SELECT key, value from %s;" % domain) - for row in data: - ret[str(row[0])] = str(row[1]) - - return ret - - def getValue(self, domain, key): - """ - Return the value of a key for a domain - """ - data = self.connection.execute("SELECT * from %s where key=?;" % domain, [key]) - for row in data: - return row[1] - - def setValue(self, domain, key, value): - """ - Sets the value of a key for a domain - """ - data = self.connection.execute("SELECT * from %s where key=?;" % domain, [key]) - rows = 0 - for row in data: - rows = rows + 1 - if rows: - self._execute("UPDATE %s SET value=? WHERE key=?;" % domain, [value, key]) - else: - self._execute("INSERT into %s(key, value) values (?, ?);" % domain, [key, value]) - - def delValue(self, domain, key): - """ - Deletes a key/value pair - """ - self._execute("DELETE from %s where key=?;" % domain, [key]) - - def _execute(self, *query): - while True: - try: - self.connection.execute(*query) - return - except sqlite3.OperationalError, e: - if 'database is locked' in str(e): - continue - raise - - - diff --git a/bitbake-dev/lib/bb/providers.py b/bitbake-dev/lib/bb/providers.py deleted file mode 100644 index 8617251ca3..0000000000 --- a/bitbake-dev/lib/bb/providers.py +++ /dev/null @@ -1,327 +0,0 @@ -# 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 version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import 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 sortPriorities(pn, dataCache, pkg_pn = None): - """ - Reorder pkg_pn by file priority and default preference - """ - - if not pkg_pn: - pkg_pn = dataCache.pkg_pn - - files = pkg_pn[pn] - priorities = {} - for f in files: - priority = dataCache.bbfile_priority[f] - preference = dataCache.pkg_dp[f] - if priority not in priorities: - priorities[priority] = {} - if preference not in priorities[priority]: - priorities[priority][preference] = [] - priorities[priority][preference].append(f) - pri_list = priorities.keys() - pri_list.sort(lambda a, b: a - b) - tmp_pn = [] - for pri in pri_list: - pref_list = priorities[pri].keys() - pref_list.sort(lambda a, b: b - a) - tmp_pref = [] - for pref in pref_list: - tmp_pref.extend(priorities[pri][pref]) - tmp_pn = [tmp_pref] + tmp_pn - - return tmp_pn - -def preferredVersionMatch(pe, pv, pr, preferred_e, preferred_v, preferred_r): - """ - Check if the version pe,pv,pr is the preferred one. - If there is preferred version defined and ends with '%', then pv has to start with that version after removing the '%' - """ - if (pr == preferred_r or preferred_r == None): - if (pe == preferred_e or preferred_e == None): - if preferred_v == pv: - return True - if preferred_v != None and preferred_v.endswith('%') and pv.startswith(preferred_v[:len(preferred_v)-1]): - return True - return False - -def findPreferredProvider(pn, cfgData, dataCache, pkg_pn = None, item = None): - """ - Find the first provider in pkg_pn with a PREFERRED_VERSION set. - """ - - preferred_file = None - preferred_ver = None - - localdata = data.createCopy(cfgData) - bb.data.setVar('OVERRIDES', "pn-%s:%s:%s" % (pn, 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('(\d+:)*(.*)(_.*)*', preferred_v) - if m: - if m.group(1): - preferred_e = int(m.group(1)[:-1]) - else: - preferred_e = None - preferred_v = m.group(2) - if m.group(3): - preferred_r = m.group(3)[1:] - else: - preferred_r = None - else: - preferred_e = None - preferred_r = None - - for file_set in pkg_pn: - for f in file_set: - pe,pv,pr = dataCache.pkg_pepvpr[f] - if preferredVersionMatch(pe, pv, pr, preferred_e, preferred_v, preferred_r): - preferred_file = f - preferred_ver = (pe, pv, pr) - break - if preferred_file: - break; - if preferred_r: - pv_str = '%s-%s' % (preferred_v, preferred_r) - else: - pv_str = preferred_v - if not (preferred_e is None): - pv_str = '%s:%s' % (preferred_e, pv_str) - 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)) - - return (preferred_ver, preferred_file) - - -def findLatestProvider(pn, cfgData, dataCache, file_set): - """ - Return the highest version of the providers in file_set. - Take default preferences into account. - """ - latest = None - latest_p = 0 - latest_f = None - for file_name in file_set: - pe,pv,pr = dataCache.pkg_pepvpr[file_name] - dp = dataCache.pkg_dp[file_name] - - if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pe, pv, pr)) < 0)) or (dp > latest_p): - latest = (pe, pv, pr) - latest_f = file_name - latest_p = dp - - return (latest, latest_f) - - -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. - """ - - sortpkg_pn = sortPriorities(pn, dataCache, pkg_pn) - # Find the highest priority provider with a PREFERRED_VERSION set - (preferred_ver, preferred_file) = findPreferredProvider(pn, cfgData, dataCache, sortpkg_pn, item) - # Find the latest version of the highest priority provider - (latest, latest_f) = findLatestProvider(pn, cfgData, dataCache, sortpkg_pn[0]) - - if preferred_file is None: - preferred_file = latest_f - preferred_ver = latest - - return (latest, latest_f, preferred_ver, preferred_file) - - -def _filterProviders(providers, item, cfgData, dataCache): - """ - Take a list of providers and filter/reorder according to the - environment variables and previous build results - """ - eligible = [] - preferred_versions = {} - sortpkg_pn = {} - - # The order of providers depends on the order of the files on the disk - # up to here. Sort pkg_pn to make dependency issues reproducible rather - # than effectively random. - providers.sort() - - # 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())) - - # First add PREFERRED_VERSIONS - for pn in pkg_pn.keys(): - sortpkg_pn[pn] = sortPriorities(pn, dataCache, pkg_pn) - preferred_versions[pn] = findPreferredProvider(pn, cfgData, dataCache, sortpkg_pn[pn], item) - if preferred_versions[pn][1]: - eligible.append(preferred_versions[pn][1]) - - # Now add latest verisons - for pn in sortpkg_pn.keys(): - if pn in preferred_versions and preferred_versions[pn][1]: - continue - preferred_versions[pn] = findLatestProvider(pn, cfgData, dataCache, sortpkg_pn[pn][0]) - eligible.append(preferred_versions[pn][1]) - - 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 - - return eligible - - -def filterProviders(providers, item, cfgData, dataCache): - """ - Take a list of providers and filter/reorder according to the - environment variables and previous build results - Takes a "normal" target item - """ - - eligible = _filterProviders(providers, item, cfgData, dataCache) - - prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, cfgData, 1) - if prefervar: - dataCache.preferred[item] = prefervar - - foundUnique = 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 - foundUnique = True - break - - bb.msg.debug(1, bb.msg.domain.Provider, "sorted providers for %s are: %s" % (item, eligible)) - - return eligible, foundUnique - -def filterProvidersRunTime(providers, item, cfgData, dataCache): - """ - Take a list of providers and filter/reorder according to the - environment variables and previous build results - Takes a "runtime" target item - """ - - eligible = _filterProviders(providers, item, cfgData, dataCache) - - # Should use dataCache.preferred here? - preferred = [] - preferred_vars = [] - for p in eligible: - pn = dataCache.pkg_fn[p] - provides = dataCache.pn_provides[pn] - for provide in provides: - bb.msg.note(2, bb.msg.domain.Provider, "checking PREFERRED_PROVIDER_%s" % (provide)) - prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % provide, cfgData, 1) - if prefervar == pn: - var = "PREFERRED_PROVIDER_%s = %s" % (provide, prefervar) - bb.msg.note(2, bb.msg.domain.Provider, "selecting %s to satisfy runtime %s due to %s" % (pn, item, var)) - preferred_vars.append(var) - eligible.remove(p) - eligible = [p] + eligible - preferred.append(p) - break - - numberPreferred = len(preferred) - - if numberPreferred > 1: - bb.msg.error(bb.msg.domain.Provider, "Conflicting PREFERRED_PROVIDER entries were found which resulted in an attempt to select multiple providers (%s) for runtime dependecy %s\nThe entries resulting in this conflict were: %s" % (preferred, item, preferred_vars)) - - bb.msg.debug(1, bb.msg.domain.Provider, "sorted providers for %s are: %s" % (item, eligible)) - - return eligible, numberPreferred - -regexp_cache = {} - -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: - pattern = pattern.replace('+', "\+") - if pattern in regexp_cache: - regexp = regexp_cache[pattern] - else: - try: - regexp = re.compile(pattern) - except: - bb.msg.error(bb.msg.domain.Provider, "Error parsing re expression: %s" % pattern) - raise - regexp_cache[pattern] = regexp - if regexp.match(rdepend): - rproviders += dataCache.packages_dynamic[pattern] - - return rproviders diff --git a/bitbake-dev/lib/bb/runqueue.py b/bitbake-dev/lib/bb/runqueue.py deleted file mode 100644 index c3ad442e47..0000000000 --- a/bitbake-dev/lib/bb/runqueue.py +++ /dev/null @@ -1,1174 +0,0 @@ -#!/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-2007 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -from bb import msg, data, event, mkdirhier, utils -import bb, os, sys -import signal -import stat - -class TaskFailure(Exception): - """Exception raised when a task in a runqueue fails""" - def __init__(self, x): - self.args = x - - -class RunQueueStats: - """ - Holds statistics on the tasks handled by the associated runQueue - """ - def __init__(self, total): - self.completed = 0 - self.skipped = 0 - self.failed = 0 - self.active = 0 - self.total = total - - def taskFailed(self): - self.active = self.active - 1 - self.failed = self.failed + 1 - - def taskCompleted(self, number = 1): - self.active = self.active - number - self.completed = self.completed + number - - def taskSkipped(self, number = 1): - self.active = self.active + number - self.skipped = self.skipped + number - - def taskActive(self): - self.active = self.active + 1 - -# These values indicate the next step due to be run in the -# runQueue state machine -runQueuePrepare = 2 -runQueueRunInit = 3 -runQueueRunning = 4 -runQueueFailed = 6 -runQueueCleanUp = 7 -runQueueComplete = 8 -runQueueChildProcess = 9 - -class RunQueueScheduler: - """ - Control the order tasks are scheduled in. - """ - def __init__(self, runqueue): - """ - The default scheduler just returns the first buildable task (the - priority map is sorted by task numer) - """ - self.rq = runqueue - numTasks = len(self.rq.runq_fnid) - - self.prio_map = [] - self.prio_map.extend(range(numTasks)) - - def next(self): - """ - Return the id of the first task we find that is buildable - """ - for task1 in range(len(self.rq.runq_fnid)): - task = self.prio_map[task1] - if self.rq.runq_running[task] == 1: - continue - if self.rq.runq_buildable[task] == 1: - return task - -class RunQueueSchedulerSpeed(RunQueueScheduler): - """ - A scheduler optimised for speed. The priority map is sorted by task weight, - heavier weighted tasks (tasks needed by the most other tasks) are run first. - """ - def __init__(self, runqueue): - """ - The priority map is sorted by task weight. - """ - from copy import deepcopy - - self.rq = runqueue - - sortweight = deepcopy(self.rq.runq_weight) - sortweight.sort() - copyweight = deepcopy(self.rq.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() - -class RunQueueSchedulerCompletion(RunQueueSchedulerSpeed): - """ - A scheduler optimised to complete .bb files are quickly as possible. The - priority map is sorted by task weight, but then reordered so once a given - .bb file starts to build, its completed as quickly as possible. This works - well where disk space is at a premium and classes like OE's rm_work are in - force. - """ - def __init__(self, runqueue): - RunQueueSchedulerSpeed.__init__(self, runqueue) - from copy import deepcopy - - #FIXME - whilst this groups all fnids together it does not reorder the - #fnid groups optimally. - - basemap = deepcopy(self.prio_map) - self.prio_map = [] - while (len(basemap) > 0): - entry = basemap.pop(0) - self.prio_map.append(entry) - fnid = self.rq.runq_fnid[entry] - todel = [] - for entry in basemap: - entry_fnid = self.rq.runq_fnid[entry] - if entry_fnid == fnid: - todel.append(basemap.index(entry)) - self.prio_map.append(entry) - todel.reverse() - for idx in todel: - del basemap[idx] - -class RunQueue: - """ - BitBake Run Queue implementation - """ - def __init__(self, cooker, cfgData, dataCache, taskData, targets): - self.reset_runqueue() - self.cooker = cooker - self.dataCache = dataCache - self.taskData = taskData - self.cfgData = cfgData - self.targets = targets - - self.number_tasks = int(bb.data.getVar("BB_NUMBER_THREADS", cfgData, 1) or 1) - self.multi_provider_whitelist = (bb.data.getVar("MULTI_PROVIDER_WHITELIST", cfgData, 1) or "").split() - self.scheduler = bb.data.getVar("BB_SCHEDULER", cfgData, 1) or "speed" - self.stamppolicy = bb.data.getVar("BB_STAMP_POLICY", cfgData, 1) or "perfile" - self.stampwhitelist = bb.data.getVar("BB_STAMP_WHITELIST", cfgData, 1) or "" - - def reset_runqueue(self): - self.runq_fnid = [] - self.runq_task = [] - self.runq_depends = [] - self.runq_revdeps = [] - - self.state = runQueuePrepare - - def get_user_idstring(self, task): - fn = self.taskData.fn_index[self.runq_fnid[task]] - taskname = self.runq_task[task] - return "%s, %s" % (fn, taskname) - - def get_task_id(self, fnid, taskname): - for listid in range(len(self.runq_fnid)): - if self.runq_fnid[listid] == fnid and self.runq_task[listid] == taskname: - return listid - return None - - def circular_depchains_handler(self, tasks): - """ - Some tasks aren't buildable, likely due to circular dependency issues. - Identify the circular dependencies and print them in a user readable format. - """ - from copy import deepcopy - - valid_chains = [] - explored_deps = {} - msgs = [] - - def chain_reorder(chain): - """ - Reorder a dependency chain so the lowest task id is first - """ - lowest = 0 - new_chain = [] - for entry in range(len(chain)): - if chain[entry] < chain[lowest]: - lowest = entry - new_chain.extend(chain[lowest:]) - new_chain.extend(chain[:lowest]) - return new_chain - - def chain_compare_equal(chain1, chain2): - """ - Compare two dependency chains and see if they're the same - """ - if len(chain1) != len(chain2): - return False - for index in range(len(chain1)): - if chain1[index] != chain2[index]: - return False - return True - - def chain_array_contains(chain, chain_array): - """ - Return True if chain_array contains chain - """ - for ch in chain_array: - if chain_compare_equal(ch, chain): - return True - return False - - def find_chains(taskid, prev_chain): - prev_chain.append(taskid) - total_deps = [] - total_deps.extend(self.runq_revdeps[taskid]) - for revdep in self.runq_revdeps[taskid]: - if revdep in prev_chain: - idx = prev_chain.index(revdep) - # To prevent duplicates, reorder the chain to start with the lowest taskid - # and search through an array of those we've already printed - chain = prev_chain[idx:] - new_chain = chain_reorder(chain) - if not chain_array_contains(new_chain, valid_chains): - valid_chains.append(new_chain) - msgs.append("Dependency loop #%d found:\n" % len(valid_chains)) - for dep in new_chain: - msgs.append(" Task %s (%s) (depends: %s)\n" % (dep, self.get_user_idstring(dep), self.runq_depends[dep])) - msgs.append("\n") - if len(valid_chains) > 10: - msgs.append("Aborted dependency loops search after 10 matches.\n") - return msgs - continue - scan = False - if revdep not in explored_deps: - scan = True - elif revdep in explored_deps[revdep]: - scan = True - else: - for dep in prev_chain: - if dep in explored_deps[revdep]: - scan = True - if scan: - find_chains(revdep, deepcopy(prev_chain)) - for dep in explored_deps[revdep]: - if dep not in total_deps: - total_deps.append(dep) - - explored_deps[taskid] = total_deps - - for task in tasks: - find_chains(task, []) - - return msgs - - def calculate_task_weights(self, endpoints): - """ - Calculate a number representing the "weight" of each task. Heavier weighted tasks - have more dependencies and hence should be executed sooner for maximum speed. - - This function also sanity checks the task list finding tasks that its not - possible to execute due to circular dependencies. - """ - - numTasks = len(self.runq_fnid) - weight = [] - deps_left = [] - task_done = [] - - for listid in range(numTasks): - task_done.append(False) - weight.append(0) - deps_left.append(len(self.runq_revdeps[listid])) - - for listid in endpoints: - weight[listid] = 1 - task_done[listid] = True - - while 1: - next_points = [] - for listid in endpoints: - for revdep in self.runq_depends[listid]: - weight[revdep] = weight[revdep] + weight[listid] - deps_left[revdep] = deps_left[revdep] - 1 - if deps_left[revdep] == 0: - next_points.append(revdep) - task_done[revdep] = True - endpoints = next_points - if len(next_points) == 0: - break - - # Circular dependency sanity check - problem_tasks = [] - for task in range(numTasks): - if task_done[task] is False or deps_left[task] != 0: - problem_tasks.append(task) - bb.msg.debug(2, bb.msg.domain.RunQueue, "Task %s (%s) is not buildable\n" % (task, self.get_user_idstring(task))) - bb.msg.debug(2, bb.msg.domain.RunQueue, "(Complete marker was %s and the remaining dependency count was %s)\n\n" % (task_done[task], deps_left[task])) - - if problem_tasks: - message = "Unbuildable tasks were found.\n" - message = message + "These are usually caused by circular dependencies and any circular dependency chains found will be printed below. Increase the debug level to see a list of unbuildable tasks.\n\n" - message = message + "Identifying dependency loops (this may take a short while)...\n" - bb.msg.error(bb.msg.domain.RunQueue, message) - - msgs = self.circular_depchains_handler(problem_tasks) - - message = "\n" - for msg in msgs: - message = message + msg - bb.msg.fatal(bb.msg.domain.RunQueue, message) - - return weight - - def prepare_runqueue(self): - """ - Turn a set of taskData into a RunQueue and compute data needed - to optimise the execution order. - """ - - runq_build = [] - recursive_tdepends = {} - runq_recrdepends = [] - tdepends_fnid = {} - - taskData = self.taskData - - if len(taskData.tasks_name) == 0: - # Nothing to do - return - - bb.msg.note(1, bb.msg.domain.RunQueue, "Preparing runqueue") - - # Step A - Work out a list of tasks to run - # - # Taskdata gives us a list of possible providers for every build and run - # target ordered by priority. It also gives information on each of those - # providers. - # - # To create the actual list of tasks to execute we fix the list of - # providers and then resolve the dependencies into task IDs. This - # process is repeated for each type of dependency (tdepends, deptask, - # rdeptast, recrdeptask, idepends). - - def add_build_dependencies(depids, tasknames, depends): - for depid in depids: - # Won't be in build_targets if ASSUME_PROVIDED - if depid not in taskData.build_targets: - continue - depdata = taskData.build_targets[depid][0] - if depdata is None: - continue - dep = taskData.fn_index[depdata] - for taskname in tasknames: - taskid = taskData.gettask_id(dep, taskname, False) - if taskid is not None: - depends.append(taskid) - - def add_runtime_dependencies(depids, tasknames, depends): - for depid in depids: - if depid not in taskData.run_targets: - continue - depdata = taskData.run_targets[depid][0] - if depdata is None: - continue - dep = taskData.fn_index[depdata] - for taskname in tasknames: - taskid = taskData.gettask_id(dep, taskname, False) - if taskid is not None: - depends.append(taskid) - - for task in range(len(taskData.tasks_name)): - depends = [] - recrdepends = [] - fnid = taskData.tasks_fnid[task] - fn = taskData.fn_index[fnid] - task_deps = self.dataCache.task_deps[fn] - - bb.msg.debug(2, bb.msg.domain.RunQueue, "Processing %s:%s" %(fn, taskData.tasks_name[task])) - - if fnid not in taskData.failed_fnids: - - # Resolve task internal dependencies - # - # e.g. addtask before X after Y - depends = taskData.tasks_tdepends[task] - - # Resolve 'deptask' dependencies - # - # e.g. do_sometask[deptask] = "do_someothertask" - # (makes sure sometask runs after someothertask of all DEPENDS) - if 'deptask' in task_deps and taskData.tasks_name[task] in task_deps['deptask']: - tasknames = task_deps['deptask'][taskData.tasks_name[task]].split() - add_build_dependencies(taskData.depids[fnid], tasknames, depends) - - # Resolve 'rdeptask' dependencies - # - # e.g. do_sometask[rdeptask] = "do_someothertask" - # (makes sure sometask runs after someothertask of all RDEPENDS) - if 'rdeptask' in task_deps and taskData.tasks_name[task] in task_deps['rdeptask']: - taskname = task_deps['rdeptask'][taskData.tasks_name[task]] - add_runtime_dependencies(taskData.rdepids[fnid], [taskname], depends) - - # Resolve inter-task dependencies - # - # e.g. do_sometask[depends] = "targetname:do_someothertask" - # (makes sure sometask runs after targetname's someothertask) - if fnid not in tdepends_fnid: - tdepends_fnid[fnid] = set() - idepends = taskData.tasks_idepends[task] - for (depid, idependtask) in idepends: - if depid in taskData.build_targets: - # Won't be in build_targets if ASSUME_PROVIDED - depdata = taskData.build_targets[depid][0] - if depdata is not None: - dep = taskData.fn_index[depdata] - taskid = taskData.gettask_id(dep, idependtask) - depends.append(taskid) - if depdata != fnid: - tdepends_fnid[fnid].add(taskid) - - - # Resolve recursive 'recrdeptask' dependencies (A) - # - # e.g. do_sometask[recrdeptask] = "do_someothertask" - # (makes sure sometask runs after someothertask of all DEPENDS, RDEPENDS and intertask dependencies, recursively) - # We cover the recursive part of the dependencies below - if 'recrdeptask' in task_deps and taskData.tasks_name[task] in task_deps['recrdeptask']: - for taskname in task_deps['recrdeptask'][taskData.tasks_name[task]].split(): - recrdepends.append(taskname) - add_build_dependencies(taskData.depids[fnid], [taskname], depends) - add_runtime_dependencies(taskData.rdepids[fnid], [taskname], depends) - - # Rmove all 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()) - - runq_build.append(0) - runq_recrdepends.append(recrdepends) - - # - # Build a list of recursive cumulative dependencies for each fnid - # We do this by fnid, since if A depends on some task in B - # we're interested in later tasks B's fnid might have but B itself - # doesn't depend on - # - # Algorithm is O(tasks) + O(tasks)*O(fnids) - # - reccumdepends = {} - for task in range(len(self.runq_fnid)): - fnid = self.runq_fnid[task] - if fnid not in reccumdepends: - if fnid in tdepends_fnid: - reccumdepends[fnid] = tdepends_fnid[fnid] - else: - reccumdepends[fnid] = set() - reccumdepends[fnid].update(self.runq_depends[task]) - for task in range(len(self.runq_fnid)): - taskfnid = self.runq_fnid[task] - for fnid in reccumdepends: - if task in reccumdepends[fnid]: - reccumdepends[fnid].add(task) - if taskfnid in reccumdepends: - reccumdepends[fnid].update(reccumdepends[taskfnid]) - - - # Resolve recursive 'recrdeptask' dependencies (B) - # - # e.g. do_sometask[recrdeptask] = "do_someothertask" - # (makes sure sometask runs after someothertask of all DEPENDS, RDEPENDS and intertask dependencies, recursively) - for task in range(len(self.runq_fnid)): - if len(runq_recrdepends[task]) > 0: - taskfnid = self.runq_fnid[task] - for dep in reccumdepends[taskfnid]: - # Ignore self references - if dep == task: - continue - for taskname in runq_recrdepends[task]: - if taskData.tasks_name[dep] == taskname: - self.runq_depends[task].add(dep) - - # Step B - Mark all active tasks - # - # Start with the tasks we were asked to run and mark all dependencies - # as active too. If the task is to be 'forced', clear its stamp. Once - # all active tasks are marked, prune the ones we don't need. - - 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) - - self.target_pairs = [] - for target in self.targets: - targetid = taskData.getbuild_id(target[0]) - - if targetid not in taskData.build_targets: - continue - - if targetid in taskData.failed_deps: - continue - - fnid = taskData.build_targets[targetid][0] - fn = taskData.fn_index[fnid] - self.target_pairs.append((fn, target[1])) - - # Remove stamps for targets if force mode active - if self.cooker.configuration.force: - bb.msg.note(2, bb.msg.domain.RunQueue, "Remove stamp %s, %s" % (target[1], fn)) - bb.build.del_stamp(target[1], self.dataCache, fn) - - if fnid in taskData.failed_fnids: - continue - - if target[1] not in taskData.tasks_lookup[fnid]: - bb.msg.fatal(bb.msg.domain.RunQueue, "Task %s does not exist for target %s" % (target[1], target[0])) - - listid = taskData.tasks_lookup[fnid][target[1]] - - mark_active(listid, 1) - - # Step C - Prune all inactive tasks - # - # Once all active tasks are marked, prune the ones we don't need. - - 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 runq_build[listid-delcount] - del self.runq_revdeps[listid-delcount] - delcount = delcount + 1 - maps.append(-1) - - # - # Step D - Sanity checks and computation - # - - # Check to make sure we still have tasks to run - if len(self.runq_fnid) == 0: - if not taskData.abort: - bb.msg.fatal(bb.msg.domain.RunQueue, "All buildable tasks have been run but the build is incomplete (--continue mode). Errors for the tasks that failed will have been printed above.") - else: - 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))) - - # Remap the dependencies to account for the deleted tasks - # Check we didn't delete a task we depend on - 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") - - # Generate a list of reverse dependencies to ease future calculations - for listid in range(len(self.runq_fnid)): - for dep in self.runq_depends[listid]: - self.runq_revdeps[dep].add(listid) - - # Identify tasks at the end of dependency chains - # Error on circular dependency loops (length two) - endpoints = [] - for listid in range(len(self.runq_fnid)): - revdeps = self.runq_revdeps[listid] - if len(revdeps) == 0: - 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])) - - bb.msg.note(2, bb.msg.domain.RunQueue, "Compute totals (have %s endpoint(s))" % len(endpoints)) - - # Calculate task weights - # Check of higher length circular dependencies - self.runq_weight = self.calculate_task_weights(endpoints) - - # Decide what order to execute the tasks in, pick a scheduler - #self.sched = RunQueueScheduler(self) - if self.scheduler == "completion": - self.sched = RunQueueSchedulerCompletion(self) - else: - self.sched = RunQueueSchedulerSpeed(self) - - # Sanity Check - Check for multiple tasks building the same provider - prov_list = {} - seen_fn = [] - for task in range(len(self.runq_fnid)): - fn = taskData.fn_index[self.runq_fnid[task]] - if fn in seen_fn: - continue - seen_fn.append(fn) - for prov in self.dataCache.fn_provides[fn]: - if prov not in prov_list: - prov_list[prov] = [fn] - elif fn not in prov_list[prov]: - prov_list[prov].append(fn) - error = False - for prov in prov_list: - if len(prov_list[prov]) > 1 and prov not in self.multi_provider_whitelist: - error = True - bb.msg.error(bb.msg.domain.RunQueue, "Multiple .bb files are due to be built which each provide %s (%s).\n This usually means one provides something the other doesn't and should." % (prov, " ".join(prov_list[prov]))) - #if error: - # bb.msg.fatal(bb.msg.domain.RunQueue, "Corrupted metadata configuration detected, aborting...") - - - # Create a whitelist usable by the stamp checks - stampfnwhitelist = [] - for entry in self.stampwhitelist.split(): - entryid = self.taskData.getbuild_id(entry) - if entryid not in self.taskData.build_targets: - continue - fnid = self.taskData.build_targets[entryid][0] - fn = self.taskData.fn_index[fnid] - stampfnwhitelist.append(fn) - self.stampfnwhitelist = stampfnwhitelist - - #self.dump_data(taskData) - - self.state = runQueueRunInit - - def check_stamps(self): - unchecked = {} - current = [] - notcurrent = [] - buildable = [] - - if self.stamppolicy == "perfile": - fulldeptree = False - else: - fulldeptree = True - stampwhitelist = [] - if self.stamppolicy == "whitelist": - stampwhitelist = self.self.stampfnwhitelist - - for task in range(len(self.runq_fnid)): - unchecked[task] = "" - if len(self.runq_depends[task]) == 0: - buildable.append(task) - - def check_buildable(self, task, buildable): - for revdep in self.runq_revdeps[task]: - alldeps = 1 - for dep in self.runq_depends[revdep]: - if dep in unchecked: - alldeps = 0 - if alldeps == 1: - if revdep in unchecked: - buildable.append(revdep) - - for task in range(len(self.runq_fnid)): - if task not in unchecked: - continue - fn = self.taskData.fn_index[self.runq_fnid[task]] - taskname = self.runq_task[task] - stampfile = "%s.%s" % (self.dataCache.stamp[fn], taskname) - # If the stamp is missing its not current - if not os.access(stampfile, os.F_OK): - del unchecked[task] - notcurrent.append(task) - check_buildable(self, task, buildable) - continue - # If its a 'nostamp' task, it's not current - taskdep = self.dataCache.task_deps[fn] - if 'nostamp' in taskdep and task in taskdep['nostamp']: - del unchecked[task] - notcurrent.append(task) - check_buildable(self, task, buildable) - continue - - while (len(buildable) > 0): - nextbuildable = [] - for task in buildable: - if task in unchecked: - fn = self.taskData.fn_index[self.runq_fnid[task]] - taskname = self.runq_task[task] - stampfile = "%s.%s" % (self.dataCache.stamp[fn], taskname) - iscurrent = True - - t1 = os.stat(stampfile)[stat.ST_MTIME] - for dep in self.runq_depends[task]: - if iscurrent: - fn2 = self.taskData.fn_index[self.runq_fnid[dep]] - taskname2 = self.runq_task[dep] - stampfile2 = "%s.%s" % (self.dataCache.stamp[fn2], taskname2) - if fn == fn2 or (fulldeptree and fn2 not in stampwhitelist): - if dep in notcurrent: - iscurrent = False - else: - t2 = os.stat(stampfile2)[stat.ST_MTIME] - if t1 < t2: - iscurrent = False - del unchecked[task] - if iscurrent: - current.append(task) - else: - notcurrent.append(task) - - check_buildable(self, task, nextbuildable) - - buildable = nextbuildable - - #for task in range(len(self.runq_fnid)): - # fn = self.taskData.fn_index[self.runq_fnid[task]] - # taskname = self.runq_task[task] - # print "%s %s.%s" % (task, taskname, fn) - - #print "Unchecked: %s" % unchecked - #print "Current: %s" % current - #print "Not current: %s" % notcurrent - - if len(unchecked) > 0: - bb.fatal("check_stamps fatal internal error") - return current - - def check_stamp_task(self, task): - - if self.stamppolicy == "perfile": - fulldeptree = False - else: - fulldeptree = True - stampwhitelist = [] - if self.stamppolicy == "whitelist": - stampwhitelist = self.stampfnwhitelist - - fn = self.taskData.fn_index[self.runq_fnid[task]] - taskname = self.runq_task[task] - stampfile = "%s.%s" % (self.dataCache.stamp[fn], taskname) - # If the stamp is missing its not current - if not os.access(stampfile, os.F_OK): - bb.msg.debug(2, bb.msg.domain.RunQueue, "Stampfile %s not available\n" % stampfile) - return False - # If its a 'nostamp' task, it's not current - taskdep = self.dataCache.task_deps[fn] - if 'nostamp' in taskdep and taskname in taskdep['nostamp']: - bb.msg.debug(2, bb.msg.domain.RunQueue, "%s.%s is nostamp\n" % (fn, taskname)) - return False - - iscurrent = True - t1 = os.stat(stampfile)[stat.ST_MTIME] - for dep in self.runq_depends[task]: - if iscurrent: - fn2 = self.taskData.fn_index[self.runq_fnid[dep]] - taskname2 = self.runq_task[dep] - stampfile2 = "%s.%s" % (self.dataCache.stamp[fn2], taskname2) - if fn == fn2 or (fulldeptree and fn2 not in stampwhitelist): - try: - t2 = os.stat(stampfile2)[stat.ST_MTIME] - if t1 < t2: - bb.msg.debug(2, bb.msg.domain.RunQueue, "Stampfile %s < %s" % (stampfile,stampfile2)) - iscurrent = False - except: - bb.msg.debug(2, bb.msg.domain.RunQueue, "Exception reading %s for %s" % (stampfile2 ,stampfile)) - iscurrent = False - - return iscurrent - - def execute_runqueue(self): - """ - 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) - """ - - if self.state is runQueuePrepare: - self.prepare_runqueue() - - if self.state is runQueueRunInit: - bb.msg.note(1, bb.msg.domain.RunQueue, "Executing runqueue") - self.execute_runqueue_initVars() - - if self.state is runQueueRunning: - self.execute_runqueue_internal() - - if self.state is runQueueCleanUp: - self.finish_runqueue() - - if self.state is runQueueFailed: - if not self.taskData.tryaltconfigs: - raise bb.runqueue.TaskFailure(self.failed_fnids) - for fnid in self.failed_fnids: - self.taskData.fail_fnid(fnid) - self.reset_runqueue() - - if self.state is runQueueComplete: - # All done - bb.msg.note(1, bb.msg.domain.RunQueue, "Tasks Summary: Attempted %d tasks of which %d didn't need to be rerun and %d failed." % (self.stats.completed, self.stats.skipped, self.stats.failed)) - return False - - if self.state is runQueueChildProcess: - print "Child process" - return False - - # Loop - return True - - def execute_runqueue_initVars(self): - - self.stats = RunQueueStats(len(self.runq_fnid)) - - self.runq_buildable = [] - self.runq_running = [] - self.runq_complete = [] - self.build_pids = {} - self.build_pipes = {} - self.failed_fnids = [] - - # Mark initial buildable tasks - for task in range(self.stats.total): - self.runq_running.append(0) - self.runq_complete.append(0) - if len(self.runq_depends[task]) == 0: - self.runq_buildable.append(1) - else: - self.runq_buildable.append(0) - - self.state = runQueueRunning - - event.fire(bb.event.StampUpdate(self.target_pairs, self.dataCache.stamp), self.cfgData) - - def task_complete(self, task): - """ - Mark a task as completed - Look at the reverse dependencies and mark any task with - completed dependencies as buildable - """ - self.runq_complete[task] = 1 - for revdep in self.runq_revdeps[task]: - if self.runq_running[revdep] == 1: - continue - if self.runq_buildable[revdep] == 1: - continue - alldeps = 1 - for dep in self.runq_depends[revdep]: - if self.runq_complete[dep] != 1: - alldeps = 0 - if alldeps == 1: - self.runq_buildable[revdep] = 1 - fn = self.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)) - - def task_fail(self, task, exitcode): - """ - Called when a task has failed - Updates the state engine with the failure - """ - bb.msg.error(bb.msg.domain.RunQueue, "Task %s (%s) failed with %s" % (task, self.get_user_idstring(task), exitcode)) - self.stats.taskFailed() - fnid = self.runq_fnid[task] - self.failed_fnids.append(fnid) - bb.event.fire(runQueueTaskFailed(task, self.stats, self), self.cfgData) - if self.taskData.abort: - self.state = runQueueCleanup - - def execute_runqueue_internal(self): - """ - Run the tasks in a queue prepared by prepare_runqueue - """ - - if self.stats.total == 0: - # nothing to do - self.state = runQueueCleanup - - while True: - task = None - if self.stats.active < self.number_tasks: - task = self.sched.next() - if task is not None: - fn = self.taskData.fn_index[self.runq_fnid[task]] - - taskname = self.runq_task[task] - if self.check_stamp_task(task): - bb.msg.debug(2, bb.msg.domain.RunQueue, "Stamp current task %s (%s)" % (task, self.get_user_idstring(task))) - self.runq_running[task] = 1 - self.runq_buildable[task] = 1 - self.task_complete(task) - self.stats.taskCompleted() - self.stats.taskSkipped() - continue - - sys.stdout.flush() - sys.stderr.flush() - try: - pipein, pipeout = os.pipe() - pid = os.fork() - except OSError, e: - bb.msg.fatal(bb.msg.domain.RunQueue, "fork failed: %d (%s)" % (e.errno, e.strerror)) - if pid == 0: - os.close(pipein) - # Save out the PID so that the event can include it the - # events - bb.event.worker_pid = os.getpid() - bb.event.worker_pipe = pipeout - - self.state = runQueueChildProcess - # Make the child the process group leader - os.setpgid(0, 0) - # No stdin - newsi = os.open('/dev/null', os.O_RDWR) - os.dup2(newsi, sys.stdin.fileno()) - - bb.event.fire(runQueueTaskStarted(task, self.stats, self), self.cfgData) - bb.msg.note(1, bb.msg.domain.RunQueue, - "Running task %d of %d (ID: %s, %s)" % (self.stats.completed + self.stats.active + 1, - self.stats.total, - task, - self.get_user_idstring(task))) - - bb.data.setVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY", self, self.cooker.configuration.data) - try: - self.cooker.tryBuild(fn, taskname[3:]) - except bb.build.EventException: - bb.msg.error(bb.msg.domain.Build, "Build of " + fn + " " + taskname + " failed") - os._exit(1) - except: - bb.msg.error(bb.msg.domain.Build, "Build of " + fn + " " + taskname + " failed") - os._exit(1) - os._exit(0) - - self.build_pids[pid] = task - self.build_pipes[pid] = runQueuePipe(pipein, pipeout, self.cfgData) - self.runq_running[task] = 1 - self.stats.taskActive() - if self.stats.active < self.number_tasks: - continue - - for pipe in self.build_pipes: - self.build_pipes[pipe].read() - - if self.stats.active > 0: - result = os.waitpid(-1, os.WNOHANG) - if result[0] is 0 and result[1] is 0: - return - task = self.build_pids[result[0]] - del self.build_pids[result[0]] - self.build_pipes[result[0]].close() - del self.build_pipes[result[0]] - if result[1] != 0: - self.task_fail(task, result[1]) - return - self.task_complete(task) - self.stats.taskCompleted() - bb.event.fire(runQueueTaskCompleted(task, self.stats, self), self.cfgData) - continue - - if len(self.failed_fnids) != 0: - self.state = runQueueFailed - return - - # Sanity Checks - for task in range(self.stats.total): - if self.runq_buildable[task] == 0: - bb.msg.error(bb.msg.domain.RunQueue, "Task %s never buildable!" % task) - if self.runq_running[task] == 0: - bb.msg.error(bb.msg.domain.RunQueue, "Task %s never ran!" % task) - if self.runq_complete[task] == 0: - bb.msg.error(bb.msg.domain.RunQueue, "Task %s never completed!" % task) - self.state = runQueueComplete - return - - def finish_runqueue_now(self): - bb.msg.note(1, bb.msg.domain.RunQueue, "Sending SIGINT to remaining %s tasks" % self.stats.active) - for k, v in self.build_pids.iteritems(): - try: - os.kill(-k, signal.SIGINT) - except: - pass - for pipe in self.build_pipes: - self.build_pipes[pipe].read() - - def finish_runqueue(self, now = False): - self.state = runQueueCleanUp - if now: - self.finish_runqueue_now() - try: - while self.stats.active > 0: - bb.event.fire(runQueueExitWait(self.stats.active), self.cfgData) - bb.msg.note(1, bb.msg.domain.RunQueue, "Waiting for %s active tasks to finish" % self.stats.active) - tasknum = 1 - for k, v in self.build_pids.iteritems(): - bb.msg.note(1, bb.msg.domain.RunQueue, "%s: %s (%s)" % (tasknum, self.get_user_idstring(v), k)) - tasknum = tasknum + 1 - result = os.waitpid(-1, os.WNOHANG) - if result[0] is 0 and result[1] is 0: - return - task = self.build_pids[result[0]] - del self.build_pids[result[0]] - self.build_pipes[result[0]].close() - del self.build_pipes[result[0]] - if result[1] != 0: - self.task_fail(task, result[1]) - else: - self.stats.taskCompleted() - bb.event.fire(runQueueTaskCompleted(task, self.stats, self), self.cfgData) - except: - self.finish_runqueue_now() - raise - - if len(self.failed_fnids) != 0: - self.state = runQueueFailed - return - - self.state = runQueueComplete - return - - 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_task)): - 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_task)): - 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])) - - -class TaskFailure(Exception): - """ - Exception raised when a task in a runqueue fails - """ - def __init__(self, x): - self.args = x - - -class runQueueExitWait(bb.event.Event): - """ - Event when waiting for task processes to exit - """ - - def __init__(self, remain): - self.remain = remain - self.message = "Waiting for %s active tasks to finish" % remain - bb.event.Event.__init__(self) - -class runQueueEvent(bb.event.Event): - """ - Base runQueue event class - """ - def __init__(self, task, stats, rq): - self.taskid = task - self.taskstring = rq.get_user_idstring(task) - self.stats = stats - bb.event.Event.__init__(self) - -class runQueueTaskStarted(runQueueEvent): - """ - Event notifing a task was started - """ - def __init__(self, task, stats, rq): - runQueueEvent.__init__(self, task, stats, rq) - self.message = "Running task %s (%d of %d) (%s)" % (task, stats.completed + stats.active + 1, self.stats.total, self.taskstring) - -class runQueueTaskFailed(runQueueEvent): - """ - Event notifing a task failed - """ - def __init__(self, task, stats, rq): - runQueueEvent.__init__(self, task, stats, rq) - self.message = "Task %s failed (%s)" % (task, self.taskstring) - -class runQueueTaskCompleted(runQueueEvent): - """ - Event notifing a task completed - """ - def __init__(self, task, stats, rq): - runQueueEvent.__init__(self, task, stats, rq) - self.message = "Task %s completed (%s)" % (task, self.taskstring) - -def check_stamp_fn(fn, taskname, d): - rq = bb.data.getVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY", d) - fnid = rq.taskData.getfn_id(fn) - taskid = rq.get_task_id(fnid, taskname) - if taskid is not None: - return rq.check_stamp_task(taskid) - return None - -class runQueuePipe(): - """ - Abstraction for a pipe between a worker thread and the server - """ - def __init__(self, pipein, pipeout, d): - self.fd = pipein - os.close(pipeout) - self.queue = "" - self.d = d - - def read(self): - start = len(self.queue) - self.queue = self.queue + os.read(self.fd, 1024) - end = len(self.queue) - index = self.queue.find("</event>") - while index != -1: - bb.event.fire_from_worker(self.queue[:index+8], self.d) - self.queue = self.queue[index+8:] - index = self.queue.find("</event>") - return (end > start) - - def close(self): - while self.read(): - continue - if len(self.queue) > 0: - print "Warning, worker left partial message" - os.close(self.fd) - diff --git a/bitbake-dev/lib/bb/server/__init__.py b/bitbake-dev/lib/bb/server/__init__.py deleted file mode 100644 index 1a732236e2..0000000000 --- a/bitbake-dev/lib/bb/server/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -import xmlrpc -import none diff --git a/bitbake-dev/lib/bb/server/none.py b/bitbake-dev/lib/bb/server/none.py deleted file mode 100644 index ebda111582..0000000000 --- a/bitbake-dev/lib/bb/server/none.py +++ /dev/null @@ -1,181 +0,0 @@ -# -# BitBake 'dummy' Passthrough Server -# -# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer -# Copyright (C) 2006 - 2008 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -""" - This module implements an xmlrpc server for BitBake. - - Use this by deriving a class from BitBakeXMLRPCServer and then adding - methods which you want to "export" via XMLRPC. If the methods have the - prefix xmlrpc_, then registering those function will happen automatically, - if not, you need to call register_function. - - Use register_idle_function() to add a function which the xmlrpc server - calls from within server_forever when no requests are pending. Make sure - that those functions are non-blocking or else you will introduce latency - in the server's main loop. -""" - -import time -import bb -from bb.ui import uievent -import xmlrpclib -import pickle - -DEBUG = False - -from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler -import inspect, select - -class BitBakeServerCommands(): - def __init__(self, server, cooker): - self.cooker = cooker - self.server = server - - def runCommand(self, command): - """ - Run a cooker command on the server - """ - #print "Running Command %s" % command - return self.cooker.command.runCommand(command) - - def terminateServer(self): - """ - Trigger the server to quit - """ - self.server.server_exit() - #print "Server (cooker) exitting" - return - - def ping(self): - """ - Dummy method which can be used to check the server is still alive - """ - return True - -eventQueue = [] - -class BBUIEventQueue: - class event: - def __init__(self, parent): - self.parent = parent - @staticmethod - def send(event): - bb.server.none.eventQueue.append(pickle.loads(event)) - @staticmethod - def quit(): - return - - def __init__(self, BBServer): - self.eventQueue = bb.server.none.eventQueue - self.BBServer = BBServer - self.EventHandle = bb.event.register_UIHhandler(self) - - def getEvent(self): - if len(self.eventQueue) == 0: - return None - - return self.eventQueue.pop(0) - - def waitEvent(self, delay): - event = self.getEvent() - if event: - return event - self.BBServer.idle_commands(delay) - return self.getEvent() - - def queue_event(self, event): - self.eventQueue.append(event) - - def system_quit( self ):
- bb.event.unregister_UIHhandler(self.EventHandle) - -class BitBakeServer(): - # remove this when you're done with debugging - # allow_reuse_address = True - - def __init__(self, cooker): - self._idlefuns = {} - self.commands = BitBakeServerCommands(self, cooker) - - def register_idle_function(self, function, data): - """Register a function to be called while the server is idle""" - assert callable(function) - self._idlefuns[function] = data - - def idle_commands(self, delay): - #print "Idle queue length %s" % len(self._idlefuns) - #print "Idle timeout, running idle functions" - #if len(self._idlefuns) == 0: - nextsleep = delay - for function, data in self._idlefuns.items(): - try: - retval = function(self, data, False) - #print "Idle function returned %s" % (retval) - if retval is False: - del self._idlefuns[function] - elif retval is True: - nextsleep = None - elif nextsleep is None: - continue - elif retval < nextsleep: - nextsleep = retval - except SystemExit: - raise - except: - import traceback - traceback.print_exc() - pass - if nextsleep is not None: - #print "Sleeping for %s (%s)" % (nextsleep, delay) - time.sleep(nextsleep) - - def server_exit(self): - # Tell idle functions we're exiting - for function, data in self._idlefuns.items(): - try: - retval = function(self, data, True) - except: - pass - -class BitbakeServerInfo(): - def __init__(self, server): - self.server = server - self.commands = server.commands - -class BitBakeServerFork(): - def __init__(self, serverinfo, command, logfile): - serverinfo.forkCommand = command - serverinfo.logfile = logfile - -class BitBakeServerConnection(): - def __init__(self, serverinfo): - self.server = serverinfo.server - self.connection = serverinfo.commands - self.events = bb.server.none.BBUIEventQueue(self.server) - - def terminate(self): - try: - self.events.system_quit() - except: - pass - try: - self.connection.terminateServer() - except: - pass - diff --git a/bitbake-dev/lib/bb/server/xmlrpc.py b/bitbake-dev/lib/bb/server/xmlrpc.py deleted file mode 100644 index 3364918c77..0000000000 --- a/bitbake-dev/lib/bb/server/xmlrpc.py +++ /dev/null @@ -1,187 +0,0 @@ -# -# BitBake XMLRPC Server -# -# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer -# Copyright (C) 2006 - 2008 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -""" - This module implements an xmlrpc server for BitBake. - - Use this by deriving a class from BitBakeXMLRPCServer and then adding - methods which you want to "export" via XMLRPC. If the methods have the - prefix xmlrpc_, then registering those function will happen automatically, - if not, you need to call register_function. - - Use register_idle_function() to add a function which the xmlrpc server - calls from within server_forever when no requests are pending. Make sure - that those functions are non-blocking or else you will introduce latency - in the server's main loop. -""" - -import bb -import xmlrpclib, sys -from bb import daemonize -from bb.ui import uievent - -DEBUG = False - -from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler -import inspect, select - -if sys.hexversion < 0x020600F0: - print "Sorry, python 2.6 or later is required for bitbake's XMLRPC mode" - sys.exit(1) - -class BitBakeServerCommands(): - def __init__(self, server, cooker): - self.cooker = cooker - self.server = server - - def registerEventHandler(self, host, port): - """ - Register a remote UI Event Handler - """ - s = xmlrpclib.Server("http://%s:%d" % (host, port), allow_none=True) - return bb.event.register_UIHhandler(s) - - def unregisterEventHandler(self, handlerNum): - """ - Unregister a remote UI Event Handler - """ - return bb.event.unregister_UIHhandler(handlerNum) - - def runCommand(self, command): - """ - Run a cooker command on the server - """ - return self.cooker.command.runCommand(command) - - def terminateServer(self): - """ - Trigger the server to quit - """ - self.server.quit = True - print "Server (cooker) exitting" - return - - def ping(self): - """ - Dummy method which can be used to check the server is still alive - """ - return True - -class BitBakeServer(SimpleXMLRPCServer): - # remove this when you're done with debugging - # allow_reuse_address = True - - def __init__(self, cooker, interface = ("localhost", 0)): - """ - Constructor - """ - SimpleXMLRPCServer.__init__(self, interface, - requestHandler=SimpleXMLRPCRequestHandler, - logRequests=False, allow_none=True) - self._idlefuns = {} - self.host, self.port = self.socket.getsockname() - #self.register_introspection_functions() - commands = BitBakeServerCommands(self, cooker) - self.autoregister_all_functions(commands, "") - - def autoregister_all_functions(self, context, prefix): - """ - Convenience method for registering all functions in the scope - of this class that start with a common prefix - """ - methodlist = inspect.getmembers(context, inspect.ismethod) - for name, method in methodlist: - if name.startswith(prefix): - self.register_function(method, name[len(prefix):]) - - def register_idle_function(self, function, data): - """Register a function to be called while the server is idle""" - assert callable(function) - self._idlefuns[function] = data - - def serve_forever(self): - """ - Serve Requests. Overloaded to honor a quit command - """ - self.quit = False - self.timeout = 0 # Run Idle calls for our first callback - while not self.quit: - #print "Idle queue length %s" % len(self._idlefuns) - self.handle_request() - #print "Idle timeout, running idle functions" - nextsleep = None - for function, data in self._idlefuns.items(): - try: - retval = function(self, data, False) - if retval is False: - del self._idlefuns[function] - elif retval is True: - nextsleep = 0 - elif nextsleep is 0: - continue - elif nextsleep is None: - nextsleep = retval - elif retval < nextsleep: - nextsleep = retval - except SystemExit: - raise - except: - import traceback - traceback.print_exc() - pass - if nextsleep is None and len(self._idlefuns) > 0: - nextsleep = 0 - self.timeout = nextsleep - # Tell idle functions we're exiting - for function, data in self._idlefuns.items(): - try: - retval = function(self, data, True) - except: - pass - - self.server_close() - return - -class BitbakeServerInfo(): - def __init__(self, server): - self.host = server.host - self.port = server.port - -class BitBakeServerFork(): - def __init__(self, serverinfo, command, logfile): - daemonize.createDaemon(command, logfile) - -class BitBakeServerConnection(): - def __init__(self, serverinfo): - self.connection = xmlrpclib.Server("http://%s:%s" % (serverinfo.host, serverinfo.port), allow_none=True) - self.events = uievent.BBUIEventQueue(self.connection) - - def terminate(self): - # Don't wait for server indefinitely - import socket - socket.setdefaulttimeout(2) - try: - self.events.system_quit() - except: - pass - try: - self.connection.terminateServer() - except: - pass - diff --git a/bitbake-dev/lib/bb/shell.py b/bitbake-dev/lib/bb/shell.py deleted file mode 100644 index 66e51719a4..0000000000 --- a/bitbake-dev/lib/bb/shell.py +++ /dev/null @@ -1,824 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -########################################################################## -# -# Copyright (C) 2005-2006 Michael 'Mickey' Lauer <mickey@Vanille.de> -# Copyright (C) 2005-2006 Vanille Media -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -########################################################################## -# -# Thanks to: -# * Holger Freyther <zecke@handhelds.org> -# * Justin Patrin <papercrane@reversefold.com> -# -########################################################################## - -""" -BitBake Shell - -IDEAS: - * list defined tasks per package - * list classes - * toggle force - * command to reparse just one (or more) bbfile(s) - * automatic check if reparsing is necessary (inotify?) - * frontend for bb file manipulation - * more shell-like features: - - output control, i.e. pipe output into grep, sort, etc. - - job control, i.e. bring running commands into background and foreground - * start parsing in background right after startup - * ncurses interface - -PROBLEMS: - * force doesn't always work - * readline completion for commands with more than one parameters - -""" - -########################################################################## -# Import and setup global variables -########################################################################## - -try: - set -except NameError: - from sets import Set as set -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> -Type 'help' for more information, press CTRL-D to exit.""" % __version__ - -cmds = {} -leave_mainloop = False -last_exception = None -cooker = None -parsed = False -debug = os.environ.get( "BBSHELL_DEBUG", "" ) - -########################################################################## -# Class BitBakeShellCommands -########################################################################## - -class BitBakeShellCommands: - """This class contains the valid commands for the shell""" - - def __init__( self, shell ): - """Register all the commands""" - self._shell = shell - for attr in BitBakeShellCommands.__dict__: - if not attr.startswith( "_" ): - if attr.endswith( "_" ): - command = attr[:-1].lower() - else: - command = attr[:].lower() - method = getattr( BitBakeShellCommands, attr ) - debugOut( "registering command '%s'" % command ) - # scan number of arguments - usage = getattr( method, "usage", "" ) - if usage != "<...>": - numArgs = len( usage.split() ) - else: - numArgs = -1 - shell.registerCommand( command, method, numArgs, "%s %s" % ( command, usage ), method.__doc__ ) - - def _checkParsed( self ): - if not parsed: - print "SHELL: This command needs to parse bbfiles..." - self.parse( None ) - - def _findProvider( self, item ): - self._checkParsed() - # Need to use taskData for this information - preferred = data.getVar( "PREFERRED_PROVIDER_%s" % item, cooker.configuration.data, 1 ) - if not preferred: preferred = item - try: - lv, lf, pv, pf = Providers.findBestProvider(preferred, cooker.configuration.data, cooker.status) - except KeyError: - if item in cooker.status.providers: - pf = cooker.status.providers[item][0] - else: - pf = None - return pf - - def alias( self, params ): - """Register a new name for a command""" - new, old = params - if not old in cmds: - print "ERROR: Command '%s' not known" % old - else: - cmds[new] = cmds[old] - print "OK" - alias.usage = "<alias> <command>" - - def buffer( self, params ): - """Dump specified output buffer""" - index = params[0] - print self._shell.myout.buffer( int( index ) ) - buffer.usage = "<index>" - - def buffers( self, params ): - """Show the available output buffers""" - commands = self._shell.myout.bufferedCommands() - if not commands: - print "SHELL: No buffered commands available yet. Start doing something." - else: - print "="*35, "Available Output Buffers", "="*27 - for index, cmd in enumerate( commands ): - print "| %s %s" % ( str( index ).ljust( 3 ), cmd ) - print "="*88 - - def build( self, params, cmd = "build" ): - """Build a providee""" - global last_exception - globexpr = params[0] - self._checkParsed() - names = globfilter( cooker.status.pkg_pn.keys(), globexpr ) - if len( names ) == 0: names = [ globexpr ] - print "SHELL: Building %s" % ' '.join( names ) - - td = taskdata.TaskData(cooker.configuration.abort) - localdata = data.createCopy(cooker.configuration.data) - data.update_data(localdata) - data.expandKeys(localdata) - - try: - tasks = [] - for name in names: - td.add_provider(localdata, cooker.status, name) - providers = td.get_provider(name) - - if len(providers) == 0: - raise Providers.NoProvider - - tasks.append([name, "do_%s" % cmd]) - - td.add_unresolved(localdata, cooker.status) - - rq = runqueue.RunQueue(cooker, localdata, cooker.status, td, tasks) - rq.prepare_runqueue() - rq.execute_runqueue() - - except Providers.NoProvider: - print "ERROR: No Provider" - last_exception = Providers.NoProvider - - except runqueue.TaskFailure, fnids: - for fnid in fnids: - print "ERROR: '%s' failed" % td.fn_index[fnid] - last_exception = runqueue.TaskFailure - - except build.EventException, e: - print "ERROR: Couldn't build '%s'" % names - last_exception = e - - - build.usage = "<providee>" - - def clean( self, params ): - """Clean a providee""" - self.build( params, "clean" ) - clean.usage = "<providee>" - - def compile( self, params ): - """Execute 'compile' on a providee""" - self.build( params, "compile" ) - compile.usage = "<providee>" - - def configure( self, params ): - """Execute 'configure' on a providee""" - self.build( params, "configure" ) - configure.usage = "<providee>" - - def install( self, params ): - """Execute 'install' on a providee""" - self.build( params, "install" ) - install.usage = "<providee>" - - def edit( self, params ): - """Call $EDITOR on a providee""" - name = params[0] - bbfile = self._findProvider( name ) - if bbfile is not None: - os.system( "%s %s" % ( os.environ.get( "EDITOR", "vi" ), bbfile ) ) - else: - print "ERROR: Nothing provides '%s'" % name - edit.usage = "<providee>" - - def environment( self, params ): - """Dump out the outer BitBake environment""" - cooker.showEnvironment() - - def exit_( self, params ): - """Leave the BitBake Shell""" - debugOut( "setting leave_mainloop to true" ) - global leave_mainloop - leave_mainloop = True - - def fetch( self, params ): - """Fetch a providee""" - self.build( params, "fetch" ) - fetch.usage = "<providee>" - - def fileBuild( self, params, cmd = "build" ): - """Parse and build a .bb file""" - global last_exception - name = params[0] - bf = completeFilePath( name ) - print "SHELL: Calling '%s' on '%s'" % ( cmd, bf ) - - try: - cooker.buildFile(bf, cmd) - except parse.ParseError: - print "ERROR: Unable to open or parse '%s'" % bf - except build.EventException, e: - print "ERROR: Couldn't build '%s'" % name - last_exception = e - - fileBuild.usage = "<bbfile>" - - def fileClean( self, params ): - """Clean a .bb file""" - self.fileBuild( params, "clean" ) - fileClean.usage = "<bbfile>" - - def fileEdit( self, params ): - """Call $EDITOR on a .bb file""" - name = params[0] - os.system( "%s %s" % ( os.environ.get( "EDITOR", "vi" ), completeFilePath( name ) ) ) - fileEdit.usage = "<bbfile>" - - def fileRebuild( self, params ): - """Rebuild (clean & build) a .bb file""" - self.fileBuild( params, "rebuild" ) - fileRebuild.usage = "<bbfile>" - - def fileReparse( self, params ): - """(re)Parse a bb file""" - bbfile = params[0] - print "SHELL: Parsing '%s'" % bbfile - parse.update_mtime( bbfile ) - cooker.bb_cache.cacheValidUpdate(bbfile) - fromCache = cooker.bb_cache.loadData(bbfile, cooker.configuration.data, cooker.status) - cooker.bb_cache.sync() - 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 - print "SHELL: Force Flag is now '%s'" % repr( cooker.configuration.force ) - - def help( self, params ): - """Show a comprehensive list of commands and their purpose""" - print "="*30, "Available Commands", "="*30 - allcmds = cmds.keys() - allcmds.sort() - for cmd in allcmds: - function,numparams,usage,helptext = cmds[cmd] - print "| %s | %s" % (usage.ljust(30), helptext) - print "="*78 - - def lastError( self, params ): - """Show the reason or log that was produced by the last BitBake event exception""" - if last_exception is None: - print "SHELL: No Errors yet (Phew)..." - else: - reason, event = last_exception.args - print "SHELL: Reason for the last error: '%s'" % reason - if ':' in reason: - msg, filename = reason.split( ':' ) - filename = filename.strip() - print "SHELL: Dumping log file for last error:" - try: - print open( filename ).read() - except IOError: - print "ERROR: Couldn't open '%s'" % filename - - def match( self, params ): - """Dump all files or providers matching a glob expression""" - what, globexpr = params - if what == "files": - self._checkParsed() - for key in globfilter( cooker.status.pkg_fn.keys(), globexpr ): print key - elif what == "providers": - self._checkParsed() - for key in globfilter( cooker.status.pkg_pn.keys(), globexpr ): print key - else: - print "Usage: match %s" % self.print_.usage - match.usage = "<files|providers> <glob>" - - def new( self, params ): - """Create a new .bb file and open the editor""" - dirname, filename = params - packages = '/'.join( data.getVar( "BBFILES", cooker.configuration.data, 1 ).split('/')[:-2] ) - fulldirname = "%s/%s" % ( packages, dirname ) - - if not os.path.exists( fulldirname ): - print "SHELL: Creating '%s'" % fulldirname - os.mkdir( fulldirname ) - if os.path.exists( fulldirname ) and os.path.isdir( fulldirname ): - if os.path.exists( "%s/%s" % ( fulldirname, filename ) ): - print "SHELL: ERROR: %s/%s already exists" % ( fulldirname, filename ) - return False - print "SHELL: Creating '%s/%s'" % ( fulldirname, filename ) - newpackage = open( "%s/%s" % ( fulldirname, filename ), "w" ) - print >>newpackage,"""DESCRIPTION = "" -SECTION = "" -AUTHOR = "" -HOMEPAGE = "" -MAINTAINER = "" -LICENSE = "GPL" -PR = "r0" - -SRC_URI = "" - -#inherit base - -#do_configure() { -# -#} - -#do_compile() { -# -#} - -#do_stage() { -# -#} - -#do_install() { -# -#} -""" - newpackage.close() - os.system( "%s %s/%s" % ( os.environ.get( "EDITOR" ), fulldirname, filename ) ) - new.usage = "<directory> <filename>" - - def package( self, params ): - """Execute 'package' on a providee""" - self.build( params, "package" ) - package.usage = "<providee>" - - def pasteBin( self, params ): - """Send a command + output buffer to the pastebin at http://rafb.net/paste""" - index = params[0] - contents = self._shell.myout.buffer( int( index ) ) - 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://rafb.net/paste""" - if last_exception is None: - print "SHELL: No Errors yet (Phew)..." - else: - reason, event = last_exception.args - print "SHELL: Reason for the last error: '%s'" % reason - if ':' in reason: - msg, filename = reason.split( ':' ) - filename = filename.strip() - print "SHELL: Pasting log file to pastebin..." - - file = open( filename ).read() - sendToPastebin( "contents of " + filename, file ) - - def patch( self, params ): - """Execute 'patch' command on a providee""" - self.build( params, "patch" ) - patch.usage = "<providee>" - - def parse( self, params ): - """(Re-)parse .bb files and calculate the dependency graph""" - 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) ) - - (filelist, masked) = cooker.collect_bbfiles() - cooker.parse_bbfiles(filelist, masked, cooker.myProgressCallback) - cooker.buildDepgraph() - global parsed - parsed = True - print - - def reparse( self, params ): - """(re)Parse a providee's bb file""" - bbfile = self._findProvider( params[0] ) - if bbfile is not None: - print "SHELL: Found bbfile '%s' for '%s'" % ( bbfile, params[0] ) - self.fileReparse( [ bbfile ] ) - else: - print "ERROR: Nothing provides '%s'" % params[0] - reparse.usage = "<providee>" - - def getvar( self, params ): - """Dump the contents of an outer BitBake environment variable""" - var = params[0] - value = data.getVar( var, cooker.configuration.data, 1 ) - print value - getvar.usage = "<variable>" - - def peek( self, params ): - """Dump contents of variable defined in providee's metadata""" - name, var = params - bbfile = self._findProvider( name ) - if bbfile is not None: - the_data = cooker.bb_cache.loadDataFull(bbfile, cooker.configuration.data) - value = the_data.getVar( var, 1 ) - print value - else: - print "ERROR: Nothing provides '%s'" % name - peek.usage = "<providee> <variable>" - - def poke( self, params ): - """Set contents of variable defined in providee's metadata""" - name, var, value = params - bbfile = self._findProvider( name ) - if bbfile is not None: - print "ERROR: Sorry, this functionality is currently broken" - #d = cooker.pkgdata[bbfile] - #data.setVar( var, value, d ) - - # mark the change semi persistant - #cooker.pkgdata.setDirty(bbfile, d) - #print "OK" - else: - print "ERROR: Nothing provides '%s'" % name - poke.usage = "<providee> <variable> <value>" - - def print_( self, params ): - """Dump all files or providers""" - what = params[0] - if what == "files": - self._checkParsed() - for key in cooker.status.pkg_fn.keys(): print key - elif what == "providers": - self._checkParsed() - for key in cooker.status.providers.keys(): print key - else: - print "Usage: print %s" % self.print_.usage - print_.usage = "<files|providers>" - - def python( self, params ): - """Enter the expert mode - an interactive BitBake Python Interpreter""" - sys.ps1 = "EXPERT BB>>> " - sys.ps2 = "EXPERT BB... " - import code - interpreter = code.InteractiveConsole( dict( globals() ) ) - interpreter.interact( "SHELL: Expert Mode - BitBake Python %s\nType 'help' for more information, press CTRL-D to switch back to BBSHELL." % sys.version ) - - def showdata( self, params ): - """Execute 'showdata' on a providee""" - cooker.showEnvironment(None, params) - showdata.usage = "<providee>" - - def setVar( self, params ): - """Set an outer BitBake environment variable""" - var, value = params - data.setVar( var, value, cooker.configuration.data ) - print "OK" - setVar.usage = "<variable> <value>" - - def rebuild( self, params ): - """Clean and rebuild a .bb file or a providee""" - self.build( params, "clean" ) - self.build( params, "build" ) - rebuild.usage = "<providee>" - - def shell( self, params ): - """Execute a shell command and dump the output""" - if params != "": - print commands.getoutput( " ".join( params ) ) - shell.usage = "<...>" - - def stage( self, params ): - """Execute 'stage' on a providee""" - self.build( params, "populate_staging" ) - stage.usage = "<providee>" - - def status( self, params ): - """<just for testing>""" - print "-" * 78 - print "building list = '%s'" % cooker.building_list - print "build path = '%s'" % cooker.build_path - print "consider_msgs_cache = '%s'" % cooker.consider_msgs_cache - print "build stats = '%s'" % cooker.stats - if last_exception is not None: print "last_exception = '%s'" % repr( last_exception.args ) - print "memory output contents = '%s'" % self._shell.myout._buffer - - def test( self, params ): - """<just for testing>""" - print "testCommand called with '%s'" % params - - def unpack( self, params ): - """Execute 'unpack' on a providee""" - self.build( params, "unpack" ) - unpack.usage = "<providee>" - - def which( self, params ): - """Computes the providers for a given providee""" - # Need to use taskData for this information - item = params[0] - - self._checkParsed() - - preferred = data.getVar( "PREFERRED_PROVIDER_%s" % item, cooker.configuration.data, 1 ) - if not preferred: preferred = item - - try: - lv, lf, pv, pf = Providers.findBestProvider(preferred, cooker.configuration.data, cooker.status) - except KeyError: - lv, lf, pv, pf = (None,)*4 - - try: - providers = cooker.status.providers[item] - except KeyError: - print "SHELL: ERROR: Nothing provides", preferred - else: - for provider in providers: - if provider == pf: provider = " (***) %s" % provider - else: provider = " %s" % provider - print provider - which.usage = "<providee>" - -########################################################################## -# Common helper functions -########################################################################## - -def completeFilePath( bbfile ): - """Get the complete bbfile path""" - if not cooker.status: return bbfile - if not cooker.status.pkg_fn: return bbfile - for key in cooker.status.pkg_fn.keys(): - if key.endswith( bbfile ): - return key - return bbfile - -def sendToPastebin( desc, content ): - """Send content to http://oe.pastebin.com""" - mydata = {} - 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"} - - host = "rafb.net" - conn = httplib.HTTPConnection( "%s:80" % host ) - conn.request("POST", "/paste/paste.php", params, headers ) - - response = conn.getresponse() - conn.close() - - 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""" - debugOut( "completer called with text='%s', state='%d'" % ( text, state ) ) - - if state == 0: - line = readline.get_line_buffer() - if " " in line: - line = line.split() - # we are in second (or more) argument - if line[0] in cmds and hasattr( cmds[line[0]][0], "usage" ): # known command and usage - u = getattr( cmds[line[0]][0], "usage" ).split()[0] - if u == "<variable>": - allmatches = cooker.configuration.data.keys() - elif u == "<bbfile>": - if cooker.status.pkg_fn is None: allmatches = [ "(No Matches Available. Parsed yet?)" ] - else: allmatches = [ x.split("/")[-1] for x in cooker.status.pkg_fn.keys() ] - elif u == "<providee>": - if cooker.status.pkg_fn is None: allmatches = [ "(No Matches Available. Parsed yet?)" ] - else: allmatches = cooker.status.providers.iterkeys() - else: allmatches = [ "(No tab completion available for this command)" ] - else: allmatches = [ "(No tab completion available for this command)" ] - else: - # we are in first argument - allmatches = cmds.iterkeys() - - completer.matches = [ x for x in allmatches if x[:len(text)] == text ] - #print "completer.matches = '%s'" % completer.matches - if len( completer.matches ) > state: - return completer.matches[state] - else: - return None - -def debugOut( text ): - if debug: - sys.stderr.write( "( %s )\n" % text ) - -def columnize( alist, width = 80 ): - """ - A word-wrap function that preserves existing line breaks - and most spaces in the text. Expects that existing line - breaks are posix newlines (\n). - """ - return reduce(lambda line, word, width=width: '%s%s%s' % - (line, - ' \n'[(len(line[line.rfind('\n')+1:]) - + len(word.split('\n',1)[0] - ) >= width)], - word), - alist - ) - -def globfilter( names, pattern ): - return fnmatch.filter( names, pattern ) - -########################################################################## -# Class MemoryOutput -########################################################################## - -class MemoryOutput: - """File-like output class buffering the output of the last 10 commands""" - def __init__( self, delegate ): - self.delegate = delegate - self._buffer = [] - self.text = [] - self._command = None - - def startCommand( self, command ): - self._command = command - self.text = [] - def endCommand( self ): - if self._command is not None: - if len( self._buffer ) == 10: del self._buffer[0] - self._buffer.append( ( self._command, self.text ) ) - def removeLast( self ): - if self._buffer: - del self._buffer[ len( self._buffer ) - 1 ] - self.text = [] - self._command = None - def lastBuffer( self ): - if self._buffer: - return self._buffer[ len( self._buffer ) -1 ][1] - def bufferedCommands( self ): - return [ cmd for cmd, output in self._buffer ] - def buffer( self, i ): - if i < len( self._buffer ): - return "BB>> %s\n%s" % ( self._buffer[i][0], "".join( self._buffer[i][1] ) ) - else: return "ERROR: Invalid buffer number. Buffer needs to be in (0, %d)" % ( len( self._buffer ) - 1 ) - def write( self, text ): - if self._command is not None and text != "BB>> ": self.text.append( text ) - if self.delegate is not None: self.delegate.write( text ) - def flush( self ): - return self.delegate.flush() - def fileno( self ): - return self.delegate.fileno() - def isatty( self ): - return self.delegate.isatty() - -########################################################################## -# Class BitBakeShell -########################################################################## - -class BitBakeShell: - - def __init__( self ): - """Register commands and set up readline""" - self.commandQ = Queue.Queue() - self.commands = BitBakeShellCommands( self ) - self.myout = MemoryOutput( sys.stdout ) - self.historyfilename = os.path.expanduser( "~/.bbsh_history" ) - self.startupfilename = os.path.expanduser( "~/.bbsh_startup" ) - - readline.set_completer( completer ) - readline.set_completer_delims( " " ) - readline.parse_and_bind("tab: complete") - - try: - readline.read_history_file( self.historyfilename ) - except IOError: - pass # It doesn't exist yet. - - print __credits__ - - def cleanup( self ): - """Write readline history and clean up resources""" - debugOut( "writing command history" ) - try: - readline.write_history_file( self.historyfilename ) - except: - print "SHELL: Unable to save command history" - - def registerCommand( self, command, function, numparams = 0, usage = "", helptext = "" ): - """Register a command""" - if usage == "": usage = command - if helptext == "": helptext = function.__doc__ or "<not yet documented>" - cmds[command] = ( function, numparams, usage, helptext ) - - def processCommand( self, command, params ): - """Process a command. Check number of params and print a usage string, if appropriate""" - debugOut( "processing command '%s'..." % command ) - try: - function, numparams, usage, helptext = cmds[command] - except KeyError: - print "SHELL: ERROR: '%s' command is not a valid command." % command - self.myout.removeLast() - else: - if (numparams != -1) and (not len( params ) == numparams): - print "Usage: '%s'" % usage - return - - result = function( self.commands, params ) - debugOut( "result was '%s'" % result ) - - def processStartupFile( self ): - """Read and execute all commands found in $HOME/.bbsh_startup""" - if os.path.exists( self.startupfilename ): - startupfile = open( self.startupfilename, "r" ) - for cmdline in startupfile: - debugOut( "processing startup line '%s'" % cmdline ) - if not cmdline: - continue - if "|" in cmdline: - print "ERROR: '|' in startup file is not allowed. Ignoring line" - continue - self.commandQ.put( cmdline.strip() ) - - def main( self ): - """The main command loop""" - while not leave_mainloop: - try: - if self.commandQ.empty(): - sys.stdout = self.myout.delegate - cmdline = raw_input( "BB>> " ) - sys.stdout = self.myout - else: - cmdline = self.commandQ.get() - if cmdline: - allCommands = cmdline.split( ';' ) - for command in allCommands: - pipecmd = None - # - # special case for expert mode - if command == 'python': - sys.stdout = self.myout.delegate - self.processCommand( command, "" ) - sys.stdout = self.myout - else: - self.myout.startCommand( command ) - if '|' in command: # disable output - command, pipecmd = command.split( '|' ) - delegate = self.myout.delegate - self.myout.delegate = None - tokens = shlex.split( command, True ) - self.processCommand( tokens[0], tokens[1:] or "" ) - self.myout.endCommand() - if pipecmd is not None: # restore output - self.myout.delegate = delegate - - pipe = popen2.Popen4( pipecmd ) - pipe.tochild.write( "\n".join( self.myout.lastBuffer() ) ) - pipe.tochild.close() - sys.stdout.write( pipe.fromchild.read() ) - # - except EOFError: - print - return - except KeyboardInterrupt: - print - -########################################################################## -# Start function - called from the BitBake command line utility -########################################################################## - -def start( aCooker ): - global cooker - cooker = aCooker - bbshell = BitBakeShell() - bbshell.processStartupFile() - bbshell.main() - bbshell.cleanup() - -if __name__ == "__main__": - print "SHELL: Sorry, this program should only be called by BitBake." diff --git a/bitbake-dev/lib/bb/taskdata.py b/bitbake-dev/lib/bb/taskdata.py deleted file mode 100644 index 4a88e75f6d..0000000000 --- a/bitbake-dev/lib/bb/taskdata.py +++ /dev/null @@ -1,610 +0,0 @@ -#!/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 this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import bb - -def re_match_strings(target, strings): - """ - Whether or not the string 'target' matches - any one string of the strings which can be regular expression string - """ - import re - - for name in strings: - if (name==target or - re.search(name,target)!=None): - return True - return False - -class TaskData: - """ - BitBake Task Data implementation - """ - def __init__(self, abort = True, tryaltconfigs = False): - 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 = [] - self.tasks_idepends = [] - # 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 - self.tryaltconfigs = tryaltconfigs - - 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_ids(self, fnid): - """ - Return an array of the ID numbers matching a given fnid. - """ - ids = [] - if fnid in self.tasks_lookup: - for task in self.tasks_lookup[fnid]: - ids.append(self.tasks_lookup[fnid][task]) - return ids - - def gettask_id(self, fn, task, create = True): - """ - Return an ID number for the task matching fn and task. - If it doesn't exist, create one by default. - Optionally return None instead. - """ - fnid = self.getfn_id(fn) - - if fnid in self.tasks_lookup: - if task in self.tasks_lookup[fnid]: - return self.tasks_lookup[fnid][task] - - if not create: - return None - - self.tasks_name.append(task) - self.tasks_fnid.append(fnid) - self.tasks_tdepends.append([]) - self.tasks_idepends.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_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 - - for task in task_deps['tasks']: - - # Work out task dependencies - parentids = [] - for dep in task_deps['parents'][task]: - parentid = self.gettask_id(fn, dep) - parentids.append(parentid) - taskid = self.gettask_id(fn, task) - self.tasks_tdepends[taskid].extend(parentids) - - # Touch all intertask dependencies - if 'depends' in task_deps and task in task_deps['depends']: - ids = [] - for dep in task_deps['depends'][task].split(): - if dep: - if ":" not in dep: - bb.msg.fatal(bb.msg.domain.TaskData, "Error, dependency %s does not contain ':' character\n. Task 'depends' should be specified in the form 'packagename:task'" % (depend, fn)) - ids.append(((self.getbuild_id(dep.split(":")[0])), dep.split(":")[1])) - self.tasks_idepends[taskid].extend(ids) - - # 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 bb.utils.explode_deps(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 bb.utils.explode_deps(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 re_match_strings(target, 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 re_match_strings(target, 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: - if self.get_rdependees_str(item): - bb.msg.error(bb.msg.domain.Provider, "Nothing PROVIDES '%s' (but '%s' DEPENDS on or otherwise requires it)" % (item, self.get_dependees_str(item))) - else: - bb.msg.error(bb.msg.domain.Provider, "Nothing PROVIDES '%s'" % (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 re_match_strings(item, dataCache.ignored_dependencies): - return - - if not item in dataCache.providers: - if self.get_rdependees_str(item): - bb.msg.note(2, bb.msg.domain.Provider, "Nothing PROVIDES '%s' (but '%s' DEPENDS on or otherwise requires it)" % (item, self.get_dependees_str(item))) - else: - bb.msg.note(2, bb.msg.domain.Provider, "Nothing PROVIDES '%s'" % (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, foundUnique = bb.providers.filterProviders(all_p, item, cfgData, dataCache) - eligible = [p for p in eligible if not self.getfn_id(p) in self.failed_fnids] - - if not eligible: - bb.msg.note(2, bb.msg.domain.Provider, "No buildable provider PROVIDES '%s' but '%s' DEPENDS on or otherwise requires it. Enable debugging and see earlier logs to find unbuildable providers." % (item, self.get_dependees_str(item))) - bb.event.fire(bb.event.NoProvider(item), cfgData) - raise bb.providers.NoProvider(item) - - if len(eligible) > 1 and foundUnique == 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 re_match_strings(item, 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, "'%s' RDEPENDS/RRECOMMENDS or otherwise requires the runtime entity '%s' but it wasn't found in any PACKAGE or RPROVIDES variables" % (self.get_rdependees_str(item), item)) - bb.event.fire(bb.event.NoProvider(item, runtime=True), cfgData) - raise bb.providers.NoRProvider(item) - - eligible, numberPreferred = bb.providers.filterProvidersRunTime(all_p, item, cfgData, dataCache) - eligible = [p for p in eligible if not self.getfn_id(p) in self.failed_fnids] - - if not eligible: - bb.msg.error(bb.msg.domain.Provider, "'%s' RDEPENDS/RRECOMMENDS or otherwise requires the runtime entity '%s' but it wasn't found in any PACKAGE or RPROVIDES variables of any buildable targets.\nEnable debugging and see earlier logs to find unbuildable targets." % (self.get_rdependees_str(item), item)) - bb.event.fire(bb.event.NoProvider(item, runtime=True), cfgData) - raise bb.providers.NoRProvider(item) - - if len(eligible) > 1 and numberPreferred == 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, runtime=True), cfgData) - self.consider_msgs_cache.append(item) - - if numberPreferred > 1: - 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 (top %s entries preferred) (%s);" % (item, numberPreferred, ", ".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, runtime=True), cfgData) - 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, missing_list = []): - """ - Mark a file as failed (unbuildable) - Remove any references from build and runtime provider lists - - missing_list, A list of missing requirements for this target - """ - if fnid in self.failed_fnids: - return - bb.msg.debug(1, bb.msg.domain.Provider, "File '%s' is unbuildable, removing..." % 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, missing_list) - 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, missing_list) - - def remove_buildtarget(self, targetid, missing_list = []): - """ - Mark a build target as failed (unbuildable) - Trigger removal of any files that have this as a dependency - """ - if not missing_list: - missing_list = [self.build_names_index[targetid]] - else: - missing_list = [self.build_names_index[targetid]] + missing_list - bb.msg.note(2, bb.msg.domain.Provider, "Target '%s' is unbuildable, removing...\nMissing or unbuildable dependency chain was: %s" % (self.build_names_index[targetid], missing_list)) - self.failed_deps.append(targetid) - dependees = self.get_dependees(targetid) - for fnid in dependees: - self.fail_fnid(fnid, missing_list) - for taskid in range(len(self.tasks_idepends)): - idepends = self.tasks_idepends[taskid] - for (idependid, idependtask) in idepends: - if idependid == targetid: - self.fail_fnid(self.tasks_fnid[taskid], missing_list) - - if self.abort and targetid in self.external_targets: - bb.msg.error(bb.msg.domain.Provider, "Required build target '%s' has no buildable providers.\nMissing or unbuildable dependency chain was: %s" % (self.build_names_index[targetid], missing_list)) - raise bb.providers.NoProvider - - def remove_runtarget(self, targetid, missing_list = []): - """ - Mark a run target as failed (unbuildable) - Trigger removal of any files that have this as a dependency - """ - if not missing_list: - missing_list = [self.run_names_index[targetid]] - else: - missing_list = [self.run_names_index[targetid]] + missing_list - - bb.msg.note(1, bb.msg.domain.Provider, "Runtime target '%s' is unbuildable, removing...\nMissing or unbuildable dependency chain was: %s" % (self.run_names_index[targetid], missing_list)) - self.failed_rdeps.append(targetid) - dependees = self.get_rdependees(targetid) - for fnid in dependees: - self.fail_fnid(fnid, missing_list) - - def add_unresolved(self, cfgData, dataCache): - """ - Resolve all unresolved build and runtime targets - """ - bb.msg.note(1, bb.msg.domain.TaskData, "Resolving any 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: - if self.get_rdependees_str(target): - bb.msg.error(bb.msg.domain.Provider, "Nothing PROVIDES '%s' (but '%s' DEPENDS on or otherwise requires it)" % (target, self.get_dependees_str(target))) - else: - bb.msg.error(bb.msg.domain.Provider, "Nothing PROVIDES '%s'" % (target)) - 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 - # self.dump_data() - - 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 buildid in range(len(self.build_names_index)): - target = self.build_names_index[buildid] - targets = "None" - if buildid in self.build_targets: - targets = self.build_targets[buildid] - bb.msg.debug(3, bb.msg.domain.TaskData, " (%s)%s: %s" % (buildid, target, targets)) - - bb.msg.debug(3, bb.msg.domain.TaskData, "run_targets:") - for runid in range(len(self.run_names_index)): - target = self.run_names_index[runid] - targets = "None" - if runid in self.run_targets: - targets = self.run_targets[runid] - bb.msg.debug(3, bb.msg.domain.TaskData, " (%s)%s: %s" % (runid, target, targets)) - - 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, "dependency ids (per fn):") - for fnid in self.depids: - bb.msg.debug(3, bb.msg.domain.TaskData, " %s %s: %s" % (fnid, self.fn_index[fnid], self.depids[fnid])) - - bb.msg.debug(3, bb.msg.domain.TaskData, "runtime dependency 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-dev/lib/bb/ui/__init__.py b/bitbake-dev/lib/bb/ui/__init__.py deleted file mode 100644 index c6a377a8e6..0000000000 --- a/bitbake-dev/lib/bb/ui/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -# BitBake UI Implementation -# -# Copyright (C) 2006-2007 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - diff --git a/bitbake-dev/lib/bb/ui/crumbs/__init__.py b/bitbake-dev/lib/bb/ui/crumbs/__init__.py deleted file mode 100644 index c6a377a8e6..0000000000 --- a/bitbake-dev/lib/bb/ui/crumbs/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -# BitBake UI Implementation -# -# Copyright (C) 2006-2007 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - diff --git a/bitbake-dev/lib/bb/ui/crumbs/buildmanager.py b/bitbake-dev/lib/bb/ui/crumbs/buildmanager.py deleted file mode 100644 index f89e8eefd4..0000000000 --- a/bitbake-dev/lib/bb/ui/crumbs/buildmanager.py +++ /dev/null @@ -1,457 +0,0 @@ -# -# BitBake Graphical GTK User Interface -# -# Copyright (C) 2008 Intel Corporation -# -# Authored by Rob Bradford <rob@linux.intel.com> -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import gtk -import gobject -import threading -import os -import datetime -import time - -class BuildConfiguration: - """ Represents a potential *or* historic *or* concrete build. It - encompasses all the things that we need to tell bitbake to do to make it - build what we want it to build. - - It also stored the metadata URL and the set of possible machines (and the - distros / images / uris for these. Apart from the metdata URL these are - not serialised to file (since they may be transient). In some ways this - functionality might be shifted to the loader class.""" - - def __init__ (self): - self.metadata_url = None - - # Tuple of (distros, image, urls) - self.machine_options = {} - - self.machine = None - self.distro = None - self.image = None - self.urls = [] - self.extra_urls = [] - self.extra_pkgs = [] - - def get_machines_model (self): - model = gtk.ListStore (gobject.TYPE_STRING) - for machine in self.machine_options.keys(): - model.append ([machine]) - - return model - - def get_distro_and_images_models (self, machine): - distro_model = gtk.ListStore (gobject.TYPE_STRING) - - for distro in self.machine_options[machine][0]: - distro_model.append ([distro]) - - image_model = gtk.ListStore (gobject.TYPE_STRING) - - for image in self.machine_options[machine][1]: - image_model.append ([image]) - - return (distro_model, image_model) - - def get_repos (self): - self.urls = self.machine_options[self.machine][2] - return self.urls - - # It might be a lot lot better if we stored these in like, bitbake conf - # file format. - @staticmethod - def load_from_file (filename): - f = open (filename, "r") - - conf = BuildConfiguration() - for line in f.readlines(): - data = line.split (";")[1] - if (line.startswith ("metadata-url;")): - conf.metadata_url = data.strip() - continue - if (line.startswith ("url;")): - conf.urls += [data.strip()] - continue - if (line.startswith ("extra-url;")): - conf.extra_urls += [data.strip()] - continue - if (line.startswith ("machine;")): - conf.machine = data.strip() - continue - if (line.startswith ("distribution;")): - conf.distro = data.strip() - continue - if (line.startswith ("image;")): - conf.image = data.strip() - continue - - f.close () - return conf - - # Serialise to a file. This is part of the build process and we use this - # to be able to repeat a given build (using the same set of parameters) - # but also so that we can include the details of the image / machine / - # distro in the build manager tree view. - def write_to_file (self, filename): - f = open (filename, "w") - - lines = [] - - if (self.metadata_url): - lines += ["metadata-url;%s\n" % (self.metadata_url)] - - for url in self.urls: - lines += ["url;%s\n" % (url)] - - for url in self.extra_urls: - lines += ["extra-url;%s\n" % (url)] - - if (self.machine): - lines += ["machine;%s\n" % (self.machine)] - - if (self.distro): - lines += ["distribution;%s\n" % (self.distro)] - - if (self.image): - lines += ["image;%s\n" % (self.image)] - - f.writelines (lines) - f.close () - -class BuildResult(gobject.GObject): - """ Represents an historic build. Perhaps not successful. But it includes - things such as the files that are in the directory (the output from the - build) as well as a deserialised BuildConfiguration file that is stored in - ".conf" in the directory for the build. - - This is GObject so that it can be included in the TreeStore.""" - - (STATE_COMPLETE, STATE_FAILED, STATE_ONGOING) = \ - (0, 1, 2) - - def __init__ (self, parent, identifier): - gobject.GObject.__init__ (self) - self.date = None - - self.files = [] - self.status = None - self.identifier = identifier - self.path = os.path.join (parent, identifier) - - # Extract the date, since the directory name is of the - # format build-<year><month><day>-<ordinal> we can easily - # pull it out. - # TODO: Better to stat a file? - (_ , date, revision) = identifier.split ("-") - print date - - year = int (date[0:4]) - month = int (date[4:6]) - day = int (date[6:8]) - - self.date = datetime.date (year, month, day) - - self.conf = None - - # By default builds are STATE_FAILED unless we find a "complete" file - # in which case they are STATE_COMPLETE - self.state = BuildResult.STATE_FAILED - for file in os.listdir (self.path): - if (file.startswith (".conf")): - conffile = os.path.join (self.path, file) - self.conf = BuildConfiguration.load_from_file (conffile) - elif (file.startswith ("complete")): - self.state = BuildResult.STATE_COMPLETE - else: - self.add_file (file) - - def add_file (self, file): - # Just add the file for now. Don't care about the type. - self.files += [(file, None)] - -class BuildManagerModel (gtk.TreeStore): - """ Model for the BuildManagerTreeView. This derives from gtk.TreeStore - but it abstracts nicely what the columns mean and the setup of the columns - in the model. """ - - (COL_IDENT, COL_DESC, COL_MACHINE, COL_DISTRO, COL_BUILD_RESULT, COL_DATE, COL_STATE) = \ - (0, 1, 2, 3, 4, 5, 6) - - def __init__ (self): - gtk.TreeStore.__init__ (self, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_OBJECT, - gobject.TYPE_INT64, - gobject.TYPE_INT) - -class BuildManager (gobject.GObject): - """ This class manages the historic builds that have been found in the - "results" directory but is also used for starting a new build.""" - - __gsignals__ = { - 'population-finished' : (gobject.SIGNAL_RUN_LAST, - gobject.TYPE_NONE, - ()), - 'populate-error' : (gobject.SIGNAL_RUN_LAST, - gobject.TYPE_NONE, - ()) - } - - def update_build_result (self, result, iter): - # Convert the date into something we can sort by. - date = long (time.mktime (result.date.timetuple())) - - # Add a top level entry for the build - - self.model.set (iter, - BuildManagerModel.COL_IDENT, result.identifier, - BuildManagerModel.COL_DESC, result.conf.image, - BuildManagerModel.COL_MACHINE, result.conf.machine, - BuildManagerModel.COL_DISTRO, result.conf.distro, - BuildManagerModel.COL_BUILD_RESULT, result, - BuildManagerModel.COL_DATE, date, - BuildManagerModel.COL_STATE, result.state) - - # And then we use the files in the directory as the children for the - # top level iter. - for file in result.files: - self.model.append (iter, (None, file[0], None, None, None, date, -1)) - - # This function is called as an idle by the BuildManagerPopulaterThread - def add_build_result (self, result): - gtk.gdk.threads_enter() - self.known_builds += [result] - - self.update_build_result (result, self.model.append (None)) - - gtk.gdk.threads_leave() - - def notify_build_finished (self): - # This is a bit of a hack. If we have a running build running then we - # will have a row in the model in STATE_ONGOING. Find it and make it - # as if it was a proper historic build (well, it is completed now....) - - # We need to use the iters here rather than the Python iterator - # interface to the model since we need to pass it into - # update_build_result - - iter = self.model.get_iter_first() - - while (iter): - (ident, state) = self.model.get(iter, - BuildManagerModel.COL_IDENT, - BuildManagerModel.COL_STATE) - - if state == BuildResult.STATE_ONGOING: - result = BuildResult (self.results_directory, ident) - self.update_build_result (result, iter) - iter = self.model.iter_next(iter) - - def notify_build_succeeded (self): - # Write the "complete" file so that when we create the BuildResult - # object we put into the model - - complete_file_path = os.path.join (self.cur_build_directory, "complete") - f = file (complete_file_path, "w") - f.close() - self.notify_build_finished() - - def notify_build_failed (self): - # Without a "complete" file then this will mark the build as failed: - self.notify_build_finished() - - # This function is called as an idle - def emit_population_finished_signal (self): - gtk.gdk.threads_enter() - self.emit ("population-finished") - gtk.gdk.threads_leave() - - class BuildManagerPopulaterThread (threading.Thread): - def __init__ (self, manager, directory): - threading.Thread.__init__ (self) - self.manager = manager - self.directory = directory - - def run (self): - # For each of the "build-<...>" directories .. - - if os.path.exists (self.directory): - for directory in os.listdir (self.directory): - - if not directory.startswith ("build-"): - continue - - build_result = BuildResult (self.directory, directory) - self.manager.add_build_result (build_result) - - gobject.idle_add (BuildManager.emit_population_finished_signal, - self.manager) - - def __init__ (self, server, results_directory): - gobject.GObject.__init__ (self) - - # The builds that we've found from walking the result directory - self.known_builds = [] - - # Save out the bitbake server, we need this for issuing commands to - # the cooker: - self.server = server - - # The TreeStore that we use - self.model = BuildManagerModel () - - # The results directory is where we create (and look for) the - # build-<xyz>-<n> directories. We need to populate ourselves from - # directory - self.results_directory = results_directory - self.populate_from_directory (self.results_directory) - - def populate_from_directory (self, directory): - thread = BuildManager.BuildManagerPopulaterThread (self, directory) - thread.start() - - # Come up with the name for the next build ident by combining "build-" - # with the date formatted as yyyymmdd and then an ordinal. We do this by - # an optimistic algorithm incrementing the ordinal if we find that it - # already exists. - def get_next_build_ident (self): - today = datetime.date.today () - datestr = str (today.year) + str (today.month) + str (today.day) - - revision = 0 - test_name = "build-%s-%d" % (datestr, revision) - test_path = os.path.join (self.results_directory, test_name) - - while (os.path.exists (test_path)): - revision += 1 - test_name = "build-%s-%d" % (datestr, revision) - test_path = os.path.join (self.results_directory, test_name) - - return test_name - - # Take a BuildConfiguration and then try and build it based on the - # parameters of that configuration. S - def do_build (self, conf): - server = self.server - - # Work out the build directory. Note we actually create the - # directories here since we need to write the ".conf" file. Otherwise - # we could have relied on bitbake's builder thread to actually make - # the directories as it proceeds with the build. - ident = self.get_next_build_ident () - build_directory = os.path.join (self.results_directory, - ident) - self.cur_build_directory = build_directory - os.makedirs (build_directory) - - conffile = os.path.join (build_directory, ".conf") - conf.write_to_file (conffile) - - # Add a row to the model representing this ongoing build. It's kinda a - # fake entry. If this build completes or fails then this gets updated - # with the real stuff like the historic builds - date = long (time.time()) - self.model.append (None, (ident, conf.image, conf.machine, conf.distro, - None, date, BuildResult.STATE_ONGOING)) - try: - server.runCommand(["setVariable", "BUILD_IMAGES_FROM_FEEDS", 1]) - server.runCommand(["setVariable", "MACHINE", conf.machine]) - server.runCommand(["setVariable", "DISTRO", conf.distro]) - server.runCommand(["setVariable", "PACKAGE_CLASSES", "package_ipk"]) - server.runCommand(["setVariable", "BBFILES", \ - """${OEROOT}/meta/packages/*/*.bb ${OEROOT}/meta-moblin/packages/*/*.bb"""]) - server.runCommand(["setVariable", "TMPDIR", "${OEROOT}/build/tmp"]) - server.runCommand(["setVariable", "IPK_FEED_URIS", \ - " ".join(conf.get_repos())]) - server.runCommand(["setVariable", "DEPLOY_DIR_IMAGE", - build_directory]) - server.runCommand(["buildTargets", [conf.image], "rootfs"]) - - except Exception, e: - print e - -class BuildManagerTreeView (gtk.TreeView): - """ The tree view for the build manager. This shows the historic builds - and so forth. """ - - # We use this function to control what goes in the cell since we store - # the date in the model as seconds since the epoch (for sorting) and so we - # need to make it human readable. - def date_format_custom_cell_data_func (self, col, cell, model, iter): - date = model.get (iter, BuildManagerModel.COL_DATE)[0] - datestr = time.strftime("%A %d %B %Y", time.localtime(date)) - cell.set_property ("text", datestr) - - # This format function controls what goes in the cell. We use this to map - # the integer state to a string and also to colourise the text - def state_format_custom_cell_data_fun (self, col, cell, model, iter): - state = model.get (iter, BuildManagerModel.COL_STATE)[0] - - if (state == BuildResult.STATE_ONGOING): - cell.set_property ("text", "Active") - cell.set_property ("foreground", "#000000") - elif (state == BuildResult.STATE_FAILED): - cell.set_property ("text", "Failed") - cell.set_property ("foreground", "#ff0000") - elif (state == BuildResult.STATE_COMPLETE): - cell.set_property ("text", "Complete") - cell.set_property ("foreground", "#00ff00") - else: - cell.set_property ("text", "") - - def __init__ (self): - gtk.TreeView.__init__(self) - - # Misc descriptiony thing - renderer = gtk.CellRendererText () - col = gtk.TreeViewColumn (None, renderer, - text=BuildManagerModel.COL_DESC) - self.append_column (col) - - # Machine - renderer = gtk.CellRendererText () - col = gtk.TreeViewColumn ("Machine", renderer, - text=BuildManagerModel.COL_MACHINE) - self.append_column (col) - - # distro - renderer = gtk.CellRendererText () - col = gtk.TreeViewColumn ("Distribution", renderer, - text=BuildManagerModel.COL_DISTRO) - self.append_column (col) - - # date (using a custom function for formatting the cell contents it - # takes epoch -> human readable string) - renderer = gtk.CellRendererText () - col = gtk.TreeViewColumn ("Date", renderer, - text=BuildManagerModel.COL_DATE) - self.append_column (col) - col.set_cell_data_func (renderer, - self.date_format_custom_cell_data_func) - - # For status. - renderer = gtk.CellRendererText () - col = gtk.TreeViewColumn ("Status", renderer, - text = BuildManagerModel.COL_STATE) - self.append_column (col) - col.set_cell_data_func (renderer, - self.state_format_custom_cell_data_fun) - diff --git a/bitbake-dev/lib/bb/ui/crumbs/puccho.glade b/bitbake-dev/lib/bb/ui/crumbs/puccho.glade deleted file mode 100644 index d7553a6e14..0000000000 --- a/bitbake-dev/lib/bb/ui/crumbs/puccho.glade +++ /dev/null @@ -1,606 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> -<!--Generated with glade3 3.4.5 on Mon Nov 10 12:24:12 2008 --> -<glade-interface> - <widget class="GtkDialog" id="build_dialog"> - <property name="title" translatable="yes">Start a build</property> - <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> - <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> - <property name="has_separator">False</property> - <child internal-child="vbox"> - <widget class="GtkVBox" id="dialog-vbox1"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <widget class="GtkTable" id="build_table"> - <property name="visible">True</property> - <property name="border_width">6</property> - <property name="n_rows">7</property> - <property name="n_columns">3</property> - <property name="column_spacing">5</property> - <property name="row_spacing">6</property> - <child> - <widget class="GtkAlignment" id="status_alignment"> - <property name="visible">True</property> - <property name="left_padding">12</property> - <child> - <widget class="GtkHBox" id="status_hbox"> - <property name="spacing">6</property> - <child> - <widget class="GtkImage" id="status_image"> - <property name="visible">True</property> - <property name="no_show_all">True</property> - <property name="xalign">0</property> - <property name="stock">gtk-dialog-error</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="status_label"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">If you see this text something is wrong...</property> - <property name="use_markup">True</property> - <property name="use_underline">True</property> - </widget> - <packing> - <property name="position">1</property> - </packing> - </child> - </widget> - </child> - </widget> - <packing> - <property name="right_attach">3</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label2"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><b>Build configuration</b></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="right_attach">3</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkComboBox" id="image_combo"> - <property name="visible">True</property> - <property name="sensitive">False</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="image_label"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="xalign">0</property> - <property name="xpad">12</property> - <property name="label" translatable="yes">Image:</property> - </widget> - <packing> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkComboBox" id="distribution_combo"> - <property name="visible">True</property> - <property name="sensitive">False</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="distribution_label"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="xalign">0</property> - <property name="xpad">12</property> - <property name="label" translatable="yes">Distribution:</property> - </widget> - <packing> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkComboBox" id="machine_combo"> - <property name="visible">True</property> - <property name="sensitive">False</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="machine_label"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="xalign">0</property> - <property name="xpad">12</property> - <property name="label" translatable="yes">Machine:</property> - </widget> - <packing> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="refresh_button"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="label" translatable="yes">gtk-refresh</property> - <property name="use_stock">True</property> - <property name="response_id">0</property> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkEntry" id="location_entry"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="width_chars">32</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label3"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">12</property> - <property name="label" translatable="yes">Location:</property> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label1"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><b>Repository</b></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="right_attach">3</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkAlignment" id="alignment1"> - <property name="visible">True</property> - <child> - <placeholder/> - </child> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkAlignment" id="alignment2"> - <property name="visible">True</property> - <child> - <placeholder/> - </child> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkAlignment" id="alignment3"> - <property name="visible">True</property> - <child> - <placeholder/> - </child> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> - <property name="y_options"></property> - </packing> - </child> - </widget> - <packing> - <property name="position">1</property> - </packing> - </child> - <child internal-child="action_area"> - <widget class="GtkHButtonBox" id="dialog-action_area1"> - <property name="visible">True</property> - <property name="layout_style">GTK_BUTTONBOX_END</property> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - </widget> - <packing> - <property name="expand">False</property> - <property name="pack_type">GTK_PACK_END</property> - </packing> - </child> - </widget> - </child> - </widget> - <widget class="GtkDialog" id="dialog2"> - <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> - <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> - <property name="has_separator">False</property> - <child internal-child="vbox"> - <widget class="GtkVBox" id="dialog-vbox2"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <widget class="GtkTable" id="table2"> - <property name="visible">True</property> - <property name="border_width">6</property> - <property name="n_rows">7</property> - <property name="n_columns">3</property> - <property name="column_spacing">6</property> - <property name="row_spacing">6</property> - <child> - <widget class="GtkLabel" id="label7"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><b>Repositories</b></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="right_attach">3</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkAlignment" id="alignment4"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="left_padding">12</property> - <child> - <widget class="GtkScrolledWindow" id="scrolledwindow1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <child> - <widget class="GtkTreeView" id="treeview1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="headers_clickable">True</property> - </widget> - </child> - </widget> - </child> - </widget> - <packing> - <property name="right_attach">3</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkEntry" id="entry1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">3</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label9"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><b>Additional packages</b></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="right_attach">3</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkAlignment" id="alignment6"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xscale">0</property> - <child> - <widget class="GtkLabel" id="label8"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="yalign">0</property> - <property name="xpad">12</property> - <property name="label" translatable="yes">Location: </property> - </widget> - </child> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkAlignment" id="alignment7"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="xscale">0</property> - <child> - <widget class="GtkHButtonBox" id="hbuttonbox1"> - <property name="visible">True</property> - <property name="spacing">5</property> - <child> - <widget class="GtkButton" id="button7"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="label" translatable="yes">gtk-remove</property> - <property name="use_stock">True</property> - <property name="response_id">0</property> - </widget> - </child> - <child> - <widget class="GtkButton" id="button6"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="label" translatable="yes">gtk-edit</property> - <property name="use_stock">True</property> - <property name="response_id">0</property> - </widget> - <packing> - <property name="position">1</property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button5"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="label" translatable="yes">gtk-add</property> - <property name="use_stock">True</property> - <property name="response_id">0</property> - </widget> - <packing> - <property name="position">2</property> - </packing> - </child> - </widget> - </child> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">3</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkAlignment" id="alignment5"> - <property name="visible">True</property> - <child> - <placeholder/> - </child> - </widget> - <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label10"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="yalign">0</property> - <property name="xpad">12</property> - <property name="label" translatable="yes">Search:</property> - </widget> - <packing> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkEntry" id="entry2"> - <property name="visible">True</property> - <property name="can_focus">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">3</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkAlignment" id="alignment8"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="left_padding">12</property> - <child> - <widget class="GtkScrolledWindow" id="scrolledwindow2"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <child> - <widget class="GtkTreeView" id="treeview2"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="headers_clickable">True</property> - </widget> - </child> - </widget> - </child> - </widget> - <packing> - <property name="right_attach">3</property> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> - <property name="y_options"></property> - </packing> - </child> - </widget> - <packing> - <property name="position">1</property> - </packing> - </child> - <child internal-child="action_area"> - <widget class="GtkHButtonBox" id="dialog-action_area2"> - <property name="visible">True</property> - <property name="layout_style">GTK_BUTTONBOX_END</property> - <child> - <widget class="GtkButton" id="button4"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="label" translatable="yes">gtk-close</property> - <property name="use_stock">True</property> - <property name="response_id">0</property> - </widget> - </child> - </widget> - <packing> - <property name="expand">False</property> - <property name="pack_type">GTK_PACK_END</property> - </packing> - </child> - </widget> - </child> - </widget> - <widget class="GtkWindow" id="main_window"> - <child> - <widget class="GtkVBox" id="main_window_vbox"> - <property name="visible">True</property> - <child> - <widget class="GtkToolbar" id="main_toolbar"> - <property name="visible">True</property> - <child> - <widget class="GtkToolButton" id="main_toolbutton_build"> - <property name="visible">True</property> - <property name="label" translatable="yes">Build</property> - <property name="stock_id">gtk-execute</property> - </widget> - <packing> - <property name="expand">False</property> - </packing> - </child> - </widget> - <packing> - <property name="expand">False</property> - </packing> - </child> - <child> - <widget class="GtkVPaned" id="vpaned1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <child> - <widget class="GtkScrolledWindow" id="results_scrolledwindow"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <child> - <placeholder/> - </child> - </widget> - <packing> - <property name="resize">False</property> - <property name="shrink">True</property> - </packing> - </child> - <child> - <widget class="GtkScrolledWindow" id="progress_scrolledwindow"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <child> - <placeholder/> - </child> - </widget> - <packing> - <property name="resize">True</property> - <property name="shrink">True</property> - </packing> - </child> - </widget> - <packing> - <property name="position">1</property> - </packing> - </child> - </widget> - </child> - </widget> -</glade-interface> diff --git a/bitbake-dev/lib/bb/ui/crumbs/runningbuild.py b/bitbake-dev/lib/bb/ui/crumbs/runningbuild.py deleted file mode 100644 index 401559255b..0000000000 --- a/bitbake-dev/lib/bb/ui/crumbs/runningbuild.py +++ /dev/null @@ -1,180 +0,0 @@ -# -# BitBake Graphical GTK User Interface -# -# Copyright (C) 2008 Intel Corporation -# -# Authored by Rob Bradford <rob@linux.intel.com> -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import gtk -import gobject - -class RunningBuildModel (gtk.TreeStore): - (COL_TYPE, COL_PACKAGE, COL_TASK, COL_MESSAGE, COL_ICON, COL_ACTIVE) = (0, 1, 2, 3, 4, 5) - def __init__ (self): - gtk.TreeStore.__init__ (self, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_BOOLEAN) - -class RunningBuild (gobject.GObject): - __gsignals__ = { - 'build-succeeded' : (gobject.SIGNAL_RUN_LAST, - gobject.TYPE_NONE, - ()), - 'build-failed' : (gobject.SIGNAL_RUN_LAST, - gobject.TYPE_NONE, - ()) - } - pids_to_task = {} - tasks_to_iter = {} - - def __init__ (self): - gobject.GObject.__init__ (self) - self.model = RunningBuildModel() - - def handle_event (self, event): - # Handle an event from the event queue, this may result in updating - # the model and thus the UI. Or it may be to tell us that the build - # has finished successfully (or not, as the case may be.) - - parent = None - pid = 0 - package = None - task = None - - # If we have a pid attached to this message/event try and get the - # (package, task) pair for it. If we get that then get the parent iter - # for the message. - if hassattr(event, 'pid'): - pid = event.pid - if self.pids_to_task.has_key(pid): - (package, task) = self.pids_to_task[pid] - parent = self.tasks_to_iter[(package, task)] - - if isinstance(event, bb.msg.Msg): - # Set a pretty icon for the message based on it's type. - if isinstance(event, bb.msg.MsgWarn): - icon = "dialog-warning" - elif isinstance(event, bb.msg.MsgErr): - icon = "dialog-error" - else: - icon = None - - # Ignore the "Running task i of n .." messages - if (event._message.startswith ("Running task")): - return - - # Add the message to the tree either at the top level if parent is - # None otherwise as a descendent of a task. - self.model.append (parent, - (event.__name__.split()[-1], # e.g. MsgWarn, MsgError - package, - task, - event._message, - icon, - False)) - elif isinstance(event, bb.build.TaskStarted): - (package, task) = (event._package, event._task) - - # Save out this PID. - self.pids_to_task[pid] = (package,task) - - # Check if we already have this package in our model. If so then - # that can be the parent for the task. Otherwise we create a new - # top level for the package. - if (self.tasks_to_iter.has_key ((package, None))): - parent = self.tasks_to_iter[(package, None)] - else: - parent = self.model.append (None, (None, - package, - None, - "Package: %s" % (package), - None, - False)) - self.tasks_to_iter[(package, None)] = parent - - # Because this parent package now has an active child mark it as - # such. - self.model.set(parent, self.model.COL_ICON, "gtk-execute") - - # Add an entry in the model for this task - i = self.model.append (parent, (None, - package, - task, - "Task: %s" % (task), - None, - False)) - - # Save out the iter so that we can find it when we have a message - # that we need to attach to a task. - self.tasks_to_iter[(package, task)] = i - - # Mark this task as active. - self.model.set(i, self.model.COL_ICON, "gtk-execute") - - elif isinstance(event, bb.build.Task): - - if isinstance(event, bb.build.TaskFailed): - # Mark the task as failed - i = self.tasks_to_iter[(package, task)] - self.model.set(i, self.model.COL_ICON, "dialog-error") - - # Mark the parent package as failed - i = self.tasks_to_iter[(package, None)] - self.model.set(i, self.model.COL_ICON, "dialog-error") - else: - # Mark the task as inactive - i = self.tasks_to_iter[(package, task)] - self.model.set(i, self.model.COL_ICON, None) - - # Mark the parent package as inactive - i = self.tasks_to_iter[(package, None)] - self.model.set(i, self.model.COL_ICON, None) - - - # Clear the iters and the pids since when the task goes away the - # pid will no longer be used for messages - del self.tasks_to_iter[(package, task)] - del self.pids_to_task[pid] - - elif isinstance(event, bb.event.BuildCompleted): - failures = int (event._failures) - - # Emit the appropriate signal depending on the number of failures - if (failures > 1): - self.emit ("build-failed") - else: - self.emit ("build-succeeded") - -class RunningBuildTreeView (gtk.TreeView): - def __init__ (self): - gtk.TreeView.__init__ (self) - - # The icon that indicates whether we're building or failed. - renderer = gtk.CellRendererPixbuf () - col = gtk.TreeViewColumn ("Status", renderer) - col.add_attribute (renderer, "icon-name", 4) - self.append_column (col) - - # The message of the build. - renderer = gtk.CellRendererText () - col = gtk.TreeViewColumn ("Message", renderer, text=3) - self.append_column (col) - - diff --git a/bitbake-dev/lib/bb/ui/depexp.py b/bitbake-dev/lib/bb/ui/depexp.py deleted file mode 100644 index cfa5b6564e..0000000000 --- a/bitbake-dev/lib/bb/ui/depexp.py +++ /dev/null @@ -1,272 +0,0 @@ -# -# BitBake Graphical GTK based Dependency Explorer -# -# Copyright (C) 2007 Ross Burton -# Copyright (C) 2007 - 2008 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import gobject -import gtk -import threading -import xmlrpclib - -# Package Model -(COL_PKG_NAME) = (0) - -# Dependency Model -(TYPE_DEP, TYPE_RDEP) = (0, 1) -(COL_DEP_TYPE, COL_DEP_PARENT, COL_DEP_PACKAGE) = (0, 1, 2) - -class PackageDepView(gtk.TreeView): - def __init__(self, model, dep_type, label): - gtk.TreeView.__init__(self) - self.current = None - self.dep_type = dep_type - self.filter_model = model.filter_new() - self.filter_model.set_visible_func(self._filter) - self.set_model(self.filter_model) - #self.connect("row-activated", self.on_package_activated, COL_DEP_PACKAGE) - self.append_column(gtk.TreeViewColumn(label, gtk.CellRendererText(), text=COL_DEP_PACKAGE)) - - def _filter(self, model, iter): - (this_type, package) = model.get(iter, COL_DEP_TYPE, COL_DEP_PARENT) - if this_type != self.dep_type: return False - return package == self.current - - def set_current_package(self, package): - self.current = package - self.filter_model.refilter() - -class PackageReverseDepView(gtk.TreeView): - def __init__(self, model, label): - gtk.TreeView.__init__(self) - self.current = None - self.filter_model = model.filter_new() - self.filter_model.set_visible_func(self._filter) - self.set_model(self.filter_model) - self.append_column(gtk.TreeViewColumn(label, gtk.CellRendererText(), text=COL_DEP_PARENT)) - - def _filter(self, model, iter): - package = model.get_value(iter, COL_DEP_PACKAGE) - return package == self.current - - def set_current_package(self, package): - self.current = package - self.filter_model.refilter() - -class DepExplorer(gtk.Window): - def __init__(self): - gtk.Window.__init__(self) - self.set_title("Dependency Explorer") - self.set_default_size(500, 500) - self.connect("delete-event", gtk.main_quit) - - # Create the data models - self.pkg_model = gtk.ListStore(gobject.TYPE_STRING) - self.depends_model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING) - - pane = gtk.HPaned() - pane.set_position(250) - self.add(pane) - - # The master list of packages - scrolled = gtk.ScrolledWindow() - scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - scrolled.set_shadow_type(gtk.SHADOW_IN) - self.pkg_treeview = gtk.TreeView(self.pkg_model) - self.pkg_treeview.get_selection().connect("changed", self.on_cursor_changed) - self.pkg_treeview.append_column(gtk.TreeViewColumn("Package", gtk.CellRendererText(), text=COL_PKG_NAME)) - pane.add1(scrolled) - scrolled.add(self.pkg_treeview) - - box = gtk.VBox(homogeneous=True, spacing=4) - - # Runtime Depends - scrolled = gtk.ScrolledWindow() - scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - scrolled.set_shadow_type(gtk.SHADOW_IN) - self.rdep_treeview = PackageDepView(self.depends_model, TYPE_RDEP, "Runtime Depends") - self.rdep_treeview.connect("row-activated", self.on_package_activated, COL_DEP_PACKAGE) - scrolled.add(self.rdep_treeview) - box.add(scrolled) - - # Build Depends - scrolled = gtk.ScrolledWindow() - scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - scrolled.set_shadow_type(gtk.SHADOW_IN) - self.dep_treeview = PackageDepView(self.depends_model, TYPE_DEP, "Build Depends") - self.dep_treeview.connect("row-activated", self.on_package_activated, COL_DEP_PACKAGE) - scrolled.add(self.dep_treeview) - box.add(scrolled) - pane.add2(box) - - # Reverse Depends - scrolled = gtk.ScrolledWindow() - scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - scrolled.set_shadow_type(gtk.SHADOW_IN) - self.revdep_treeview = PackageReverseDepView(self.depends_model, "Reverse Depends") - self.revdep_treeview.connect("row-activated", self.on_package_activated, COL_DEP_PARENT) - scrolled.add(self.revdep_treeview) - box.add(scrolled) - pane.add2(box) - - self.show_all() - - def on_package_activated(self, treeview, path, column, data_col): - model = treeview.get_model() - package = model.get_value(model.get_iter(path), data_col) - - pkg_path = [] - def finder(model, path, iter, needle): - package = model.get_value(iter, COL_PKG_NAME) - if package == needle: - pkg_path.append(path) - return True - else: - return False - self.pkg_model.foreach(finder, package) - if pkg_path: - self.pkg_treeview.get_selection().select_path(pkg_path[0]) - self.pkg_treeview.scroll_to_cell(pkg_path[0]) - - def on_cursor_changed(self, selection): - (model, it) = selection.get_selected() - if iter is None: - current_package = None - else: - current_package = model.get_value(it, COL_PKG_NAME) - self.rdep_treeview.set_current_package(current_package) - self.dep_treeview.set_current_package(current_package) - self.revdep_treeview.set_current_package(current_package) - - -def parse(depgraph, pkg_model, depends_model): - - for package in depgraph["pn"]: - pkg_model.set(pkg_model.append(), COL_PKG_NAME, package) - - for package in depgraph["depends"]: - for depend in depgraph["depends"][package]: - depends_model.set (depends_model.append(), - COL_DEP_TYPE, TYPE_DEP, - COL_DEP_PARENT, package, - COL_DEP_PACKAGE, depend) - - for package in depgraph["rdepends-pn"]: - for rdepend in depgraph["rdepends-pn"][package]: - depends_model.set (depends_model.append(), - COL_DEP_TYPE, TYPE_RDEP, - COL_DEP_PARENT, package, - COL_DEP_PACKAGE, rdepend) - -class ProgressBar(gtk.Window): - def __init__(self): - - gtk.Window.__init__(self) - self.set_title("Parsing .bb files, please wait...") - self.set_default_size(500, 0) - self.connect("delete-event", gtk.main_quit) - - self.progress = gtk.ProgressBar() - self.add(self.progress) - self.show_all() - -class gtkthread(threading.Thread): - quit = threading.Event() - def __init__(self, shutdown): - threading.Thread.__init__(self) - self.setDaemon(True) - self.shutdown = shutdown - - def run(self): - gobject.threads_init() - gtk.gdk.threads_init() - gtk.main() - gtkthread.quit.set() - -def init(server, eventHandler): - - try: - cmdline = server.runCommand(["getCmdLineAction"]) - if not cmdline or cmdline[0] != "generateDotGraph": - print "This UI is only compatible with the -g option" - return - ret = server.runCommand(["generateDepTreeEvent", cmdline[1], cmdline[2]]) - if ret != True: - print "Couldn't run command! %s" % ret - return - except xmlrpclib.Fault, x: - print "XMLRPC Fault getting commandline:\n %s" % x - return - - shutdown = 0 - - gtkgui = gtkthread(shutdown) - gtkgui.start() - - gtk.gdk.threads_enter() - pbar = ProgressBar() - dep = DepExplorer() - gtk.gdk.threads_leave() - - while True: - try: - event = eventHandler.waitEvent(0.25) - if gtkthread.quit.isSet(): - break - - if event is None: - continue - if isinstance(event, bb.event.ParseProgress): - x = event.sofar - y = event.total - if x == y: - print("\nParsing finished. %d cached, %d parsed, %d skipped, %d masked, %d errors." - % ( event.cached, event.parsed, event.skipped, event.masked, event.errors)) - pbar.hide() - gtk.gdk.threads_enter() - pbar.progress.set_fraction(float(x)/float(y)) - pbar.progress.set_text("%d/%d (%2d %%)" % (x, y, x*100/y)) - gtk.gdk.threads_leave() - continue - - if isinstance(event, bb.event.DepTreeGenerated): - gtk.gdk.threads_enter() - parse(event._depgraph, dep.pkg_model, dep.depends_model) - gtk.gdk.threads_leave() - - if isinstance(event, bb.command.CookerCommandCompleted): - continue - if isinstance(event, bb.command.CookerCommandFailed): - print "Command execution failed: %s" % event.error - break - if isinstance(event, bb.cooker.CookerExit): - break - - continue - - except KeyboardInterrupt: - if shutdown == 2: - print "\nThird Keyboard Interrupt, exit.\n" - break - if shutdown == 1: - print "\nSecond Keyboard Interrupt, stopping...\n" - server.runCommand(["stateStop"]) - if shutdown == 0: - print "\nKeyboard Interrupt, closing down...\n" - server.runCommand(["stateShutdown"]) - shutdown = shutdown + 1 - pass - diff --git a/bitbake-dev/lib/bb/ui/goggle.py b/bitbake-dev/lib/bb/ui/goggle.py deleted file mode 100644 index 94995d82db..0000000000 --- a/bitbake-dev/lib/bb/ui/goggle.py +++ /dev/null @@ -1,77 +0,0 @@ -# -# BitBake Graphical GTK User Interface -# -# Copyright (C) 2008 Intel Corporation -# -# Authored by Rob Bradford <rob@linux.intel.com> -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import gobject -import gtk -import xmlrpclib -from bb.ui.crumbs.runningbuild import RunningBuildTreeView, RunningBuild - -def event_handle_idle_func (eventHandler, build): - - # Consume as many messages as we can in the time available to us - event = eventHandler.getEvent() - while event: - build.handle_event (event) - event = eventHandler.getEvent() - - return True - -class MainWindow (gtk.Window): - def __init__ (self): - gtk.Window.__init__ (self, gtk.WINDOW_TOPLEVEL) - - # Setup tree view and the scrolled window - scrolled_window = gtk.ScrolledWindow () - self.add (scrolled_window) - self.cur_build_tv = RunningBuildTreeView() - scrolled_window.add (self.cur_build_tv) - -def init (server, eventHandler): - gobject.threads_init() - gtk.gdk.threads_init() - - window = MainWindow () - window.show_all () - - # Create the object for the current build - running_build = RunningBuild () - window.cur_build_tv.set_model (running_build.model) - try: - cmdline = server.runCommand(["getCmdLineAction"]) - print cmdline - if not cmdline: - return 1 - ret = server.runCommand(cmdline) - if ret != True: - print "Couldn't get default commandline! %s" % ret - return 1 - except xmlrpclib.Fault, x: - print "XMLRPC Fault getting commandline:\n %s" % x - return 1 - - # Use a timeout function for probing the event queue to find out if we - # have a message waiting for us. - gobject.timeout_add (200, - event_handle_idle_func, - eventHandler, - running_build) - - gtk.main() - diff --git a/bitbake-dev/lib/bb/ui/knotty.py b/bitbake-dev/lib/bb/ui/knotty.py deleted file mode 100644 index c69fd6ca64..0000000000 --- a/bitbake-dev/lib/bb/ui/knotty.py +++ /dev/null @@ -1,162 +0,0 @@ -# -# BitBake (No)TTY UI Implementation -# -# Handling output to TTYs or files (no TTY) -# -# Copyright (C) 2006-2007 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import os - -import sys -import itertools -import xmlrpclib - -parsespin = itertools.cycle( r'|/-\\' ) - -def init(server, eventHandler): - - # Get values of variables which control our output - includelogs = server.runCommand(["getVariable", "BBINCLUDELOGS"]) - loglines = server.runCommand(["getVariable", "BBINCLUDELOGS_LINES"]) - - try: - cmdline = server.runCommand(["getCmdLineAction"]) - #print cmdline - if not cmdline: - return 1 - ret = server.runCommand(cmdline) - if ret != True: - print "Couldn't get default commandline! %s" % ret - return 1 - except xmlrpclib.Fault, x: - print "XMLRPC Fault getting commandline:\n %s" % x - return 1 - - shutdown = 0 - return_value = 0 - while True: - try: - event = eventHandler.waitEvent(0.25) - if event is None: - continue - #print event - if isinstance(event, bb.msg.MsgPlain): - print event._message - continue - if isinstance(event, bb.msg.MsgDebug): - print 'DEBUG: ' + event._message - continue - if isinstance(event, bb.msg.MsgNote): - print 'NOTE: ' + event._message - continue - if isinstance(event, bb.msg.MsgWarn): - print 'WARNING: ' + event._message - continue - if isinstance(event, bb.msg.MsgError): - return_value = 1 - print 'ERROR: ' + event._message - continue - if isinstance(event, bb.msg.MsgFatal): - return_value = 1 - print 'FATAL: ' + event._message - break - if isinstance(event, bb.build.TaskFailed): - return_value = 1 - logfile = event.logfile - if logfile: - print "ERROR: Logfile of failure stored in %s." % logfile - if 1 or includelogs: - print "Log data follows:" - f = open(logfile, "r") - lines = [] - while True: - l = f.readline() - if l == '': - break - l = l.rstrip() - if loglines: - lines.append(' | %s' % l) - if len(lines) > int(loglines): - lines.pop(0) - else: - print '| %s' % l - f.close() - if lines: - for line in lines: - print line - if isinstance(event, bb.build.TaskBase): - print "NOTE: %s" % event._message - continue - if isinstance(event, bb.event.ParseProgress): - x = event.sofar - y = event.total - if os.isatty(sys.stdout.fileno()): - sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) ) - sys.stdout.flush() - else: - if x == 1: - sys.stdout.write("Parsing .bb files, please wait...") - sys.stdout.flush() - if x == y: - sys.stdout.write("done.") - sys.stdout.flush() - if x == y: - print("\nParsing of %d .bb files complete (%d cached, %d parsed). %d targets, %d skipped, %d masked, %d errors." - % ( event.total, event.cached, event.parsed, event.virtuals, event.skipped, event.masked, event.errors)) - continue - - if isinstance(event, bb.command.CookerCommandCompleted): - break - if isinstance(event, bb.command.CookerCommandSetExitCode): - return_value = event.exitcode - continue - if isinstance(event, bb.command.CookerCommandFailed): - return_value = 1 - print "Command execution failed: %s" % event.error - break - if isinstance(event, bb.cooker.CookerExit): - break - - # ignore - if isinstance(event, bb.event.BuildStarted): - continue - if isinstance(event, bb.event.BuildCompleted): - continue - if isinstance(event, bb.event.MultipleProviders): - continue - if isinstance(event, bb.runqueue.runQueueEvent): - continue - if isinstance(event, bb.event.StampUpdate): - continue - if isinstance(event, bb.event.ConfigParsed): - continue - if isinstance(event, bb.event.RecipeParsed): - continue - print "Unknown Event: %s" % event - - except KeyboardInterrupt: - if shutdown == 2: - print "\nThird Keyboard Interrupt, exit.\n" - break - if shutdown == 1: - print "\nSecond Keyboard Interrupt, stopping...\n" - server.runCommand(["stateStop"]) - if shutdown == 0: - print "\nKeyboard Interrupt, closing down...\n" - server.runCommand(["stateShutdown"]) - shutdown = shutdown + 1 - pass - return return_value diff --git a/bitbake-dev/lib/bb/ui/ncurses.py b/bitbake-dev/lib/bb/ui/ncurses.py deleted file mode 100644 index 14310dc124..0000000000 --- a/bitbake-dev/lib/bb/ui/ncurses.py +++ /dev/null @@ -1,335 +0,0 @@ -# -# BitBake Curses UI Implementation -# -# Implements an ncurses frontend for the BitBake utility. -# -# Copyright (C) 2006 Michael 'Mickey' Lauer -# Copyright (C) 2006-2007 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -""" - We have the following windows: - - 1.) Main Window: Shows what we are ultimately building and how far we are. Includes status bar - 2.) Thread Activity Window: Shows one status line for every concurrent bitbake thread. - 3.) Command Line Window: Contains an interactive command line where you can interact w/ Bitbake. - - Basic window layout is like that: - - |---------------------------------------------------------| - | <Main Window> | <Thread Activity Window> | - | | 0: foo do_compile complete| - | Building Gtk+-2.6.10 | 1: bar do_patch complete | - | Status: 60% | ... | - | | ... | - | | ... | - |---------------------------------------------------------| - |<Command Line Window> | - |>>> which virtual/kernel | - |openzaurus-kernel | - |>>> _ | - |---------------------------------------------------------| - -""" - -import os, sys, curses, itertools, time -import bb -import xmlrpclib -from bb import ui -from bb.ui import uihelper - -parsespin = itertools.cycle( r'|/-\\' ) - -X = 0 -Y = 1 -WIDTH = 2 -HEIGHT = 3 - -MAXSTATUSLENGTH = 32 - -class NCursesUI: - """ - NCurses UI Class - """ - class Window: - """Base Window Class""" - def __init__( self, x, y, width, height, fg=curses.COLOR_BLACK, bg=curses.COLOR_WHITE ): - self.win = curses.newwin( height, width, y, x ) - self.dimensions = ( x, y, width, height ) - """ - if curses.has_colors(): - color = 1 - curses.init_pair( color, fg, bg ) - self.win.bkgdset( ord(' '), curses.color_pair(color) ) - else: - self.win.bkgdset( ord(' '), curses.A_BOLD ) - """ - self.erase() - self.setScrolling() - self.win.noutrefresh() - - def erase( self ): - self.win.erase() - - def setScrolling( self, b = True ): - self.win.scrollok( b ) - self.win.idlok( b ) - - def setBoxed( self ): - self.boxed = True - self.win.box() - self.win.noutrefresh() - - def setText( self, x, y, text, *args ): - self.win.addstr( y, x, text, *args ) - self.win.noutrefresh() - - def appendText( self, text, *args ): - self.win.addstr( text, *args ) - self.win.noutrefresh() - - def drawHline( self, y ): - self.win.hline( y, 0, curses.ACS_HLINE, self.dimensions[WIDTH] ) - self.win.noutrefresh() - - class DecoratedWindow( Window ): - """Base class for windows with a box and a title bar""" - def __init__( self, title, x, y, width, height, fg=curses.COLOR_BLACK, bg=curses.COLOR_WHITE ): - NCursesUI.Window.__init__( self, x+1, y+3, width-2, height-4, fg, bg ) - self.decoration = NCursesUI.Window( x, y, width, height, fg, bg ) - self.decoration.setBoxed() - self.decoration.win.hline( 2, 1, curses.ACS_HLINE, width-2 ) - self.setTitle( title ) - - def setTitle( self, title ): - self.decoration.setText( 1, 1, title.center( self.dimensions[WIDTH]-2 ), curses.A_BOLD ) - - #-------------------------------------------------------------------------# -# class TitleWindow( Window ): - #-------------------------------------------------------------------------# -# """Title Window""" -# def __init__( self, x, y, width, height ): -# NCursesUI.Window.__init__( self, x, y, width, height ) -# version = bb.__version__ -# title = "BitBake %s" % version -# credit = "(C) 2003-2007 Team BitBake" -# #self.win.hline( 2, 1, curses.ACS_HLINE, width-2 ) -# self.win.border() -# self.setText( 1, 1, title.center( self.dimensions[WIDTH]-2 ), curses.A_BOLD ) -# self.setText( 1, 2, credit.center( self.dimensions[WIDTH]-2 ), curses.A_BOLD ) - - #-------------------------------------------------------------------------# - class ThreadActivityWindow( DecoratedWindow ): - #-------------------------------------------------------------------------# - """Thread Activity Window""" - def __init__( self, x, y, width, height ): - NCursesUI.DecoratedWindow.__init__( self, "Thread Activity", x, y, width, height ) - - def setStatus( self, thread, text ): - line = "%02d: %s" % ( thread, text ) - width = self.dimensions[WIDTH] - if ( len(line) > width ): - line = line[:width-3] + "..." - else: - line = line.ljust( width ) - self.setText( 0, thread, line ) - - #-------------------------------------------------------------------------# - class MainWindow( DecoratedWindow ): - #-------------------------------------------------------------------------# - """Main Window""" - def __init__( self, x, y, width, height ): - self.StatusPosition = width - MAXSTATUSLENGTH - NCursesUI.DecoratedWindow.__init__( self, None, x, y, width, height ) - curses.nl() - - def setTitle( self, title ): - title = "BitBake %s" % bb.__version__ - self.decoration.setText( 2, 1, title, curses.A_BOLD ) - self.decoration.setText( self.StatusPosition - 8, 1, "Status:", curses.A_BOLD ) - - def setStatus(self, status): - while len(status) < MAXSTATUSLENGTH: - status = status + " " - self.decoration.setText( self.StatusPosition, 1, status, curses.A_BOLD ) - - - #-------------------------------------------------------------------------# - class ShellOutputWindow( DecoratedWindow ): - #-------------------------------------------------------------------------# - """Interactive Command Line Output""" - def __init__( self, x, y, width, height ): - NCursesUI.DecoratedWindow.__init__( self, "Command Line Window", x, y, width, height ) - - #-------------------------------------------------------------------------# - class ShellInputWindow( Window ): - #-------------------------------------------------------------------------# - """Interactive Command Line Input""" - def __init__( self, x, y, width, height ): - NCursesUI.Window.__init__( self, x, y, width, height ) - -# put that to the top again from curses.textpad import Textbox -# self.textbox = Textbox( self.win ) -# t = threading.Thread() -# t.run = self.textbox.edit -# t.start() - - #-------------------------------------------------------------------------# - def main(self, stdscr, server, eventHandler): - #-------------------------------------------------------------------------# - height, width = stdscr.getmaxyx() - - # for now split it like that: - # MAIN_y + THREAD_y = 2/3 screen at the top - # MAIN_x = 2/3 left, THREAD_y = 1/3 right - # CLI_y = 1/3 of screen at the bottom - # CLI_x = full - - main_left = 0 - main_top = 0 - main_height = ( height / 3 * 2 ) - main_width = ( width / 3 ) * 2 - clo_left = main_left - clo_top = main_top + main_height - clo_height = height - main_height - main_top - 1 - clo_width = width - cli_left = main_left - cli_top = clo_top + clo_height - cli_height = 1 - cli_width = width - thread_left = main_left + main_width - thread_top = main_top - thread_height = main_height - thread_width = width - main_width - - #tw = self.TitleWindow( 0, 0, width, main_top ) - mw = self.MainWindow( main_left, main_top, main_width, main_height ) - taw = self.ThreadActivityWindow( thread_left, thread_top, thread_width, thread_height ) - clo = self.ShellOutputWindow( clo_left, clo_top, clo_width, clo_height ) - cli = self.ShellInputWindow( cli_left, cli_top, cli_width, cli_height ) - cli.setText( 0, 0, "BB>" ) - - mw.setStatus("Idle") - - helper = uihelper.BBUIHelper() - shutdown = 0 - - try: - cmdline = server.runCommand(["getCmdLineAction"]) - if not cmdline: - return - ret = server.runCommand(cmdline) - if ret != True: - print "Couldn't get default commandlind! %s" % ret - return - except xmlrpclib.Fault, x: - print "XMLRPC Fault getting commandline:\n %s" % x - return - - exitflag = False - while not exitflag: - try: - event = eventHandler.waitEvent(0.25) - if not event: - continue - helper.eventHandler(event) - #mw.appendText("%s\n" % event[0]) - if isinstance(event, bb.build.Task): - mw.appendText("NOTE: %s\n" % event._message) - if isinstance(event, bb.msg.MsgDebug): - mw.appendText('DEBUG: ' + event._message + '\n') - if isinstance(event, bb.msg.MsgNote): - mw.appendText('NOTE: ' + event._message + '\n') - if isinstance(event, bb.msg.MsgWarn): - mw.appendText('WARNING: ' + event._message + '\n') - if isinstance(event, bb.msg.MsgError): - mw.appendText('ERROR: ' + event._message + '\n') - if isinstance(event, bb.msg.MsgFatal): - mw.appendText('FATAL: ' + event._message + '\n') - if isinstance(event, bb.event.ParseProgress): - x = event.sofar - y = event.total - if x == y: - mw.setStatus("Idle") - mw.appendText("Parsing finished. %d cached, %d parsed, %d skipped, %d masked." - % ( event.cached, event.parsed, event.skipped, event.masked )) - else: - mw.setStatus("Parsing: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) ) -# if isinstance(event, bb.build.TaskFailed): -# if event.logfile: -# if data.getVar("BBINCLUDELOGS", d): -# bb.msg.error(bb.msg.domain.Build, "log data follows (%s)" % logfile) -# number_of_lines = data.getVar("BBINCLUDELOGS_LINES", d) -# if number_of_lines: -# os.system('tail -n%s %s' % (number_of_lines, logfile)) -# else: -# f = open(logfile, "r") -# while True: -# l = f.readline() -# if l == '': -# break -# l = l.rstrip() -# print '| %s' % l -# f.close() -# else: -# bb.msg.error(bb.msg.domain.Build, "see log in %s" % logfile) - - if isinstance(event, bb.command.CookerCommandCompleted): - exitflag = True - if isinstance(event, bb.command.CookerCommandFailed): - mw.appendText("Command execution failed: %s" % event.error) - time.sleep(2) - exitflag = True - if isinstance(event, bb.cooker.CookerExit): - exitflag = True - - if helper.needUpdate: - activetasks, failedtasks = helper.getTasks() - taw.erase() - taw.setText(0, 0, "") - if activetasks: - taw.appendText("Active Tasks:\n") - for task in activetasks: - taw.appendText(task) - if failedtasks: - taw.appendText("Failed Tasks:\n") - for task in failedtasks: - taw.appendText(task) - - curses.doupdate() - except KeyboardInterrupt: - if shutdown == 2: - mw.appendText("Third Keyboard Interrupt, exit.\n") - exitflag = True - if shutdown == 1: - mw.appendText("Second Keyboard Interrupt, stopping...\n") - server.runCommand(["stateStop"]) - if shutdown == 0: - mw.appendText("Keyboard Interrupt, closing down...\n") - server.runCommand(["stateShutdown"]) - shutdown = shutdown + 1 - pass - -def init(server, eventHandler): - if not os.isatty(sys.stdout.fileno()): - print "FATAL: Unable to run 'ncurses' UI without a TTY." - return - ui = NCursesUI() - try: - curses.wrapper(ui.main, server, eventHandler) - except: - import traceback - traceback.print_exc() - diff --git a/bitbake-dev/lib/bb/ui/puccho.py b/bitbake-dev/lib/bb/ui/puccho.py deleted file mode 100644 index 713aa1f4a6..0000000000 --- a/bitbake-dev/lib/bb/ui/puccho.py +++ /dev/null @@ -1,425 +0,0 @@ -# -# BitBake Graphical GTK User Interface -# -# Copyright (C) 2008 Intel Corporation -# -# Authored by Rob Bradford <rob@linux.intel.com> -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import gtk -import gobject -import gtk.glade -import threading -import urllib2 -import os - -from bb.ui.crumbs.buildmanager import BuildManager, BuildConfiguration -from bb.ui.crumbs.buildmanager import BuildManagerTreeView - -from bb.ui.crumbs.runningbuild import RunningBuild, RunningBuildTreeView - -# The metadata loader is used by the BuildSetupDialog to download the -# available options to populate the dialog -class MetaDataLoader(gobject.GObject): - """ This class provides the mechanism for loading the metadata (the - fetching and parsing) from a given URL. The metadata encompasses details - on what machines are available. The distribution and images available for - the machine and the the uris to use for building the given machine.""" - __gsignals__ = { - 'success' : (gobject.SIGNAL_RUN_LAST, - gobject.TYPE_NONE, - ()), - 'error' : (gobject.SIGNAL_RUN_LAST, - gobject.TYPE_NONE, - (gobject.TYPE_STRING,)) - } - - # We use these little helper functions to ensure that we take the gdk lock - # when emitting the signal. These functions are called as idles (so that - # they happen in the gtk / main thread's main loop. - def emit_error_signal (self, remark): - gtk.gdk.threads_enter() - self.emit ("error", remark) - gtk.gdk.threads_leave() - - def emit_success_signal (self): - gtk.gdk.threads_enter() - self.emit ("success") - gtk.gdk.threads_leave() - - def __init__ (self): - gobject.GObject.__init__ (self) - - class LoaderThread(threading.Thread): - """ This class provides an asynchronous loader for the metadata (by - using threads and signals). This is useful since the metadata may be - at a remote URL.""" - class LoaderImportException (Exception): - pass - - def __init__(self, loader, url): - threading.Thread.__init__ (self) - self.url = url - self.loader = loader - - def run (self): - result = {} - try: - f = urllib2.urlopen (self.url) - - # Parse the metadata format. The format is.... - # <machine>;<default distro>|<distro>...;<default image>|<image>...;<type##url>|... - for line in f.readlines(): - components = line.split(";") - if (len (components) < 4): - raise MetaDataLoader.LoaderThread.LoaderImportException - machine = components[0] - distros = components[1].split("|") - images = components[2].split("|") - urls = components[3].split("|") - - result[machine] = (distros, images, urls) - - # Create an object representing this *potential* - # configuration. It can become concrete if the machine, distro - # and image are all chosen in the UI - configuration = BuildConfiguration() - configuration.metadata_url = self.url - configuration.machine_options = result - self.loader.configuration = configuration - - # Emit that we've actually got a configuration - gobject.idle_add (MetaDataLoader.emit_success_signal, - self.loader) - - except MetaDataLoader.LoaderThread.LoaderImportException, e: - gobject.idle_add (MetaDataLoader.emit_error_signal, self.loader, - "Repository metadata corrupt") - except Exception, e: - gobject.idle_add (MetaDataLoader.emit_error_signal, self.loader, - "Unable to download repository metadata") - print e - - def try_fetch_from_url (self, url): - # Try and download the metadata. Firing a signal if successful - thread = MetaDataLoader.LoaderThread(self, url) - thread.start() - -class BuildSetupDialog (gtk.Dialog): - RESPONSE_BUILD = 1 - - # A little helper method that just sets the states on the widgets based on - # whether we've got good metadata or not. - def set_configurable (self, configurable): - if (self.configurable == configurable): - return - - self.configurable = configurable - for widget in self.conf_widgets: - widget.set_sensitive (configurable) - - if not configurable: - self.machine_combo.set_active (-1) - self.distribution_combo.set_active (-1) - self.image_combo.set_active (-1) - - # GTK widget callbacks - def refresh_button_clicked (self, button): - # Refresh button clicked. - - url = self.location_entry.get_chars (0, -1) - self.loader.try_fetch_from_url(url) - - def repository_entry_editable_changed (self, entry): - if (len (entry.get_chars (0, -1)) > 0): - self.refresh_button.set_sensitive (True) - else: - self.refresh_button.set_sensitive (False) - self.clear_status_message() - - # If we were previously configurable we are no longer since the - # location entry has been changed - self.set_configurable (False) - - def machine_combo_changed (self, combobox): - active_iter = combobox.get_active_iter() - - if not active_iter: - return - - model = combobox.get_model() - - if model: - chosen_machine = model.get (active_iter, 0)[0] - - (distros_model, images_model) = \ - self.loader.configuration.get_distro_and_images_models (chosen_machine) - - self.distribution_combo.set_model (distros_model) - self.image_combo.set_model (images_model) - - # Callbacks from the loader - def loader_success_cb (self, loader): - self.status_image.set_from_icon_name ("info", - gtk.ICON_SIZE_BUTTON) - self.status_image.show() - self.status_label.set_label ("Repository metadata successfully downloaded") - - # Set the models on the combo boxes based on the models generated from - # the configuration that the loader has created - - # We just need to set the machine here, that then determines the - # distro and image options. Cunning huh? :-) - - self.configuration = self.loader.configuration - model = self.configuration.get_machines_model () - self.machine_combo.set_model (model) - - self.set_configurable (True) - - def loader_error_cb (self, loader, message): - self.status_image.set_from_icon_name ("error", - gtk.ICON_SIZE_BUTTON) - self.status_image.show() - self.status_label.set_text ("Error downloading repository metadata") - for widget in self.conf_widgets: - widget.set_sensitive (False) - - def clear_status_message (self): - self.status_image.hide() - self.status_label.set_label ( - """<i>Enter the repository location and press _Refresh</i>""") - - def __init__ (self): - gtk.Dialog.__init__ (self) - - # Cancel - self.add_button (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) - - # Build - button = gtk.Button ("_Build", None, True) - image = gtk.Image () - image.set_from_stock (gtk.STOCK_EXECUTE,gtk.ICON_SIZE_BUTTON) - button.set_image (image) - self.add_action_widget (button, BuildSetupDialog.RESPONSE_BUILD) - button.show_all () - - # Pull in *just* the table from the Glade XML data. - gxml = gtk.glade.XML (os.path.dirname(__file__) + "/crumbs/puccho.glade", - root = "build_table") - table = gxml.get_widget ("build_table") - self.vbox.pack_start (table, True, False, 0) - - # Grab all the widgets that we need to turn on/off when we refresh... - self.conf_widgets = [] - self.conf_widgets += [gxml.get_widget ("machine_label")] - self.conf_widgets += [gxml.get_widget ("distribution_label")] - self.conf_widgets += [gxml.get_widget ("image_label")] - self.conf_widgets += [gxml.get_widget ("machine_combo")] - self.conf_widgets += [gxml.get_widget ("distribution_combo")] - self.conf_widgets += [gxml.get_widget ("image_combo")] - - # Grab the status widgets - self.status_image = gxml.get_widget ("status_image") - self.status_label = gxml.get_widget ("status_label") - - # Grab the refresh button and connect to the clicked signal - self.refresh_button = gxml.get_widget ("refresh_button") - self.refresh_button.connect ("clicked", self.refresh_button_clicked) - - # Grab the location entry and connect to editable::changed - self.location_entry = gxml.get_widget ("location_entry") - self.location_entry.connect ("changed", - self.repository_entry_editable_changed) - - # Grab the machine combo and hook onto the changed signal. This then - # allows us to populate the distro and image combos - self.machine_combo = gxml.get_widget ("machine_combo") - self.machine_combo.connect ("changed", self.machine_combo_changed) - - # Setup the combo - cell = gtk.CellRendererText() - self.machine_combo.pack_start(cell, True) - self.machine_combo.add_attribute(cell, 'text', 0) - - # Grab the distro and image combos. We need these to populate with - # models once the machine is chosen - self.distribution_combo = gxml.get_widget ("distribution_combo") - cell = gtk.CellRendererText() - self.distribution_combo.pack_start(cell, True) - self.distribution_combo.add_attribute(cell, 'text', 0) - - self.image_combo = gxml.get_widget ("image_combo") - cell = gtk.CellRendererText() - self.image_combo.pack_start(cell, True) - self.image_combo.add_attribute(cell, 'text', 0) - - # Put the default descriptive text in the status box - self.clear_status_message() - - # Mark as non-configurable, this is just greys out the widgets the - # user can't yet use - self.configurable = False - self.set_configurable(False) - - # Show the table - table.show_all () - - # The loader and some signals connected to it to update the status - # area - self.loader = MetaDataLoader() - self.loader.connect ("success", self.loader_success_cb) - self.loader.connect ("error", self.loader_error_cb) - - def update_configuration (self): - """ A poorly named function but it updates the internal configuration - from the widgets. This can make that configuration concrete and can - thus be used for building """ - # Extract the chosen machine from the combo - model = self.machine_combo.get_model() - active_iter = self.machine_combo.get_active_iter() - if (active_iter): - self.configuration.machine = model.get(active_iter, 0)[0] - - # Extract the chosen distro from the combo - model = self.distribution_combo.get_model() - active_iter = self.distribution_combo.get_active_iter() - if (active_iter): - self.configuration.distro = model.get(active_iter, 0)[0] - - # Extract the chosen image from the combo - model = self.image_combo.get_model() - active_iter = self.image_combo.get_active_iter() - if (active_iter): - self.configuration.image = model.get(active_iter, 0)[0] - -# This function operates to pull events out from the event queue and then push -# them into the RunningBuild (which then drives the RunningBuild which then -# pushes through and updates the progress tree view.) -# -# TODO: Should be a method on the RunningBuild class -def event_handle_timeout (eventHandler, build): - # Consume as many messages as we can ... - event = eventHandler.getEvent() - while event: - build.handle_event (event) - event = eventHandler.getEvent() - return True - -class MainWindow (gtk.Window): - - # Callback that gets fired when the user hits a button in the - # BuildSetupDialog. - def build_dialog_box_response_cb (self, dialog, response_id): - conf = None - if (response_id == BuildSetupDialog.RESPONSE_BUILD): - dialog.update_configuration() - print dialog.configuration.machine, dialog.configuration.distro, \ - dialog.configuration.image - conf = dialog.configuration - - dialog.destroy() - - if conf: - self.manager.do_build (conf) - - def build_button_clicked_cb (self, button): - dialog = BuildSetupDialog () - - # For some unknown reason Dialog.run causes nice little deadlocks ... :-( - dialog.connect ("response", self.build_dialog_box_response_cb) - dialog.show() - - def __init__ (self): - gtk.Window.__init__ (self) - - # Pull in *just* the main vbox from the Glade XML data and then pack - # that inside the window - gxml = gtk.glade.XML (os.path.dirname(__file__) + "/crumbs/puccho.glade", - root = "main_window_vbox") - vbox = gxml.get_widget ("main_window_vbox") - self.add (vbox) - - # Create the tree views for the build manager view and the progress view - self.build_manager_view = BuildManagerTreeView() - self.running_build_view = RunningBuildTreeView() - - # Grab the scrolled windows that we put the tree views into - self.results_scrolledwindow = gxml.get_widget ("results_scrolledwindow") - self.progress_scrolledwindow = gxml.get_widget ("progress_scrolledwindow") - - # Put the tree views inside ... - self.results_scrolledwindow.add (self.build_manager_view) - self.progress_scrolledwindow.add (self.running_build_view) - - # Hook up the build button... - self.build_button = gxml.get_widget ("main_toolbutton_build") - self.build_button.connect ("clicked", self.build_button_clicked_cb) - -# I'm not very happy about the current ownership of the RunningBuild. I have -# my suspicions that this object should be held by the BuildManager since we -# care about the signals in the manager - -def running_build_succeeded_cb (running_build, manager): - # Notify the manager that a build has succeeded. This is necessary as part - # of the 'hack' that we use for making the row in the model / view - # representing the ongoing build change into a row representing the - # completed build. Since we know only one build can be running a time then - # we can handle this. - - # FIXME: Refactor all this so that the RunningBuild is owned by the - # BuildManager. It can then hook onto the signals directly and drive - # interesting things it cares about. - manager.notify_build_succeeded () - print "build succeeded" - -def running_build_failed_cb (running_build, manager): - # As above - print "build failed" - manager.notify_build_failed () - -def init (server, eventHandler): - # Initialise threading... - gobject.threads_init() - gtk.gdk.threads_init() - - main_window = MainWindow () - main_window.show_all () - - # Set up the build manager stuff in general - builds_dir = os.path.join (os.getcwd(), "results") - manager = BuildManager (server, builds_dir) - main_window.build_manager_view.set_model (manager.model) - - # Do the running build setup - running_build = RunningBuild () - main_window.running_build_view.set_model (running_build.model) - running_build.connect ("build-succeeded", running_build_succeeded_cb, - manager) - running_build.connect ("build-failed", running_build_failed_cb, manager) - - # We need to save the manager into the MainWindow so that the toolbar - # button can use it. - # FIXME: Refactor ? - main_window.manager = manager - - # Use a timeout function for probing the event queue to find out if we - # have a message waiting for us. - gobject.timeout_add (200, - event_handle_timeout, - eventHandler, - running_build) - - gtk.main() diff --git a/bitbake-dev/lib/bb/ui/uievent.py b/bitbake-dev/lib/bb/ui/uievent.py deleted file mode 100644 index 36302f4da7..0000000000 --- a/bitbake-dev/lib/bb/ui/uievent.py +++ /dev/null @@ -1,125 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -# -# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer -# Copyright (C) 2006 - 2007 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - -""" -Use this class to fork off a thread to recieve event callbacks from the bitbake -server and queue them for the UI to process. This process must be used to avoid -client/server deadlocks. -""" - -import socket, threading, pickle -from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler - -class BBUIEventQueue: - def __init__(self, BBServer): - - self.eventQueue = [] - self.eventQueueLock = threading.Lock() - self.eventQueueNotify = threading.Event() - - self.BBServer = BBServer - - self.t = threading.Thread() - self.t.setDaemon(True)
- self.t.run = self.startCallbackHandler
- self.t.start() - - def getEvent(self): - - self.eventQueueLock.acquire() - - if len(self.eventQueue) == 0: - self.eventQueueLock.release() - return None - - item = self.eventQueue.pop(0) - - if len(self.eventQueue) == 0: - self.eventQueueNotify.clear() - - self.eventQueueLock.release() - return item - - def waitEvent(self, delay): - self.eventQueueNotify.wait(delay) - return self.getEvent() - - def queue_event(self, event): - self.eventQueueLock.acquire() - self.eventQueue.append(pickle.loads(event)) - self.eventQueueNotify.set() - self.eventQueueLock.release() - - def startCallbackHandler(self): - - server = UIXMLRPCServer() - self.host, self.port = server.socket.getsockname()
- - server.register_function( self.system_quit, "event.quit" ) - server.register_function( self.queue_event, "event.send" ) - server.socket.settimeout(1) - - self.EventHandle = self.BBServer.registerEventHandler(self.host, self.port) - - self.server = server - while not server.quit: - server.handle_request() - server.server_close() - - def system_quit( self ):
- """ - Shut down the callback thread - """ - try: - self.BBServer.unregisterEventHandler(self.EventHandle) - except: - pass - self.server.quit = True - -class UIXMLRPCServer (SimpleXMLRPCServer): - - def __init__( self, interface = ("localhost", 0) ):
- self.quit = False - SimpleXMLRPCServer.__init__( self,
- interface,
- requestHandler=SimpleXMLRPCRequestHandler,
- logRequests=False, allow_none=True) - - def get_request(self): - while not self.quit: - try: - sock, addr = self.socket.accept() - sock.settimeout(1) - return (sock, addr) - except socket.timeout: - pass - return (None,None) - - def close_request(self, request): - if request is None: - return - SimpleXMLRPCServer.close_request(self, request) - - def process_request(self, request, client_address): - if request is None: - return - SimpleXMLRPCServer.process_request(self, request, client_address) -
- diff --git a/bitbake-dev/lib/bb/ui/uihelper.py b/bitbake-dev/lib/bb/ui/uihelper.py deleted file mode 100644 index 151ffc5854..0000000000 --- a/bitbake-dev/lib/bb/ui/uihelper.py +++ /dev/null @@ -1,49 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -# -# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer -# Copyright (C) 2006 - 2007 Richard Purdie -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -class BBUIHelper: - def __init__(self): - self.needUpdate = False - self.running_tasks = {} - self.failed_tasks = {} - - def eventHandler(self, event): - if isinstance(event, bb.build.TaskStarted): - self.running_tasks["%s %s\n" % (event._package, event._task)] = "" - self.needUpdate = True - if isinstance(event, bb.build.TaskSucceeded): - del self.running_tasks["%s %s\n" % (event._package, event._task)] - self.needUpdate = True - if isinstance(event, bb.build.TaskFailed): - del self.running_tasks["%s %s\n" % (event._package, event._task)] - self.failed_tasks["%s %s\n" % (event._package, event._task)] = "" - self.needUpdate = True - - # Add runqueue event handling - #if isinstance(event, bb.runqueue.runQueueTaskCompleted): - # a = 1 - #if isinstance(event, bb.runqueue.runQueueTaskStarted): - # a = 1 - #if isinstance(event, bb.runqueue.runQueueTaskFailed): - # a = 1 - #if isinstance(event, bb.runqueue.runQueueExitWait): - # a = 1 - - def getTasks(self): - return (self.running_tasks, self.failed_tasks) diff --git a/bitbake-dev/lib/bb/utils.py b/bitbake-dev/lib/bb/utils.py deleted file mode 100644 index 5fc1463e67..0000000000 --- a/bitbake-dev/lib/bb/utils.py +++ /dev/null @@ -1,431 +0,0 @@ -# ex:ts=4:sw=4:sts=4:et -# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- -""" -BitBake Utility Functions -""" - -# Copyright (C) 2004 Michael Lauer -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -digits = "0123456789" -ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" -separators = ".-" - -import re, fcntl, os, types - -def explode_version(s): - r = [] - alpha_regexp = re.compile('^([a-zA-Z]+)(.*)$') - numeric_regexp = re.compile('^(\d+)(.*)$') - while (s != ''): - if s[0] in digits: - m = numeric_regexp.match(s) - r.append(int(m.group(1))) - s = m.group(2) - continue - if s[0] in ascii_letters: - m = alpha_regexp.match(s) - r.append(m.group(1)) - s = m.group(2) - continue - r.append(s[0]) - s = s[1:] - return r - -def vercmp_part(a, b): - va = explode_version(a) - vb = explode_version(b) - sa = False - sb = False - while True: - if va == []: - ca = None - else: - ca = va.pop(0) - if vb == []: - cb = None - else: - cb = vb.pop(0) - if ca == None and cb == None: - return 0 - - if type(ca) is types.StringType: - sa = ca in separators - if type(cb) is types.StringType: - sb = cb in separators - if sa and not sb: - return -1 - if not sa and sb: - return 1 - - if ca > cb: - return 1 - if ca < cb: - return -1 - -def vercmp(ta, tb): - (ea, va, ra) = ta - (eb, vb, rb) = tb - - r = int(ea)-int(eb) - if (r == 0): - r = vercmp_part(va, vb) - if (r == 0): - r = vercmp_part(ra, rb) - return r - -def explode_deps(s): - """ - Take an RDEPENDS style string of format: - "DEPEND1 (optional version) DEPEND2 (optional version) ..." - and return a list of dependencies. - Version information is ignored. - """ - r = [] - l = s.split() - flag = False - for i in l: - if i[0] == '(': - flag = True - #j = [] - if not flag: - r.append(i) - #else: - # j.append(i) - if flag and i.endswith(')'): - flag = False - # Ignore version - #r[-1] += ' ' + ' '.join(j) - return r - -def explode_dep_versions(s): - """ - Take an RDEPENDS style string of format: - "DEPEND1 (optional version) DEPEND2 (optional version) ..." - and return a dictonary of dependencies and versions. - """ - r = {} - l = s.split() - lastdep = None - lastver = "" - inversion = False - for i in l: - if i[0] == '(': - inversion = True - lastver = i[1:] or "" - #j = [] - elif inversion and i.endswith(')'): - inversion = False - lastver = lastver + " " + (i[:-1] or "") - r[lastdep] = lastver - elif not inversion: - r[i] = None - lastdep = i - lastver = "" - elif inversion: - lastver = lastver + " " + i - - return r - -def _print_trace(body, line): - """ - Print the Environment of a Text Body - """ - import bb - - # print the environment of the method - 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.msg.error(bb.msg.domain.Util, "\t%.4d:%s" % (i, body[i-1]) ) - - -def better_compile(text, file, realfile): - """ - A better compile method. This method - will print the offending lines. - """ - try: - return compile(text, file, "exec") - except Exception, e: - import bb,sys - - # split the text into lines again - body = text.split('\n') - bb.msg.error(bb.msg.domain.Util, "Error in compiling python function in: ", 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) - - # exit now - sys.exit(1) - -def better_exec(code, context, text, realfile): - """ - Similiar to better_compile, better_exec will - print the lines that are responsible for the - error. - """ - import bb,sys - try: - exec code in context - except: - (t,value,tb) = sys.exc_info() - - if t in [bb.parse.SkipPackage, bb.build.FuncFailed]: - raise - - # print the Header of the Error Message - bb.msg.error(bb.msg.domain.Util, "Error in executing python function in: %s" % 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: - tb = tb.tb_next - - import traceback - line = traceback.tb_lineno(tb) - - _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 - -def lockfile(name): - """ - Use the file fn as a lock file, return when the lock has been acquired. - Returns a variable to pass to unlockfile(). - """ - path = os.path.dirname(name) - if not os.path.isdir(path): - import bb, sys - bb.msg.error(bb.msg.domain.Util, "Error, lockfile path does not exist!: %s" % path) - sys.exit(1) - - while True: - # If we leave the lockfiles lying around there is no problem - # but we should clean up after ourselves. This gives potential - # for races though. To work around this, when we acquire the lock - # we check the file we locked was still the lock file on disk. - # by comparing inode numbers. If they don't match or the lockfile - # no longer exists, we start again. - - # This implementation is unfair since the last person to request the - # lock is the most likely to win it. - - try: - lf = open(name, "a+") - fcntl.flock(lf.fileno(), fcntl.LOCK_EX) - statinfo = os.fstat(lf.fileno()) - if os.path.exists(lf.name): - statinfo2 = os.stat(lf.name) - if statinfo.st_ino == statinfo2.st_ino: - return lf - # File no longer exists or changed, retry - lf.close - except Exception, e: - continue - -def unlockfile(lf): - """ - Unlock a file locked using lockfile() - """ - os.unlink(lf.name) - fcntl.flock(lf.fileno(), fcntl.LOCK_UN) - lf.close - -def md5_file(filename): - """ - Return the hex string representation of the MD5 checksum of filename. - """ - try: - import hashlib - m = hashlib.md5() - except ImportError: - import md5 - m = md5.new() - - for line in open(filename): - m.update(line) - return m.hexdigest() - -def sha256_file(filename): - """ - Return the hex string representation of the 256-bit SHA checksum of - filename. On Python 2.4 this will return None, so callers will need to - handle that by either skipping SHA checks, or running a standalone sha256sum - binary. - """ - try: - import hashlib - except ImportError: - return None - - s = hashlib.sha256() - for line in open(filename): - s.update(line) - return s.hexdigest() - -def preserved_envvars_list(): - return [ - 'BBPATH', - 'BB_PRESERVE_ENV', - 'BB_ENV_WHITELIST', - 'BB_ENV_EXTRAWHITE', - 'COLORTERM', - 'DBUS_SESSION_BUS_ADDRESS', - 'DESKTOP_SESSION', - 'DESKTOP_STARTUP_ID', - 'DISPLAY', - 'GNOME_KEYRING_PID', - 'GNOME_KEYRING_SOCKET', - 'GPG_AGENT_INFO', - 'GTK_RC_FILES', - 'HOME', - 'LANG', - 'LOGNAME', - 'PATH', - 'PWD', - 'SESSION_MANAGER', - 'SHELL', - 'SSH_AUTH_SOCK', - 'TERM', - 'USER', - 'USERNAME', - '_', - 'XAUTHORITY', - 'XDG_DATA_DIRS', - 'XDG_SESSION_COOKIE', - ] - -def filter_environment(good_vars): - """ - Create a pristine environment for bitbake. This will remove variables that - are not known and may influence the build in a negative way. - """ - - import bb - - removed_vars = [] - for key in os.environ.keys(): - if key in good_vars: - continue - - removed_vars.append(key) - os.unsetenv(key) - del os.environ[key] - - if len(removed_vars): - bb.debug(1, "Removed the following variables from the environment:", ",".join(removed_vars)) - - return removed_vars - -def clean_environment(): - """ - Clean up any spurious environment variables. This will remove any - variables the user hasn't chose to preserve. - """ - if 'BB_PRESERVE_ENV' not in os.environ: - if 'BB_ENV_WHITELIST' in os.environ: - good_vars = os.environ['BB_ENV_WHITELIST'].split() - else: - good_vars = preserved_envvars_list() - if 'BB_ENV_EXTRAWHITE' in os.environ: - good_vars.extend(os.environ['BB_ENV_EXTRAWHITE'].split()) - filter_environment(good_vars) - -def empty_environment(): - """ - Remove all variables from the environment. - """ - for s in os.environ.keys(): - os.unsetenv(s) - del os.environ[s] - -def build_environment(d): - """ - Build an environment from all exported variables. - """ - import bb - for var in bb.data.keys(d): - export = bb.data.getVarFlag(var, "export", d) - if export: - os.environ[var] = bb.data.getVar(var, d, True) - -def prunedir(topdir): - # Delete everything reachable from the directory named in 'topdir'. - # CAUTION: This is dangerous! - for root, dirs, files in os.walk(topdir, topdown=False): - for name in files: - os.remove(os.path.join(root, name)) - for name in dirs: - if os.path.islink(os.path.join(root, name)): - os.remove(os.path.join(root, name)) - else: - os.rmdir(os.path.join(root, name)) - os.rmdir(topdir) - -# -# Could also use return re.compile("(%s)" % "|".join(map(re.escape, suffixes))).sub(lambda mo: "", var) -# but thats possibly insane and suffixes is probably going to be small -# -def prune_suffix(var, suffixes, d): - # See if var ends with any of the suffixes listed and - # remove it if found - for suffix in suffixes: - if var.endswith(suffix): - return var.replace(suffix, "") - return var |