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 ( ...@@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"path"
"github.com/ethereum-optimism/optimism/op-service/ioutil" "github.com/ethereum-optimism/optimism/op-service/ioutil"
) )
...@@ -29,13 +30,20 @@ func loadJSON[X any](inputPath string) (*X, error) { ...@@ -29,13 +30,20 @@ func loadJSON[X any](inputPath string) (*X, error) {
func writeJSON[X any](outputPath string, value X, outIfEmpty bool) error { func writeJSON[X any](outputPath string, value X, outIfEmpty bool) error {
var out io.Writer var out io.Writer
finish := func() error { return nil }
if outputPath != "" { 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 { if err != nil {
return fmt.Errorf("failed to open output file: %w", err) return fmt.Errorf("failed to open output file: %w", err)
} }
defer f.Close() defer f.Close()
out = f 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 { } else if outIfEmpty {
out = os.Stdout out = os.Stdout
} else { } else {
...@@ -49,5 +57,8 @@ func writeJSON[X any](outputPath string, value X, outIfEmpty bool) error { ...@@ -49,5 +57,8 @@ func writeJSON[X any](outputPath string, value X, outIfEmpty bool) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to append new-line: %w", err) 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 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