bake: make file-relative paths definition-scoped
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
+86
-18
@@ -347,6 +347,8 @@ func ParseFiles(files []File, defaults, vars map[string]string, opts ...ParseOpt
|
|||||||
err = formatHCLError(err, files)
|
err = formatHCLError(err, files)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
frel := fileRelativePaths(opts)
|
||||||
|
|
||||||
var c Config
|
var c Config
|
||||||
var composeFiles []File
|
var composeFiles []File
|
||||||
var hclFiles []*hcl.File
|
var hclFiles []*hcl.File
|
||||||
@@ -374,7 +376,7 @@ func ParseFiles(files []File, defaults, vars map[string]string, opts ...ParseOpt
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(composeFiles) > 0 {
|
if len(composeFiles) > 0 {
|
||||||
cfg, cmperr := ParseComposeFiles(composeFiles, vars)
|
cfg, cmperr := parseComposeFilesWithBase(composeFiles, vars, frel)
|
||||||
if cmperr != nil {
|
if cmperr != nil {
|
||||||
return nil, nil, errors.Wrap(cmperr, "failed to parse compose file")
|
return nil, nil, errors.Wrap(cmperr, "failed to parse compose file")
|
||||||
}
|
}
|
||||||
@@ -418,41 +420,51 @@ func ParseFiles(files []File, defaults, vars map[string]string, opts ...ParseOpt
|
|||||||
pm = *res
|
pm = *res
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, opt := range opts {
|
if frel {
|
||||||
if opt.FileRelativePaths {
|
rebaseContextPaths(&c)
|
||||||
rebaseContextPaths(&c, files)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &c, &pm, nil
|
return &c, &pm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func rebaseContextPaths(c *Config, files []File) {
|
func fileRelativePaths(opts []ParseOpt) bool {
|
||||||
base, ok := firstLocalFileDir(files)
|
return slices.ContainsFunc(opts, func(opt ParseOpt) bool {
|
||||||
if !ok {
|
return opt.FileRelativePaths
|
||||||
return
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func rebaseContextPaths(c *Config) {
|
||||||
for _, t := range c.Targets {
|
for _, t := range c.Targets {
|
||||||
if t.Context != nil {
|
t.rebaseContextPaths()
|
||||||
contextPath := rebaseContextPath(base, *t.Context)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Target) rebaseContextPaths() {
|
||||||
|
if t.Context != nil {
|
||||||
|
if t.hasContextBase {
|
||||||
|
contextPath := rebaseContextPath(t.contextBase, *t.Context)
|
||||||
t.Context = &contextPath
|
t.Context = &contextPath
|
||||||
}
|
}
|
||||||
for k, v := range t.Contexts {
|
} else if t.hasDefaultContextBase {
|
||||||
|
contextPath := rebaseContextPath(t.defaultContextBase, ".")
|
||||||
|
t.Context = &contextPath
|
||||||
|
}
|
||||||
|
for k, v := range t.Contexts {
|
||||||
|
if base, ok := t.contextsBase[k]; ok {
|
||||||
t.Contexts[k] = rebaseContextPath(base, v)
|
t.Contexts[k] = rebaseContextPath(base, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func firstLocalFileDir(files []File) (string, bool) {
|
func localFileDir(name string) (string, bool) {
|
||||||
if len(files) == 0 || files[0].Name == "-" || urlutil.IsRemoteURL(files[0].Name) {
|
if name == "" || name == "-" || urlutil.IsRemoteURL(name) {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
return filepath.Dir(files[0].Name), true
|
return filepath.Dir(name), true
|
||||||
}
|
}
|
||||||
|
|
||||||
func rebaseContextPath(base, p string) string {
|
func rebaseContextPath(base, p string) string {
|
||||||
if p == "" || isSpecialContextPath(p) || filepath.IsAbs(p) {
|
if base == "" || p == "" || isSpecialContextPath(p) || filepath.IsAbs(p) {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
return osutil.SanitizePath(filepath.Join(base, filepath.FromSlash(p)))
|
return osutil.SanitizePath(filepath.Join(base, filepath.FromSlash(p)))
|
||||||
@@ -831,6 +843,12 @@ type Target struct {
|
|||||||
|
|
||||||
// linked is a private field to mark a target used as a linked one
|
// linked is a private field to mark a target used as a linked one
|
||||||
linked bool
|
linked bool
|
||||||
|
|
||||||
|
defaultContextBase string
|
||||||
|
hasDefaultContextBase bool
|
||||||
|
contextBase string
|
||||||
|
hasContextBase bool
|
||||||
|
contextsBase map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Target) MarshalJSON() ([]byte, error) {
|
func (t *Target) MarshalJSON() ([]byte, error) {
|
||||||
@@ -879,10 +897,46 @@ func (t *Target) MarshalJSON() ([]byte, error) {
|
|||||||
var (
|
var (
|
||||||
_ hclparser.WithEvalContexts = &Target{}
|
_ hclparser.WithEvalContexts = &Target{}
|
||||||
_ hclparser.WithGetName = &Target{}
|
_ hclparser.WithGetName = &Target{}
|
||||||
|
_ hclparser.WithBlockSource = &Target{}
|
||||||
_ hclparser.WithEvalContexts = &Group{}
|
_ hclparser.WithEvalContexts = &Group{}
|
||||||
_ hclparser.WithGetName = &Group{}
|
_ hclparser.WithGetName = &Group{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (t *Target) SetBlockSource(block *hcl.Block) {
|
||||||
|
base, _ := localFileDir(block.DefRange.Filename)
|
||||||
|
t.defaultContextBase = base
|
||||||
|
t.hasDefaultContextBase = true
|
||||||
|
|
||||||
|
content, _, diags := block.Body.PartialContent(&hcl.BodySchema{
|
||||||
|
Attributes: []hcl.AttributeSchema{
|
||||||
|
{Name: "context"},
|
||||||
|
{Name: "contexts"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if diags.HasErrors() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, ok := content.Attributes["context"]; ok {
|
||||||
|
t.contextBase = base
|
||||||
|
t.hasContextBase = true
|
||||||
|
}
|
||||||
|
if _, ok := content.Attributes["contexts"]; ok {
|
||||||
|
t.setContextsBase(base)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Target) setContextsBase(base string) {
|
||||||
|
if len(t.Contexts) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if t.contextsBase == nil {
|
||||||
|
t.contextsBase = map[string]string{}
|
||||||
|
}
|
||||||
|
for k := range t.Contexts {
|
||||||
|
t.contextsBase[k] = base
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Target) normalize() {
|
func (t *Target) normalize() {
|
||||||
t.Annotations = removeDupesStr(t.Annotations)
|
t.Annotations = removeDupesStr(t.Annotations)
|
||||||
t.Attest = t.Attest.Normalize()
|
t.Attest = t.Attest.Normalize()
|
||||||
@@ -913,8 +967,14 @@ func (t *Target) normalize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Target) Merge(t2 *Target) {
|
func (t *Target) Merge(t2 *Target) {
|
||||||
|
if t2.hasDefaultContextBase {
|
||||||
|
t.defaultContextBase = t2.defaultContextBase
|
||||||
|
t.hasDefaultContextBase = true
|
||||||
|
}
|
||||||
if t2.Context != nil {
|
if t2.Context != nil {
|
||||||
t.Context = t2.Context
|
t.Context = t2.Context
|
||||||
|
t.contextBase = t2.contextBase
|
||||||
|
t.hasContextBase = t2.hasContextBase
|
||||||
}
|
}
|
||||||
if t2.Dockerfile != nil {
|
if t2.Dockerfile != nil {
|
||||||
t.Dockerfile = t2.Dockerfile
|
t.Dockerfile = t2.Dockerfile
|
||||||
@@ -936,6 +996,14 @@ func (t *Target) Merge(t2 *Target) {
|
|||||||
t.Contexts = map[string]string{}
|
t.Contexts = map[string]string{}
|
||||||
}
|
}
|
||||||
t.Contexts[k] = v
|
t.Contexts[k] = v
|
||||||
|
if t.contextsBase == nil {
|
||||||
|
t.contextsBase = map[string]string{}
|
||||||
|
}
|
||||||
|
if base, ok := t2.contextsBase[k]; ok {
|
||||||
|
t.contextsBase[k] = base
|
||||||
|
} else {
|
||||||
|
delete(t.contextsBase, k)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for k, v := range t2.Labels {
|
for k, v := range t2.Labels {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
|
|||||||
+71
-1
@@ -805,6 +805,70 @@ target "app" {
|
|||||||
require.Equal(t, filepath.ToSlash(filepath.Clean("shared")), bo["app"].Inputs.NamedContexts["shared"].Path)
|
require.Equal(t, filepath.ToSlash(filepath.Clean("shared")), bo["app"].Inputs.NamedContexts["shared"].Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDefaultContextRebase(t *testing.T) {
|
||||||
|
fp := File{
|
||||||
|
Name: filepath.Join("definitions", "docker-bake.hcl"),
|
||||||
|
Data: []byte(`
|
||||||
|
target "app" {
|
||||||
|
dockerfile-inline = <<EOT
|
||||||
|
FROM scratch
|
||||||
|
EOT
|
||||||
|
}`),
|
||||||
|
}
|
||||||
|
|
||||||
|
m, _, err := ReadTargets(context.TODO(), []File{fp}, []string{"app"}, nil, nil, nil, &EntitlementConf{}, ParseOpt{
|
||||||
|
FileRelativePaths: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, filepath.ToSlash(filepath.Clean("definitions")), *m["app"].Context)
|
||||||
|
|
||||||
|
bo, err := TargetsToBuildOpt(m, &Input{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, filepath.ToSlash(filepath.Clean("definitions")), bo["app"].Inputs.ContextPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDefinitionPathBase(t *testing.T) {
|
||||||
|
fp1 := File{
|
||||||
|
Name: filepath.Join("one", "docker-bake.hcl"),
|
||||||
|
Data: []byte(`
|
||||||
|
target "app" {
|
||||||
|
context = "."
|
||||||
|
contexts = {
|
||||||
|
shared = "../shared"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target "implicit" {
|
||||||
|
dockerfile-inline = <<EOT
|
||||||
|
FROM scratch
|
||||||
|
EOT
|
||||||
|
}`),
|
||||||
|
}
|
||||||
|
fp2 := File{
|
||||||
|
Name: filepath.Join("two", "docker-bake.hcl"),
|
||||||
|
Data: []byte(`
|
||||||
|
target "app" {
|
||||||
|
tags = ["app:latest"]
|
||||||
|
}
|
||||||
|
|
||||||
|
target "other" {
|
||||||
|
context = "."
|
||||||
|
}`),
|
||||||
|
}
|
||||||
|
|
||||||
|
m, _, err := ReadTargets(context.TODO(), []File{fp1, fp2}, []string{"app", "implicit", "other"}, nil, nil, nil, &EntitlementConf{}, ParseOpt{
|
||||||
|
FileRelativePaths: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, filepath.ToSlash(filepath.Clean("one")), *m["app"].Context)
|
||||||
|
require.Equal(t, filepath.ToSlash(filepath.Clean("shared")), m["app"].Contexts["shared"])
|
||||||
|
require.Equal(t, []string{"app:latest"}, m["app"].Tags)
|
||||||
|
require.Equal(t, filepath.ToSlash(filepath.Clean("one")), *m["implicit"].Context)
|
||||||
|
require.Equal(t, filepath.ToSlash(filepath.Clean("two")), *m["other"].Context)
|
||||||
|
}
|
||||||
|
|
||||||
func TestOverridesNotRebased(t *testing.T) {
|
func TestOverridesNotRebased(t *testing.T) {
|
||||||
fp := File{
|
fp := File{
|
||||||
Name: filepath.Join("subdir", "docker-bake.hcl"),
|
Name: filepath.Join("subdir", "docker-bake.hcl"),
|
||||||
@@ -839,21 +903,27 @@ services:
|
|||||||
context: ./dockerfiles/debian
|
context: ./dockerfiles/debian
|
||||||
additional_contexts:
|
additional_contexts:
|
||||||
shared: ../shared
|
shared: ../shared
|
||||||
|
implicit:
|
||||||
|
build:
|
||||||
|
dockerfile_inline: |
|
||||||
|
FROM scratch
|
||||||
`),
|
`),
|
||||||
}
|
}
|
||||||
|
|
||||||
m, _, err := ReadTargets(context.TODO(), []File{fp}, []string{"debian"}, nil, nil, nil, &EntitlementConf{}, ParseOpt{
|
m, _, err := ReadTargets(context.TODO(), []File{fp}, []string{"debian", "implicit"}, nil, nil, nil, &EntitlementConf{}, ParseOpt{
|
||||||
FileRelativePaths: true,
|
FileRelativePaths: true,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, filepath.ToSlash(filepath.Clean("tests/dockerfiles/debian")), *m["debian"].Context)
|
require.Equal(t, filepath.ToSlash(filepath.Clean("tests/dockerfiles/debian")), *m["debian"].Context)
|
||||||
require.Equal(t, filepath.ToSlash(filepath.Clean("shared")), m["debian"].Contexts["shared"])
|
require.Equal(t, filepath.ToSlash(filepath.Clean("shared")), m["debian"].Contexts["shared"])
|
||||||
|
require.Equal(t, filepath.ToSlash(filepath.Clean("tests")), *m["implicit"].Context)
|
||||||
|
|
||||||
bo, err := TargetsToBuildOpt(m, &Input{})
|
bo, err := TargetsToBuildOpt(m, &Input{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, filepath.ToSlash(filepath.Clean("tests/dockerfiles/debian")), bo["debian"].Inputs.ContextPath)
|
require.Equal(t, filepath.ToSlash(filepath.Clean("tests/dockerfiles/debian")), bo["debian"].Inputs.ContextPath)
|
||||||
require.Equal(t, filepath.Join("tests", "dockerfiles", "debian", "Dockerfile"), bo["debian"].Inputs.DockerfilePath)
|
require.Equal(t, filepath.Join("tests", "dockerfiles", "debian", "Dockerfile"), bo["debian"].Inputs.DockerfilePath)
|
||||||
|
require.Equal(t, filepath.ToSlash(filepath.Clean("tests")), bo["implicit"].Inputs.ContextPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOverrideMerge(t *testing.T) {
|
func TestOverrideMerge(t *testing.T) {
|
||||||
|
|||||||
+45
-1
@@ -21,11 +21,42 @@ import (
|
|||||||
"go.yaml.in/yaml/v3"
|
"go.yaml.in/yaml/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseComposeFiles(fs []File, envOverrides map[string]string) (*Config, error) {
|
func ParseComposeFiles(fs []File, envOverrides map[string]string, opts ...ParseOpt) (*Config, error) {
|
||||||
|
frel := fileRelativePaths(opts)
|
||||||
|
cfg, err := parseComposeFilesWithBase(fs, envOverrides, frel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if frel {
|
||||||
|
rebaseContextPaths(cfg)
|
||||||
|
}
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseComposeFilesWithBase(fs []File, envOverrides map[string]string, withBase bool) (*Config, error) {
|
||||||
envs, err := composeEnv(envOverrides)
|
envs, err := composeEnv(envOverrides)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if withBase && len(fs) > 0 {
|
||||||
|
var c Config
|
||||||
|
for _, f := range fs {
|
||||||
|
cfg, err := parseComposeFiles([]File{f}, envs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
setComposeContextBase(cfg, f.Name)
|
||||||
|
c = mergeConfig(c, *cfg)
|
||||||
|
c = dedupeConfig(c)
|
||||||
|
}
|
||||||
|
return &c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseComposeFiles(fs, envs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseComposeFiles(fs []File, envs map[string]string) (*Config, error) {
|
||||||
var cfgs []composetypes.ConfigFile
|
var cfgs []composetypes.ConfigFile
|
||||||
for _, f := range fs {
|
for _, f := range fs {
|
||||||
cfgs = append(cfgs, composetypes.ConfigFile{
|
cfgs = append(cfgs, composetypes.ConfigFile{
|
||||||
@@ -36,6 +67,19 @@ func ParseComposeFiles(fs []File, envOverrides map[string]string) (*Config, erro
|
|||||||
return ParseCompose(cfgs, envs)
|
return ParseCompose(cfgs, envs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setComposeContextBase(c *Config, name string) {
|
||||||
|
base, _ := localFileDir(name)
|
||||||
|
for _, t := range c.Targets {
|
||||||
|
t.defaultContextBase = base
|
||||||
|
t.hasDefaultContextBase = true
|
||||||
|
if t.Context != nil {
|
||||||
|
t.contextBase = base
|
||||||
|
t.hasContextBase = true
|
||||||
|
}
|
||||||
|
t.setContextsBase(base)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func ParseCompose(cfgs []composetypes.ConfigFile, envs map[string]string) (*Config, error) {
|
func ParseCompose(cfgs []composetypes.ConfigFile, envs map[string]string) (*Config, error) {
|
||||||
cfg, err := loadComposeFiles(cfgs, envs)
|
cfg, err := loadComposeFiles(cfgs, envs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -91,6 +91,10 @@ type WithGetName interface {
|
|||||||
GetName(ectx *hcl.EvalContext, block *hcl.Block, loadDeps func(hcl.Expression) hcl.Diagnostics) (string, error)
|
GetName(ectx *hcl.EvalContext, block *hcl.Block, loadDeps func(hcl.Expression) hcl.Diagnostics) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WithBlockSource interface {
|
||||||
|
SetBlockSource(block *hcl.Block)
|
||||||
|
}
|
||||||
|
|
||||||
// errUndefined is returned when a variable or function is not defined.
|
// errUndefined is returned when a variable or function is not defined.
|
||||||
type errUndefined struct{}
|
type errUndefined struct{}
|
||||||
|
|
||||||
@@ -944,6 +948,10 @@ func Parse(b hcl.Body, opt Opt, val any) (*ParseMeta, hcl.Diagnostics) {
|
|||||||
|
|
||||||
vvs := p.blockValues[b]
|
vvs := p.blockValues[b]
|
||||||
for _, vv := range vvs {
|
for _, vv := range vvs {
|
||||||
|
if v, ok := vv.Interface().(WithBlockSource); ok {
|
||||||
|
v.SetBlockSource(b)
|
||||||
|
}
|
||||||
|
|
||||||
t := types[b.Type]
|
t := types[b.Type]
|
||||||
lblIndex, lblExists := getNameIndex(vv)
|
lblIndex, lblExists := getNameIndex(vv)
|
||||||
lblName, _ := getName(vv)
|
lblName, _ := getName(vv)
|
||||||
|
|||||||
@@ -417,9 +417,9 @@ target "app" {
|
|||||||
|
|
||||||
This resolves to the current working directory (`"."`) by default.
|
This resolves to the current working directory (`"."`) by default.
|
||||||
Set `BUILDX_BAKE_FILE_RELATIVE_PATHS=1` to resolve local directory paths in
|
Set `BUILDX_BAKE_FILE_RELATIVE_PATHS=1` to resolve local directory paths in
|
||||||
`target.context` and `target.contexts` relative to the directory of the first
|
`target.context` and `target.contexts` relative to the Bake or Compose file
|
||||||
Bake file. Use `cwd://` for paths that should remain relative to the current
|
that defines each path. Use `cwd://` for paths that should remain relative to
|
||||||
working directory when this opt-in is enabled.
|
the current working directory when this opt-in is enabled.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ docker buildx bake --print -f - <<< 'target "default" {}'
|
$ docker buildx bake --print -f - <<< 'target "default" {}'
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ Multiple definitions can be specified by separating them with the system's path
|
|||||||
|
|
||||||
By default, local directory build contexts in Bake files are resolved from the
|
By default, local directory build contexts in Bake files are resolved from the
|
||||||
current working directory. To opt in to resolving local directory build contexts
|
current working directory. To opt in to resolving local directory build contexts
|
||||||
from the directory of the first Bake file, set
|
from the Bake or Compose file that defines each path, set
|
||||||
`BUILDX_BAKE_FILE_RELATIVE_PATHS=1`. Use the `cwd://` prefix for paths that
|
`BUILDX_BAKE_FILE_RELATIVE_PATHS=1`. Use the `cwd://` prefix for paths that
|
||||||
should remain relative to the current working directory.
|
should remain relative to the current working directory.
|
||||||
|
|
||||||
|
|||||||
@@ -715,6 +715,34 @@ services:
|
|||||||
require.FileExists(t, filepath.Join(dirDest, "shared-marker"))
|
require.FileExists(t, filepath.Join(dirDest, "shared-marker"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("default context", func(t *testing.T) {
|
||||||
|
bakefile := []byte(`
|
||||||
|
target "default" {
|
||||||
|
dockerfile-inline = <<EOT
|
||||||
|
FROM scratch
|
||||||
|
COPY marker /marker
|
||||||
|
EOT
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
dir := tmpdir(
|
||||||
|
t,
|
||||||
|
fstest.CreateDir("definitions", 0700),
|
||||||
|
fstest.CreateFile("definitions/docker-bake.hcl", bakefile, 0600),
|
||||||
|
fstest.CreateFile("definitions/marker", []byte("marker"), 0600),
|
||||||
|
)
|
||||||
|
dirDest := t.TempDir()
|
||||||
|
|
||||||
|
out, err := bakeCmd(
|
||||||
|
sb,
|
||||||
|
withDir(dir),
|
||||||
|
withArgs("--file", "definitions/docker-bake.hcl", "--set", "*.output=type=local,dest="+dirDest),
|
||||||
|
withEnv("BUILDX_BAKE_FILE_RELATIVE_PATHS=1"),
|
||||||
|
)
|
||||||
|
require.NoError(t, err, out)
|
||||||
|
require.FileExists(t, filepath.Join(dirDest, "marker"))
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("cwd prefix", func(t *testing.T) {
|
t.Run("cwd prefix", func(t *testing.T) {
|
||||||
bakefile := []byte(`
|
bakefile := []byte(`
|
||||||
target "default" {
|
target "default" {
|
||||||
|
|||||||
Reference in New Issue
Block a user