"Fossies" - the Fresh Open Source Software Archive

Member "gdrive-2.1.1/drive/download.go" (28 May 2021, 6031 Bytes) of package /linux/misc/gdrive-2.1.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 package drive
    2 
    3 import (
    4     "fmt"
    5     "io"
    6     "os"
    7     "path/filepath"
    8     "time"
    9 
   10     "google.golang.org/api/drive/v3"
   11     "google.golang.org/api/googleapi"
   12 )
   13 
   14 type DownloadArgs struct {
   15     Out       io.Writer
   16     Progress  io.Writer
   17     Id        string
   18     Path      string
   19     Force     bool
   20     Skip      bool
   21     Recursive bool
   22     Delete    bool
   23     Stdout    bool
   24     Timeout   time.Duration
   25 }
   26 
   27 func (self *Drive) Download(args DownloadArgs) error {
   28     if args.Recursive {
   29         return self.downloadRecursive(args)
   30     }
   31 
   32     f, err := self.service.Files.Get(args.Id).Fields("id", "name", "size", "mimeType", "md5Checksum").Do()
   33     if err != nil {
   34         return fmt.Errorf("Failed to get file: %s", err)
   35     }
   36 
   37     if isDir(f) {
   38         return fmt.Errorf("'%s' is a directory, use --recursive to download directories", f.Name)
   39     }
   40 
   41     if !isBinary(f) {
   42         return fmt.Errorf("'%s' is a google document and must be exported, see the export command", f.Name)
   43     }
   44 
   45     bytes, rate, err := self.downloadBinary(f, args)
   46     if err != nil {
   47         return err
   48     }
   49 
   50     if !args.Stdout {
   51         fmt.Fprintf(args.Out, "Downloaded %s at %s/s, total %s\n", f.Id, formatSize(rate, false), formatSize(bytes, false))
   52     }
   53 
   54     if args.Delete {
   55         err = self.deleteFile(args.Id)
   56         if err != nil {
   57             return fmt.Errorf("Failed to delete file: %s", err)
   58         }
   59 
   60         if !args.Stdout {
   61             fmt.Fprintf(args.Out, "Removed %s\n", args.Id)
   62         }
   63     }
   64     return err
   65 }
   66 
   67 type DownloadQueryArgs struct {
   68     Out       io.Writer
   69     Progress  io.Writer
   70     Query     string
   71     Path      string
   72     Force     bool
   73     Skip      bool
   74     Recursive bool
   75 }
   76 
   77 func (self *Drive) DownloadQuery(args DownloadQueryArgs) error {
   78     listArgs := listAllFilesArgs{
   79         query:  args.Query,
   80         fields: []googleapi.Field{"nextPageToken", "files(id,name,mimeType,size,md5Checksum)"},
   81     }
   82     files, err := self.listAllFiles(listArgs)
   83     if err != nil {
   84         return fmt.Errorf("Failed to list files: %s", err)
   85     }
   86 
   87     downloadArgs := DownloadArgs{
   88         Out:      args.Out,
   89         Progress: args.Progress,
   90         Path:     args.Path,
   91         Force:    args.Force,
   92         Skip:     args.Skip,
   93     }
   94 
   95     for _, f := range files {
   96         if isDir(f) && args.Recursive {
   97             err = self.downloadDirectory(f, downloadArgs)
   98         } else if isBinary(f) {
   99             _, _, err = self.downloadBinary(f, downloadArgs)
  100         }
  101 
  102         if err != nil {
  103             return err
  104         }
  105     }
  106 
  107     return nil
  108 }
  109 
  110 func (self *Drive) downloadRecursive(args DownloadArgs) error {
  111     f, err := self.service.Files.Get(args.Id).Fields("id", "name", "size", "mimeType", "md5Checksum").Do()
  112     if err != nil {
  113         return fmt.Errorf("Failed to get file: %s", err)
  114     }
  115 
  116     if isDir(f) {
  117         return self.downloadDirectory(f, args)
  118     } else if isBinary(f) {
  119         _, _, err = self.downloadBinary(f, args)
  120         return err
  121     }
  122 
  123     return nil
  124 }
  125 
  126 func (self *Drive) downloadBinary(f *drive.File, args DownloadArgs) (int64, int64, error) {
  127     // Get timeout reader wrapper and context
  128     timeoutReaderWrapper, ctx := getTimeoutReaderWrapperContext(args.Timeout)
  129 
  130     res, err := self.service.Files.Get(f.Id).Context(ctx).Download()
  131     if err != nil {
  132         if isTimeoutError(err) {
  133             return 0, 0, fmt.Errorf("Failed to download file: timeout, no data was transferred for %v", args.Timeout)
  134         }
  135         return 0, 0, fmt.Errorf("Failed to download file: %s", err)
  136     }
  137 
  138     // Close body on function exit
  139     defer res.Body.Close()
  140 
  141     // Path to file
  142     fpath := filepath.Join(args.Path, f.Name)
  143 
  144     if !args.Stdout {
  145         fmt.Fprintf(args.Out, "Downloading %s -> %s\n", f.Name, fpath)
  146     }
  147 
  148     return self.saveFile(saveFileArgs{
  149         out:           args.Out,
  150         body:          timeoutReaderWrapper(res.Body),
  151         contentLength: res.ContentLength,
  152         fpath:         fpath,
  153         force:         args.Force,
  154         skip:          args.Skip,
  155         stdout:        args.Stdout,
  156         progress:      args.Progress,
  157     })
  158 }
  159 
  160 type saveFileArgs struct {
  161     out           io.Writer
  162     body          io.Reader
  163     contentLength int64
  164     fpath         string
  165     force         bool
  166     skip          bool
  167     stdout        bool
  168     progress      io.Writer
  169 }
  170 
  171 func (self *Drive) saveFile(args saveFileArgs) (int64, int64, error) {
  172     // Wrap response body in progress reader
  173     srcReader := getProgressReader(args.body, args.progress, args.contentLength)
  174 
  175     if args.stdout {
  176         // Write file content to stdout
  177         _, err := io.Copy(args.out, srcReader)
  178         return 0, 0, err
  179     }
  180 
  181     // Check if file exists to force
  182     if !args.skip && !args.force && fileExists(args.fpath) {
  183         return 0, 0, fmt.Errorf("File '%s' already exists, use --force to overwrite or --skip to skip", args.fpath)
  184     }
  185 
  186     //Check if file exists to skip
  187     if args.skip && fileExists(args.fpath) {
  188         fmt.Printf("File '%s' already exists, skipping\n", args.fpath)
  189         return 0, 0, nil
  190     }
  191 
  192     // Ensure any parent directories exists
  193     if err := mkdir(args.fpath); err != nil {
  194         return 0, 0, err
  195     }
  196 
  197     // Download to tmp file
  198     tmpPath := args.fpath + ".incomplete"
  199 
  200     // Create new file
  201     outFile, err := os.Create(tmpPath)
  202     if err != nil {
  203         return 0, 0, fmt.Errorf("Unable to create new file: %s", err)
  204     }
  205 
  206     started := time.Now()
  207 
  208     // Save file to disk
  209     bytes, err := io.Copy(outFile, srcReader)
  210     if err != nil {
  211         outFile.Close()
  212         os.Remove(tmpPath)
  213         return 0, 0, fmt.Errorf("Failed saving file: %s", err)
  214     }
  215 
  216     // Calculate average download rate
  217     rate := calcRate(bytes, started, time.Now())
  218 
  219     // Close File
  220     outFile.Close()
  221 
  222     // Rename tmp file to proper filename
  223     return bytes, rate, os.Rename(tmpPath, args.fpath)
  224 }
  225 
  226 func (self *Drive) downloadDirectory(parent *drive.File, args DownloadArgs) error {
  227     listArgs := listAllFilesArgs{
  228         query:  fmt.Sprintf("'%s' in parents", parent.Id),
  229         fields: []googleapi.Field{"nextPageToken", "files(id,name)"},
  230     }
  231     files, err := self.listAllFiles(listArgs)
  232     if err != nil {
  233         return fmt.Errorf("Failed listing files: %s", err)
  234     }
  235 
  236     newPath := filepath.Join(args.Path, parent.Name)
  237 
  238     for _, f := range files {
  239         // Copy args and update changed fields
  240         newArgs := args
  241         newArgs.Path = newPath
  242         newArgs.Id = f.Id
  243         newArgs.Stdout = false
  244 
  245         err = self.downloadRecursive(newArgs)
  246         if err != nil {
  247             return err
  248         }
  249     }
  250 
  251     return nil
  252 }
  253 
  254 func isDir(f *drive.File) bool {
  255     return f.MimeType == DirectoryMimeType
  256 }
  257 
  258 func isBinary(f *drive.File) bool {
  259     return f.Md5Checksum != ""
  260 }