Skip to content

Commit

Permalink
config,validate: allow config types to conflict based on key prefix
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Snaipe committed Nov 13, 2022
1 parent e1edd80 commit 5061abd
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 0 deletions.
12 changes: 12 additions & 0 deletions config/util/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,22 @@ type Keyed interface {
Key() string
}

type KeyPrefixed interface {
KeyPrefix() string
}

// CallKey is a helper to call the Key() function since this needs to happen a lot
func CallKey(v reflect.Value) string {
if v.Kind() == reflect.String {
return v.Convert(reflect.TypeOf("")).Interface().(string)
}
return v.Interface().(Keyed).Key()
}

// CallKeyPrefix is a helper to call the KeyPrefix() method.
func CallKeyPrefix(v reflect.Value) string {
if prefixable, ok := v.Interface().(KeyPrefixed); ok {
return prefixable.KeyPrefix()
}
return ""
}
17 changes: 17 additions & 0 deletions config/validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package validate
import (
"fmt"
"reflect"
"strings"

"github.com/coreos/ignition/v2/config/shared/errors"
"github.com/coreos/ignition/v2/config/util"
Expand All @@ -33,6 +34,12 @@ func ValidateDups(v reflect.Value, c path.ContextPath) (r report.Report) {
return
}
dupsLists := map[string]map[string]struct{}{}

// This should probably be a collection of prefix trees, but this would
// either require implementing one or adding a new dependency for what
// amounts to a minute amount of gain in performance, given that we do
// not have thousands of key prefixes to manage.
prefixLists := map[string][]string{}
ignoreDups := map[string]struct{}{}
if i, ok := v.Interface().(util.IgnoresDups); ok {
ignoreDups = i.IgnoreDuplicates()
Expand All @@ -59,13 +66,23 @@ func ValidateDups(v reflect.Value, c path.ContextPath) (r report.Report) {
dupsLists[dupListName] = make(map[string]struct{}, field.Value.Len())
dupList = dupsLists[dupListName]
}
prefixList := prefixLists[dupListName]
for i := 0; i < field.Value.Len(); i++ {
key := util.CallKey(field.Value.Index(i))
if _, isDup := dupList[key]; isDup {
r.AddOnError(c.Append(validate.FieldName(field, c.Tag), i), errors.ErrDuplicate)
}
for _, prefix := range prefixList {
if strings.HasPrefix(key, prefix) {
r.AddOnError(c.Append(validate.FieldName(field, c.Tag), i), errors.ErrDuplicate)
}
}
if prefix := util.CallKeyPrefix(field.Value.Index(i)); prefix != "" {
prefixList = append(prefixList, prefix)
}
dupList[key] = struct{}{}
}
prefixLists[dupListName] = prefixList
}
return
}
Expand Down

0 comments on commit 5061abd

Please sign in to comment.