Skip to content

Commit d5ac6c8

Browse files
authored
fix: enforce removal before copying library files (#2765)
Fixes #2593
1 parent 514cf7e commit d5ac6c8

File tree

4 files changed

+57
-20
lines changed

4 files changed

+57
-20
lines changed

internal/librarian/command.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,15 +299,21 @@ func cleanAndCopyLibrary(state *config.LibrarianState, repoDir, libraryID, outpu
299299
return fmt.Errorf("failed to clean library, %s: %w", library.ID, err)
300300
}
301301

302-
return copyLibraryFiles(state, repoDir, libraryID, outputDir)
302+
return copyLibraryFiles(state, repoDir, libraryID, outputDir, true)
303303
}
304304

305305
// copyLibraryFiles copies the files in state.SourceRoots relative to the src folder to the dest
306-
// folder. It overwrites any existing files.
306+
// folder.
307+
//
308+
// If `failOnExistingFile` is true, the function will check if a file already
309+
// exists at the destination. If it does, an error is returned immediately without copying.
310+
// If `failOnExistingFile` is false, it will overwrite any existing files.
311+
//
307312
// If there's no files in the library's SourceRoots under the src directory, no copy will happen.
313+
//
308314
// If a file is being copied to the library's SourceRoots in the dest folder but the folder does
309315
// not exist, the copy fails.
310-
func copyLibraryFiles(state *config.LibrarianState, dest, libraryID, src string) error {
316+
func copyLibraryFiles(state *config.LibrarianState, dest, libraryID, src string, failOnExistingFile bool) error {
311317
library := state.LibraryByID(libraryID)
312318
if library == nil {
313319
return fmt.Errorf("library %q not found", libraryID)
@@ -324,6 +330,9 @@ func copyLibraryFiles(state *config.LibrarianState, dest, libraryID, src string)
324330
slog.Debug("copying file", "file", file)
325331
srcFile := filepath.Join(srcPath, file)
326332
dstFile := filepath.Join(dstPath, file)
333+
if _, err := os.Stat(dstFile); failOnExistingFile && err == nil {
334+
return fmt.Errorf("file existed in destination: %s", dstFile)
335+
}
327336
if err := copyFile(dstFile, srcFile); err != nil {
328337
return fmt.Errorf("failed to copy file %q for library %s: %w", srcFile, library.ID, err)
329338
}

internal/librarian/command_test.go

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,19 +1782,20 @@ func TestCopyLibraryFiles(t *testing.T) {
17821782
}
17831783
}
17841784
for _, test := range []struct {
1785-
name string
1786-
repoDir string
1787-
outputDir string
1788-
libraryID string
1789-
state *config.LibrarianState
1790-
existingFiles []string
1791-
filesToCreate []string
1792-
setup func(t *testing.T, outputDir string)
1793-
verify func(t *testing.T, repoDir string)
1794-
wantFiles []string
1795-
skipFiles []string
1796-
wantErr bool
1797-
wantErrMsg string
1785+
name string
1786+
repoDir string
1787+
outputDir string
1788+
libraryID string
1789+
state *config.LibrarianState
1790+
existingFiles []string
1791+
filesToCreate []string
1792+
setup func(t *testing.T, outputDir string)
1793+
verify func(t *testing.T, repoDir string)
1794+
wantFiles []string
1795+
skipFiles []string
1796+
failOnExistingFile bool
1797+
wantErr bool
1798+
wantErrMsg string
17981799
}{
17991800
{
18001801
repoDir: "/invalid-dst-path",
@@ -1960,6 +1961,33 @@ func TestCopyLibraryFiles(t *testing.T) {
19601961
"another/path/example.txt",
19611962
},
19621963
},
1964+
{
1965+
name: "file_existed_in_dst",
1966+
repoDir: filepath.Join(t.TempDir(), "dst"),
1967+
outputDir: filepath.Join(t.TempDir(), "foo"),
1968+
libraryID: "example-library",
1969+
state: &config.LibrarianState{
1970+
Libraries: []*config.LibraryState{
1971+
{
1972+
ID: "example-library",
1973+
SourceRoots: []string{
1974+
"a/path",
1975+
"another/path",
1976+
},
1977+
},
1978+
},
1979+
},
1980+
existingFiles: []string{
1981+
"a/path/example.txt",
1982+
},
1983+
filesToCreate: []string{
1984+
"a/path/example.txt",
1985+
"another/path/example.txt",
1986+
},
1987+
failOnExistingFile: true,
1988+
wantErr: true,
1989+
wantErrMsg: "file existed in destination",
1990+
},
19631991
} {
19641992
t.Run(test.name, func(t *testing.T) {
19651993
if len(test.existingFiles) > 0 {
@@ -1971,10 +1999,10 @@ func TestCopyLibraryFiles(t *testing.T) {
19711999
if test.setup != nil {
19722000
test.setup(t, test.outputDir)
19732001
}
1974-
err := copyLibraryFiles(test.state, test.repoDir, test.libraryID, test.outputDir)
2002+
err := copyLibraryFiles(test.state, test.repoDir, test.libraryID, test.outputDir, test.failOnExistingFile)
19752003
if test.wantErr {
19762004
if err == nil {
1977-
t.Fatal("copyLibraryFiles() shoud fail")
2005+
t.Fatal("copyLibraryFiles() should fail")
19782006
}
19792007
if !strings.Contains(err.Error(), test.wantErrMsg) {
19802008
t.Errorf("want error message: %s, got: %s", test.wantErrMsg, err.Error())

internal/librarian/generate_command.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ func (r *generateRunner) runConfigureCommand(ctx context.Context, outputDir stri
375375
r.state.Libraries[i] = libraryState
376376
}
377377

378-
if err := copyLibraryFiles(r.state, r.repo.GetDir(), libraryState.ID, outputDir); err != nil {
378+
if err := copyLibraryFiles(r.state, r.repo.GetDir(), libraryState.ID, outputDir, false); err != nil {
379379
return "", err
380380
}
381381

internal/librarian/release_stage.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ func (r *stageRunner) runStageCommand(ctx context.Context, outputDir string) err
190190
for _, library := range librariesToRelease {
191191
// Copy the library files back if a release is needed
192192
if library.ReleaseTriggered {
193-
if err := copyLibraryFiles(r.state, r.repo.GetDir(), library.ID, outputDir); err != nil {
193+
if err := copyLibraryFiles(r.state, r.repo.GetDir(), library.ID, outputDir, false); err != nil {
194194
return err
195195
}
196196
}

0 commit comments

Comments
 (0)