diff -r e1eecf4d390d -r 593a8820b912 sbsv2/raptor/python/raptor_data.py --- a/sbsv2/raptor/python/raptor_data.py Mon Nov 16 09:46:46 2009 +0000 +++ b/sbsv2/raptor/python/raptor_data.py Mon Nov 16 20:39:37 2009 +0000 @@ -27,8 +27,13 @@ import subprocess from tempfile import gettempdir from time import time, clock +import traceback +import raptor_cache +class MissingInterfaceError(Exception): + def __init__(self, s): + Exception.__init__(self,s) # What host platforms we recognise # This allows us to tie some variants to one host platform and some to another @@ -68,16 +73,14 @@ class Model(object): "Base class for data-model objects" + __slots__ = ('host', 'source', 'cacheID') + def __init__(self): - self.owner = None # Raptor object self.source = None # XML file - self.indent = " " # for DebugPrint self.host = None self.cacheID = "" # default set of cached objects - - - def SetOwner(self, aRaptor): - self.owner = aRaptor + # not using the cache parameter - there to make the + # init for all Model objects "standard" def SetSourceFile(self, filename): @@ -92,10 +95,6 @@ raise InvalidChildError() - def DebugPrint(self, prefix = ""): - if self.owner: - self.owner.Debug("%s", prefix) - def Valid(self): return False @@ -139,8 +138,7 @@ def Resolve(self): raise BadReferenceError() - def GetModifiers(self): - cache = self.owner.cache + def GetModifiers(self, cache): return [ cache.FindNamedVariant(m) for m in self.modifiers ] def Valid(self): @@ -154,20 +152,13 @@ self.variants = [] - def SetOwner(self, aRaptor): - Model.SetOwner(self, aRaptor) - for v in self.variants: - v.SetOwner(aRaptor) - - - def DebugPrint(self, prefix = ""): - for v in self.variants: - v.DebugPrint(prefix) + def __str__(self): + return "\n".join([str(v) for v in self.variants]) def AddVariant(self, variant): if type(variant) is types.StringTypes: - variant = VariantRef(variant) + variant = VariantRef(ref = variant) # Only add the variant if it's not in the list @@ -175,15 +166,19 @@ if not variant in self.variants: self.variants.append(variant) - def GetVariants(self): + def GetVariants(self, cache): # resolve any VariantRef objects into Variant objects + missing_variants = [] for i,var in enumerate(self.variants): if isinstance(var, Reference): try: - self.variants[i] = var.Resolve() + self.variants[i] = var.Resolve(cache=cache) except BadReferenceError: - self.owner.Error("Missing variant '%s'", var.ref) + missing_variants.append(var.ref) + + if len(missing_variants) > 0: + raise MissingVariantException("Missing variants '%s'", " ".join(missing_variants)) return self.variants @@ -199,27 +194,25 @@ self.params = [] self.paramgroups = [] - def DebugPrint(self, prefix = ""): - self.owner.Debug("%s", prefix, self.name) - self.owner.Debug("%s...", prefix) - self.owner.Debug("%s", prefix) + def __str__(self): + return "" % self.name + "" - def FindParent(self): + def FindParent(self, cache): try: - return self.owner.cache.FindNamedInterface(self.extends, self.cacheID) + return cache.FindNamedInterface(self.extends, self.cacheID) except KeyError: raise BadReferenceError("Cannot extend interface because it cannot be found: "+str(self.extends)) - def GetParams(self): + def GetParams(self, cache): if self.extends != None: - parent = self.FindParent() + parent = self.FindParent(cache) # what parameter names do we have already? names = set([x.name for x in self.params]) # pick up ones we don't have that are in our parent pp = [] - for p in parent.GetParams(): + for p in parent.GetParams(cache): if not p.name in names: pp.append(p) @@ -229,29 +222,29 @@ return self.params - def GetParamGroups(self): + def GetParamGroups(self, cache): if self.extends != None: - parent = self.FindParent() + parent = self.FindParent(cache) # what parameter names do we have already? patterns = set([x.pattern for x in self.paramgroups]) # pick up ones we don't have that are in our parent - for g in parent.GetParamGroups(): + for g in parent.GetParamGroups(cache): if not g.pattern in patterns: self.paramgroups.append(g) return self.paramgroups - def GetFLMIncludePath(self): + def GetFLMIncludePath(self, cache): "absolute path to the FLM" if self.flm == None: if self.extends != None: - parent = self.FindParent() + parent = self.FindParent(cache) - return parent.GetFLMIncludePath() + return parent.GetFLMIncludePath(cache) else: raise InvalidPropertyError() @@ -295,12 +288,12 @@ class InterfaceRef(Reference): - def DebugPrint(self, prefix = ""): - self.owner.Debug("%s", prefix, self.ref) + def __str__(self): + return "" % self.ref - def Resolve(self): + def Resolve(self, cache): try: - return self.owner.cache.FindNamedInterface(self.ref, self.cacheID) + return cache.FindNamedInterface(self.ref, self.cacheID) except KeyError: raise BadReferenceError() @@ -316,24 +309,13 @@ self.parentSpec = None - def DebugPrint(self, prefix = ""): - self.owner.Debug("%s", prefix, self.name) - if self.interface: - self.interface.DebugPrint(prefix + self.indent) - VariantContainer.DebugPrint(self, prefix + self.indent) + def __str__(self): + s = "" % str(self.name) + s += VariantContainer.__str__(self) for c in self.childSpecs: - c.DebugPrint(prefix + self.indent) - self.owner.Debug("%s", prefix) - - - def SetOwner(self, aRaptor): - VariantContainer.SetOwner(self, aRaptor) - - if self.interface != None: - self.interface.SetOwner(aRaptor) - - for s in self.childSpecs: - s.SetOwner(aRaptor) + s += str(c) + '\n' + s += "" + return s def SetProperty(self, name, value): @@ -343,10 +325,10 @@ raise InvalidPropertyError() - def Configure(self, config): + def Configure(self, config, cache): # configure all the children (some may be Filters or parents of) for spec in self.GetChildSpecs(): - spec.Configure(config) + spec.Configure(config, cache = cache) def HasInterface(self): @@ -358,10 +340,10 @@ or isinstance(interface, InterfaceRef): self.interface = interface else: - self.interface = InterfaceRef(interface) + self.interface = InterfaceRef(ref = interface) - def GetInterface(self): + def GetInterface(self, cache): """return the Interface (fetching from the cache if it was a ref) may return None""" @@ -371,13 +353,11 @@ if isinstance(self.interface, InterfaceRef): try: - self.interface = self.interface.Resolve() + self.interface = self.interface.Resolve(cache=cache) return self.interface except BadReferenceError: - self.owner.Error("Missing interface %s", self.interface.ref) - return None - + raise MissingInterfaceError("Missing interface %s" % self.interface.ref) def AddChild(self, child): if isinstance(child, Specification): @@ -409,7 +389,7 @@ return True - def GetAllVariantsRecursively(self): + def GetAllVariantsRecursively(self, cache): """Returns all variants contained in this node and in its ancestors. The returned value is a list, the structure of which is [variants-in-parent, @@ -419,11 +399,11 @@ the variants themselves. """ if self.parentSpec: - variants = self.parentSpec.GetAllVariantsRecursively() + variants = self.parentSpec.GetAllVariantsRecursively(cache = cache) else: variants = [] - variants.extend( self.GetVariants() ) + variants.extend( self.GetVariants(cache = cache) ) return variants @@ -438,22 +418,21 @@ If several Conditions are set, the test is an OR of all of them.""" def __init__(self, name = ""): - Specification.__init__(self, name) # base class constructor - self.Else = Specification(name) # same for Else part + Specification.__init__(self, name = name) # base class constructor + self.Else = Specification(name = name) # same for Else part self.isTrue = True self.configNames = set() # self.variableNames = set() # TO DO: Condition class self.variableValues = {} # - def DebugPrint(self, prefix = ""): - self.owner.Debug("%s", prefix, self.name) - self.owner.Debug("%s ", prefix, " | ".join(self.configNames)) - Specification.DebugPrint(self, prefix + self.indent) - self.owner.Debug("%s ", prefix) - self.owner.Debug("%s ", prefix) - self.Else.DebugPrint(prefix + self.indent) - self.owner.Debug("%s ", prefix) - self.owner.Debug("%s", prefix) + def __str__(self, prefix = ""): + s = "\n"% self.name + s += "\n" % " | ".join(self.configNames) + s += Specification.__str__(self) + s += "\n \n" + s += str(self.Else) + s += " \n\n" + return s def SetConfigCondition(self, configName): @@ -478,13 +457,14 @@ self.variableValues[variableName] = set([variableValues]) - def Configure(self, buildUnit): + def Configure(self, buildUnit, cache): self.isTrue = False if buildUnit.name in self.configNames: self.isTrue = True elif self.variableNames: - evaluator = self.owner.GetEvaluator(self.parentSpec, buildUnit) + + evaluator = Evaluator(self.parentSpec, buildUnit, cache=cache) for variableName in self.variableNames: variableValue = evaluator.Get(variableName) @@ -495,14 +475,7 @@ # configure all the children too for spec in self.GetChildSpecs(): - spec.Configure(buildUnit) - - - def SetOwner(self, aRaptor): - # base class method - Specification.SetOwner(self, aRaptor) - # same for Else part - self.Else.SetOwner(aRaptor) + spec.Configure(buildUnit, cache=cache) def HasInterface(self): @@ -512,18 +485,18 @@ return self.Else.HasInterface() - def GetInterface(self): + def GetInterface(self, cache): if self.isTrue: - return Specification.GetInterface(self) + return Specification.GetInterface(self, cache = cache) else: - return self.Else.GetInterface() + return self.Else.GetInterface(cache = cache) - def GetVariants(self): + def GetVariants(self, cache): if self.isTrue: - return Specification.GetVariants(self) + return Specification.GetVariants(self, cache = cache) else: - return self.Else.GetVariants() + return self.Else.GetVariants(cache = cache) def SetParentSpec(self, parent): @@ -591,18 +564,17 @@ class Operation(Model): "Base class for variant operations" + __slots__ = 'type' def __init__(self): Model.__init__(self) # base class constructor self.type = None - def Apply(self, oldValue): pass class Append(Operation): - __slots__ = ('name','value','separator','owner') - + __slots__ = ('name', 'value', 'separator') def __init__(self, name = None, value = None, separator = " "): Operation.__init__(self) # base class constructor self.name = name @@ -610,9 +582,9 @@ self.separator = separator - def DebugPrint(self, prefix = ""): + def __str__(self): attributes = "name='" + self.name + "' value='" + self.value + "' separator='" + self.separator + "'" - self.owner.Debug("%s", prefix, attributes) + return "" % attributes def Apply(self, oldValue): @@ -641,6 +613,7 @@ class Prepend(Operation): + __slots__ = ('name', 'value', 'separator') def __init__(self, name = None, value = None, separator = " "): Operation.__init__(self) # base class constructor self.name = name @@ -648,9 +621,9 @@ self.separator = separator - def DebugPrint(self, prefix = ""): + def __str__(self, prefix = ""): attributes = "name='" + self.name + "' value='" + self.value + "' separator='" + self.separator + "'" - self.owner.Debug("%s", prefix, attributes) + return "" % prefix def Apply(self, oldValue): @@ -679,8 +652,8 @@ class Set(Operation): + __slots__ = ('name', 'value', 'type', 'versionCommand', 'versionResult') """implementation of operation""" - __slots__ = ('name','value', 'type', 'versionCommand', 'versionResult', 'owner') def __init__(self, name = None, value = "", type = ""): Operation.__init__(self) # base class constructor @@ -691,12 +664,12 @@ self.versionResult = "" - def DebugPrint(self, prefix = ""): + def __str__(self): attributes = "name='" + self.name + "' value='" + self.value + "' type='" + self.type + "'" if type == "tool": attributes += " versionCommand='" + self.versionCommand + "' versionResult='" + self.versionResult - self.owner.Debug("%s", prefix, attributes) + return "" % attributes def Apply(self, oldValue): @@ -724,6 +697,8 @@ def Valid(self): return (self.name != None and self.value != None) +class BadToolValue(Exception): + pass class Env(Set): """implementation of operator""" @@ -733,7 +708,7 @@ self.default = default - def DebugPrint(self, prefix = ""): + def __str__(self): attributes = "name='" + self.name + "' type='" + self.type + "'" if default != None: attributes += " default='" + self.default + "'" @@ -741,7 +716,7 @@ if type == "tool": attributes += " versionCommand='" + self.versionCommand + "' versionResult='" + self.versionResult + "'" - self.owner.Debug("%s", prefix, attributes) + return "" % attributes def Apply(self, oldValue): @@ -755,14 +730,12 @@ path = generic_path.Path(value) value = str(path.Absolute()) except ValueError,e: - self.owner.Error("the environment variable %s is incorrect: %s" % (self.name, str(e))) - return "NO_VALUE_FOR_" + self.name + raise BadToolValue("the environment variable %s is incorrect: %s" % (self.name, str(e))) except KeyError: if self.default != None: value = self.default else: - self.owner.Error("%s is not set in the environment and has no default", self.name) - return "NO_VALUE_FOR_" + self.name + raise BadToolValue("%s is not set in the environment and has no default" % self.name) return value @@ -791,7 +764,7 @@ self.operations = [] self.variantKey = "" - def GetOperations(self): + def GetOperations(self, cache): """Return all operations related to this BuildUnit. The result is cached, and so will only be computed once per BuildUnit. @@ -800,7 +773,7 @@ if self.variantKey != key: self.variantKey = key for v in self.variants: - self.operations.extend( v.GetAllOperationsRecursively() ) + self.operations.extend( v.GetAllOperationsRecursively(cache=cache) ) return self.operations @@ -820,7 +793,7 @@ def ClearModifiers(self): self.modifiers = [] - def GenerateBuildUnits(self): + def GenerateBuildUnits(self,cache): """Returns a list of BuildUnits. This function must be overridden by derived classes. @@ -830,6 +803,8 @@ class Variant(Model, Config): + __slots__ = ('cache','name','host','extends','ops','variantRefs','allOperations') + def __init__(self, name = ""): Model.__init__(self) Config.__init__(self) @@ -868,20 +843,10 @@ def Valid(self): return self.name - def SetOwner(self, aRaptor): - - Model.SetOwner(self, aRaptor) - - for r in self.variantRefs: - r.SetOwner(aRaptor) - - for op in self.ops: - op.SetOwner(aRaptor) - def AddOperation(self, op): self.ops.append(op) - def GetAllOperationsRecursively(self): + def GetAllOperationsRecursively(self, cache): """Returns a list of all operations in this variant. The list elements are themselves lists; the overall structure of the @@ -892,16 +857,16 @@ if not self.allOperations: if self.extends: - parent = self.owner.cache.FindNamedVariant(self.extends) - self.allOperations.extend( parent.GetAllOperationsRecursively() ) + parent = cache.FindNamedVariant(self.extends) + self.allOperations.extend( parent.GetAllOperationsRecursively(cache = cache) ) for r in self.variantRefs: - for v in [ r.Resolve() ] + r.GetModifiers(): - self.allOperations.extend( v.GetAllOperationsRecursively() ) + for v in [ r.Resolve(cache = cache) ] + r.GetModifiers(cache = cache): + self.allOperations.extend( v.GetAllOperationsRecursively(cache = cache) ) self.allOperations.append(self.ops) return self.allOperations - def GenerateBuildUnits(self): + def GenerateBuildUnits(self,cache): name = self.name vars = [self] @@ -909,32 +874,32 @@ for m in self.modifiers: name = name + "." + m.name vars.append(m) - - return [ BuildUnit(name, vars) ] - - def DebugPrint(self, prefix = ""): + return [ BuildUnit(name=name, variants=vars) ] - self.owner.Debug("%s", prefix, self.name, self.extends) + def __str__(self): + s = "\n" % (self.name, self.extends) for op in self.ops: - op.DebugPrint(prefix + self.indent) + s += str(op) + '\n' + s += "" + return s - self.owner.Debug("%s", prefix) - - +import traceback class VariantRef(Reference): def __init__(self, ref=None): - Reference.__init__(self, ref) + Reference.__init__(self, ref = ref) - def DebugPrint(self, prefix = ""): - self.owner.Debug("%s", prefix, self.ref) + def __str__(self): + return "" % self.ref - def Resolve(self): + def Resolve(self, cache): try: - return self.owner.cache.FindNamedVariant(self.ref) - except KeyError: + return cache.FindNamedVariant(self.ref) + except KeyError, e: raise BadReferenceError(self.ref) +class MissingVariantException(Exception): + pass class Alias(Model, Config): @@ -946,8 +911,8 @@ self.varRefs = [] self.variants = [] - def DebugPrint(self, prefix = ""): - self.owner.Debug("%s", prefix, self.name, self.meaning) + def __str__(self): + return "" % (self.name, self.meaning) def SetProperty(self, key, val): if key == "name": @@ -956,32 +921,31 @@ self.meaning = val for u in val.split("."): - self.varRefs.append( VariantRef(u) ) + self.varRefs.append( VariantRef(ref = u) ) else: raise InvalidPropertyError() - def SetOwner(self, raptor): - Model.SetOwner(self, raptor) - for r in self.varRefs: - r.SetOwner(raptor) - def Valid(self): return self.name and self.meaning - def GenerateBuildUnits(self): + def GenerateBuildUnits(self, cache): if not self.variants: + missing_variants = [] for r in self.varRefs: try: - self.variants.append( r.Resolve() ) + self.variants.append( r.Resolve(cache=cache) ) except BadReferenceError: - self.owner.Error("Missing variant '%s'", r.ref) + missing_variants.append(r.ref) + + if len(missing_variants) > 0: + raise MissingVariantException("Missing variants '%s'", " ".join(missing_variants)) name = self.name for v in self.modifiers: name = name + "." + v.name - return [ BuildUnit(name, self.variants + self.modifiers) ] + return [ BuildUnit(name=name, variants=self.variants + self.modifiers) ] class AliasRef(Reference): @@ -989,12 +953,12 @@ def __init__(self, ref=None): Reference.__init__(self, ref) - def DebugPrint(self, prefix = ""): - self.owner.Debug("%s", prefix, self.ref) + def __str__(self): + return "" % self.ref - def Resolve(self): + def Resolve(self, cache): try: - return self.owner.cache.FindNamedAlias(self.ref) + return cache.FindNamedAlias(self.ref) except KeyError: raise BadReferenceError(self.ref) @@ -1018,41 +982,37 @@ else: raise InvalidChildError() - def SetOwner(self, raptor): - Model.SetOwner(self, raptor) - for r in self.childRefs: - r.SetOwner(raptor) - def Valid(self): return self.name and self.childRefs - def DebugPrint(self, prefix = ""): - - self.owner.Debug("", prefix, self.name) - + def __str__(self): + s = "" % self.name for r in self.childRefs: - r.DebugPrint(prefix + self.indent) + s += str(r) + s += "" + return s - self.owner.Debug("%s", prefix) - - def GenerateBuildUnits(self): - + def GenerateBuildUnits(self, cache): units = [] + missing_variants = [] for r in self.childRefs: - refMods = r.GetModifiers() + refMods = r.GetModifiers(cache) try: - obj = r.Resolve() + obj = r.Resolve(cache=cache) except BadReferenceError: - self.owner.Error("Missing variant '%s'", r.ref) + missing_variants.append(r.ref) else: obj.ClearModifiers() for m in refMods + self.modifiers: obj.AddModifier(m) - units.extend( obj.GenerateBuildUnits() ) + units.extend( obj.GenerateBuildUnits(cache) ) + + if len(missing_variants) > 0: + raise MissingVariantException("Missing variants '%s'", " ".join(missing_variants)) return units @@ -1062,19 +1022,27 @@ def __init__(self, ref=None): Reference.__init__(self, ref) - def DebugPrint(self, prefix = ""): - mod = ".".join(self.modifiers) - self.owner.Debug("%s", prefix, self.ref, mod) + def __str__(self): + return "<%s />" % (prefix, self.ref, ".".join(self.modifiers)) - def Resolve(self): + def Resolve(self, cache): try: - return self.owner.cache.FindNamedGroup(self.ref) + return cache.FindNamedGroup(self.ref) except KeyError: raise BadReferenceError(self.ref) +class ToolErrorException(Exception): + def __init__(self, s): + Exception.__init__(self,s) + class Tool(object): """Represents a tool that might be used by raptor e.g. a compiler""" + # It's difficult and expensive to give each tool a log reference but a class one + # will facilitate debugging when that is needed without being a design flaw the + # rest of the time. + log = raptor_utilities.nulllog + # For use in dealing with tools that return non-ascii version strings. nonascii = "" identity_chartable = chr(0) @@ -1084,7 +1052,7 @@ nonascii += chr(c) identity_chartable += " " - def __init__(self, name, command, versioncommand, versionresult, id="", log = raptor_utilities.nulllog): + def __init__(self, name, command, versioncommand, versionresult, id=""): self.name = name self.command = command self.versioncommand = versioncommand @@ -1097,7 +1065,6 @@ # version until someone proves that it's OK self.valid = False - self.log=log def expand(self, toolset): self.versioncommand = toolset.ExpandAll(self.versioncommand) @@ -1117,7 +1084,7 @@ # If it really is not a simple command then we won't be able to get a date and # we won't be able to tell if it is altered or updated - too bad! testfile = generic_path.Where(self.command) - self.log.Debug("toolcheck: tool '%s' was found on the path at '%s' ", self.command, testfile) + #self.log.Debug("toolcheck: tool '%s' was found on the path at '%s' ", self.command, testfile) if testfile is None: raise Exception("Can't be found in path") @@ -1127,18 +1094,20 @@ testfile_stat = os.stat(testfile) self.date = testfile_stat.st_mtime except Exception,e: - self.log.Debug("toolcheck: '%s=%s' cannot be dated - this is ok, but the toolcheck won't be able to tell when a new of the tool is installed. (%s)", self.name, self.command, str(e)) + # We really don't mind if the tool could not be dated - for any reason + Tool.log.Debug("toolcheck: '%s=%s' cannot be dated - this is ok, but the toolcheck won't be able to tell when a new version of the tool is installed. (%s)", self.name, self.command, str(e)) + pass - def check(self, shell, evaluator): + def check(self, shell, evaluator, log = raptor_utilities.nulllog): self.vre = re.compile(self.versionresult) try: self.log.Debug("Pre toolcheck: '%s' for version '%s'", self.name, self.versionresult) p = subprocess.Popen(args=[shell, "-c", self.versioncommand], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + log.Debug("Checking tool '%s' for version '%s'", self.name, self.versionresult) versionoutput,err = p.communicate() - self.log.Debug("Checking tool '%s' for version '%s'", self.name, self.versionresult) except Exception,e: versionoutput=None @@ -1148,12 +1117,11 @@ versionoutput_a = versionoutput.translate(Tool.identity_chartable,"") if versionoutput_a and self.vre.search(versionoutput_a) != None: - self.log.Debug("tool '%s' returned an acceptable version '%s' at %s", self.name, versionoutput_a, str(self.date)) + log.Debug("tool '%s' returned an acceptable version '%s'", self.name, versionoutput_a) self.valid = True else: - self.log.Error("tool '%s' from config '%s' did not return version '%s' as required.\nCommand '%s' returned:\n%s\nCheck your environment and configuration.\n", self.name, self.id, self.versionresult, self.versioncommand, versionoutput_a) self.valid = False - return self.valid + raise ToolErrorException("tool '%s' from config '%s' did not return version '%s' as required.\nCommand '%s' returned:\n%s\nCheck your environment and configuration.\n" % (self.name, self.id, self.versionresult, self.versioncommand, versionoutput_a)) def envhash(irrelevant_vars): """Determine something unique about this environment to identify it. @@ -1175,16 +1143,19 @@ write() is used to flush the cache to disc. """ # The raptor shell - this is not mutable. - hostbinaries = os.path.join(os.environ['SBS_HOME'], - os.environ['HOSTPLATFORM_DIR']) + if 'SBS_SHELL' in os.environ: + shell = os.environ['SBS_SHELL'] + else: + hostbinaries = os.path.join(os.environ['SBS_HOME'], + os.environ['HOSTPLATFORM_DIR']) - if HostPlatform.IsHost('lin*'): - shell=os.path.join(hostbinaries, 'bin/bash') - else: - if 'SBS_CYGWIN' in os.environ: - shell=os.path.join(os.environ['SBS_CYGWIN'], 'bin\\bash.exe') + if HostPlatform.IsHost('lin*'): + shell=os.path.join(hostbinaries, 'bin/bash') else: - shell=os.path.join(hostbinaries, 'cygwin\\bin\\bash.exe') + if 'SBS_CYGWIN' in os.environ: + shell=os.path.join(os.environ['SBS_CYGWIN'], 'bin\\bash.exe') + else: + shell=os.path.join(hostbinaries, 'cygwin\\bin\\bash.exe') irrelevant_vars = ['PWD','OLDPWD','PID','PPID', 'SHLVL' ] @@ -1255,7 +1226,6 @@ except Exception, e: log.Info("Ignoring garbled toolcheck cache: %s (%s)\n", self.cachefilename, str(e)) self.__toolcheckcache = {} - else: log.Info("Toolcheck cache %s ignored - environment changed\n", self.cachefilename) @@ -1316,8 +1286,11 @@ self.log.Debug("toolcheck done: %s -key: %s" % (tool.name, tool.key)) - if not tool.check(ToolSet.shell, evaluator): + try: + tool.check(ToolSet.shell, evaluator, log = self.log) + except ToolErrorException, e: self.valid = False + self.log.Error("%s\n" % str(e)) # Tool failures are cached just like successes - don't want to repeat them cache[tool.key] = { "name" : tool.name, "valid" : tool.valid, "age" : 0 , "date" : tool.date } @@ -1356,6 +1329,8 @@ self.log.Info("Could not write toolcheck cache: %s", str(e)) return self.valid +class UninitialisedVariableException(Exception): + pass class Evaluator(object): """Determine the values of variables under different Configurations. @@ -1364,11 +1339,11 @@ refRegex = re.compile("\$\((.+?)\)") - def __init__(self, Raptor, specification, buildUnit, gathertools = False): - self.raptor = Raptor + def __init__(self, specification, buildUnit, cache, gathertools = False): self.dict = {} self.tools = [] self.gathertools = gathertools + self.cache = cache specName = "none" configName = "none" @@ -1377,14 +1352,18 @@ opsLists = [] if buildUnit: - opsLists.extend( buildUnit.GetOperations() ) + ol = buildUnit.GetOperations(cache) + self.buildUnit = buildUnit + + opsLists.extend( ol ) if specification: - for v in specification.GetAllVariantsRecursively(): - opsLists.extend( v.GetAllOperationsRecursively() ) + for v in specification.GetAllVariantsRecursively(cache): + opsLists.extend( v.GetAllOperationsRecursively(cache) ) tools = {} + unfound_values = [] for opsList in opsLists: for op in opsList: # applying an Operation to a non-existent variable @@ -1394,13 +1373,20 @@ except KeyError: oldValue = "" - newValue = op.Apply(oldValue) + try: + newValue = op.Apply(oldValue) + except BadToolValue, e: + unfound_values.append(str(e)) + newValue = "NO_VALUE_FOR_" + op.name + self.dict[op.name] = newValue if self.gathertools: if op.type == "tool" and op.versionCommand and op.versionResult: - tools[op.name] = Tool(op.name, newValue, op.versionCommand, op.versionResult, configName, log = self.raptor) + tools[op.name] = Tool(op.name, newValue, op.versionCommand, op.versionResult, configName) + if len(unfound_values) > 0: + raise UninitialisedVariableException("\n".join(unfound_values)) if self.gathertools: self.tools = tools.values() @@ -1417,8 +1403,8 @@ unresolved = False for k, v in self.dict.items(): if v.find('$(' + k + ')') != -1: - self.raptor.Error("Recursion Detected in variable '%s' in configuration '%s' ",k,configName) - expanded = "RECURSIVE_INVALID_STRING" + raise RecursionException("Recursion Detected in variable '%s' in configuration '%s' " % (k,configName)) + expanded = "RECURSIVE_INVALID_STRING" else: expanded = self.ExpandAll(v, specName, configName) @@ -1466,20 +1452,24 @@ refs = Evaluator.refRegex.findall(value) + # store up all the unset variables before raising an exception + # to allow us to find them all + unset_variables = [] + for r in set(refs): expansion = None - if r in self.raptor.override: - expansion = self.raptor.override[r] - elif r in self.dict: + if r in self.dict: expansion = self.dict[r] else: # no expansion for $(r) - self.raptor.Error("Unset variable '%s' used in spec '%s' with config '%s'", - r, spec, config) + unset_variables.append("Unset variable '%s' used in spec '%s' with config '%s'" % (r, spec, config)) if expansion != None: value = value.replace("$(" + r + ")", expansion) + if len(unset_variables) > 0: # raise them all + raise UninitialisedVariableException(". ".join(unset_variables)) + return value