Add instrumented file provider support to Skylark rules.
RELNOTES: Add instrumented file provider support to Skylark rules.
--
MOS_MIGRATED_REVID=114255963
diff --git a/site/docs/skylark/rules.md b/site/docs/skylark/rules.md
index 12d6f96..f248a5e 100644
--- a/site/docs/skylark/rules.md
+++ b/site/docs/skylark/rules.md
@@ -357,6 +357,29 @@
Also note that if an action uses an executable, the executable's runfiles can
be used when the action executes.
+Instrumented files
+------------------
+
+Instrumented files are a set of files used by the coverage command. A rule can
+use the `instrumented_files` provider to provide information about which files
+should be used for measuring coverage.
+
+```skylark
+def rule_implementation(ctx):
+ ...
+ return struct(instrumented_files=struct(
+ # Optional: File extensions used to filter files from source_attributes.
+ # If not provided, then all files from source_attributes will be
+ # added to instrumented files, if an empty list is provided, then
+ # no files from source attributes will be added.
+ extensions=["ext1", "ext2"],
+ # Optional: Attributes that contain source files for this rule.
+ source_attributes=["srcs"],
+ # Optional: Attributes for dependencies that could include instrumented
+ # files.
+ dependency_attributes=["data", "deps"]))
+```
+
Executable rules
----------------
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
index 5fb0bc5..3c38f3f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
@@ -52,6 +52,7 @@
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
import com.google.devtools.build.lib.packages.Attribute.LateBoundLabel;
+import com.google.devtools.build.lib.packages.Attribute.LateBoundLabelList;
import com.google.devtools.build.lib.packages.AttributeMap;
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SkylarkImplicitOutputsFunctionWithCallback;
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SkylarkImplicitOutputsFunctionWithMap;
@@ -93,6 +94,7 @@
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.util.Preconditions;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@@ -120,6 +122,39 @@
}
};
+ private static final Label COVERAGE_SUPPORT_LABEL =
+ Label.parseAbsoluteUnchecked("//tools/defaults:coverage");
+
+ private static final LateBoundLabelList<BuildConfiguration> GCOV =
+ new LateBoundLabelList<BuildConfiguration>(ImmutableList.of(COVERAGE_SUPPORT_LABEL)) {
+ @Override
+ public List<Label> getDefault(Rule rule, BuildConfiguration configuration) {
+ return configuration.isCodeCoverageEnabled()
+ ? ImmutableList.copyOf(configuration.getGcovLabels())
+ : ImmutableList.<Label>of();
+ }
+ };
+
+ private static final LateBoundLabelList<BuildConfiguration> COVERAGE_REPORT_GENERATOR =
+ new LateBoundLabelList<BuildConfiguration>(ImmutableList.of(COVERAGE_SUPPORT_LABEL)) {
+ @Override
+ public List<Label> getDefault(Rule rule, BuildConfiguration configuration) {
+ return configuration.isCodeCoverageEnabled()
+ ? ImmutableList.copyOf(configuration.getCoverageReportGeneratorLabels())
+ : ImmutableList.<Label>of();
+ }
+ };
+
+ private static final LateBoundLabelList<BuildConfiguration> COVERAGE_SUPPORT =
+ new LateBoundLabelList<BuildConfiguration>(ImmutableList.of(COVERAGE_SUPPORT_LABEL)) {
+ @Override
+ public List<Label> getDefault(Rule rule, BuildConfiguration configuration) {
+ return configuration.isCodeCoverageEnabled()
+ ? ImmutableList.copyOf(configuration.getCoverageLabels())
+ : ImmutableList.<Label>of();
+ }
+ };
+
// TODO(bazel-team): Copied from ConfiguredRuleClassProvider for the transition from built-in
// rules to skylark extensions. Using the same instance would require a large refactoring.
// If we don't want to support old built-in rules and Skylark simultaneously
@@ -183,6 +218,12 @@
.add(attr("$test_runtime", LABEL_LIST).cfg(HOST).value(ImmutableList.of(
labelCache.getUnchecked(Constants.TOOLS_REPOSITORY + "//tools/test:runtime"))))
.add(attr(":run_under", LABEL).cfg(DATA).value(RUN_UNDER))
+ .add(attr(":gcov", LABEL_LIST).cfg(HOST).value(GCOV))
+ .add(attr(":coverage_support", LABEL_LIST).cfg(HOST).value(COVERAGE_SUPPORT))
+ .add(
+ attr(":coverage_report_generator", LABEL_LIST)
+ .cfg(HOST)
+ .value(COVERAGE_REPORT_GENERATOR))
.build();
/**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java
index a07fb06..309e68a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java
@@ -29,6 +29,9 @@
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.TargetUtils;
import com.google.devtools.build.lib.rules.SkylarkRuleContext.Kind;
+import com.google.devtools.build.lib.rules.test.InstrumentedFilesCollector;
+import com.google.devtools.build.lib.rules.test.InstrumentedFilesCollector.InstrumentationSpec;
+import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.syntax.BaseFunction;
import com.google.devtools.build.lib.syntax.ClassObject;
@@ -43,7 +46,11 @@
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
import com.google.devtools.build.lib.syntax.SkylarkType;
import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.util.FileType;
+import com.google.devtools.build.lib.util.FileTypeSet;
+import java.util.Collections;
+import java.util.List;
import java.util.Map;
/**
@@ -221,6 +228,44 @@
defaultRunfiles = cast("default_runfiles", struct, Runfiles.class, loc);
} else if (key.equals("output_groups")) {
addOutputGroups(struct.getValue(key), loc, builder);
+ } else if (key.equals("instrumented_files")) {
+ SkylarkClassObject insStruct =
+ cast("instrumented_files", struct, SkylarkClassObject.class, loc);
+ Location insLoc = insStruct.getCreationLoc();
+ FileTypeSet fileTypeSet = FileTypeSet.ANY_FILE;
+ if (insStruct.getKeys().contains("extensions")) {
+ List<String> exts = cast("extensions", insStruct, List.class, String.class, insLoc);
+ if (exts.isEmpty()) {
+ fileTypeSet = FileTypeSet.NO_FILE;
+ } else {
+ FileType[] fileTypes = new FileType[exts.size()];
+ for (int i = 0; i < fileTypes.length; i++) {
+ fileTypes[i] = FileType.of(exts.get(i));
+ }
+ fileTypeSet = FileTypeSet.of(fileTypes);
+ }
+ }
+ List<String> dependencyAttributes = Collections.emptyList();
+ if (insStruct.getKeys().contains("dependency_attributes")) {
+ dependencyAttributes =
+ cast("dependency_attributes", insStruct, List.class, String.class, insLoc);
+ }
+ List<String> sourceAttributes = Collections.emptyList();
+ if (insStruct.getKeys().contains("source_attributes")) {
+ sourceAttributes =
+ cast("source_attributes", insStruct, List.class, String.class, insLoc);
+ }
+ InstrumentationSpec instrumentationSpec =
+ new InstrumentationSpec(fileTypeSet)
+ .withSourceAttributes(sourceAttributes.toArray(new String[0]))
+ .withDependencyAttributes(dependencyAttributes.toArray(new String[0]));
+ InstrumentedFilesProvider instrumentedFilesProvider =
+ InstrumentedFilesCollector.collect(
+ ruleContext,
+ instrumentationSpec,
+ InstrumentedFilesCollector.NO_METADATA_COLLECTOR,
+ Collections.<Artifact>emptySet());
+ builder.addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider);
} else if (!key.equals("executable")) {
// We handled executable already.
builder.addSkylarkTransitiveInfo(key, struct.getValue(key), loc);