diff --git a/internal/plan/plan.go b/internal/plan/plan.go index 62d18007..5ab98472 100644 --- a/internal/plan/plan.go +++ b/internal/plan/plan.go @@ -70,10 +70,16 @@ const ( ) type StringVariable struct { - Name string `yaml:"name"` - Value string `yaml:"value"` + Name string + Value string } +// Ensure we're implementing both the custom unmarshaler and marshaller. Note +// that the unmarshaller is on *StringVariable, but the marshaller needs to be +// on the non-pointer type. +var _ yaml.Unmarshaler = &StringVariable{} +var _ yaml.Marshaler = StringVariable{} + func (sv *StringVariable) UnmarshalYAML(node *yaml.Node) error { if node.ShortTag() != "!!map" || len(node.Content) != 2 { return fmt.Errorf("environment must be a list of single-item maps (- name: value)") @@ -91,6 +97,10 @@ func (sv *StringVariable) UnmarshalYAML(node *yaml.Node) error { return nil } +func (sv StringVariable) MarshalYAML() (interface{}, error) { + return map[string]string{sv.Name: sv.Value}, nil +} + // CombineLayers combines the given layers into a Plan, with the later layers // layers overriding earlier ones. func CombineLayers(layers ...*Layer) (*Layer, error) { diff --git a/internal/plan/plan_test.go b/internal/plan/plan_test.go index fccda71a..f1043c02 100644 --- a/internal/plan/plan_test.go +++ b/internal/plan/plan_test.go @@ -23,9 +23,10 @@ import ( "path/filepath" "strings" - "github.com/canonical/pebble/internal/plan" - . "gopkg.in/check.v1" + "gopkg.in/yaml.v3" + + "github.com/canonical/pebble/internal/plan" ) // TODOs: @@ -33,7 +34,7 @@ import ( // - error on invalid keys // - constraints on service names -// The YAML on tests below passes throught this function to deindent and +// The YAML on tests below passes through this function to deindent and // replace tabs by spaces, so we can keep the code here sane. func reindent(in string) []byte { var buf bytes.Buffer @@ -478,3 +479,37 @@ func (s *S) TestReadDirDupNames(c *C) { } } } + +func (s *S) TestMarshalLayer(c *C) { + layerBytes := reindent(` + summary: Simple layer + description: A simple layer. + services: + srv1: + summary: Service summary + default: start + override: replace + command: cmd arg1 "arg2 arg3" + after: + - srv2 + before: + - srv3 + requires: + - srv2 + - srv3 + environment: + - var1: val1 + - var0: val0 + - var2: val2 + srv2: + override: replace + command: srv2cmd + srv3: + override: replace + command: srv3cmd`) + layer, err := plan.ParseLayer(1, "layer1", layerBytes) + c.Assert(err, IsNil) + out, err := yaml.Marshal(layer) + c.Assert(err, IsNil) + c.Assert(string(out), Equals, string(layerBytes)) +}