podman

Форк
0
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

15
package swag
16

17
import (
18
	"encoding/json"
19
	"fmt"
20
	"path/filepath"
21
	"strconv"
22

23
	"github.com/mailru/easyjson/jlexer"
24
	"github.com/mailru/easyjson/jwriter"
25
	yaml "gopkg.in/yaml.v3"
26
)
27

28
// YAMLMatcher matches yaml
29
func YAMLMatcher(path string) bool {
30
	ext := filepath.Ext(path)
31
	return ext == ".yaml" || ext == ".yml"
32
}
33

34
// YAMLToJSON converts YAML unmarshaled data into json compatible data
35
func YAMLToJSON(data interface{}) (json.RawMessage, error) {
36
	jm, err := transformData(data)
37
	if err != nil {
38
		return nil, err
39
	}
40
	b, err := WriteJSON(jm)
41
	return json.RawMessage(b), err
42
}
43

44
// BytesToYAMLDoc converts a byte slice into a YAML document
45
func BytesToYAMLDoc(data []byte) (interface{}, error) {
46
	var document yaml.Node // preserve order that is present in the document
47
	if err := yaml.Unmarshal(data, &document); err != nil {
48
		return nil, err
49
	}
50
	if document.Kind != yaml.DocumentNode || len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode {
51
		return nil, fmt.Errorf("only YAML documents that are objects are supported")
52
	}
53
	return &document, nil
54
}
55

56
func yamlNode(root *yaml.Node) (interface{}, error) {
57
	switch root.Kind {
58
	case yaml.DocumentNode:
59
		return yamlDocument(root)
60
	case yaml.SequenceNode:
61
		return yamlSequence(root)
62
	case yaml.MappingNode:
63
		return yamlMapping(root)
64
	case yaml.ScalarNode:
65
		return yamlScalar(root)
66
	case yaml.AliasNode:
67
		return yamlNode(root.Alias)
68
	default:
69
		return nil, fmt.Errorf("unsupported YAML node type: %v", root.Kind)
70
	}
71
}
72

73
func yamlDocument(node *yaml.Node) (interface{}, error) {
74
	if len(node.Content) != 1 {
75
		return nil, fmt.Errorf("unexpected YAML Document node content length: %d", len(node.Content))
76
	}
77
	return yamlNode(node.Content[0])
78
}
79

80
func yamlMapping(node *yaml.Node) (interface{}, error) {
81
	m := make(JSONMapSlice, len(node.Content)/2)
82

83
	var j int
84
	for i := 0; i < len(node.Content); i += 2 {
85
		var nmi JSONMapItem
86
		k, err := yamlStringScalarC(node.Content[i])
87
		if err != nil {
88
			return nil, fmt.Errorf("unable to decode YAML map key: %w", err)
89
		}
90
		nmi.Key = k
91
		v, err := yamlNode(node.Content[i+1])
92
		if err != nil {
93
			return nil, fmt.Errorf("unable to process YAML map value for key %q: %w", k, err)
94
		}
95
		nmi.Value = v
96
		m[j] = nmi
97
		j++
98
	}
99
	return m, nil
100
}
101

102
func yamlSequence(node *yaml.Node) (interface{}, error) {
103
	s := make([]interface{}, 0)
104

105
	for i := 0; i < len(node.Content); i++ {
106

107
		v, err := yamlNode(node.Content[i])
108
		if err != nil {
109
			return nil, fmt.Errorf("unable to decode YAML sequence value: %w", err)
110
		}
111
		s = append(s, v)
112
	}
113
	return s, nil
114
}
115

116
const ( // See https://yaml.org/type/
117
	yamlStringScalar = "tag:yaml.org,2002:str"
118
	yamlIntScalar    = "tag:yaml.org,2002:int"
119
	yamlBoolScalar   = "tag:yaml.org,2002:bool"
120
	yamlFloatScalar  = "tag:yaml.org,2002:float"
121
	yamlTimestamp    = "tag:yaml.org,2002:timestamp"
122
	yamlNull         = "tag:yaml.org,2002:null"
123
)
124

125
func yamlScalar(node *yaml.Node) (interface{}, error) {
126
	switch node.LongTag() {
127
	case yamlStringScalar:
128
		return node.Value, nil
129
	case yamlBoolScalar:
130
		b, err := strconv.ParseBool(node.Value)
131
		if err != nil {
132
			return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting bool content: %w", node.Value, err)
133
		}
134
		return b, nil
135
	case yamlIntScalar:
136
		i, err := strconv.ParseInt(node.Value, 10, 64)
137
		if err != nil {
138
			return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting integer content: %w", node.Value, err)
139
		}
140
		return i, nil
141
	case yamlFloatScalar:
142
		f, err := strconv.ParseFloat(node.Value, 64)
143
		if err != nil {
144
			return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting float content: %w", node.Value, err)
145
		}
146
		return f, nil
147
	case yamlTimestamp:
148
		return node.Value, nil
149
	case yamlNull:
150
		return nil, nil
151
	default:
152
		return nil, fmt.Errorf("YAML tag %q is not supported", node.LongTag())
153
	}
154
}
155

