aquery: Don't print environment / execution info in text output if it would be empty.

RELNOTES: None
PiperOrigin-RevId: 211788133
diff --git a/src/main/java/com/google/devtools/build/lib/query2/ActionGraphTextOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/ActionGraphTextOutputFormatterCallback.java
index 2f8772d..45a1e96 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/ActionGraphTextOutputFormatterCallback.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/ActionGraphTextOutputFormatterCallback.java
@@ -15,7 +15,7 @@
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Streams;
 import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
 import com.google.devtools.build.lib.actions.ActionExecutionMetadata;
@@ -39,6 +39,8 @@
 import java.io.PrintStream;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /** Output callback for aquery, prints human readable output. */
@@ -127,19 +129,23 @@
       SpawnAction spawnAction = (SpawnAction) action;
       // TODO(twerth): This handles the fixed environment. We probably want to output the inherited
       // environment as well.
-      ImmutableMap<String, String> fixedEnvironment = spawnAction.getEnvironment().getFixedEnv();
-      stringBuilder
-          .append("  Environment: [")
-          .append(
-              Streams.stream(fixedEnvironment.entrySet())
-                  .map(
-                      environmentVariable ->
-                          environmentVariable.getKey() + "=" + environmentVariable.getValue())
-                  .sorted()
-                  .collect(Collectors.joining(", ")))
-          .append("]\n")
+      ImmutableSet<Entry<String, String>> fixedEnvironment =
+          spawnAction.getEnvironment().getFixedEnv().entrySet();
+      if (!fixedEnvironment.isEmpty()) {
+        stringBuilder
+            .append("  Environment: [")
+            .append(
+                fixedEnvironment.stream()
+                    .map(
+                        environmentVariable ->
+                            environmentVariable.getKey() + "=" + environmentVariable.getValue())
+                    .sorted()
+                    .collect(Collectors.joining(", ")))
+            .append("]\n");
+      }
 
-          // TODO(twerth): Add option to only optionally include the command line.
+      // TODO(twerth): Add option to only optionally include the command line.
+      stringBuilder
           .append("  Command Line: ")
           .append(
               CommandFailureUtils.describeCommand(
@@ -152,20 +158,23 @@
     }
 
     if (action instanceof ExecutionInfoSpecifier) {
-      ExecutionInfoSpecifier executionInfoSpecifier = (ExecutionInfoSpecifier) action;
-      stringBuilder
-          .append("  ExecutionInfo: {")
-          .append(
-              executionInfoSpecifier.getExecutionInfo().entrySet().stream()
-                  .sorted(Map.Entry.comparingByKey())
-                  .map(
-                      e ->
-                          String.format(
-                              "%s: %s",
-                              ShellEscaper.escapeString(e.getKey()),
-                              ShellEscaper.escapeString(e.getValue())))
-                  .collect(Collectors.joining(", ")))
-          .append("}\n");
+      Set<Entry<String, String>> executionInfoSpecifiers =
+          ((ExecutionInfoSpecifier) action).getExecutionInfo().entrySet();
+      if (!executionInfoSpecifiers.isEmpty()) {
+        stringBuilder
+            .append("  ExecutionInfo: {")
+            .append(
+                executionInfoSpecifiers.stream()
+                    .sorted(Map.Entry.comparingByKey())
+                    .map(
+                        e ->
+                            String.format(
+                                "%s: %s",
+                                ShellEscaper.escapeString(e.getKey()),
+                                ShellEscaper.escapeString(e.getValue())))
+                    .collect(Collectors.joining(", ")))
+            .append("}\n");
+      }
     }
 
     stringBuilder.append('\n');
diff --git a/src/test/shell/integration/aquery_test.sh b/src/test/shell/integration/aquery_test.sh
index 4b7bfe1..67f34bb 100755
--- a/src/test/shell/integration/aquery_test.sh
+++ b/src/test/shell/integration/aquery_test.sh
@@ -115,8 +115,47 @@
   else
     assert_contains "Command Line: (" output
   fi
-  assert_contains "Environment: \[" output
+}
 
+function test_aquery_skylark_env() {
+  local pkg="${FUNCNAME[0]}"
+  mkdir -p "$pkg" || fail "mkdir -p $pkg"
+  cat > "$pkg/rule.bzl" <<'EOF'
+def _impl(ctx):
+    output = ctx.outputs.out
+    input = ctx.file.source
+    env = {}
+    env["foo"] = "bar"
+
+    ctx.actions.run_shell(
+        inputs = [input],
+        outputs = [output],
+        command = "cat '%s' > '%s'" % (input.path, output.path),
+        env = env,
+    )
+
+copy = rule(
+    implementation = _impl,
+    attrs = {"source": attr.label(mandatory = True, allow_single_file = True)},
+    outputs = {"out": "%{name}.copy"},
+)
+EOF
+
+  cat > "$pkg/BUILD" <<'EOF'
+load(":rule.bzl", "copy")
+copy(
+    name = "goo",
+    source = "dummy.txt",
+)
+EOF
+  echo "hello aquery" > "$pkg/dummy.txt"
+
+  bazel aquery --output=text "//$pkg:goo" > output 2> "$TEST_log" \
+    || fail "Expected success"
+  cat output >> "$TEST_log"
+  assert_contains "Mnemonic: SkylarkAction" output
+  assert_contains "Owner: //$pkg:goo" output
+  assert_contains "Environment: \[.*foo=bar" output
 }
 
 run_suite "${PRODUCT_NAME} action graph query tests"