mirror of
https://github.com/rclone/rclone.git
synced 2025-02-03 00:46:31 +08:00
33d2747829
Before this change, this code implemented an ad-hoc parser for a subset of vfs and mount options. After the config re-organization it can use the same parsing code as the rest of rclone which simplifies the code and exposes all the VFS and mount options.
197 lines
5.2 KiB
Go
197 lines
5.2 KiB
Go
package docker
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/rclone/rclone/cmd/mountlib"
|
|
"github.com/rclone/rclone/fs"
|
|
"github.com/rclone/rclone/fs/config/configmap"
|
|
"github.com/rclone/rclone/fs/config/configstruct"
|
|
"github.com/rclone/rclone/fs/fspath"
|
|
"github.com/rclone/rclone/fs/rc"
|
|
"github.com/rclone/rclone/vfs/vfscommon"
|
|
)
|
|
|
|
// applyOptions configures volume from request options.
|
|
//
|
|
// There are 5 special options:
|
|
// - "remote" aka "fs" determines existing remote from config file
|
|
// with a path or on-the-fly remote using the ":backend:" syntax.
|
|
// It is usually named "remote" in documentation but can be aliased as
|
|
// "fs" to avoid confusion with the "remote" option of some backends.
|
|
// - "type" is equivalent to the ":backend:" syntax (optional).
|
|
// - "path" provides explicit on-remote path for "type" (optional).
|
|
// - "mount-type" can be "mount", "cmount" or "mount2", defaults to
|
|
// first found (optional).
|
|
// - "persist" is reserved for future to create remotes persisted
|
|
// in rclone.conf similar to rcd (optional).
|
|
//
|
|
// Unlike rcd we use the flat naming scheme for mount, vfs and backend
|
|
// options without substructures. Dashes, underscores and mixed case
|
|
// in option names can be used interchangeably. Option name conflicts
|
|
// can be resolved in a manner similar to rclone CLI by adding prefixes:
|
|
// "vfs-", primary mount backend type like "sftp-", and so on.
|
|
//
|
|
// After triaging the options are put in MountOpt, VFSOpt or connect
|
|
// string for actual filesystem setup and in volume.Options for saving
|
|
// the state.
|
|
func (vol *Volume) applyOptions(volOpt VolOpts) error {
|
|
// copy options to override later
|
|
mntOpt := &vol.mnt.MountOpt
|
|
vfsOpt := &vol.mnt.VFSOpt
|
|
*mntOpt = vol.drv.mntOpt
|
|
*vfsOpt = vol.drv.vfsOpt
|
|
|
|
// vol.Options has all options except "remote" and "type"
|
|
vol.Options = VolOpts{}
|
|
vol.fsString = ""
|
|
|
|
var fsName, fsPath, fsType string
|
|
var explicitPath string
|
|
var fsOpt configmap.Simple
|
|
|
|
// parse "remote" or "type"
|
|
for key, str := range volOpt {
|
|
switch key {
|
|
case "":
|
|
continue
|
|
case "remote", "fs":
|
|
if str != "" {
|
|
p, err := fspath.Parse(str)
|
|
if err != nil || p.Name == ":" {
|
|
return fmt.Errorf("cannot parse path %q: %w", str, err)
|
|
}
|
|
fsName, fsPath, fsOpt = p.Name, p.Path, p.Config
|
|
vol.Fs = str
|
|
}
|
|
case "type":
|
|
fsType = str
|
|
vol.Type = str
|
|
case "path":
|
|
explicitPath = str
|
|
vol.Path = str
|
|
default:
|
|
vol.Options[key] = str
|
|
}
|
|
}
|
|
|
|
// find options supported by backend
|
|
if strings.HasPrefix(fsName, ":") {
|
|
fsType = fsName[1:]
|
|
fsName = ""
|
|
}
|
|
if fsType == "" {
|
|
fsType = "local"
|
|
if fsName != "" {
|
|
var ok bool
|
|
fsType, ok = fs.ConfigMap("", nil, fsName, nil).Get("type")
|
|
if !ok {
|
|
return fs.ErrorNotFoundInConfigFile
|
|
}
|
|
}
|
|
}
|
|
if explicitPath != "" {
|
|
if fsPath != "" {
|
|
fs.Logf(nil, "Explicit path will override connection string")
|
|
}
|
|
fsPath = explicitPath
|
|
}
|
|
fsInfo, err := fs.Find(fsType)
|
|
if err != nil {
|
|
return fmt.Errorf("unknown filesystem type %q", fsType)
|
|
}
|
|
|
|
// handle remaining options, override fsOpt
|
|
if fsOpt == nil {
|
|
fsOpt = configmap.Simple{}
|
|
}
|
|
opt := rc.Params{}
|
|
for key, val := range vol.Options {
|
|
opt[key] = val
|
|
}
|
|
mntMap := configmap.Simple{}
|
|
vfsMap := configmap.Simple{}
|
|
for key := range opt {
|
|
var ok bool
|
|
var err error
|
|
normalKey := normalOptName(key)
|
|
underscoreKey := strings.ReplaceAll(normalKey, "-", "_")
|
|
|
|
switch normalKey {
|
|
case "persist":
|
|
vol.persist, err = opt.GetBool(key)
|
|
ok = true
|
|
case "mount-type":
|
|
vol.mountType, err = opt.GetString(key)
|
|
ok = true
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("cannot parse option %q: %w", key, err)
|
|
}
|
|
|
|
if !ok {
|
|
// try to use as a mount option in mntMap
|
|
if mountlib.OptionsInfo.Get(underscoreKey) != nil {
|
|
mntMap[underscoreKey] = vol.Options[key]
|
|
ok = true
|
|
}
|
|
}
|
|
if !ok {
|
|
// try as a vfs option in vfsMap
|
|
if vfscommon.OptionsInfo.Get(underscoreKey) != nil {
|
|
vfsMap[underscoreKey] = vol.Options[key]
|
|
ok = true
|
|
}
|
|
}
|
|
|
|
if !ok {
|
|
// try as a backend option in fsOpt (backends use "_" instead of "-")
|
|
fsOptName := strings.TrimPrefix(underscoreKey, fsType+"_")
|
|
hasFsPrefix := underscoreKey != fsOptName
|
|
if !hasFsPrefix || fsInfo.Options.Get(fsOptName) == nil {
|
|
fs.Logf(nil, "Option %q is not supported by backend %q", key, fsType)
|
|
return fmt.Errorf("unsupported backend option %q", key)
|
|
}
|
|
fsOpt[fsOptName], err = opt.GetString(key)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot parse backend option %q: %w", key, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Parse VFS options
|
|
err = configstruct.Set(vfsMap, vfsOpt)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot parse vfs options: %w", err)
|
|
}
|
|
|
|
// Parse Mount options
|
|
err = configstruct.Set(mntMap, mntOpt)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot parse mount options: %w", err)
|
|
}
|
|
|
|
// build remote string from fsName, fsType, fsOpt, fsPath
|
|
colon := ":"
|
|
comma := ","
|
|
if fsName == "" {
|
|
fsName = ":" + fsType
|
|
}
|
|
connString := fsOpt.String()
|
|
if fsName == "" && fsType == "" {
|
|
colon = ""
|
|
connString = ""
|
|
}
|
|
if connString == "" {
|
|
comma = ""
|
|
}
|
|
vol.fsString = fsName + comma + connString + colon + fsPath
|
|
|
|
return vol.validate()
|
|
}
|
|
|
|
func normalOptName(key string) string {
|
|
return strings.ReplaceAll(strings.TrimPrefix(strings.ToLower(key), "--"), "_", "-")
|
|
}
|