mirror of
https://github.com/rclone/rclone.git
synced 2024-12-23 15:38:57 +01:00
config: add rc operations for config
This commit is contained in:
parent
e600217666
commit
e6dd121f52
@ -1,8 +1,11 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/ncw/rclone/cmd"
|
"github.com/ncw/rclone/cmd"
|
||||||
"github.com/ncw/rclone/fs/config"
|
"github.com/ncw/rclone/fs/config"
|
||||||
|
"github.com/ncw/rclone/fs/rc"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -93,7 +96,16 @@ you would do:
|
|||||||
`,
|
`,
|
||||||
RunE: func(command *cobra.Command, args []string) error {
|
RunE: func(command *cobra.Command, args []string) error {
|
||||||
cmd.CheckArgs(2, 256, command, args)
|
cmd.CheckArgs(2, 256, command, args)
|
||||||
return config.CreateRemote(args[0], args[1], args[2:])
|
in, err := argsToMap(args[2:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = config.CreateRemote(args[0], args[1], in)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
config.ShowRemote(args[0])
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +122,16 @@ For example to update the env_auth field of a remote of name myremote you would
|
|||||||
`,
|
`,
|
||||||
RunE: func(command *cobra.Command, args []string) error {
|
RunE: func(command *cobra.Command, args []string) error {
|
||||||
cmd.CheckArgs(3, 256, command, args)
|
cmd.CheckArgs(3, 256, command, args)
|
||||||
return config.UpdateRemote(args[0], args[1:])
|
in, err := argsToMap(args[1:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = config.UpdateRemote(args[0], in)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
config.ShowRemote(args[0])
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,6 +157,29 @@ For example to set password of a remote of name myremote you would do:
|
|||||||
`,
|
`,
|
||||||
RunE: func(command *cobra.Command, args []string) error {
|
RunE: func(command *cobra.Command, args []string) error {
|
||||||
cmd.CheckArgs(3, 256, command, args)
|
cmd.CheckArgs(3, 256, command, args)
|
||||||
return config.PasswordRemote(args[0], args[1:])
|
in, err := argsToMap(args[1:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = config.PasswordRemote(args[0], in)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
config.ShowRemote(args[0])
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This takes a list of arguments in key value key value form and
|
||||||
|
// converts it into a map
|
||||||
|
func argsToMap(args []string) (out rc.Params, err error) {
|
||||||
|
if len(args)%2 != 0 {
|
||||||
|
return nil, errors.New("found key without value")
|
||||||
|
}
|
||||||
|
out = rc.Params{}
|
||||||
|
// Set the config
|
||||||
|
for i := 0; i < len(args); i += 2 {
|
||||||
|
out[args[i]] = args[i+1]
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
"github.com/ncw/rclone/fs/driveletter"
|
"github.com/ncw/rclone/fs/driveletter"
|
||||||
"github.com/ncw/rclone/fs/fshttp"
|
"github.com/ncw/rclone/fs/fshttp"
|
||||||
"github.com/ncw/rclone/fs/fspath"
|
"github.com/ncw/rclone/fs/fspath"
|
||||||
|
"github.com/ncw/rclone/fs/rc"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/crypto/nacl/secretbox"
|
"golang.org/x/crypto/nacl/secretbox"
|
||||||
"golang.org/x/text/unicode/norm"
|
"golang.org/x/text/unicode/norm"
|
||||||
@ -901,18 +902,24 @@ func ChooseOption(o *fs.Option, name string) string {
|
|||||||
return in
|
return in
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Suppress the confirm prompts and return a function to undo that
|
||||||
|
func suppressConfirm() func() {
|
||||||
|
old := fs.Config.AutoConfirm
|
||||||
|
fs.Config.AutoConfirm = true
|
||||||
|
return func() {
|
||||||
|
fs.Config.AutoConfirm = old
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateRemote adds the keyValues passed in to the remote of name.
|
// UpdateRemote adds the keyValues passed in to the remote of name.
|
||||||
// keyValues should be key, value pairs.
|
// keyValues should be key, value pairs.
|
||||||
func UpdateRemote(name string, keyValues []string) error {
|
func UpdateRemote(name string, keyValues rc.Params) error {
|
||||||
if len(keyValues)%2 != 0 {
|
defer suppressConfirm()()
|
||||||
return errors.New("found key without value")
|
|
||||||
}
|
|
||||||
// Set the config
|
// Set the config
|
||||||
for i := 0; i < len(keyValues); i += 2 {
|
for k, v := range keyValues {
|
||||||
getConfigData().SetValue(name, keyValues[i], keyValues[i+1])
|
getConfigData().SetValue(name, k, fmt.Sprint(v))
|
||||||
}
|
}
|
||||||
RemoteConfig(name)
|
RemoteConfig(name)
|
||||||
ShowRemote(name)
|
|
||||||
SaveConfig()
|
SaveConfig()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -920,9 +927,7 @@ func UpdateRemote(name string, keyValues []string) error {
|
|||||||
// CreateRemote creates a new remote with name, provider and a list of
|
// CreateRemote creates a new remote with name, provider and a list of
|
||||||
// parameters which are key, value pairs. If update is set then it
|
// parameters which are key, value pairs. If update is set then it
|
||||||
// adds the new keys rather than replacing all of them.
|
// adds the new keys rather than replacing all of them.
|
||||||
func CreateRemote(name string, provider string, keyValues []string) error {
|
func CreateRemote(name string, provider string, keyValues rc.Params) error {
|
||||||
// Suppress Confirm
|
|
||||||
fs.Config.AutoConfirm = true
|
|
||||||
// Delete the old config if it exists
|
// Delete the old config if it exists
|
||||||
getConfigData().DeleteSection(name)
|
getConfigData().DeleteSection(name)
|
||||||
// Set the type
|
// Set the type
|
||||||
@ -935,20 +940,12 @@ func CreateRemote(name string, provider string, keyValues []string) error {
|
|||||||
|
|
||||||
// PasswordRemote adds the keyValues passed in to the remote of name.
|
// PasswordRemote adds the keyValues passed in to the remote of name.
|
||||||
// keyValues should be key, value pairs.
|
// keyValues should be key, value pairs.
|
||||||
func PasswordRemote(name string, keyValues []string) error {
|
func PasswordRemote(name string, keyValues rc.Params) error {
|
||||||
if len(keyValues) != 2 {
|
defer suppressConfirm()()
|
||||||
return errors.New("found key without value")
|
for k, v := range keyValues {
|
||||||
|
keyValues[k] = obscure.MustObscure(fmt.Sprint(v))
|
||||||
}
|
}
|
||||||
// Suppress Confirm
|
return UpdateRemote(name, keyValues)
|
||||||
fs.Config.AutoConfirm = true
|
|
||||||
passwd := obscure.MustObscure(keyValues[1])
|
|
||||||
if passwd != "" {
|
|
||||||
getConfigData().SetValue(name, keyValues[0], passwd)
|
|
||||||
RemoteConfig(name)
|
|
||||||
ShowRemote(name)
|
|
||||||
SaveConfig()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSONListProviders prints all the providers and options in JSON format
|
// JSONListProviders prints all the providers and options in JSON format
|
||||||
@ -1297,16 +1294,28 @@ func FileSections() []string {
|
|||||||
return sections
|
return sections
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump dumps all the config as a JSON file
|
// DumpRcRemote dumps the config for a single remote
|
||||||
func Dump() error {
|
func DumpRcRemote(name string) (dump rc.Params) {
|
||||||
dump := make(map[string]map[string]string)
|
params := rc.Params{}
|
||||||
for _, name := range getConfigData().GetSectionList() {
|
|
||||||
params := make(map[string]string)
|
|
||||||
for _, key := range getConfigData().GetKeyList(name) {
|
for _, key := range getConfigData().GetKeyList(name) {
|
||||||
params[key] = FileGet(name, key)
|
params[key] = FileGet(name, key)
|
||||||
}
|
}
|
||||||
dump[name] = params
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
// DumpRcBlob dumps all the config as an unstructured blob suitable
|
||||||
|
// for the rc
|
||||||
|
func DumpRcBlob() (dump rc.Params) {
|
||||||
|
dump = rc.Params{}
|
||||||
|
for _, name := range getConfigData().GetSectionList() {
|
||||||
|
dump[name] = DumpRcRemote(name)
|
||||||
}
|
}
|
||||||
|
return dump
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump dumps all the config as a JSON file
|
||||||
|
func Dump() error {
|
||||||
|
dump := DumpRcBlob()
|
||||||
b, err := json.MarshalIndent(dump, "", " ")
|
b, err := json.MarshalIndent(dump, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to marshal config dump")
|
return errors.Wrap(err, "failed to marshal config dump")
|
||||||
|
178
fs/config/rc.go
Normal file
178
fs/config/rc.go
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ncw/rclone/fs"
|
||||||
|
"github.com/ncw/rclone/fs/rc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rc.Add(rc.Call{
|
||||||
|
Path: "config/dump",
|
||||||
|
Fn: rcDump,
|
||||||
|
Title: "Dumps the config file.",
|
||||||
|
AuthRequired: true,
|
||||||
|
Help: `
|
||||||
|
Returns a JSON object:
|
||||||
|
- key: value
|
||||||
|
|
||||||
|
Where keys are remote names and values are the config parameters.
|
||||||
|
|
||||||
|
See the [config dump command](/commands/rclone_config_dump/) command for more information on the above.
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the config file dump
|
||||||
|
func rcDump(in rc.Params) (out rc.Params, err error) {
|
||||||
|
return DumpRcBlob(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rc.Add(rc.Call{
|
||||||
|
Path: "config/get",
|
||||||
|
Fn: rcGet,
|
||||||
|
Title: "Get a remote in the config file.",
|
||||||
|
AuthRequired: true,
|
||||||
|
Help: `
|
||||||
|
Parameters:
|
||||||
|
- name - name of remote to get
|
||||||
|
|
||||||
|
See the [config dump command](/commands/rclone_config_dump/) command for more information on the above.
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the config file get
|
||||||
|
func rcGet(in rc.Params) (out rc.Params, err error) {
|
||||||
|
name, err := in.GetString("name")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return DumpRcRemote(name), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rc.Add(rc.Call{
|
||||||
|
Path: "config/listremotes",
|
||||||
|
Fn: rcListRemotes,
|
||||||
|
Title: "Lists the remotes in the config file.",
|
||||||
|
AuthRequired: true,
|
||||||
|
Help: `
|
||||||
|
Returns
|
||||||
|
- remotes - array of remote names
|
||||||
|
|
||||||
|
See the [listremotes command](/commands/rclone_listremotes/) command for more information on the above.
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the a list of remotes in the config file
|
||||||
|
func rcListRemotes(in rc.Params) (out rc.Params, err error) {
|
||||||
|
var remotes = []string{}
|
||||||
|
for _, remote := range getConfigData().GetSectionList() {
|
||||||
|
remotes = append(remotes, remote)
|
||||||
|
}
|
||||||
|
out = rc.Params{
|
||||||
|
"remotes": remotes,
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rc.Add(rc.Call{
|
||||||
|
Path: "config/providers",
|
||||||
|
Fn: rcProviders,
|
||||||
|
Title: "Shows how providers are configured in the config file.",
|
||||||
|
AuthRequired: true,
|
||||||
|
Help: `
|
||||||
|
Returns a JSON object:
|
||||||
|
- providers - array of objects
|
||||||
|
|
||||||
|
See the [config providers command](/commands/rclone_config_providers/) command for more information on the above.
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the config file providers
|
||||||
|
func rcProviders(in rc.Params) (out rc.Params, err error) {
|
||||||
|
out = rc.Params{
|
||||||
|
"providers": fs.Registry,
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for _, name := range []string{"create", "update", "password"} {
|
||||||
|
name := name
|
||||||
|
extraHelp := ""
|
||||||
|
if name == "create" {
|
||||||
|
extraHelp = "- type - type of the new remote\n"
|
||||||
|
}
|
||||||
|
rc.Add(rc.Call{
|
||||||
|
Path: "config/" + name,
|
||||||
|
AuthRequired: true,
|
||||||
|
Fn: func(in rc.Params) (rc.Params, error) {
|
||||||
|
return rcConfig(in, name)
|
||||||
|
},
|
||||||
|
Title: name + " the config for a remote.",
|
||||||
|
Help: `This takes the following parameters
|
||||||
|
|
||||||
|
- name - name of remote
|
||||||
|
- type - type of new remote
|
||||||
|
` + extraHelp + `
|
||||||
|
|
||||||
|
See the [config ` + name + ` command](/commands/rclone_config_` + name + `/) command for more information on the above.`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manipulate the config file
|
||||||
|
func rcConfig(in rc.Params, what string) (out rc.Params, err error) {
|
||||||
|
name, err := in.GetString("name")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
parameters := rc.Params{}
|
||||||
|
err = in.GetStruct("parameters", ¶meters)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch what {
|
||||||
|
case "create":
|
||||||
|
remoteType, err := in.GetString("type")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, CreateRemote(name, remoteType, parameters)
|
||||||
|
case "update":
|
||||||
|
return nil, UpdateRemote(name, parameters)
|
||||||
|
case "password":
|
||||||
|
return nil, PasswordRemote(name, parameters)
|
||||||
|
}
|
||||||
|
panic("unknown rcConfig type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rc.Add(rc.Call{
|
||||||
|
Path: "config/delete",
|
||||||
|
Fn: rcDelete,
|
||||||
|
Title: "Delete a remote in the config file.",
|
||||||
|
AuthRequired: true,
|
||||||
|
Help: `
|
||||||
|
Parameters:
|
||||||
|
- name - name of remote to delete
|
||||||
|
|
||||||
|
See the [config delete command](/commands/rclone_config_delete/) command for more information on the above.
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the config file delete
|
||||||
|
func rcDelete(in rc.Params) (out rc.Params, err error) {
|
||||||
|
name, err := in.GetString("name")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
DeleteRemote(name)
|
||||||
|
return nil, nil
|
||||||
|
}
|
149
fs/config/rc_test.go
Normal file
149
fs/config/rc_test.go
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
_ "github.com/ncw/rclone/backend/local"
|
||||||
|
"github.com/ncw/rclone/fs"
|
||||||
|
"github.com/ncw/rclone/fs/config/obscure"
|
||||||
|
"github.com/ncw/rclone/fs/rc"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
const testName = "configTestNameForRc"
|
||||||
|
|
||||||
|
func TestRc(t *testing.T) {
|
||||||
|
// Create the test remote
|
||||||
|
call := rc.Calls.Get("config/create")
|
||||||
|
assert.NotNil(t, call)
|
||||||
|
in := rc.Params{
|
||||||
|
"name": testName,
|
||||||
|
"type": "local",
|
||||||
|
"parameters": rc.Params{
|
||||||
|
"test_key": "sausage",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
out, err := call.Fn(in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, out)
|
||||||
|
assert.Equal(t, "local", FileGet(testName, "type"))
|
||||||
|
assert.Equal(t, "sausage", FileGet(testName, "test_key"))
|
||||||
|
|
||||||
|
// The sub tests rely on the remote created above but they can
|
||||||
|
// all be run independently
|
||||||
|
|
||||||
|
t.Run("Dump", func(t *testing.T) {
|
||||||
|
call := rc.Calls.Get("config/dump")
|
||||||
|
assert.NotNil(t, call)
|
||||||
|
in := rc.Params{}
|
||||||
|
out, err := call.Fn(in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, out)
|
||||||
|
|
||||||
|
require.NotNil(t, out[testName])
|
||||||
|
config := out[testName].(rc.Params)
|
||||||
|
|
||||||
|
assert.Equal(t, "local", config["type"])
|
||||||
|
assert.Equal(t, "sausage", config["test_key"])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Get", func(t *testing.T) {
|
||||||
|
call := rc.Calls.Get("config/get")
|
||||||
|
assert.NotNil(t, call)
|
||||||
|
in := rc.Params{
|
||||||
|
"name": testName,
|
||||||
|
}
|
||||||
|
out, err := call.Fn(in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, out)
|
||||||
|
|
||||||
|
assert.Equal(t, "local", out["type"])
|
||||||
|
assert.Equal(t, "sausage", out["test_key"])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ListRemotes", func(t *testing.T) {
|
||||||
|
call := rc.Calls.Get("config/listremotes")
|
||||||
|
assert.NotNil(t, call)
|
||||||
|
in := rc.Params{}
|
||||||
|
out, err := call.Fn(in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, out)
|
||||||
|
|
||||||
|
var remotes []string
|
||||||
|
err = out.GetStruct("remotes", &remotes)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Contains(t, remotes, testName)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Update", func(t *testing.T) {
|
||||||
|
call := rc.Calls.Get("config/update")
|
||||||
|
assert.NotNil(t, call)
|
||||||
|
in := rc.Params{
|
||||||
|
"name": testName,
|
||||||
|
"parameters": rc.Params{
|
||||||
|
"test_key": "rutabaga",
|
||||||
|
"test_key2": "cabbage",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
out, err := call.Fn(in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Nil(t, out)
|
||||||
|
|
||||||
|
assert.Equal(t, "local", FileGet(testName, "type"))
|
||||||
|
assert.Equal(t, "rutabaga", FileGet(testName, "test_key"))
|
||||||
|
assert.Equal(t, "cabbage", FileGet(testName, "test_key2"))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Password", func(t *testing.T) {
|
||||||
|
call := rc.Calls.Get("config/password")
|
||||||
|
assert.NotNil(t, call)
|
||||||
|
in := rc.Params{
|
||||||
|
"name": testName,
|
||||||
|
"parameters": rc.Params{
|
||||||
|
"test_key": "rutabaga",
|
||||||
|
"test_key2": "cabbage",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
out, err := call.Fn(in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Nil(t, out)
|
||||||
|
|
||||||
|
assert.Equal(t, "local", FileGet(testName, "type"))
|
||||||
|
assert.Equal(t, "rutabaga", obscure.MustReveal(FileGet(testName, "test_key")))
|
||||||
|
assert.Equal(t, "cabbage", obscure.MustReveal(FileGet(testName, "test_key2")))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Delete the test remote
|
||||||
|
call = rc.Calls.Get("config/delete")
|
||||||
|
assert.NotNil(t, call)
|
||||||
|
in = rc.Params{
|
||||||
|
"name": testName,
|
||||||
|
}
|
||||||
|
out, err = call.Fn(in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Nil(t, out)
|
||||||
|
assert.Equal(t, "", FileGet(testName, "type"))
|
||||||
|
assert.Equal(t, "", FileGet(testName, "test_key"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRcProviders(t *testing.T) {
|
||||||
|
call := rc.Calls.Get("config/providers")
|
||||||
|
assert.NotNil(t, call)
|
||||||
|
in := rc.Params{}
|
||||||
|
out, err := call.Fn(in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, out)
|
||||||
|
var registry []*fs.RegInfo
|
||||||
|
err = out.GetStruct("providers", ®istry)
|
||||||
|
require.NoError(t, err)
|
||||||
|
foundLocal := false
|
||||||
|
for _, provider := range registry {
|
||||||
|
if provider.Name == "local" {
|
||||||
|
foundLocal = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.True(t, foundLocal, "didn't find local provider")
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user