podman
450 строк · 10.9 Кб
1// Copyright 2015 go-swagger maintainers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package swag16
17import (18"encoding/json"19"fmt"20"path/filepath"21"strconv"22
23"github.com/mailru/easyjson/jlexer"24"github.com/mailru/easyjson/jwriter"25yaml "gopkg.in/yaml.v3"26)
27
28// YAMLMatcher matches yaml
29func YAMLMatcher(path string) bool {30ext := filepath.Ext(path)31return ext == ".yaml" || ext == ".yml"32}
33
34// YAMLToJSON converts YAML unmarshaled data into json compatible data
35func YAMLToJSON(data interface{}) (json.RawMessage, error) {36jm, err := transformData(data)37if err != nil {38return nil, err39}40b, err := WriteJSON(jm)41return json.RawMessage(b), err42}
43
44// BytesToYAMLDoc converts a byte slice into a YAML document
45func BytesToYAMLDoc(data []byte) (interface{}, error) {46var document yaml.Node // preserve order that is present in the document47if err := yaml.Unmarshal(data, &document); err != nil {48return nil, err49}50if document.Kind != yaml.DocumentNode || len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode {51return nil, fmt.Errorf("only YAML documents that are objects are supported")52}53return &document, nil54}
55
56func yamlNode(root *yaml.Node) (interface{}, error) {57switch root.Kind {58case yaml.DocumentNode:59return yamlDocument(root)60case yaml.SequenceNode:61return yamlSequence(root)62case yaml.MappingNode:63return yamlMapping(root)64case yaml.ScalarNode:65return yamlScalar(root)66case yaml.AliasNode:67return yamlNode(root.Alias)68default:69return nil, fmt.Errorf("unsupported YAML node type: %v", root.Kind)70}71}
72
73func yamlDocument(node *yaml.Node) (interface{}, error) {74if len(node.Content) != 1 {75return nil, fmt.Errorf("unexpected YAML Document node content length: %d", len(node.Content))76}77return yamlNode(node.Content[0])78}
79
80func yamlMapping(node *yaml.Node) (interface{}, error) {81m := make(JSONMapSlice, len(node.Content)/2)82
83var j int84for i := 0; i < len(node.Content); i += 2 {85var nmi JSONMapItem86k, err := yamlStringScalarC(node.Content[i])87if err != nil {88return nil, fmt.Errorf("unable to decode YAML map key: %w", err)89}90nmi.Key = k91v, err := yamlNode(node.Content[i+1])92if err != nil {93return nil, fmt.Errorf("unable to process YAML map value for key %q: %w", k, err)94}95nmi.Value = v96m[j] = nmi97j++98}99return m, nil100}
101
102func yamlSequence(node *yaml.Node) (interface{}, error) {103s := make([]interface{}, 0)104
105for i := 0; i < len(node.Content); i++ {106
107v, err := yamlNode(node.Content[i])108if err != nil {109return nil, fmt.Errorf("unable to decode YAML sequence value: %w", err)110}111s = append(s, v)112}113return s, nil114}
115
116const ( // See https://yaml.org/type/117yamlStringScalar = "tag:yaml.org,2002:str"118yamlIntScalar = "tag:yaml.org,2002:int"119yamlBoolScalar = "tag:yaml.org,2002:bool"120yamlFloatScalar = "tag:yaml.org,2002:float"121yamlTimestamp = "tag:yaml.org,2002:timestamp"122yamlNull = "tag:yaml.org,2002:null"123)
124
125func yamlScalar(node *yaml.Node) (interface{}, error) {126switch node.LongTag() {127case yamlStringScalar:128return node.Value, nil129case yamlBoolScalar:130b, err := strconv.ParseBool(node.Value)131if err != nil {132return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting bool content: %w", node.Value, err)133}134return b, nil135case yamlIntScalar:136i, err := strconv.ParseInt(node.Value, 10, 64)137if err != nil {138return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting integer content: %w", node.Value, err)139}140return i, nil141case yamlFloatScalar:142f, err := strconv.ParseFloat(node.Value, 64)143if err != nil {144return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting float content: %w", node.Value, err)145}146return f, nil147case yamlTimestamp:148return node.Value, nil149case yamlNull:150return nil, nil151default:152return nil, fmt.Errorf("YAML tag %q is not supported", node.LongTag())153}154}
155
156func yamlStringScalarC(node *yaml.Node) (string, error) {157if node.Kind != yaml.ScalarNode {158return "", fmt.Errorf("expecting a string scalar but got %q", node.Kind)159}160switch node.LongTag() {161case yamlStringScalar, yamlIntScalar, yamlFloatScalar:162return node.Value, nil163default:164return "", fmt.Errorf("YAML tag %q is not supported as map key", node.LongTag())165}166}
167
168// JSONMapSlice represent a JSON object, with the order of keys maintained
169type JSONMapSlice []JSONMapItem170
171// MarshalJSON renders a JSONMapSlice as JSON
172func (s JSONMapSlice) MarshalJSON() ([]byte, error) {173w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}174s.MarshalEasyJSON(w)175return w.BuildBytes()176}
177
178// MarshalEasyJSON renders a JSONMapSlice as JSON, using easyJSON
179func (s JSONMapSlice) MarshalEasyJSON(w *jwriter.Writer) {180w.RawByte('{')181
182ln := len(s)183last := ln - 1184for i := 0; i < ln; i++ {185s[i].MarshalEasyJSON(w)186if i != last { // last item187w.RawByte(',')188}189}190
191w.RawByte('}')192}
193
194// UnmarshalJSON makes a JSONMapSlice from JSON
195func (s *JSONMapSlice) UnmarshalJSON(data []byte) error {196l := jlexer.Lexer{Data: data}197s.UnmarshalEasyJSON(&l)198return l.Error()199}
200
201// UnmarshalEasyJSON makes a JSONMapSlice from JSON, using easyJSON
202func (s *JSONMapSlice) UnmarshalEasyJSON(in *jlexer.Lexer) {203if in.IsNull() {204in.Skip()205return206}207
208var result JSONMapSlice209in.Delim('{')210for !in.IsDelim('}') {211var mi JSONMapItem212mi.UnmarshalEasyJSON(in)213result = append(result, mi)214}215*s = result216}
217
218func (s JSONMapSlice) MarshalYAML() (interface{}, error) {219var n yaml.Node220n.Kind = yaml.DocumentNode221var nodes []*yaml.Node222for _, item := range s {223nn, err := json2yaml(item.Value)224if err != nil {225return nil, err226}227ns := []*yaml.Node{228{229Kind: yaml.ScalarNode,230Tag: yamlStringScalar,231Value: item.Key,232},233nn,234}235nodes = append(nodes, ns...)236}237
238n.Content = []*yaml.Node{239{240Kind: yaml.MappingNode,241Content: nodes,242},243}244
245return yaml.Marshal(&n)246}
247
248func json2yaml(item interface{}) (*yaml.Node, error) {249switch val := item.(type) {250case JSONMapSlice:251var n yaml.Node252n.Kind = yaml.MappingNode253for i := range val {254childNode, err := json2yaml(&val[i].Value)255if err != nil {256return nil, err257}258n.Content = append(n.Content, &yaml.Node{259Kind: yaml.ScalarNode,260Tag: yamlStringScalar,261Value: val[i].Key,262}, childNode)263}264return &n, nil265case map[string]interface{}:266var n yaml.Node267n.Kind = yaml.MappingNode268for k, v := range val {269childNode, err := json2yaml(v)270if err != nil {271return nil, err272}273n.Content = append(n.Content, &yaml.Node{274Kind: yaml.ScalarNode,275Tag: yamlStringScalar,276Value: k,277}, childNode)278}279return &n, nil280case []interface{}:281var n yaml.Node282n.Kind = yaml.SequenceNode283for i := range val {284childNode, err := json2yaml(val[i])285if err != nil {286return nil, err287}288n.Content = append(n.Content, childNode)289}290return &n, nil291case string:292return &yaml.Node{293Kind: yaml.ScalarNode,294Tag: yamlStringScalar,295Value: val,296}, nil297case float64:298return &yaml.Node{299Kind: yaml.ScalarNode,300Tag: yamlFloatScalar,301Value: strconv.FormatFloat(val, 'f', -1, 64),302}, nil303case int64:304return &yaml.Node{305Kind: yaml.ScalarNode,306Tag: yamlIntScalar,307Value: strconv.FormatInt(val, 10),308}, nil309case uint64:310return &yaml.Node{311Kind: yaml.ScalarNode,312Tag: yamlIntScalar,313Value: strconv.FormatUint(val, 10),314}, nil315case bool:316return &yaml.Node{317Kind: yaml.ScalarNode,318Tag: yamlBoolScalar,319Value: strconv.FormatBool(val),320}, nil321}322return nil, nil323}
324
325// JSONMapItem represents the value of a key in a JSON object held by JSONMapSlice
326type JSONMapItem struct {327Key string328Value interface{}329}
330
331// MarshalJSON renders a JSONMapItem as JSON
332func (s JSONMapItem) MarshalJSON() ([]byte, error) {333w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}334s.MarshalEasyJSON(w)335return w.BuildBytes()336}
337
338// MarshalEasyJSON renders a JSONMapItem as JSON, using easyJSON
339func (s JSONMapItem) MarshalEasyJSON(w *jwriter.Writer) {340w.String(s.Key)341w.RawByte(':')342w.Raw(WriteJSON(s.Value))343}
344
345// UnmarshalJSON makes a JSONMapItem from JSON
346func (s *JSONMapItem) UnmarshalJSON(data []byte) error {347l := jlexer.Lexer{Data: data}348s.UnmarshalEasyJSON(&l)349return l.Error()350}
351
352// UnmarshalEasyJSON makes a JSONMapItem from JSON, using easyJSON
353func (s *JSONMapItem) UnmarshalEasyJSON(in *jlexer.Lexer) {354key := in.UnsafeString()355in.WantColon()356value := in.Interface()357in.WantComma()358s.Key = key359s.Value = value360}
361
362func transformData(input interface{}) (out interface{}, err error) {363format := func(t interface{}) (string, error) {364switch k := t.(type) {365case string:366return k, nil367case uint:368return strconv.FormatUint(uint64(k), 10), nil369case uint8:370return strconv.FormatUint(uint64(k), 10), nil371case uint16:372return strconv.FormatUint(uint64(k), 10), nil373case uint32:374return strconv.FormatUint(uint64(k), 10), nil375case uint64:376return strconv.FormatUint(k, 10), nil377case int:378return strconv.Itoa(k), nil379case int8:380return strconv.FormatInt(int64(k), 10), nil381case int16:382return strconv.FormatInt(int64(k), 10), nil383case int32:384return strconv.FormatInt(int64(k), 10), nil385case int64:386return strconv.FormatInt(k, 10), nil387default:388return "", fmt.Errorf("unexpected map key type, got: %T", k)389}390}391
392switch in := input.(type) {393case yaml.Node:394return yamlNode(&in)395case *yaml.Node:396return yamlNode(in)397case map[interface{}]interface{}:398o := make(JSONMapSlice, 0, len(in))399for ke, va := range in {400var nmi JSONMapItem401if nmi.Key, err = format(ke); err != nil {402return nil, err403}404
405v, ert := transformData(va)406if ert != nil {407return nil, ert408}409nmi.Value = v410o = append(o, nmi)411}412return o, nil413case []interface{}:414len1 := len(in)415o := make([]interface{}, len1)416for i := 0; i < len1; i++ {417o[i], err = transformData(in[i])418if err != nil {419return nil, err420}421}422return o, nil423}424return input, nil425}
426
427// YAMLDoc loads a yaml document from either http or a file and converts it to json
428func YAMLDoc(path string) (json.RawMessage, error) {429yamlDoc, err := YAMLData(path)430if err != nil {431return nil, err432}433
434data, err := YAMLToJSON(yamlDoc)435if err != nil {436return nil, err437}438
439return data, nil440}
441
442// YAMLData loads a yaml document from either http or a file
443func YAMLData(path string) (interface{}, error) {444data, err := LoadFromFileOrHTTP(path)445if err != nil {446return nil, err447}448
449return BytesToYAMLDoc(data)450}
451