Use strings.Cut instead of strings.Split* where possible #76

Merged
acid-ant merged 1 commit from improve/65-use-cut-insteadof-split into master 2023-02-28 10:39:15 +00:00
11 changed files with 69 additions and 72 deletions
Showing only changes of commit 95e799ed05 - Show all commits

View file

@ -141,13 +141,13 @@ func setConfigCmd(cmd *cobra.Command, args []string) error {
}
func parseConfigPair(kvStr string, force bool) (key string, val any, err error) {
kv := strings.SplitN(kvStr, "=", 2)
if len(kv) != 2 {
k, v, found := strings.Cut(kvStr, "=")
if !found {
return "", nil, fmt.Errorf("invalid parameter format: must be 'key=val', got: %s", kvStr)
}
key = kv[0]
valRaw := kv[1]
key = k
valRaw := v
switch key {
case netmapAuditFeeKey, netmapBasicIncomeRateKey,
@ -162,7 +162,7 @@ func parseConfigPair(kvStr string, force bool) (key string, val any, err error)
case netmapEigenTrustAlphaKey:
// just check that it could
// be parsed correctly
_, err = strconv.ParseFloat(kv[1], 64)
_, err = strconv.ParseFloat(v, 64)
if err != nil {
err = fmt.Errorf("could not parse %s's value '%s' as float: %w", key, valRaw, err)
}

View file

@ -27,23 +27,23 @@ func setPolicyCmd(cmd *cobra.Command, args []string) error {
bw := io.NewBufBinWriter()
for i := range args {
kv := strings.SplitN(args[i], "=", 2)
if len(kv) != 2 {
k, v, found := strings.Cut(args[i], "=")
if !found {
return fmt.Errorf("invalid parameter format, must be Parameter=Value")
}
switch kv[0] {
switch k {
case execFeeParam, storagePriceParam, setFeeParam:
default:
return fmt.Errorf("parameter must be one of %s, %s and %s", execFeeParam, storagePriceParam, setFeeParam)
}
value, err := strconv.ParseUint(kv[1], 10, 32)
value, err := strconv.ParseUint(v, 10, 32)
if err != nil {
return fmt.Errorf("can't parse parameter value '%s': %w", args[1], err)
}
emit.AppCall(bw.BinWriter, policy.Hash, "set"+kv[0], callflag.All, int64(value))
emit.AppCall(bw.BinWriter, policy.Hash, "set"+k, callflag.All, int64(value))
}
if err := wCtx.sendCommitteeTx(bw.Bytes(), false); err != nil {

View file

@ -197,12 +197,12 @@ func parseContainerPolicy(cmd *cobra.Command, policyString string) (*netmap.Plac
func parseAttributes(dst *container.Container, attributes []string) error {
for i := range attributes {
kvPair := strings.Split(attributes[i], attributeDelimiter)
if len(kvPair) != 2 {
k, v, found := strings.Cut(attributes[i], attributeDelimiter)
if !found {
return errors.New("invalid container attribute")
}
dst.SetAttribute(kvPair[0], kvPair[1])
dst.SetAttribute(k, v)
}
if !containerNoTimestamp {
dstepanov-yadro commented 2023-02-27 14:52:25 +00:00 (Migrated from github.com)
Review

I suppose attribute key=value=value is not valid, but after this it will pass check.
image

I suppose attribute `key=value=value` is not valid, but after this it will pass check. ![image](https://user-images.githubusercontent.com/125876766/221595977-22eb48c8-171e-490d-b4f7-96d661bae234.png)
acid-ant commented 2023-02-28 07:02:19 +00:00 (Migrated from github.com)
Review

Agree, but there are no restriction in the sdk for the content of the key or value. it should be non empty only. The idea of the cli is to be as simple as it can, @fyrchik correct me if I'm wrong.

Agree, but there are no restriction in the sdk for the content of the key or value. it should be non empty only. The idea of the cli is to be as simple as it can, @fyrchik correct me if I'm wrong.
fyrchik commented 2023-02-28 07:22:27 +00:00 (Migrated from github.com)
Review

Most likely, it was a bug. API gives no restrictions on container value https://github.com/TrueCloudLab/frostfs-api/blob/master/container/types.proto#L30

Most likely, it was a bug. API gives no restrictions on container value https://github.com/TrueCloudLab/frostfs-api/blob/master/container/types.proto#L30

View file

@ -179,12 +179,12 @@ func parseObjectAttrs(cmd *cobra.Command) ([]object.Attribute, error) {
attrs := make([]object.Attribute, len(rawAttrs), len(rawAttrs)+2) // name + timestamp attributes
for i := range rawAttrs {
kv := strings.SplitN(rawAttrs[i], "=", 2)
if len(kv) != 2 {
k, v, found := strings.Cut(rawAttrs[i], "=")
if !found {
return nil, fmt.Errorf("invalid attribute format: %s", rawAttrs[i])
}
attrs[i].SetKey(kv[0])
attrs[i].SetValue(kv[1])
attrs[i].SetKey(k)
attrs[i].SetValue(v)
}
disableFilename, _ := cmd.Flags().GetBool("disable-filename")
@ -218,26 +218,26 @@ func parseObjectNotifications(cmd *cobra.Command) (*object.NotificationInfo, err
return nil, nil
}
rawSlice := strings.SplitN(raw, separator, 2)
if len(rawSlice) != 2 {
before, after, found := strings.Cut(raw, separator)
if !found {
return nil, fmt.Errorf("notification must be in the form of: *epoch*%s*topic*, got %s", separator, raw)
}
ni := new(object.NotificationInfo)
epoch, err := strconv.ParseUint(rawSlice[0], 10, 64)
epoch, err := strconv.ParseUint(before, 10, 64)
if err != nil {
return nil, fmt.Errorf("could not parse notification epoch %s: %w", rawSlice[0], err)
return nil, fmt.Errorf("could not parse notification epoch %s: %w", before, err)
}
ni.SetEpoch(epoch)
if rawSlice[1] == "" {
if after == "" {
return nil, fmt.Errorf("incorrect empty topic: use %s to force using default topic", useDefaultTopic)
}
if rawSlice[1] != useDefaultTopic {
ni.SetTopic(rawSlice[1])
if after != useDefaultTopic {
ni.SetTopic(after)
}
return ni, nil

View file

@ -154,16 +154,16 @@ func getRangeList(cmd *cobra.Command) ([]*object.Range, error) {
vs := strings.Split(v, ",")
rs := make([]*object.Range, len(vs))
for i := range vs {
r := strings.Split(vs[i], rangeSep)
if len(r) != 2 {
before, after, found := strings.Cut(vs[i], rangeSep)
if !found {
return nil, fmt.Errorf("invalid range specifier: %s", vs[i])
}
offset, err := strconv.ParseUint(r[0], 10, 64)
offset, err := strconv.ParseUint(before, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid '%s' range offset specifier: %w", vs[i], err)
}
length, err := strconv.ParseUint(r[1], 10, 64)
length, err := strconv.ParseUint(after, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid '%s' range length specifier: %w", vs[i], err)
}

View file

@ -63,12 +63,12 @@ func parseXHeaders(cmd *cobra.Command) []string {
xs := make([]string, 0, 2*len(xHeaders))
for i := range xHeaders {
kv := strings.SplitN(xHeaders[i], "=", 2)
if len(kv) != 2 {
k, v, found := strings.Cut(xHeaders[i], "=")
if !found {
panic(fmt.Errorf("invalid X-Header format: %s", xHeaders[i]))
}
xs = append(xs, kv[0], kv[1])
xs = append(xs, k, v)
}
return xs

View file

@ -79,14 +79,14 @@ func parseMeta(cmd *cobra.Command) ([]*tree.KeyValue, error) {
pairs := make([]*tree.KeyValue, 0, len(raws))
for i := range raws {
kv := strings.SplitN(raws[i], "=", 2)
if len(kv) != 2 {
k, v, found := strings.Cut(raws[i], "=")
if !found {
return nil, fmt.Errorf("invalid meta pair format: %s", raws[i])
}
var pair tree.KeyValue
pair.Key = kv[0]
pair.Value = []byte(kv[1])
pair.Key = k
pair.Value = []byte(v)
pairs = append(pairs, &pair)
}

View file

@ -226,35 +226,32 @@ func parseEACLTable(tb *eacl.Table, args []string) error {
fyrchik commented 2023-02-28 07:29:08 +00:00 (Migrated from github.com)
Review

Can use Cut here too.

Can use `Cut` here too.
acid-ant commented 2023-02-28 08:12:06 +00:00 (Migrated from github.com)
Review

Done.

Done.
func parseEACLRecord(args []string) (*eacl.Record, error) {
r := new(eacl.Record)
for i := range args {
ss := strings.SplitN(args[i], ":", 2)
for _, arg := range args {
before, after, found := strings.Cut(arg, ":")
switch prefix := strings.ToLower(ss[0]); prefix {
switch prefix := strings.ToLower(before); prefix {
case "req", "obj": // filters
if len(ss) != 2 {
return nil, fmt.Errorf("invalid filter or target: %s", args[i])
}
i := strings.Index(ss[1], "=")
if i < 0 {
return nil, fmt.Errorf("invalid filter key-value pair: %s", ss[1])
if !found {
return nil, fmt.Errorf("invalid filter or target: %s", arg)
}
var key, value string
var op eacl.Match
var f bool
if 0 < i && ss[1][i-1] == '!' {
key = ss[1][:i-1]
key, value, f = strings.Cut(after, "!=")
if f {
op = eacl.MatchStringNotEqual
} else {
key = ss[1][:i]
key, value, f = strings.Cut(after, "=")
if !f {
return nil, fmt.Errorf("invalid filter key-value pair: %s", after)
}
op = eacl.MatchStringEqual
}
value = ss[1][i+1:]
typ := eacl.HeaderFromRequest
if ss[0] == "obj" {
if before == "obj" {
typ = eacl.HeaderFromObject
}
@ -263,8 +260,8 @@ func parseEACLRecord(args []string) (*eacl.Record, error) {
var err error
var pubs []ecdsa.PublicKey
if len(ss) == 2 {
pubs, err = parseKeyList(ss[1])
if found {
pubs, err = parseKeyList(after)
if err != nil {
return nil, err
}
@ -281,7 +278,7 @@ func parseEACLRecord(args []string) (*eacl.Record, error) {
eacl.AddFormedTarget(r, role, pubs...)
default:
return nil, fmt.Errorf("invalid prefix: %s", ss[0])
return nil, fmt.Errorf("invalid prefix: %s", before)
}
}

View file

@ -65,14 +65,14 @@ func loadEnv(path string) {
scanner := bufio.NewScanner(f)
for scanner.Scan() {
pair := strings.SplitN(scanner.Text(), "=", 2)
if len(pair) != 2 {
k, v, found := strings.Cut(scanner.Text(), "=")
if !found {
continue
}
pair[1] = strings.Trim(pair[1], `"`)
v = strings.Trim(v, `"`)
err = os.Setenv(pair[0], pair[1])
err = os.Setenv(k, v)
if err != nil {
panic("can't set environment variable")
}

View file

@ -73,18 +73,18 @@ func stringifyAddress(addr oid.Address) string {
}
func addressFromString(s string) (oid.Address, error) {
i := strings.IndexByte(s, '.')
if i == -1 {
before, after, found := strings.Cut(s, ".")
if !found {
return oid.Address{}, errors.New("invalid address")
}
var obj oid.ID
if err := obj.DecodeString(s[:i]); err != nil {
if err := obj.DecodeString(before); err != nil {
return oid.Address{}, err
}
var cnr cid.ID
if err := cnr.DecodeString(s[i+1:]); err != nil {
if err := cnr.DecodeString(after); err != nil {
return oid.Address{}, err
}

View file

@ -19,29 +19,29 @@ func ReadNodeAttributes(dst *netmap.NodeInfo, attrs []string) error {
for i := range attrs {
line := replaceEscaping(attrs[i], false) // replaced escaped symbols with non-printable symbols
words := strings.Split(line, keyValueSeparator)
if len(words) != 2 {
k, v, found := strings.Cut(line, keyValueSeparator)
if !found {
return errors.New("missing attribute key and/or value")
}
dstepanov-yadro commented 2023-02-27 15:00:21 +00:00 (Migrated from github.com)
Review

Maybe if !found || len(k) == 0 || len(v) == 0 will be better?

Maybe `if !found || len(k) == 0 || len(v) == 0` will be better?
acid-ant commented 2023-02-28 08:04:47 +00:00 (Migrated from github.com)
Review

We already have this check in sdk.

We already have this check in sdk.
_, ok := cache[words[0]]
_, ok := cache[k]
if ok {
return fmt.Errorf("duplicated keys %s", words[0])
return fmt.Errorf("duplicated keys %s", k)
}
cache[words[0]] = struct{}{}
cache[k] = struct{}{}
// replace non-printable symbols with escaped symbols without escape character
words[0] = replaceEscaping(words[0], true)
words[1] = replaceEscaping(words[1], true)
k = replaceEscaping(k, true)
v = replaceEscaping(v, true)
if words[0] == "" {
if k == "" {
return errors.New("empty key")
} else if words[1] == "" {
} else if v == "" {
return errors.New("empty value")
}
dst.SetAttribute(words[0], words[1])
dst.SetAttribute(k, v)
}
return nil