diff --git a/.gitignore b/.gitignore index 921e29d..1500e9c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ release dist FILE list +.idea \ No newline at end of file diff --git a/commands.go b/commands.go index 432dafd..7da29d9 100644 --- a/commands.go +++ b/commands.go @@ -363,6 +363,7 @@ func NewPutCommand() cli.Command { c.Int("w"), c.Bool("all"), c.Bool("in-progress"), + c.Int("mode"), ) return nil }, @@ -371,6 +372,7 @@ func NewPutCommand() cli.Command { cli.BoolFlag{Name: "in-progress", Usage: "upload a file that can be downloaded simultaneously"}, cli.BoolFlag{Name: "all", Usage: "upload all files including hidden files"}, cli.StringFlag{Name: "err-log", Usage: "upload file error log to file"}, + cli.IntFlag{Name: "mode", Usage: "upload mode: 1=overwrite, 2=skip if exists, 3=overwrite if remote is smaller (default)", Value: 3}, }, } } @@ -403,6 +405,7 @@ func NewUploadCommand() cli.Command { c.String("remote"), c.Int("w"), c.Bool("all"), + c.Int("mode"), ) return nil }, @@ -411,6 +414,7 @@ func NewUploadCommand() cli.Command { cli.IntFlag{Name: "w", Usage: "max concurrent threads", Value: 5}, cli.StringFlag{Name: "remote", Usage: "remote path", Value: "./"}, cli.StringFlag{Name: "err-log", Usage: "upload file error log to file"}, + cli.IntFlag{Name: "mode", Usage: "upload mode: 1=overwrite, 2=skip if exists, 3=overwrite if remote is smaller (default)", Value: 3}, }, } } @@ -634,3 +638,23 @@ func NewMoveCommand() cli.Command { }, } } + +func NewPutByMapCommand() cli.Command { + return cli.Command{ + Name: "put-by-map", + Usage: "put files inside cloud storage by map", + ArgsUsage: "[map-file]", + Before: CreateInitCheckFunc(LOGIN, CHECK), + Action: func(c *cli.Context) error { + if c.NArg() != 1 { + PrintErrorAndExit("invalid command args") + } + session.PutByMap(c.Args()[0], c.Int("w"), c.Int("mode")) + return nil + }, + Flags: []cli.Flag{ + cli.IntFlag{Name: "w", Usage: "max concurrent threads", Value: 5}, + cli.IntFlag{Name: "mode", Usage: "upload mode: 1=overwrite, 2=skip if exists, 3=overwrite if remote is smaller (default)", Value: 3}, + }, + } +} diff --git a/session.go b/session.go index 83279f8..73678dd 100644 --- a/session.go +++ b/session.go @@ -1,12 +1,12 @@ package upx import ( + "bufio" "bytes" "encoding/json" "fmt" "io" "io/fs" - "io/ioutil" "log" "math/rand" "net/http" @@ -71,6 +71,7 @@ type UploadedFile struct { LocalPath string UpPath string LocalInfo os.FileInfo + Mode int } var ( @@ -620,10 +621,11 @@ func (sess *Session) putFilesWitchProgress(localFiles []*UploadedFile, workers i go func() { defer wg.Done() for task := range tasks { - err := sess.putFileWithProgress( + err := sess.putFileWithProgressAndMode( task.LocalPath, task.UpPath, task.LocalInfo, + task.Mode, ) if err != nil { fmt.Println("putFileWithProgress error: ", err.Error()) @@ -641,7 +643,7 @@ func (sess *Session) putFilesWitchProgress(localFiles []*UploadedFile, workers i wg.Wait() } -func (sess *Session) putDir(localPath, upPath string, workers int, withIgnore bool) { +func (sess *Session) putDir(localPath, upPath string, workers int, withIgnore bool, mode int) { localAbsPath, err := filepath.Abs(localPath) if err != nil { PrintErrorAndExit(err.Error()) @@ -672,7 +674,7 @@ func (sess *Session) putDir(localPath, upPath string, workers int, withIgnore bo if err == nil && fInfo.IsDir() { err = sess.updriver.Mkdir(desPath) } else { - err = sess.putFileWithProgress(info.fpath, desPath, info.fInfo) + err = sess.putFileWithProgressAndMode(info.fpath, desPath, info.fInfo, mode) } if err != nil { log.Printf("put %s to %s error: %s", info.fpath, desPath, err) @@ -708,7 +710,7 @@ func (sess *Session) putDir(localPath, upPath string, workers int, withIgnore bo } // / Put 上传单文件或单目录 -func (sess *Session) Put(localPath, upPath string, workers int, withIgnore, inprogress bool) { +func (sess *Session) Put(localPath, upPath string, workers int, withIgnore, inprogress bool, mode int) { upPath = sess.AbsPath(upPath) if inprogress { sess.multipart = true @@ -762,17 +764,18 @@ func (sess *Session) Put(localPath, upPath string, workers int, withIgnore, inpr upPath = path.Join(upPath, filepath.Base(localPath)) } } - sess.putDir(localPath, upPath, workers, withIgnore) + sess.putDir(localPath, upPath, workers, withIgnore, mode) } else { if isDir { upPath = path.Join(upPath, filepath.Base(localPath)) } - sess.putFileWithProgress(localPath, upPath, localInfo) + + sess.putFileWithProgressAndMode(localPath, upPath, localInfo, mode) } } // put 的升级版命令, 支持多文件上传 -func (sess *Session) Upload(filenames []string, upPath string, workers int, withIgnore bool) { +func (sess *Session) Upload(filenames []string, upPath string, workers int, withIgnore bool, mode int) { upPath = sess.AbsPath(upPath) // 检测云端的目的地目录 @@ -804,6 +807,7 @@ func (sess *Session) Upload(filenames []string, upPath string, workers int, with LocalPath: filename, UpPath: path.Join(upPath, filepath.Base(filename)), LocalInfo: localInfo, + Mode: mode, }) } } @@ -815,6 +819,7 @@ func (sess *Session) Upload(filenames []string, upPath string, workers int, with path.Join(upPath, filepath.Base(localPath)), workers, withIgnore, + mode, ) } @@ -1216,7 +1221,7 @@ func (sess *Session) PostTask(app, notify, taskFile string) { PrintErrorAndExit("open %s: %v", taskFile, err) } - body, err := ioutil.ReadAll(fd) + body, err := io.ReadAll(fd) fd.Close() if err != nil { PrintErrorAndExit("read %s: %v", taskFile, err) @@ -1250,7 +1255,7 @@ func (sess *Session) Purge(urls []string, file string) { if err != nil { PrintErrorAndExit("open %s: %v", file, err) } - body, err := ioutil.ReadAll(fd) + body, err := io.ReadAll(fd) fd.Close() if err != nil { PrintErrorAndExit("read %s: %v", file, err) @@ -1373,3 +1378,96 @@ func (sess *Session) copyMove(srcPath, destPath, method string, force bool) erro return fmt.Errorf("not support method") } } + +func (sess *Session) putFileWithProgressAndMode(localPath, upPath string, localInfo os.FileInfo, mode int) error { + // 检查文件是否存在于远程 + upInfo, err := sess.updriver.GetInfo(upPath) + + // 根据不同模式处理上传逻辑 + if err == nil { // 文件存在于远程 + switch mode { + case 1: // 覆盖上传 + // 继续上传,覆盖远程文件 + case 2: // 跳过重复 + if !IsVerbose { + log.Printf("file: %s, Skipped (already exists)\n", upPath) + } else { + fmt.Printf("file: %s, Skipped (already exists)\n", upPath) + } + return nil + case 3: // 检查文件大小 + // 如果远程文件大小大于等于本地文件,则跳过 + if upInfo.Size >= localInfo.Size() { + if !IsVerbose { + log.Printf("file: %s, Skipped (remote size >= local size)\n", upPath) + } else { + fmt.Printf("file: %s, Skipped (remote size >= local size)\n", upPath) + } + return nil + } + // 否则继续上传,覆盖远程文件 + default: + // 默认为模式3 + if upInfo.Size >= localInfo.Size() { + if !IsVerbose { + log.Printf("file: %s, Skipped (remote size >= local size)\n", upPath) + } else { + fmt.Printf("file: %s, Skipped (remote size >= local size)\n", upPath) + } + return nil + } + } + } + + // 执行上传 + return sess.putFileWithProgress(localPath, upPath, localInfo) +} + +func (sess *Session) PutByMap(mapFile string, workers int, mode int) { + fd, err := os.Open(mapFile) + if err != nil { + PrintErrorAndExit("open %s: %v", mapFile, err) + } + defer fd.Close() + + scanner := bufio.NewScanner(fd) + var ( + uploadedFile []*UploadedFile + ) + + for scanner.Scan() { + line := scanner.Text() + if line == "" { + continue + } + + fields := strings.Fields(line) + if len(fields) != 2 { + continue + } + + localPath := fields[0] + upPath := fields[1] + + localInfo, err := os.Stat(localPath) + if err != nil { + PrintErrorAndExit(err.Error()) + } + + uploadedFile = append(uploadedFile, &UploadedFile{ + barId: -1, + LocalPath: localPath, + UpPath: upPath, + LocalInfo: localInfo, + Mode: mode, + }) + + } + + if err := scanner.Err(); err != nil { + PrintErrorAndExit("read %s: %v", mapFile, err) + } + + // 上传文件 + sess.putFilesWitchProgress(uploadedFile, workers) +} diff --git a/upx.go b/upx.go index 9bde3ec..e24058b 100644 --- a/upx.go +++ b/upx.go @@ -60,6 +60,7 @@ func CreateUpxApp() *cli.App { NewUpgradeCommand(), NewCopyCommand(), NewMoveCommand(), + NewPutByMapCommand(), } return app }