Skip to content
Merged
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
17 changes: 9 additions & 8 deletions loader/extends.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
"github.com/compose-spec/compose-go/v2/types"
)

func ApplyExtends(ctx context.Context, dict map[string]any, workingdir string, opts *Options, tracker *cycleTracker, post ...PostProcessor) error {
func ApplyExtends(ctx context.Context, dict map[string]any, opts *Options, tracker *cycleTracker, post ...PostProcessor) error {
a, ok := dict["services"]
if !ok {
return nil
Expand Down Expand Up @@ -71,14 +71,15 @@ func ApplyExtends(ctx context.Context, dict map[string]any, workingdir string, o
if err != nil {
return err
}
relworkingdir := filepath.Dir(local)
if !filepath.IsAbs(local) {
relworkingdir, err = filepath.Rel(workingdir, relworkingdir)
if err != nil {
return err
}
}
localdir := filepath.Dir(local)
relworkingdir := loader.Dir(path)

extendsOpts := opts.clone()
extendsOpts.ResourceLoaders = append([]ResourceLoader{}, opts.ResourceLoaders...)
// replace localResourceLoader with a new flavour, using extended file base path
extendsOpts.ResourceLoaders[len(opts.ResourceLoaders)-1] = localResourceLoader{
WorkingDir: localdir,
}
extendsOpts.ResolvePaths = true
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is the root cause of the docker/compose#11377
It was introduced to remove potential import cycles 714c186

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ResolvePaths MUST be set so that ./env in a compose file that is used by extends: file=./foo/bar/compose.yaml is resolved as ./foo/bar/env and can be used as expected by the caller

Used by extend, PathResolution resolves relative paths from working directory, which is itself relative

extendsOpts.SkipNormalization = true
extendsOpts.SkipConsistencyCheck = true
Expand Down
27 changes: 27 additions & 0 deletions loader/extends_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,30 @@ services:
assert.NilError(t, err)
assert.Equal(t, p.Services["test"].Ulimits["nproc"].Single, 65535)
}

func TestExtendsRelativePath(t *testing.T) {
yaml := `
name: test-extends-port
services:
test:
extends:
file: testdata/extends/base.yaml
service: with-build
`
abs, err := filepath.Abs(".")
assert.NilError(t, err)

p, err := LoadWithContext(context.Background(), types.ConfigDetails{
ConfigFiles: []types.ConfigFile{
{
Content: []byte(yaml),
Filename: "(inline)",
},
},
WorkingDir: abs,
}, func(options *Options) {
options.ResolvePaths = false
})
assert.NilError(t, err)
assert.Equal(t, p.Services["test"].Build.Context, filepath.Join("testdata", "extends"))
}
13 changes: 12 additions & 1 deletion loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ type ResourceLoader interface {
Accept(path string) bool
// Load returns the path to a local copy of remote resource identified by `path`.
Load(ctx context.Context, path string) (string, error)
// Dir computes path to resource"s parent folder, made relative if possible
Dir(path string) string
}

type localResourceLoader struct {
Expand All @@ -105,6 +107,15 @@ func (l localResourceLoader) Load(_ context.Context, p string) (string, error) {
return l.abs(p), nil
}

func (l localResourceLoader) Dir(path string) string {
path = l.abs(filepath.Dir(path))
rel, err := filepath.Rel(l.WorkingDir, path)
if err != nil {
return path
}
return rel
}

func (o *Options) clone() *Options {
return &Options{
SkipValidation: o.SkipValidation,
Expand Down Expand Up @@ -313,7 +324,7 @@ func loadYamlModel(ctx context.Context, config types.ConfigDetails, opts *Option
fixEmptyNotNull(cfg)

if !opts.SkipExtends {
err = ApplyExtends(fctx, cfg, config.WorkingDir, opts, ct, processors...)
err = ApplyExtends(fctx, cfg, opts, ct, processors...)
if err != nil {
return err
}
Expand Down
10 changes: 9 additions & 1 deletion loader/loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2636,15 +2636,23 @@ func (c customLoader) Accept(s string) bool {
return strings.HasPrefix(s, c.prefix+":")
}

func (c customLoader) path(s string) string {
return filepath.Join("testdata", c.prefix, s[len(c.prefix)+1:])
}

func (c customLoader) Load(_ context.Context, s string) (string, error) {
path := filepath.Join("testdata", c.prefix, s[len(c.prefix)+1:])
path := c.path(s)
_, err := os.Stat(path)
if err != nil {
return "", err
}
return filepath.Abs(path)
}

func (c customLoader) Dir(s string) string {
return filepath.Dir(c.path(s))
}

func TestLoadWithRemoteResources(t *testing.T) {
config := buildConfigDetails(`
name: test-remote-resources
Expand Down
7 changes: 6 additions & 1 deletion loader/testdata/extends/base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ services:
nofile:
soft: 20000
hard: 40000


with-build:
extends:
file: sibling.yaml
service: test

3 changes: 3 additions & 0 deletions loader/testdata/extends/sibling.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
services:
test:
build: .