diff --git a/client/plan.go b/client/plan.go index 25b447f0..9c34f58e 100644 --- a/client/plan.go +++ b/client/plan.go @@ -25,6 +25,11 @@ type AddLayerOptions struct { // has the given label. False (the default) means append a new layer. Combine bool + // Inner set to true means a new layer append may go into an existing + // subdirectory, even though it may not result in appending it + // to the end of the layers slice (it becomes an insert). + Inner bool + // Label is the label for the new layer if appending, and the label of the // layer to combine with if Combine is true. Label string @@ -38,16 +43,26 @@ func (client *Client) AddLayer(opts *AddLayerOptions) error { var payload = struct { Action string `json:"action"` Combine bool `json:"combine"` + Inner bool `json:"inner"` Label string `json:"label"` Format string `json:"format"` Layer string `json:"layer"` }{ Action: "add", Combine: opts.Combine, + Inner: opts.Inner, Label: opts.Label, Format: "yaml", Layer: string(opts.LayerData), } + + // Add label validation here once layer persistence is supported over + // the API. We cannot do this in the plan library because JUJU already + // has labels in production systems that violates the layers file + // naming convention (which includes the label). Since JUJU uses its + // own client, we can enforce the label naming convention on all other + // systems using the Pebble supplied client by validating it here. + var body bytes.Buffer if err := json.NewEncoder(&body).Encode(&payload); err != nil { return err diff --git a/client/plan_test.go b/client/plan_test.go index 385d6e20..38fd081a 100644 --- a/client/plan_test.go +++ b/client/plan_test.go @@ -24,7 +24,22 @@ import ( ) func (cs *clientSuite) TestAddLayer(c *check.C) { - for _, combine := range []bool{false, true} { + for _, option := range []struct { + combine bool + inner bool + }{{ + combine: false, + inner: false, + }, { + combine: true, + inner: false, + }, { + combine: false, + inner: true, + }, { + combine: true, + inner: true, + }} { cs.rsp = `{ "type": "sync", "status-code": 200, @@ -37,7 +52,8 @@ services: command: cmd `[1:] err := cs.cli.AddLayer(&client.AddLayerOptions{ - Combine: combine, + Combine: option.combine, + Inner: option.inner, Label: "foo", LayerData: []byte(layerYAML), }) @@ -49,10 +65,11 @@ services: c.Assert(json.NewDecoder(cs.req.Body).Decode(&body), check.IsNil) c.Assert(body, check.DeepEquals, map[string]interface{}{ "action": "add", - "combine": combine, + "combine": option.combine, "label": "foo", "format": "yaml", "layer": layerYAML, + "inner": option.inner, }) } } diff --git a/docs/reference/cli-commands/add.md b/docs/reference/cli-commands/add.md index 5ef74110..9e229979 100644 --- a/docs/reference/cli-commands/add.md +++ b/docs/reference/cli-commands/add.md @@ -19,5 +19,7 @@ label (or append if the label is not found). [add command options] --combine Combine the new layer with an existing layer that has the given label (default is to append) + --inner Allow appending a new layer inside an existing + subdirectory ``` diff --git a/internals/cli/cmd_add.go b/internals/cli/cmd_add.go index 1d8e841c..247a4d6c 100644 --- a/internals/cli/cmd_add.go +++ b/internals/cli/cmd_add.go @@ -35,6 +35,7 @@ type cmdAdd struct { client *client.Client Combine bool `long:"combine"` + Inner bool `long:"inner"` Positional struct { Label string `positional-arg-name:"