diff options
Diffstat (limited to 'src/main')
5 files changed, 76 insertions, 36 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/InvocationPolicyEnforcer.java b/src/main/java/com/google/devtools/build/lib/runtime/InvocationPolicyEnforcer.java index de235eb09c..edd367830e 100644 --- a/src/main/java/com/google/devtools/build/lib/runtime/InvocationPolicyEnforcer.java +++ b/src/main/java/com/google/devtools/build/lib/runtime/InvocationPolicyEnforcer.java @@ -70,6 +70,12 @@ public final class InvocationPolicyEnforcer { return new InvocationPolicyEnforcer(parsePolicy(blazeServerStartupOptions.invocationPolicy)); } + public static InvocationPolicyEnforcer create(String invocationPolicy) + throws OptionsParsingException { + + return new InvocationPolicyEnforcer(parsePolicy(invocationPolicy)); + } + /** * Parses the given InvocationPolicy string, which may be a base64-encoded binary-serialized * InvocationPolicy message, or a text formatted InvocationPolicy message. Note that the diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/CanonicalizeCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/CanonicalizeCommand.java index 9e1a2c269b..290995e9e2 100644 --- a/src/main/java/com/google/devtools/build/lib/runtime/commands/CanonicalizeCommand.java +++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/CanonicalizeCommand.java @@ -20,6 +20,7 @@ import com.google.devtools.build.lib.runtime.BlazeCommandUtils; import com.google.devtools.build.lib.runtime.BlazeRuntime; import com.google.devtools.build.lib.runtime.Command; import com.google.devtools.build.lib.runtime.CommandEnvironment; +import com.google.devtools.build.lib.runtime.InvocationPolicyEnforcer; import com.google.devtools.build.lib.util.ExitCode; import com.google.devtools.common.options.Option; import com.google.devtools.common.options.OptionsBase; @@ -49,12 +50,17 @@ public final class CanonicalizeCommand implements BlazeCommand { category = "misc", help = "The command for which the options should be canonicalized.") public String forCommand; + + @Option(name = "invocation_policy", + defaultValue = "null") + public String invocationPolicy; } @Override public ExitCode exec(CommandEnvironment env, OptionsProvider options) { BlazeRuntime runtime = env.getRuntime(); - String commandName = options.getOptions(Options.class).forCommand; + Options canonicalizeOptions = options.getOptions(Options.class); + String commandName = canonicalizeOptions.forCommand; BlazeCommand command = runtime.getCommandMap().get(commandName); if (command == null) { env.getReporter().handle(Event.error("Not a valid command: '" + commandName @@ -65,7 +71,17 @@ public final class CanonicalizeCommand implements BlazeCommand { BlazeCommandUtils.getOptions( command.getClass(), runtime.getBlazeModules(), runtime.getRuleClassProvider()); try { - List<String> result = OptionsParser.canonicalize(optionsClasses, options.getResidue()); + + OptionsParser parser = OptionsParser.newOptionsParser(optionsClasses); + parser.setAllowResidue(false); + parser.parse(options.getResidue()); + + InvocationPolicyEnforcer invocationPolicyEnforcer = InvocationPolicyEnforcer.create( + canonicalizeOptions.invocationPolicy); + invocationPolicyEnforcer.enforce(parser, commandName); + + List<String> result = parser.canonicalize(); + for (String piece : result) { env.getReporter().getOutErr().printOutLn(piece); } diff --git a/src/main/java/com/google/devtools/common/options/OptionsParser.java b/src/main/java/com/google/devtools/common/options/OptionsParser.java index 400adee114..5b107b78ae 100644 --- a/src/main/java/com/google/devtools/common/options/OptionsParser.java +++ b/src/main/java/com/google/devtools/common/options/OptionsParser.java @@ -114,22 +114,6 @@ public class OptionsParser implements OptionsProvider { return new OptionsParser(getOptionsData(ImmutableList.copyOf(optionsClasses))); } - /** - * Canonicalizes a list of options using the given option classes. The - * contract is that if the returned set of options is passed to an options - * parser with the same options classes, then that will have the same effect - * as using the original args (which are passed in here), except for cosmetic - * differences. - */ - public static List<String> canonicalize( - Collection<Class<? extends OptionsBase>> optionsClasses, List<String> args) - throws OptionsParsingException { - OptionsParser parser = new OptionsParser(optionsClasses); - parser.setAllowResidue(false); - parser.parse(args); - return parser.impl.asCanonicalizedList(); - } - private final OptionsParserImpl impl; private final List<String> residue = new ArrayList<String>(); private boolean allowResidue = true; @@ -628,4 +612,9 @@ public class OptionsParser implements OptionsProvider { public List<OptionValueDescription> asListOfEffectiveOptions() { return impl.asListOfEffectiveOptions(); } + + @Override + public List<String> canonicalize() { + return impl.asCanonicalizedList(); + } } diff --git a/src/main/java/com/google/devtools/common/options/OptionsParserImpl.java b/src/main/java/com/google/devtools/common/options/OptionsParserImpl.java index 5f90594f1a..48dac23b80 100644 --- a/src/main/java/com/google/devtools/common/options/OptionsParserImpl.java +++ b/src/main/java/com/google/devtools/common/options/OptionsParserImpl.java @@ -22,9 +22,11 @@ import com.google.common.base.Predicate; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; import com.google.devtools.common.options.OptionsParser.OptionDescription; import com.google.devtools.common.options.OptionsParser.OptionValueDescription; import com.google.devtools.common.options.OptionsParser.UnparsedOptionValueDescription; @@ -227,8 +229,19 @@ class OptionsParserImpl { * We use partially preparsed options, which can be different from the original * representation, e.g. "--nofoo" becomes "--foo=0". */ - private final List<UnparsedOptionValueDescription> unparsedValues = - Lists.newArrayList(); + private final List<UnparsedOptionValueDescription> unparsedValues = Lists.newArrayList(); + + /** + * Unparsed values for use with the canonicalize command are stored separately from + * unparsedValues so that invocation policy can modify the values for canonicalization (e.g. + * override user-specified values with default values) without corrupting the data used to + * represent the user's original invocation for {@link #asListOfExplicitOptions()} and + * {@link #asListOfUnparsedOptions()}. A LinkedHashMultimap is used so that canonicalization + * happens in the correct order and multiple values can be stored for flags that allow multiple + * values. + */ + private final Multimap<Field, UnparsedOptionValueDescription> canonicalizeValues + = LinkedHashMultimap.create(); private final List<String> warnings = Lists.newArrayList(); @@ -313,13 +326,14 @@ class OptionsParserImpl { * Implements {@link OptionsParser#canonicalize}. */ List<String> asCanonicalizedList() { - List<UnparsedOptionValueDescription> processed = Lists.newArrayList(unparsedValues); + + List<UnparsedOptionValueDescription> processed = Lists.newArrayList( + canonicalizeValues.values()); + // Sort implicit requirement options to the end, keeping their existing order, and sort the + // other options alphabetically. Collections.sort(processed, new Comparator<UnparsedOptionValueDescription>() { - // This Comparator sorts implicit requirement options to the end, keeping their existing - // order, and sorts the other options alphabetically. @Override - public int compare(UnparsedOptionValueDescription o1, - UnparsedOptionValueDescription o2) { + public int compare(UnparsedOptionValueDescription o1, UnparsedOptionValueDescription o2) { if (o1.isImplicitRequirement()) { return o2.isImplicitRequirement() ? 0 : 1; } @@ -331,15 +345,7 @@ class OptionsParserImpl { }); List<String> result = Lists.newArrayList(); - for (int i = 0; i < processed.size(); i++) { - UnparsedOptionValueDescription value = processed.get(i); - // Skip an option if the next option is the same, but only if the option does not allow - // multiple values. - if (!value.allowMultiple()) { - if ((i < processed.size() - 1) && value.getName().equals(processed.get(i + 1).getName())) { - continue; - } - } + for (UnparsedOptionValueDescription value : processed) { // Ignore expansion options. if (value.isExpansion()) { @@ -449,6 +455,8 @@ class OptionsParserImpl { clearedValues.put(optionName, removed.asOptionValueDescription(optionName)); } + canonicalizeValues.removeAll(field); + // Recurse to remove any implicit or expansion flags that this flag may have added when // originally parsed. Option option = field.getAnnotation(Option.class); @@ -642,8 +650,20 @@ class OptionsParserImpl { // Log explicit options and expanded options in the order they are parsed (can be sorted // later). Also remember whether they were expanded or not. This information is needed to // correctly canonicalize flags. - unparsedValues.add(new UnparsedOptionValueDescription(originalName, field, value, - priority, sourceFunction.apply(originalName), expandedFrom == null)); + UnparsedOptionValueDescription unparsedOptionValueDescription = + new UnparsedOptionValueDescription( + originalName, + field, + value, + priority, + sourceFunction.apply(originalName), + expandedFrom == null); + unparsedValues.add(unparsedOptionValueDescription); + if (option.allowMultiple()) { + canonicalizeValues.put(field, unparsedOptionValueDescription); + } else { + canonicalizeValues.replaceValues(field, ImmutableList.of(unparsedOptionValueDescription)); + } } // Handle expansion options. diff --git a/src/main/java/com/google/devtools/common/options/OptionsProvider.java b/src/main/java/com/google/devtools/common/options/OptionsProvider.java index 015cc6c61f..040aa055a3 100644 --- a/src/main/java/com/google/devtools/common/options/OptionsProvider.java +++ b/src/main/java/com/google/devtools/common/options/OptionsProvider.java @@ -64,4 +64,13 @@ public interface OptionsProvider extends OptionsClassProvider { * effective values. There is no guaranteed ordering for the result. */ List<OptionValueDescription> asListOfEffectiveOptions(); + + /** + * Canonicalizes the list of options that this OptionsParser has parsed. The + * contract is that if the returned set of options is passed to an options + * parser with the same options classes, then that will have the same effect + * as using the original args (which are passed in here), except for cosmetic + * differences. + */ + List<String> canonicalize(); } |