Files
kustomize/vendor/github.com/krishicks/yaml-patch/container.go
2018-08-30 13:45:25 -07:00

168 lines
2.9 KiB
Go

package yamlpatch
import (
"fmt"
"strconv"
"strings"
)
// Container is the interface for performing operations on Nodes
type Container interface {
Get(key string) (*Node, error)
Set(key string, val *Node) error
Add(key string, val *Node) error
Remove(key string) error
}
type nodeMap map[interface{}]*Node
func (n *nodeMap) Set(key string, val *Node) error {
(*n)[key] = val
return nil
}
func (n *nodeMap) Add(key string, val *Node) error {
(*n)[key] = val
return nil
}
func (n *nodeMap) Get(key string) (*Node, error) {
return (*n)[key], nil
}
func (n *nodeMap) Remove(key string) error {
_, ok := (*n)[key]
if !ok {
return fmt.Errorf("Unable to remove nonexistent key: %s", key)
}
delete(*n, key)
return nil
}
type nodeSlice []*Node
func (n *nodeSlice) Set(index string, val *Node) error {
i, err := strconv.Atoi(index)
if err != nil {
return err
}
sz := len(*n)
if i+1 > sz {
sz = i + 1
}
ary := make([]*Node, sz)
cur := *n
copy(ary, cur)
if i >= len(ary) {
return fmt.Errorf("Unable to access invalid index: %d", i)
}
ary[i] = val
*n = ary
return nil
}
func (n *nodeSlice) Add(index string, val *Node) error {
if index == "-" {
*n = append(*n, val)
return nil
}
i, err := strconv.Atoi(index)
if err != nil {
return err
}
ary := make([]*Node, len(*n)+1)
cur := *n
copy(ary[0:i], cur[0:i])
ary[i] = val
copy(ary[i+1:], cur[i:])
*n = ary
return nil
}
func (n *nodeSlice) Get(index string) (*Node, error) {
i, err := strconv.Atoi(index)
if err != nil {
return nil, err
}
if i >= 0 && i <= len(*n)-1 {
return (*n)[i], nil
}
return nil, fmt.Errorf("Unable to access invalid index: %d", i)
}
func (n *nodeSlice) Remove(index string) error {
i, err := strconv.Atoi(index)
if err != nil {
return err
}
cur := *n
if i >= len(cur) {
return fmt.Errorf("Unable to remove invalid index: %d", i)
}
ary := make([]*Node, len(cur)-1)
copy(ary[0:i], cur[0:i])
copy(ary[i:], cur[i+1:])
*n = ary
return nil
}
func findContainer(c Container, path *OpPath) (Container, string, error) {
parts, key, err := path.Decompose()
if err != nil {
return nil, "", err
}
foundContainer := c
for _, part := range parts {
node, err := foundContainer.Get(decodePatchKey(part))
if err != nil {
return nil, "", err
}
if node == nil {
return nil, "", fmt.Errorf("path does not exist: %s", path)
}
foundContainer = node.Container()
}
return foundContainer, decodePatchKey(key), nil
}
// From http://tools.ietf.org/html/rfc6901#section-4 :
//
// Evaluation of each reference token begins by decoding any escaped
// character sequence. This is performed by first transforming any
// occurrence of the sequence '~1' to '/', and then transforming any
// occurrence of the sequence '~0' to '~'.
var (
rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")
)
func decodePatchKey(k string) string {
return rfc6901Decoder.Replace(k)
}