diff options
| -rw-r--r-- | drive/download.go | 91 | ||||
| -rw-r--r-- | drive/util.go | 9 | ||||
| -rw-r--r-- | gdrive.go | 11 | ||||
| -rw-r--r-- | handlers_drive.go | 4 |
4 files changed, 104 insertions, 11 deletions
diff --git a/drive/download.go b/drive/download.go index e5674ad..9434ca6 100644 --- a/drive/download.go +++ b/drive/download.go @@ -4,25 +4,46 @@ import ( "fmt" "io" "os" + "time" + "path/filepath" + "google.golang.org/api/drive/v3" ) -type DownloadFileArgs struct { +type DownloadArgs struct { Out io.Writer Progress io.Writer Id string + Path string Force bool + Recursive bool Stdout bool } -func (self *Drive) Download(args DownloadFileArgs) (err error) { - getFile := self.service.Files.Get(args.Id) +func (self *Drive) Download(args DownloadArgs) error { + return self.download(args) +} - f, err := getFile.Do() +func (self *Drive) download(args DownloadArgs) error { + f, err := self.service.Files.Get(args.Id).Fields("id", "name", "size", "mimeType", "md5Checksum").Do() if err != nil { return fmt.Errorf("Failed to get file: %s", err) } - res, err := getFile.Download() + if isDir(f) && !args.Recursive { + return fmt.Errorf("'%s' is a directory, use --recursive to download directories", f.Name) + } else if isDir(f) && args.Recursive { + return self.downloadDirectory(f, args) + } else if isBinary(f) { + return self.downloadBinary(f, args) + } else if !args.Recursive { + return fmt.Errorf("'%s' is a google document and must be exported, see the export command", f.Name) + } + + return nil +} + +func (self *Drive) downloadBinary(f *drive.File, args DownloadArgs) error { + res, err := self.service.Files.Get(f.Id).Download() if err != nil { return fmt.Errorf("Failed to download file: %s", err) } @@ -39,13 +60,20 @@ func (self *Drive) Download(args DownloadFileArgs) (err error) { return err } + filename := filepath.Join(args.Path, f.Name) + // Check if file exists - if !args.Force && fileExists(f.Name) { - return fmt.Errorf("File '%s' already exists, use --force to overwrite", f.Name) + if !args.Force && fileExists(filename) { + return fmt.Errorf("File '%s' already exists, use --force to overwrite", filename) + } + + // Ensure any parent directories exists + if err = mkdir(filename); err != nil { + return err } // Create new file - outFile, err := os.Create(f.Name) + outFile, err := os.Create(filename) if err != nil { return fmt.Errorf("Unable to create new file: %s", err) } @@ -53,16 +81,59 @@ func (self *Drive) Download(args DownloadFileArgs) (err error) { // Close file on function exit defer outFile.Close() + fmt.Fprintf(args.Out, "\nDownloading %s...\n", f.Name) + started := time.Now() + // Save file to disk bytes, err := io.Copy(outFile, srcReader) if err != nil { return fmt.Errorf("Failed saving file: %s", err) } - fmt.Fprintf(args.Out, "Downloaded '%s' at %s, total %d\n", f.Name, "x/s", bytes) + // Calculate average download rate + rate := calcRate(f.Size, started, time.Now()) + + fmt.Fprintf(args.Out, "Downloaded '%s' at %s/s, total %s\n", filename, formatSize(rate, false), formatSize(bytes, false)) //if deleteSourceFile { // self.Delete(args.Id) //} - return + return nil +} + +func (self *Drive) downloadDirectory(parent *drive.File, args DownloadArgs) error { + query := fmt.Sprintf("'%s' in parents", parent.Id) + fileList, err := self.service.Files.List().Q(query).Fields("files(id,name)").Do() + if err != nil { + return fmt.Errorf("Failed listing files: %s", err) + } + + // Update download path + path := filepath.Join(args.Path, parent.Name) + + for _, f := range fileList.Files { + err = self.download(DownloadArgs{ + Out: args.Out, + Id: f.Id, + Progress: args.Progress, + Force: args.Force, + Path: path, + Recursive: args.Recursive, + Stdout: false, + }) + + if err != nil { + return err + } + } + + return nil +} + +func isDir(f *drive.File) bool { + return f.MimeType == DirectoryMimeType +} + +func isBinary(f *drive.File) bool { + return f.Md5Checksum != "" } diff --git a/drive/util.go b/drive/util.go index 8b3d171..f492286 100644 --- a/drive/util.go +++ b/drive/util.go @@ -3,6 +3,7 @@ package drive import ( "os" "fmt" + "path/filepath" "strings" "strconv" "unicode/utf8" @@ -122,6 +123,14 @@ func fileExists(path string) bool { return false } +func mkdir(path string) error { + dir := filepath.Dir(path) + if fileExists(dir) { + return nil + } + return os.MkdirAll(dir, 0775) +} + func intMax() int64 { return 1 << (strconv.IntSize - 1) - 1 } @@ -110,6 +110,17 @@ func main() { Description: "Overwrite existing file", OmitValue: true, }, + cli.StringFlag{ + Name: "path", + Patterns: []string{"--path"}, + Description: "Download path", + }, + cli.BoolFlag{ + Name: "recursive", + Patterns: []string{"-r", "--recursive"}, + Description: "Download directory recursively, documents will be skipped", + OmitValue: true, + }, cli.BoolFlag{ Name: "noProgress", Patterns: []string{"--no-progress"}, diff --git a/handlers_drive.go b/handlers_drive.go index 04075f4..38c1e1c 100644 --- a/handlers_drive.go +++ b/handlers_drive.go @@ -30,10 +30,12 @@ func listHandler(ctx cli.Context) { func downloadHandler(ctx cli.Context) { args := ctx.Args() - err := newDrive(args).Download(drive.DownloadFileArgs{ + err := newDrive(args).Download(drive.DownloadArgs{ Out: os.Stdout, Id: args.String("id"), Force: args.Bool("force"), + Path: args.String("path"), + Recursive: args.Bool("recursive"), Stdout: args.Bool("stdout"), Progress: progressWriter(args.Bool("noProgress")), }) |
