@@ -27,14 +27,17 @@ type Options struct {
2727 Target string
2828}
2929
30- // Dir atomically writes files to a given directory.
30+ // Dir atomically (best-effort on Windows) writes files to a given directory.
3131type Dir struct {
3232 log logger.Logger
3333
3434 base string
3535 target string
3636 targetDir string
3737
38+ // prev holds a path we should delete on the *next* successful Write.
39+ // On Unix: the previously active versioned dir.
40+ // On Windows: the last backup directory (target renamed aside).
3841 prev * string
3942}
4043
@@ -50,41 +53,45 @@ func New(opts Options) *Dir {
5053func (d * Dir ) Write (files map [string ][]byte ) error {
5154 newDir := filepath .Join (d .base , fmt .Sprintf ("%d-%s" , time .Now ().UTC ().UnixNano (), d .targetDir ))
5255
56+ // Ensure base exists
5357 if err := os .MkdirAll (d .base , 0o700 ); err != nil {
5458 return err
5559 }
56-
60+ // Create the new versioned directory
5761 if err := os .MkdirAll (newDir , 0o700 ); err != nil {
5862 return err
5963 }
6064
65+ // Write all files into the new versioned directory
6166 for file , b := range files {
6267 path := filepath .Join (newDir , file )
68+ // Ensure parent directories exist for nested files
69+ if err := os .MkdirAll (filepath .Dir (path ), 0o700 ); err != nil {
70+ return err
71+ }
6372 if err := os .WriteFile (path , b , 0o600 ); err != nil {
6473 return err
6574 }
6675 d .log .Infof ("Written file %s" , file )
6776 }
6877
69- if err := os .Symlink (newDir , d .target + ".new" ); err != nil {
70- return err
71- }
72-
73- d .log .Infof ("Syslink %s to %s.new" , newDir , d .target )
74-
75- if err := os .Rename (d .target + ".new" , d .target ); err != nil {
78+ // Platform-specific switch into place. It returns what we should delete on the NEXT run.
79+ nextPrev , err := d .switchTo (newDir )
80+ if err != nil {
7681 return err
7782 }
7883
7984 d .log .Infof ("Atomic write to %s" , d .target )
8085
86+ // Best-effort cleanup from the *previous* run
8187 if d .prev != nil {
8288 if err := os .RemoveAll (* d .prev ); err != nil {
8389 return err
8490 }
8591 }
8692
87- d .prev = & newDir
93+ // Set what to delete on the *next* run.
94+ d .prev = nextPrev
8895
8996 return nil
9097}
0 commit comments