Beispiel #1
0
// uploadFileContents does its best to upload the local file stored at
// localPath to the given *drive.File on Google Drive.  (It assumes that
// the *drive.File has already been created.)
func uploadFileContents(localPath string, driveFile *gdrive.File, encrypt bool,
	pb *pb.ProgressBar) error {
	var iv []byte
	var err error
	if encrypt {
		iv, err = getInitializationVector(driveFile)
		if err != nil {
			return fmt.Errorf("unable to get IV: %v", err)
		}
	}

	for try := 0; ; try++ {
		contentsReader, length, err :=
			getFileContentsReaderForUpload(localPath, encrypt, iv)
		if contentsReader != nil {
			defer contentsReader.Close()
		}
		if err != nil {
			return err
		}

		// Keep track of how many bytes are uploaded in case we fail
		// part-way through and need to roll back the progress bar.
		countingReader := &byteCountingReader{R: contentsReader}

		// Also tee reads to the progress bar as they are done so that it
		// stays in sync with how much data has been transmitted.
		var uploadReader io.Reader
		if pb != nil {
			uploadReader = io.TeeReader(countingReader, pb)
		} else {
			uploadReader = countingReader
		}

		if length >= resumableUploadMinSize {
			err = gd.UploadFileContentsResumable(driveFile, uploadReader, length)
		} else {
			err = gd.UploadFileContents(driveFile, uploadReader, length, try)
		}
		atomic.AddInt64(&stats.DiskReadBytes, countingReader.bytesRead)

		if err == nil {
			// Success!
			atomic.AddInt64(&stats.DriveFilesUpdated, 1)
			atomic.AddInt64(&stats.UploadBytes, length)
			return nil
		}

		// The "progress" made so far on this file should be rolled back;
		// if we don't do this, when retries happen, we end up going over
		// 100% progress...
		if pb != nil {
			pb.Add64(-countingReader.bytesRead)
		}

		if re, ok := err.(gdrive.RetryHTTPTransmitError); ok && try < 5 {
			debug.Printf("%s: got retry http error--retrying: %s",
				localPath, re.Error())
		} else {
			debug.Printf("%s: giving up due to error: %v", localPath, err)
			// We're giving up on this file, so subtract its length from
			// what the progress bar is expecting.
			if pb != nil {
				pb.Total -= length
			}
			return err
		}
	}
}