mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-17 02:06:23 +00:00
Encode/Decode PathElement to/from strings
This commit is contained in:
committed by
jennybuckley
parent
16df5bb7bb
commit
df76269a30
8
Godeps/Godeps.json
generated
8
Godeps/Godeps.json
generated
@@ -4069,7 +4069,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
|
||||
"Rev": "01332b709372d8d83b4d7653b30a1961680a47d5"
|
||||
"Rev": "d45b5c336b0e2bdd0b58ae4181caba85f24c6257"
|
||||
},
|
||||
{
|
||||
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
|
||||
@@ -4077,15 +4077,15 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
|
||||
"Rev": "01332b709372d8d83b4d7653b30a1961680a47d5"
|
||||
"Rev": "d45b5c336b0e2bdd0b58ae4181caba85f24c6257"
|
||||
},
|
||||
{
|
||||
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
|
||||
"Rev": "01332b709372d8d83b4d7653b30a1961680a47d5"
|
||||
"Rev": "d45b5c336b0e2bdd0b58ae4181caba85f24c6257"
|
||||
},
|
||||
{
|
||||
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
|
||||
"Rev": "01332b709372d8d83b4d7653b30a1961680a47d5"
|
||||
"Rev": "d45b5c336b0e2bdd0b58ae4181caba85f24c6257"
|
||||
},
|
||||
{
|
||||
"ImportPath": "sigs.k8s.io/yaml",
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package apply
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/structured-merge-diff/fieldpath"
|
||||
"sigs.k8s.io/structured-merge-diff/value"
|
||||
)
|
||||
|
||||
const (
|
||||
Field = "f"
|
||||
Value = "v"
|
||||
Index = "i"
|
||||
Key = "k"
|
||||
|
||||
Separator = ":"
|
||||
)
|
||||
|
||||
func NewPathElement(s string) (fieldpath.PathElement, error) {
|
||||
split := strings.SplitN(s, Separator, 2)
|
||||
if len(split) < 2 {
|
||||
return fieldpath.PathElement{}, fmt.Errorf("missing colon: %v", s)
|
||||
}
|
||||
switch split[0] {
|
||||
case Field:
|
||||
return fieldpath.PathElement{
|
||||
FieldName: &split[1],
|
||||
}, nil
|
||||
case Value:
|
||||
val, err := value.FromJSON([]byte(split[1]))
|
||||
if err != nil {
|
||||
return fieldpath.PathElement{}, err
|
||||
}
|
||||
return fieldpath.PathElement{
|
||||
Value: &val,
|
||||
}, nil
|
||||
case Index:
|
||||
i, err := strconv.Atoi(split[1])
|
||||
if err != nil {
|
||||
return fieldpath.PathElement{}, err
|
||||
}
|
||||
return fieldpath.PathElement{
|
||||
Index: &i,
|
||||
}, nil
|
||||
case Key:
|
||||
kv := map[string]string{}
|
||||
err := json.Unmarshal([]byte(split[1]), &kv)
|
||||
if err != nil {
|
||||
return fieldpath.PathElement{}, err
|
||||
}
|
||||
fields := []value.Field{}
|
||||
for k, v := range kv {
|
||||
fmt.Println(v)
|
||||
val, err := value.FromJSON([]byte(v))
|
||||
if err != nil {
|
||||
return fieldpath.PathElement{}, err
|
||||
}
|
||||
|
||||
fields = append(fields, value.Field{
|
||||
Name: k,
|
||||
Value: val,
|
||||
})
|
||||
}
|
||||
return fieldpath.PathElement{
|
||||
Key: fields,
|
||||
}, nil
|
||||
default:
|
||||
// Ignore unknown key types
|
||||
return fieldpath.PathElement{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func PathElementString(pe fieldpath.PathElement) (string, error) {
|
||||
switch {
|
||||
case pe.FieldName != nil:
|
||||
return Field + Separator + *pe.FieldName, nil
|
||||
case len(pe.Key) > 0:
|
||||
kv := map[string]string{}
|
||||
for _, k := range pe.Key {
|
||||
b, err := k.Value.ToJSON()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
kv[k.Name] = string(b)
|
||||
}
|
||||
b, err := json.Marshal(kv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Key + ":" + string(b), nil
|
||||
case pe.Value != nil:
|
||||
b, err := pe.Value.ToJSON()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Value + ":" + string(b), nil
|
||||
case pe.Index != nil:
|
||||
return Index + ":" + strconv.Itoa(*pe.Index), nil
|
||||
default:
|
||||
return "", errors.New("Invalid type of path element")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package apply
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestPathElementRoundTrip(t *testing.T) {
|
||||
tests := []string{
|
||||
"i:0",
|
||||
"i:1234",
|
||||
"f:",
|
||||
"f:spec",
|
||||
"f:more-complicated-string",
|
||||
"k:{\"name\":\"\\\"my-container\\\"\"}",
|
||||
"k:{\"port\":\"\\\"8080\\\"\",\"protocol\":\"\\\"TCP\\\"\"}",
|
||||
"v:null",
|
||||
"v:\"some-string\"",
|
||||
"v:1234",
|
||||
"v:{\"some\":\"json\"}",
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test, func(t *testing.T) {
|
||||
pe, err := NewPathElement(test)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create path element: %v", err)
|
||||
}
|
||||
output, err := PathElementString(pe)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create string from path element: %v", err)
|
||||
}
|
||||
if test != output {
|
||||
t.Fatalf("Expected round-trip:\ninput: %v\noutput: %v", test, output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathElementIgnoreUnknown(t *testing.T) {
|
||||
_, err := NewPathElement("r:Hello")
|
||||
if err != nil {
|
||||
t.Fatalf("Unknown qualifiers should be ignored")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPathElementError(t *testing.T) {
|
||||
tests := []string{
|
||||
"",
|
||||
"no-colon",
|
||||
"i:index is not a number",
|
||||
"i:1.23",
|
||||
"i:",
|
||||
"v:invalid json",
|
||||
"v:",
|
||||
"k:invalid json",
|
||||
"k:{\"name\":\"invalid json\"}",
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test, func(t *testing.T) {
|
||||
_, err := NewPathElement(test)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error, no error found")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ go_library(
|
||||
srcs = [
|
||||
"gvkparser.go",
|
||||
"managedfields.go",
|
||||
"pathelement.go",
|
||||
"typeconverter.go",
|
||||
"versionconverter.go",
|
||||
],
|
||||
@@ -31,6 +32,7 @@ go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"managedfields_test.go",
|
||||
"pathelement_test.go",
|
||||
"typeconverter_test.go",
|
||||
"versionconverter_test.go",
|
||||
],
|
||||
|
||||
28
vendor/sigs.k8s.io/structured-merge-diff/value/unstructured.go
generated
vendored
28
vendor/sigs.k8s.io/structured-merge-diff/value/unstructured.go
generated
vendored
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package value
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
@@ -53,6 +54,21 @@ func FromYAML(input []byte) (Value, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// FromJSON is a helper function for reading a JSON document
|
||||
func FromJSON(input []byte) (Value, error) {
|
||||
var decoded interface{}
|
||||
|
||||
if err := json.Unmarshal(input, &decoded); err != nil {
|
||||
return Value{}, err
|
||||
}
|
||||
|
||||
v, err := FromUnstructured(decoded)
|
||||
if err != nil {
|
||||
return Value{}, fmt.Errorf("failed to interpret (%v):\n%s", err, input)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// FromUnstructured will convert a go interface to a Value.
|
||||
// It's most commonly expected to be used with map[string]interface{} as the
|
||||
// input. `in` must not have any structures with cycles in them.
|
||||
@@ -156,12 +172,12 @@ func FromUnstructured(in interface{}) (Value, error) {
|
||||
// preserve order of keys within maps/structs. This is as a convenience to
|
||||
// humans keeping YAML documents, not because there is a behavior difference.
|
||||
func (v *Value) ToYAML() ([]byte, error) {
|
||||
out := v.ToUnstructured(true)
|
||||
b, err := yaml.Marshal(out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
return yaml.Marshal(v.ToUnstructured(true))
|
||||
}
|
||||
|
||||
// ToJSON is a helper function for producing a JSon document.
|
||||
func (v *Value) ToJSON() ([]byte, error) {
|
||||
return json.Marshal(v.ToUnstructured(false))
|
||||
}
|
||||
|
||||
// ToUnstructured will convert the Value into a go-typed object.
|
||||
|
||||
Reference in New Issue
Block a user