blob: 1ac9e718982f1436e9d3b0724d17aaaa9a52c03a [file] [log] [blame]
// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.analysis.config;
import static com.google.devtools.build.lib.packages.BuildType.LABEL;
import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
import static com.google.devtools.build.lib.packages.Type.INTEGER;
import static com.google.devtools.build.lib.packages.Type.STRING;
import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.packages.Type;
import com.google.devtools.common.options.Converter;
import com.google.devtools.common.options.Converters.BooleanConverter;
import com.google.devtools.common.options.Converters.CommaSeparatedOptionListConverter;
import com.google.devtools.common.options.Converters.IntegerConverter;
import com.google.devtools.common.options.Converters.StringConverter;
import com.google.devtools.common.options.EnumConverter;
import com.google.devtools.common.options.OptionsParsingException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* {@link Converter}s for {@link com.google.devtools.common.options.Option}s that aren't
* domain-specific (i.e. aren't consumed within a single {@link FragmentOptions}).
*/
public class CoreOptionConverters {
/**
* The set of converters used for {@link com.google.devtools.build.lib.packages.BuildSetting}
* value parsing.
*/
public static final ImmutableMap<Type<?>, Converter<?>> BUILD_SETTING_CONVERTERS =
new ImmutableMap.Builder<Type<?>, Converter<?>>()
.put(INTEGER, new IntegerConverter())
.put(BOOLEAN, new BooleanConverter())
.put(STRING, new StringConverter())
.put(STRING_LIST, new CommaSeparatedOptionListConverter())
.put(LABEL, new LabelConverter())
.put(LABEL_LIST, new LabelListConverter())
.build();
/** A converter from strings to Labels. */
public static class LabelConverter implements Converter<Label> {
@Override
public Label convert(String input) throws OptionsParsingException {
return convertOptionsLabel(input);
}
@Override
public String getTypeDescription() {
return "a build target label";
}
}
/** A converter from comma-separated strings to Label lists. */
public static class LabelListConverter implements Converter<List<Label>> {
@Override
public List<Label> convert(String input) throws OptionsParsingException {
ImmutableList.Builder<Label> result = ImmutableList.builder();
for (String label : Splitter.on(",").omitEmptyStrings().split(input)) {
result.add(convertOptionsLabel(label));
}
return result.build();
}
@Override
public String getTypeDescription() {
return "a build target label";
}
}
/**
* A converter that returns null if the input string is empty, otherwise it converts the input to
* a label.
*/
public static class EmptyToNullLabelConverter implements Converter<Label> {
@Override
public Label convert(String input) throws OptionsParsingException {
return input.isEmpty() ? null : convertOptionsLabel(input);
}
@Override
public String getTypeDescription() {
return "a build target label";
}
}
/** A label converter that returns a default value if the input string is empty. */
public static class DefaultLabelConverter implements Converter<Label> {
private final Label defaultValue;
protected DefaultLabelConverter(String defaultValue) {
this.defaultValue =
defaultValue.equals("null") ? null : Label.parseAbsoluteUnchecked(defaultValue);
}
@Override
public Label convert(String input) throws OptionsParsingException {
return input.isEmpty() ? defaultValue : convertOptionsLabel(input);
}
@Override
public String getTypeDescription() {
return "a build target label";
}
}
/** Flag converter for a map of unique keys with optional labels as values. */
public static class LabelMapConverter implements Converter<Map<String, Label>> {
@Override
public Map<String, Label> convert(String input) throws OptionsParsingException {
// Use LinkedHashMap so we can report duplicate keys more easily while preserving order
Map<String, Label> result = new LinkedHashMap<>();
for (String entry : Splitter.on(",").omitEmptyStrings().trimResults().split(input)) {
String key;
Label label;
int sepIndex = entry.indexOf('=');
if (sepIndex < 0) {
key = entry;
label = null;
} else {
key = entry.substring(0, sepIndex);
String value = entry.substring(sepIndex + 1);
label = value.isEmpty() ? null : convertOptionsLabel(value);
}
if (result.containsKey(key)) {
throw new OptionsParsingException("Key '" + key + "' appears twice");
}
result.put(key, label);
}
return Collections.unmodifiableMap(result);
}
@Override
public String getTypeDescription() {
return "a comma-separated list of keys optionally followed by '=' and a label";
}
}
/** Values for the --strict_*_deps option */
public enum StrictDepsMode {
/** Silently allow referencing transitive dependencies. */
OFF,
/** Warn about transitive dependencies being used directly. */
WARN,
/** Fail the build when transitive dependencies are used directly. */
ERROR,
/** Transition to strict by default. */
STRICT,
/** When no flag value is specified on the command line. */
DEFAULT
}
/** Converter for the --strict_*_deps option. */
public static class StrictDepsConverter extends EnumConverter<StrictDepsMode> {
public StrictDepsConverter() {
super(StrictDepsMode.class, "strict dependency checking level");
}
}
private static final Label convertOptionsLabel(String input) throws OptionsParsingException {
try {
// Check if the input starts with '/'. We don't check for "//" so that
// we get a better error message if the user accidentally tries to use
// an absolute path (starting with '/') for a label.
if (!input.startsWith("/") && !input.startsWith("@")) {
input = "//" + input;
}
return Label.parseAbsolute(input, ImmutableMap.of());
} catch (LabelSyntaxException e) {
throw new OptionsParsingException(e.getMessage());
}
}
}