bake: fix file-relative target references
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
+54
-1
@@ -437,7 +437,22 @@ func fileRelativePaths(opts []ParseOpt) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func rebaseContextPaths(c *Config) {
|
func rebaseContextPaths(c *Config) {
|
||||||
|
targets := make(map[string]*Target, len(c.Targets))
|
||||||
for _, t := range c.Targets {
|
for _, t := range c.Targets {
|
||||||
|
targets[t.Name] = t
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, t := range c.Targets {
|
||||||
|
if ref := targets[t.contextBaseRef]; ref != nil {
|
||||||
|
switch {
|
||||||
|
case ref.hasContextBase:
|
||||||
|
t.contextBase = ref.contextBase
|
||||||
|
t.hasContextBase = true
|
||||||
|
case ref.hasDefaultContextBase:
|
||||||
|
t.contextBase = ref.defaultContextBase
|
||||||
|
t.hasContextBase = true
|
||||||
|
}
|
||||||
|
}
|
||||||
t.rebaseContextPaths()
|
t.rebaseContextPaths()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -854,6 +869,7 @@ type Target struct {
|
|||||||
useDefaultContextBase bool
|
useDefaultContextBase bool
|
||||||
contextBase string
|
contextBase string
|
||||||
hasContextBase bool
|
hasContextBase bool
|
||||||
|
contextBaseRef string
|
||||||
contextsBase map[string]string
|
contextsBase map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,9 +938,10 @@ func (t *Target) SetBlockSource(block *hcl.Block) {
|
|||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, ok := content.Attributes["context"]; ok {
|
if attr, ok := content.Attributes["context"]; ok {
|
||||||
t.contextBase = base
|
t.contextBase = base
|
||||||
t.hasContextBase = true
|
t.hasContextBase = true
|
||||||
|
t.contextBaseRef = targetContextRef(attr.Expr)
|
||||||
}
|
}
|
||||||
if _, ok := content.Attributes["contexts"]; ok {
|
if _, ok := content.Attributes["contexts"]; ok {
|
||||||
t.setContextsBase(base)
|
t.setContextsBase(base)
|
||||||
@@ -943,6 +960,41 @@ func (t *Target) setContextsBase(base string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func targetContextRef(expr hcl.Expression) string {
|
||||||
|
traversal, diags := hcl.AbsTraversalForExpr(expr)
|
||||||
|
if diags.HasErrors() || len(traversal) != 3 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
root, ok := traversal[0].(hcl.TraverseRoot)
|
||||||
|
if !ok || root.Name != "target" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
target, ok := traversalStepName(traversal[1])
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
field, ok := traversal[2].(hcl.TraverseAttr)
|
||||||
|
if !ok || field.Name != "context" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
func traversalStepName(step hcl.Traverser) (string, bool) {
|
||||||
|
switch step := step.(type) {
|
||||||
|
case hcl.TraverseAttr:
|
||||||
|
return step.Name, true
|
||||||
|
case hcl.TraverseIndex:
|
||||||
|
key, err := convert.Convert(step.Key, cty.String)
|
||||||
|
if err != nil || key.IsNull() || !key.IsKnown() {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return key.AsString(), true
|
||||||
|
default:
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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()
|
||||||
@@ -982,6 +1034,7 @@ func (t *Target) Merge(t2 *Target) {
|
|||||||
t.Context = t2.Context
|
t.Context = t2.Context
|
||||||
t.contextBase = t2.contextBase
|
t.contextBase = t2.contextBase
|
||||||
t.hasContextBase = t2.hasContextBase
|
t.hasContextBase = t2.hasContextBase
|
||||||
|
t.contextBaseRef = t2.contextBaseRef
|
||||||
}
|
}
|
||||||
if t2.Dockerfile != nil {
|
if t2.Dockerfile != nil {
|
||||||
t.Dockerfile = t2.Dockerfile
|
t.Dockerfile = t2.Dockerfile
|
||||||
|
|||||||
@@ -918,6 +918,30 @@ target "app" {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTargetReferenceContextRebase(t *testing.T) {
|
||||||
|
fp1 := File{
|
||||||
|
Name: filepath.Join("one", "docker-bake.hcl"),
|
||||||
|
Data: []byte(`
|
||||||
|
target "base" {
|
||||||
|
context = "basectx"
|
||||||
|
}`),
|
||||||
|
}
|
||||||
|
fp2 := File{
|
||||||
|
Name: filepath.Join("two", "docker-bake.hcl"),
|
||||||
|
Data: []byte(`
|
||||||
|
target "app" {
|
||||||
|
context = target.base.context
|
||||||
|
}`),
|
||||||
|
}
|
||||||
|
|
||||||
|
m, _, err := ReadTargets(context.TODO(), []File{fp1, fp2}, []string{"app"}, nil, nil, nil, &EntitlementConf{}, ParseOpt{
|
||||||
|
FileRelativePaths: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, filepath.ToSlash(filepath.Clean("one/basectx")), *m["app"].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"),
|
||||||
|
|||||||
@@ -786,6 +786,48 @@ EOT
|
|||||||
require.FileExists(t, filepath.Join(dirDest, "marker"))
|
require.FileExists(t, filepath.Join(dirDest, "marker"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("hcl target reference", func(t *testing.T) {
|
||||||
|
baseBakefile := []byte(`
|
||||||
|
target "base" {
|
||||||
|
context = "basectx"
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
appBakefile := []byte(`
|
||||||
|
target "app" {
|
||||||
|
context = target.base.context
|
||||||
|
dockerfile-inline = <<EOT
|
||||||
|
FROM scratch
|
||||||
|
COPY marker /marker
|
||||||
|
EOT
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
dir := tmpdir(
|
||||||
|
t,
|
||||||
|
fstest.CreateDir("one", 0700),
|
||||||
|
fstest.CreateDir("one/basectx", 0700),
|
||||||
|
fstest.CreateDir("two", 0700),
|
||||||
|
fstest.CreateDir("two/basectx", 0700),
|
||||||
|
fstest.CreateFile("one/docker-bake.hcl", baseBakefile, 0600),
|
||||||
|
fstest.CreateFile("one/basectx/marker", []byte("source-file"), 0600),
|
||||||
|
fstest.CreateFile("two/docker-bake.hcl", appBakefile, 0600),
|
||||||
|
fstest.CreateFile("two/basectx/marker", []byte("consumer-file"), 0600),
|
||||||
|
)
|
||||||
|
dirDest := t.TempDir()
|
||||||
|
|
||||||
|
out, err := bakeCmd(
|
||||||
|
sb,
|
||||||
|
withDir(dir),
|
||||||
|
withArgs("--file", "one/docker-bake.hcl", "--file", "two/docker-bake.hcl", "--set", "app.output=type=local,dest="+dirDest, "app"),
|
||||||
|
withEnv("BUILDX_BAKE_FILE_RELATIVE_PATHS=1"),
|
||||||
|
)
|
||||||
|
require.NoError(t, err, out)
|
||||||
|
|
||||||
|
dt, err := os.ReadFile(filepath.Join(dirDest, "marker"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "source-file", string(dt))
|
||||||
|
})
|
||||||
|
|
||||||
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