Centralize atomic artifact writes

This commit is contained in:
2026-05-29 20:33:35 +00:00
parent 7dc2ac9253
commit 1355605e70
13 changed files with 207 additions and 181 deletions

View File

@@ -0,0 +1,48 @@
// Package fileutil provides narrow filesystem helpers for durable artifacts.
package fileutil
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
)
func WriteFileAtomic(path string, data []byte) error {
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return fmt.Errorf("create directory %q: %w", filepath.Dir(path), err)
}
tmp, err := os.CreateTemp(filepath.Dir(path), "."+filepath.Base(path)+".*.tmp")
if err != nil {
return fmt.Errorf("create temporary file for %q: %w", path, err)
}
tmpName := tmp.Name()
defer os.Remove(tmpName)
if _, err := tmp.Write(data); err != nil {
tmp.Close()
return fmt.Errorf("write temporary file for %q: %w", path, err)
}
if err := tmp.Close(); err != nil {
return fmt.Errorf("close temporary file for %q: %w", path, err)
}
if err := os.Rename(tmpName, path); err != nil {
return fmt.Errorf("save %q: %w", path, err)
}
return nil
}
func WriteJSONAtomic(path string, value any) error {
data, err := json.MarshalIndent(value, "", " ")
if err != nil {
return fmt.Errorf("marshal %q: %w", path, err)
}
return WriteFileAtomic(path, data)
}
func CopyFileAtomic(source string, target string) error {
data, err := os.ReadFile(source)
if err != nil {
return fmt.Errorf("read %q: %w", source, err)
}
return WriteFileAtomic(target, data)
}