Optionally include file contents for the file write action.
For the action created by the `ctx.actions.write` call, return the files's contents in the `bazel aquery --include_file_write_contents ...` output.
With `--output=<...>proto`, the file contents is the value of the `file_contents` field. With `--output=text`, show Base64-encoded file contents as the value of `FileWriteContents:` (e.g., if the file contains "hello world", the output will have ` FileWriteContents: [aGVsbG8gd29ybGQ=]` line.
PiperOrigin-RevId: 452789828
Change-Id: I0bde308cc1ebd1ed45f800542307009c005bb33d
diff --git a/site/en/docs/aquery.md b/site/en/docs/aquery.md
index 445d547..2656f9a 100644
--- a/site/en/docs/aquery.md
+++ b/site/en/docs/aquery.md
@@ -133,6 +133,16 @@
Warning: Enabling this flag will automatically enable the `--include_commandline` flag.
+#### `--include_file_write_contents, default=false` {:#include-file-write-contents}
+
+Include file contents for the `actions.write()` action. The file contents is
+returned in the `file_contents` field with `--output=`xxx`proto`.
+With `--output=text`, the output has
+```
+FileWriteContents: [<base64-encoded file contents>]
+```
+line
+
#### `--skyframe_state, default=false` {:#skyframe-state}
Without performing extra analysis, dump the Action Graph from Skyframe.
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/AqueryProcessor.java b/src/main/java/com/google/devtools/build/lib/buildtool/AqueryProcessor.java
index f37ff34..3e78649 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/AqueryProcessor.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/AqueryProcessor.java
@@ -86,6 +86,7 @@
actionFilters,
aqueryOptions.includeParamFiles,
aqueryOptions.deduplicateDepsets,
+ aqueryOptions.includeFileWriteContents,
aqueryOutputHandler);
((SequencedSkyframeExecutor) env.getSkyframeExecutor()).dumpSkyframeState(actionGraphDump);
} catch (InvalidAqueryOutputFormatException e) {
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
index b4936ab..c7c7a8e 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
@@ -437,6 +437,7 @@
/* actionFilters= */ null,
/* includeParamFiles= */ false,
/* deduplicateDepsets= */ true,
+ /* includeFileWriteContents */ false,
aqueryOutputHandler);
((SequencedSkyframeExecutor) env.getSkyframeExecutor()).dumpSkyframeState(actionGraphDump);
}
diff --git a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphProtoOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphProtoOutputFormatterCallback.java
index 7dc7dc3..fa2c7e5 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphProtoOutputFormatterCallback.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphProtoOutputFormatterCallback.java
@@ -65,6 +65,7 @@
this.actionFilters,
options.includeParamFiles,
options.deduplicateDepsets,
+ options.includeFileWriteContents,
aqueryOutputHandler);
}
diff --git a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphTextOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphTextOutputFormatterCallback.java
index c276eb3..1ad9e5c 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphTextOutputFormatterCallback.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphTextOutputFormatterCallback.java
@@ -31,6 +31,7 @@
import com.google.devtools.build.lib.actions.CommandLineExpansionException;
import com.google.devtools.build.lib.analysis.AspectValue;
import com.google.devtools.build.lib.analysis.ConfiguredTargetValue;
+import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction;
import com.google.devtools.build.lib.analysis.actions.Substitution;
import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction;
@@ -47,6 +48,7 @@
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
+import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@@ -327,6 +329,15 @@
stringBuilder.append(" ]\n");
}
+ if (options.includeFileWriteContents && action instanceof FileWriteAction) {
+ FileWriteAction fileWriteAction = (FileWriteAction) action;
+ stringBuilder
+ .append(" FileWriteContents: [")
+ .append(
+ Base64.getEncoder().encodeToString(fileWriteAction.getFileContents().getBytes(UTF_8)))
+ .append("]");
+ }
+
stringBuilder.append('\n');
printStream.write(stringBuilder.toString().getBytes(UTF_8));
diff --git a/src/main/java/com/google/devtools/build/lib/query2/aquery/AqueryOptions.java b/src/main/java/com/google/devtools/build/lib/query2/aquery/AqueryOptions.java
index 58a841a..0117996 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/aquery/AqueryOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/aquery/AqueryOptions.java
@@ -59,6 +59,14 @@
public boolean includeParamFiles;
@Option(
+ name = "include_file_write_contents",
+ defaultValue = "false",
+ documentationCategory = OptionDocumentationCategory.QUERY,
+ effectTags = {OptionEffectTag.TERMINAL_OUTPUT},
+ help = "Include the file contents for the FileWrite action (potentially large). ")
+ public boolean includeFileWriteContents;
+
+ @Option(
name = "skyframe_state",
defaultValue = "false",
documentationCategory = OptionDocumentationCategory.QUERY,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/ActionGraphDump.java b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/ActionGraphDump.java
index c1a443f..c8fd5be 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/ActionGraphDump.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/ActionGraphDump.java
@@ -29,6 +29,7 @@
import com.google.devtools.build.lib.analysis.AspectValue;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.ConfiguredTargetValue;
+import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.analysis.actions.Substitution;
@@ -64,6 +65,7 @@
private final boolean includeActionCmdLine;
private final boolean includeArtifacts;
private final boolean includeParamFiles;
+ private final boolean includeFileWriteContents;
private final AqueryOutputHandler aqueryOutputHandler;
private Map<String, Iterable<String>> paramFileNameToContentMap;
@@ -74,6 +76,7 @@
AqueryActionFilter actionFilters,
boolean includeParamFiles,
boolean deduplicateDepsets,
+ boolean includeFileWriteContents,
AqueryOutputHandler aqueryOutputHandler) {
this(
/* actionGraphTargets= */ ImmutableList.of("..."),
@@ -82,6 +85,7 @@
actionFilters,
includeParamFiles,
deduplicateDepsets,
+ includeFileWriteContents,
aqueryOutputHandler);
}
@@ -92,12 +96,14 @@
AqueryActionFilter actionFilters,
boolean includeParamFiles,
boolean deduplicateDepsets,
+ boolean includeFileWriteContents,
AqueryOutputHandler aqueryOutputHandler) {
this.actionGraphTargets = ImmutableSet.copyOf(actionGraphTargets);
this.includeActionCmdLine = includeActionCmdLine;
this.includeArtifacts = includeArtifacts;
this.actionFilters = actionFilters;
this.includeParamFiles = includeParamFiles;
+ this.includeFileWriteContents = includeFileWriteContents;
this.aqueryOutputHandler = aqueryOutputHandler;
KnownRuleClassStrings knownRuleClassStrings = new KnownRuleClassStrings(aqueryOutputHandler);
@@ -177,6 +183,11 @@
actionBuilder.addAllArguments(commandAction.getArguments());
}
+ if (includeFileWriteContents && action instanceof FileWriteAction) {
+ FileWriteAction fileWriteAction = (FileWriteAction) action;
+ actionBuilder.setFileContents(fileWriteAction.getFileContents());
+ }
+
// Include the content of param files in output.
if (includeParamFiles) {
// Assumption: if an Action takes a params file as an input, it will be used
diff --git a/src/main/protobuf/analysis_v2.proto b/src/main/protobuf/analysis_v2.proto
index d04916b..d3ae80b 100644
--- a/src/main/protobuf/analysis_v2.proto
+++ b/src/main/protobuf/analysis_v2.proto
@@ -112,6 +112,10 @@
// the string to be substituted and the value is the string to be substituted
// to.
repeated KeyValuePair substitutions = 16;
+
+ // The contents of the file for the actions.write() action
+ // (guarded by the --include_file_write_contents flag).
+ string file_contents = 17;
}
// Represents a single target (without configuration information) that is
diff --git a/src/test/shell/integration/aquery_test.sh b/src/test/shell/integration/aquery_test.sh
index 39522d0..eee4a15 100755
--- a/src/test/shell/integration/aquery_test.sh
+++ b/src/test/shell/integration/aquery_test.sh
@@ -1599,6 +1599,41 @@
assert_contains 'Outputs: \[.*/output-\\u00FCn\\u00EFc\\u00F6d\\u00EB.txt' output
}
+function test_file_write() {
+ local pkg="${FUNCNAME[0]}"
+ mkdir -p "$pkg" || fail "mkdir -p $pkg"
+ cat > "$pkg/rule.bzl" <<'EOF'
+def _impl(ctx):
+ ctx.actions.write(content = "hello world", output = ctx.outputs.out)
+
+hello = rule(
+ implementation = _impl,
+ attrs = {
+ },
+ outputs = {"out": "%{name}.count"},
+)
+EOF
+ cat > "$pkg/BUILD" <<'EOF'
+load(":rule.bzl", "hello")
+
+hello(
+ name = 'bar',
+)
+EOF
+
+ bazel aquery --output=text --include_file_write_contents "//$pkg:bar" > output 2> "$TEST_log" \
+ || fail "Expected success"
+ cat output >> "$TEST_log"
+ assert_contains "Mnemonic: FileWrite" output
+ # FileWrite contents is base64-encoded 'hello world'
+ assert_contains "FileWriteContents: \[aGVsbG8gd29ybGQ=\]" output
+
+ bazel aquery --output=textproto --include_file_write_contents "//$pkg:bar" > output 2> "$TEST_log" \
+ || fail "Expected success"
+ cat output >> "$TEST_log"
+ assert_contains 'file_contents: "hello world"' output
+}
+
# TODO(bazel-team): The non-text aquery output formats don't correctly handle
# non-ASCII fields (input/output paths, environment variables, etc).
function DISABLED_test_unicode_textproto() {