fix(setup): preserve symlinks in atomicWriteFile

Add ResolveForWrite helper that resolves symlinks before writing,
so atomic writes go to the symlink target instead of replacing
the symlink itself.
This commit is contained in:
Doug Campos
2025-12-20 18:07:48 -05:00
parent 79191bf7d1
commit c7615e4075
4 changed files with 117 additions and 2 deletions

View File

@@ -179,3 +179,54 @@ func TestCanonicalizePathSymlink(t *testing.T) {
}
}
}
func TestResolveForWrite(t *testing.T) {
t.Run("regular file", func(t *testing.T) {
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "regular.txt")
if err := os.WriteFile(file, []byte("test"), 0644); err != nil {
t.Fatal(err)
}
got, err := ResolveForWrite(file)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got != file {
t.Errorf("got %q, want %q", got, file)
}
})
t.Run("symlink", func(t *testing.T) {
tmpDir := t.TempDir()
target := filepath.Join(tmpDir, "target.txt")
if err := os.WriteFile(target, []byte("test"), 0644); err != nil {
t.Fatal(err)
}
link := filepath.Join(tmpDir, "link.txt")
if err := os.Symlink(target, link); err != nil {
t.Fatal(err)
}
got, err := ResolveForWrite(link)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got != target {
t.Errorf("got %q, want %q", got, target)
}
})
t.Run("non-existent", func(t *testing.T) {
tmpDir := t.TempDir()
newFile := filepath.Join(tmpDir, "new.txt")
got, err := ResolveForWrite(newFile)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got != newFile {
t.Errorf("got %q, want %q", got, newFile)
}
})
}