diff --git a/build.go b/build.go index 7733d1c..bc48647 100644 --- a/build.go +++ b/build.go @@ -47,6 +47,7 @@ import ( "go.elara.ws/lure/internal/db" "go.elara.ws/lure/internal/dl" "go.elara.ws/lure/internal/repos" + "go.elara.ws/lure/internal/osutils" "go.elara.ws/lure/internal/shutils" "go.elara.ws/lure/internal/shutils/decoder" "go.elara.ws/lure/manager" @@ -117,7 +118,7 @@ func buildCmd(c *cli.Context) error { for _, pkgPath := range pkgPaths { name := filepath.Base(pkgPath) - err = os.Rename(pkgPath, filepath.Join(wd, name)) + err = osutils.Move(pkgPath, filepath.Join(wd, name)) if err != nil { log.Fatal("Error moving the package").Err(err).Send() } diff --git a/internal/osutils/move.go b/internal/osutils/move.go new file mode 100644 index 0000000..5637605 --- /dev/null +++ b/internal/osutils/move.go @@ -0,0 +1,92 @@ +package osutils + +import ( + "io" + "os" + "path/filepath" +) + +// Move attempts to use os.Rename and if that fails (such as for a cross-device move), +// it instead copies the source to the destination and then removes the source. +func Move(sourcePath, destPath string) error { + // Try to rename the source to the destination + err := os.Rename(sourcePath, destPath) + if err == nil { + return nil // Successful move + } + + // Rename failed, so copy the source to the destination + err = copyDirOrFile(sourcePath, destPath) + if err != nil { + return err + } + + // Copy successful, remove the original source + err = os.RemoveAll(sourcePath) + if err != nil { + return err + } + + return nil +} + +func copyDirOrFile(sourcePath, destPath string) error { + sourceInfo, err := os.Stat(sourcePath) + if err != nil { + return err + } + + if sourceInfo.IsDir() { + return copyDir(sourcePath, destPath, sourceInfo) + } else if sourceInfo.Mode().IsRegular() { + return copyFile(sourcePath, destPath, sourceInfo) + } else { + // ignore non-regular files + return nil + } +} + +func copyDir(sourcePath, destPath string, sourceInfo os.FileInfo) error { + err := os.MkdirAll(destPath, sourceInfo.Mode()) + if err != nil { + return err + } + + entries, err := os.ReadDir(sourcePath) + if err != nil { + return err + } + + for _, entry := range entries { + sourceEntry := filepath.Join(sourcePath, entry.Name()) + destEntry := filepath.Join(destPath, entry.Name()) + + err = copyDirOrFile(sourceEntry, destEntry) + if err != nil { + return err + } + } + + return nil +} + +func copyFile(sourcePath, destPath string, sourceInfo os.FileInfo) error { + sourceFile, err := os.Open(sourcePath) + if err != nil { + return err + } + defer sourceFile.Close() + + destFile, err := os.OpenFile(destPath, os.O_CREATE|os.O_TRUNC|os.O_RDWR, sourceInfo.Mode()) + if err != nil { + return err + } + defer destFile.Close() + + _, err = io.Copy(destFile, sourceFile) + if err != nil { + return err + } + + return nil +}