Merge pull request #671 from tonistiigi/remote-context

bake: allow BAKE_CMD_CONTEXT builtin var
pull/676/head
Tõnis Tiigi 4 years ago committed by GitHub
commit 6e3a319a9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -61,8 +61,8 @@ func ReadLocalFiles(names []string) ([]File, error) {
return out, nil return out, nil
} }
func ReadTargets(ctx context.Context, files []File, targets, overrides []string) (map[string]*Target, error) { func ReadTargets(ctx context.Context, files []File, targets, overrides []string, defaults map[string]string) (map[string]*Target, error) {
c, err := ParseFiles(files) c, err := ParseFiles(files, defaults)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -86,7 +86,7 @@ func ReadTargets(ctx context.Context, files []File, targets, overrides []string)
return m, nil return m, nil
} }
func ParseFiles(files []File) (_ *Config, err error) { func ParseFiles(files []File, defaults map[string]string) (_ *Config, err error) {
defer func() { defer func() {
err = formatHCLError(err, files) err = formatHCLError(err, files)
}() }()
@ -120,6 +120,7 @@ func ParseFiles(files []File) (_ *Config, err error) {
if len(fs) > 0 { if len(fs) > 0 {
if err := hclparser.Parse(hcl.MergeFiles(fs), hclparser.Opt{ if err := hclparser.Parse(hcl.MergeFiles(fs), hclparser.Opt{
LookupVar: os.LookupEnv, LookupVar: os.LookupEnv,
Vars: defaults,
}, &c); err.HasErrors() { }, &c); err.HasErrors() {
return nil, err return nil, err
} }
@ -143,7 +144,7 @@ func dedupeConfig(c Config) Config {
} }
func ParseFile(dt []byte, fn string) (*Config, error) { func ParseFile(dt []byte, fn string) (*Config, error) {
return ParseFiles([]File{{Data: dt, Name: fn}}) return ParseFiles([]File{{Data: dt, Name: fn}}, nil)
} }
func ParseComposeFile(dt []byte, fn string) (*Config, bool, error) { func ParseComposeFile(dt []byte, fn string) (*Config, bool, error) {
@ -526,6 +527,12 @@ func updateContext(t *build.Inputs, inp *Input) {
t.ContextPath = inp.URL t.ContextPath = inp.URL
return return
} }
if strings.HasPrefix(t.ContextPath, "cwd://") {
return
}
if IsRemoteURL(t.ContextPath) {
return
}
st := llb.Scratch().File(llb.Copy(*inp.State, t.ContextPath, "/"), llb.WithCustomNamef("set context to %s", t.ContextPath)) st := llb.Scratch().File(llb.Copy(*inp.State, t.ContextPath, "/"), llb.WithCustomNamef("set context to %s", t.ContextPath))
t.ContextState = &st t.ContextState = &st
} }
@ -542,7 +549,9 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
if t.Context != nil { if t.Context != nil {
contextPath = *t.Context contextPath = *t.Context
} }
contextPath = path.Clean(contextPath) if !strings.HasPrefix(contextPath, "cwd://") && !IsRemoteURL(contextPath) {
contextPath = path.Clean(contextPath)
}
dockerfilePath := "Dockerfile" dockerfilePath := "Dockerfile"
if t.Dockerfile != nil { if t.Dockerfile != nil {
dockerfilePath = *t.Dockerfile dockerfilePath = *t.Dockerfile
@ -569,6 +578,11 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
bi.DockerfileInline = *t.DockerfileInline bi.DockerfileInline = *t.DockerfileInline
} }
updateContext(&bi, inp) updateContext(&bi, inp)
if strings.HasPrefix(bi.ContextPath, "cwd://") {
bi.ContextPath = path.Clean(strings.TrimPrefix(bi.ContextPath, "cwd://"))
}
t.Context = &bi.ContextPath
bo := &build.Options{ bo := &build.Options{
Inputs: bi, Inputs: bi,

@ -34,7 +34,7 @@ target "webapp" {
ctx := context.TODO() ctx := context.TODO()
t.Run("NoOverrides", func(t *testing.T) { t.Run("NoOverrides", func(t *testing.T) {
m, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, nil) m, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, nil, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, len(m)) require.Equal(t, 1, len(m))
@ -46,7 +46,7 @@ target "webapp" {
}) })
t.Run("InvalidTargetOverrides", func(t *testing.T) { t.Run("InvalidTargetOverrides", func(t *testing.T) {
_, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"nosuchtarget.context=foo"}) _, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"nosuchtarget.context=foo"}, nil)
require.NotNil(t, err) require.NotNil(t, err)
require.Equal(t, err.Error(), "could not find any target matching 'nosuchtarget'") require.Equal(t, err.Error(), "could not find any target matching 'nosuchtarget'")
}) })
@ -63,7 +63,7 @@ target "webapp" {
"webapp.args.VAR_FROMENV" + t.Name(), "webapp.args.VAR_FROMENV" + t.Name(),
"webapp.args.VAR_INHERITED=override", "webapp.args.VAR_INHERITED=override",
// not overriding VAR_BOTH on purpose // not overriding VAR_BOTH on purpose
}) }, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "Dockerfile.webapp", *m["webapp"].Dockerfile) require.Equal(t, "Dockerfile.webapp", *m["webapp"].Dockerfile)
@ -88,7 +88,7 @@ target "webapp" {
m, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{ m, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{
"webDEP.args.VAR_INHERITED=override", "webDEP.args.VAR_INHERITED=override",
"webDEP.args.VAR_BOTH=override", "webDEP.args.VAR_BOTH=override",
}) }, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, m["webapp"].Args["VAR_INHERITED"], "override") require.Equal(t, m["webapp"].Args["VAR_INHERITED"], "override")
require.Equal(t, m["webapp"].Args["VAR_BOTH"], "webapp") require.Equal(t, m["webapp"].Args["VAR_BOTH"], "webapp")
@ -96,23 +96,23 @@ target "webapp" {
}) })
t.Run("ContextOverride", func(t *testing.T) { t.Run("ContextOverride", func(t *testing.T) {
_, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.context"}) _, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.context"}, nil)
require.NotNil(t, err) require.NotNil(t, err)
m, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.context=foo"}) m, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.context=foo"}, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "foo", *m["webapp"].Context) require.Equal(t, "foo", *m["webapp"].Context)
}) })
t.Run("NoCacheOverride", func(t *testing.T) { t.Run("NoCacheOverride", func(t *testing.T) {
m, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.no-cache=false"}) m, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.no-cache=false"}, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, false, *m["webapp"].NoCache) require.Equal(t, false, *m["webapp"].NoCache)
}) })
t.Run("PullOverride", func(t *testing.T) { t.Run("PullOverride", func(t *testing.T) {
m, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.pull=false"}) m, err := ReadTargets(ctx, []File{fp}, []string{"webapp"}, []string{"webapp.pull=false"}, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, false, *m["webapp"].Pull) require.Equal(t, false, *m["webapp"].Pull)
}) })
@ -172,7 +172,7 @@ target "webapp" {
} }
for _, test := range cases { for _, test := range cases {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
m, err := ReadTargets(ctx, []File{fp}, test.targets, test.overrides) m, err := ReadTargets(ctx, []File{fp}, test.targets, test.overrides, nil)
test.check(t, m, err) test.check(t, m, err)
}) })
} }
@ -215,7 +215,7 @@ services:
ctx := context.TODO() ctx := context.TODO()
m, err := ReadTargets(ctx, []File{fp, fp2}, []string{"default"}, nil) m, err := ReadTargets(ctx, []File{fp, fp2}, []string{"default"}, nil, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 3, len(m)) require.Equal(t, 3, len(m))
@ -226,3 +226,28 @@ services:
require.Equal(t, "1", m["webapp"].Args["buildno"]) require.Equal(t, "1", m["webapp"].Args["buildno"])
require.Equal(t, "12", m["webapp"].Args["buildno2"]) require.Equal(t, "12", m["webapp"].Args["buildno2"])
} }
func TestHCLCwdPrefix(t *testing.T) {
fp := File{
Name: "docker-bake.hc",
Data: []byte(
`target "app" {
context = "cwd://foo"
dockerfile = "test"
}`),
}
ctx := context.TODO()
m, err := ReadTargets(ctx, []File{fp}, []string{"app"}, nil, nil)
require.NoError(t, err)
require.Equal(t, 1, len(m))
_, ok := m["app"]
require.True(t, ok)
_, err = TargetsToBuildOpt(m, &Input{})
require.NoError(t, err)
require.Equal(t, "test", *m["app"].Dockerfile)
require.Equal(t, "foo", *m["app"].Context)
}

