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 |
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): |