package limayaml
import (
"fmt"
"github.com/goccy/go-yaml"
"github.com/sirupsen/logrus"
"github.com/lima-vm/lima/v2/pkg/limatype"
"github.com/lima-vm/lima/v2/pkg/yqutil"
)
const (
documentStart = "---\n"
documentEnd = "...\n"
)
func Marshal(y *limatype.LimaYAML, stream bool) ([]byte, error) {
b, err := yaml.Marshal(y)
if err != nil {
return nil, err
}
if stream {
doc := documentStart + string(b) + documentEnd
b = []byte(doc)
}
return b, nil
}
func unmarshalDisk(dst *limatype.Disk, b []byte) error {
var s string
if err := yaml.Unmarshal(b, &s); err == nil {
*dst = limatype.Disk{Name: s}
return nil
}
return yaml.Unmarshal(b, dst)
}
func unmarshalBaseTemplates(dst *limatype.BaseTemplates, b []byte) error {
var s string
if err := yaml.Unmarshal(b, &s); err == nil {
*dst = limatype.BaseTemplates{limatype.LocatorWithDigest{URL: s}}
return nil
}
return yaml.UnmarshalWithOptions(b, dst, yaml.CustomUnmarshaler[limatype.LocatorWithDigest](unmarshalLocatorWithDigest))
}
func unmarshalLocatorWithDigest(dst *limatype.LocatorWithDigest, b []byte) error {
var s string
if err := yaml.Unmarshal(b, &s); err == nil {
*dst = limatype.LocatorWithDigest{URL: s}
return nil
}
return yaml.Unmarshal(b, dst)
}
func Unmarshal(data []byte, y *limatype.LimaYAML, comment string) error {
opts := []yaml.DecodeOption{
yaml.CustomUnmarshaler[limatype.BaseTemplates](unmarshalBaseTemplates),
yaml.CustomUnmarshaler[limatype.Disk](unmarshalDisk),
yaml.CustomUnmarshaler[limatype.LocatorWithDigest](unmarshalLocatorWithDigest),
}
if err := yaml.UnmarshalWithOptions(data, y, opts...); err != nil {
return fmt.Errorf("failed to unmarshal YAML (%s): %w", comment, err)
}
if err := yqutil.ValidateContent(data); err != nil {
return fmt.Errorf("failed to unmarshal YAML (%s): %w", comment, err)
}
opts = append(opts, yaml.Strict())
var ignore limatype.LimaYAML
if err := yaml.UnmarshalWithOptions(data, &ignore, opts...); err != nil {
logrus.WithField("comment", comment).WithError(err).Warn("Non-strict YAML detected; please check for typos")
}
return nil
}
func Convert(x, y any, comment string) error {
if x == nil {
return nil
}
b, err := yaml.Marshal(x)
if err != nil {
return err
}
err = yaml.Unmarshal(b, y)
if err != nil {
return fmt.Errorf("failed to unmarshal YAML (%s): %w", comment, err)
}
return nil
}