aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drive/download.go55
-rw-r--r--drive/drive.go23
-rw-r--r--drive/files.go139
-rw-r--r--drive/info.go49
-rw-r--r--drive/list.go55
-rw-r--r--drive/mkdir.go32
-rw-r--r--drive/print.go139
-rw-r--r--drive/share.go (renamed from drive/permissions.go)8
-rw-r--r--drive/types.go90
-rw-r--r--drive/upload.go62
-rw-r--r--drive/util.go100
11 files changed, 383 insertions, 369 deletions
diff --git a/drive/download.go b/drive/download.go
new file mode 100644
index 0000000..9a35912
--- /dev/null
+++ b/drive/download.go
@@ -0,0 +1,55 @@
+package drive
+
+import (
+ "fmt"
+ "io"
+ "os"
+)
+
+type DownloadFileArgs struct {
+ Id string
+ Force bool
+ NoProgress bool
+ Stdout bool
+}
+
+func (self *Drive) Download(args DownloadFileArgs) {
+ getFile := self.service.Files.Get(args.Id)
+
+ f, err := getFile.Do()
+ errorF(err, "Failed to get file: %s", err)
+
+ res, err := getFile.Download()
+ errorF(err, "Failed to download file: %s", err)
+
+ // Close body on function exit
+ defer res.Body.Close()
+
+ if args.Stdout {
+ // Write file content to stdout
+ io.Copy(os.Stdout, res.Body)
+ return
+ }
+
+ // Check if file exists
+ if !args.Force && fileExists(f.Name) {
+ exitF("File '%s' already exists, use --force to overwrite", f.Name)
+ }
+
+ // Create new file
+ outFile, err := os.Create(f.Name)
+ errorF(err, "Unable to create new file: %s", err)
+
+ // Close file on function exit
+ defer outFile.Close()
+
+ // Save file to disk
+ bytes, err := io.Copy(outFile, res.Body)
+ errorF(err, "Failed saving file: %s", err)
+
+ fmt.Printf("Downloaded '%s' at %s, total %d\n", f.Name, "x/s", bytes)
+
+ //if deleteSourceFile {
+ // self.Delete(args.Id)
+ //}
+}
diff --git a/drive/drive.go b/drive/drive.go
new file mode 100644
index 0000000..047030a
--- /dev/null
+++ b/drive/drive.go
@@ -0,0 +1,23 @@
+package drive
+
+import (
+ "net/http"
+ "google.golang.org/api/drive/v3"
+)
+
+type Client interface {
+ Service() *drive.Service
+ Http() *http.Client
+}
+
+type Drive struct {
+ service *drive.Service
+ http *http.Client
+}
+
+func NewDrive(client Client) *Drive {
+ return &Drive{
+ service: client.Service(),
+ http: client.Http(),
+ }
+}
diff --git a/drive/files.go b/drive/files.go
deleted file mode 100644
index b6eed04..0000000
--- a/drive/files.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package drive
-
-import (
- "fmt"
- "io"
- "mime"
- "os"
- "path/filepath"
- "google.golang.org/api/drive/v3"
- "golang.org/x/net/context"
-)
-
-const DirectoryMimeType = "application/vnd.google-apps.folder"
-
-
-func (self *Drive) List(args ListFilesArgs) {
- fileList, err := self.service.Files.List().PageSize(args.MaxFiles).Q(args.Query).Fields("nextPageToken", "files(id,name,size,createdTime)").Do()
- errorF(err, "Failed listing files: %s\n", err)
-
- PrintFileList(PrintFileListArgs{
- Files: fileList.Files,
- NameWidth: int(args.NameWidth),
- SkipHeader: args.SkipHeader,
- SizeInBytes: args.SizeInBytes,
- })
-}
-
-
-func (self *Drive) Download(args DownloadFileArgs) {
- getFile := self.service.Files.Get(args.Id)
-
- f, err := getFile.Do()
- errorF(err, "Failed to get file: %s", err)
-
- res, err := getFile.Download()
- errorF(err, "Failed to download file: %s", err)
-
- // Close body on function exit
- defer res.Body.Close()
-
- if args.Stdout {
- // Write file content to stdout
- io.Copy(os.Stdout, res.Body)
- return
- }
-
- // Check if file exists
- if !args.Force && fileExists(f.Name) {
- exitF("File '%s' already exists, use --force to overwrite", f.Name)
- }
-
- // Create new file
- outFile, err := os.Create(f.Name)
- errorF(err, "Unable to create new file: %s", err)
-
- // Close file on function exit
- defer outFile.Close()
-
- // Save file to disk
- bytes, err := io.Copy(outFile, res.Body)
- errorF(err, "Failed saving file: %s", err)
-
- fmt.Printf("Downloaded '%s' at %s, total %d\n", f.Name, "x/s", bytes)
-
- //if deleteSourceFile {
- // self.Delete(args.Id)
- //}
-}
-
-func (self *Drive) Upload(args UploadFileArgs) {
- //if args.Stdin {
- // self.uploadStdin()
- //}
-
- srcFile, err := os.Open(args.Path)
- errorF(err, "Failed to open file: %s", err)
-
- srcFileInfo, err := srcFile.Stat()
- errorF(err, "Failed to read file metadata: %s", err)
-
- // Instantiate empty drive file
- dstFile := &drive.File{}
-
- // Use provided file name or use filename
- if args.Name == "" {
- dstFile.Name = filepath.Base(srcFileInfo.Name())
- } else {
- dstFile.Name = args.Name
- }
-
- // Set provided mime type or get type based on file extension
- if args.Mime == "" {
- dstFile.MimeType = mime.TypeByExtension(filepath.Ext(dstFile.Name))
- } else {
- dstFile.MimeType = args.Mime
- }
-
- // Set parent folder if provided
- if args.Parent != "" {
- dstFile.Parents = []string{args.Parent}
- }
-
- f, err := self.service.Files.Create(dstFile).ResumableMedia(context.Background(), srcFile, srcFileInfo.Size(), dstFile.MimeType).Do()
- errorF(err, "Failed to upload file: %s", err)
-
- fmt.Printf("Uploaded '%s' at %s, total %d\n", f.Name, "x/s", f.Size)
- //if args.Share {
- // self.Share(TODO)
- //}
-}
-
-func (self *Drive) Info(args FileInfoArgs) {
- f, err := self.service.Files.Get(args.Id).Fields("id", "name", "size", "createdTime", "modifiedTime", "md5Checksum", "mimeType", "parents", "shared", "description").Do()
- errorF(err, "Failed to get file: %s", err)
-
- PrintFileInfo(PrintFileInfoArgs{
- File: f,
- SizeInBytes: args.SizeInBytes,
- })
-}
-
-func (self *Drive) Mkdir(args MkdirArgs) {
- dstFile := &drive.File{Name: args.Name, MimeType: DirectoryMimeType}
-
- // Set parent folder if provided
- if args.Parent != "" {
- dstFile.Parents = []string{args.Parent}
- }
-
- // Create folder
- f, err := self.service.Files.Create(dstFile).Do()
- errorF(err, "Failed to create folder: %s", err)
-
- PrintFileInfo(PrintFileInfoArgs{File: f})
-
- //if args.Share {
- // self.Share(TODO)
- //}
-}
diff --git a/drive/info.go b/drive/info.go
new file mode 100644
index 0000000..f5f5602
--- /dev/null
+++ b/drive/info.go
@@ -0,0 +1,49 @@
+package drive
+
+import (
+ "fmt"
+ "google.golang.org/api/drive/v3"
+)
+
+type FileInfoArgs struct {
+ Id string
+ SizeInBytes bool
+}
+
+func (self *Drive) Info(args FileInfoArgs) {
+ f, err := self.service.Files.Get(args.Id).Fields("id", "name", "size", "createdTime", "modifiedTime", "md5Checksum", "mimeType", "parents", "shared", "description").Do()
+ errorF(err, "Failed to get file: %s", err)
+
+ PrintFileInfo(PrintFileInfoArgs{
+ File: f,
+ SizeInBytes: args.SizeInBytes,
+ })
+}
+
+type PrintFileInfoArgs struct {
+ File *drive.File
+ SizeInBytes bool
+}
+
+func PrintFileInfo(args PrintFileInfoArgs) {
+ f := args.File
+
+ items := []kv{
+ kv{"Id", f.Id},
+ kv{"Name", f.Name},
+ kv{"Description", f.Description},
+ kv{"Mime", f.MimeType},
+ kv{"Size", formatSize(f.Size, args.SizeInBytes)},
+ kv{"Created", formatDatetime(f.CreatedTime)},
+ kv{"Modified", formatDatetime(f.ModifiedTime)},
+ kv{"Md5sum", f.Md5Checksum},
+ kv{"Shared", formatBool(f.Shared)},
+ kv{"Parents", formatList(f.Parents)},
+ }
+
+ for _, item := range items {
+ if item.value() != "" {
+ fmt.Printf("%s: %s\n", item.key(), item.value())
+ }
+ }
+}
diff --git a/drive/list.go b/drive/list.go
new file mode 100644
index 0000000..c542785
--- /dev/null
+++ b/drive/list.go
@@ -0,0 +1,55 @@
+package drive
+
+import (
+ "fmt"
+ "os"
+ "text/tabwriter"
+ "google.golang.org/api/drive/v3"
+)
+
+type ListFilesArgs struct {
+ MaxFiles int64
+ NameWidth int64
+ Query string
+ SkipHeader bool
+ SizeInBytes bool
+}
+
+func (self *Drive) List(args ListFilesArgs) {
+ fileList, err := self.service.Files.List().PageSize(args.MaxFiles).Q(args.Query).Fields("nextPageToken", "files(id,name,size,createdTime)").Do()
+ errorF(err, "Failed listing files: %s\n", err)
+
+ PrintFileList(PrintFileListArgs{
+ Files: fileList.Files,
+ NameWidth: int(args.NameWidth),
+ SkipHeader: args.SkipHeader,
+ SizeInBytes: args.SizeInBytes,
+ })
+}
+
+type PrintFileListArgs struct {
+ Files []*drive.File
+ NameWidth int
+ SkipHeader bool
+ SizeInBytes bool
+}
+
+func PrintFileList(args PrintFileListArgs) {
+ w := new(tabwriter.Writer)
+ w.Init(os.Stdout, 0, 0, 3, ' ', 0)
+
+ if !args.SkipHeader {
+ fmt.Fprintln(w, "Id\tName\tSize\tCreated")
+ }
+
+ for _, f := range args.Files {
+ fmt.Fprintf(w, "%s\t%s\t%s\t%s\n",
+ f.Id,
+ truncateString(f.Name, args.NameWidth),
+ formatSize(f.Size, args.SizeInBytes),
+ formatDatetime(f.CreatedTime),
+ )
+ }
+
+ w.Flush()
+}
diff --git a/drive/mkdir.go b/drive/mkdir.go
new file mode 100644
index 0000000..8295649
--- /dev/null
+++ b/drive/mkdir.go
@@ -0,0 +1,32 @@
+package drive
+
+import (
+ "google.golang.org/api/drive/v3"
+)
+
+const DirectoryMimeType = "application/vnd.google-apps.folder"
+
+type MkdirArgs struct {
+ Name string
+ Parent string
+ Share bool
+}
+
+func (self *Drive) Mkdir(args MkdirArgs) {
+ dstFile := &drive.File{Name: args.Name, MimeType: DirectoryMimeType}
+
+ // Set parent folder if provided
+ if args.Parent != "" {
+ dstFile.Parents = []string{args.Parent}
+ }
+
+ // Create folder
+ f, err := self.service.Files.Create(dstFile).Do()
+ errorF(err, "Failed to create folder: %s", err)
+
+ PrintFileInfo(PrintFileInfoArgs{File: f})
+
+ //if args.Share {
+ // self.Share(TODO)
+ //}
+}
diff --git a/drive/print.go b/drive/print.go
deleted file mode 100644
index 84d4ec7..0000000
--- a/drive/print.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package drive
-
-import (
- "os"
- "fmt"
- "text/tabwriter"
- "strings"
- "strconv"
- "unicode/utf8"
- "time"
-)
-
-
-func PrintFileList(args PrintFileListArgs) {
- w := new(tabwriter.Writer)
- w.Init(os.Stdout, 0, 0, 3, ' ', 0)
-
- if !args.SkipHeader {
- fmt.Fprintln(w, "Id\tName\tSize\tCreated")
- }
-
- for _, f := range args.Files {
- fmt.Fprintf(w, "%s\t%s\t%s\t%s\n",
- f.Id,
- truncateString(f.Name, args.NameWidth),
- formatSize(f.Size, args.SizeInBytes),
- formatDatetime(f.CreatedTime),
- )
- }
-
- w.Flush()
-}
-
-func PrintFileInfo(args PrintFileInfoArgs) {
- f := args.File
-
- items := []kv{
- kv{"Id", f.Id},
- kv{"Name", f.Name},
- kv{"Description", f.Description},
- kv{"Mime", f.MimeType},
- kv{"Size", formatSize(f.Size, args.SizeInBytes)},
- kv{"Created", formatDatetime(f.CreatedTime)},
- kv{"Modified", formatDatetime(f.ModifiedTime)},
- kv{"Md5sum", f.Md5Checksum},
- kv{"Shared", formatBool(f.Shared)},
- kv{"Parents", formatList(f.Parents)},
- }
-
- for _, item := range items {
- if item.value() != "" {
- fmt.Printf("%s: %s\n", item.key(), item.value())
- }
- }
-}
-
-func formatList(a []string) string {
- return strings.Join(a, ", ")
-}
-
-func formatSize(bytes int64, forceBytes bool) string {
- if bytes == 0 {
- return ""
- }
-
- if forceBytes {
- return fmt.Sprintf("%v B", bytes)
- }
-
- units := []string{"B", "KB", "MB", "GB", "TB", "PB"}
-
- var i int
- value := float64(bytes)
-
- for value > 1000 {
- value /= 1000
- i++
- }
- return fmt.Sprintf("%.1f %s", value, units[i])
-}
-
-func formatBool(b bool) string {
- return strings.Title(strconv.FormatBool(b))
-}
-
-func formatDatetime(iso string) string {
- t, err := time.Parse(time.RFC3339, iso)
- if err != nil {
- return iso
- }
- local := t.Local()
- year, month, day := local.Date()
- hour, min, sec := local.Clock()
- return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, min, sec)
-}
-
-// Truncates string to given max length, and inserts ellipsis into
-// the middle of the string to signify that the string has been truncated
-func truncateString(str string, maxRunes int) string {
- indicator := "..."
-
- // Number of runes in string
- runeCount := utf8.RuneCountInString(str)
-
- // Return input string if length of input string is less than max length
- // Input string is also returned if max length is less than 9 which is the minmal supported length
- 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)
-
- // Start skipping chars when the left and right offsets are equal
- // Or in the case where we wont be able to do an even split: when the left offset is larger than the right offset
- if leftOffset == rightOffset || (leftOffset > rightOffset && !skip) {
- skip = true
- truncated += indicator
- }
-
- if skip && remaining > 0 {
- // Skip char and decrement the remaining skip counter
- remaining--
- continue
- }
-
- // Add char to result string
- truncated += string(char)
- }
-
- // Return truncated string
- return truncated
-}
diff --git a/drive/permissions.go b/drive/share.go
index 1e2c004..7e7036d 100644
--- a/drive/permissions.go
+++ b/drive/share.go
@@ -5,6 +5,14 @@ import (
"google.golang.org/api/drive/v3"
)
+type ShareArgs struct {
+ FileId string
+ Role string
+ Type string
+ Email string
+ Discoverable bool
+ Revoke bool
+}
func (self *Drive) Share(args ShareArgs) {
if args.Revoke {
diff --git a/drive/types.go b/drive/types.go
deleted file mode 100644
index f252dde..0000000
--- a/drive/types.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package drive
-
-import (
- "net/http"
- "google.golang.org/api/drive/v3"
-)
-
-type Client interface {
- Service() *drive.Service
- Http() *http.Client
-}
-
-type Drive struct {
- service *drive.Service
- http *http.Client
-}
-
-func NewDrive(client Client) *Drive {
- return &Drive{
- service: client.Service(),
- http: client.Http(),
- }
-}
-
-type ListFilesArgs struct {
- MaxFiles int64
- NameWidth int64
- Query string
- SkipHeader bool
- SizeInBytes bool
-}
-
-type DownloadFileArgs struct {
- Id string
- Force bool
- NoProgress bool
- Stdout bool
-}
-
-type UploadFileArgs struct {
- Path string
- Name string
- Parent string
- Mime string
- Recursive bool
- Stdin bool
- Share bool
-}
-
-type FileInfoArgs struct {
- Id string
- SizeInBytes bool
-}
-
-type MkdirArgs struct {
- Name string
- Parent string
- Share bool
-}
-
-type ShareArgs struct {
- FileId string
- Role string
- Type string
- Email string
- Discoverable bool
- Revoke bool
-}
-
-type PrintFileListArgs struct {
- Files []*drive.File
- NameWidth int
- SkipHeader bool
- SizeInBytes bool
-}
-
-type PrintFileInfoArgs struct {
- File *drive.File
- SizeInBytes bool
-}
-
-type kv [2]string
-
-func (self kv) key() string {
- return self[0]
-}
-
-func (self kv) value() string {
- return self[1]
-}
diff --git a/drive/upload.go b/drive/upload.go
new file mode 100644
index 0000000..ed373ef
--- /dev/null
+++ b/drive/upload.go
@@ -0,0 +1,62 @@
+package drive
+
+import (
+ "fmt"
+ "mime"
+ "os"
+ "path/filepath"
+ "google.golang.org/api/drive/v3"
+ "golang.org/x/net/context"
+)
+
+type UploadFileArgs struct {
+ Path string
+ Name string
+ Parent string
+ Mime string
+ Recursive bool
+ Stdin bool
+ Share bool
+}
+
+func (self *Drive) Upload(args UploadFileArgs) {
+ //if args.Stdin {
+ // self.uploadStdin()
+ //}
+
+ srcFile, err := os.Open(args.Path)
+ errorF(err, "Failed to open file: %s", err)
+
+ srcFileInfo, err := srcFile.Stat()
+ errorF(err, "Failed to read file metadata: %s", err)
+
+ // Instantiate empty drive file
+ dstFile := &drive.File{}
+
+ // Use provided file name or use filename
+ if args.Name == "" {
+ dstFile.Name = filepath.Base(srcFileInfo.Name())
+ } else {
+ dstFile.Name = args.Name
+ }
+
+ // Set provided mime type or get type based on file extension
+ if args.Mime == "" {
+ dstFile.MimeType = mime.TypeByExtension(filepath.Ext(dstFile.Name))
+ } else {
+ dstFile.MimeType = args.Mime
+ }
+
+ // Set parent folder if provided
+ if args.Parent != "" {
+ dstFile.Parents = []string{args.Parent}
+ }
+
+ f, err := self.service.Files.Create(dstFile).ResumableMedia(context.Background(), srcFile, srcFileInfo.Size(), dstFile.MimeType).Do()
+ errorF(err, "Failed to upload file: %s", err)
+
+ fmt.Printf("Uploaded '%s' at %s, total %d\n", f.Name, "x/s", f.Size)
+ //if args.Share {
+ // self.Share(TODO)
+ //}
+}
diff --git a/drive/util.go b/drive/util.go
index 8dda213..bc2d5c3 100644
--- a/drive/util.go
+++ b/drive/util.go
@@ -1,10 +1,108 @@
package drive
import (
- "fmt"
"os"
+ "fmt"
+ "strings"
+ "strconv"
+ "unicode/utf8"
+ "time"
)
+type kv [2]string
+
+func (self kv) key() string {
+ return self[0]
+}
+
+func (self kv) value() string {
+ return self[1]
+}
+
+func formatList(a []string) string {
+ return strings.Join(a, ", ")
+}
+
+func formatSize(bytes int64, forceBytes bool) string {
+ if bytes == 0 {
+ return ""
+ }
+
+ if forceBytes {
+ return fmt.Sprintf("%v B", bytes)
+ }
+
+ units := []string{"B", "KB", "MB", "GB", "TB", "PB"}
+
+ var i int
+ value := float64(bytes)
+
+ for value > 1000 {
+ value /= 1000
+ i++
+ }
+ return fmt.Sprintf("%.1f %s", value, units[i])
+}
+
+func formatBool(b bool) string {
+ return strings.Title(strconv.FormatBool(b))
+}
+
+func formatDatetime(iso string) string {
+ t, err := time.Parse(time.RFC3339, iso)
+ if err != nil {
+ return iso
+ }
+ local := t.Local()
+ year, month, day := local.Date()
+ hour, min, sec := local.Clock()
+ return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, min, sec)
+}
+
+// Truncates string to given max length, and inserts ellipsis into
+// the middle of the string to signify that the string has been truncated
+func truncateString(str string, maxRunes int) string {
+ indicator := "..."
+
+ // Number of runes in string
+ runeCount := utf8.RuneCountInString(str)
+
+ // Return input string if length of input string is less than max length
+ // Input string is also returned if max length is less than 9 which is the minmal supported length
+ 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)
+
+ // Start skipping chars when the left and right offsets are equal
+ // Or in the case where we wont be able to do an even split: when the left offset is larger than the right offset
+ if leftOffset == rightOffset || (leftOffset > rightOffset && !skip) {
+ skip = true
+ truncated += indicator
+ }
+
+ if skip && remaining > 0 {
+ // Skip char and decrement the remaining skip counter
+ remaining--
+ continue
+ }
+
+ // Add char to result string
+ truncated += string(char)
+ }
+
+ // Return truncated string
+ return truncated
+}
+
func errorF(err error, format string, a ...interface{}) {
if err == nil {
return