Skip to content

Commit bb2dfee

Browse files
Fix --report-file not created due to cross-device link (#4675)
1 parent f8dab19 commit bb2dfee

File tree

3 files changed

+42
-2
lines changed

3 files changed

+42
-2
lines changed

internal/report/writer.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"strings"
1111
"time"
1212

13+
"github.com/gruntwork-io/terragrunt/util"
1314
"github.com/invopop/jsonschema"
1415
)
1516

@@ -61,7 +62,7 @@ func (r *Report) WriteToFile(path string) error {
6162
path = filepath.Join(r.workingDir, path)
6263
}
6364

64-
return os.Rename(tmpFile.Name(), path)
65+
return util.MoveFile(tmpFile.Name(), path)
6566
}
6667

6768
// WriteCSV writes the report to a writer in CSV format.
@@ -192,7 +193,7 @@ func (r *Report) WriteSchemaToFile(path string) error {
192193
path = filepath.Join(r.workingDir, path)
193194
}
194195

195-
return os.Rename(tmpFile.Name(), path)
196+
return util.MoveFile(tmpFile.Name(), path)
196197
}
197198

198199
// WriteSchema writes a JSON schema for the report to a writer.

util/file.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"path/filepath"
1212
"regexp"
1313
"strings"
14+
"syscall"
1415

1516
urlhelper "github.com/hashicorp/go-getter/helper/url"
1617

@@ -1020,3 +1021,23 @@ func SanitizePath(baseDir string, file string) (string, error) {
10201021

10211022
return fullPath, nil
10221023
}
1024+
1025+
// MoveFile attempts to rename a file from source to destination, if this fails
1026+
// due to invalid cross-device link it falls back to copying the file contents
1027+
// and deleting the original file.
1028+
func MoveFile(source string, destination string) error {
1029+
if renameErr := os.Rename(source, destination); renameErr != nil {
1030+
var sysErr syscall.Errno
1031+
if errors.As(renameErr, &sysErr) && sysErr == syscall.EXDEV {
1032+
if moveErr := CopyFile(source, destination); moveErr != nil {
1033+
return moveErr
1034+
}
1035+
1036+
return os.Remove(source)
1037+
}
1038+
1039+
return renameErr
1040+
}
1041+
1042+
return nil
1043+
}

util/file_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,3 +724,21 @@ func Test_sanitizePath(t *testing.T) {
724724
})
725725
}
726726
}
727+
728+
func TestMoveFile(t *testing.T) {
729+
t.Parallel()
730+
tempDir := t.TempDir()
731+
732+
src := filepath.Join(tempDir, "src.txt")
733+
dst := filepath.Join(tempDir, "dst.txt")
734+
735+
require.NoError(t, os.WriteFile(src, []byte("test"), 0644))
736+
require.NoError(t, util.MoveFile(src, dst))
737+
738+
// Verify the file was moved
739+
_, err := os.Stat(src)
740+
require.True(t, os.IsNotExist(err))
741+
contents, err := os.ReadFile(dst)
742+
require.NoError(t, err)
743+
assert.Equal(t, "test", string(contents))
744+
}

0 commit comments

Comments
 (0)