Implement a possible direction to allow envvars to expand into lists.
--- a/docker/build.go Wed Sep 20 20:07:30 2017 -0500
+++ b/docker/build.go Wed Sep 20 20:43:49 2017 -0500
@@ -48,6 +48,11 @@
func (b *Build) Execute(name string, logger *gomol.LogAdapter, env []string, st *state.State) error {
fullEnv := environment.Merge(env, st.Environment)
+ files, err := environment.SliceMapExpander(b.Files, fullEnv) // create out build directory
tmpDir, err := ioutil.TempDir("", "convey-build-")
@@ -59,12 +64,7 @@
base := filepath.Dir(b.Dockerfile)
// export the files to it
- for _, src := range b.Files {
- src, err := environment.Mapper(src, fullEnv)
+ for _, src := range files { src, dest := tasks.ParseFilePath(base, src)
cleanDest := filepath.Clean(filepath.Join(tmpDir, dest))
--- a/docker/export.go Wed Sep 20 20:07:30 2017 -0500
+++ b/docker/export.go Wed Sep 20 20:43:49 2017 -0500
@@ -86,12 +86,12 @@
func (e *Export) Execute(name string, logger *gomol.LogAdapter, env []string, st *state.State) error {
fullEnv := environment.Merge(env, st.Environment)
- for _, file := range e.Files {
- file, err := environment.Mapper(file, fullEnv)
+ files, err := environment.SliceMapExpander(e.Files, fullEnv) + for _, file := range files { if err := checkFilePattern(file); err != nil {
--- a/docker/import.go Wed Sep 20 20:07:30 2017 -0500
+++ b/docker/import.go Wed Sep 20 20:43:49 2017 -0500
@@ -35,7 +35,12 @@
func (i *Import) Execute(name string, logger *gomol.LogAdapter, env []string, st *state.State) error {
fullEnv := environment.Merge(env, st.Environment)
- for _, file := range i.Files {
+ files, err := environment.SliceMapExpander(i.Files, fullEnv) + for _, file := range files { file, err := environment.Mapper(file, fullEnv)
--- a/docker/pull.go Wed Sep 20 20:07:30 2017 -0500
+++ b/docker/pull.go Wed Sep 20 20:43:49 2017 -0500
@@ -36,12 +36,12 @@
func (p *Pull) Execute(name string, logger *gomol.LogAdapter, env []string, st *state.State) error {
fullEnv := environment.Merge(env, st.Environment)
- for _, image := range p.Images {
- image, err := environment.Mapper(image, fullEnv)
+ images, err := environment.SliceMapExpander(p.Images, fullEnv) + for _, image := range images { params := map[string]interface{}{
--- a/docker/push.go Wed Sep 20 20:07:30 2017 -0500
+++ b/docker/push.go Wed Sep 20 20:43:49 2017 -0500
@@ -36,12 +36,12 @@
func (p *Push) Execute(name string, logger *gomol.LogAdapter, env []string, st *state.State) error {
fullEnv := environment.Merge(env, st.Environment)
- for _, image := range p.Images {
- image, err := environment.Mapper(image, fullEnv)
+ images, err := environment.SliceMapExpander(p.Images, fullEnv) + for _, image := range images { params := map[string]interface{}{
--- a/docker/remove.go Wed Sep 20 20:07:30 2017 -0500
+++ b/docker/remove.go Wed Sep 20 20:43:49 2017 -0500
@@ -36,12 +36,12 @@
func (r *Remove) Execute(name string, logger *gomol.LogAdapter, env []string, st *state.State) error {
fullEnv := environment.Merge(env, st.Environment)
- for _, image := range r.Images {
- image, err := environment.Mapper(image, fullEnv)
+ images, err := environment.SliceMapExpander(r.Images, fullEnv) + for _, image := range images { params := map[string]interface{}{
--- a/docker/run.go Wed Sep 20 20:07:30 2017 -0500
+++ b/docker/run.go Wed Sep 20 20:43:49 2017 -0500
@@ -118,7 +118,7 @@
// set the run command argument to the script file
- // iterate the script and run the environment variable exapansion on each line
+ // iterate the script and run the environment variable expansion on each line for idx, item := range r.Script {
item, err := environment.Mapper(item, fullEnv)
@@ -198,7 +198,7 @@
- labels, err := environment.SliceMapper(r.Labels, fullEnv)
+ labels, err := environment.SliceMapExpander(r.Labels, fullEnv) --- a/docker/tag.go Wed Sep 20 20:07:30 2017 -0500
+++ b/docker/tag.go Wed Sep 20 20:43:49 2017 -0500
@@ -37,17 +37,17 @@
func (t *Tag) Execute(name string, logger *gomol.LogAdapter, env []string, st *state.State) error {
fullEnv := environment.Merge(env, st.Environment)
- for _, destination := range t.Destinations {
- source, err := environment.Mapper(t.Source, fullEnv)
+ source, err := environment.Mapper(t.Source, fullEnv) - destination, err := environment.Mapper(destination, fullEnv)
+ destinations, err := environment.SliceMapExpander(t.Destinations, fullEnv) + for _, destination := range destinations { params := map[string]interface{}{
"destination": destination,
--- a/environment/mapper.go Wed Sep 20 20:07:30 2017 -0500
+++ b/environment/mapper.go Wed Sep 20 20:43:49 2017 -0500
@@ -79,3 +79,19 @@
+// SliceMapExpander expand yaml.StringOrSlice elements as follows: if value +// is a single item of the form `$var`, then split on ';'. Otherwise, expand +// every element separately in-place, just as in SliceMapper. +func SliceMapExpander(slice []string, env []string) ([]string, error) { + if len(slice) != 1 || strings.TrimSpace(os.Expand(slice[0], func(string) string { return "" })) != "" { + return SliceMapper(slice, env) + expanded, err := Mapper(slice[0], env) + return strings.SplitN(expanded, ";", -1), nil --- a/environment/mapper_test.go Wed Sep 20 20:07:30 2017 -0500
+++ b/environment/mapper_test.go Wed Sep 20 20:43:49 2017 -0500
@@ -79,3 +79,17 @@
_, err := Mapper("${FOO}", []string{"FOO=$BAR", "BAR=$FOO"})
Expect(err).To(MatchError("infinite environment mapping loop while expanding '$BAR'"))
+func (e *environmentSuite) TestSliceMapExpander(t sweet.T) { + Expect(SliceMapExpander([]string{"${FOO}"}, []string{"FOO=bar"})).To(Equal([]string{"bar"})) + // Expanding this as it's the only item containing a `;` + Expect(SliceMapExpander([]string{"${FOO}"}, []string{"FOO=bar;baz"})).To(Equal([]string{"bar", "baz"})) + // Not ONLY expanding this, so we leave it + Expect(SliceMapExpander([]string{"1${FOO}2"}, []string{"FOO=bar;baz"})).To(Equal([]string{"1bar;baz2"})) + // Multiple items in array + Expect(SliceMapExpander([]string{"${FOO}", "${FOO}"}, []string{"FOO=bar;baz"})).To(Equal([]string{"bar;baz", "bar;baz"})) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/extend-slices.yml Wed Sep 20 20:43:49 2017 -0500
@@ -0,0 +1,24 @@
+# This example shows how to use automatic splitting of expanded +# environment variables over directives that take arrays. Running +# this configuration file executes the following commands: +# - docker tag gliderlabs/alpine:edge foo +# - docker tag gliderlabs/alpine:edge bar +# - docker tag gliderlabs/alpine:edge baz + source: gliderlabs/alpine:edge + destinations: ${IMAGE_TAGS} + - IMAGE_TAGS=foo;bar;baz