sbsv2/raptor/python/raptor_data.py
changeset 412 824dddcc66f7
parent 400 554cc189839f
child 498 564986768b79
equal deleted inserted replaced
406:698b9b7141d7 412:824dddcc66f7
    63 		return False
    63 		return False
    64 
    64 
    65 
    65 
    66 # Make sure not to start up on an unsupported platform
    66 # Make sure not to start up on an unsupported platform
    67 if not HostPlatform.IsKnown(HostPlatform.hostplatform):
    67 if not HostPlatform.IsKnown(HostPlatform.hostplatform):
    68 	raise Exception("raptor_data module loaded on an unrecognised platform '%s'. Expected one of %s" % (hostplatform, str(hostplatforms)))
    68 	raise Exception("raptor_data module loaded on an unrecognised platform '%s'. Expected one of %s" % (HostPlatform.hostplatform, str(HostPlatform.hostplatforms)))
    69 
    69 
    70 
    70 
    71 # raptor_data module classes
    71 # raptor_data module classes
    72 
    72 
    73 class Model(object):
    73 class Model(object):
   137 
   137 
   138 	def Resolve(self):
   138 	def Resolve(self):
   139 		raise BadReferenceError()
   139 		raise BadReferenceError()
   140 
   140 
   141 	def GetModifiers(self, cache):
   141 	def GetModifiers(self, cache):
   142 		return [ cache.FindNamedVariant(m) for m in self.modifiers ]
   142 		mods = []
       
   143 		for m in self.modifiers:
       
   144 			try:
       
   145 				mods.append(cache.FindNamedVariant(m))
       
   146 			except KeyError:
       
   147 				raise BadReferenceError(m)
       
   148 		return mods
   143 
   149 
   144 	def Valid(self):
   150 	def Valid(self):
   145 		return self.ref
   151 		return self.ref
   146 
   152 
   147 
   153 
   708 		self.default = default
   714 		self.default = default
   709 
   715 
   710 
   716 
   711 	def __str__(self):
   717 	def __str__(self):
   712 		attributes = "name='" + self.name + "' type='" + self.type + "'"
   718 		attributes = "name='" + self.name + "' type='" + self.type + "'"
   713 		if default != None:
   719 		if self.default != None:
   714 			attributes += " default='" + self.default + "'"
   720 			attributes += " default='" + self.default + "'"
   715 
   721 
   716 		if type == "tool":
   722 		if type == "tool":
   717 			attributes += " versionCommand='" + self.versionCommand + "' versionResult='" + self.versionResult + "'"
   723 			attributes += " versionCommand='" + self.versionCommand + "' versionResult='" + self.versionResult + "'"
   718 
   724 
   722 	def Apply(self, oldValue):
   728 	def Apply(self, oldValue):
   723 		try:
   729 		try:
   724 			value = os.environ[self.name]
   730 			value = os.environ[self.name]
   725 			
   731 			
   726 			if value:
   732 			if value:
   727 				# if this value is a "path" or a "tool" then we need to make sure
   733 				if self.type in ["path", "tool", "toolchainpath"]:
   728 				# it is a proper absolute path in our preferred format.
   734 					# if this value is some sort of path or tool then we need to make sure
   729 				if self.type == "path" or self.type == "tool":
   735 					# it is a proper absolute path in our preferred format.
   730 					try:
   736 					try:
   731 						path = generic_path.Path(value)
   737 						path = generic_path.Path(value)
   732 						value = str(path.Absolute())
   738 						value = str(path.Absolute())
   733 					except ValueError,e:
   739 					except ValueError,e:
   734 						raise BadToolValue("the environment variable %s is incorrect: %s" % (self.name, str(e)))				
   740 						raise BadToolValue("the environment variable %s is incorrect: %s" % (self.name, str(e)))
   735 				# if this value ends in an un-escaped backslash, then it will be treated as a line continuation character
   741 					
   736 				# in makefile parsing - un-escaped backslashes at the end of values are therefore escaped
   742 					if self.type in ["tool", "toolchainpath"]:
       
   743 						# if  we're dealing with tool-related values, then make sure that we can get "safe"
       
   744 						# versions if they contain spaces - if we can't, that's an error, as they won't
       
   745 						# survive full usage in the toolcheck or when used and/or referenced in FLMs						
       
   746 						if ' ' in value:
       
   747 							path = generic_path.Path(value)
       
   748 							spaceSafeValue = path.GetSpaceSafePath()
       
   749 						
       
   750 							if not spaceSafeValue:
       
   751 								raise BadToolValue("the environment variable %s is incorrect - it is a '%s' type but contains spaces that cannot be neutralised: %s" % (self.name, self.type, value))
       
   752 							
       
   753 							value = spaceSafeValue	
   737 				elif value.endswith('\\'):
   754 				elif value.endswith('\\'):
   738 					# an odd number of backslashes means there's one to escape
   755 					# if this value ends in an un-escaped backslash, then it will be treated as a line continuation character
   739 					count = len(value) - len(value.rstrip('\\'))
   756 					# in makefile parsing - un-escaped backslashes at the end of values are therefore escaped					
       
   757 					count = len(value) - len(value.rstrip('\\'))	# an odd number of backslashes means there's one to escape
   740 					if count % 2:
   758 					if count % 2:
   741 						value += '\\'	
   759 						value += '\\'	
   742 		except KeyError:
   760 		except KeyError:
   743 			if self.default != None:
   761 			if self.default != None:
   744 				value = self.default
   762 				value = self.default
   904 		for op in self.ops:
   922 		for op in self.ops:
   905 			s +=  str(op) + '\n'
   923 			s +=  str(op) + '\n'
   906 		s += "</var>"
   924 		s += "</var>"
   907 		return s
   925 		return s
   908 
   926 
   909 import traceback
       
   910 class VariantRef(Reference):
   927 class VariantRef(Reference):
   911 
   928 
   912 	def __init__(self, ref=None):
   929 	def __init__(self, ref=None):
   913 		Reference.__init__(self, ref = ref)
   930 		Reference.__init__(self, ref = ref)
   914 
   931 
   916 		return "<varRef ref='%s'/>" % self.ref
   933 		return "<varRef ref='%s'/>" % self.ref
   917 
   934 
   918 	def Resolve(self, cache):
   935 	def Resolve(self, cache):
   919 		try:
   936 		try:
   920 			return cache.FindNamedVariant(self.ref)
   937 			return cache.FindNamedVariant(self.ref)
   921 		except KeyError, e:
   938 		except KeyError:
   922 			raise BadReferenceError(self.ref)
   939 			raise BadReferenceError(self.ref)
   923 
   940 
   924 class MissingVariantException(Exception):
   941 class MissingVariantException(Exception):
   925 	pass
   942 	pass
   926 
   943 
   959 					self.variants.append( r.Resolve(cache=cache) )
   976 					self.variants.append( r.Resolve(cache=cache) )
   960 				except BadReferenceError:
   977 				except BadReferenceError:
   961 					missing_variants.append(r.ref)
   978 					missing_variants.append(r.ref)
   962 				
   979 				
   963 			if len(missing_variants) > 0:
   980 			if len(missing_variants) > 0:
   964 				raise MissingVariantException("Missing variants '%s'", " ".join(missing_variants))
   981 				raise MissingVariantException("Missing variants '%s'" % " ".join(missing_variants))
   965 
   982 
   966 	def GenerateBuildUnits(self, cache):
   983 	def GenerateBuildUnits(self, cache):
   967 		self.Resolve(cache)
   984 		self.Resolve(cache)
   968 
   985 
   969 		name = self.name
   986 		name = self.name
  1024 		s += "</group>"
  1041 		s += "</group>"
  1025 		return s
  1042 		return s
  1026 
  1043 
  1027 	def GenerateBuildUnits(self, cache):
  1044 	def GenerateBuildUnits(self, cache):
  1028 		units = []
  1045 		units = []
  1029 
  1046 		
  1030 		missing_variants = []
  1047 		missing_variants = []
  1031 		for r in self.childRefs:
  1048 		for r in self.childRefs:
  1032 			refMods = r.GetModifiers(cache)
       
  1033 
       
  1034 			try:
  1049 			try:
  1035 				obj = r.Resolve(cache=cache)
  1050 				obj = r.Resolve(cache=cache)
  1036 			except BadReferenceError:
  1051 			except BadReferenceError:
  1037 				missing_variants.append(r.ref)
  1052 				missing_variants.append(r.ref)
  1038 			else:
  1053 			else:
  1039 				obj.ClearModifiers()
  1054 				obj.ClearModifiers()
  1040 
  1055 				try:
  1041 				for m in refMods + self.modifiers:
  1056 					refMods = r.GetModifiers(cache)
  1042 					obj.AddModifier(m)
  1057 				except BadReferenceError,e:
  1043 
  1058 					missing_variants.append(str(e))
  1044 				units.extend( obj.GenerateBuildUnits(cache) )
  1059 				else:
       
  1060 					for m in refMods + self.modifiers:
       
  1061 						obj.AddModifier(m)
       
  1062 
       
  1063 					units.extend( obj.GenerateBuildUnits(cache) )
  1045 
  1064 
  1046 		if len(missing_variants) > 0:
  1065 		if len(missing_variants) > 0:
  1047 			raise MissingVariantException("Missing variants '%s'", " ".join(missing_variants))
  1066 			raise MissingVariantException("Missing variants '%s'" % " ".join(missing_variants))
  1048 
  1067 
  1049 		return units
  1068 		return units
  1050 
  1069 
  1051 
  1070 
  1052 class GroupRef(Reference):
  1071 class GroupRef(Reference):
  1053 
  1072 
  1054 	def __init__(self, ref=None):
  1073 	def __init__(self, ref=None):
  1055 		Reference.__init__(self, ref)
  1074 		Reference.__init__(self, ref)
  1056 
  1075 
  1057 	def __str__(self):
  1076 	def __str__(self):
  1058 		return "<%s /><groupRef ref='%s' mod='%s'/>" % (prefix, self.ref, ".".join(self.modifiers))
  1077 		return "<groupRef ref='%s' mod='%s'/>" % (self.ref, ".".join(self.modifiers))
  1059 
  1078 
  1060 	def Resolve(self, cache):
  1079 	def Resolve(self, cache):
  1061 		try:
  1080 		try:
  1062 			return cache.FindNamedGroup(self.ref)
  1081 			return cache.FindNamedGroup(self.ref)
  1063 		except KeyError:
  1082 		except KeyError:
  1064 			raise BadReferenceError(self.ref)
  1083 			raise BadReferenceError(self.ref)
  1065 
  1084 
       
  1085 def GetBuildUnits(configNames, cache, logger):
       
  1086 	"""expand a list of config strings like "arm.v5.urel" into a list
       
  1087 	of BuildUnit objects that can be queried for settings.
       
  1088 	
       
  1089 	The expansion tries to be tolerant of errors in the XML so that a
       
  1090 	typo in one part of a group does not invalidate the whole group.
       
  1091 	"""
       
  1092 	
       
  1093 	# turn dot-separated name strings into Model objects (Group, Alias, Variant)
       
  1094 	models = []
       
  1095 		
       
  1096 	for c in set(configNames):
       
  1097 		ok = True
       
  1098 		names = c.split(".")
       
  1099 
       
  1100 		base = names[0]
       
  1101 		mods = names[1:]
       
  1102 
       
  1103 		if base in cache.groups:
       
  1104 			x = cache.FindNamedGroup(base)
       
  1105 		elif base in cache.aliases:
       
  1106 			x = cache.FindNamedAlias(base)
       
  1107 		elif base in cache.variants:
       
  1108 			x = cache.FindNamedVariant(base)
       
  1109 		else:
       
  1110 			logger.Error("Unknown build configuration '%s'" % base)
       
  1111 			continue
       
  1112 
       
  1113 		x.ClearModifiers()
       
  1114 
       
  1115 		for m in mods:
       
  1116 			if m in cache.variants:
       
  1117 				x.AddModifier( cache.FindNamedVariant(m) )
       
  1118 			else:
       
  1119 				logger.Error("Unknown build variant '%s'" % m)
       
  1120 				ok = False
       
  1121 				
       
  1122 		if ok:
       
  1123 			models.append(copy.copy(x))
       
  1124 
       
  1125 	# turn Model objects into BuildUnit objects
       
  1126 	#
       
  1127 	# all objects have a GenerateBuildUnits method but don't use
       
  1128 	# that for Groups because it is not tolerant of errors (the
       
  1129 	# first error raises an exception and the rest of the group is
       
  1130 	# abandoned)
       
  1131 	units = []
       
  1132 		
       
  1133 	while len(models) > 0:
       
  1134 		x = models.pop()
       
  1135 		try:
       
  1136 			if isinstance(x, (Alias, Variant)):
       
  1137 				# these we just turn straight into BuildUnits
       
  1138 				units.extend(x.GenerateBuildUnits(cache))
       
  1139 			elif isinstance(x, Group):
       
  1140 				# deal with each part of the group separately (later)
       
  1141 				for child in x.childRefs:
       
  1142 					modChild = copy.copy(child)
       
  1143 					modChild.modifiers = child.modifiers + [m.name for m in x.modifiers]
       
  1144 					models.append(modChild)
       
  1145 			elif isinstance(x, Reference):
       
  1146 				# resolve references and their modifiers
       
  1147 				try:
       
  1148 					obj = x.Resolve(cache)
       
  1149 					modObj = copy.copy(obj)
       
  1150 					modObj.modifiers = x.GetModifiers(cache)
       
  1151 				except BadReferenceError,e:
       
  1152 					logger.Error("Unknown reference '%s'" % str(e))
       
  1153 				else:
       
  1154 					models.append(modObj)
       
  1155 		except Exception, e:
       
  1156 			logger.Error(str(e))
       
  1157 
       
  1158 	return units
       
  1159 	
  1066 class ToolErrorException(Exception):
  1160 class ToolErrorException(Exception):
  1067 	def __init__(self, s):
  1161 	def __init__(self, s):
  1068 		Exception.__init__(self,s)
  1162 		Exception.__init__(self,s)
  1069 
  1163 
  1070 class Tool(object):
  1164 class Tool(object):
  1362 		return self.valid
  1456 		return self.valid
  1363 
  1457 
  1364 class UninitialisedVariableException(Exception):
  1458 class UninitialisedVariableException(Exception):
  1365 	pass
  1459 	pass
  1366 
  1460 
       
  1461 class RecursionException(Exception):
       
  1462 	pass
       
  1463 
  1367 class Evaluator(object):
  1464 class Evaluator(object):
  1368 	"""Determine the values of variables under different Configurations.
  1465 	"""Determine the values of variables under different Configurations.
  1369 	Either of specification and buildUnit may be None."""
  1466 	Either of specification and buildUnit may be None."""
  1370 
  1467 
  1371 
  1468 
  1434 		while unresolved:
  1531 		while unresolved:
  1435 			unresolved = False
  1532 			unresolved = False
  1436 			for k, v in self.dict.items():
  1533 			for k, v in self.dict.items():
  1437 				if v.find('$(' + k + ')') != -1:
  1534 				if v.find('$(' + k + ')') != -1:
  1438 						raise RecursionException("Recursion Detected in variable '%s' in configuration '%s' " % (k,configName))
  1535 						raise RecursionException("Recursion Detected in variable '%s' in configuration '%s' " % (k,configName))
  1439 						expanded = "RECURSIVE_INVALID_STRING"
       
  1440 				else:
  1536 				else:
  1441 					expanded = self.ExpandAll(v, specName, configName)
  1537 					expanded = self.ExpandAll(v, specName, configName)
  1442 
  1538 
  1443 				if expanded != v:				# something changed?
  1539 				if expanded != v:				# something changed?
  1444 					self.dict[k] = expanded
  1540 					self.dict[k] = expanded