diff options
| author | Petter Rasmussen | 2016-01-17 13:41:40 +0100 |
|---|---|---|
| committer | Petter Rasmussen | 2016-01-17 13:41:40 +0100 |
| commit | f16b89b6f6bee6023c51b4f8120a3e4776128384 (patch) | |
| tree | d551bdeffdf6bf57b575a0cbf00aa40555a80d47 | |
| parent | 0f9535df1b2a64e8f895671025bf7823e9391135 (diff) | |
| download | gdrive-f16b89b6f6bee6023c51b4f8120a3e4776128384.tar.bz2 | |
Delete stale files
| -rw-r--r-- | auth/auth.go | 73 | ||||
| -rw-r--r-- | config/config.go | 74 | ||||
| -rw-r--r-- | drive.go | 170 | ||||
| -rw-r--r-- | gdrive/gdrive.go | 53 | ||||
| -rw-r--r-- | gdrive/handlers.go | 0 | ||||
| -rw-r--r-- | util/drive.go | 88 | ||||
| -rw-r--r-- | util/generic.go | 213 |
7 files changed, 0 insertions, 671 deletions
diff --git a/auth/auth.go b/auth/auth.go deleted file mode 100644 index 6bb14d6..0000000 --- a/auth/auth.go +++ /dev/null @@ -1,73 +0,0 @@ -package auth - -import ( - "code.google.com/p/goauth2/oauth" - "errors" - "fmt" - "github.com/prasmussen/gdrive/util" - "net/http" -) - -// Get auth code from user -func promptUserForAuthCode(config *oauth.Config) string { - authUrl := config.AuthCodeURL("state") - fmt.Println("Go to the following link in your browser:") - fmt.Printf("%v\n\n", authUrl) - return util.Prompt("Enter verification code: ") -} - -// Returns true if we have a valid cached token -func hasValidToken(cacheFile oauth.CacheFile, transport *oauth.Transport) bool { - // Check if we have a cached token - token, err := cacheFile.Token() - if err != nil { - return false - } - - // Refresh token if its expired - if token.Expired() { - transport.Token = token - err = transport.Refresh() - if err != nil { - fmt.Println(err) - return false - } - } - return true -} - -func GetOauth2Client(clientId, clientSecret, cachePath string, promptUser bool) (*http.Client, error) { - cacheFile := oauth.CacheFile(cachePath) - - config := &oauth.Config{ - ClientId: clientId, - ClientSecret: clientSecret, - Scope: "https://www.googleapis.com/auth/drive", - RedirectURL: "urn:ietf:wg:oauth:2.0:oob", - AuthURL: "https://accounts.google.com/o/oauth2/auth", - TokenURL: "https://accounts.google.com/o/oauth2/token", - TokenCache: cacheFile, - } - - transport := &oauth.Transport{ - Config: config, - Transport: http.DefaultTransport, - } - - // Return client if we have a valid token - if hasValidToken(cacheFile, transport) { - return transport.Client(), nil - } - - if !promptUser { - return nil, errors.New("no valid token found") - } - - // Get auth code from user and request a new token - code := promptUserForAuthCode(config) - _, err := transport.Exchange(code) - if err != nil { - return nil, err - } - return transport.Client(), nil -} diff --git a/config/config.go b/config/config.go deleted file mode 100644 index 76d2285..0000000 --- a/config/config.go +++ /dev/null @@ -1,74 +0,0 @@ -package config - -import ( - "encoding/json" - "fmt" - "github.com/prasmussen/gdrive/util" - "io/ioutil" -) - -// Client ID and secrect for installed applications -const ( - ClientId = "367116221053-7n0vf5akeru7on6o2fjinrecpdoe99eg.apps.googleusercontent.com" - ClientSecret = "1qsNodXNaWq1mQuBjUjmvhoO" -) - -type Config struct { - ClientId string - ClientSecret string -} - -func defaultConfig() *Config { - return &Config{ - ClientId: ClientId, - ClientSecret: ClientSecret, - } -} - -func promptUser() *Config { - return &Config{ - ClientId: util.Prompt("Enter Client Id: "), - ClientSecret: util.Prompt("Enter Client Secret: "), - } -} - -func load(fname string) (*Config, error) { - data, err := ioutil.ReadFile(fname) - if err != nil { - return nil, err - } - config := &Config{} - return config, json.Unmarshal(data, config) -} - -func save(fname string, config *Config) error { - data, err := json.MarshalIndent(config, "", " ") - if err != nil { - return err - } - - if err = util.Mkdir(fname); err != nil { - return err - } - return ioutil.WriteFile(fname, data, 0600) -} - -func Load(fname string, advancedUser bool) *Config { - config, err := load(fname) - if err != nil { - // Unable to read existing config, lets start from scracth - // Get config from user input for advanced users, or just use default settings - if advancedUser { - config = promptUser() - } else { - config = defaultConfig() - } - - // Save config to file - err := save(fname, config) - if err != nil { - fmt.Printf("Failed to save config (%s)\n", err) - } - } - return config -} diff --git a/drive.go b/drive.go deleted file mode 100644 index 2466087..0000000 --- a/drive.go +++ /dev/null @@ -1,170 +0,0 @@ -package foo - -import ( - "fmt" - "github.com/prasmussen/gdrive/cli" - "github.com/prasmussen/gdrive/gdrive" - "github.com/prasmussen/gdrive/util" - "github.com/prasmussen/google-api-go-client/googleapi" - "github.com/voxelbrain/goptions" - "os" -) - -const ( - VersionNumber = "1.9.0" -) - -type Options struct { - Advanced bool `goptions:"-a, --advanced, description='Advanced Mode -- lets you specify your own oauth client id and secret on setup'"` - AppPath string `goptions:"-c, --config, description='Set application path where config and token is stored. Defaults to ~/.gdrive'"` - Version bool `goptions:"-v, --version, description='Print version'"` - goptions.Help `goptions:"-h, --help, description='Show this help'"` - - goptions.Verbs - - List struct { - MaxResults int `goptions:"-m, --max, description='Max results'"` - IncludeDocs bool `goptions:"--include-docs, description='Include google docs in listing'"` - 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'"` - SizeInBytes bool `goptions:"--bytes, description='Show size in bytes'"` - } `goptions:"list"` - - Info struct { - FileId string `goptions:"-i, --id, obligatory, description='File Id'"` - SizeInBytes bool `goptions:"--bytes, description='Show size in bytes'"` - } `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 or directory 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'"` - MimeType string `goptions:"--mimetype, description='The MIME type (default will try to figure it out)'"` - Convert bool `goptions:"--convert, description='File will be converted to Google Docs format'"` - ChunkSize int64 `goptions:"-C, --chunksize, description='Set chunk size in bytes. Minimum is 262144, default is 4194304. Recommended to be a power of two.'"` - } `goptions:"upload"` - - Download struct { - FileId string `goptions:"-i, --id, mutexgroup='download', obligatory, description='File Id'"` - Format string `goptions:"--format, description='Download file in a specified format (needed for google docs)'"` - Stdout bool `goptions:"-s, --stdout, description='Write file content to stdout'"` - Force bool `goptions:"--force, description='Overwrite existing file'"` - Pop bool `goptions:"--pop, mutexgroup='download', description='Download latest file, and remove it from google drive'"` - } `goptions:"download"` - - Delete struct { - FileId string `goptions:"-i, --id, obligatory, description='File Id'"` - } `goptions:"delete"` - - Share struct { - FileId string `goptions:"-i, --id, obligatory, description='File Id'"` - } `goptions:"share"` - - Unshare struct { - FileId string `goptions:"-i, --id, obligatory, description='File Id'"` - } `goptions:"unshare"` - - Url struct { - FileId string `goptions:"-i, --id, obligatory, description='File Id'"` - Preview bool `goptions:"-p, --preview, mutexgroup='urltype', description='Generate preview url (default)'"` - Download bool `goptions:"-d, --download, mutexgroup='urltype', description='Generate download url'"` - } `goptions:"url"` - - Quota struct { - SizeInBytes bool `goptions:"--bytes, description='Show size in bytes'"` - } `goptions:"quota"` -} - -func main() { - opts := &Options{} - goptions.ParseAndFail(opts) - - // Print version number and exit if the version flag is set - if opts.Version { - fmt.Printf("gdrive v%s\n", VersionNumber) - return - } - - // Get authorized drive client - drive, err := gdrive.New(opts.AppPath, opts.Advanced, true) - if err != nil { - writeError("An error occurred creating Drive client: %v\n", err) - } - - switch opts.Verbs { - case "list": - args := opts.List - err = cli.List(drive, args.Query, args.TitleFilter, args.MaxResults, args.SharedStatus, args.NoHeader, args.IncludeDocs, args.SizeInBytes) - - case "info": - err = cli.Info(drive, opts.Info.FileId, opts.Info.SizeInBytes) - - case "folder": - args := opts.Folder - err = cli.Folder(drive, args.Title, args.ParentId, args.Share) - - case "upload": - args := opts.Upload - - // Set custom chunksize if given - if args.ChunkSize >= (1 << 18) { - googleapi.SetChunkSize(args.ChunkSize) - } - - if args.Stdin { - err = cli.UploadStdin(drive, os.Stdin, args.Title, args.ParentId, args.Share, args.MimeType, args.Convert) - } else { - err = cli.Upload(drive, args.File, args.Title, args.ParentId, args.Share, args.MimeType, args.Convert) - } - - case "download": - args := opts.Download - if args.Pop { - err = cli.DownloadLatest(drive, args.Stdout, args.Format, args.Force) - } else { - err = cli.Download(drive, args.FileId, args.Stdout, false, args.Format, args.Force) - } - - case "delete": - err = cli.Delete(drive, opts.Delete.FileId) - - case "share": - err = cli.Share(drive, opts.Share.FileId) - - case "unshare": - err = cli.Unshare(drive, opts.Unshare.FileId) - - case "url": - if opts.Url.Download { - fmt.Println(util.DownloadUrl(opts.Url.FileId)) - } else { - fmt.Println(util.PreviewUrl(opts.Url.FileId)) - } - - case "quota": - err = cli.Quota(drive, opts.Quota.SizeInBytes) - - default: - goptions.PrintHelp() - } - - if err != nil { - writeError("%s", err) - } -} - -func writeError(format string, err error) { - fmt.Fprintf(os.Stderr, format, err) - fmt.Print("\n") - os.Exit(1) -} diff --git a/gdrive/gdrive.go b/gdrive/gdrive.go deleted file mode 100644 index 1f8f4c7..0000000 --- a/gdrive/gdrive.go +++ /dev/null @@ -1,53 +0,0 @@ -package gdrive - -import ( - "github.com/prasmussen/google-api-go-client/drive/v2" - "github.com/prasmussen/gdrive/auth" - "github.com/prasmussen/gdrive/config" - "github.com/prasmussen/gdrive/util" - "net/http" - "path/filepath" -) - -// File paths and names -var ( - AppPath = filepath.Join(util.Homedir(), ".gdrive") - ConfigFname = "config.json" - TokenFname = "token.json" - //ConfigPath = filepath.Join(ConfigDir, "config.json") - //TokenPath = filepath.Join(ConfigDir, "token.json") -) - -type Drive struct { - *drive.Service - client *http.Client -} - -// Returns the raw http client which has the oauth transport -func (self *Drive) Client() *http.Client { - return self.client -} - -func New(customAppPath string, advancedMode bool, promptUser bool) (*Drive, error) { - if customAppPath != "" { - AppPath = customAppPath - } - - // Build paths to config files - configPath := filepath.Join(AppPath, ConfigFname) - tokenPath := filepath.Join(AppPath, TokenFname) - - config := config.Load(configPath, advancedMode) - client, err := auth.GetOauth2Client(config.ClientId, config.ClientSecret, tokenPath, promptUser) - if err != nil { - return nil, err - } - - drive, err := drive.New(client) - if err != nil { - return nil, err - } - - // Return a new authorized Drive client. - return &Drive{drive, client}, nil -} diff --git a/gdrive/handlers.go b/gdrive/handlers.go deleted file mode 100644 index e69de29..0000000 --- a/gdrive/handlers.go +++ /dev/null diff --git a/util/drive.go b/util/drive.go deleted file mode 100644 index a8e7777..0000000 --- a/util/drive.go +++ /dev/null @@ -1,88 +0,0 @@ -package util - -import ( - "fmt" - "github.com/prasmussen/google-api-go-client/drive/v2" - "strings" -) - -func PreviewUrl(id string) string { - //return fmt.Sprintf("https://drive.google.com/uc?id=%s&export=preview", id) - return fmt.Sprintf("https://drive.google.com/uc?id=%s", id) -} - -// Note to self: file.WebContentLink = https://docs.google.com/uc?id=<id>&export=download -func DownloadUrl(id string) string { - return fmt.Sprintf("https://drive.google.com/uc?id=%s&export=download", id) -} - -func ParentList(parents []*drive.ParentReference) string { - ids := make([]string, 0) - for _, parent := range parents { - ids = append(ids, parent.Id) - } - - return strings.Join(ids, ", ") -} - -func InternalDownloadUrlAndExtension(info *drive.File, format string) (downloadUrl string, extension string, err error) { - // Make a list of available mime types for this file - availableMimeTypes := make([]string, 0) - for mime, _ := range info.ExportLinks { - availableMimeTypes = append(availableMimeTypes, mime) - } - - mimeExtensions := map[string]string{ - "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx", - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx", - "application/application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx", - "application/vnd.oasis.opendocument.text": "odf", - "application/x-vnd.oasis.opendocument.spreadsheet": "ods", - "application/pdf": "pdf", - "application/rtf": "rtf", - "text/csv": "csv", - "text/html": "html", - "text/plain": "txt", - "application/vnd.google-apps.script+json": "json", - } - - // Make a list of available formats for this file - availableFormats := make([]string, 0) - for _, mime := range availableMimeTypes { - if ext, ok := mimeExtensions[mime]; ok { - availableFormats = append(availableFormats, ext) - } - } - - // Return DownloadUrl if no format is specified - if format == "" { - if info.DownloadUrl == "" { - if len(availableFormats) > 0 { - return "", "", fmt.Errorf("A format needs to be specified to download this file (--format). Available formats: %s", strings.Join(availableFormats, ", ")) - } else { - return "", "", fmt.Errorf("Download is not supported for this filetype") - } - } - return info.DownloadUrl, "", nil - } - - // Ensure that the specified format is available - if !inArray(format, availableFormats) { - if len(availableFormats) > 0 { - return "", "", fmt.Errorf("Invalid format. Available formats: %s", strings.Join(availableFormats, ", ")) - } else { - return "", "", fmt.Errorf("No export formats are available for this file") - } - } - - // Grab download url - for mime, f := range mimeExtensions { - if f == format { - downloadUrl = info.ExportLinks[mime] - break - } - } - - extension = "." + format - return -} diff --git a/util/generic.go b/util/generic.go deleted file mode 100644 index ded985d..0000000 --- a/util/generic.go +++ /dev/null @@ -1,213 +0,0 @@ -package util - -import ( - "fmt" - "os" - "path/filepath" - "runtime" - "strconv" - "strings" - "time" - "unicode/utf8" -) - -// Prompt user to input data -func Prompt(msg string) string { - fmt.Printf(msg) - var str string - fmt.Scanln(&str) - return str -} - -// Returns true if file/directory exists -func FileExists(path string) bool { - _, err := os.Stat(path) - if err == nil { - return true - } - return false -} - -func Mkdir(path string) error { - dir := filepath.Dir(path) - if FileExists(dir) { - return nil - } - return os.Mkdir(dir, 0700) -} - -// Returns the users home dir -func Homedir() string { - if runtime.GOOS == "windows" { - return os.Getenv("APPDATA") - } - return os.Getenv("HOME") -} - -func FormatBool(b bool) string { - return strings.Title(strconv.FormatBool(b)) -} - -func FileSizeFormat(bytes int64, forceBytes bool) string { - 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]) -} - -// 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 ISODateToLocal(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) -} - -func MeasureTransferRate() func(int64) string { - start := time.Now() - - return func(bytes int64) string { - seconds := int64(time.Now().Sub(start).Seconds()) - if seconds < 1 { - return fmt.Sprintf("%s/s", FileSizeFormat(bytes, false)) - } - bps := bytes / seconds - return fmt.Sprintf("%s/s", FileSizeFormat(bps, false)) - } -} - -// Prints a map in the provided order with one key-value-pair per line -func Print(m map[string]string, keyOrder []string) { - for _, key := range keyOrder { - value, ok := m[key] - if ok && value != "" { - fmt.Printf("%s: %s\n", key, value) - } - } -} - -// Prints items in columns with header and correct padding -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...) - } - - // 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 - - // Add each column to line with correct padding - for _, key := range keyOrder { - value, _ := item[key] - line += padFns[key](value) - } - - // Print line - fmt.Println(line) - } -} - -// Returns a padding function, that pads input to the longest string in items -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] - length := utf8.RuneCountInString(str) - if length > max { - max = length - } - } - - // Return padding function - return func(str string) string { - column := str - for utf8.RuneCountInString(column) < max+spacing { - column += " " - } - return column - } -} - -func inArray(needle string, haystack []string) bool { - for _, x := range haystack { - if needle == x { - return true - } - } - - return false -} |
