diff options
| author | Erich Roncarolo | 2014-02-15 17:24:26 +0100 | 
|---|---|---|
| committer | Erich Roncarolo | 2014-02-15 17:24:26 +0100 | 
| commit | 10cfc69a087a96833bfb2f9d8feab0875f4f9aa7 (patch) | |
| tree | 5ce8ac5ea6ac6b37c5e85a424fbe0c669f44b500 | |
| parent | d1e0a57e2b08311da8eb6866497c763aec3121db (diff) | |
| download | gdrive-10cfc69a087a96833bfb2f9d8feab0875f4f9aa7.tar.bz2 | |
Folder support added
| -rw-r--r-- | README.md | 44 | ||||
| -rw-r--r-- | cli/cli.go | 52 | ||||
| -rw-r--r-- | drive.go | 18 | ||||
| -rw-r--r-- | util/generic.go | 33 | 
4 files changed, 99 insertions, 48 deletions
| @@ -33,34 +33,40 @@ If you want to compile from source you need the go toolchain: http://golang.org/  #### Options      Global options: -        -a, --advanced Advanced Mode -- lets you specify your own oauth client id and secret on setup -        -c, --config   Set application path where config and token is stored. Defaults to ~/.gdrive -        -v, --version  Print version -        -h, --help     Show this help +            -a, --advanced Advanced Mode -- lets you specify your own oauth client id and secret on setup +            -c, --config   Set application path where config and token is stored. Defaults to ~/.gdrive +            -v, --version  Print version +            -h, --help     Show this help      Verbs:          delete: -            -i, --id File Id (*) +            -i, --id       File Id (*)          download: -            -i, --id     File Id (*) -            -s, --stdout Write file content to stdout -                --pop    Download latest file, and remove it from google drive +            -i, --id       File Id (*) +            -s, --stdout   Write file content to stdout +                --pop      Download latest file, and remove it from google drive +        folder: +            -t, --title    Folder to create (*) +            -p, --parent   Parent Id of the folder +                --share    Share created folder          info: -            -i, --id File Id (*) +            -i, --id       File Id (*)          list: -            -m, --max    Max results -            -t, --title  Title filter -            -q, --query  Query (see https://developers.google.com/drive/search-parameters) -            -s, --shared Show shared status (Note: this will generate 1 http req per file) +            -m, --max      Max results +            -t, --title    Title filter +            -q, --query    Query (see https://developers.google.com/drive/search-parameters) +            -s, --shared   Show shared status (Note: this will generate 1 http req per file) +            -n, --noheader Do not show the header          share: -            -i, --id File Id (*) +            -i, --id       File Id (*)          unshare: -            -i, --id File Id (*) +            -i, --id       File Id (*)          upload: -            -f, --file  File to upload (*) -            -s, --stdin Use stdin as file content (*) -            -t, --title Title to give uploaded file. Defaults to filename -                --share Share uploaded file +            -f, --file     File to upload (*) +            -s, --stdin    Use stdin as file content (*) +            -t, --title    Title to give uploaded file. Defaults to filename +            -p, --parent   Parent Id of the file +                --share    Share uploaded file          url:              -i, --id       File Id (*)              -p, --preview  Generate preview url (default) @@ -12,7 +12,7 @@ import (      "../gdrive"  ) -func List(d *gdrive.Drive, query, titleFilter string, maxResults int, sharedStatus bool) { +func List(d *gdrive.Drive, query, titleFilter string, maxResults int, sharedStatus bool, noHeader bool) {      caller := d.Files.List()      if maxResults > 0 { @@ -39,8 +39,13 @@ func List(d *gdrive.Drive, query, titleFilter string, maxResults int, sharedStat      for _, f := range list.Items {          // Skip files that dont have a download url (they are not stored on google drive)          if f.DownloadUrl == "" { -            continue +			if f.MimeType != "application/vnd.google-apps.folder" { +				continue +			}          } +        if f.Labels.Trashed { +			continue +		}          items = append(items, map[string]string{              "Id": f.Id, @@ -57,7 +62,7 @@ func List(d *gdrive.Drive, query, titleFilter string, maxResults int, sharedStat          columnOrder = append(columnOrder, "Shared")      } -    util.PrintColumns(items, columnOrder, 3) +    util.PrintColumns(items, columnOrder, 3, noHeader)  }  // Adds the key-value-pair 'Shared: True/False' to the map @@ -117,8 +122,30 @@ func printInfo(d *gdrive.Drive, f *drive.File) {      util.Print(fields, order)  } +// Create folder in drive +func Folder(d *gdrive.Drive, title string, parentId string, share bool) { +	// File instance +	f := &drive.File{Title: title, MimeType: "application/vnd.google-apps.folder"} +	// Set parent (if provided) +	if parentId != "" { +		p := &drive.ParentReference{Id: parentId} +		f.Parents = []*drive.ParentReference{p} +	} +	// Create folder +    info, err := d.Files.Insert(f).Do() +    if err != nil { +        fmt.Printf("An error occurred creating the folder: %v\n", err) +        os.Exit(1) +    } +    // Share folder if the share flag was provided +    if share { +        Share(d, info.Id) +    } +	fmt.Printf("Folder created in %s\n", parentId) +} +  // Upload file to drive -func Upload(d *gdrive.Drive, input io.ReadCloser, title string, share bool) { +func Upload(d *gdrive.Drive, input io.ReadCloser, title string, parentId string, share bool) {      // Use filename or 'untitled' as title if no title is specified      if title == "" {          if f, ok := input.(*os.File); ok && input != os.Stdin { @@ -129,13 +156,16 @@ func Upload(d *gdrive.Drive, input io.ReadCloser, title string, share bool) {      }      var mimeType = mime.TypeByExtension(filepath.Ext(title)) -    metadata := &drive.File{ -      Title: title,  -      MimeType: mimeType, -    } +	// File instance +	f := &drive.File{Title: title, MimeType: mimeType} +	// Set parent (if provided) +	if parentId != "" { +		p := &drive.ParentReference{Id: parentId} +		f.Parents = []*drive.ParentReference{p} +	}      getRate := util.MeasureTransferRate() -    info, err := d.Files.Insert(metadata).Media(input).Do() +    info, err := d.Files.Insert(f).Media(input).Do()      if err != nil {          fmt.Printf("An error occurred uploading the document: %v\n", err)          os.Exit(1) @@ -218,7 +248,7 @@ func Download(d *gdrive.Drive, fileId string, stdout, deleteAfterDownload bool)      }      // Create a new file -    outFile, err := os.Create(info.Title)  +    outFile, err := os.Create(info.Title)      if err != nil {          fmt.Printf("An error occurred: %v\n", err)          os.Exit(1) @@ -253,7 +283,7 @@ func Delete(d *gdrive.Drive, fileId string) {          fmt.Printf("An error occurred: %v\n", err)          os.Exit(1)      } -     +      fmt.Printf("Removed file '%s'\n", info.Title)  } @@ -26,16 +26,24 @@ type Options struct {          TitleFilter string `goptions:"-t, --title, mutexgroup='query', description='Title filter'"`          Query string `goptions:"-q, --query, mutexgroup='query', description='Query (see https://developers.google.com/drive/search-parameters)'"`          SharedStatus bool `goptions:"-s, --shared, description='Show shared status (Note: this will generate 1 http req per file)'"` +        NoHeader bool `goptions:"-n, --noheader, description='Do not show the header'"`      } `goptions:"list"`      Info struct {          FileId string `goptions:"-i, --id, obligatory, description='File Id'"`      } `goptions:"info"` +    Folder struct { +        Title string `goptions:"-t, --title, obligatory, description='Folder to create'"` +        ParentId string `goptions:"-p, --parent, description='Parent Id of the folder'"` +        Share bool `goptions:"--share, description='Share created folder'"` +    } `goptions:"folder"` +      Upload struct {          File *os.File `goptions:"-f, --file, mutexgroup='input', obligatory, rdonly, description='File to upload'"`          Stdin bool `goptions:"-s, --stdin, mutexgroup='input', obligatory, description='Use stdin as file content'"`          Title string `goptions:"-t, --title, description='Title to give uploaded file. Defaults to filename'"` +        ParentId string `goptions:"-p, --parent, description='Parent Id of the file'"`          Share bool `goptions:"--share, description='Share uploaded file'"`      } `goptions:"upload"` @@ -84,17 +92,21 @@ func main() {      switch opts.Verbs {          case "list":              args := opts.List -            cli.List(drive, args.Query, args.TitleFilter, args.MaxResults, args.SharedStatus) +            cli.List(drive, args.Query, args.TitleFilter, args.MaxResults, args.SharedStatus, args.NoHeader)          case "info":              cli.Info(drive, opts.Info.FileId) +        case "folder": +            args := opts.Folder +			cli.Folder(drive, args.Title, args.ParentId, args.Share) +          case "upload":              args := opts.Upload              if args.Stdin { -                cli.Upload(drive, os.Stdin, args.Title, args.Share) +                cli.Upload(drive, os.Stdin, args.Title, args.ParentId, args.Share)              } else { -                cli.Upload(drive, args.File, args.Title, args.Share) +                cli.Upload(drive, args.File, args.Title, args.ParentId, args.Share)              }          case "download": diff --git a/util/generic.go b/util/generic.go index fec2c31..972aabf 100644 --- a/util/generic.go +++ b/util/generic.go @@ -74,13 +74,13 @@ func TruncateString(str string, maxRunes int) string {      if runeCount <= maxRunes || maxRunes < 9 {          return str      } -     +      // Number of remaining runes to be removed      remaining := (runeCount - maxRunes) + utf8.RuneCountInString(indicator) -     +      var truncated string      var skip bool -     +      for leftOffset, char := range str {          rightOffset := runeCount - (leftOffset + remaining) @@ -96,11 +96,11 @@ func TruncateString(str string, maxRunes int) string {              remaining--              continue          } -         +          // Add char to result string          truncated += string(char)      } -     +      // Return truncated string      return truncated  } @@ -140,22 +140,25 @@ func Print(m map[string]string, keyOrder []string) {  }  // Prints items in columns with header and correct padding -func PrintColumns(items []map[string]string, keyOrder []string, columnSpacing int) { -    // Create header -    header := make(map[string]string) -    for _, key := range keyOrder { -        header[key] = key -    } +func PrintColumns(items []map[string]string, keyOrder []string, columnSpacing int, noHeader bool) { + +	if !noHeader { +		// Create header +		header := make(map[string]string) +		for _, key := range keyOrder { +			header[key] = key +		} -    // Add header as the first element of items -    items = append([]map[string]string{header}, items...) +		// Add header as the first element of items +		items = append([]map[string]string{header}, items...) +	}      // Get a padding function for each column      padFns := make(map[string]func(string)string)      for _, key := range keyOrder {          padFns[key] = columnPadder(items, key, columnSpacing)      } -     +      // Loop, pad and print items      for _, item := range items {          var line string @@ -175,7 +178,7 @@ func PrintColumns(items []map[string]string, keyOrder []string, columnSpacing in  func columnPadder(items []map[string]string, key string, spacing int) func(string)string {      // Holds length of longest string      var max int -     +      // Find the longest string of type key in the array      for _, item := range items {          str := item[key] | 
