Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 30 additions & 17 deletions loader/include.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ import (
"fmt"
"os"
"path/filepath"
"reflect"
"strings"

"github.com/compose-spec/compose-go/v2/dotenv"
interp "github.com/compose-spec/compose-go/v2/interpolation"
"github.com/compose-spec/compose-go/v2/override"
"github.com/compose-spec/compose-go/v2/tree"
"github.com/compose-spec/compose-go/v2/types"
)

Expand All @@ -50,7 +51,7 @@ func loadIncludeConfig(source any) ([]types.IncludeConfig, error) {
return requires, err
}

func ApplyInclude(ctx context.Context, workingDir string, environment types.Mapping, model map[string]any, options *Options, included []string) error {
func ApplyInclude(ctx context.Context, workingDir string, environment types.Mapping, model map[string]any, options *Options, included []string, processor PostProcessor) error {
includeConfig, err := loadIncludeConfig(model["include"])
if err != nil {
return err
Expand Down Expand Up @@ -151,7 +152,7 @@ func ApplyInclude(ctx context.Context, workingDir string, environment types.Mapp
if err != nil {
return err
}
err = importResources(imported, model)
err = importResources(imported, model, processor)
if err != nil {
return err
}
Expand All @@ -161,29 +162,29 @@ func ApplyInclude(ctx context.Context, workingDir string, environment types.Mapp
}

// importResources import into model all resources defined by imported, and report error on conflict
func importResources(source map[string]any, target map[string]any) error {
if err := importResource(source, target, "services"); err != nil {
func importResources(source map[string]any, target map[string]any, processor PostProcessor) error {
if err := importResource(source, target, "services", processor); err != nil {
return err
}
if err := importResource(source, target, "volumes"); err != nil {
if err := importResource(source, target, "volumes", processor); err != nil {
return err
}
if err := importResource(source, target, "networks"); err != nil {
if err := importResource(source, target, "networks", processor); err != nil {
return err
}
if err := importResource(source, target, "secrets"); err != nil {
if err := importResource(source, target, "secrets", processor); err != nil {
return err
}
if err := importResource(source, target, "configs"); err != nil {
if err := importResource(source, target, "configs", processor); err != nil {
return err
}
if err := importResource(source, target, "models"); err != nil {
if err := importResource(source, target, "models", processor); err != nil {
return err
}
return nil
}

func importResource(source map[string]any, target map[string]any, key string) error {
func importResource(source map[string]any, target map[string]any, key string, processor PostProcessor) error {
from := source[key]
if from != nil {
var to map[string]any
Expand All @@ -193,13 +194,25 @@ func importResource(source map[string]any, target map[string]any, key string) er
to = map[string]any{}
}
for name, a := range from.(map[string]any) {
if conflict, ok := to[name]; ok {
if reflect.DeepEqual(a, conflict) {
continue
}
return fmt.Errorf("%s.%s conflicts with imported resource", key, name)
conflict, ok := to[name]
if !ok {
to[name] = a
continue
}
err := processor.Apply(map[string]any{
key: map[string]any{
name: a,
},
})
if err != nil {
return err
}

merged, err := override.MergeYaml(a, conflict, tree.NewPath(key, name))
if err != nil {
return err
}
to[name] = a
to[name] = merged
}
target[key] = to
}
Expand Down
13 changes: 11 additions & 2 deletions loader/include_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,21 @@ include:
services:
bar:
image: busybox
environment: !override
- ZOT=QIX
`, map[string]string{"SOURCE": "override"})
_, err := LoadWithContext(context.TODO(), details, func(options *Options) {
p, err := LoadWithContext(context.TODO(), details, func(options *Options) {
options.SkipNormalization = true
options.ResolvePaths = true
})
assert.ErrorContains(t, err, "services.bar conflicts with imported resource", err)
assert.NilError(t, err)
assert.DeepEqual(t, p.Services["bar"], types.ServiceConfig{
Name: "bar",
Image: "busybox",
Environment: types.MappingWithEquals{
"ZOT": strPtr("QIX"),
},
})
}

func TestIncludeRelative(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ func loadYamlFile(ctx context.Context,

if !opts.SkipInclude {
included = append(included, file.Filename)
err = ApplyInclude(ctx, workingDir, environment, cfg, opts, included)
err = ApplyInclude(ctx, workingDir, environment, cfg, opts, included, processor)
if err != nil {
return err
}
Expand Down
4 changes: 3 additions & 1 deletion loader/testdata/compose-include.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ include:

services:
bar:
image: bar
image: bar
environment:
- FOO=BAR
2 changes: 1 addition & 1 deletion override/extends.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package override
import "github.com/compose-spec/compose-go/v2/tree"

func ExtendService(base, override map[string]any) (map[string]any, error) {
yaml, err := mergeYaml(base, override, tree.NewPath("services.x"))
yaml, err := MergeYaml(base, override, tree.NewPath("services.x"))
if err != nil {
return nil, err
}
Expand Down
8 changes: 4 additions & 4 deletions override/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (

// Merge applies overrides to a config model
func Merge(right, left map[string]any) (map[string]any, error) {
merged, err := mergeYaml(right, left, tree.NewPath())
merged, err := MergeYaml(right, left, tree.NewPath())
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -70,8 +70,8 @@ func init() {
mergeSpecials["services.*.ulimits.*"] = mergeUlimit
}

// mergeYaml merges map[string]any yaml trees handling special rules
func mergeYaml(e any, o any, p tree.Path) (any, error) {
// MergeYaml merges map[string]any yaml trees handling special rules
func MergeYaml(e any, o any, p tree.Path) (any, error) {
for pattern, merger := range mergeSpecials {
if p.Matches(pattern) {
merged, err := merger(e, o, p)
Expand Down Expand Up @@ -110,7 +110,7 @@ func mergeMappings(mapping map[string]any, other map[string]any, p tree.Path) (m
continue
}
next := p.Next(k)
merged, err := mergeYaml(e, v, next)
merged, err := MergeYaml(e, v, next)
if err != nil {
return nil, err
}
Expand Down