fs: Allow on the fly remotes with :backend: syntax - fixes #2449

This change allows remotes to be created on the fly without a config
file by using the remote type prefixed with a : as the remote name, Eg
:s3: to make an s3 remote.

This assumes the user is supplying the backend config via command line
flags or environment variables.
This commit is contained in:
Nick Craig-Wood 2018-08-07 22:51:06 +01:00
parent 174ca22936
commit 8656bd2bb0
5 changed files with 64 additions and 18 deletions

View file

@ -133,6 +133,48 @@ It is recommended to use `copy` when copying individual files, not `sync`.
They have pretty much the same effect but `copy` will use a lot less They have pretty much the same effect but `copy` will use a lot less
memory. memory.
Syntax of remote paths
----------------------
The syntax of the paths passed to the rclone command are as follows.
### /path/to/dir
This refers to the local file system.
On Windows only `\` may be used instead of `/` in local paths
**only**, non local paths must use `/`.
These paths needn't start with a leading `/` - if they don't then they
will be relative to the current directory.
### remote:path/to/dir
This refers to a directory `path/to/dir` on `remote:` as defined in
the config file (configured with `rclone config`).
### remote:/path/to/dir
On most backends this is refers to the same directory as
`remote:path/to/dir` and that format should be preferred. On a very
small number of remotes (FTP, SFTP, Dropbox for business) this will
refer to a different directory. On these, paths without a leading `/`
will refer to your "home" directory and paths with a leading `/` will
refer to the root.
### :backend:path/to/dir
This is an advanced form for creating remotes on the fly. `backend`
should be the name or prefix of a backend (the `type` in the config
file) and all the configuration for the backend should be provided on
the command line (or in environment variables).
Eg
rclone lsd --http-url https://pub.rclone.org :http:
Which lists all the directories in `pub.rclone.org`.
Quoting and the shell Quoting and the shell
--------------------- ---------------------

View file

@ -121,17 +121,7 @@ No checksums are stored.
### Usage without a config file ### ### Usage without a config file ###
Note that since only two environment variable need to be set, it is Since the http remote only has one config parameter it is easy to use
easy to use without a config file like this. without a config file:
``` rclone lsd --http-url https://beta.rclone.org :http:
RCLONE_CONFIG_ZZ_TYPE=http RCLONE_CONFIG_ZZ_URL=https://beta.rclone.org rclone lsd zz:
```
Or if you prefer
```
export RCLONE_CONFIG_ZZ_TYPE=http
export RCLONE_CONFIG_ZZ_URL=https://beta.rclone.org
rclone lsd zz:
```

View file

@ -859,10 +859,14 @@ func ParseRemote(path string) (fsInfo *RegInfo, configName, fsPath string, err e
var fsName string var fsName string
var ok bool var ok bool
if configName != "" { if configName != "" {
m := ConfigMap(nil, configName) if strings.HasPrefix(configName, ":") {
fsName, ok = m.Get("type") fsName = configName[1:]
if !ok { } else {
return nil, "", "", ErrorNotFoundInConfigFile m := ConfigMap(nil, configName)
fsName, ok = m.Get("type")
if !ok {
return nil, "", "", ErrorNotFoundInConfigFile
}
} }
} else { } else {
fsName = "local" fsName = "local"

View file

@ -10,7 +10,7 @@ import (
) )
// Matcher is a pattern to match an rclone URL // Matcher is a pattern to match an rclone URL
var Matcher = regexp.MustCompile(`^([\w_ -]+):(.*)$`) var Matcher = regexp.MustCompile(`^(:?[\w_ -]+):(.*)$`)
// Parse deconstructs a remote path into configName and fsPath // Parse deconstructs a remote path into configName and fsPath
// //

View file

@ -16,6 +16,7 @@ func TestParse(t *testing.T) {
{"path/to/file", "", "path/to/file"}, {"path/to/file", "", "path/to/file"},
{"remote:path/to/file", "remote", "path/to/file"}, {"remote:path/to/file", "remote", "path/to/file"},
{"remote:/path/to/file", "remote", "/path/to/file"}, {"remote:/path/to/file", "remote", "/path/to/file"},
{":backend:/path/to/file", ":backend", "/path/to/file"},
} { } {
gotConfigName, gotFsPath := Parse(test.in) gotConfigName, gotFsPath := Parse(test.in)
assert.Equal(t, test.wantConfigName, gotConfigName) assert.Equal(t, test.wantConfigName, gotConfigName)
@ -28,12 +29,21 @@ func TestSplit(t *testing.T) {
remote, wantParent, wantLeaf string remote, wantParent, wantLeaf string
}{ }{
{"", "", ""}, {"", "", ""},
{"remote:", "remote:", ""}, {"remote:", "remote:", ""},
{"remote:potato", "remote:", "potato"}, {"remote:potato", "remote:", "potato"},
{"remote:/", "remote:/", ""}, {"remote:/", "remote:/", ""},
{"remote:/potato", "remote:/", "potato"}, {"remote:/potato", "remote:/", "potato"},
{"remote:/potato/potato", "remote:/potato/", "potato"}, {"remote:/potato/potato", "remote:/potato/", "potato"},
{"remote:potato/sausage", "remote:potato/", "sausage"}, {"remote:potato/sausage", "remote:potato/", "sausage"},
{":remote:", ":remote:", ""},
{":remote:potato", ":remote:", "potato"},
{":remote:/", ":remote:/", ""},
{":remote:/potato", ":remote:/", "potato"},
{":remote:/potato/potato", ":remote:/potato/", "potato"},
{":remote:potato/sausage", ":remote:potato/", "sausage"},
{"/", "/", ""}, {"/", "/", ""},
{"/root", "/", "root"}, {"/root", "/", "root"},
{"/a/b", "/a/", "b"}, {"/a/b", "/a/", "b"},