mirror of
https://github.com/rclone/rclone.git
synced 2025-01-22 22:28:47 +01:00
config: experiment with a text UI for config
This commit is contained in:
parent
956fc5062b
commit
ad38432cc3
@ -24,6 +24,7 @@ import (
|
|||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/Unknwon/goconfig"
|
"github.com/Unknwon/goconfig"
|
||||||
|
"github.com/manifoldco/promptui"
|
||||||
homedir "github.com/mitchellh/go-homedir"
|
homedir "github.com/mitchellh/go-homedir"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/rclone/rclone/fs"
|
"github.com/rclone/rclone/fs"
|
||||||
@ -611,7 +612,11 @@ func ShowRemotes() {
|
|||||||
func ChooseRemote() string {
|
func ChooseRemote() string {
|
||||||
remotes := getConfigData().GetSectionList()
|
remotes := getConfigData().GetSectionList()
|
||||||
sort.Strings(remotes)
|
sort.Strings(remotes)
|
||||||
return Choose("remote", remotes, nil, false)
|
var help []string
|
||||||
|
for _, remote := range remotes {
|
||||||
|
help = append(help, DumpRemote(remote))
|
||||||
|
}
|
||||||
|
return Choose("remote", remotes, help, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadLine reads some input
|
// ReadLine reads some input
|
||||||
@ -631,19 +636,36 @@ func Command(commands []string) byte {
|
|||||||
fmt.Printf("%c) %s\n", text[0], text[1:])
|
fmt.Printf("%c) %s\n", text[0], text[1:])
|
||||||
opts = append(opts, text[:1])
|
opts = append(opts, text[:1])
|
||||||
}
|
}
|
||||||
|
|
||||||
optString := strings.Join(opts, "")
|
optString := strings.Join(opts, "")
|
||||||
optHelp := strings.Join(opts, "/")
|
optHelp := strings.Join(opts, "/")
|
||||||
for {
|
|
||||||
fmt.Printf("%s> ", optHelp)
|
validate := func(input string) error {
|
||||||
result := strings.ToLower(ReadLine())
|
if len(input) == 0 {
|
||||||
if len(result) != 1 {
|
return errors.New("type a letter")
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
i := strings.Index(optString, string(result[0]))
|
if len(input) > 1 {
|
||||||
if i >= 0 {
|
return errors.New("only one letter required")
|
||||||
return result[0]
|
|
||||||
}
|
}
|
||||||
|
input = strings.ToLower(input)
|
||||||
|
i := strings.Index(optString, string(input[0]))
|
||||||
|
if i < 0 {
|
||||||
|
return errors.New("bad letter")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt := promptui.Prompt{
|
||||||
|
Label: optHelp,
|
||||||
|
Validate: validate,
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := prompt.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Prompt failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.ToLower(result)[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Confirm asks the user for Yes or No and returns true or false
|
// Confirm asks the user for Yes or No and returns true or false
|
||||||
@ -680,8 +702,8 @@ func ConfirmWithConfig(m configmap.Getter, configName string, Default bool) bool
|
|||||||
return Confirm()
|
return Confirm()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Choose one of the defaults or type a new string if newOk is set
|
// ChooseOld one of the defaults or type a new string if newOk is set
|
||||||
func Choose(what string, defaults, help []string, newOk bool) string {
|
func ChooseOld(what string, defaults, help []string, newOk bool) string {
|
||||||
valueDescription := "an existing"
|
valueDescription := "an existing"
|
||||||
if newOk {
|
if newOk {
|
||||||
valueDescription = "your own"
|
valueDescription = "your own"
|
||||||
@ -738,6 +760,67 @@ func Choose(what string, defaults, help []string, newOk bool) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Choose one of the defaults or type a new string if newOk is set
|
||||||
|
func Choose(what string, defaults, help []string, newOk bool) string {
|
||||||
|
const trim = 78
|
||||||
|
// tidy the help trimming all of its lines to trim chars
|
||||||
|
for i := range help {
|
||||||
|
parts := strings.Split(help[i], "\n")
|
||||||
|
for j := range parts {
|
||||||
|
p := []rune(parts[j])
|
||||||
|
if len(p) > trim {
|
||||||
|
p = p[:trim]
|
||||||
|
p[trim-1] = '…'
|
||||||
|
parts[j] = string(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
help[i] = strings.Join(parts, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
var items []fs.OptionExample
|
||||||
|
for i := range defaults {
|
||||||
|
item := fs.OptionExample{
|
||||||
|
Value: defaults[i],
|
||||||
|
}
|
||||||
|
if i < len(help) {
|
||||||
|
item.Help = help[i]
|
||||||
|
}
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
templates := &promptui.SelectTemplates{
|
||||||
|
Label: "{{ . }}?",
|
||||||
|
Active: "▸ {{ .Value | underline }}",
|
||||||
|
Inactive: " {{ .Value | faint }}",
|
||||||
|
Selected: "▸ {{ .Value | underline }}",
|
||||||
|
Details: `
|
||||||
|
--------- Help ----------
|
||||||
|
{{ .Help }}`,
|
||||||
|
}
|
||||||
|
|
||||||
|
searcher := func(input string, index int) bool {
|
||||||
|
name := items[index].Value + " " + items[index].Help
|
||||||
|
name = strings.Replace(strings.ToLower(name), " ", "", -1)
|
||||||
|
input = strings.Replace(strings.ToLower(input), " ", "", -1)
|
||||||
|
|
||||||
|
return strings.Contains(name, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt := promptui.Select{
|
||||||
|
Label: what,
|
||||||
|
Items: items,
|
||||||
|
Size: 8,
|
||||||
|
Searcher: searcher,
|
||||||
|
Templates: templates,
|
||||||
|
}
|
||||||
|
i, _, err := prompt.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Prompt failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaults[i]
|
||||||
|
}
|
||||||
|
|
||||||
// ChooseNumber asks the user to enter a number between min and max
|
// ChooseNumber asks the user to enter a number between min and max
|
||||||
// inclusive prompting them with what.
|
// inclusive prompting them with what.
|
||||||
func ChooseNumber(what string, min, max int) int {
|
func ChooseNumber(what string, min, max int) int {
|
||||||
@ -757,11 +840,16 @@ func ChooseNumber(what string, min, max int) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShowRemote shows the contents of the remote
|
// DumpRemote shows the contents of the remote
|
||||||
func ShowRemote(name string) {
|
func DumpRemote(name string) string {
|
||||||
fmt.Printf("--------------------\n")
|
var out []string
|
||||||
fmt.Printf("[%s]\n", name)
|
fs, err := FindByName(name)
|
||||||
fs := MustFindByName(name)
|
if err != nil {
|
||||||
|
return fmt.Sprintf("Error looking up %q: %v", name, err)
|
||||||
|
}
|
||||||
|
// fmt.Printf("--------------------\n")
|
||||||
|
// fmt.Printf("[%s]\n", name)
|
||||||
|
// fs := MustFindByName(name)
|
||||||
for _, key := range getConfigData().GetKeyList(name) {
|
for _, key := range getConfigData().GetKeyList(name) {
|
||||||
isPassword := false
|
isPassword := false
|
||||||
for _, option := range fs.Options {
|
for _, option := range fs.Options {
|
||||||
@ -772,11 +860,19 @@ func ShowRemote(name string) {
|
|||||||
}
|
}
|
||||||
value := FileGet(name, key)
|
value := FileGet(name, key)
|
||||||
if isPassword && value != "" {
|
if isPassword && value != "" {
|
||||||
fmt.Printf("%s = *** ENCRYPTED ***\n", key)
|
out = append(out, fmt.Sprintf("%s = *** ENCRYPTED ***", key))
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%s = %s\n", key, value)
|
out = append(out, fmt.Sprintf("%s = %s", key, value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return strings.Join(out, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShowRemote shows the contents of the remote
|
||||||
|
func ShowRemote(name string) {
|
||||||
|
fmt.Printf("--------------------\n")
|
||||||
|
fmt.Printf("[%s]\n", name)
|
||||||
|
fmt.Printf("%s\n", DumpRemote(name))
|
||||||
fmt.Printf("--------------------\n")
|
fmt.Printf("--------------------\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -807,6 +903,16 @@ func MustFindByName(name string) *fs.RegInfo {
|
|||||||
return fs.MustFind(fsType)
|
return fs.MustFind(fsType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindByName finds the RegInfo for the remote name passed in or
|
||||||
|
// returns nil and an error
|
||||||
|
func FindByName(name string) (*fs.RegInfo, error) {
|
||||||
|
fsType := FileGet(name, "type")
|
||||||
|
if fsType == "" {
|
||||||
|
return nil, errors.Errorf("Couldn't find type of fs for %q", name)
|
||||||
|
}
|
||||||
|
return fs.Find(fsType)
|
||||||
|
}
|
||||||
|
|
||||||
// RemoteConfig runs the config helper for the remote if needed
|
// RemoteConfig runs the config helper for the remote if needed
|
||||||
func RemoteConfig(name string) {
|
func RemoteConfig(name string) {
|
||||||
fmt.Printf("Remote config\n")
|
fmt.Printf("Remote config\n")
|
||||||
|
Loading…
Reference in New Issue
Block a user