drive: handle shared drives with leading/trailing space in name (related to #6618)
This commit is contained in:
parent
8b9f3bbe29
commit
5a59b49b6b
3 changed files with 51 additions and 30 deletions
|
@ -18,7 +18,6 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -3431,13 +3430,12 @@ func (f *Fs) Command(ctx context.Context, name string, arg []string, opt map[str
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
re := regexp.MustCompile(`[^\w\p{L}\p{N}. -]+`)
|
|
||||||
if _, ok := opt["config"]; ok {
|
if _, ok := opt["config"]; ok {
|
||||||
lines := []string{}
|
lines := []string{}
|
||||||
upstreams := []string{}
|
upstreams := []string{}
|
||||||
names := make(map[string]struct{}, len(drives))
|
names := make(map[string]struct{}, len(drives))
|
||||||
for i, drive := range drives {
|
for i, drive := range drives {
|
||||||
name := re.ReplaceAllString(drive.Name, "_")
|
name := fspath.MakeConfigName(drive.Name)
|
||||||
for {
|
for {
|
||||||
if _, found := names[name]; !found {
|
if _, found := names[name]; !found {
|
||||||
break
|
break
|
||||||
|
|
|
@ -13,7 +13,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
configNameRe = `[\w\p{L}\p{N}.]+(?:[ -]+[\w\p{L}\p{N}.-]+)*` // don't allow it to start with `-` as it complicates usage (#4261)
|
configNameRe = `[\w\p{L}\p{N}.]+(?:[ -]+[\w\p{L}\p{N}.-]+)*` // May contain Unicode numbers and letters, as well as `_`, `-`, `.` and space, but not start with `-` (it complicates usage, see #4261) or space, and not end with space
|
||||||
|
illegalPartOfConfigNameRe = `^[ -]+|[^\w\p{L}\p{N}. -]+|[ ]+$`
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -32,6 +33,9 @@ var (
|
||||||
// configNameMatcher is a pattern to match an rclone config name
|
// configNameMatcher is a pattern to match an rclone config name
|
||||||
configNameMatcher = regexp.MustCompile(`^` + configNameRe + `$`)
|
configNameMatcher = regexp.MustCompile(`^` + configNameRe + `$`)
|
||||||
|
|
||||||
|
// illegalPartOfConfigNameMatcher is a pattern to match a sequence of characters not allowed in an rclone config name
|
||||||
|
illegalPartOfConfigNameMatcher = regexp.MustCompile(illegalPartOfConfigNameRe)
|
||||||
|
|
||||||
// remoteNameMatcher is a pattern to match an rclone remote name at the start of a config
|
// remoteNameMatcher is a pattern to match an rclone remote name at the start of a config
|
||||||
remoteNameMatcher = regexp.MustCompile(`^:?` + configNameRe + `(?::$|,)`)
|
remoteNameMatcher = regexp.MustCompile(`^:?` + configNameRe + `(?::$|,)`)
|
||||||
)
|
)
|
||||||
|
@ -44,6 +48,21 @@ func CheckConfigName(configName string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MakeConfigName makes an input into something legal to be used as a config name.
|
||||||
|
// Returns a string where any sequences of illegal characters are replaced with
|
||||||
|
// a single underscore. If the input is already valid as a config name, it is
|
||||||
|
// returned unchanged. If the input is an empty string, a single underscore is
|
||||||
|
// returned.
|
||||||
|
func MakeConfigName(name string) string {
|
||||||
|
if name == "" {
|
||||||
|
return "_"
|
||||||
|
}
|
||||||
|
if configNameMatcher.MatchString(name) {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
return illegalPartOfConfigNameMatcher.ReplaceAllString(name, "_")
|
||||||
|
}
|
||||||
|
|
||||||
// checkRemoteName returns an error if remoteName is invalid
|
// checkRemoteName returns an error if remoteName is invalid
|
||||||
func checkRemoteName(remoteName string) error {
|
func checkRemoteName(remoteName string) error {
|
||||||
if remoteName == ":" || remoteName == "::" {
|
if remoteName == ":" || remoteName == "::" {
|
||||||
|
|
|
@ -19,34 +19,38 @@ var (
|
||||||
|
|
||||||
func TestCheckConfigName(t *testing.T) {
|
func TestCheckConfigName(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
in string
|
in string
|
||||||
want error
|
problem error
|
||||||
|
fixed string
|
||||||
}{
|
}{
|
||||||
{"remote", nil},
|
{"remote", nil, "remote"},
|
||||||
{"REMOTE", nil},
|
{"REMOTE", nil, "REMOTE"},
|
||||||
{"", errInvalidCharacters},
|
{"", errInvalidCharacters, "_"},
|
||||||
{":remote:", errInvalidCharacters},
|
{":remote:", errInvalidCharacters, "_remote_"},
|
||||||
{"remote:", errInvalidCharacters},
|
{"remote:", errInvalidCharacters, "remote_"},
|
||||||
{"rem:ote", errInvalidCharacters},
|
{"rem:ote", errInvalidCharacters, "rem_ote"},
|
||||||
{"rem/ote", errInvalidCharacters},
|
{"rem/ote", errInvalidCharacters, "rem_ote"},
|
||||||
{"rem\\ote", errInvalidCharacters},
|
{"rem\\ote", errInvalidCharacters, "rem_ote"},
|
||||||
{"[remote", errInvalidCharacters},
|
{"[remote", errInvalidCharacters, "_remote"},
|
||||||
{"*", errInvalidCharacters},
|
{"*", errInvalidCharacters, "_"},
|
||||||
{"-remote", errInvalidCharacters},
|
{"-remote", errInvalidCharacters, "_remote"},
|
||||||
{"r-emote-", nil},
|
{"r-emote-", nil, "r-emote-"},
|
||||||
{"_rem_ote_", nil},
|
{"---rem:::ote???", errInvalidCharacters, "_rem_ote_"},
|
||||||
{".", nil},
|
{"_rem_ote_", nil, "_rem_ote_"},
|
||||||
{"..", nil},
|
{".", nil, "."},
|
||||||
{".r.e.m.o.t.e.", nil},
|
{"..", nil, ".."},
|
||||||
{"rem ote", nil},
|
{".r.e.m.o.t.e.", nil, ".r.e.m.o.t.e."},
|
||||||
{"blåbær", nil},
|
{"rem ote", nil, "rem ote"},
|
||||||
{"chữ Quốc ngữ", nil},
|
{"blåbær", nil, "blåbær"},
|
||||||
{"remote ", errInvalidCharacters},
|
{"chữ Quốc ngữ", nil, "chữ Quốc ngữ"},
|
||||||
{" remote", errInvalidCharacters},
|
{"remote ", errInvalidCharacters, "remote_"},
|
||||||
{" remote ", errInvalidCharacters},
|
{" remote", errInvalidCharacters, "_remote"},
|
||||||
|
{" remote ", errInvalidCharacters, "_remote_"},
|
||||||
} {
|
} {
|
||||||
got := CheckConfigName(test.in)
|
problem := CheckConfigName(test.in)
|
||||||
assert.Equal(t, test.want, got, test.in)
|
assert.Equal(t, test.problem, problem, test.in)
|
||||||
|
fixed := MakeConfigName(test.in)
|
||||||
|
assert.Equal(t, test.fixed, fixed, test.in)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue