Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lima-vm
GitHub Repository: lima-vm/lima
Path: blob/master/pkg/limayaml/marshal.go
2608 views
1
// SPDX-FileCopyrightText: Copyright The Lima Authors
2
// SPDX-License-Identifier: Apache-2.0
3
4
package limayaml
5
6
import (
7
"fmt"
8
9
"github.com/goccy/go-yaml"
10
"github.com/sirupsen/logrus"
11
12
"github.com/lima-vm/lima/v2/pkg/limatype"
13
"github.com/lima-vm/lima/v2/pkg/yqutil"
14
)
15
16
const (
17
documentStart = "---\n"
18
documentEnd = "...\n"
19
)
20
21
// Marshal the struct as a YAML document, optionally as a stream.
22
func Marshal(y *limatype.LimaYAML, stream bool) ([]byte, error) {
23
b, err := yaml.Marshal(y)
24
if err != nil {
25
return nil, err
26
}
27
if stream {
28
doc := documentStart + string(b) + documentEnd
29
b = []byte(doc)
30
}
31
return b, nil
32
}
33
34
func unmarshalDisk(dst *limatype.Disk, b []byte) error {
35
var s string
36
if err := yaml.Unmarshal(b, &s); err == nil {
37
*dst = limatype.Disk{Name: s}
38
return nil
39
}
40
return yaml.Unmarshal(b, dst)
41
}
42
43
// unmarshalBaseTemplates unmarshalls `base` which is either a string or a list of Locators.
44
func unmarshalBaseTemplates(dst *limatype.BaseTemplates, b []byte) error {
45
var s string
46
if err := yaml.Unmarshal(b, &s); err == nil {
47
*dst = limatype.BaseTemplates{limatype.LocatorWithDigest{URL: s}}
48
return nil
49
}
50
return yaml.UnmarshalWithOptions(b, dst, yaml.CustomUnmarshaler[limatype.LocatorWithDigest](unmarshalLocatorWithDigest))
51
}
52
53
// unmarshalLocator unmarshalls a locator which is either a string or a Locator struct.
54
func unmarshalLocatorWithDigest(dst *limatype.LocatorWithDigest, b []byte) error {
55
var s string
56
if err := yaml.Unmarshal(b, &s); err == nil {
57
*dst = limatype.LocatorWithDigest{URL: s}
58
return nil
59
}
60
return yaml.Unmarshal(b, dst)
61
}
62
63
func Unmarshal(data []byte, y *limatype.LimaYAML, comment string) error {
64
opts := []yaml.DecodeOption{
65
yaml.CustomUnmarshaler[limatype.BaseTemplates](unmarshalBaseTemplates),
66
yaml.CustomUnmarshaler[limatype.Disk](unmarshalDisk),
67
yaml.CustomUnmarshaler[limatype.LocatorWithDigest](unmarshalLocatorWithDigest),
68
}
69
if err := yaml.UnmarshalWithOptions(data, y, opts...); err != nil {
70
return fmt.Errorf("failed to unmarshal YAML (%s): %w", comment, err)
71
}
72
// The go-yaml library doesn't catch all markup errors, unfortunately
73
// make sure to get a "second opinion", using the same library as "yq"
74
if err := yqutil.ValidateContent(data); err != nil {
75
return fmt.Errorf("failed to unmarshal YAML (%s): %w", comment, err)
76
}
77
// Finally log a warning if the YAML file violates the "strict" rules
78
opts = append(opts, yaml.Strict())
79
var ignore limatype.LimaYAML
80
if err := yaml.UnmarshalWithOptions(data, &ignore, opts...); err != nil {
81
logrus.WithField("comment", comment).WithError(err).Warn("Non-strict YAML detected; please check for typos")
82
}
83
return nil
84
}
85
86
// Convert converts from x to y, using YAML.
87
// If x is nil, then y is left unmodified.
88
func Convert(x, y any, comment string) error {
89
if x == nil {
90
return nil
91
}
92
b, err := yaml.Marshal(x)
93
if err != nil {
94
return err
95
}
96
err = yaml.Unmarshal(b, y)
97
if err != nil {
98
return fmt.Errorf("failed to unmarshal YAML (%s): %w", comment, err)
99
}
100
return nil
101
}
102
103