about: add new command 'about' to get quota info from a remote

Implemented for drive only.

Relates to #1138 and #1564.
This commit is contained in:
a-roussos 2018-02-09 22:48:32 +02:00 committed by Nick Craig-Wood
parent b83814082b
commit 94e277d759
9 changed files with 130 additions and 21 deletions

View file

@ -1413,6 +1413,18 @@ func (f *Fs) CleanUp() error {
return do() return do()
} }
// About gets quota information from the Fs
func (f *Fs) About() error {
f.CleanUpCache(false)
do := f.Fs.Features().About
if do == nil {
return nil
}
return do()
}
// Stats returns stats about the cache storage // Stats returns stats about the cache storage
func (f *Fs) Stats() (map[string]map[string]interface{}, error) { func (f *Fs) Stats() (map[string]map[string]interface{}, error) {
return f.cache.Stats() return f.cache.Stats()
@ -1551,4 +1563,5 @@ var (
_ fs.Wrapper = (*Fs)(nil) _ fs.Wrapper = (*Fs)(nil)
_ fs.ListRer = (*Fs)(nil) _ fs.ListRer = (*Fs)(nil)
_ fs.ChangeNotifier = (*Fs)(nil) _ fs.ChangeNotifier = (*Fs)(nil)
_ fs.Abouter = (*Fs)(nil)
) )

View file

@ -1050,6 +1050,29 @@ func (f *Fs) CleanUp() error {
return nil return nil
} }
// About gets quota information
func (f *Fs) About() error {
var about *drive.About
var err error
err = f.pacer.Call(func() (bool, error) {
about, err = f.svc.About.Get().Fields("storageQuota").Do()
return shouldRetry(err)
})
if err != nil {
fs.Errorf(f, "Failed to get Drive storageQuota: %v", err)
return nil
}
quota := float64(about.StorageQuota.Limit) / (1 << 30)
usagetotal := float64(about.StorageQuota.Usage) / (1 << 30)
usagedrive := float64(about.StorageQuota.UsageInDrive) / (1 << 30)
usagetrash := float64(about.StorageQuota.UsageInDriveTrash) / (1 << 30)
fmt.Printf("Quota: %.0f GiB | Used: %.1f GiB (Trash: %.1f GiB) | Available: %.1f GiB | Usage: %d%%\n",
quota, usagedrive, usagetrash, quota-usagedrive, int((usagedrive/quota)*100))
fmt.Printf("Space used in other Google services (such as Gmail): %.2f GiB\n",
usagetotal-usagedrive)
return nil
}
// Move src to this remote using server side move operations. // Move src to this remote using server side move operations.
// //
// This is stored with the remote path given // This is stored with the remote path given

27
cmd/about/about.go Normal file
View file

@ -0,0 +1,27 @@
package about
import (
"github.com/ncw/rclone/cmd"
"github.com/ncw/rclone/fs/operations"
"github.com/spf13/cobra"
)
func init() {
cmd.Root.AddCommand(commandDefintion)
}
var commandDefintion = &cobra.Command{
Use: "about remote:",
Short: `Get quota information from the remote.`,
Long: `
Get quota information from the remote, like bytes used/free/quota and bytes
used in the trash. Not supported by all remotes.
`,
Run: func(command *cobra.Command, args []string) {
cmd.CheckArgs(1, 1, command, args)
fsrc := cmd.NewFsSrc(args)
cmd.Run(true, false, command, func() error {
return operations.About(fsrc)
})
},
}

View file

