aboutsummaryrefslogtreecommitdiff
path: root/atomictemp/atomictemp.go
diff options
context:
space:
mode:
Diffstat (limited to 'atomictemp/atomictemp.go')
-rw-r--r--atomictemp/atomictemp.go48
1 files changed, 48 insertions, 0 deletions
diff --git a/atomictemp/atomictemp.go b/atomictemp/atomictemp.go
new file mode 100644
index 0000000..b56d095
--- /dev/null
+++ b/atomictemp/atomictemp.go
@@ -0,0 +1,48 @@
+// Create a temporary file in the directory of the given destination
+// file, then rename the temporary file over the destination file if
+// writes to the temporary file complete without error.
+//
+// Used to atomically update files.
+//
+// Note: This is not guaranteed and depends on the sync semantics of the
+// underlying filesystem.
+package atomictemp
+
+import (
+ "io"
+ "os"
+ "path/filepath"
+)
+
+// Create a temporary file in the directory of the given destination
+// file, then rename the temporary file over the destination file if
+// writes to the temporary file complete without error.
+//
+// Used to atomically update files.
+//
+// Note: This is not guaranteed and depends on the sync semantics of the
+// underlying filesystem.
+func Create(dstPath string, fn func(io.Writer) error) error {
+ // open temp output file
+ f, err := os.CreateTemp(filepath.Dir(dstPath), "")
+ if err != nil {
+ return err
+ }
+
+ // build absolute path to temporary file
+ // tmpPath := filepath.Join(filepath.Dir(dstPath), f.Name())
+ defer os.Remove(f.Name())
+
+ // invoke callback
+ if err = fn(f); err != nil {
+ return err
+ }
+
+ // close temp file
+ if err = f.Close(); err != nil {
+ return err
+ }
+
+ // rename to destination file, return result
+ return os.Rename(f.Name(), dstPath)
+}