diff --git a/internal/command/download.go b/internal/command/download.go index a047de9..dc39485 100644 --- a/internal/command/download.go +++ b/internal/command/download.go @@ -45,8 +45,8 @@ type ( MaxRetry int NoCheck bool ShowProgress bool - DriveId string - UseInternalUrl bool // 是否使用内置链接 + DriveId string + UseInternalUrl bool // 是否使用内置链接 } // LocateDownloadOption 获取下载链接可选参数 @@ -120,7 +120,7 @@ func CmdDownload() cli.Command { MaxRetry: c.Int("retry"), NoCheck: c.Bool("nocheck"), ShowProgress: !c.Bool("np"), - DriveId: parseDriveId(c), + DriveId: parseDriveId(c), } RunDownload(c.Args(), do) @@ -213,8 +213,8 @@ func RunDownload(paths []string, options *DownloadOptions) { BlockSize: MaxDownloadRangeSize, MaxRate: config.Config.MaxDownloadRate, InstanceStateStorageFormat: downloader.InstanceStateStorageFormatJSON, - ShowProgress: options.ShowProgress, - UseInternalUrl: config.Config.TransferUrlType == 2, + ShowProgress: options.ShowProgress, + UseInternalUrl: config.Config.TransferUrlType == 2, } if cfg.CacheSize == 0 { cfg.CacheSize = int(DownloadCacheSize) @@ -231,6 +231,23 @@ func RunDownload(paths []string, options *DownloadOptions) { options.Parallel = config.MaxFileDownloadParallelNum } + // 保存文件的本地根文件夹 + originSaveRootPath := "" + if options.SaveTo != "" { + originSaveRootPath = options.SaveTo + } else { + // 使用默认的保存路径 + originSaveRootPath = GetActiveUser().GetSavePath("") + } + fi, err1 := os.Stat(originSaveRootPath) + if err1 != nil && !os.IsExist(err1) { + os.MkdirAll(originSaveRootPath, 0777) // 首先在本地创建目录 + } else { + if !fi.IsDir() { + fmt.Println("本地保存路径不是文件夹,请删除或者创建对应的文件夹:", originSaveRootPath) + } + } + paths, err := matchPathByShellPattern(options.DriveId, paths...) if err != nil { fmt.Println(err) diff --git a/internal/functions/pandownload/download_task_unit.go b/internal/functions/pandownload/download_task_unit.go index cf6eab0..c82e78f 100644 --- a/internal/functions/pandownload/download_task_unit.go +++ b/internal/functions/pandownload/download_task_unit.go @@ -22,6 +22,7 @@ import ( "github.com/tickstep/aliyunpan/internal/config" "github.com/tickstep/aliyunpan/internal/file/downloader" "github.com/tickstep/aliyunpan/internal/functions" + "github.com/tickstep/aliyunpan/internal/localfile" "github.com/tickstep/aliyunpan/internal/plugins" "github.com/tickstep/aliyunpan/internal/taskframework" "github.com/tickstep/aliyunpan/library/requester/transfer" @@ -95,32 +96,60 @@ func (dtu *DownloadTaskUnit) verboseInfof(format string, a ...interface{}) { } } -// download 执行下载 +// download 执行下载文件(非目录) func (dtu *DownloadTaskUnit) download() (err error) { var ( writer downloader.Writer file *os.File ) - dtu.Cfg.InstanceStatePath = dtu.SavePath + DownloadSuffix - // 创建下载的目录 // 获取SavePath所在的目录 dir := filepath.Dir(dtu.SavePath) - fileInfo, err := os.Stat(dir) - if err != nil { + //fileInfo, err := os.Stat(dir) + //if err != nil { + // // 目录不存在, 创建 + // err = os.MkdirAll(dir, 0777) + // if err != nil { + // return err + // } + //} else if !fileInfo.IsDir() { + // // SavePath所在的目录不是目录 + // return fmt.Errorf("%s, path %s: not a directory", StrDownloadInitError, dir) + //} + // 支持本地符号链接文件,整体逻辑和上面注释代码一致 + savePathSymlinkFile := localfile.SymlinkFile{ + LogicPath: dtu.SavePath, + RealPath: "", + } + originSaveRootSymlinkFile := localfile.NewSymlinkFile(dtu.OriginSaveRootPath) + suffixPath := localfile.GetSuffixPath(dir, dtu.OriginSaveRootPath) + saveDirPathSymlinkFile, saveDirPathFileInfo, err := localfile.RetrieveRealPathFromLogicSuffixPath(originSaveRootSymlinkFile, suffixPath) + if err != nil && !os.IsExist(err) { + realSavePath := saveDirPathSymlinkFile.RealPath + suffixPath = localfile.GetSuffixPath(dtu.SavePath, saveDirPathSymlinkFile.LogicPath) // 获取后缀不存在的路径 + if suffixPath != "" { + realSavePath = filepath.Join(realSavePath, suffixPath) // 拼接 + } // 目录不存在, 创建 - err = os.MkdirAll(dir, 0777) + err = os.MkdirAll(realSavePath, 0777) if err != nil { return err } - } else if !fileInfo.IsDir() { + savePathSymlinkFile.RealPath = realSavePath + "/" + filepath.Base(localfile.CleanPath(dtu.SavePath)) + } else if !saveDirPathFileInfo.IsDir() { // SavePath所在的目录不是目录 - return fmt.Errorf("%s, path %s: not a directory", StrDownloadInitError, dir) + return fmt.Errorf("%s, path %s: not a directory", StrDownloadInitError, saveDirPathSymlinkFile.RealPath) + } else { + savePathSymlinkFile.RealPath = filepath.Join(saveDirPathSymlinkFile.RealPath, filepath.Base(localfile.CleanPath(dtu.SavePath))) } + savePathSymlinkFile, _, _ = localfile.RetrieveRealPath(savePathSymlinkFile) + + // 下载配置文件存储路径 + dtu.Cfg.InstanceStatePath = savePathSymlinkFile.RealPath + DownloadSuffix // 打开文件 - writer, file, err = downloader.NewDownloaderWriterByFilename(dtu.SavePath, os.O_CREATE|os.O_WRONLY, 0666) + writer, file, err = downloader.NewDownloaderWriterByFilename(savePathSymlinkFile.RealPath, os.O_CREATE|os.O_WRONLY, 0666) if err != nil { return fmt.Errorf("%s, %s", StrDownloadInitError, err) } @@ -442,9 +471,21 @@ func (dtu *DownloadTaskUnit) Run() (result *taskframework.TaskUnitRunResult) { // 如果是一个目录, 将子文件和子目录加入队列 if dtu.fileInfo.IsFolder() { - _, err := os.Stat(dtu.SavePath) + //_, err := os.Stat(dtu.SavePath) + //if err != nil && !os.IsExist(err) { + // os.MkdirAll(dtu.SavePath, 0777) // 首先在本地创建目录, 保证空目录也能被保存 + //} + // 支持本地符号逻辑文件,整体逻辑等效上面的注释代码 + originSaveRootSymlinkFile := localfile.NewSymlinkFile(dtu.OriginSaveRootPath) + suffixPath := localfile.GetSuffixPath(dtu.SavePath, dtu.OriginSaveRootPath) + savePathSymlinkFile, _, err := localfile.RetrieveRealPathFromLogicSuffixPath(originSaveRootSymlinkFile, suffixPath) if err != nil && !os.IsExist(err) { - os.MkdirAll(dtu.SavePath, 0777) // 首先在本地创建目录, 保证空目录也能被保存 + realSavePath := savePathSymlinkFile.RealPath + suffixPath = localfile.GetSuffixPath(dtu.SavePath, savePathSymlinkFile.LogicPath) // 获取后缀不存在的路径 + if suffixPath != "" { + realSavePath = filepath.Join(realSavePath, suffixPath) + } + os.MkdirAll(realSavePath, 0777) // 首先在本地创建目录, 保证空目录也能被保存 } // 获取该目录下的文件列表 @@ -508,7 +549,13 @@ func (dtu *DownloadTaskUnit) Run() (result *taskframework.TaskUnitRunResult) { fmt.Printf("[%s] 准备下载: %s\n", dtu.taskInfo.Id(), dtu.FilePanPath) - if !dtu.IsOverwrite && FileExist(dtu.SavePath) { + //if !dtu.IsOverwrite && FileExist(dtu.SavePath) { + // fmt.Printf("[%s] 文件已经存在: %s, 跳过...\n", dtu.taskInfo.Id(), dtu.SavePath) + // result.Succeed = true // 执行成功 + // return + //} + // 支持符号文件,逻辑和注释代码一致 + if !dtu.IsOverwrite && SymlinkFileExist(dtu.SavePath, dtu.OriginSaveRootPath) { fmt.Printf("[%s] 文件已经存在: %s, 跳过...\n", dtu.taskInfo.Id(), dtu.SavePath) result.Succeed = true // 执行成功 return