blob: 7ba8bf61ec5c2b12cc3e01fc5b967027ddb40786 [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.skylark;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.Attribute.AllowedValueSet;
import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
import com.google.devtools.build.lib.packages.Attribute.SkylarkComputedDefaultTemplate;
import com.google.devtools.build.lib.packages.Attribute.SplitTransition;
import com.google.devtools.build.lib.packages.Attribute.SplitTransitionProvider;
import com.google.devtools.build.lib.packages.AttributeValueSource;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.Provider;
import com.google.devtools.build.lib.packages.SkylarkAspect;
import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
import com.google.devtools.build.lib.skylarkinterface.Param;
import com.google.devtools.build.lib.skylarkinterface.ParamType;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.syntax.BuiltinFunction;
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.EvalUtils;
import com.google.devtools.build.lib.syntax.FuncallExpression;
import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkCallbackFunction;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor;
import com.google.devtools.build.lib.syntax.SkylarkType;
import com.google.devtools.build.lib.syntax.SkylarkUtils;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.syntax.Type.ConversionException;
import com.google.devtools.build.lib.syntax.Type.LabelClass;
import com.google.devtools.build.lib.syntax.UserDefinedFunction;
import com.google.devtools.build.lib.util.FileType;
import com.google.devtools.build.lib.util.FileTypeSet;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
/**
* A helper class to provide Attr module in Skylark.
*
* <p>It exposes functions (e.g. 'attr.string', 'attr.label_list', etc.) to Skylark users. The
* functions are executed through reflection. As everywhere in Skylark, arguments are type-checked
* with the signature and cannot be null.
*/
@SkylarkModule(
name = "attr",
namespace = true,
category = SkylarkModuleCategory.BUILTIN,
doc =
"Module for creating new attributes. "
+ "They are only for use with <a href=\"globals.html#rule\">rule</a> or "
+ "<a href=\"globals.html#aspect\">aspect</a>."
)
public final class SkylarkAttr implements SkylarkValue {
// Arguments
private static final String ALLOW_FILES_ARG = "allow_files";
private static final String ALLOW_FILES_DOC =
"whether File targets are allowed. Can be True, False (default), or a list of file "
+ "extensions that are allowed (e.g. <code>[\".cc\", \".cpp\"]</code>).";
private static final String ALLOW_RULES_ARG = "allow_rules";
private static final String ALLOW_RULES_DOC =
"which rule targets (name of the classes) are allowed. This is deprecated (kept only for "
+ "compatibility), use providers instead.";
private static final String ASPECTS_ARG = "aspects";
private static final String ASPECTS_ARG_DOC =
"aspects that should be applied to the dependency or dependencies specified by this "
+ "attribute";
private static final String CONFIGURATION_ARG = "cfg";
private static final String CONFIGURATION_DOC =
"configuration of the attribute. It can be either \"data\", \"host\", or \"target\". "
+ "This parameter is required if <code>executable</code> is True.";
private static final String DEFAULT_ARG = "default";
private static final String DEFAULT_DOC = "the default value of the attribute.";
private static final String DOC_ARG = "doc";
private static final String DOC_DOC =
"a description of the attribute that can be extracted by documentation generating tools.";
private static final String EXECUTABLE_ARG = "executable";
private static final String EXECUTABLE_DOC =
"True if the labels have to be executable. This means the label must refer to an "
+ "executable file, or to a rule that outputs an executable file. Access the labels "
+ "with <code>ctx.executable.&lt;attribute_name&gt;</code>.";
private static final String FLAGS_ARG = "flags";
private static final String FLAGS_DOC = "deprecated, will be removed";
private static final String MANDATORY_ARG = "mandatory";
private static final String MANDATORY_DOC = "True if the value must be explicitly specified";
private static final String NON_EMPTY_ARG = "non_empty";
private static final String NON_EMPTY_DOC =
"True if the attribute must not be empty. Deprecated: Use allow_empty instead.";
private static final String ALLOW_EMPTY_ARG = "allow_empty";
private static final String ALLOW_EMPTY_DOC = "True if the attribute can be empty";
private static final String PROVIDERS_ARG = "providers";
private static final String PROVIDERS_DOC =
"mandatory providers list. It should be either a list of providers, or a "
+ "list of lists of providers. Every dependency should provide ALL providers "
+ "from at least ONE of these lists. A single list of providers will be "
+ "automatically converted to a list containing one list of providers.";
private static final String SINGLE_FILE_ARG = "single_file";
private static final String ALLOW_SINGLE_FILE_ARG = "allow_single_file";
private static final String VALUES_ARG = "values";
private static final String VALUES_DOC =
"the list of allowed values for the attribute. An error is raised if any other "
+ "value is given.";
private static boolean containsNonNoneKey(SkylarkDict<String, Object> arguments, String key) {
return arguments.containsKey(key) && arguments.get(key) != Runtime.NONE;
}
private static void setAllowedFileTypes(
String attr, Object fileTypesObj, FuncallExpression ast, Attribute.Builder<?> builder)
throws EvalException {
if (fileTypesObj == Boolean.TRUE) {
builder.allowedFileTypes(FileTypeSet.ANY_FILE);
} else if (fileTypesObj == Boolean.FALSE) {
builder.allowedFileTypes(FileTypeSet.NO_FILE);
} else if (fileTypesObj instanceof SkylarkFileType) {
// TODO(laurentlb): deprecated, to be removed
builder.allowedFileTypes(((SkylarkFileType) fileTypesObj).getFileTypeSet());
} else if (fileTypesObj instanceof SkylarkList) {
List<String> arg =
SkylarkList.castSkylarkListOrNoneToList(
fileTypesObj, String.class, "allow_files argument");
builder.allowedFileTypes(FileType.of(arg));
} else {
throw new EvalException(
ast.getLocation(), attr + " should be a boolean or a string list");
}
}
private static Attribute.Builder<?> createAttribute(
Type<?> type, SkylarkDict<String, Object> arguments, FuncallExpression ast, Environment env)
throws EvalException {
// We use an empty name now so that we can set it later.
// This trick makes sense only in the context of Skylark (builtin rules should not use it).
return createAttribute(type, arguments, ast, env, "");
}
private static Attribute.Builder<?> createAttribute(
Type<?> type,
SkylarkDict<String, Object> arguments,
FuncallExpression ast,
Environment env,
String name)
throws EvalException {
Attribute.Builder<?> builder = Attribute.attr(name, type);
Object defaultValue = arguments.get(DEFAULT_ARG);
if (!EvalUtils.isNullOrNone(defaultValue)) {
if (defaultValue instanceof UserDefinedFunction) {
// Computed attribute. Non label type attributes already caused a type check error.
SkylarkCallbackFunction callback =
new SkylarkCallbackFunction((UserDefinedFunction) defaultValue, ast, env);
// SkylarkComputedDefaultTemplate needs to know the names of all attributes that it depends
// on. However, this method does not know anything about other attributes.
// We solve this problem by asking the SkylarkCallbackFunction for the parameter names used
// in the function definition, which must be the names of attributes used by the callback.
builder.value(
new SkylarkComputedDefaultTemplate(
type, callback.getParameterNames(), callback, ast.getLocation()));
} else if (defaultValue instanceof SkylarkLateBoundDefault) {
builder.value((SkylarkLateBoundDefault) defaultValue);
} else {
builder.defaultValue(defaultValue, env.getGlobals().getTransitiveLabel(), DEFAULT_ARG);
}
}
for (String flag : SkylarkList.castSkylarkListOrNoneToList(
arguments.get(FLAGS_ARG), String.class, FLAGS_ARG)) {
builder.setPropertyFlag(flag);
}
if (containsNonNoneKey(arguments, MANDATORY_ARG) && (Boolean) arguments.get(MANDATORY_ARG)) {
builder.setPropertyFlag("MANDATORY");
}
// TODO(laurentlb): Deprecated, remove in August 2016 (use allow_empty instead).
if (containsNonNoneKey(arguments, NON_EMPTY_ARG) && (Boolean) arguments.get(NON_EMPTY_ARG)) {
builder.setPropertyFlag("NON_EMPTY");
}
if (containsNonNoneKey(arguments, ALLOW_EMPTY_ARG)
&& !(Boolean) arguments.get(ALLOW_EMPTY_ARG)) {
builder.setPropertyFlag("NON_EMPTY");
}
if (containsNonNoneKey(arguments, EXECUTABLE_ARG) && (Boolean) arguments.get(EXECUTABLE_ARG)) {
builder.setPropertyFlag("EXECUTABLE");
if (!containsNonNoneKey(arguments, CONFIGURATION_ARG)) {
throw new EvalException(
ast.getLocation(),
"cfg parameter is mandatory when executable=True is provided. Please see "
+ "https://www.bazel.build/versions/master/docs/skylark/rules.html#configurations "
+ "for more details.");
}
}
// TODO(laurentlb): Deprecated, remove in August 2016 (use allow_single_file).
if (containsNonNoneKey(arguments, SINGLE_FILE_ARG)
&& (Boolean) arguments.get(SINGLE_FILE_ARG)) {
if (containsNonNoneKey(arguments, ALLOW_SINGLE_FILE_ARG)) {
throw new EvalException(
ast.getLocation(),
"Cannot specify both single_file (deprecated) and allow_single_file");
}
builder.setPropertyFlag("SINGLE_ARTIFACT");
}
if (containsNonNoneKey(arguments, ALLOW_FILES_ARG)
&& containsNonNoneKey(arguments, ALLOW_SINGLE_FILE_ARG)) {
throw new EvalException(
ast.getLocation(), "Cannot specify both allow_files and allow_single_file");
}
if (containsNonNoneKey(arguments, ALLOW_FILES_ARG)) {
Object fileTypesObj = arguments.get(ALLOW_FILES_ARG);
setAllowedFileTypes(ALLOW_FILES_ARG, fileTypesObj, ast, builder);
} else if (containsNonNoneKey(arguments, ALLOW_SINGLE_FILE_ARG)) {
Object fileTypesObj = arguments.get(ALLOW_SINGLE_FILE_ARG);
setAllowedFileTypes(ALLOW_SINGLE_FILE_ARG, fileTypesObj, ast, builder);
builder.setPropertyFlag("SINGLE_ARTIFACT");
} else if (type.getLabelClass() == LabelClass.DEPENDENCY) {
builder.allowedFileTypes(FileTypeSet.NO_FILE);
}
Object ruleClassesObj = arguments.get(ALLOW_RULES_ARG);
if (ruleClassesObj != null && ruleClassesObj != Runtime.NONE) {
builder.allowedRuleClasses(
SkylarkList.castSkylarkListOrNoneToList(
ruleClassesObj, String.class, "allowed rule classes for attribute definition"));
}
List<Object> values = SkylarkList.castSkylarkListOrNoneToList(
arguments.get(VALUES_ARG), Object.class, VALUES_ARG);
if (!Iterables.isEmpty(values)) {
builder.allowedValues(new AllowedValueSet(values));
}
if (containsNonNoneKey(arguments, PROVIDERS_ARG)) {
Object obj = arguments.get(PROVIDERS_ARG);
SkylarkType.checkType(obj, SkylarkList.class, PROVIDERS_ARG);
ImmutableList<ImmutableSet<SkylarkProviderIdentifier>> providersList = buildProviderPredicate(
(SkylarkList<?>) obj, PROVIDERS_ARG, ast.getLocation());
// If there is at least one empty set, there is no restriction.
if (providersList.stream().noneMatch(ImmutableSet::isEmpty)) {
builder.mandatoryProvidersList(providersList);
}
}
if (containsNonNoneKey(arguments, CONFIGURATION_ARG)) {
Object trans = arguments.get(CONFIGURATION_ARG);
if (trans.equals("data")) {
builder.cfg(ConfigurationTransition.DATA);
} else if (trans.equals("host")) {
builder.cfg(ConfigurationTransition.HOST);
} else if (trans instanceof SplitTransition<?>) {
builder.cfg((SplitTransition<?>) trans);
} else if (trans instanceof SplitTransitionProvider) {
builder.cfg((SplitTransitionProvider) trans);
} else if (!trans.equals("target")) {
throw new EvalException(ast.getLocation(),
"cfg must be either 'data', 'host', or 'target'.");
}
}
if (containsNonNoneKey(arguments, ASPECTS_ARG)) {
Object obj = arguments.get(ASPECTS_ARG);
SkylarkType.checkType(obj, SkylarkList.class, ASPECTS_ARG);
List<SkylarkAspect> aspects =
((SkylarkList<?>) obj).getContents(SkylarkAspect.class, "aspects");
for (SkylarkAspect aspect : aspects) {
if (!aspect.isExported()) {
throw new EvalException(
ast.getLocation(),
"Aspects should be top-level values in extension files that define them.");
}
builder.aspect(aspect, ast.getLocation());
}
}
return builder;
}
/**
* Builds a list of sets of accepted providers from Skylark list {@code obj}.
* The list can either be a list of providers (in that case the result is a list with one
* set) or a list of lists of providers (then the result is the list of sets).
* @param argumentName used in error messages.
* @param location location for error messages.
*/
static ImmutableList<ImmutableSet<SkylarkProviderIdentifier>> buildProviderPredicate(
SkylarkList<?> obj, String argumentName, Location location) throws EvalException {
if (obj.isEmpty()) {
return ImmutableList.of();
}
boolean isListOfProviders = true;
for (Object o : obj) {
if (!isProvider(o)) {
isListOfProviders = false;
break;
}
}
if (isListOfProviders) {
return ImmutableList.of(getSkylarkProviderIdentifiers(obj, location));
} else {
return getProvidersList(obj, argumentName, location);
}
}
/**
* Returns true if {@code o} is a Skylark provider (either a declared provider or
* a legacy provider name.
*/
static boolean isProvider(Object o) {
return o instanceof String || o instanceof Provider;
}
/**
* Converts Skylark identifiers of providers (either a string or a provider value)
* to their internal representations.
*/
static ImmutableSet<SkylarkProviderIdentifier> getSkylarkProviderIdentifiers(
SkylarkList<?> list, Location location) throws EvalException {
ImmutableList.Builder<SkylarkProviderIdentifier> result = ImmutableList.builder();
for (Object obj : list) {
if (obj instanceof String) {
result.add(SkylarkProviderIdentifier.forLegacy((String) obj));
} else if (obj instanceof Provider) {
Provider constructor = (Provider) obj;
if (!constructor.isExported()) {
throw new EvalException(location,
"Providers should be top-level values in extension files that define them.");
}
result.add(SkylarkProviderIdentifier.forKey(constructor.getKey()));
}
}
return ImmutableSet.copyOf(result.build());
}
private static ImmutableList<ImmutableSet<SkylarkProviderIdentifier>> getProvidersList(
SkylarkList<?> skylarkList, String argumentName, Location location) throws EvalException {
ImmutableList.Builder<ImmutableSet<SkylarkProviderIdentifier>> providersList =
ImmutableList.builder();
String errorMsg = "Illegal argument: element in '%s' is of unexpected type. "
+ "Either all elements should be providers, "
+ "or all elements should be lists of providers, but got %s.";
for (Object o : skylarkList) {
if (!(o instanceof SkylarkList)) {
throw new EvalException(location, String.format(errorMsg, PROVIDERS_ARG,
"an element of type " + EvalUtils.getDataTypeName(o, true)));
}
for (Object value : (SkylarkList) o) {
if (!isProvider(value)) {
throw new EvalException(location, String.format(errorMsg, argumentName,
"list with an element of type "
+ EvalUtils.getDataTypeNameFromClass(value.getClass())));
}
}
providersList.add(getSkylarkProviderIdentifiers((SkylarkList<?>) o, location));
}
return providersList.build();
}
private static Descriptor createAttrDescriptor(
String name,
SkylarkDict<String, Object> kwargs,
Type<?> type,
FuncallExpression ast,
Environment env)
throws EvalException {
try {
return new Descriptor(name, createAttribute(type, kwargs, ast, env));
} catch (ConversionException e) {
throw new EvalException(ast.getLocation(), e.getMessage());
}
}
private static final Map<Type<?>, String> whyNotConfigurable =
ImmutableMap.<Type<?>, String>builder()
.put(BuildType.LICENSE,
"loading phase license checking logic assumes non-configurable values")
.put(BuildType.OUTPUT, "output paths are part of the static graph structure")
.build();
/**
* If the given attribute type is non-configurable, returns the reason why. Otherwise, returns
* {@code null}.
*/
@Nullable
public static String maybeGetNonConfigurableReason(Type<?> type) {
return whyNotConfigurable.get(type);
}
private static Descriptor createNonconfigurableAttrDescriptor(
String name,
SkylarkDict<String, Object> kwargs,
Type<?> type,
FuncallExpression ast,
Environment env)
throws EvalException {
String whyNotConfigurableReason =
Preconditions.checkNotNull(maybeGetNonConfigurableReason(type), type);
try {
return new Descriptor(
name, createAttribute(type, kwargs, ast, env).nonconfigurable(whyNotConfigurableReason));
} catch (ConversionException e) {
throw new EvalException(ast.getLocation(), e.getMessage());
}
}
@Override
public void repr(SkylarkPrinter printer) {
printer.append("<attr>");
}
@SkylarkSignature(
name = "int",
doc = "Creates an attribute of type int.",
objectType = SkylarkAttr.class,
returnType = Descriptor.class,
parameters = {
@Param(
name = DEFAULT_ARG,
type = Integer.class,
defaultValue = "0",
doc = DEFAULT_DOC,
named = true,
positional = false
),
@Param(
name = DOC_ARG,
type = String.class,
defaultValue = "''",
doc = DOC_DOC,
named = true,
positional = false
),
@Param(
name = MANDATORY_ARG,
type = Boolean.class,
defaultValue = "False",
doc = MANDATORY_DOC,
named = true,
positional = false
),
@Param(
name = VALUES_ARG,
type = SkylarkList.class,
generic1 = Integer.class,
defaultValue = "[]",
doc = VALUES_DOC,
named = true,
positional = false
)
},
useAst = true,
useEnvironment = true
)
private static BuiltinFunction integer =
new BuiltinFunction("int") {
public Descriptor invoke(
Integer defaultInt,
String doc,
Boolean mandatory,
SkylarkList<?> values,
FuncallExpression ast,
Environment env)
throws EvalException {
// TODO(bazel-team): Replace literal strings with constants.
env.checkLoadingOrWorkspacePhase("attr.int", ast.getLocation());
return createAttrDescriptor(
getName(),
EvalUtils.<String, Object>optionMap(
env, DEFAULT_ARG, defaultInt, MANDATORY_ARG, mandatory, VALUES_ARG, values),
Type.INTEGER,
ast,
env);
}
};
@SkylarkSignature(
name = "configuration_field",
returnType = SkylarkLateBoundDefault.class,
// TODO(cparsons): Provide a link to documentation for available SkylarkConfigurationFields.
doc = "References a late-bound default value for an attribute of type "
+ "<a href=\"attr.html#label\">label</a>. A value is 'late-bound' if it requires "
+ "the configuration to be built before determining the value. Any attribute using this "
+ "as a value must <a href=\"../rules.html#private-attributes\">be private</a>.",
parameters = {
@Param(
name = "fragment",
type = String.class,
doc = "The name of a configuration fragment which contains the late-bound value."
),
@Param(
name = "name",
type = String.class,
doc = "The name of the value to obtain from the configuration fragment."),
},
useLocation = true,
useEnvironment = true
)
private static final BuiltinFunction configurationField =
new BuiltinFunction("configuration_field") {
public SkylarkLateBoundDefault<?> invoke(
String fragment, String name, Location loc, Environment env)
throws EvalException {
Class<?> fragmentClass = SkylarkUtils.getFragmentMap(env).get(fragment);
if (fragmentClass == null) {
throw new EvalException(
loc,
String.format("invalid configuration fragment name '%s'", fragment));
}
try {
return SkylarkLateBoundDefault.forConfigurationField(
fragmentClass, name, SkylarkUtils.getToolsRepository(env));
} catch (SkylarkLateBoundDefault.InvalidConfigurationFieldException exception) {
throw new EvalException(loc, exception);
}
}
};
@SkylarkSignature(
name = "string",
doc = "Creates an attribute of type <a href=\"string.html\">string</a>.",
objectType = SkylarkAttr.class,
returnType = Descriptor.class,
parameters = {
@Param(
name = DEFAULT_ARG,
type = String.class,
defaultValue = "''",
doc = DEFAULT_DOC,
named = true,
positional = false
),
@Param(
name = DOC_ARG,
type = String.class,
defaultValue = "''",
doc = DOC_DOC,
named = true,
positional = false
),
@Param(
name = MANDATORY_ARG,
type = Boolean.class,
defaultValue = "False",
doc = MANDATORY_DOC,
named = true,
positional = false
),
@Param(
name = VALUES_ARG,
type = SkylarkList.class,
generic1 = String.class,
defaultValue = "[]",
doc = VALUES_DOC,
named = true,
positional = false
)
},
useAst = true,
useEnvironment = true
)
private static BuiltinFunction string =
new BuiltinFunction("string") {
public Descriptor invoke(
String defaultString,
String doc,
Boolean mandatory,
SkylarkList<?> values,
FuncallExpression ast,
Environment env)
throws EvalException {
env.checkLoadingOrWorkspacePhase("attr.string", ast.getLocation());
return createAttrDescriptor(
getName(),
EvalUtils.<String, Object>optionMap(
env, DEFAULT_ARG, defaultString, MANDATORY_ARG, mandatory, VALUES_ARG, values),
Type.STRING,
ast,
env);
}
};
@SkylarkSignature(
name = "label",
doc =
"Creates an attribute of type <a href=\"Target.html\">Target</a> which is the target "
+ "referred to by the label. "
+ "It is the only way to specify a dependency to another target. "
+ "If you need a dependency that the user cannot overwrite, "
+ "<a href=\"../rules.html#private-attributes\">make the attribute private</a>.",
objectType = SkylarkAttr.class,
returnType = Descriptor.class,
parameters = {
@Param(
name = DEFAULT_ARG,
allowedTypes = {
@ParamType(type = Label.class),
@ParamType(type = String.class),
@ParamType(type = SkylarkLateBoundDefault.class)
},
callbackEnabled = true,
noneable = true,
defaultValue = "None",
named = true,
positional = false,
doc =
DEFAULT_DOC
+ "Use a string or the <a href=\"globals.html#Label\"><code>Label</code></a> "
+ "function to specify a default value ex: "
+ "<code>attr.label(default = \"//a:b\")</code>"
),
@Param(
name = DOC_ARG,
type = String.class,
defaultValue = "''",
doc = DOC_DOC,
named = true,
positional = false
),
@Param(
name = EXECUTABLE_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = EXECUTABLE_DOC
),
@Param(
name = ALLOW_FILES_ARG,
defaultValue = "None",
named = true,
positional = false,
doc = ALLOW_FILES_DOC
),
@Param(
name = ALLOW_SINGLE_FILE_ARG,
defaultValue = "None",
named = true,
positional = false,
doc =
"This is similar to <code>allow_files</code>, with the restriction that the label must "
+ "correspond to a single <a href=\"File.html\">File</a>. "
+ "Access it through <code>ctx.file.&lt;attribute_name&gt;</code>."
),
@Param(
name = MANDATORY_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = MANDATORY_DOC
),
@Param(
name = PROVIDERS_ARG,
type = SkylarkList.class,
defaultValue = "[]",
named = true,
positional = false,
doc = PROVIDERS_DOC
),
@Param(
name = ALLOW_RULES_ARG,
type = SkylarkList.class,
generic1 = String.class,
noneable = true,
defaultValue = "None",
named = true,
positional = false,
doc = ALLOW_RULES_DOC
),
@Param(
name = SINGLE_FILE_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc =
"Deprecated: Use <code>allow_single_file</code> instead. "
+ "If True, the label must correspond to a single <a href=\"File.html\">File</a>. "
+ "Access it through <code>ctx.file.&lt;attribute_name&gt;</code>."
),
@Param(
name = CONFIGURATION_ARG,
type = Object.class,
noneable = true,
defaultValue = "None",
named = true,
positional = false,
doc = CONFIGURATION_DOC
),
@Param(
name = ASPECTS_ARG,
type = SkylarkList.class,
generic1 = SkylarkAspect.class,
defaultValue = "[]",
named = true,
positional = false,
doc = ASPECTS_ARG_DOC
)
},
useAst = true,
useEnvironment = true
)
private static BuiltinFunction label =
new BuiltinFunction("label") {
public Descriptor invoke(
Object defaultO,
String doc,
Boolean executable,
Object allowFiles,
Object allowSingleFile,
Boolean mandatory,
SkylarkList<?> providers,
Object allowRules,
Boolean singleFile,
Object cfg,
SkylarkList<?> aspects,
FuncallExpression ast,
Environment env)
throws EvalException {
env.checkLoadingOrWorkspacePhase("attr.label", ast.getLocation());
try {
Attribute.Builder<?> attribute =
createAttribute(
BuildType.LABEL,
EvalUtils.<String, Object>optionMap(
env,
DEFAULT_ARG,
defaultO,
EXECUTABLE_ARG,
executable,
ALLOW_FILES_ARG,
allowFiles,
ALLOW_SINGLE_FILE_ARG,
allowSingleFile,
MANDATORY_ARG,
mandatory,
PROVIDERS_ARG,
providers,
ALLOW_RULES_ARG,
allowRules,
SINGLE_FILE_ARG,
singleFile,
CONFIGURATION_ARG,
cfg,
ASPECTS_ARG,
aspects),
ast,
env,
"label");
return new Descriptor(getName(), attribute);
} catch (EvalException e) {
throw new EvalException(ast.getLocation(), e.getMessage(), e);
}
}
};
@SkylarkSignature(
name = "string_list",
doc =
"Creates an attribute which is a <a href=\"list.html\">list</a> of "
+ "<a href=\"string.html\">strings</a>.",
objectType = SkylarkAttr.class,
returnType = Descriptor.class,
parameters = {
@Param(
name = DEFAULT_ARG,
type = SkylarkList.class,
generic1 = String.class,
defaultValue = "[]",
doc = DEFAULT_DOC
),
@Param(
name = DOC_ARG,
type = String.class,
defaultValue = "''",
doc = DOC_DOC,
named = true,
positional = false
),
@Param(
name = MANDATORY_ARG,
type = Boolean.class,
defaultValue = "False",
doc = MANDATORY_DOC
),
@Param(
name = NON_EMPTY_ARG,
type = Boolean.class,
defaultValue = "False",
doc = NON_EMPTY_DOC
),
@Param(
name = ALLOW_EMPTY_ARG,
type = Boolean.class,
defaultValue = "True",
doc = ALLOW_EMPTY_DOC
)
},
useAst = true,
useEnvironment = true
)
private static BuiltinFunction stringList =
new BuiltinFunction("string_list") {
public Descriptor invoke(
SkylarkList<?> defaultList,
String doc,
Boolean mandatory,
Boolean nonEmpty,
Boolean allowEmpty,
FuncallExpression ast,
Environment env)
throws EvalException {
env.checkLoadingOrWorkspacePhase("attr.string_list", ast.getLocation());
return createAttrDescriptor(
getName(),
EvalUtils.<String, Object>optionMap(
env,
DEFAULT_ARG,
defaultList,
MANDATORY_ARG,
mandatory,
NON_EMPTY_ARG,
nonEmpty,
ALLOW_EMPTY_ARG,
allowEmpty),
Type.STRING_LIST,
ast,
env);
}
};
@SkylarkSignature(
name = "int_list",
doc = "Creates an attribute which is a <a href=\"list.html\">list</a> of ints.",
objectType = SkylarkAttr.class,
returnType = Descriptor.class,
parameters = {
@Param(
name = DEFAULT_ARG,
type = SkylarkList.class,
generic1 = Integer.class,
defaultValue = "[]",
doc = DEFAULT_DOC
),
@Param(
name = DOC_ARG,
type = String.class,
defaultValue = "''",
doc = DOC_DOC,
named = true,
positional = false
),
@Param(
name = MANDATORY_ARG,
type = Boolean.class,
defaultValue = "False",
doc = MANDATORY_DOC
),
@Param(
name = NON_EMPTY_ARG,
type = Boolean.class,
defaultValue = "False",
doc = NON_EMPTY_DOC
),
@Param(
name = ALLOW_EMPTY_ARG,
type = Boolean.class,
defaultValue = "True",
doc = ALLOW_EMPTY_DOC
)
},
useAst = true,
useEnvironment = true
)
private static BuiltinFunction intList =
new BuiltinFunction("int_list") {
public Descriptor invoke(
SkylarkList<?> defaultList,
String doc,
Boolean mandatory,
Boolean nonEmpty,
Boolean allowEmpty,
FuncallExpression ast,
Environment env)
throws EvalException {
env.checkLoadingOrWorkspacePhase("attr.int_list", ast.getLocation());
return createAttrDescriptor(
getName(),
EvalUtils.<String, Object>optionMap(
env,
DEFAULT_ARG,
defaultList,
MANDATORY_ARG,
mandatory,
NON_EMPTY_ARG,
nonEmpty,
ALLOW_EMPTY_ARG,
allowEmpty),
Type.INTEGER_LIST,
ast,
env);
}
};
@SkylarkSignature(
name = "label_list",
doc =
"Creates an attribute which is a <a href=\"list.html\">list</a> of type "
+ "<a href=\"Target.html\">Target</a> which are specified by the labels in the list. "
+ "See <a href=\"attr.html#label\">label</a> for more information.",
objectType = SkylarkAttr.class,
returnType = Descriptor.class,
parameters = {
@Param(
name = DEFAULT_ARG,
type = SkylarkList.class,
generic1 = Label.class,
callbackEnabled = true,
defaultValue = "[]",
named = true,
positional = false,
doc =
DEFAULT_DOC
+ "Use strings or the <a href=\"globals.html#Label\"><code>Label</code></a> "
+ "function to specify default values ex: "
+ "<code>attr.label_list(default = [\"//a:b\", \"//a:c\"])</code>"
),
@Param(
name = DOC_ARG,
type = String.class,
defaultValue = "''",
doc = DOC_DOC,
named = true,
positional = false
),
@Param(
name = ALLOW_FILES_ARG, // bool or FileType filter
defaultValue = "None",
named = true,
positional = false,
doc = ALLOW_FILES_DOC
),
@Param(
name = ALLOW_RULES_ARG,
type = SkylarkList.class,
generic1 = String.class,
noneable = true,
defaultValue = "None",
named = true,
positional = false,
doc = ALLOW_RULES_DOC
),
@Param(
name = PROVIDERS_ARG,
type = SkylarkList.class,
defaultValue = "[]",
named = true,
positional = false,
doc = PROVIDERS_DOC
),
@Param(
name = FLAGS_ARG,
type = SkylarkList.class,
generic1 = String.class,
defaultValue = "[]",
named = true,
positional = false,
doc = FLAGS_DOC
),
@Param(
name = MANDATORY_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = MANDATORY_DOC
),
@Param(
name = NON_EMPTY_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = NON_EMPTY_DOC
),
@Param(
name = ALLOW_EMPTY_ARG,
type = Boolean.class,
defaultValue = "True",
doc = ALLOW_EMPTY_DOC
),
@Param(
name = CONFIGURATION_ARG,
type = Object.class,
noneable = true,
defaultValue = "None",
named = true,
positional = false,
doc = CONFIGURATION_DOC
),
@Param(
name = ASPECTS_ARG,
type = SkylarkList.class,
generic1 = SkylarkAspect.class,
defaultValue = "[]",
named = true,
positional = false,
doc = ASPECTS_ARG_DOC
)
},
useAst = true,
useEnvironment = true
)
private static BuiltinFunction labelList =
new BuiltinFunction("label_list") {
public Descriptor invoke(
Object defaultList,
String doc,
Object allowFiles,
Object allowRules,
SkylarkList<?> providers,
SkylarkList<?> flags,
Boolean mandatory,
Boolean nonEmpty,
Boolean allowEmpty,
Object cfg,
SkylarkList<?> aspects,
FuncallExpression ast,
Environment env)
throws EvalException {
env.checkLoadingOrWorkspacePhase("attr.label_list", ast.getLocation());
SkylarkDict<String, Object> kwargs =
EvalUtils.<String, Object>optionMap(
env,
DEFAULT_ARG,
defaultList,
ALLOW_FILES_ARG,
allowFiles,
ALLOW_RULES_ARG,
allowRules,
PROVIDERS_ARG,
providers,
FLAGS_ARG,
flags,
MANDATORY_ARG,
mandatory,
NON_EMPTY_ARG,
nonEmpty,
ALLOW_EMPTY_ARG,
allowEmpty,
CONFIGURATION_ARG,
cfg,
ASPECTS_ARG,
aspects);
try {
Attribute.Builder<?> attribute =
createAttribute(BuildType.LABEL_LIST, kwargs, ast, env, "label_list");
return new Descriptor(getName(), attribute);
} catch (EvalException e) {
throw new EvalException(ast.getLocation(), e.getMessage(), e);
}
}
};
@SkylarkSignature(
name = "label_keyed_string_dict",
doc =
"Creates an attribute which is a <a href=\"dict.html\">dict</a>. Its keys are type "
+ "<a href=\"Target.html\">Target</a> and are specified by the label keys of the "
+ "input dict. Its values are <a href=\"string.html\">strings</a>. See "
+ "<a href=\"attr.html#label\">label</a> for more information.",
objectType = SkylarkAttr.class,
returnType = Descriptor.class,
parameters = {
@Param(
name = DEFAULT_ARG,
type = SkylarkDict.class,
callbackEnabled = true,
defaultValue = "{}",
named = true,
positional = false,
doc =
DEFAULT_DOC
+ "Use strings or the <a href=\"globals.html#Label\"><code>Label</code></a> "
+ "function to specify default values ex: "
+ "<code>attr.label_keyed_string_dict(default = "
+ "{\"//a:b\": \"value\", \"//a:c\": \"string\"})</code>"
),
@Param(
name = DOC_ARG,
type = String.class,
defaultValue = "''",
doc = DOC_DOC,
named = true,
positional = false
),
@Param(
name = ALLOW_FILES_ARG, // bool or FileType filter
defaultValue = "None",
named = true,
positional = false,
doc = ALLOW_FILES_DOC
),
@Param(
name = ALLOW_RULES_ARG,
type = SkylarkList.class,
generic1 = String.class,
noneable = true,
defaultValue = "None",
named = true,
positional = false,
doc = ALLOW_RULES_DOC
),
@Param(
name = PROVIDERS_ARG,
type = SkylarkList.class,
defaultValue = "[]",
named = true,
positional = false,
doc = PROVIDERS_DOC
),
@Param(
name = FLAGS_ARG,
type = SkylarkList.class,
generic1 = String.class,
defaultValue = "[]",
named = true,
positional = false,
doc = FLAGS_DOC
),
@Param(
name = MANDATORY_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = MANDATORY_DOC
),
@Param(
name = NON_EMPTY_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = NON_EMPTY_DOC
),
@Param(
name = ALLOW_EMPTY_ARG,
type = Boolean.class,
defaultValue = "True",
doc = ALLOW_EMPTY_DOC
),
@Param(
name = CONFIGURATION_ARG,
type = Object.class,
noneable = true,
defaultValue = "None",
named = true,
positional = false,
doc = CONFIGURATION_DOC
),
@Param(
name = ASPECTS_ARG,
type = SkylarkList.class,
generic1 = SkylarkAspect.class,
defaultValue = "[]",
named = true,
positional = false,
doc = ASPECTS_ARG_DOC
)
},
useAst = true,
useEnvironment = true
)
private static BuiltinFunction labelKeyedStringDict =
new BuiltinFunction("label_keyed_string_dict") {
public Descriptor invoke(
Object defaultList,
String doc,
Object allowFiles,
Object allowRules,
SkylarkList<?> providers,
SkylarkList<?> flags,
Boolean mandatory,
Boolean nonEmpty,
Boolean allowEmpty,
Object cfg,
SkylarkList<?> aspects,
FuncallExpression ast,
Environment env)
throws EvalException {
env.checkLoadingOrWorkspacePhase("attr.label_keyed_string_dict", ast.getLocation());
SkylarkDict<String, Object> kwargs =
EvalUtils.<String, Object>optionMap(
env,
DEFAULT_ARG,
defaultList,
ALLOW_FILES_ARG,
allowFiles,
ALLOW_RULES_ARG,
allowRules,
PROVIDERS_ARG,
providers,
FLAGS_ARG,
flags,
MANDATORY_ARG,
mandatory,
NON_EMPTY_ARG,
nonEmpty,
ALLOW_EMPTY_ARG,
allowEmpty,
CONFIGURATION_ARG,
cfg,
ASPECTS_ARG,
aspects);
try {
Attribute.Builder<?> attribute =
createAttribute(
BuildType.LABEL_KEYED_STRING_DICT, kwargs, ast, env, "label_keyed_string_dict");
return new Descriptor(this.getName(), attribute);
} catch (EvalException e) {
throw new EvalException(ast.getLocation(), e.getMessage(), e);
}
}
};
@SkylarkSignature(
name = "bool",
doc = "Creates an attribute of type bool.",
objectType = SkylarkAttr.class,
returnType = Descriptor.class,
parameters = {
@Param(
name = DEFAULT_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = DEFAULT_DOC
),
@Param(
name = DOC_ARG,
type = String.class,
defaultValue = "''",
doc = DOC_DOC,
named = true,
positional = false
),
@Param(
name = MANDATORY_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = MANDATORY_DOC
)
},
useAst = true,
useEnvironment = true
)
private static BuiltinFunction bool =
new BuiltinFunction("bool") {
public Descriptor invoke(
Boolean defaultO, String doc, Boolean mandatory, FuncallExpression ast, Environment env)
throws EvalException {
env.checkLoadingOrWorkspacePhase("attr.bool", ast.getLocation());
return createAttrDescriptor(
getName(),
EvalUtils.<String, Object>optionMap(
env, DEFAULT_ARG, defaultO, MANDATORY_ARG, mandatory),
Type.BOOLEAN,
ast,
env);
}
};
@SkylarkSignature(
name = "output",
doc =
"Creates an attribute of type output. "
+ "The user provides a file name (string) and the rule must create an action that "
+ "generates the file.",
objectType = SkylarkAttr.class,
returnType = Descriptor.class,
parameters = {
@Param(
name = DEFAULT_ARG,
type = Label.class,
noneable = true,
defaultValue = "None",
named = true,
positional = false,
doc = DEFAULT_DOC
),
@Param(
name = DOC_ARG,
type = String.class,
defaultValue = "''",
doc = DOC_DOC,
named = true,
positional = false
),
@Param(
name = MANDATORY_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = MANDATORY_DOC
)
},
useAst = true,
useEnvironment = true
)
private static BuiltinFunction output =
new BuiltinFunction("output") {
public Descriptor invoke(
Object defaultO, String doc, Boolean mandatory, FuncallExpression ast, Environment env)
throws EvalException {
env.checkLoadingOrWorkspacePhase("attr.output", ast.getLocation());
return createNonconfigurableAttrDescriptor(
getName(),
EvalUtils.<String, Object>optionMap(
env, DEFAULT_ARG, defaultO, MANDATORY_ARG, mandatory),
BuildType.OUTPUT,
ast,
env);
}
};
@SkylarkSignature(
name = "output_list",
doc =
"Creates an attribute which is a <a href=\"list.html\">list</a> of outputs. "
+ "See <a href=\"attr.html#output\">output</a> for more information.",
objectType = SkylarkAttr.class,
returnType = Descriptor.class,
parameters = {
@Param(
name = DEFAULT_ARG,
type = SkylarkList.class,
generic1 = Label.class,
defaultValue = "[]",
named = true,
positional = false,
doc = DEFAULT_DOC
),
@Param(
name = DOC_ARG,
type = String.class,
defaultValue = "''",
doc = DOC_DOC,
named = true,
positional = false
),
@Param(
name = MANDATORY_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = MANDATORY_DOC
),
@Param(
name = NON_EMPTY_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = NON_EMPTY_DOC
),
@Param(
name = ALLOW_EMPTY_ARG,
type = Boolean.class,
defaultValue = "True",
doc = ALLOW_EMPTY_DOC
)
},
useAst = true,
useEnvironment = true
)
private static BuiltinFunction outputList =
new BuiltinFunction("output_list") {
public Descriptor invoke(
SkylarkList defaultList,
String doc,
Boolean mandatory,
Boolean nonEmpty,
Boolean allowEmpty,
FuncallExpression ast,
Environment env)
throws EvalException {
env.checkLoadingOrWorkspacePhase("attr.output_list", ast.getLocation());
return createAttrDescriptor(
getName(),
EvalUtils.<String, Object>optionMap(
env,
DEFAULT_ARG,
defaultList,
MANDATORY_ARG,
mandatory,
NON_EMPTY_ARG,
nonEmpty,
ALLOW_EMPTY_ARG,
allowEmpty),
BuildType.OUTPUT_LIST,
ast,
env);
}
};
@SkylarkSignature(
name = "string_dict",
doc =
"Creates an attribute of type <a href=\"dict.html\">dict</a>, mapping from "
+ "<a href=\"string.html\">string</a> to <a href=\"string.html\">string</a>.",
objectType = SkylarkAttr.class,
returnType = Descriptor.class,
parameters = {
@Param(
name = DEFAULT_ARG,
type = SkylarkDict.class,
named = true,
positional = false,
defaultValue = "{}",
doc = DEFAULT_DOC
),
@Param(
name = DOC_ARG,
type = String.class,
defaultValue = "''",
doc = DOC_DOC,
named = true,
positional = false
),
@Param(
name = MANDATORY_ARG,
type = Boolean.class,
named = true,
positional = false,
defaultValue = "False",
doc = MANDATORY_DOC
),
@Param(
name = NON_EMPTY_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = NON_EMPTY_DOC
),
@Param(
name = ALLOW_EMPTY_ARG,
type = Boolean.class,
defaultValue = "True",
doc = ALLOW_EMPTY_DOC
)
},
useAst = true,
useEnvironment = true
)
private static BuiltinFunction stringDict =
new BuiltinFunction("string_dict") {
public Descriptor invoke(
SkylarkDict<?, ?> defaultO,
String doc,
Boolean mandatory,
Boolean nonEmpty,
Boolean allowEmpty,
FuncallExpression ast,
Environment env)
throws EvalException {
env.checkLoadingOrWorkspacePhase("attr.string_dict", ast.getLocation());
return createAttrDescriptor(
getName(),
EvalUtils.<String, Object>optionMap(
env,
DEFAULT_ARG,
defaultO,
MANDATORY_ARG,
mandatory,
NON_EMPTY_ARG,
nonEmpty,
ALLOW_EMPTY_ARG,
allowEmpty),
Type.STRING_DICT,
ast,
env);
}
};
@SkylarkSignature(
name = "string_list_dict",
doc =
"Creates an attribute of type <a href=\"dict.html\">dict</a>, mapping from "
+ "<a href=\"string.html\">string</a> to <a href=\"list.html\">list</a> of "
+ "<a href=\"string.html\">string</a>.",
objectType = SkylarkAttr.class,
returnType = Descriptor.class,
parameters = {
@Param(
name = DEFAULT_ARG,
type = SkylarkDict.class,
defaultValue = "{}",
named = true,
positional = false,
doc = DEFAULT_DOC
),
@Param(
name = DOC_ARG,
type = String.class,
defaultValue = "''",
doc = DOC_DOC,
named = true,
positional = false
),
@Param(
name = MANDATORY_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = MANDATORY_DOC
),
@Param(
name = NON_EMPTY_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = NON_EMPTY_DOC
),
@Param(
name = ALLOW_EMPTY_ARG,
type = Boolean.class,
defaultValue = "True",
doc = ALLOW_EMPTY_DOC
)
},
useAst = true,
useEnvironment = true
)
private static BuiltinFunction stringListDict =
new BuiltinFunction("string_list_dict") {
public Descriptor invoke(
SkylarkDict<?, ?> defaultO,
String doc,
Boolean mandatory,
Boolean nonEmpty,
Boolean allowEmpty,
FuncallExpression ast,
Environment env)
throws EvalException {
env.checkLoadingOrWorkspacePhase("attr.string_list_dict", ast.getLocation());
return createAttrDescriptor(
getName(),
EvalUtils.<String, Object>optionMap(
env,
DEFAULT_ARG,
defaultO,
MANDATORY_ARG,
mandatory,
NON_EMPTY_ARG,
nonEmpty,
ALLOW_EMPTY_ARG,
allowEmpty),
Type.STRING_LIST_DICT,
ast,
env);
}
};
@SkylarkSignature(
name = "license",
doc = "Creates an attribute of type license.",
// TODO(bazel-team): Implement proper license support for Skylark.
objectType = SkylarkAttr.class,
returnType = Descriptor.class,
parameters = {
// TODO(bazel-team): ensure this is the correct default value
@Param(
name = DEFAULT_ARG,
defaultValue = "None",
noneable = true,
named = true,
positional = false,
doc = DEFAULT_DOC
),
@Param(
name = DOC_ARG,
type = String.class,
defaultValue = "''",
doc = DOC_DOC,
named = true,
positional = false
),
@Param(
name = MANDATORY_ARG,
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = MANDATORY_DOC
)
},
useAst = true,
useEnvironment = true
)
private static BuiltinFunction license =
new BuiltinFunction("license") {
public Descriptor invoke(
Object defaultO, String doc, Boolean mandatory, FuncallExpression ast, Environment env)
throws EvalException {
env.checkLoadingOrWorkspacePhase("attr.license", ast.getLocation());
return createNonconfigurableAttrDescriptor(
getName(),
EvalUtils.<String, Object>optionMap(
env, DEFAULT_ARG, defaultO, MANDATORY_ARG, mandatory),
BuildType.LICENSE,
ast,
env);
}
};
/** A descriptor of an attribute defined in Skylark. */
@SkylarkModule(
name = "Attribute",
category = SkylarkModuleCategory.NONE,
doc =
"Representation of a definition of an attribute. Use the <a href=\"attr\"> module to "
+ "create an Attribute. They are only for use with "
+ "<a href=\"globals.html#rule\">rule</a> or "
+ "<a href=\"globals.html#aspect\">aspect</a>."
)
public static final class Descriptor implements SkylarkValue {
private final Attribute.Builder<?> attributeBuilder;
/**
* This lock guards {@code attributeBuilder} field.
*
* {@link Attribute.Builder} class is not thread-safe for concurrent modification.
*/
private final Object lock = new Object();
private final String name;
public Descriptor(String name, Attribute.Builder<?> attributeBuilder) {
this.attributeBuilder = attributeBuilder;
this.name = name;
}
public boolean hasDefault() {
synchronized (lock) {
return attributeBuilder.isValueSet();
}
}
public AttributeValueSource getValueSource() {
synchronized (lock) {
return attributeBuilder.getValueSource();
}
}
public Attribute build(String name) {
synchronized (lock) {
return attributeBuilder.build(name);
}
}
@Override
public void repr(SkylarkPrinter printer) {
printer.append("<attr." + name + ">");
}
}
static {
SkylarkSignatureProcessor.configureSkylarkFunctions(SkylarkAttr.class);
}
}