Skip to content

Commit 1613111

Browse files
committed
config,validate: allow config types to conflict based on key prefix
This allows some schema types to specify a key prefix for which keys matching said prefix should conflict. This is used by a subsequent commit where a directory is populated from an archive, and any file, directory, or link whose path is under the original directory should conflict.
1 parent e1edd80 commit 1613111

File tree

2 files changed

+29
-0
lines changed

2 files changed

+29
-0
lines changed

config/util/interfaces.go

+12
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,22 @@ type Keyed interface {
3030
Key() string
3131
}
3232

33+
type KeyPrefixed interface {
34+
KeyPrefix() string
35+
}
36+
3337
// CallKey is a helper to call the Key() function since this needs to happen a lot
3438
func CallKey(v reflect.Value) string {
3539
if v.Kind() == reflect.String {
3640
return v.Convert(reflect.TypeOf("")).Interface().(string)
3741
}
3842
return v.Interface().(Keyed).Key()
3943
}
44+
45+
// CallKeyPrefix is a helper to call the KeyPrefix() method, or fall back to Key().
46+
func CallKeyPrefix(v reflect.Value) string {
47+
if prefixable, ok := v.Interface().(KeyPrefixed); ok {
48+
return prefixable.KeyPrefix()
49+
}
50+
return ""
51+
}

config/validate/validate.go

+17
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package validate
1717
import (
1818
"fmt"
1919
"reflect"
20+
"strings"
2021

2122
"github.com/coreos/ignition/v2/config/shared/errors"
2223
"github.com/coreos/ignition/v2/config/util"
@@ -33,6 +34,12 @@ func ValidateDups(v reflect.Value, c path.ContextPath) (r report.Report) {
3334
return
3435
}
3536
dupsLists := map[string]map[string]struct{}{}
37+
38+
// This should probably be a collection of prefix trees, but this would
39+
// either require implementing one or adding a new dependency for what
40+
// amounts to a minute amount of gain in performance, given that we do
41+
// not have thousands of key prefixes to manage.
42+
prefixLists := map[string][]string{}
3643
ignoreDups := map[string]struct{}{}
3744
if i, ok := v.Interface().(util.IgnoresDups); ok {
3845
ignoreDups = i.IgnoreDuplicates()
@@ -59,13 +66,23 @@ func ValidateDups(v reflect.Value, c path.ContextPath) (r report.Report) {
5966
dupsLists[dupListName] = make(map[string]struct{}, field.Value.Len())
6067
dupList = dupsLists[dupListName]
6168
}
69+
prefixList := prefixLists[dupListName]
6270
for i := 0; i < field.Value.Len(); i++ {
6371
key := util.CallKey(field.Value.Index(i))
6472
if _, isDup := dupList[key]; isDup {
6573
r.AddOnError(c.Append(validate.FieldName(field, c.Tag), i), errors.ErrDuplicate)
6674
}
75+
for _, prefix := range prefixList {
76+
if strings.HasPrefix(key, prefix) {
77+
r.AddOnError(c.Append(validate.FieldName(field, c.Tag), i), errors.ErrDuplicate)
78+
}
79+
}
80+
if prefix := util.CallKeyPrefix(field.Value.Index(i)); prefix != "" {
81+
prefixList = append(prefixList, prefix)
82+
}
6783
dupList[key] = struct{}{}
6884
}
85+
prefixLists[dupListName] = prefixList
6986
}
7087
return
7188
}

0 commit comments

Comments
 (0)