From 0e4d7aa7a9ee516ea61dde0bfaee811547fc4119 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Tue, 28 Sep 2021 23:20:17 -0700 Subject: [PATCH 1/2] bake: add test for merging overrides Signed-off-by: Tonis Tiigi --- bake/bake_test.go | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/bake/bake_test.go b/bake/bake_test.go index ebce5dd2..caf43cf4 100644 --- a/bake/bake_test.go +++ b/bake/bake_test.go @@ -274,7 +274,7 @@ services: func TestHCLCwdPrefix(t *testing.T) { fp := File{ - Name: "docker-bake.hc", + Name: "docker-bake.hcl", Data: []byte( `target "app" { context = "cwd://foo" @@ -295,3 +295,32 @@ func TestHCLCwdPrefix(t *testing.T) { require.Equal(t, "test", *m["app"].Dockerfile) require.Equal(t, "foo", *m["app"].Context) } + +func TestOverrideMerge(t *testing.T) { + fp := File{ + Name: "docker-bake.hcl", + Data: []byte( + `target "app" { + platforms = ["linux/amd64"] + output = ["foo"] + }`), + } + ctx := context.TODO() + m, _, err := ReadTargets(ctx, []File{fp}, []string{"app"}, []string{ + "app.platform=linux/arm", + "app.platform=linux/ppc64le", + "app.output=type=registry", + }, nil) + require.NoError(t, err) + + require.Equal(t, 1, len(m)) + _, ok := m["app"] + require.True(t, ok) + + _, err = TargetsToBuildOpt(m, &Input{}) + require.NoError(t, err) + + require.Equal(t, []string{"linux/arm", "linux/ppc64le"}, m["app"].Platforms) + require.Equal(t, 1, len(m["app"].Outputs)) + require.Equal(t, "type=registry", m["app"].Outputs[0]) +} From 7a7b73c043dbd504fc23bb14e6604f01e403d01c Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Tue, 28 Sep 2021 23:55:19 -0700 Subject: [PATCH 2/2] bake: restore previous override merge behavior For array fields, overrides are merged together but override is not merged with the target. If merging with target is desired we can add support for overrides with += operator in the future. Signed-off-by: Tonis Tiigi --- bake/bake.go | 58 +++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/bake/bake.go b/bake/bake.go index 44c961f0..199259de 100644 --- a/bake/bake.go +++ b/bake/bake.go @@ -31,8 +31,8 @@ type File struct { } type Override struct { - Key string - Value string + Value string + ArrValue []string } func defaultFilenames() []string { @@ -246,8 +246,8 @@ func (c Config) expandTargets(pattern string) ([]string, error) { return names, nil } -func (c Config) newOverrides(v []string) (map[string][]Override, error) { - m := map[string][]Override{} +func (c Config) newOverrides(v []string) (map[string]map[string]Override, error) { + m := map[string]map[string]Override{} for _, v := range v { parts := strings.SplitN(v, "=", 2) @@ -269,16 +269,19 @@ func (c Config) newOverrides(v []string) (map[string][]Override, error) { kk := strings.SplitN(parts[0], ".", 2) for _, name := range names { - t := m[name] - - o := Override{ - Key: kk[1], - } - if len(parts) == 2 { - o.Value = parts[1] + t, ok := m[name] + if !ok { + t = map[string]Override{} + m[name] = t } + o := t[kk[1]] + switch keys[1] { + case "output", "cache-to", "cache-from", "tags", "platform", "secrets", "ssh": + if len(parts) == 2 { + o.ArrValue = append(o.ArrValue, parts[1]) + } case "args": if len(keys) != 3 { return nil, errors.Errorf("invalid key %s, args requires name", parts[0]) @@ -290,11 +293,14 @@ func (c Config) newOverrides(v []string) (map[string][]Override, error) { } o.Value = v } + fallthrough + default: + if len(parts) == 2 { + o.Value = parts[1] + } } - t = append(t, o) - - m[name] = t + t[kk[1]] = o } } return m, nil @@ -326,7 +332,7 @@ func (c Config) group(name string, visited map[string]struct{}) []string { return targets } -func (c Config) ResolveTarget(name string, overrides map[string][]Override) (*Target, error) { +func (c Config) ResolveTarget(name string, overrides map[string]map[string]Override) (*Target, error) { t, err := c.target(name, map[string]struct{}{}, overrides) if err != nil { return nil, err @@ -342,7 +348,7 @@ func (c Config) ResolveTarget(name string, overrides map[string][]Override) (*Ta return t, nil } -func (c Config) target(name string, visited map[string]struct{}, overrides map[string][]Override) (*Target, error) { +func (c Config) target(name string, visited map[string]struct{}, overrides map[string]map[string]Override) (*Target, error) { if _, ok := visited[name]; ok { return nil, nil } @@ -476,10 +482,10 @@ func (t *Target) Merge(t2 *Target) { t.Inherits = append(t.Inherits, t2.Inherits...) } -func (t *Target) AddOverrides(overrides []Override) error { - for _, o := range overrides { +func (t *Target) AddOverrides(overrides map[string]Override) error { + for key, o := range overrides { value := o.Value - keys := strings.SplitN(o.Key, ".", 2) + keys := strings.SplitN(key, ".", 2) switch keys[0] { case "context": t.Context = &value @@ -503,21 +509,21 @@ func (t *Target) AddOverrides(overrides []Override) error { } t.Labels[keys[1]] = value case "tags": - t.Tags = append(t.Tags, value) + t.Tags = o.ArrValue case "cache-from": - t.CacheFrom = append(t.CacheFrom, value) + t.CacheFrom = o.ArrValue case "cache-to": - t.CacheTo = append(t.CacheTo, value) + t.CacheTo = o.ArrValue case "target": t.Target = &value case "secrets": - t.Secrets = append(t.Secrets, value) + t.Secrets = o.ArrValue case "ssh": - t.SSH = append(t.SSH, value) + t.SSH = o.ArrValue case "platform": - t.Platforms = append(t.Platforms, value) + t.Platforms = o.ArrValue case "output": - t.Outputs = append(t.Outputs, value) + t.Outputs = o.ArrValue case "no-cache": noCache, err := strconv.ParseBool(value) if err != nil {