Add lexicographical sorting for graphless query unordered output guarded by a flag --incompatible_use_lexicographical_unordered_output.

The motivation behind this CL is to make consistent the output order between graphless query and graphless genquery, which outputs in unordered and lexicographical order respectively. The goal is to eventually switch to graphless query with lexicographical ordering as the default. This issue https://github.com/bazelbuild/bazel/issues/12757 keeps track of the flag on github.

PiperOrigin-RevId: 351107138
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/output/QueryOptions.java b/src/main/java/com/google/devtools/build/lib/query2/query/output/QueryOptions.java
index 6d81d1a..d45d940 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/output/QueryOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/output/QueryOptions.java
@@ -130,6 +130,18 @@
   public boolean preferUnorderedOutput;
 
   @Option(
+      name = "incompatible_use_lexicographical_unordered_output",
+      defaultValue = "false",
+      documentationCategory = OptionDocumentationCategory.QUERY,
+      effectTags = {OptionEffectTag.TERMINAL_OUTPUT},
+      metadataTags = {
+        OptionMetadataTag.INCOMPATIBLE_CHANGE,
+        OptionMetadataTag.TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES
+      },
+      help = "If this option is set, sorts unordered output in lexicographical order.")
+  public boolean useLexicographicalUnorderedOutput;
+
+  @Option(
       name = "graph:conditional_edges_limit",
       defaultValue = "4",
       documentationCategory = OptionDocumentationCategory.QUERY,
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java
index 11fdad3..2cf22e8 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java
@@ -127,7 +127,11 @@
           queryOptions.aspectDeps.createResolver(env.getPackageManager(), env.getReporter()),
           hashFunction);
       streamedFormatter.setEventHandler(env.getReporter());
-      callback = streamedFormatter.createStreamCallback(out, queryOptions, queryEnv);
+      if (queryOptions.useLexicographicalUnorderedOutput) {
+        callback = QueryUtil.newLexicographicallySortedTargetAggregator();
+      } else {
+        callback = streamedFormatter.createStreamCallback(out, queryOptions, queryEnv);
+      }
     } else {
       callback = QueryUtil.newOrderedAggregateAllOutputFormatterCallback(queryEnv);
     }
@@ -166,7 +170,7 @@
           out.flush();
         }
       }
-      if (!streamResults) {
+      if (!streamResults || queryOptions.useLexicographicalUnorderedOutput) {
         disableAnsiCharactersFiltering(env);
         try (SilentCloseable closeable = Profiler.instance().profile("QueryOutputUtils.output")) {
           Set<Target> targets =
diff --git a/src/test/shell/integration/bazel_query_test.sh b/src/test/shell/integration/bazel_query_test.sh
index 0ed2599..ec033d7 100755
--- a/src/test/shell/integration/bazel_query_test.sh
+++ b/src/test/shell/integration/bazel_query_test.sh
@@ -711,6 +711,47 @@
   assert_equals "$(cat foo/expected_ap_output)" "$(cat bazel-bin/foo/allpaths)"
 }
 
+function test_graphless_query_matches_graphless_genquery_output() {
+  mkdir -p foo
+  cat > foo/BUILD <<EOF
+sh_library(name = "b", deps = [":c"])
+sh_library(name = "c", deps = [":a"])
+sh_library(name = "a")
+genquery(
+    name = "q",
+    expression = "deps(//foo:b)",
+    scope = ["//foo:b"],
+)
+EOF
+
+  cat > foo/expected_lexicographical_result <<EOF
+//foo:a
+//foo:b
+//foo:c
+EOF
+
+  # Genquery uses a graphless blaze environment by default.
+  bazel build --experimental_genquery_use_graphless_query \
+      //foo:q || fail "Expected success"
+
+  # TODO(tanzhengwei): Remove flags from query when this becomes the default.
+  # Query currently requires the --incompatible_prefer_unordered_output flag to
+  # switch to graphless.
+  # In addition, --incompatible_use_lexicographical_unordered_output is used to
+  # switch sort the graphless output in lexicographical order.
+  bazel query --incompatible_prefer_unordered_output \
+      --incompatible_use_lexicographical_unordered_output \
+      "deps(//foo:b)" | grep foo >& foo/query_output || fail "Expected success"
+
+  # The outputs of graphless query and graphless genquery should be the same.
+  assert_equals "$(cat bazel-bin/foo/q)" "$(cat foo/query_output)"
+
+  # The outputs of both graphless query and graphless genquery should be in
+  # lexicographical order (comparing one should be sufficient).
+  assert_equals \
+      "$(cat foo/expected_lexicographical_result)" "$(cat bazel-bin/foo/q)"
+}
+
 # Regression test for https://github.com/bazelbuild/bazel/issues/8582.
 function test_rbuildfiles_can_handle_non_loading_phase_edges() {
   mkdir -p foo