Remove IOException from FileWriteAction's newDeterministicWriter

It's rarely employed, and where it is thrown, an ExecException should
be thrown instead.

RELNOTES: None.
PiperOrigin-RevId: 315828068
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/SourceManifestAction.java b/src/main/java/com/google/devtools/build/lib/analysis/SourceManifestAction.java
index 047a178..dbc1470 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/SourceManifestAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/SourceManifestAction.java
@@ -148,8 +148,7 @@
   }
 
   @Override
-  public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx)
-      throws IOException {
+  public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx) {
     final Map<PathFragment, Artifact> runfilesInputs =
         runfiles.getRunfilesInputs(ctx.getEventHandler(), getOwner().getLocation());
     return out -> writeFile(out, runfilesInputs);
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/AbstractFileWriteAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/AbstractFileWriteAction.java
index 1a0c17f..fd4e550 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/AbstractFileWriteAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/AbstractFileWriteAction.java
@@ -24,12 +24,10 @@
 import com.google.devtools.build.lib.actions.ActionOwner;
 import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.EnvironmentalExecException;
 import com.google.devtools.build.lib.actions.ExecException;
 import com.google.devtools.build.lib.actions.SpawnContinuation;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
-import java.io.IOException;
 import javax.annotation.Nullable;
 
 /**
@@ -63,15 +61,7 @@
       ActionExecutionContext actionExecutionContext)
       throws ActionExecutionException, InterruptedException {
     try {
-      DeterministicWriter deterministicWriter;
-      try {
-        deterministicWriter = newDeterministicWriter(actionExecutionContext);
-      } catch (IOException e) {
-        // Message is a bit misleading but is good enough for the end user.
-        throw new EnvironmentalExecException(
-            "Failed to write '" + getPrimaryOutput().prettyPrint() + "'", e);
-      }
-
+      DeterministicWriter deterministicWriter = newDeterministicWriter(actionExecutionContext);
       FileWriteActionContext context = getStrategy(actionExecutionContext);
       SpawnContinuation first =
           context.beginWriteOutputToFile(
@@ -122,10 +112,10 @@
   /**
    * Produce a DeterministicWriter that can write the file to an OutputStream deterministically.
    *
-   * @param ctx context for use with creating the writer.  
+   * @param ctx context for use with creating the writer.
    */
   public abstract DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx)
-      throws IOException, InterruptedException, ExecException;
+      throws InterruptedException, ExecException;
 
   /**
    * This hook is called after the File has been successfully written to disk.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeployInfoAction.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeployInfoAction.java
index 9cb0762..2429cf6 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeployInfoAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeployInfoAction.java
@@ -106,7 +106,7 @@
   }
 
   @Override
-  public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx) throws IOException {
+  public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx) {
     return new ByteStringDeterministicWriter(getByteString());
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/WriteAdbArgsAction.java b/src/main/java/com/google/devtools/build/lib/rules/android/WriteAdbArgsAction.java
index c2e12cb..42db5a5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/WriteAdbArgsAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/WriteAdbArgsAction.java
@@ -17,7 +17,6 @@
 import com.google.devtools.build.lib.actions.ActionKeyContext;
 import com.google.devtools.build.lib.actions.ActionOwner;
 import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.ExecException;
 import com.google.devtools.build.lib.analysis.actions.AbstractFileWriteAction;
 import com.google.devtools.build.lib.analysis.actions.DeterministicWriter;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
@@ -122,8 +121,7 @@
   }
 
   @Override
-  public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx)
-      throws IOException, InterruptedException, ExecException {
+  public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx) {
     Options options = ctx.getOptions().getOptions(Options.class);
     final List<String> args = new ArrayList<>(options.adbArgs);
     final String adb = options.adb;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/WriteBuildInfoHeaderAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/WriteBuildInfoHeaderAction.java
index 3fe5d69..3670d8c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/WriteBuildInfoHeaderAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/WriteBuildInfoHeaderAction.java
@@ -21,11 +21,16 @@
 import com.google.devtools.build.lib.actions.ActionKeyContext;
 import com.google.devtools.build.lib.actions.ActionOwner;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.EnvironmentalExecException;
+import com.google.devtools.build.lib.actions.ExecException;
 import com.google.devtools.build.lib.analysis.WorkspaceStatusAction;
 import com.google.devtools.build.lib.analysis.actions.AbstractFileWriteAction;
 import com.google.devtools.build.lib.analysis.actions.DeterministicWriter;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
+import com.google.devtools.build.lib.server.FailureDetails.WorkspaceStatus;
+import com.google.devtools.build.lib.server.FailureDetails.WorkspaceStatus.Code;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.lib.util.Fingerprint;
 import java.io.IOException;
@@ -84,7 +89,7 @@
 
   @Override
   public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx)
-      throws IOException {
+      throws ExecException {
     WorkspaceStatusAction.Context context = ctx.getContext(WorkspaceStatusAction.Context.class);
 
     final Map<String, WorkspaceStatusAction.Key> keys = new LinkedHashMap<>();
@@ -98,7 +103,16 @@
 
     final Map<String, String> values = new LinkedHashMap<>();
     for (Artifact valueFile : getInputs().toList()) {
-      values.putAll(WorkspaceStatusAction.parseValues(ctx.getInputPath(valueFile)));
+      try {
+        values.putAll(WorkspaceStatusAction.parseValues(ctx.getInputPath(valueFile)));
+      } catch (IOException e) {
+        throw new EnvironmentalExecException(
+            e,
+            FailureDetail.newBuilder()
+                .setMessage("Failed to parse workspace status: " + e.getMessage())
+                .setWorkspaceStatus(WorkspaceStatus.newBuilder().setCode(Code.PARSE_FAILURE))
+                .build());
+      }
     }
 
     final boolean redacted = getInputs().isEmpty();
diff --git a/src/main/protobuf/failure_details.proto b/src/main/protobuf/failure_details.proto
index 69f1477..d53717b 100644
--- a/src/main/protobuf/failure_details.proto
+++ b/src/main/protobuf/failure_details.proto
@@ -149,6 +149,7 @@
   reserved 143; // For internal use
   reserved 149; // For internal use
   reserved 155 to 157; // For internal use
+  reserved 165; // For internal use
 }
 
 message Interrupted {
@@ -364,6 +365,7 @@
     SYMLINK_TREE_MANIFEST_COPY_IO_EXCEPTION = 15
         [(metadata) = { exit_code: 36 }];
     SYMLINK_TREE_CREATION_IO_EXCEPTION = 16 [(metadata) = { exit_code: 36 }];
+    ACTION_INPUT_READ_IO_EXCEPTION = 17 [(metadata) = { exit_code: 36 }];
   }
 
   Code code = 1;
@@ -795,6 +797,7 @@
     NON_ZERO_EXIT = 1 [(metadata) = { exit_code: 1 }];
     ABNORMAL_TERMINATION = 2 [(metadata) = { exit_code: 1 }];
     EXEC_FAILED = 3 [(metadata) = { exit_code: 1 }];
+    PARSE_FAILURE = 4 [(metadata) = { exit_code: 36 }];
   }
 
   Code code = 1;