@ -276,7 +276,7 @@ func TestHCLMultiFileSharedVariables(t *testing.T) {
c, err := ParseFiles([]File{ c, err := ParseFiles([]File{
{Data: dt, Name: "c1.hcl"}, {Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"}, {Data: dt2, Name: "c2.hcl"},
}) }, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, len(c.Targets)) require.Equal(t, 1, len(c.Targets))
require.Equal(t, c.Targets[0].Name, "app") require.Equal(t, c.Targets[0].Name, "app")
@ -288,7 +288,7 @@ func TestHCLMultiFileSharedVariables(t *testing.T) {
c, err = ParseFiles([]File{ c, err = ParseFiles([]File{
{Data: dt, Name: "c1.hcl"}, {Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"}, {Data: dt2, Name: "c2.hcl"},
}) }, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, len(c.Targets)) require.Equal(t, 1, len(c.Targets))
@ -326,7 +326,7 @@ func TestHCLVarsWithVars(t *testing.T) {
c, err := ParseFiles([]File{ c, err := ParseFiles([]File{
{Data: dt, Name: "c1.hcl"}, {Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"}, {Data: dt2, Name: "c2.hcl"},
}) }, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, len(c.Targets)) require.Equal(t, 1, len(c.Targets))
require.Equal(t, c.Targets[0].Name, "app") require.Equal(t, c.Targets[0].Name, "app")
@ -338,7 +338,7 @@ func TestHCLVarsWithVars(t *testing.T) {
c, err = ParseFiles([]File{ c, err = ParseFiles([]File{
{Data: dt, Name: "c1.hcl"}, {Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"}, {Data: dt2, Name: "c2.hcl"},
}) }, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, len(c.Targets)) require.Equal(t, 1, len(c.Targets))
@ -483,7 +483,7 @@ func TestHCLMultiFileAttrs(t *testing.T) {
c, err := ParseFiles([]File{ c, err := ParseFiles([]File{
{Data: dt, Name: "c1.hcl"}, {Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"}, {Data: dt2, Name: "c2.hcl"},
}) }, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, len(c.Targets)) require.Equal(t, 1, len(c.Targets))
require.Equal(t, c.Targets[0].Name, "app") require.Equal(t, c.Targets[0].Name, "app")
@ -494,7 +494,7 @@ func TestHCLMultiFileAttrs(t *testing.T) {
c, err = ParseFiles([]File{ c, err = ParseFiles([]File{
{Data: dt, Name: "c1.hcl"}, {Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"}, {Data: dt2, Name: "c2.hcl"},
}) }, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, len(c.Targets)) require.Equal(t, 1, len(c.Targets))
@ -589,7 +589,7 @@ services:
c, err := ParseFiles([]File{ c, err := ParseFiles([]File{
{Data: dt, Name: "c1.hcl"}, {Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.yml"}, {Data: dt2, Name: "c2.yml"},
}) }, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, len(c.Targets)) require.Equal(t, 1, len(c.Targets))
@ -599,3 +599,24 @@ services:
require.Equal(t, "dir", *c.Targets[0].Context) require.Equal(t, "dir", *c.Targets[0].Context)
require.Equal(t, "Dockerfile-alternate", *c.Targets[0].Dockerfile) require.Equal(t, "Dockerfile-alternate", *c.Targets[0].Dockerfile)
} }
func TestHCLBuiltinVars(t *testing.T) {
dt := []byte(`
target "app" {
context = BAKE_CMD_CONTEXT
dockerfile = "test"
}
`)
c, err := ParseFiles([]File{
{Data: dt, Name: "c1.hcl"},
}, map[string]string{
"BAKE_CMD_CONTEXT": "foo",
})
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))
require.Equal(t, c.Targets[0].Name, "app")
require.Equal(t, "foo", *c.Targets[0].Context)
require.Equal(t, "test", *c.Targets[0].Dockerfile)
}

@ -17,6 +17,7 @@ import (
type Opt struct { type Opt struct {
LookupVar func(string) (string, bool) LookupVar func(string) (string, bool)
Vars map[string]string
} }
type variable struct { type variable struct {
@ -178,7 +179,7 @@ func (p *parser) resolveValue(name string) (err error) {
}() }()
def, ok := p.attrs[name] def, ok := p.attrs[name]
if !ok { if _, builtin := p.opt.Vars[name]; !ok && !builtin {
vr, ok := p.vars[name] vr, ok := p.vars[name]
if !ok { if !ok {
return errors.Errorf("undefined variable %q", name) return errors.Errorf("undefined variable %q", name)
@ -187,7 +188,10 @@ func (p *parser) resolveValue(name string) (err error) {
} }
if def == nil { if def == nil {
val, _ := p.opt.LookupVar(name) val, ok := p.opt.Vars[name]
if !ok {
val, _ = p.opt.LookupVar(name)
}
vv := cty.StringVal(val) vv := cty.StringVal(val)
v = &vv v = &vv
return return
@ -243,6 +247,9 @@ func Parse(b hcl.Body, opt Opt, val interface{}) hcl.Diagnostics {
for _, bs := range schema.Blocks { for _, bs := range schema.Blocks {
reserved[bs.Type] = struct{}{} reserved[bs.Type] = struct{}{}
} }
for k := range opt.Vars {
reserved[k] = struct{}{}
}
var defs inputs var defs inputs
if err := gohcl.DecodeBody(b, nil, &defs); err != nil { if err := gohcl.DecodeBody(b, nil, &defs); err != nil {
@ -303,6 +310,10 @@ func Parse(b hcl.Body, opt Opt, val interface{}) hcl.Diagnostics {
} }
delete(p.attrs, "function") delete(p.attrs, "function")
for k := range p.opt.Vars {
_ = p.resolveValue(k)
}
for k := range p.attrs { for k := range p.attrs {
if err := p.resolveValue(k); err != nil { if err := p.resolveValue(k); err != nil {
if diags, ok := err.(hcl.Diagnostics); ok { if diags, ok := err.(hcl.Diagnostics); ok {

@ -36,11 +36,19 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions) (err error
}() }()
var url string var url string
cmdContext := "cwd://"
if len(targets) > 0 { if len(targets) > 0 {
if bake.IsRemoteURL(targets[0]) { if bake.IsRemoteURL(targets[0]) {
url = targets[0] url = targets[0]
targets = targets[1:] targets = targets[1:]
if len(targets) > 0 {
if bake.IsRemoteURL(targets[0]) {
cmdContext = targets[0]
targets = targets[1:]
}
}
} }
} }
@ -85,6 +93,7 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions) (err error
var files []bake.File var files []bake.File
var inp *bake.Input var inp *bake.Input
if url != "" { if url != "" {
files, inp, err = bake.ReadRemoteFiles(ctx, dis, url, in.files, printer) files, inp, err = bake.ReadRemoteFiles(ctx, dis, url, in.files, printer)
} else { } else {
@ -94,7 +103,15 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions) (err error
return err return err
} }
m, err := bake.ReadTargets(ctx, files, targets, overrides) m, err := bake.ReadTargets(ctx, files, targets, overrides, map[string]string{
"BAKE_CMD_CONTEXT": cmdContext,
})
if err != nil {
return err
}
// this function can update target context string from the input so call before printOnly check
bo, err := bake.TargetsToBuildOpt(m, inp)
if err != nil { if err != nil {
return err return err
} }
@ -113,11 +130,6 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions) (err error
return nil return nil
} }
bo, err := bake.TargetsToBuildOpt(m, inp)
if err != nil {
return err
}
resp, err := build.Build(ctx, dis, bo, dockerAPI(dockerCli), dockerCli.ConfigFile(), printer) resp, err := build.Build(ctx, dis, bo, dockerAPI(dockerCli), dockerCli.ConfigFile(), printer)
if err != nil { if err != nil {
return err return err

Loading…
Cancel
Save