grim/convey

955b9c1d8976
Parents 0e0c2d936684
Children 8b0dc7be36f2
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)
+ if err != nil {
+ return err
+ }
+
// create out build directory
tmpDir, err := ioutil.TempDir("", "convey-build-")
if err != nil {
@@ -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)
- if err != nil {
- return err
- }
-
+ 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)
- if err != nil {
- return err
- }
+ files, err := environment.SliceMapExpander(e.Files, fullEnv)
+ if err != nil {
+ return err
+ }
+ for _, file := range files {
if err := checkFilePattern(file); err != nil {
return err
}
--- 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)
+ if err != nil {
+ return err
+ }
+
+ for _, file := range files {
file, err := environment.Mapper(file, fullEnv)
if err != nil {
return err
--- 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)
- if err != nil {
- return err
- }
+ images, err := environment.SliceMapExpander(p.Images, fullEnv)
+ if err != nil {
+ return err
+ }
+ for _, image := range images {
params := map[string]interface{}{
"image": image,
}
--- 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)
- if err != nil {
- return err
- }
+ images, err := environment.SliceMapExpander(p.Images, fullEnv)
+ if err != nil {
+ return err
+ }
+ for _, image := range images {
params := map[string]interface{}{
"image": image,
}
--- 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)
- if err != nil {
- return err
- }
+ images, err := environment.SliceMapExpander(r.Images, fullEnv)
+ if err != nil {
+ return err
+ }
+ for _, image := range images {
params := map[string]interface{}{
"image": image,
}
--- 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
commandArg := scriptFile
- // 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)
if err != nil {
@@ -198,7 +198,7 @@
return err
}
- labels, err := environment.SliceMapper(r.Labels, fullEnv)
+ labels, err := environment.SliceMapExpander(r.Labels, fullEnv)
if err != nil {
return err
}
--- 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)
- if err != nil {
- return err
- }
+ source, err := environment.Mapper(t.Source, fullEnv)
+ if err != nil {
+ return err
+ }
- destination, err := environment.Mapper(destination, fullEnv)
- if err != nil {
- return err
- }
+ destinations, err := environment.SliceMapExpander(t.Destinations, fullEnv)
+ if err != nil {
+ return err
+ }
+ for _, destination := range destinations {
params := map[string]interface{}{
"source": source,
"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 @@
return mapped, nil
}
+
+// 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)
+ if err != nil {
+ return nil, err
+ }
+
+ 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) {
+ // Single item
+ 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
+
+tasks:
+ tag-abstract:
+ type: tag
+ source: gliderlabs/alpine:edge
+ destinations: ${IMAGE_TAGS}
+
+ tag-concrete:
+ type: extend
+ task: tag-abstract
+ environment:
+ - IMAGE_TAGS=foo;bar;baz
+
+plans:
+ default:
+ stages:
+ - tasks: tag-concrete