@@ -137,6 +137,41 @@ def __init__(self, name, unit_name, unit_kind):
137
137
self .macro_name = name
138
138
self .macro_value = None
139
139
140
+ # Representation of overrides for cumulative attributes
141
+ class ConfigCumulativeOverride :
142
+ def __init__ (self , name , additions = set (), removals = set (), strict = False ):
143
+ self .name = name
144
+ self .additions = set (additions )
145
+ self .removals = set (removals )
146
+ self .strict = strict
147
+
148
+ # Add attr to the cumulative override
149
+ def remove_cumulative_overrides (self , overrides ):
150
+ for override in overrides :
151
+ if override in self .additions :
152
+ raise ConfigException ("Configuration conflict. The %s %s both added and removed." % (self .name [:- 1 ], override ))
153
+
154
+ self .removals |= set (overrides )
155
+
156
+ # Remove attr from the cumulative overrides
157
+ def add_cumulative_overrides (self , overrides ):
158
+ for override in overrides :
159
+ if (override in self .removals or (self .strict and override not in self .additions )):
160
+ raise ConfigException ("Configuration conflict. The %s %s both added and removed." % (self .name [:- 1 ], override ))
161
+
162
+ self .additions |= set (overrides )
163
+
164
+ # Enable strict set of cumulative overrides for the specified attr
165
+ def strict_cumulative_overrides (self , overrides ):
166
+ self .remove_cumulative_overrides (self .additions - set (overrides ))
167
+ self .add_cumulative_overrides (overrides )
168
+ self .strict = True
169
+
170
+ def update_target (self , target ):
171
+ setattr (target , self .name , list (
172
+ set (getattr (target , self .name , [])) | self .additions - self .removals ))
173
+
174
+
140
175
# 'Config' implements the mbed configuration mechanism
141
176
class Config :
142
177
# Libraries and applications have different names for their configuration files
@@ -184,9 +219,12 @@ def __init__(self, target, top_level_dirs = []):
184
219
self .processed_configs = {}
185
220
self .target = target if isinstance (target , basestring ) else target .name
186
221
self .target_labels = Target .get_target (self .target ).get_labels ()
187
- self .added_features = set ()
188
- self .removed_features = set ()
189
- self .removed_unecessary_features = False
222
+
223
+ self .cumulative_overrides = { key : ConfigCumulativeOverride (key )
224
+ for key in Target ._Target__cumulative_attributes }
225
+
226
+ self ._process_config_and_overrides (self .app_config_data , {}, "app" , "application" )
227
+ self .target_labels = Target .get_target (self .target ).get_labels ()
190
228
191
229
# Add one or more configuration files
192
230
def add_config_files (self , flist ):
@@ -222,23 +260,6 @@ def _process_config_parameters(self, data, params, unit_name, unit_kind):
222
260
params [full_name ] = ConfigParameter (name , v if isinstance (v , dict ) else {"value" : v }, unit_name , unit_kind )
223
261
return params
224
262
225
- # Add features to the available features
226
- def remove_features (self , features ):
227
- for feature in features :
228
- if feature in self .added_features :
229
- raise ConfigException ("Configuration conflict. Feature %s both added and removed." % feature )
230
-
231
- self .removed_features |= set (features )
232
-
233
- # Remove features from the available features
234
- def add_features (self , features ):
235
- for feature in features :
236
- if (feature in self .removed_features
237
- or (self .removed_unecessary_features and feature not in self .added_features )):
238
- raise ConfigException ("Configuration conflict. Feature %s both added and removed." % feature )
239
-
240
- self .added_features |= set (features )
241
-
242
263
# Helper function: process "config_parameters" and "target_config_overrides" in a given dictionary
243
264
# data: the configuration data of the library/appliation
244
265
# params: storage for the discovered configuration parameters
@@ -250,21 +271,25 @@ def _process_config_and_overrides(self, data, params, unit_name, unit_kind):
250
271
for label , overrides in data .get ("target_overrides" , {}).items ():
251
272
# If the label is defined by the target or it has the special value "*", process the overrides
252
273
if (label == '*' ) or (label in self .target_labels ):
253
- # Parse out features
254
- if 'target.features' in overrides :
255
- features = overrides ['target.features' ]
256
- self .remove_features (self .added_features - set (features ))
257
- self .add_features (features )
258
- self .removed_unecessary_features = True
259
- del overrides ['target.features' ]
260
-
261
- if 'target.features_add' in overrides :
262
- self .add_features (overrides ['target.features_add' ])
263
- del overrides ['target.features_add' ]
264
-
265
- if 'target.features_remove' in overrides :
266
- self .remove_features (overrides ['target.features_remove' ])
267
- del overrides ['target.features_remove' ]
274
+ # Check for invalid cumulative overrides in libraries
275
+ if (unit_kind == 'library' and
276
+ any (attr .startswith ('target.extra_labels' ) for attr in overrides .iterkeys ())):
277
+ raise ConfigException ("Target override '%s' in '%s' is only allowed at the application level"
278
+ % ("target.extra_labels" , ConfigParameter .get_display_name (unit_name , unit_kind , label )))
279
+
280
+ # Parse out cumulative overrides
281
+ for attr , cumulatives in self .cumulative_overrides .iteritems ():
282
+ if 'target.' + attr in overrides :
283
+ cumulatives .strict_cumulative_overrides (overrides ['target.' + attr ])
284
+ del overrides ['target.' + attr ]
285
+
286
+ if 'target.' + attr + '_add' in overrides :
287
+ cumulatives .add_cumulative_overrides (overrides ['target.' + attr + '_add' ])
288
+ del overrides ['target.' + attr + '_add' ]
289
+
290
+ if 'target.' + attr + '_remove' in overrides :
291
+ cumulatives .remove_cumulative_overrides (overrides ['target.' + attr + '_remove' ])
292
+ del overrides ['target.' + attr + '_remove' ]
268
293
269
294
# Consider the others as overrides
270
295
for name , v in overrides .items ():
@@ -275,6 +300,10 @@ def _process_config_and_overrides(self, data, params, unit_name, unit_kind):
275
300
else :
276
301
self .config_errors .append (ConfigException ("Attempt to override undefined parameter '%s' in '%s'"
277
302
% (full_name , ConfigParameter .get_display_name (unit_name , unit_kind , label ))))
303
+
304
+ for cumulatives in self .cumulative_overrides .itervalues ():
305
+ cumulatives .update_target (Target .get_target (self .target ))
306
+
278
307
return params
279
308
280
309
# Read and interpret configuration data defined by targets
@@ -389,8 +418,8 @@ def get_config_data_macros(self):
389
418
def get_features (self ):
390
419
params , _ = self .get_config_data ()
391
420
self ._check_required_parameters (params )
392
- features = (( set ( Target .get_target (self .target ). features )
393
- | self . added_features ) - self .removed_features )
421
+ self . cumulative_overrides [ ' features' ]. update_target ( Target .get_target (self .target ))
422
+ features = Target . get_target ( self .target ). features
394
423
395
424
for feature in features :
396
425
if feature not in self .__allowed_features :
0 commit comments