Skip to content

Commit

Permalink
Merge pull request #2726 from jandubois/lima-marshal
Browse files Browse the repository at this point in the history
Refactor limayaml.Save and store.SaveYAML → limayaml.Marshal
  • Loading branch information
AkihiroSuda authored Oct 13, 2024
2 parents 46aa594 + 2edcf1c commit 11eb750
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 82 deletions.
3 changes: 2 additions & 1 deletion cmd/limactl/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

"github.com/lima-vm/lima/cmd/limactl/guessarg"
"github.com/lima-vm/lima/pkg/limayaml"
"github.com/lima-vm/lima/pkg/store"
"github.com/spf13/cobra"

Expand Down Expand Up @@ -38,7 +39,7 @@ func validateAction(cmd *cobra.Command, args []string) error {
}
logrus.Infof("%q: OK", f)
if fill {
b, err := store.SaveYAML(y, len(args) > 1)
b, err := limayaml.Marshal(y, len(args) > 1)
if err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/limayaml/limayaml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const emptyYAML = "images: []\n"
func TestEmptyYAML(t *testing.T) {
var y LimaYAML
t.Log(dumpJSON(t, y))
b, err := marshalYAML(y)
b, err := Marshal(&y, false)
assert.NilError(t, err)
assert.Equal(t, string(b), emptyYAML)
}
Expand All @@ -32,12 +32,12 @@ func TestDefaultYAML(t *testing.T) {
bytes, err := os.ReadFile("default.yaml")
assert.NilError(t, err)
var y LimaYAML
err = unmarshalYAML(bytes, &y, "")
err = Unmarshal(bytes, &y, "")
assert.NilError(t, err)
y.Images = nil // remove default images
y.Mounts = nil // remove default mounts
t.Log(dumpJSON(t, y))
b, err := marshalYAML(y)
b, err := Marshal(&y, false)
assert.NilError(t, err)
assert.Equal(t, string(b), defaultYAML)
}
34 changes: 3 additions & 31 deletions pkg/limayaml/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,18 @@ import (
"os"
"path/filepath"

"github.com/goccy/go-yaml"
"github.com/lima-vm/lima/pkg/store/dirnames"
"github.com/lima-vm/lima/pkg/store/filenames"
"github.com/lima-vm/lima/pkg/yqutil"
"github.com/sirupsen/logrus"
)

func unmarshalDisk(dst *Disk, b []byte) error {
var s string
if err := yaml.Unmarshal(b, &s); err == nil {
*dst = Disk{Name: s}
return nil
}
return yaml.Unmarshal(b, dst)
}

func unmarshalYAML(data []byte, v interface{}, comment string) error {
if err := yaml.UnmarshalWithOptions(data, v, yaml.DisallowDuplicateKey(), yaml.CustomUnmarshaler[Disk](unmarshalDisk)); err != nil {
return fmt.Errorf("failed to unmarshal YAML (%s): %w", comment, err)
}
// the go-yaml library doesn't catch all markup errors, unfortunately
// make sure to get a "second opinion", using the same library as "yq"
if err := yqutil.ValidateContent(data); err != nil {
return fmt.Errorf("failed to unmarshal YAML (%s): %w", comment, err)
}
if err := yaml.UnmarshalWithOptions(data, v, yaml.Strict(), yaml.CustomUnmarshaler[Disk](unmarshalDisk)); err != nil {
logrus.WithField("comment", comment).WithError(err).Warn("Non-strict YAML is deprecated and will be unsupported in a future version of Lima")
// Non-strict YAML is known to be used by Rancher Desktop:
// https://github.com/rancher-sandbox/rancher-desktop/blob/c7ea7508a0191634adf16f4675f64c73198e8d37/src/backend/lima.ts#L114-L117
}
return nil
}

// Load loads the yaml and fulfills unspecified fields with the default values.
//
// Load does not validate. Use Validate for validation.
func Load(b []byte, filePath string) (*LimaYAML, error) {
var y, d, o LimaYAML

if err := unmarshalYAML(b, &y, fmt.Sprintf("main file %q", filePath)); err != nil {
if err := Unmarshal(b, &y, fmt.Sprintf("main file %q", filePath)); err != nil {
return nil, err
}
configDir, err := dirnames.LimaConfigDir()
Expand All @@ -57,7 +29,7 @@ func Load(b []byte, filePath string) (*LimaYAML, error) {
bytes, err := os.ReadFile(defaultPath)
if err == nil {
logrus.Debugf("Mixing %q into %q", defaultPath, filePath)
if err := unmarshalYAML(bytes, &d, fmt.Sprintf("default file %q", defaultPath)); err != nil {
if err := Unmarshal(bytes, &d, fmt.Sprintf("default file %q", defaultPath)); err != nil {
return nil, err
}
} else if !errors.Is(err, os.ErrNotExist) {
Expand All @@ -68,7 +40,7 @@ func Load(b []byte, filePath string) (*LimaYAML, error) {
bytes, err = os.ReadFile(overridePath)
if err == nil {
logrus.Debugf("Mixing %q into %q", overridePath, filePath)
if err := unmarshalYAML(bytes, &o, fmt.Sprintf("override file %q", overridePath)); err != nil {
if err := Unmarshal(bytes, &o, fmt.Sprintf("override file %q", overridePath)); err != nil {
return nil, err
}
} else if !errors.Is(err, os.ErrNotExist) {
Expand Down
62 changes: 62 additions & 0 deletions pkg/limayaml/marshal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package limayaml

import (
"fmt"

"github.com/goccy/go-yaml"
"github.com/lima-vm/lima/pkg/yqutil"
"github.com/sirupsen/logrus"
)

func marshalString(s string) ([]byte, error) {
if s == "null" || s == "~" {
// work around go-yaml bugs
return []byte("\"" + s + "\""), nil
}
return yaml.Marshal(s)
}

const (
documentStart = "---\n"
documentEnd = "...\n"
)

// Marshal the struct as a YAML document, optionally as a stream.
func Marshal(y *LimaYAML, stream bool) ([]byte, error) {
options := []yaml.EncodeOption{yaml.CustomMarshaler[string](marshalString)}
b, err := yaml.MarshalWithOptions(y, options...)
if err != nil {
return nil, err
}
if stream {
doc := documentStart + string(b) + documentEnd
b = []byte(doc)
}
return b, nil
}

func unmarshalDisk(dst *Disk, b []byte) error {
var s string
if err := yaml.Unmarshal(b, &s); err == nil {
*dst = Disk{Name: s}
return nil
}
return yaml.Unmarshal(b, dst)
}

func Unmarshal(data []byte, v interface{}, comment string) error {
if err := yaml.UnmarshalWithOptions(data, v, yaml.DisallowDuplicateKey(), yaml.CustomUnmarshaler[Disk](unmarshalDisk)); err != nil {
return fmt.Errorf("failed to unmarshal YAML (%s): %w", comment, err)
}
// the go-yaml library doesn't catch all markup errors, unfortunately
// make sure to get a "second opinion", using the same library as "yq"
if err := yqutil.ValidateContent(data); err != nil {
return fmt.Errorf("failed to unmarshal YAML (%s): %w", comment, err)
}
if err := yaml.UnmarshalWithOptions(data, v, yaml.Strict(), yaml.CustomUnmarshaler[Disk](unmarshalDisk)); err != nil {
logrus.WithField("comment", comment).WithError(err).Warn("Non-strict YAML is deprecated and will be unsupported in a future version of Lima")
// Non-strict YAML is known to be used by Rancher Desktop:
// https://github.com/rancher-sandbox/rancher-desktop/blob/c7ea7508a0191634adf16f4675f64c73198e8d37/src/backend/lima.ts#L114-L117
}
return nil
}
12 changes: 7 additions & 5 deletions pkg/limayaml/save_test.go → pkg/limayaml/marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,31 @@ import (
"gotest.tools/v3/assert"
)

func TestSaveEmpty(t *testing.T) {
_, err := Save(&LimaYAML{})
func TestMarshalEmpty(t *testing.T) {
_, err := Marshal(&LimaYAML{}, false)
assert.NilError(t, err)
}

func TestSaveTilde(t *testing.T) {
func TestMarshalTilde(t *testing.T) {
y := LimaYAML{
Mounts: []Mount{
{Location: "~", Writable: ptr.Of(false)},
{Location: "/tmp/lima", Writable: ptr.Of(true)},
{Location: "null"},
},
}
b, err := Save(&y)
b, err := Marshal(&y, true)
assert.NilError(t, err)
// yaml will load ~ (or null) as null
// make sure that it is always quoted
assert.Equal(t, string(b), `images: []
assert.Equal(t, string(b), `---
images: []
mounts:
- location: "~"
writable: false
- location: /tmp/lima
writable: true
- location: "null"
...
`)
}
25 changes: 0 additions & 25 deletions pkg/limayaml/save.go

This file was deleted.

17 changes: 0 additions & 17 deletions pkg/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,20 +133,3 @@ func LoadYAMLByFilePath(filePath string) (*limayaml.LimaYAML, error) {
}
return y, nil
}

const documentStart = "---\n"

const documentEnd = "...\n"

// SaveYAML saves the yaml, optionally as a stream.
func SaveYAML(y *limayaml.LimaYAML, stream bool) ([]byte, error) {
b, err := limayaml.Save(y)
if err != nil {
return nil, err
}
if stream {
doc := documentStart + string(b) + documentEnd
b = []byte(doc)
}
return b, nil
}

0 comments on commit 11eb750

Please sign in to comment.