Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v0.10] cherry-picks for v0.10.3 #1609

Merged
merged 8 commits into from
Feb 16, 2023
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
1 change: 1 addition & 0 deletions bake/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ func ParseCompose(cfgs []compose.ConfigFile, envs map[string]string) (*Config, e
// compose does not support nil values for labels
labels := map[string]*string{}
for k, v := range s.Build.Labels {
v := v
labels[k] = &v
}

Expand Down
18 changes: 18 additions & 0 deletions bake/hcl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,24 @@ func TestJSONFunctions(t *testing.T) {
require.Equal(t, ptrstr("pre-<FOO-abc>"), c.Targets[0].Args["v1"])
}

func TestJSONInvalidFunctions(t *testing.T) {
dt := []byte(`{
"target": {
"app": {
"args": {
"v1": "myfunc(\"foo\")"
}
}
}}`)

c, err := ParseFile(dt, "docker-bake.json")
require.NoError(t, err)

require.Equal(t, 1, len(c.Targets))
require.Equal(t, c.Targets[0].Name, "app")
require.Equal(t, ptrstr(`myfunc("foo")`), c.Targets[0].Args["v1"])
}

func TestHCLFunctionInAttr(t *testing.T) {
dt := []byte(`
function "brace" {
Expand Down
10 changes: 1 addition & 9 deletions bake/hclparser/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,7 @@ func funcCalls(exp hcl.Expression) ([]string, hcl.Diagnostics) {
if !ok {
fns, err := jsonFuncCallsRecursive(exp)
if err != nil {
return nil, hcl.Diagnostics{
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid expression",
Detail: err.Error(),
Subject: exp.Range().Ptr(),
Context: exp.Range().Ptr(),
},
}
return nil, wrapErrorDiagnostic("Invalid expression", err, exp.Range().Ptr(), exp.Range().Ptr())
}
return fns, nil
}
Expand Down
117 changes: 43 additions & 74 deletions bake/hclparser/hclparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,23 +62,20 @@ type parser struct {
doneB map[*hcl.Block]map[string]struct{}
}

func (p *parser) loadDeps(exp hcl.Expression, exclude map[string]struct{}) hcl.Diagnostics {
var errUndefined = errors.New("undefined")

func (p *parser) loadDeps(exp hcl.Expression, exclude map[string]struct{}, allowMissing bool) hcl.Diagnostics {
fns, hcldiags := funcCalls(exp)
if hcldiags.HasErrors() {
return hcldiags
}

for _, fn := range fns {
if err := p.resolveFunction(fn); err != nil {
return hcl.Diagnostics{
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid expression",
Detail: err.Error(),
Subject: exp.Range().Ptr(),
Context: exp.Range().Ptr(),
},
if allowMissing && errors.Is(err, errUndefined) {
continue
}
return wrapErrorDiagnostic("Invalid expression", err, exp.Range().Ptr(), exp.Range().Ptr())
}
}

Expand Down Expand Up @@ -128,27 +125,17 @@ func (p *parser) loadDeps(exp hcl.Expression, exclude map[string]struct{}) hcl.D
}
}
if err := p.resolveBlock(blocks[0], target); err != nil {
return hcl.Diagnostics{
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid expression",
Detail: err.Error(),
Subject: v.SourceRange().Ptr(),
Context: v.SourceRange().Ptr(),
},
if allowMissing && errors.Is(err, errUndefined) {
continue
}
return wrapErrorDiagnostic("Invalid expression", err, exp.Range().Ptr(), exp.Range().Ptr())
}
} else {
if err := p.resolveValue(v.RootName()); err != nil {
return hcl.Diagnostics{
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid expression",
Detail: err.Error(),
Subject: v.SourceRange().Ptr(),
Context: v.SourceRange().Ptr(),
},
if allowMissing && errors.Is(err, errUndefined) {
continue
}
return wrapErrorDiagnostic("Invalid expression", err, exp.Range().Ptr(), exp.Range().Ptr())
}
}
}
Expand All @@ -167,7 +154,7 @@ func (p *parser) resolveFunction(name string) error {
if _, ok := p.ectx.Functions[name]; ok {
return nil
}
return errors.Errorf("undefined function %s", name)
return errors.Wrapf(errUndefined, "function %q does not exit", name)
}
if _, ok := p.progressF[name]; ok {
return errors.Errorf("function cycle not allowed for %s", name)
Expand Down Expand Up @@ -217,7 +204,7 @@ func (p *parser) resolveFunction(name string) error {
return diags
}

if diags := p.loadDeps(f.Result.Expr, params); diags.HasErrors() {
if diags := p.loadDeps(f.Result.Expr, params, false); diags.HasErrors() {
return diags
}

Expand Down Expand Up @@ -255,7 +242,7 @@ func (p *parser) resolveValue(name string) (err error) {
if _, builtin := p.opt.Vars[name]; !ok && !builtin {
vr, ok := p.vars[name]
if !ok {
return errors.Errorf("undefined variable %q", name)
return errors.Wrapf(errUndefined, "variable %q does not exit", name)
}
def = vr.Default
}
Expand All @@ -270,7 +257,7 @@ func (p *parser) resolveValue(name string) (err error) {
return
}

if diags := p.loadDeps(def.Expr, nil); diags.HasErrors() {
if diags := p.loadDeps(def.Expr, nil, true); diags.HasErrors() {
return diags
}
vv, diags := def.Expr.Value(p.ectx)
Expand Down Expand Up @@ -314,14 +301,7 @@ func (p *parser) resolveValue(name string) (err error) {
func (p *parser) resolveBlock(block *hcl.Block, target *hcl.BodySchema) (err error) {
name := block.Labels[0]
if err := p.opt.ValidateLabel(name); err != nil {
return hcl.Diagnostics{
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid name",
Detail: err.Error(),
Subject: &block.LabelRanges[0],
},
}
return wrapErrorDiagnostic("Invalid name", err, &block.LabelRanges[0], &block.LabelRanges[0])
}

if _, ok := p.doneB[block]; !ok {
Expand Down Expand Up @@ -395,7 +375,7 @@ func (p *parser) resolveBlock(block *hcl.Block, target *hcl.BodySchema) (err err
return diag
}
for _, a := range content.Attributes {
diag := p.loadDeps(a.Expr, nil)
diag := p.loadDeps(a.Expr, nil, true)
if diag.HasErrors() {
return diag
}
Expand Down Expand Up @@ -573,15 +553,7 @@ func Parse(b hcl.Body, opt Opt, val interface{}) hcl.Diagnostics {
return diags
}
r := p.vars[k].Body.MissingItemRange()
return hcl.Diagnostics{
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid value",
Detail: err.Error(),
Subject: &r,
Context: &r,
},
}
return wrapErrorDiagnostic("Invalid value", err, &r, &r)
}
}

Expand All @@ -604,15 +576,7 @@ func Parse(b hcl.Body, opt Opt, val interface{}) hcl.Diagnostics {
}
}
}
return hcl.Diagnostics{
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid function",
Detail: err.Error(),
Subject: subject,
Context: context,
},
}
return wrapErrorDiagnostic("Invalid function", err, subject, context)
}
}

Expand Down Expand Up @@ -673,15 +637,7 @@ func Parse(b hcl.Body, opt Opt, val interface{}) hcl.Diagnostics {
continue
}
} else {
return hcl.Diagnostics{
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid attribute",
Detail: err.Error(),
Subject: &b.LabelRanges[0],
Context: &b.DefRange,
},
}
return wrapErrorDiagnostic("Invalid block", err, &b.LabelRanges[0], &b.DefRange)
}
}

Expand Down Expand Up @@ -726,21 +682,34 @@ func Parse(b hcl.Body, opt Opt, val interface{}) hcl.Diagnostics {
if diags, ok := err.(hcl.Diagnostics); ok {
return diags
}
return hcl.Diagnostics{
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid attribute",
Detail: err.Error(),
Subject: &p.attrs[k].Range,
Context: &p.attrs[k].Range,
},
}
return wrapErrorDiagnostic("Invalid attribute", err, &p.attrs[k].Range, &p.attrs[k].Range)
}
}

return nil
}

// wrapErrorDiagnostic wraps an error into a hcl.Diagnostics object.
// If the error is already an hcl.Diagnostics object, it is returned as is.
func wrapErrorDiagnostic(message string, err error, subject *hcl.Range, context *hcl.Range) hcl.Diagnostics {
switch err := err.(type) {
case *hcl.Diagnostic:
return hcl.Diagnostics{err}
case hcl.Diagnostics:
return err
default:
return hcl.Diagnostics{
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: message,
Detail: err.Error(),
Subject: subject,
Context: context,
},
}
}
}

func setLabel(v reflect.Value, lbl string) int {
// cache field index?
numFields := v.Elem().Type().NumField()
Expand Down
4 changes: 2 additions & 2 deletions bake/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ func ReadRemoteFiles(ctx context.Context, nodes []builder.Node, url string, name
var files []File

var node *builder.Node
for _, n := range nodes {
for i, n := range nodes {
if n.Err == nil {
node = &n
node = &nodes[i]
continue
}
}
Expand Down
2 changes: 1 addition & 1 deletion build/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath st
return res, nil
}

if sha, err := gitc.FullCommit(); err != nil {
if sha, err := gitc.FullCommit(); err != nil && !gitutil.IsUnknownRevision(err) {
return res, errors.Wrapf(err, "buildx: failed to get git commit")
} else if sha != "" {
if gitc.IsDirty() {
Expand Down
31 changes: 27 additions & 4 deletions docs/reference/buildx_build.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ BuildKit currently supports:
Use `--attest=type=provenance` to generate provenance for an image at
build-time. Alternatively, you can use the [`--provenance` shorthand](#provenance).

By default, a minimal provenance attestation will be created for the build
result, which will only be attached for images pushed to registries.

For more information, see [here](https://docs.docker.com/build/attestations/slsa-provenance/).

### <a name="allow"></a> Allow extra privileged entitlement (--allow)
Expand Down Expand Up @@ -477,8 +480,20 @@ $ docker buildx build --load --progress=plain .

### <a name="provenance"></a> Create provenance attestations (--provenance)

Shorthand for [`--attest=type=provenance`](#attest). Enables provenance
attestations for the build result.
Shorthand for [`--attest=type=provenance`](#attest), used to configure
provenance attestations for the build result. For example,
`--provenance=mode=max` can be used as an abbreviation for
`--attest=type=provenance,mode=max`.

Additionally, `--provenance` can be used with boolean values to broadly enable
or disable provenance attestations. For example, `--provenance=false` can be
used to disable all provenance attestations, while `--provenance=true` can be
used to enable all provenance attestations.

By default, a minimal provenance attestation will be created for the build
result, which will only be attached for images pushed to registries.

For more information, see [here](https://docs.docker.com/build/attestations/slsa-provenance/).

### <a name="push"></a> Push the build result to a registry (--push)

Expand All @@ -487,8 +502,16 @@ build result to registry.

### <a name="sbom"></a> Create SBOM attestations (--sbom)

Shorthand for [`--attest=type=sbom`](#attest). Enables SBOM attestations for
the build result.
Shorthand for [`--attest=type=sbom`](#attest), used to configure SBOM
attestations for the build result. For example,
`--sbom=generator=<user>/<generator-image>` can be used as an abbreviation for
`--attest=type=sbom,generator=<user>/<generator-image>`.

Additionally, `--sbom` can be used with boolean values to broadly enable or
disable SBOM attestations. For example, `--sbom=false` can be used to disable
all SBOM attestations.

For more information, see [here](https://docs.docker.com/build/attestations/sbom/).

### <a name="secret"></a> Secret to expose to the build (--secret)

Expand Down
1 change: 1 addition & 0 deletions store/storeutil/storeutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func GetNodeGroup(txn *store.Txn, dockerCli command.Cli, name string) (*store.No
Endpoint: name,
},
},
DockerContext: true,
}
if ng.LastActivity, err = txn.GetLastActivity(ng); err != nil {
return nil, err
Expand Down
13 changes: 13 additions & 0 deletions util/gitutil/gitutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package gitutil
import (
"bytes"
"context"
"os"
"os/exec"
"strings"

Expand Down Expand Up @@ -116,6 +117,9 @@ func (c *Git) run(args ...string) (string, error) {
cmd.Dir = c.wd
}

// Override the locale to ensure consistent output
cmd.Env = append(os.Environ(), "LC_ALL=C")

stdout := bytes.Buffer{}
stderr := bytes.Buffer{}
cmd.Stdout = &stdout
Expand All @@ -134,3 +138,12 @@ func (c *Git) clean(out string, err error) (string, error) {
}
return out, err
}

func IsUnknownRevision(err error) bool {
if err == nil {
return false
}
// https://github.com/git/git/blob/a6a323b31e2bcbac2518bddec71ea7ad558870eb/setup.c#L204
errMsg := strings.ToLower(err.Error())
return strings.Contains(errMsg, "unknown revision or path not in the working tree") || strings.Contains(errMsg, "bad revision")
}
Loading