From 454dfd3c9e275e51b18975ca9a33030382c3f697 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood <nick@craig-wood.com> Date: Sat, 8 Jun 2019 09:19:07 +0100 Subject: [PATCH] rc: Add operations/fsinfo: Return information about the remote This returns a information about the remote including Name, Root, Hashes and optional Features. --- fs/operations/operations.go | 37 +++++++++++++++ fs/operations/operations_test.go | 20 ++++++++ fs/operations/rc.go | 81 +++++++++++++++++++++++++++++++- fs/operations/rc_test.go | 27 +++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) diff --git a/fs/operations/operations.go b/fs/operations/operations.go index a142140a2..5d15e80c6 100644 --- a/fs/operations/operations.go +++ b/fs/operations/operations.go @@ -1750,3 +1750,40 @@ func DirMove(f fs.Fs, srcRemote, dstRemote string) (err error) { return nil } + +// FsInfo provides information about a remote +type FsInfo struct { + // Name of the remote (as passed into NewFs) + Name string + + // Root of the remote (as passed into NewFs) + Root string + + // String returns a description of the FS + String string + + // Precision of the ModTimes in this Fs in Nanoseconds + Precision time.Duration + + // Returns the supported hash types of the filesystem + Hashes []string + + // Features returns the optional features of this Fs + Features map[string]bool +} + +// GetFsInfo gets the information (FsInfo) about a given Fs +func GetFsInfo(f fs.Fs) *FsInfo { + info := &FsInfo{ + Name: f.Name(), + Root: f.Root(), + String: f.String(), + Precision: f.Precision(), + Hashes: make([]string, 0, 4), + Features: f.Features().Enabled(), + } + for _, hashType := range f.Hashes().Array() { + info.Hashes = append(info.Hashes, hashType.String()) + } + return info +} diff --git a/fs/operations/operations_test.go b/fs/operations/operations_test.go index 09cc60c64..507af4d5a 100644 --- a/fs/operations/operations_test.go +++ b/fs/operations/operations_test.go @@ -1182,3 +1182,23 @@ func TestDirMove(t *testing.T) { ) } + +func TestGetFsInfo(t *testing.T) { + r := fstest.NewRun(t) + defer r.Finalise() + + f := r.Fremote + info := operations.GetFsInfo(f) + assert.Equal(t, f.Name(), info.Name) + assert.Equal(t, f.Root(), info.Root) + assert.Equal(t, f.String(), info.String) + assert.Equal(t, f.Precision(), info.Precision) + hashSet := hash.NewHashSet() + for _, hashName := range info.Hashes { + var ht hash.Type + require.NoError(t, ht.Set(hashName)) + hashSet.Add(ht) + } + assert.Equal(t, f.Hashes(), hashSet) + assert.Equal(t, f.Features().Enabled(), info.Features) +} diff --git a/fs/operations/rc.go b/fs/operations/rc.go index d5d3fcc4f..351f7cccc 100644 --- a/fs/operations/rc.go +++ b/fs/operations/rc.go @@ -68,9 +68,10 @@ func init() { Help: `This takes the following parameters - fs - a remote name string eg "drive:" -- remote - a path within that remote eg "dir" The result is as returned from rclone about --json + +See the [about command](/commands/rclone_size/) command for more information on the above. `, }) } @@ -290,3 +291,81 @@ func rcPublicLink(in rc.Params) (out rc.Params, err error) { out["url"] = url return out, nil } + +func init() { + rc.Add(rc.Call{ + Path: "operations/fsinfo", + Fn: rcFsInfo, + Title: "Return information about the remote", + Help: `This takes the following parameters + +- fs - a remote name string eg "drive:" + +This returns info about the remote passed in; + +` + "```" + ` +{ + // optional features and whether they are available or not + "Features": { + "About": true, + "BucketBased": false, + "CanHaveEmptyDirectories": true, + "CaseInsensitive": false, + "ChangeNotify": false, + "CleanUp": false, + "Copy": false, + "DirCacheFlush": false, + "DirMove": true, + "DuplicateFiles": false, + "GetTier": false, + "ListR": false, + "MergeDirs": false, + "Move": true, + "OpenWriterAt": true, + "PublicLink": false, + "Purge": true, + "PutStream": true, + "PutUnchecked": false, + "ReadMimeType": false, + "ServerSideAcrossConfigs": false, + "SetTier": false, + "SetWrapper": false, + "UnWrap": false, + "WrapFs": false, + "WriteMimeType": false + }, + // Names of hashes available + "Hashes": [ + "MD5", + "SHA-1", + "DropboxHash", + "QuickXorHash" + ], + "Name": "local", // Name as created + "Precision": 1, // Precision of timestamps in ns + "Root": "/", // Path as created + "String": "Local file system at /" // how the remote will appear in logs +} +` + "```" + ` + +This command does not have a command line equivalent so use this instead: + + rclone rc --loopback operations/fsinfo fs=remote: + +`, + }) +} + +// Fsinfo the remote +func rcFsInfo(in rc.Params) (out rc.Params, err error) { + f, err := rc.GetFs(in) + if err != nil { + return nil, err + } + info := GetFsInfo(f) + err = rc.Reshape(&out, info) + if err != nil { + return nil, errors.Wrap(err, "fsinfo Reshape failed") + } + return out, nil +} diff --git a/fs/operations/rc_test.go b/fs/operations/rc_test.go index 426abc62a..c3c16bfd2 100644 --- a/fs/operations/rc_test.go +++ b/fs/operations/rc_test.go @@ -370,3 +370,30 @@ func TestRcPublicLink(t *testing.T) { require.Error(t, err) assert.Contains(t, err.Error(), "doesn't support public links") } + +// operations/fsinfo: Return information about the remote +func TestRcFsInfo(t *testing.T) { + r, call := rcNewRun(t, "operations/fsinfo") + defer r.Finalise() + in := rc.Params{ + "fs": r.FremoteName, + } + got, err := call.Fn(in) + require.NoError(t, err) + want := operations.GetFsInfo(r.Fremote) + assert.Equal(t, want.Name, got["Name"]) + assert.Equal(t, want.Root, got["Root"]) + assert.Equal(t, want.String, got["String"]) + assert.Equal(t, float64(want.Precision), got["Precision"]) + var hashes []interface{} + for _, hash := range want.Hashes { + hashes = append(hashes, hash) + } + assert.Equal(t, hashes, got["Hashes"]) + var features = map[string]interface{}{} + for k, v := range want.Features { + features[k] = v + } + assert.Equal(t, features, got["Features"]) + +}