156
func yamlStringScalarC(node *yaml.Node) (string, error) {
157
	if node.Kind != yaml.ScalarNode {
158
		return "", fmt.Errorf("expecting a string scalar but got %q", node.Kind)
159
	}
160
	switch node.LongTag() {
161
	case yamlStringScalar, yamlIntScalar, yamlFloatScalar:
162
		return node.Value, nil
163
	default:
164
		return "", 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
169
type JSONMapSlice []JSONMapItem
170

171
// MarshalJSON renders a JSONMapSlice as JSON
172
func (s JSONMapSlice) MarshalJSON() ([]byte, error) {
173
	w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}
174
	s.MarshalEasyJSON(w)
175
	return w.BuildBytes()
176
}
177

178
// MarshalEasyJSON renders a JSONMapSlice as JSON, using easyJSON
179
func (s JSONMapSlice) MarshalEasyJSON(w *jwriter.Writer) {
180
	w.RawByte('{')
181

182
	ln := len(s)
183
	last := ln - 1
184
	for i := 0; i < ln; i++ {
185
		s[i].MarshalEasyJSON(w)
186
		if i != last { // last item
187
			w.RawByte(',')
188
		}
189
	}
190

191
	w.RawByte('}')
192
}
193

194
// UnmarshalJSON makes a JSONMapSlice from JSON
195
func (s *JSONMapSlice) UnmarshalJSON(data []byte) error {
196
	l := jlexer.Lexer{Data: data}
197
	s.UnmarshalEasyJSON(&l)
198
	return l.Error()
199
}
200

201
// UnmarshalEasyJSON makes a JSONMapSlice from JSON, using easyJSON
202
func (s *JSONMapSlice) UnmarshalEasyJSON(in *jlexer.Lexer) {
203
	if in.IsNull() {
204
		in.Skip()
205
		return
206
	}
207

208
	var result JSONMapSlice
209
	in.Delim('{')
210
	for !in.IsDelim('}') {
211
		var mi JSONMapItem
212
		mi.UnmarshalEasyJSON(in)
213
		result = append(result, mi)
214
	}
215
	*s = result
216
}
217

218
func (s JSONMapSlice) MarshalYAML() (interface{}, error) {
219
	var n yaml.Node
220
	n.Kind = yaml.DocumentNode
221
	var nodes []*yaml.Node
222
	for _, item := range s {
223
		nn, err := json2yaml(item.Value)
224
		if err != nil {
225
			return nil, err
226
		}
227
		ns := []*yaml.Node{
228
			{
229
				Kind:  yaml.ScalarNode,
230
				Tag:   yamlStringScalar,
231
				Value: item.Key,
232
			},
233
			nn,
234
		}
235
		nodes = append(nodes, ns...)
236
	}
237

238
	n.Content = []*yaml.Node{
239
		{
240
			Kind:    yaml.MappingNode,
241
			Content: nodes,
242
		},
243
	}
244

245
	return yaml.Marshal(&n)
246
}
247

248
func json2yaml(item interface{}) (*yaml.Node, error) {
249
	switch val := item.(type) {
250
	case JSONMapSlice:
251
		var n yaml.Node
252
		n.Kind = yaml.MappingNode
253
		for i := range val {
254
			childNode, err := json2yaml(&val[i].Value)
255
			if err != nil {
256
				return nil, err
257
			}
258
			n.Content = append(n.Content, &yaml.Node{
259
				Kind:  yaml.ScalarNode,
260
				Tag:   yamlStringScalar,
261
				Value: val[i].Key,
262
			}, childNode)
263
		}
264
		return &n, nil
265
	case map[string]interface{}:
266
		var n yaml.Node
267
		n.Kind = yaml.MappingNode
268
		for k, v := range val {
269
			childNode, err := json2yaml(v)
270
			if err != nil {
271
				return nil, err
272
			}
273
			n.Content = append(n.Content, &yaml.Node{
274
				Kind:  yaml.ScalarNode,
275
				Tag:   yamlStringScalar,
276
				Value: k,
277
			}, childNode)
278
		}
279
		return &n, nil
280
	case []interface{}:
281
		var n yaml.Node
282
		n.Kind = yaml.SequenceNode
283
		for i := range val {
284
			childNode, err := json2yaml(val[i])
285
			if err != nil {
286
				return nil, err
287
			}
288
			n.Content = append(n.Content, childNode)
289
		}
290
		return &n, nil
291
	case string:
292
		return &yaml.Node{
293
			Kind:  yaml.ScalarNode,
294
			Tag:   yamlStringScalar,
295
			Value: val,
296
		}, nil
297
	case float64:
298
		return &yaml.Node{
299
			Kind:  yaml.ScalarNode,
300
			Tag:   yamlFloatScalar,
301
			Value: strconv.FormatFloat(val, 'f', -1, 64),
302
		}, nil
303
	case int64:
304
		return &yaml.Node{
305
			Kind:  yaml.ScalarNode,
306
			Tag:   yamlIntScalar,
307
			Value: strconv.FormatInt(val, 10),
308
		}, nil
309
	case uint64:
310
		return &yaml.Node{
311
			Kind:  yaml.ScalarNode,
312
			Tag:   yamlIntScalar,
313
			Value: strconv.FormatUint(val, 10),
314
		}, nil
315
	case bool:
316
		return &yaml.Node{
317
			Kind:  yaml.ScalarNode,
318
			Tag:   yamlBoolScalar,
319
			Value: strconv.FormatBool(val),
320
		}, nil
321
	}
322
	return nil, nil
323
}
324

325
// JSONMapItem represents the value of a key in a JSON object held by JSONMapSlice
326
type JSONMapItem struct {
327
	Key   string
328
	Value interface{}
329
}
330

331
// MarshalJSON renders a JSONMapItem as JSON
332
func (s JSONMapItem) MarshalJSON() ([]byte, error) {
333
	w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}
334
	s.MarshalEasyJSON(w)
335
	return w.BuildBytes()
336
}
337