@ -4,6 +4,7 @@ package all
import ( import (
// Active commands // Active commands
_ "github.com/ncw/rclone/cmd" _ "github.com/ncw/rclone/cmd"
_ "github.com/ncw/rclone/cmd/about"
_ "github.com/ncw/rclone/cmd/authorize" _ "github.com/ncw/rclone/cmd/authorize"
_ "github.com/ncw/rclone/cmd/cachestats" _ "github.com/ncw/rclone/cmd/cachestats"
_ "github.com/ncw/rclone/cmd/cat" _ "github.com/ncw/rclone/cmd/cat"

View file

@ -98,6 +98,7 @@ The main rclone commands with most used first
* [rclone moveto](/commands/rclone_moveto/) - Move file or directory from source to dest. * [rclone moveto](/commands/rclone_moveto/) - Move file or directory from source to dest.
* [rclone obscure](/commands/rclone_obscure/) - Obscure password for use in the rclone.conf * [rclone obscure](/commands/rclone_obscure/) - Obscure password for use in the rclone.conf
* [rclone cryptcheck](/commands/rclone_cryptcheck/) - Check the integrity of a crypted remote. * [rclone cryptcheck](/commands/rclone_cryptcheck/) - Check the integrity of a crypted remote.
* [rclone about](/commands/rclone_about/) - Get quota information from the remote.
See the [commands index](/commands/) for the full list. See the [commands index](/commands/) for the full list.

View file

@ -338,6 +338,14 @@ If you wish to empty your trash you can use the `rclone cleanup remote:`
command which will permanently delete all your trashed files. This command command which will permanently delete all your trashed files. This command
does not take any path arguments. does not take any path arguments.
### Quota information ###
To view your current quota you can use the `rclone about remote:`
command which will display your usage limit (quota), the usage in Google
Drive, the size of all files in the Trash and the space used by other
Google services such as Gmail. This command does not take any path
arguments.
### Specific options ### ### Specific options ###
Here are the command line options specific to this cloud storage Here are the command line options specific to this cloud storage

View file

@ -119,27 +119,27 @@ All the remotes support a basic set of features, but there are some
optional features supported by some remotes used to make some optional features supported by some remotes used to make some
operations more efficient. operations more efficient.
| Name | Purge | Copy | Move | DirMove | CleanUp | ListR | StreamUpload | LinkSharing | | Name | Purge | Copy | Move | DirMove | CleanUp | ListR | StreamUpload | LinkSharing | About |
| ---------------------------- |:-----:|:----:|:----:|:-------:|:-------:|:-----:|:------------:|:------------:| | ---------------------------- |:-----:|:----:|:----:|:-------:|:-------:|:-----:|:------------:|:------------:|:-----:|
| Amazon Drive | Yes | No | Yes | Yes | No [#575](https://github.com/ncw/rclone/issues/575) | No | No | No [#2178](https://github.com/ncw/rclone/issues/2178) | | Amazon Drive | Yes | No | Yes | Yes | No [#575](https://github.com/ncw/rclone/issues/575) | No | No | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| Amazon S3 | No | Yes | No | No | No | Yes | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | | Amazon S3 | No | Yes | No | No | No | Yes | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| Backblaze B2 | No | No | No | No | Yes | Yes | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | | Backblaze B2 | No | No | No | No | Yes | Yes | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| Box | Yes | Yes | Yes | Yes | No [#575](https://github.com/ncw/rclone/issues/575) | No | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | | Box | Yes | Yes | Yes | Yes | No [#575](https://github.com/ncw/rclone/issues/575) | No | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| Dropbox | Yes | Yes | Yes | Yes | No [#575](https://github.com/ncw/rclone/issues/575) | No | Yes | Yes | | Dropbox | Yes | Yes | Yes | Yes | No [#575](https://github.com/ncw/rclone/issues/575) | No | Yes | Yes | No |
| FTP | No | No | Yes | Yes | No | No | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | | FTP | No | No | Yes | Yes | No | No | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| Google Cloud Storage | Yes | Yes | No | No | No | Yes | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | | Google Cloud Storage | Yes | Yes | No | No | No | Yes | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| Google Drive | Yes | Yes | Yes | Yes | Yes | No | Yes | Yes | | Google Drive | Yes | Yes | Yes | Yes | Yes | No | Yes | Yes | Yes |
| HTTP | No | No | No | No | No | No | No | No [#2178](https://github.com/ncw/rclone/issues/2178) | | HTTP | No | No | No | No | No | No | No | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| Hubic | Yes † | Yes | No | No | No | Yes | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | | Hubic | Yes † | Yes | No | No | No | Yes | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| Microsoft Azure Blob Storage | Yes | Yes | No | No | No | Yes | No | No [#2178](https://github.com/ncw/rclone/issues/2178) | | Microsoft Azure Blob Storage | Yes | Yes | No | No | No | Yes | No | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| Microsoft OneDrive | Yes | Yes | Yes | No [#197](https://github.com/ncw/rclone/issues/197) | No [#575](https://github.com/ncw/rclone/issues/575) | No | No | No [#2178](https://github.com/ncw/rclone/issues/2178) | | Microsoft OneDrive | Yes | Yes | Yes | No [#197](https://github.com/ncw/rclone/issues/197) | No [#575](https://github.com/ncw/rclone/issues/575) | No | No | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| Openstack Swift | Yes † | Yes | No | No | No | Yes | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | | Openstack Swift | Yes † | Yes | No | No | No | Yes | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| pCloud | Yes | Yes | Yes | Yes | Yes | No | No | No [#2178](https://github.com/ncw/rclone/issues/2178) | | pCloud | Yes | Yes | Yes | Yes | Yes | No | No | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| QingStor | No | Yes | No | No | No | Yes | No | No [#2178](https://github.com/ncw/rclone/issues/2178) | | QingStor | No | Yes | No | No | No | Yes | No | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| SFTP | No | No | Yes | Yes | No | No | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | | SFTP | No | No | Yes | Yes | No | No | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| WebDAV | Yes | Yes | Yes | Yes | No | No | Yes ‡ | No [#2178](https://github.com/ncw/rclone/issues/2178) | | WebDAV | Yes | Yes | Yes | Yes | No | No | Yes ‡ | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| Yandex Disk | Yes | No | No | No | Yes | Yes | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | | Yandex Disk | Yes | No | No | No | Yes | Yes | Yes | No [#2178](https://github.com/ncw/rclone/issues/2178) | No |
| The local filesystem | Yes | No | Yes | Yes | No | No | Yes | No | | The local filesystem | Yes | No | Yes | Yes | No | No | Yes | No | No |
### Purge ### ### Purge ###
@ -202,3 +202,11 @@ file to local disk first, e.g. `rclone rcat`.
Sets the necessary permissions on a file or folder and prints a link Sets the necessary permissions on a file or folder and prints a link
that allows others to access them, even if they don't have an account that allows others to access them, even if they don't have an account
on the particular cloud provider. on the particular cloud provider.
### About ###
This is used to fetch quota information from the remote, like bytes
used/free/quota and bytes used in the trash.
If the server can't do `About` then `rclone about` will return an
error.

View file

@ -377,6 +377,9 @@ type Features struct {
// Don't implement this unless you have a more efficient way // Don't implement this unless you have a more efficient way
// of listing recursively that doing a directory traversal. // of listing recursively that doing a directory traversal.
ListR ListRFn ListR ListRFn
// Get quota information from the Fs
About func() error
} }
// Disable nil's out the named feature. If it isn't found then it // Disable nil's out the named feature. If it isn't found then it
@ -466,6 +469,9 @@ func (ft *Features) Fill(f Fs) *Features {
if do, ok := f.(ListRer); ok { if do, ok := f.(ListRer); ok {
ft.ListR = do.ListR ft.ListR = do.ListR
} }
if do, ok := f.(Abouter); ok {
ft.About = do.About
}
return ft.DisableList(Config.DisableFeatures) return ft.DisableList(Config.DisableFeatures)
} }
@ -519,6 +525,9 @@ func (ft *Features) Mask(f Fs) *Features {
if mask.ListR == nil { if mask.ListR == nil {
ft.ListR = nil ft.ListR = nil
} }
if mask.About == nil {
ft.About = nil
}
return ft.DisableList(Config.DisableFeatures) return ft.DisableList(Config.DisableFeatures)
} }
@ -706,6 +715,12 @@ type RangeSeeker interface {
RangeSeek(offset int64, whence int, length int64) (int64, error) RangeSeek(offset int64, whence int, length int64) (int64, error)
} }
// Abouter is an optional interface for Fs
type Abouter interface {
// About gets quota information from the Fs
About() error
}
// ObjectsChan is a channel of Objects // ObjectsChan is a channel of Objects
type ObjectsChan chan Object type ObjectsChan chan Object

View file

@ -1049,6 +1049,19 @@ func CleanUp(f fs.Fs) error {
return doCleanUp() return doCleanUp()
} }
// About gets quota information from the remote
func About(f fs.Fs) error {
doAbout := f.Features().About
if doAbout == nil {
return errors.Errorf("%v doesn't support about", f)
}
if fs.Config.DryRun {
fs.Logf(f, "Not running about as --dry-run set")
return nil
}
return doAbout()
}
// wrap a Reader and a Closer together into a ReadCloser // wrap a Reader and a Closer together into a ReadCloser
type readCloser struct { type readCloser struct {
io.Reader io.Reader