Skip to content

Commit

Permalink
Move build args up to Project level
Browse files Browse the repository at this point in the history
Signed-off-by: Peter Engelbert <[email protected]>
  • Loading branch information
pmengelbert committed Feb 29, 2024
1 parent 20fc9cd commit 3be456e
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 45 deletions.
31 changes: 25 additions & 6 deletions frontend/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,15 +284,22 @@ func Build(ctx context.Context, client gwclient.Client) (*gwclient.Result, error
}
buildPlatform = bc.BuildPlatforms[0]

args := dalec.DuplicateMap(bc.BuildArgs)
fillPlatformArgs("TARGET", args, targetPlatform)
fillPlatformArgs("BUILD", args, buildPlatform)
for _, spec := range project.GetSpecs() {
env := dalec.DuplicateMap(bc.BuildArgs)
fillPlatformArgs("TARGET", env, targetPlatform)
fillPlatformArgs("BUILD", env, buildPlatform)

args := make(map[string]string)
for k, v := range project.Args {
args[k] = v
}

spec := project.GetSpec()
if err := spec.SubstituteArgs(args); err != nil {
return nil, nil, err
if err := spec.SubstituteArgs(env, args); err != nil {
return nil, nil, err
}
}

spec := project.GetSpec()
return handlerFunc(ctx, client, spec)
})
if err != nil {
Expand All @@ -301,3 +308,15 @@ func Build(ctx context.Context, client gwclient.Client) (*gwclient.Result, error

return rb.Finalize()
}

func (p *projectWrapper) GetSpecs() []*dalec.Spec {
if p.isSingleSpec {
return []*dalec.Spec{p.Spec}
}

specs := make([]*dalec.Spec, len(p.Specs))
for i := range p.Specs {
specs[i] = &p.Specs[i]
}
return specs
}
6 changes: 1 addition & 5 deletions load.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,13 +211,9 @@ func (s *SourceBuild) validate(failContext ...string) (retErr error) {
return
}

func (s *Spec) SubstituteArgs(env map[string]string) error {
func (s *Spec) SubstituteArgs(env, args map[string]string) error {
lex := shell.NewLex('\\')

args := make(map[string]string)
for k, v := range s.Args {
args[k] = v
}
for k, v := range env {
if _, ok := args[k]; !ok {
if !knownArg(k) {
Expand Down
21 changes: 17 additions & 4 deletions project.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
package dalec

// `Project` is either a) A single spec or b) a list of specs nested
// under the `specs` key. In the case of the latter, the specs may
// or may not depend on one another.
// under the `specs` key. In the case of the latter, the specs may or
// may not depend on one another.
type Project struct {
*Spec `json:",inline,omitempty" yaml:",inline,omitempty"`
// The spec, in the event that the project is a single spec
*Spec `json:",inline,omitempty" yaml:",inline,omitempty"`

// Args is the list of arguments that can be used for shell-style expansion in (certain fields of) the spec.
// Any arg supplied in the build request which does not appear in this list will cause an error.
// Attempts to use an arg in the spec which is not specified here will assume to be a literal string.
// The map value is the default value to use if the arg is not supplied in the build request.
Args map[string]string `yaml:"args,omitempty" json:"args,omitempty"`

// A map of target-group to Frontend configurations. This
// applies to all specs in the file
Frontends map[string]Frontend `json:"frontend,omitempty" yaml:"frontend,omitempty"`
Specs []Spec `json:"specs,omitempty" yaml:"specs,omitempty"`

// The list of specs, in the event that the project contains
// multiple specs
Specs []Spec `json:"specs,omitempty" yaml:"specs,omitempty"`
}

// This is a placeholder until it is implemented by PR #146
Expand Down
6 changes: 0 additions & 6 deletions spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,6 @@ type Spec struct {
// Build is the configuration for building the artifacts in the package.
Build ArtifactBuild `yaml:"build,omitempty" json:"build,omitempty"`

// Args is the list of arguments that can be used for shell-style expansion in (certain fields of) the spec.
// Any arg supplied in the build request which does not appear in this list will cause an error.
// Attempts to use an arg in the spec which is not specified here will assume to be a literal string.
// The map value is the default value to use if the arg is not supplied in the build request.
Args map[string]string `yaml:"args,omitempty" json:"args,omitempty"`

// License is the license of the package.
License string `yaml:"license" json:"license"`
// Vendor is the vendor of the package.
Expand Down
28 changes: 28 additions & 0 deletions test/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,28 @@ func specToSolveRequest(ctx context.Context, t *testing.T, spec *dalec.Spec, sr
sr.FrontendInputs[dockerui.DefaultLocalNameDockerfile] = def.ToPB()
}

// specToSolveRequest injects the spec as the build context into the solve request.
func projectToSolveRequest(ctx context.Context, t *testing.T, project *dalec.Project, sr *gwclient.SolveRequest) {
t.Helper()

dt, err := yaml.Marshal(project)
if err != nil {
t.Fatal(err)
}

def, err := llb.Scratch().File(llb.Mkfile("Dockerfile", 0o644, dt)).Marshal(ctx)
if err != nil {
t.Fatal(err)
}

if sr.FrontendInputs == nil {
sr.FrontendInputs = make(map[string]*pb.Definition)
}

sr.FrontendInputs[dockerui.DefaultLocalNameContext] = def.ToPB()
sr.FrontendInputs[dockerui.DefaultLocalNameDockerfile] = def.ToPB()
}

func readFile(ctx context.Context, t *testing.T, name string, res *gwclient.Result) []byte {
t.Helper()

Expand Down Expand Up @@ -175,6 +197,12 @@ func withSpec(ctx context.Context, t *testing.T, spec *dalec.Spec) srOpt {
}
}

func withProject(ctx context.Context, t *testing.T, project *dalec.Project) srOpt {
return func(sr *gwclient.SolveRequest) {
projectToSolveRequest(ctx, t, project, sr)
}
}

func withBuildTarget(target string) srOpt {
return func(sr *gwclient.SolveRequest) {
if sr.FrontendOpt == nil {
Expand Down
47 changes: 25 additions & 22 deletions test/source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,34 @@ func TestSourceCmd(t *testing.T) {
ctx := startTestSpan(baseCtx, t)

sourceName := "checkcmd"
spec := &dalec.Spec{
project := &dalec.Project{
Args: map[string]string{
"BAR": "bar",
},
Name: "cmd-source-ref",
Sources: map[string]dalec.Source{
sourceName: {
Path: "/output",
DockerImage: &dalec.SourceDockerImage{
Ref: "busybox:latest",
Cmd: &dalec.Command{
Steps: []*dalec.BuildStep{
{
Command: `mkdir -p /output; echo "$FOO $BAR" > /output/foo`,
Env: map[string]string{
"FOO": "foo",
"BAR": "$BAR", // make sure args are passed through
Spec: &dalec.Spec{

Name: "cmd-source-ref",
Sources: map[string]dalec.Source{
sourceName: {
Path: "/output",
DockerImage: &dalec.SourceDockerImage{
Ref: "busybox:latest",
Cmd: &dalec.Command{
Steps: []*dalec.BuildStep{
{
Command: `mkdir -p /output; echo "$FOO $BAR" > /output/foo`,
Env: map[string]string{
"FOO": "foo",
"BAR": "$BAR", // make sure args are passed through
},
},
// make sure state is preserved for multiple steps
{
Command: `echo "hello" > /output/hello`,
},
{
Command: `cat /output/foo | grep "foo bar"`,
},
},
// make sure state is preserved for multiple steps
{
Command: `echo "hello" > /output/hello`,
},
{
Command: `cat /output/foo | grep "foo bar"`,
},
},
},
Expand All @@ -48,7 +51,7 @@ func TestSourceCmd(t *testing.T) {
}

testEnv.RunTest(ctx, t, func(ctx context.Context, gwc gwclient.Client) (*gwclient.Result, error) {
req := newSolveRequest(withBuildTarget("debug/sources"), withSpec(ctx, t, spec))
req := newSolveRequest(withBuildTarget("debug/sources"), withProject(ctx, t, project))
res, err := gwc.Solve(ctx, req)
if err != nil {
return nil, err
Expand Down
4 changes: 2 additions & 2 deletions test/var_passthrough_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ func TestPassthroughVars(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
runTest(t, func(ctx context.Context, gwc gwclient.Client) (*gwclient.Result, error) {
spec := &dalec.Spec{Args: tt.optInArgs, Build: dalec.ArtifactBuild{Env: tt.env}}
req := newSolveRequest(withBuildTarget("debug/resolve"), withSpec(ctx, t, spec), withPlatform(tt.targetPlatform))
project := &dalec.Project{Args: tt.optInArgs, Spec: &dalec.Spec{Build: dalec.ArtifactBuild{Env: tt.env}}}
req := newSolveRequest(withBuildTarget("debug/resolve"), withProject(ctx, t, project), withPlatform(tt.targetPlatform))
res, err := gwc.Solve(ctx, req)
if err != nil {
return nil, err
Expand Down

0 comments on commit 3be456e

Please sign in to comment.