338
// MarshalEasyJSON renders a JSONMapItem as JSON, using easyJSON
339
func (s JSONMapItem) MarshalEasyJSON(w *jwriter.Writer) {
340
	w.String(s.Key)
341
	w.RawByte(':')
342
	w.Raw(WriteJSON(s.Value))
343
}
344

345
// UnmarshalJSON makes a JSONMapItem from JSON
346
func (s *JSONMapItem) UnmarshalJSON(data []byte) error {
347
	l := jlexer.Lexer{Data: data}
348
	s.UnmarshalEasyJSON(&l)
349
	return l.Error()
350
}
351

352
// UnmarshalEasyJSON makes a JSONMapItem from JSON, using easyJSON
353
func (s *JSONMapItem) UnmarshalEasyJSON(in *jlexer.Lexer) {
354
	key := in.UnsafeString()
355
	in.WantColon()
356
	value := in.Interface()
357
	in.WantComma()
358
	s.Key = key
359
	s.Value = value
360
}
361

362
func transformData(input interface{}) (out interface{}, err error) {
363
	format := func(t interface{}) (string, error) {
364
		switch k := t.(type) {
365
		case string:
366
			return k, nil
367
		case uint:
368
			return strconv.FormatUint(uint64(k), 10), nil
369
		case uint8:
370
			return strconv.FormatUint(uint64(k), 10), nil
371
		case uint16:
372
			return strconv.FormatUint(uint64(k), 10), nil
373
		case uint32:
374
			return strconv.FormatUint(uint64(k), 10), nil
375
		case uint64:
376
			return strconv.FormatUint(k, 10), nil
377
		case int:
378
			return strconv.Itoa(k), nil
379
		case int8:
380
			return strconv.FormatInt(int64(k), 10), nil
381
		case int16:
382
			return strconv.FormatInt(int64(k), 10), nil
383
		case int32:
384
			return strconv.FormatInt(int64(k), 10), nil
385
		case int64:
386
			return strconv.FormatInt(k, 10), nil
387
		default:
388
			return "", fmt.Errorf("unexpected map key type, got: %T", k)
389
		}
390
	}
391

392
	switch in := input.(type) {
393
	case yaml.Node:
394
		return yamlNode(&in)
395
	case *yaml.Node:
396
		return yamlNode(in)
397
	case map[interface{}]interface{}:
398
		o := make(JSONMapSlice, 0, len(in))
399
		for ke, va := range in {
400
			var nmi JSONMapItem
401
			if nmi.Key, err = format(ke); err != nil {
402
				return nil, err
403
			}
404

405
			v, ert := transformData(va)
406
			if ert != nil {
407
				return nil, ert
408
			}
409
			nmi.Value = v
410
			o = append(o, nmi)
411
		}
412
		return o, nil
413
	case []interface{}:
414
		len1 := len(in)
415
		o := make([]interface{}, len1)
416
		for i := 0; i < len1; i++ {
417
			o[i], err = transformData(in[i])
418
			if err != nil {
419
				return nil, err
420
			}
421
		}
422
		return o, nil
423
	}
424
	return input, nil
425
}
426

427
// YAMLDoc loads a yaml document from either http or a file and converts it to json
428
func YAMLDoc(path string) (json.RawMessage, error) {
429
	yamlDoc, err := YAMLData(path)
430
	if err != nil {
431
		return nil, err
432
	}
433

434
	data, err := YAMLToJSON(yamlDoc)
435
	if err != nil {
436
		return nil, err
437
	}
438

439
	return data, nil
440
}
441

442
// YAMLData loads a yaml document from either http or a file
443
func YAMLData(path string) (interface{}, error) {
444
	data, err := LoadFromFileOrHTTP(path)
445
	if err != nil {
446
		return nil, err
447
	}
448

449
	return BytesToYAMLDoc(data)
450
}
451

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.