aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/osutil
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2025-04-03 14:35:27 +0200
committerDmitry Vyukov <dvyukov@google.com>2025-04-03 13:17:55 +0000
commitd7ae3a111bd75df44dda69b37da945b50d5133e2 (patch)
tree9797c351f3f4d30ae71068ae1447b457506afb7c /pkg/osutil
parent012c639d904cf60a221b8b16833c02eed9b2514e (diff)
pkg/ifuzz: fix generate/build
Currently the commands we have in go:generate first create an empty file and then write final contents. This breaks any parallel builds of the source. Even running go generate ./... does not work. Write output files atomically.
Diffstat (limited to 'pkg/osutil')
-rw-r--r--pkg/osutil/osutil.go13
1 files changed, 13 insertions, 0 deletions
diff --git a/pkg/osutil/osutil.go b/pkg/osutil/osutil.go
index 8e0ed7ea3..d16a76cb7 100644
--- a/pkg/osutil/osutil.go
+++ b/pkg/osutil/osutil.go
@@ -257,6 +257,19 @@ func WriteFile(filename string, data []byte) error {
return os.WriteFile(filename, data, DefaultFilePerm)
}
+// WriteFileAtomically writes data to file filename without exposing and empty/partially-written file.
+// This is useful for writing generated source files. Exposing an empty file may break tools
+// that run on source files in parallel.
+func WriteFileAtomically(filename string, data []byte) error {
+ // We can't use os.CreateTemp b/c it may be on a different mount,
+ // and Rename can't move across mounts.
+ tmpFile := filename + ".tmp"
+ if err := WriteFile(tmpFile, data); err != nil {
+ return err
+ }
+ return os.Rename(tmpFile, filename)
+}
+
func WriteJSON[T any](filename string, obj T) error {
jsonData, err := json.MarshalIndent(obj, "", "\t")
if err != nil {