From e558e5de0070df4606028846cc080c074ad9a6b2 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Fri, 19 Jan 2024 15:43:17 +0100 Subject: [PATCH] let resource loader compute a (possibly) relative path Signed-off-by: Nicolas De Loof --- loader/extends.go | 17 +++++++++-------- loader/extends_test.go | 27 +++++++++++++++++++++++++++ loader/loader.go | 13 ++++++++++++- loader/loader_test.go | 10 +++++++++- loader/testdata/extends/base.yaml | 7 ++++++- loader/testdata/extends/sibling.yaml | 3 +++ 6 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 loader/testdata/extends/sibling.yaml diff --git a/loader/extends.go b/loader/extends.go index a56ca1f1..97c6ca36 100644 --- a/loader/extends.go +++ b/loader/extends.go @@ -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 @@ -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 extendsOpts.SkipNormalization = true extendsOpts.SkipConsistencyCheck = true diff --git a/loader/extends_test.go b/loader/extends_test.go index fa57ec98..e5bafaa1 100644 --- a/loader/extends_test.go +++ b/loader/extends_test.go @@ -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")) +} diff --git a/loader/loader.go b/loader/loader.go index 08b28db9..5100d9f5 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -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 { @@ -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, @@ -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 } diff --git a/loader/loader_test.go b/loader/loader_test.go index 693b9733..b2f499b8 100644 --- a/loader/loader_test.go +++ b/loader/loader_test.go @@ -2636,8 +2636,12 @@ 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 @@ -2645,6 +2649,10 @@ func (c customLoader) Load(_ context.Context, s string) (string, error) { 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 diff --git a/loader/testdata/extends/base.yaml b/loader/testdata/extends/base.yaml index a194db19..3c2f6930 100644 --- a/loader/testdata/extends/base.yaml +++ b/loader/testdata/extends/base.yaml @@ -16,4 +16,9 @@ services: nofile: soft: 20000 hard: 40000 - + + with-build: + extends: + file: sibling.yaml + service: test + diff --git a/loader/testdata/extends/sibling.yaml b/loader/testdata/extends/sibling.yaml new file mode 100644 index 00000000..cd109c7a --- /dev/null +++ b/loader/testdata/extends/sibling.yaml @@ -0,0 +1,3 @@ +services: + test: + build: .