Support relative paths and `%workspace%` in `--experimental_execution_graph_log_path`.

When specifying a relative path for `--experimental_execution_graph_log_path` (e.g. `--experimental_execution_graph_log_path=graph.log`), Bazel previously resolved the path against `env.getOutputBase()`.

Preserves the behavior of writing the default log (`action_graph.dump`) to `env.getOutputBase()` when the flag is unset.

Fixes https://github.com/bazelbuild/bazel/issues/22437

PiperOrigin-RevId: 971922602
Change-Id: I1bf42b62c3ef37fc951625490abc46d8ac45beee
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BUILD b/src/main/java/com/google/devtools/build/lib/runtime/BUILD
index ca23afe..f132c07 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BUILD
@@ -779,6 +779,7 @@
         "//src/main/java/com/google/devtools/build/lib/util:exit_code",
         "//src/main/java/com/google/devtools/build/lib/util:interrupted_failure_details",
         "//src/main/java/com/google/devtools/build/lib/vfs",
+        "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
         "//src/main/java/com/google/devtools/build/skyframe",
         "//src/main/java/com/google/devtools/common/options",
         "//src/main/protobuf:execution_graph_java_proto",
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/ExecutionGraphModule.java b/src/main/java/com/google/devtools/build/lib/runtime/ExecutionGraphModule.java
index 11dc141..5255c0a 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/ExecutionGraphModule.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/ExecutionGraphModule.java
@@ -72,6 +72,7 @@
 import com.google.devtools.build.lib.util.ExitCode;
 import com.google.devtools.build.lib.util.InterruptedFailureDetails;
 import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.build.skyframe.WalkableGraph;
 import com.google.devtools.common.options.EnumConverter;
 import com.google.devtools.common.options.Option;
@@ -102,6 +103,7 @@
 public class ExecutionGraphModule extends BlazeModule {
 
   private static final String ACTION_DUMP_NAME = "execution_graph_dump.proto.zst";
+  private static final PathFragment WORKSPACE_PREFIX = PathFragment.create("%workspace%");
 
   private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();
 
@@ -131,7 +133,8 @@
                 + " experimental_enable_execution_graph_log is disabled, there will be an error. If"
                 + " this is unset while BEP uploads are disabled and"
                 + " experimental_enable_execution_graph_log is enabled, the log will be written to"
-                + " a local default.")
+                + " a local default. The path can be absolute, relative to the current working"
+                + " directory, or prefixed with %workspace% to be relative to the workspace root.")
     public abstract String getExecutionGraphLogPath();
 
     @Option(
@@ -966,10 +969,12 @@
     }
 
     String path = executionGraphOptions.getExecutionGraphLogPath();
+    Path actionGraphFile;
     if (path.isBlank()) {
-      path = ACTION_DUMP_NAME;
+      actionGraphFile = env.getOutputBase().getRelative(ACTION_DUMP_NAME);
+    } else {
+      actionGraphFile = getAbsolutePath(PathFragment.create(path), env);
     }
-    Path actionGraphFile = env.getOutputBase().getRelative(path);
     try {
       return new FilesystemActionDumpWriter(
           env.getRuntime().getBugReporter(),
@@ -985,6 +990,22 @@
     }
   }
 
+  /**
+   * If the given path is an absolute path, leave it as it is. If the given path is a relative path,
+   * it is relative to the current working directory. If the given path starts with '%workspace%',
+   * it is relative to the workspace root, which is the output of `bazel info workspace`.
+   */
+  private static Path getAbsolutePath(PathFragment path, CommandEnvironment env) {
+    if (env.getWorkspace() != null && path.startsWith(WORKSPACE_PREFIX)) {
+      return env.getWorkspace().getRelative(path.relativeTo(WORKSPACE_PREFIX));
+    }
+    if (!path.isAbsolute()) {
+      return env.getWorkingDirectory().getRelative(path);
+    }
+
+    return env.getRuntime().getFileSystem().getPath(path);
+  }
+
   private static final class FilesystemActionDumpWriter extends ActionDumpWriter {
     private final Path actionGraphFile;