...

Source file src/sigs.k8s.io/structured-merge-diff/v4/typed/parser.go

Documentation: sigs.k8s.io/structured-merge-diff/v4/typed

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package typed
    18  
    19  import (
    20  	"fmt"
    21  
    22  	yaml "gopkg.in/yaml.v2"
    23  	"sigs.k8s.io/structured-merge-diff/v4/schema"
    24  	"sigs.k8s.io/structured-merge-diff/v4/value"
    25  )
    26  
    27  // YAMLObject is an object encoded in YAML.
    28  type YAMLObject string
    29  
    30  // Parser implements YAMLParser and allows introspecting the schema.
    31  type Parser struct {
    32  	Schema schema.Schema
    33  }
    34  
    35  // create builds an unvalidated parser.
    36  func create(s YAMLObject) (*Parser, error) {
    37  	p := Parser{}
    38  	err := yaml.Unmarshal([]byte(s), &p.Schema)
    39  	return &p, err
    40  }
    41  
    42  func createOrDie(schema YAMLObject) *Parser {
    43  	p, err := create(schema)
    44  	if err != nil {
    45  		panic(fmt.Errorf("failed to create parser: %v", err))
    46  	}
    47  	return p
    48  }
    49  
    50  var ssParser = createOrDie(YAMLObject(schema.SchemaSchemaYAML))
    51  
    52  // NewParser will build a YAMLParser from a schema. The schema is validated.
    53  func NewParser(schema YAMLObject) (*Parser, error) {
    54  	_, err := ssParser.Type("schema").FromYAML(schema)
    55  	if err != nil {
    56  		return nil, fmt.Errorf("unable to validate schema: %v", err)
    57  	}
    58  	p, err := create(schema)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	return p, nil
    63  }
    64  
    65  // TypeNames returns a list of types this parser understands.
    66  func (p *Parser) TypeNames() (names []string) {
    67  	for _, td := range p.Schema.Types {
    68  		names = append(names, td.Name)
    69  	}
    70  	return names
    71  }
    72  
    73  // Type returns a helper which can produce objects of the given type. Any
    74  // errors are deferred until a further function is called.
    75  func (p *Parser) Type(name string) ParseableType {
    76  	return ParseableType{
    77  		Schema:  &p.Schema,
    78  		TypeRef: schema.TypeRef{NamedType: &name},
    79  	}
    80  }
    81  
    82  // ParseableType allows for easy production of typed objects.
    83  type ParseableType struct {
    84  	TypeRef schema.TypeRef
    85  	Schema  *schema.Schema
    86  }
    87  
    88  // IsValid return true if p's schema and typename are valid.
    89  func (p ParseableType) IsValid() bool {
    90  	_, ok := p.Schema.Resolve(p.TypeRef)
    91  	return ok
    92  }
    93  
    94  // FromYAML parses a yaml string into an object with the current schema
    95  // and the type "typename" or an error if validation fails.
    96  func (p ParseableType) FromYAML(object YAMLObject, opts ...ValidationOptions) (*TypedValue, error) {
    97  	var v interface{}
    98  	err := yaml.Unmarshal([]byte(object), &v)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	return AsTyped(value.NewValueInterface(v), p.Schema, p.TypeRef, opts...)
   103  }
   104  
   105  // FromUnstructured converts a go "interface{}" type, typically an
   106  // unstructured object in Kubernetes world, to a TypedValue. It returns an
   107  // error if the resulting object fails schema validation.
   108  // The provided interface{} must be one of: map[string]interface{},
   109  // map[interface{}]interface{}, []interface{}, int types, float types,
   110  // string or boolean. Nested interface{} must also be one of these types.
   111  func (p ParseableType) FromUnstructured(in interface{}, opts ...ValidationOptions) (*TypedValue, error) {
   112  	return AsTyped(value.NewValueInterface(in), p.Schema, p.TypeRef, opts...)
   113  }
   114  
   115  // FromStructured converts a go "interface{}" type, typically an structured object in
   116  // Kubernetes, to a TypedValue. It will return an error if the resulting object fails
   117  // schema validation. The provided "interface{}" value must be a pointer so that the
   118  // value can be modified via reflection. The provided "interface{}" may contain structs
   119  // and types that are converted to Values by the jsonMarshaler interface.
   120  func (p ParseableType) FromStructured(in interface{}, opts ...ValidationOptions) (*TypedValue, error) {
   121  	v, err := value.NewValueReflect(in)
   122  	if err != nil {
   123  		return nil, fmt.Errorf("error creating struct value reflector: %v", err)
   124  	}
   125  	return AsTyped(v, p.Schema, p.TypeRef, opts...)
   126  }
   127  
   128  // DeducedParseableType is a ParseableType that deduces the type from
   129  // the content of the object.
   130  var DeducedParseableType ParseableType = createOrDie(YAMLObject(`types:
   131  - name: __untyped_atomic_
   132    scalar: untyped
   133    list:
   134      elementType:
   135        namedType: __untyped_atomic_
   136      elementRelationship: atomic
   137    map:
   138      elementType:
   139        namedType: __untyped_atomic_
   140      elementRelationship: atomic
   141  - name: __untyped_deduced_
   142    scalar: untyped
   143    list:
   144      elementType:
   145        namedType: __untyped_atomic_
   146      elementRelationship: atomic
   147    map:
   148      elementType:
   149        namedType: __untyped_deduced_
   150      elementRelationship: separable
   151  `)).Type("__untyped_deduced_")
   152  

View as plain text