// 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.rules;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.Root;
import com.google.devtools.build.lib.analysis.ActionsProvider;
import com.google.devtools.build.lib.analysis.AnalysisUtils;
import com.google.devtools.build.lib.analysis.ConfigurationMakeVariableContext;
import com.google.devtools.build.lib.analysis.DefaultProvider;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
import com.google.devtools.build.lib.analysis.LabelExpander;
import com.google.devtools.build.lib.analysis.LabelExpander.NotUniqueExpansionException;
import com.google.devtools.build.lib.analysis.MakeVariableExpander.ExpansionException;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.FragmentCollection;
import com.google.devtools.build.lib.analysis.platform.ToolchainInfo;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.AspectDescriptor;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.ClassObjectConstructor;
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SkylarkImplicitOutputsFunction;
import com.google.devtools.build.lib.packages.NativeClassObjectConstructor;
import com.google.devtools.build.lib.packages.OutputFile;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.packages.RawAttributeMapper;
import com.google.devtools.build.lib.packages.SkylarkClassObject;
import com.google.devtools.build.lib.rules.test.InstrumentedFilesCollector;
import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider;
import com.google.devtools.build.lib.shell.ShellUtils;
import com.google.devtools.build.lib.shell.ShellUtils.TokenizationException;
import com.google.devtools.build.lib.skylarkinterface.Param;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.FuncallExpression.FuncallException;
import com.google.devtools.build.lib.syntax.Printer;
import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkType;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.syntax.Type.LabelClass;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.Nullable;
/** A Skylark API for the ruleContext.
*
* "This object becomes featureless once the rule implementation function that it was created for
* has completed. To achieve this, the {@link #nullify()} should be called once the evaluation of
* the function is completed. The method both frees memory by deleting all significant fields of the
* object and makes it impossible to accidentally use this object where it's not supposed to be used
* (such attempts will result in {@link EvalException}s).
*/
@SkylarkModule(
name = "ctx",
category = SkylarkModuleCategory.BUILTIN,
doc =
"The context of the rule containing helper functions and "
+ "information about attributes, depending targets and outputs. "
+ "You get a ctx object as an argument to the implementation
function when "
+ "you create a rule."
)
public final class SkylarkRuleContext implements SkylarkValue {
private static final String DOC_NEW_FILE_TAIL = "Does not actually create a file on the file "
+ "system, just declares that some action will do so. You must create an action that "
+ "generates the file. If the file should be visible to other rules, declare a rule output "
+ "instead when possible. Doing so enables Blaze to associate a label with the file that "
+ "rules can refer to (allowing finer dependency control) instead of referencing the whole "
+ "rule.";
public static final String EXECUTABLE_DOC =
"A struct
containing executable files defined in label type "
+ "attributes marked as executable=True
. The struct fields correspond "
+ "to the attribute names. Each value in the struct is either a file
or "
+ "None
. If an optional attribute is not specified in the rule "
+ "then the corresponding struct value is None
. If a label type is not "
+ "marked as executable=True
, no corresponding struct field is generated.";
public static final String FILES_DOC =
"A struct
containing files defined in label or label list "
+ "type attributes. The struct fields correspond to the attribute names. The struct "
+ "values are list
of file
s. If an optional attribute is "
+ "not specified in the rule, an empty list is generated. "
+ "It is a shortcut for:"
+ "
[f for t in ctx.attr.<ATTR> for f in t.files]"; public static final String FILE_DOC = "A
struct
containing files defined in label type "
+ "attributes marked as single_file=True
. The struct fields correspond "
+ "to the attribute names. The struct value is always a file
or "
+ "None
. If an optional attribute is not specified in the rule "
+ "then the corresponding struct value is None
. If a label type is not "
+ "marked as single_file=True
, no corresponding struct field is generated. "
+ "It is a shortcut for:"
+ "list(ctx.attr.<ATTR>.files)[0]"; public static final String ATTR_DOC = "A struct to access the values of the attributes. The values are provided by " + "the user (if not, a default value is used)."; public static final String SPLIT_ATTR_DOC = "A struct to access the values of attributes with split configurations. If the attribute is " + "a label list, the value of split_attr is a dict of the keys of the split (as strings) " + "to lists of the ConfiguredTargets in that branch of the split. If the attribute is a " + "label, then the value of split_attr is a dict of the keys of the split (as strings) " + "to single ConfiguredTargets. Attributes with split configurations still appear in the " + "attr struct, but their values will be single lists with all the branches of the split " + "merged together."; public static final String OUTPUTS_DOC = "A
struct
containing all the output files."
+ " The struct is generated the following way:executable=True
the struct has an "
+ "\"executable\" field with the rules default executable file
value."
+ "outputs
dict an attr is generated with "
+ "the same name and the corresponding file
value."
+ "file
value or None
, "
+ "if no value is specified in the rule."
+ "list
of file
s value "
+ "(an empty list if no value is specified in the rule).null
* if it is for a rule.
* @throws InterruptedException
*/
public SkylarkRuleContext(RuleContext ruleContext,
@Nullable AspectDescriptor aspectDescriptor)
throws EvalException, InterruptedException {
this.ruleContext = Preconditions.checkNotNull(ruleContext);
this.ruleLabelCanonicalName = ruleContext.getLabel().getCanonicalForm();
this.fragments = new FragmentCollection(ruleContext, ConfigurationTransition.NONE);
this.hostFragments = new FragmentCollection(ruleContext, ConfigurationTransition.HOST);
this.aspectDescriptor = aspectDescriptor;
if (aspectDescriptor == null) {
Collection