Skip to content

Commit a24b5f3

Browse files
aragoscopybara-github
authored andcommitted
Match options against parsing result.
Checks whether an existing build options matches a set of flags provided through an option parser (for example from the command line or a file). Step 2/N towards the platforms mapping functionality for #6426 RELNOTES: None. PiperOrigin-RevId: 238085427
1 parent 30976d8 commit a24b5f3

File tree

2 files changed

+166
-2
lines changed

2 files changed

+166
-2
lines changed

src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java

+57
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import com.google.common.collect.ImmutableSet;
2424
import com.google.common.collect.ImmutableSortedMap;
2525
import com.google.common.collect.Iterables;
26+
import com.google.common.collect.MapDifference;
27+
import com.google.common.collect.Maps;
2628
import com.google.common.collect.Multimap;
2729
import com.google.common.collect.Ordering;
2830
import com.google.common.collect.Sets;
@@ -384,6 +386,61 @@ private Map<Class<? extends FragmentOptions>, FragmentOptions> toModifiedFragmen
384386
return replacedOptions;
385387
}
386388

389+
/**
390+
* Returns true if the passed parsing result's options have the same value as these options.
391+
*
392+
* <p>If a native parsed option is passed whose fragment has been trimmed in these options it is
393+
* considered to match.
394+
*
395+
* <p>If no options are present in the parsing result or all options in the parsing result have
396+
* been trimmed the result is considered not to match. This is because otherwise the parsing
397+
* result would match any options in a similar trimmed state, regardless of contents.
398+
*
399+
* @param parsingResult parsing result to be compared to these options
400+
* @return true if all non-trimmed values match
401+
* @throws OptionsParsingException if options cannot be parsed
402+
*/
403+
public boolean matches(OptionsParsingResult parsingResult) throws OptionsParsingException {
404+
Set<OptionDefinition> ignoredDefinitions = new HashSet<>();
405+
for (ParsedOptionDescription parsedOption : parsingResult.asListOfExplicitOptions()) {
406+
OptionDefinition optionDefinition = parsedOption.getOptionDefinition();
407+
408+
// All options obtained from an options parser are guaranteed to have been defined in an
409+
// FragmentOptions class.
410+
@SuppressWarnings("unchecked")
411+
Class<? extends FragmentOptions> fragmentClass =
412+
(Class<? extends FragmentOptions>) optionDefinition.getField().getDeclaringClass();
413+
414+
FragmentOptions originalFragment = fragmentOptionsMap.get(fragmentClass);
415+
if (originalFragment == null) {
416+
// Ignore flags set in trimmed fragments.
417+
ignoredDefinitions.add(optionDefinition);
418+
continue;
419+
}
420+
Object originalValue = originalFragment.asMap().get(optionDefinition.getOptionName());
421+
if (!Objects.equals(originalValue, parsedOption.getConvertedValue())) {
422+
return false;
423+
}
424+
}
425+
426+
Map<Label, Object> starlarkOptions =
427+
labelizeStarlarkOptions(parsingResult.getStarlarkOptions());
428+
MapDifference<Label, Object> starlarkDifference =
429+
Maps.difference(skylarkOptionsMap, starlarkOptions);
430+
if (starlarkDifference.entriesInCommon().size() < starlarkOptions.size()) {
431+
return false;
432+
}
433+
434+
if (ignoredDefinitions.size() == parsingResult.asListOfExplicitOptions().size()
435+
&& starlarkOptions.isEmpty()) {
436+
// Zero options were compared, either because none were passed or because all of them were
437+
// trimmed.
438+
return false;
439+
}
440+
441+
return true;
442+
}
443+
387444
/** Creates a builder object for BuildOptions */
388445
public static Builder builder() {
389446
return new Builder();

src/test/java/com/google/devtools/build/lib/analysis/config/BuildOptionsTest.java

+109-2
Original file line numberDiff line numberDiff line change
@@ -345,17 +345,18 @@ public void testMultiValueOptionImmutability() throws Exception {
345345

346346
@Test
347347
public void parsingResultTransform() throws Exception {
348-
BuildOptions original = BuildOptions.of(BUILD_CONFIG_OPTIONS, "--cpu=foo");
348+
BuildOptions original = BuildOptions.of(BUILD_CONFIG_OPTIONS, "--cpu=foo", "--stamp");
349349

350350
OptionsParser parser = OptionsParser.newOptionsParser(BUILD_CONFIG_OPTIONS);
351-
parser.parse("--cpu=bar");
351+
parser.parse("--cpu=bar", "--nostamp");
352352
parser.setStarlarkOptions(ImmutableMap.of("//custom:flag", "hello"));
353353

354354
BuildOptions modified = original.applyParsingResult(parser);
355355

356356
assertThat(original.get(BuildConfiguration.Options.class).cpu)
357357
.isNotEqualTo(modified.get(BuildConfiguration.Options.class).cpu);
358358
assertThat(modified.get(BuildConfiguration.Options.class).cpu).isEqualTo("bar");
359+
assertThat(modified.get(Options.class).stampBinaries).isFalse();
359360
assertThat(modified.getStarlarkOptions().get(Label.parseAbsoluteUnchecked("//custom:flag")))
360361
.isEqualTo("hello");
361362
}
@@ -387,4 +388,110 @@ public void parsingResultTransformIllegalStarlarkLabel() throws Exception {
387388

388389
assertThrows(IllegalArgumentException.class, () -> original.applyParsingResult(parser));
389390
}
391+
392+
@Test
393+
public void parsingResultMatch() throws Exception {
394+
BuildOptions original = BuildOptions.of(BUILD_CONFIG_OPTIONS, "--cpu=foo", "--stamp");
395+
396+
OptionsParser matchingParser = OptionsParser.newOptionsParser(BUILD_CONFIG_OPTIONS);
397+
matchingParser.parse("--cpu=foo", "--stamp");
398+
399+
OptionsParser notMatchingParser = OptionsParser.newOptionsParser(BUILD_CONFIG_OPTIONS);
400+
notMatchingParser.parse("--cpu=foo", "--nostamp");
401+
402+
assertThat(original.matches(matchingParser)).isTrue();
403+
assertThat(original.matches(notMatchingParser)).isFalse();
404+
}
405+
406+
@Test
407+
public void parsingResultMatchStarlark() throws Exception {
408+
BuildOptions original =
409+
BuildOptions.builder()
410+
.addStarlarkOption(Label.parseAbsoluteUnchecked("//custom:flag"), "hello")
411+
.build();
412+
413+
OptionsParser matchingParser = OptionsParser.newOptionsParser(BUILD_CONFIG_OPTIONS);
414+
matchingParser.setStarlarkOptions(ImmutableMap.of("//custom:flag", "hello"));
415+
416+
OptionsParser notMatchingParser = OptionsParser.newOptionsParser(BUILD_CONFIG_OPTIONS);
417+
notMatchingParser.setStarlarkOptions(ImmutableMap.of("//custom:flag", "foo"));
418+
419+
assertThat(original.matches(matchingParser)).isTrue();
420+
assertThat(original.matches(notMatchingParser)).isFalse();
421+
}
422+
423+
@Test
424+
public void parsingResultMatchMissingFragment() throws Exception {
425+
BuildOptions original = BuildOptions.of(BUILD_CONFIG_OPTIONS, "--cpu=foo");
426+
427+
ImmutableList<Class<? extends FragmentOptions>> fragmentClasses =
428+
ImmutableList.<Class<? extends FragmentOptions>>builder()
429+
.add(BuildConfiguration.Options.class)
430+
.add(CppOptions.class)
431+
.build();
432+
433+
OptionsParser parser = OptionsParser.newOptionsParser(fragmentClasses);
434+
parser.parse("--cpu=foo", "--cxxopt=bar");
435+
436+
assertThat(original.matches(parser)).isTrue();
437+
}
438+
439+
@Test
440+
public void parsingResultMatchEmptyNativeMatch() throws Exception {
441+
BuildOptions original = BuildOptions.of(BUILD_CONFIG_OPTIONS, "--cpu=foo");
442+
443+
ImmutableList<Class<? extends FragmentOptions>> fragmentClasses =
444+
ImmutableList.<Class<? extends FragmentOptions>>builder()
445+
.add(BuildConfiguration.Options.class)
446+
.add(CppOptions.class)
447+
.build();
448+
449+
OptionsParser parser = OptionsParser.newOptionsParser(fragmentClasses);
450+
parser.parse("--cxxopt=bar");
451+
452+
assertThat(original.matches(parser)).isFalse();
453+
}
454+
455+
@Test
456+
public void parsingResultMatchEmptyNativeMatchWithStarlark() throws Exception {
457+
BuildOptions original =
458+
BuildOptions.builder()
459+
.addStarlarkOption(Label.parseAbsoluteUnchecked("//custom:flag"), "hello")
460+
.build();
461+
462+
ImmutableList<Class<? extends FragmentOptions>> fragmentClasses =
463+
ImmutableList.<Class<? extends FragmentOptions>>builder()
464+
.add(BuildConfiguration.Options.class)
465+
.add(CppOptions.class)
466+
.build();
467+
468+
OptionsParser parser = OptionsParser.newOptionsParser(fragmentClasses);
469+
parser.parse("--cxxopt=bar");
470+
parser.setStarlarkOptions(ImmutableMap.of("//custom:flag", "hello"));
471+
472+
assertThat(original.matches(parser)).isTrue();
473+
}
474+
475+
@Test
476+
public void parsingResultMatchStarlarkOptionMissing() throws Exception {
477+
BuildOptions original =
478+
BuildOptions.builder()
479+
.addStarlarkOption(Label.parseAbsoluteUnchecked("//custom:flag1"), "hello")
480+
.build();
481+
482+
OptionsParser parser = OptionsParser.newOptionsParser(BUILD_CONFIG_OPTIONS);
483+
parser.setStarlarkOptions(ImmutableMap.of("//custom:flag2", "foo"));
484+
485+
assertThat(original.matches(parser)).isFalse();
486+
}
487+
488+
@Test
489+
public void parsingResultMatchNullOption() throws Exception {
490+
BuildOptions original = BuildOptions.of(BUILD_CONFIG_OPTIONS);
491+
492+
OptionsParser parser = OptionsParser.newOptionsParser(BUILD_CONFIG_OPTIONS);
493+
parser.parse("--platform_suffix=foo"); // Note: platform_suffix is null by default.
494+
495+
assertThat(original.matches(parser)).isFalse();
496+
}
390497
}

0 commit comments

Comments
 (0)