Adds a mechanism for invocation policy. The policy is taken through the --invocation_policy startup flag and allows an application invoking Bazel to set or override flag values (whether from the command line or a bazelrc).
--
MOS_MIGRATED_REVID=104160290
diff --git a/src/main/java/com/google/devtools/common/options/Option.java b/src/main/java/com/google/devtools/common/options/Option.java
index f41a051..ca3add9 100644
--- a/src/main/java/com/google/devtools/common/options/Option.java
+++ b/src/main/java/com/google/devtools/common/options/Option.java
@@ -62,6 +62,9 @@
* be a compile-time constant.) This special interpretation of the string
* "null" is only applicable when computing the default value; if specified
* on the command-line, this string will have its usual literal meaning.
+ *
+ * <p>The default value for flags that set allowMultiple to true is always
+ * the empty list and the value in the annotation is ignored.
*/
String defaultValue();
@@ -90,6 +93,9 @@
* converter for this option must either match the parameter {@code T} or
* {@code List<T>}. In the latter case the individual lists are concatenated
* to form the full options value.
+ *
+ * <p>The {@link #defaultValue()} field of the annotation is ignored for repeatable
+ * flags and the default value will be the empty list.
*/
boolean allowMultiple() default false;
diff --git a/src/main/java/com/google/devtools/common/options/OptionPriority.java b/src/main/java/com/google/devtools/common/options/OptionPriority.java
index b352e88..a28f012 100644
--- a/src/main/java/com/google/devtools/common/options/OptionPriority.java
+++ b/src/main/java/com/google/devtools/common/options/OptionPriority.java
@@ -50,9 +50,13 @@
COMMAND_LINE,
/**
+ * For options coming from invocation policy.
+ */
+ INVOCATION_POLICY,
+
+ /**
* This priority can be used to unconditionally override any user-provided options.
* This should be used rarely and with caution!
*/
SOFTWARE_REQUIREMENT;
-
}
diff --git a/src/main/java/com/google/devtools/common/options/OptionsData.java b/src/main/java/com/google/devtools/common/options/OptionsData.java
index d5512a1..61d798a 100644
--- a/src/main/java/com/google/devtools/common/options/OptionsData.java
+++ b/src/main/java/com/google/devtools/common/options/OptionsData.java
@@ -71,12 +71,19 @@
*/
private final Map<Field, Converter<?>> converters;
+ /**
+ * Mapping from each Option-annotated field to a boolean for whether that field allows multiple
+ * values.
+ */
+ private final Map<Field, Boolean> allowMultiple;
+
private OptionsData(Map<Class<? extends OptionsBase>, Constructor<?>> optionsClasses,
Map<String, Field> nameToField,
Map<Character, Field> abbrevToField,
Map<Class<? extends OptionsBase>, List<Field>> allOptionsFields,
Map<Field, Object> optionDefaults,
- Map<Field, Converter<?>> converters) {
+ Map<Field, Converter<?>> converters,
+ Map<Field, Boolean> allowMultiple) {
this.optionsClasses = ImmutableMap.copyOf(optionsClasses);
this.allOptionsFields = ImmutableMap.copyOf(allOptionsFields);
this.nameToField = ImmutableMap.copyOf(nameToField);
@@ -84,6 +91,7 @@
// Can't use an ImmutableMap here because of null values.
this.optionDefaults = Collections.unmodifiableMap(optionDefaults);
this.converters = ImmutableMap.copyOf(converters);
+ this.allowMultiple = ImmutableMap.copyOf(allowMultiple);
}
public Collection<Class<? extends OptionsBase>> getOptionsClasses() {
@@ -119,6 +127,10 @@
return converters.get(field);
}
+ public boolean getAllowMultiple(Field field) {
+ return allowMultiple.get(field);
+ }
+
private static List<Field> getAllAnnotatedFields(Class<? extends OptionsBase> optionsClass) {
List<Field> allFields = Lists.newArrayList();
for (Field field : optionsClass.getFields()) {
@@ -157,6 +169,7 @@
Map<Character, Field> abbrevToFieldBuilder = Maps.newHashMap();
Map<Field, Object> optionDefaultsBuilder = Maps.newHashMap();
Map<Field, Converter<?>> convertersBuilder = Maps.newHashMap();
+ Map<Field, Boolean> allowMultipleBuilder = Maps.newHashMap();
// Read all Option annotations:
for (Class<? extends OptionsBase> parsedOptionsClass : classes) {
@@ -256,9 +269,11 @@
optionDefaultsBuilder.put(field, retrieveDefaultFromAnnotation(field));
convertersBuilder.put(field, OptionsParserImpl.findConverter(field));
+
+ allowMultipleBuilder.put(field, annotation.allowMultiple());
}
}
return new OptionsData(constructorBuilder, nameToFieldBuilder, abbrevToFieldBuilder,
- allOptionsFieldsBuilder, optionDefaultsBuilder, convertersBuilder);
+ allOptionsFieldsBuilder, optionDefaultsBuilder, convertersBuilder, allowMultipleBuilder);
}
}
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 80e56cb..400adee 100644
--- a/src/main/java/com/google/devtools/common/options/OptionsParser.java
+++ b/src/main/java/com/google/devtools/common/options/OptionsParser.java
@@ -187,6 +187,41 @@
}
/**
+ * The metadata about an option.
+ */
+ public static final class OptionDescription {
+
+ private final String name;
+ private final Object defaultValue;
+ private final Converter<?> converter;
+ private final boolean allowMultiple;
+
+ public OptionDescription(String name, Object defaultValue, Converter<?> converter,
+ boolean allowMultiple) {
+ this.name = name;
+ this.defaultValue = defaultValue;
+ this.converter = converter;
+ this.allowMultiple = allowMultiple;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Object getDefaultValue() {
+ return defaultValue;
+ }
+
+ public Converter<?> getConverter() {
+ return converter;
+ }
+
+ public boolean getAllowMultiple() {
+ return allowMultiple;
+ }
+ }
+
+ /**
* The name and value of an option with additional metadata describing its
* priority, source, whether it was set via an implicit dependency, and if so,
* by which other option.
@@ -217,10 +252,16 @@
return value;
}
+ /**
+ * @return the priority of the thing that set this value for this flag
+ */
public OptionPriority getPriority() {
return priority;
}
+ /**
+ * @return the thing that set this value for this flag
+ */
public String getSource() {
return source;
}
@@ -450,10 +491,24 @@
}
/**
+ * Returns a description of the option.
+ *
+ * @return The {@link OptionValueDescription} for the option, or null if there is no option by
+ * the given name.
+ */
+ public OptionDescription getOptionDescription(String name) {
+ return impl.getOptionDescription(name);
+ }
+
+ /**
* Returns a description of the option value set by the last previous call to
* {@link #parse(OptionPriority, String, List)} that successfully set the given
* option. If the option is of type {@link List}, the description will
* correspond to any one of the calls, but not necessarily the last.
+ *
+ * @return The {@link OptionValueDescription} for the option, or null if the value has not been
+ * set.
+ * @throws IllegalArgumentException if there is no option by the given name.
*/
public OptionValueDescription getOptionValueDescription(String name) {
return impl.getOptionValueDescription(name);
@@ -520,6 +575,23 @@
}
}
+ /**
+ * Clears the given option. Also clears expansion arguments and implicit requirements for that
+ * option.
+ *
+ * <p>This will not affect options objects that have already been retrieved from this parser
+ * through {@link #getOptions(Class)}.
+ *
+ * @param optionName The full name of the option to clear.
+ * @return A map of an option name to the old value of the options that were cleared.
+ * @throws IllegalArgumentException If the flag does not exist.
+ */
+ public Map<String, OptionValueDescription> clearValue(String optionName) {
+ Map<String, OptionValueDescription> clearedValues = Maps.newHashMap();
+ impl.clearValue(optionName, clearedValues);
+ return clearedValues;
+ }
+
@Override
public List<String> getResidue() {
return ImmutableList.copyOf(residue);
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 bae5293..59d4a0c 100644
--- a/src/main/java/com/google/devtools/common/options/OptionsParserImpl.java
+++ b/src/main/java/com/google/devtools/common/options/OptionsParserImpl.java
@@ -25,6 +25,7 @@
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.devtools.common.options.OptionsParser.OptionDescription;
import com.google.devtools.common.options.OptionsParser.OptionValueDescription;
import com.google.devtools.common.options.OptionsParser.UnparsedOptionValueDescription;
@@ -433,6 +434,28 @@
entry.addValue(priority, value);
}
+ void clearValue(String optionName, Map<String, OptionValueDescription> clearedValues) {
+ Field field = optionsData.getFieldFromName(optionName);
+ if (field == null) {
+ throw new IllegalArgumentException("No such option '" + optionName + "'");
+ }
+
+ ParsedOptionEntry removed = parsedValues.remove(field);
+ if (removed != null) {
+ clearedValues.put(optionName, removed.asOptionValueDescription(optionName));
+ }
+
+ // Recurse to remove any implicit or expansion flags that this flag may have added when
+ // originally parsed.
+ Option option = field.getAnnotation(Option.class);
+ for (String implicitRequirement : option.implicitRequirements()) {
+ clearValue(implicitRequirement, clearedValues);
+ }
+ for (String expansion : option.expansion()) {
+ clearValue(expansion, clearedValues);
+ }
+ }
+
private Object getValue(Field field) {
ParsedOptionEntry entry = parsedValues.get(field);
return entry == null ? null : entry.getValue();
@@ -450,6 +473,20 @@
return entry.asOptionValueDescription(name);
}
+ OptionDescription getOptionDescription(String name) {
+ Field field = optionsData.getFieldFromName(name);
+ if (field == null) {
+ return null;
+ }
+
+ Option optionAnnotation = field.getAnnotation(Option.class);
+ return new OptionDescription(
+ name,
+ optionsData.getDefaultValue(field),
+ optionsData.getConverter(field),
+ optionAnnotation.allowMultiple());
+ }
+
boolean containsExplicitOption(String name) {
Field field = optionsData.getFieldFromName(name);
if (field == null) {
@@ -475,7 +512,7 @@
* of options; in that case, the arg seen last takes precedence.
*
* <p>The method uses the invariant that if an option has neither an implicit
- * dependant nor an expanded from value, then it must have been explicitly
+ * dependent nor an expanded from value, then it must have been explicitly
* set.
*/
private List<String> parse(OptionPriority priority,
@@ -720,5 +757,4 @@
throw new AssertionError(e);
}
}
-
}