Commit 486c7bb6 authored by Adrian Sutton's avatar Adrian Sutton

cannon: Use atomic write pattern to avoid leaving partially written files.

parent 5053698b
......@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"os"
"path"
"github.com/ethereum-optimism/optimism/op-service/ioutil"
)
......@@ -29,13 +30,20 @@ func loadJSON[X any](inputPath string) (*X, error) {
func writeJSON[X any](outputPath string, value X, outIfEmpty bool) error {
var out io.Writer
finish := func() error { return nil }
if outputPath != "" {
f, err := ioutil.OpenCompressed(outputPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
// Write to a tmp file but reserve the file extension if present
tmpPath := outputPath + "-tmp" + path.Ext(outputPath)
f, err := ioutil.OpenCompressed(tmpPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
if err != nil {
return fmt.Errorf("failed to open output file: %w", err)
}
defer f.Close()
out = f
finish = func() error {
// Rename the file into place as atomically as the OS will allow
return os.Rename(tmpPath, outputPath)
}
} else if outIfEmpty {
out = os.Stdout
} else {
......@@ -49,5 +57,8 @@ func writeJSON[X any](outputPath string, value X, outIfEmpty bool) error {
if err != nil {
return fmt.Errorf("failed to append new-line: %w", err)
}
if err := finish(); err != nil {
return fmt.Errorf("failed to finish write: %w", err)
}
return nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment