forked from TrueCloudLab/restic
backend, options: Prefer strings.Cut to SplitN
Also realigned the various "split into host🪣prefix"
implementations.
This commit is contained in:
parent
60aa87bbab
commit
65612d797c
9 changed files with 56 additions and 66 deletions
|
@ -43,14 +43,13 @@ func ParseConfig(s string) (interface{}, error) {
|
|||
|
||||
// use the first entry of the path as the bucket name and the
|
||||
// remainder as prefix
|
||||
data := strings.SplitN(s, ":", 2)
|
||||
if len(data) < 2 {
|
||||
container, prefix, colon := strings.Cut(s, ":")
|
||||
if !colon {
|
||||
return nil, errors.New("azure: invalid format: bucket name or path not found")
|
||||
}
|
||||
container, path := data[0], path.Clean(data[1])
|
||||
path = strings.TrimPrefix(path, "/")
|
||||
prefix = strings.TrimPrefix(path.Clean(prefix), "/")
|
||||
cfg := NewConfig()
|
||||
cfg.Container = container
|
||||
cfg.Prefix = path
|
||||
cfg.Prefix = prefix
|
||||
return cfg, nil
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ var bucketName = regexp.MustCompile("^[a-zA-Z0-9-]+$")
|
|||
// https://help.backblaze.com/hc/en-us/articles/217666908-What-you-need-to-know-about-B2-Bucket-names
|
||||
func checkBucketName(name string) error {
|
||||
if name == "" {
|
||||
return errors.New("bucket name is empty")
|
||||
return errors.New("bucket name not found")
|
||||
}
|
||||
|
||||
if len(name) < 6 {
|
||||
|
@ -64,30 +64,18 @@ func ParseConfig(s string) (interface{}, error) {
|
|||
}
|
||||
|
||||
s = s[3:]
|
||||
data := strings.SplitN(s, ":", 2)
|
||||
if len(data) == 0 || len(data[0]) == 0 {
|
||||
return nil, errors.New("bucket name not found")
|
||||
}
|
||||
|
||||
cfg := NewConfig()
|
||||
cfg.Bucket = data[0]
|
||||
|
||||
if err := checkBucketName(cfg.Bucket); err != nil {
|
||||
bucket, prefix, _ := strings.Cut(s, ":")
|
||||
if err := checkBucketName(bucket); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(data) == 2 {
|
||||
p := data[1]
|
||||
if len(p) > 0 {
|
||||
p = path.Clean(p)
|
||||
}
|
||||
|
||||
if len(p) > 0 && path.IsAbs(p) {
|
||||
p = p[1:]
|
||||
}
|
||||
|
||||
cfg.Prefix = p
|
||||
if len(prefix) > 0 {
|
||||
prefix = strings.TrimPrefix(path.Clean(prefix), "/")
|
||||
}
|
||||
|
||||
cfg := NewConfig()
|
||||
cfg.Bucket = bucket
|
||||
cfg.Prefix = prefix
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
|
|
@ -42,17 +42,15 @@ func ParseConfig(s string) (interface{}, error) {
|
|||
|
||||
// use the first entry of the path as the bucket name and the
|
||||
// remainder as prefix
|
||||
data := strings.SplitN(s, ":", 2)
|
||||
if len(data) < 2 {
|
||||
bucket, prefix, colon := strings.Cut(s, ":")
|
||||
if !colon {
|
||||
return nil, errors.New("gs: invalid format: bucket name or path not found")
|
||||
}
|
||||
|
||||
bucket, path := data[0], path.Clean(data[1])
|
||||
|
||||
path = strings.TrimPrefix(path, "/")
|
||||
prefix = strings.TrimPrefix(path.Clean(prefix), "/")
|
||||
|
||||
cfg := NewConfig()
|
||||
cfg.Bucket = bucket
|
||||
cfg.Prefix = path
|
||||
cfg.Prefix = prefix
|
||||
return cfg, nil
|
||||
}
|
||||
|
|
|
@ -127,6 +127,6 @@ func StripPassword(s string) string {
|
|||
}
|
||||
|
||||
func extractScheme(s string) string {
|
||||
data := strings.SplitN(s, ":", 2)
|
||||
return data[0]
|
||||
scheme, _, _ := strings.Cut(s, ":")
|
||||
return scheme
|
||||
}
|
||||
|
|
|
@ -59,8 +59,8 @@ func ParseConfig(s string) (interface{}, error) {
|
|||
return nil, errors.New("s3: bucket name not found")
|
||||
}
|
||||
|
||||
path := strings.SplitN(url.Path[1:], "/", 2)
|
||||
return createConfig(url.Host, path, url.Scheme == "http")
|
||||
bucket, path, _ := strings.Cut(url.Path[1:], "/")
|
||||
return createConfig(url.Host, bucket, path, url.Scheme == "http")
|
||||
case strings.HasPrefix(s, "s3://"):
|
||||
s = s[5:]
|
||||
case strings.HasPrefix(s, "s3:"):
|
||||
|
@ -70,24 +70,24 @@ func ParseConfig(s string) (interface{}, error) {
|
|||
}
|
||||
// use the first entry of the path as the endpoint and the
|
||||
// remainder as bucket name and prefix
|
||||
path := strings.SplitN(s, "/", 3)
|
||||
return createConfig(path[0], path[1:], false)
|
||||
endpoint, rest, _ := strings.Cut(s, "/")
|
||||
bucket, prefix, _ := strings.Cut(rest, "/")
|
||||
return createConfig(endpoint, bucket, prefix, false)
|
||||
}
|
||||
|
||||
func createConfig(endpoint string, p []string, useHTTP bool) (interface{}, error) {
|
||||
if len(p) < 1 {
|
||||
func createConfig(endpoint, bucket, prefix string, useHTTP bool) (interface{}, error) {
|
||||
if endpoint == "" {
|
||||
return nil, errors.New("s3: invalid format, host/region or bucket name not found")
|
||||
}
|
||||
|
||||
var prefix string
|
||||
if len(p) > 1 && p[1] != "" {
|
||||
prefix = path.Clean(p[1])
|
||||
if prefix != "" {
|
||||
prefix = path.Clean(prefix)
|
||||
}
|
||||
|
||||
cfg := NewConfig()
|
||||
cfg.Endpoint = endpoint
|
||||
cfg.UseHTTP = useHTTP
|
||||
cfg.Bucket = p[0]
|
||||
cfg.Bucket = bucket
|
||||
cfg.Prefix = prefix
|
||||
return cfg, nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package s3
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var configTests = []struct {
|
||||
s string
|
||||
|
@ -111,3 +114,14 @@ func TestParseConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseError(t *testing.T) {
|
||||
const prefix = "s3: invalid format,"
|
||||
|
||||
for _, s := range []string{"", "/", "//", "/bucket/prefix"} {
|
||||
_, err := ParseConfig("s3://" + s)
|
||||
if err == nil || !strings.HasPrefix(err.Error(), prefix) {
|
||||
t.Errorf("expected %q, got %q", prefix, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,14 +60,13 @@ func ParseConfig(s string) (interface{}, error) {
|
|||
// "user@host:path" in s
|
||||
s = s[5:]
|
||||
// split user@host and path at the colon
|
||||
data := strings.SplitN(s, ":", 2)
|
||||
if len(data) < 2 {
|
||||
var colon bool
|
||||
host, dir, colon = strings.Cut(s, ":")
|
||||
if !colon {
|
||||
return nil, errors.New("sftp: invalid format, hostname or path not found")
|
||||
}
|
||||
host = data[0]
|
||||
dir = data[1]
|
||||
// split user and host at the "@"
|
||||
data = strings.SplitN(host, "@", 3)
|
||||
data := strings.SplitN(host, "@", 3)
|
||||
if len(data) == 3 {
|
||||
user = data[0] + "@" + data[1]
|
||||
host = data[2]
|
||||
|
|
|
@ -51,17 +51,13 @@ func NewConfig() Config {
|
|||
|
||||
// ParseConfig parses the string s and extract swift's container name and prefix.
|
||||
func ParseConfig(s string) (interface{}, error) {
|
||||
data := strings.SplitN(s, ":", 3)
|
||||
if len(data) != 3 {
|
||||
if !strings.HasPrefix(s, "swift:") {
|
||||
return nil, errors.New("invalid URL, expected: swift:container-name:/[prefix]")
|
||||
}
|
||||
s = strings.TrimPrefix(s, "swift:")
|
||||
|
||||
scheme, container, prefix := data[0], data[1], data[2]
|
||||
if scheme != "swift" {
|
||||
return nil, errors.Errorf("unexpected prefix: %s", data[0])
|
||||
}
|
||||
|
||||
if len(prefix) == 0 {
|
||||
container, prefix, _ := strings.Cut(s, ":")
|
||||
if prefix == "" {
|
||||
return nil, errors.Errorf("prefix is empty")
|
||||
}
|
||||
|
||||
|
|
|
@ -92,14 +92,10 @@ func (h helpList) Swap(i, j int) {
|
|||
|
||||
// splitKeyValue splits at the first equals (=) sign.
|
||||
func splitKeyValue(s string) (key string, value string) {
|
||||
data := strings.SplitN(s, "=", 2)
|
||||
key = strings.ToLower(strings.TrimSpace(data[0]))
|
||||
if len(data) == 1 {
|
||||
// no equals sign is treated as the empty value
|
||||
return key, ""
|
||||
}
|
||||
|
||||
return key, strings.TrimSpace(data[1])
|
||||
key, value, _ = strings.Cut(s, "=")
|
||||
key = strings.ToLower(strings.TrimSpace(key))
|
||||
value = strings.TrimSpace(value)
|
||||
return key, value
|
||||
}
|
||||
|
||||
// Parse takes a slice of key=value pairs and returns an Options type.
|
||||
|
|
Loading…
Reference in a new issue