@@ -5,13 +5,16 @@ import (
55 "io/fs"
66 "os"
77 "path"
8+ "sync"
89
910 "github.com/pkg/errors"
1011)
1112
1213type AtomicWriter struct {
1314 filename string
1415 tempFile * os.File
16+
17+ lock sync.Mutex
1518}
1619
1720var _ io.WriteCloser = & AtomicWriter {}
@@ -52,29 +55,39 @@ func NewAtomicWriter(filename string) (*AtomicWriter, error) {
5255 }
5356 }
5457
55- tempFile , err := os .CreateTemp (path .Dir (filename ), path .Base (filename )+ "*.tmp" )
56- if err != nil {
57- return nil , errors .Wrap (err , "unable to create temporary file" )
58- }
59-
60- return & AtomicWriter {filename : filename , tempFile : tempFile }, nil
58+ return & AtomicWriter {filename : filename }, nil
6159}
6260
63- // Close closes the temp file handle and moves the temp file to the final destination
61+ // Close closes the temp file handle and moves the temp file to the final destination.
62+ // Multiple calls to Close will have no effect after the first success.
6463func (a * AtomicWriter ) Close () error {
65- if err := a .tempFile .Close (); err != nil {
64+ a .lock .Lock ()
65+ defer a .lock .Unlock ()
66+ if a .tempFile == nil {
67+ return nil
68+ }
69+ if err := a .tempFile .Close (); err != nil && ! errors .Is (err , os .ErrClosed ) {
6670 return errors .Wrapf (err , "unable to close temp file %s" , a .tempFile .Name ())
6771 }
68-
6972 if err := os .Rename (a .tempFile .Name (), a .filename ); err != nil {
7073 return errors .Wrapf (err , "unable to move temp file %s to destination %s" , a .tempFile .Name (), a .filename )
7174 }
72-
75+ a . tempFile = nil
7376 return nil
7477}
7578
76- // Write writes the buffer to the temp file. You must call Close() to complete the move from temp file to dest file
79+ // Write writes the buffer to the temp file. You must call Close() to complete the move from temp file to dest file.
80+ // Multiple calls to Write will append to the temp file.
7781func (a * AtomicWriter ) Write (p []byte ) (int , error ) {
82+ a .lock .Lock ()
83+ defer a .lock .Unlock ()
84+ if a .tempFile == nil {
85+ tempFile , err := os .CreateTemp ("" , path .Base (a .filename )+ "*.tmp" )
86+ if err != nil {
87+ return 0 , errors .Wrap (err , "unable to create temporary file" )
88+ }
89+ a .tempFile = tempFile
90+ }
7891 bs , err := a .tempFile .Write (p )
7992 return bs , errors .Wrap (err , "unable to write to temp file" )
8093}
0 commit comments