aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main
diff options
context:
space:
mode:
authorGravatar Alex Humesky <ahumesky@google.com>2016-01-15 19:21:03 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2016-01-15 22:29:53 +0000
commitc5ac4308655cbd7eebb70efde3ce1b9450133aec (patch)
tree4f78d35486d45b127a9c1990c4333d9a3991a23d /src/main
parentda1e38736daa2f4187525421308054d4a489ca1a (diff)
Adds support for invocation policy to the canonicalize-flags command.
-- MOS_MIGRATED_REVID=112267123
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/InvocationPolicyEnforcer.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/commands/CanonicalizeCommand.java20
-rw-r--r--src/main/java/com/google/devtools/common/options/OptionsParser.java21
-rw-r--r--src/main/java/com/google/devtools/common/options/OptionsParserImpl.java56
-rw-r--r--src/main/java/com/google/devtools/common/options/OptionsProvider.java9
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();
}