@@ -267,31 +267,38 @@ public static Map<String, BuildOptions> validate(
267
267
Map <PackageValue .Key , PackageValue > buildSettingPackages ,
268
268
Map <String , BuildOptions > toOptions )
269
269
throws TransitionException {
270
- // Collect settings changed during this transition and their types. This includes settings that
271
- // were only used as inputs as to the transition and thus had their default values added to the
272
- // fromOptions, which in case of a no-op transition directly end up in toOptions.
273
- Map <Label , Rule > changedSettingToRule = Maps .newHashMap ();
270
+ // Collect settings that are input or outputs of the transition together with their types.
271
+ // Output setting values will be validated and cleaned if set to the default.
272
+ Map <Label , Rule > inputAndOutputSettingsToRule = Maps .newHashMap ();
273
+ // Collect settings that were only used as inputs to the transition and thus had their default
274
+ // values added to the fromOptions. They always have to be cleaned.
275
+ Set <Label > inputOnlySettings = Sets .newHashSet ();
274
276
root .visit (
275
277
(StarlarkTransitionVisitor )
276
278
transition -> {
277
- ImmutableSet <Label > changedSettings =
279
+ ImmutableSet <Label > inputAndOutputSettings =
278
280
getRelevantStarlarkSettingsFromTransition (
279
281
transition , Settings .INPUTS_AND_OUTPUTS );
280
- for (Label setting : changedSettings ) {
281
- changedSettingToRule .put (
282
+ ImmutableSet <Label > outputSettings =
283
+ getRelevantStarlarkSettingsFromTransition (transition , Settings .OUTPUTS );
284
+ for (Label setting : inputAndOutputSettings ) {
285
+ inputAndOutputSettingsToRule .put (
282
286
setting , getActual (buildSettingPackages , setting ).getAssociatedRule ());
287
+ if (!outputSettings .contains (setting )) {
288
+ inputOnlySettings .add (setting );
289
+ }
283
290
}
284
291
});
285
292
286
293
// Return early if no starlark settings were affected.
287
- if (changedSettingToRule .isEmpty ()) {
294
+ if (inputAndOutputSettingsToRule .isEmpty ()) {
288
295
return toOptions ;
289
296
}
290
297
291
298
ImmutableMap .Builder <Label , Label > aliasToActualBuilder = new ImmutableMap .Builder <>();
292
- for (Map .Entry <Label , Rule > changedSettingWithRule : changedSettingToRule .entrySet ()) {
293
- Label setting = changedSettingWithRule .getKey ();
294
- Rule rule = changedSettingWithRule .getValue ();
299
+ for (Map .Entry <Label , Rule > settingWithRule : inputAndOutputSettingsToRule .entrySet ()) {
300
+ Label setting = settingWithRule .getKey ();
301
+ Rule rule = settingWithRule .getValue ();
295
302
if (!rule .getLabel ().equals (setting )) {
296
303
aliasToActualBuilder .put (setting , rule .getLabel ());
297
304
}
@@ -307,69 +314,19 @@ public static Map<String, BuildOptions> validate(
307
314
BuildOptions .Builder cleanedOptions = null ;
308
315
// Clean up aliased values.
309
316
BuildOptions options = unalias (entry .getValue (), aliasToActual );
310
- for (Map .Entry <Label , Rule > changedSettingWithRule : changedSettingToRule .entrySet ()) {
317
+ for (Map .Entry <Label , Rule > settingWithRule : inputAndOutputSettingsToRule .entrySet ()) {
311
318
// If the build setting was referenced in the transition via an alias, this is that alias
312
- Label maybeAliasSetting = changedSettingWithRule .getKey ();
313
- Rule rule = changedSettingWithRule .getValue ();
314
- // If the build setting was *not* referenced in the transition by an alias, this is the same
315
- // value as {@code maybeAliasSetting} above.
316
- Label actualSetting = rule .getLabel ();
317
- Object newValue = options .getStarlarkOptions ().get (actualSetting );
318
- // TODO(b/154132845): fix NPE occasionally observed here.
319
- Preconditions .checkState (
320
- newValue != null ,
321
- "Error while attempting to validate new values from starlark"
322
- + " transition(s) with the outputs %s. Post-transition configuration should include"
323
- + " '%s' but only includes starlark options: %s. If you run into this error"
324
- +
" please ping b/154132845 or email [email protected] ." ,
325
- changedSettingToRule .keySet (),
326
- actualSetting ,
327
- options .getStarlarkOptions ().keySet ());
328
- boolean allowsMultiple = rule .getRuleClassObject ().getBuildSetting ().allowsMultiple ();
329
- if (allowsMultiple ) {
330
- // if this setting allows multiple settings
331
- if (!(newValue instanceof List )) {
332
- throw new TransitionException (
333
- String .format (
334
- "'%s' allows multiple values and must be set"
335
- + " in transition using a starlark list instead of single value '%s'" ,
336
- actualSetting , newValue ));
337
- }
338
- List <?> rawNewValueAsList = (List <?>) newValue ;
339
- List <Object > convertedValue = new ArrayList <>();
340
- Type <?> type = rule .getRuleClassObject ().getBuildSetting ().getType ();
341
- for (Object value : rawNewValueAsList ) {
342
- try {
343
- convertedValue .add (type .convert (value , maybeAliasSetting ));
344
- } catch (ConversionException e ) {
345
- throw new TransitionException (e );
346
- }
347
- }
348
- if (convertedValue .equals (
349
- ImmutableList .of (rule .getAttr (STARLARK_BUILD_SETTING_DEFAULT_ATTR_NAME )))) {
350
- if (cleanedOptions == null ) {
351
- cleanedOptions = options .toBuilder ();
352
- }
353
- cleanedOptions .removeStarlarkOption (rule .getLabel ());
354
- }
355
- } else {
356
- // if this setting does not allow multiple settings
357
- Object convertedValue ;
358
- try {
359
- convertedValue =
360
- rule .getRuleClassObject ()
361
- .getBuildSetting ()
362
- .getType ()
363
- .convert (newValue , maybeAliasSetting );
364
- } catch (ConversionException e ) {
365
- throw new TransitionException (e );
366
- }
367
- if (convertedValue .equals (rule .getAttr (STARLARK_BUILD_SETTING_DEFAULT_ATTR_NAME ))) {
368
- if (cleanedOptions == null ) {
369
- cleanedOptions = options .toBuilder ();
370
- }
371
- cleanedOptions .removeStarlarkOption (rule .getLabel ());
319
+ Label maybeAliasSetting = settingWithRule .getKey ();
320
+ Rule rule = settingWithRule .getValue ();
321
+ // Input-only settings had their default value added to the BuildOptions and thus always
322
+ // have to be cleaned, whereas output settings have their value validated, converted and
323
+ // stripped if it is equivalent to the setting's default value.
324
+ if (inputOnlySettings .contains (maybeAliasSetting ) || validateAndCheckIfAtDefault (
325
+ rule , options , maybeAliasSetting , inputAndOutputSettingsToRule .keySet ())) {
326
+ if (cleanedOptions == null ) {
327
+ cleanedOptions = options .toBuilder ();
372
328
}
329
+ cleanedOptions .removeStarlarkOption (rule .getLabel ());
373
330
}
374
331
}
375
332
// Keep the same instance if we didn't do anything to maintain reference equality later on.
@@ -381,6 +338,74 @@ public static Map<String, BuildOptions> validate(
381
338
return cleanedOptionMap .buildOrThrow ();
382
339
}
383
340
341
+ /**
342
+ * Validate the value of a particular build setting after a transition has been applied.
343
+ * @param buildSettingRule the build setting to validate.
344
+ * @param options the {@link BuildOptions} reflecting the post-transition configuration.
345
+ * @param maybeAliasSetting the label used to refer to the build setting in the transition,
346
+ * possibly an alias. This is only used for error messages.
347
+ * @param inputAndOutputSettings the transition input and output settings. This is only used for
348
+ * error messages.
349
+ * @return {@code true} if and only if the setting is set to its default value after the
350
+ * transition.
351
+ * @throws TransitionException if the value returned by the transition for this setting has an
352
+ * invalid type.
353
+ */
354
+ private static boolean validateAndCheckIfAtDefault (Rule buildSettingRule , BuildOptions options ,
355
+ Label maybeAliasSetting , Set <Label > inputAndOutputSettings ) throws TransitionException {
356
+ // If the build setting was *not* referenced in the transition by an alias, this is the same
357
+ // value as {@code maybeAliasSetting}.
358
+ Label actualSetting = buildSettingRule .getLabel ();
359
+ Object newValue = options .getStarlarkOptions ().get (actualSetting );
360
+ // TODO(b/154132845): fix NPE occasionally observed here.
361
+ Preconditions .checkState (
362
+ newValue != null ,
363
+ "Error while attempting to validate new values from starlark"
364
+ + " transition(s) with the inputs and outputs %s. Post-transition configuration should"
365
+ + " include '%s' but only includes starlark options: %s. If you run into this error"
366
+ +
" please ping b/154132845 or email [email protected] ." ,
367
+ inputAndOutputSettings ,
368
+ actualSetting ,
369
+ options .getStarlarkOptions ().keySet ());
370
+ boolean allowsMultiple = buildSettingRule .getRuleClassObject ().getBuildSetting ()
371
+ .allowsMultiple ();
372
+ if (allowsMultiple ) {
373
+ // if this setting allows multiple settings
374
+ if (!(newValue instanceof List )) {
375
+ throw new TransitionException (
376
+ String .format (
377
+ "'%s' allows multiple values and must be set"
378
+ + " in transition using a starlark list instead of single value '%s'" ,
379
+ actualSetting , newValue ));
380
+ }
381
+ List <?> rawNewValueAsList = (List <?>) newValue ;
382
+ List <Object > convertedValue = new ArrayList <>();
383
+ Type <?> type = buildSettingRule .getRuleClassObject ().getBuildSetting ().getType ();
384
+ for (Object value : rawNewValueAsList ) {
385
+ try {
386
+ convertedValue .add (type .convert (value , maybeAliasSetting ));
387
+ } catch (ConversionException e ) {
388
+ throw new TransitionException (e );
389
+ }
390
+ }
391
+ return convertedValue .equals (
392
+ ImmutableList .of (buildSettingRule .getAttr (STARLARK_BUILD_SETTING_DEFAULT_ATTR_NAME )));
393
+ } else {
394
+ // if this setting does not allow multiple settings
395
+ Object convertedValue ;
396
+ try {
397
+ convertedValue =
398
+ buildSettingRule .getRuleClassObject ()
399
+ .getBuildSetting ()
400
+ .getType ()
401
+ .convert (newValue , maybeAliasSetting );
402
+ } catch (ConversionException e ) {
403
+ throw new TransitionException (e );
404
+ }
405
+ return convertedValue .equals (buildSettingRule .getAttr (STARLARK_BUILD_SETTING_DEFAULT_ATTR_NAME ));
406
+ }
407
+ }
408
+
384
409
/*
385
410
* Resolve aliased build setting issues
386
411
*
0 commit comments