From 69bb8e8a1582db889d872d7088db6884454c4675 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Tue, 10 Jul 2018 16:57:57 -0700 Subject: [PATCH] dockerfile: allow automatic platform variables Signed-off-by: Tonis Tiigi --- frontend/dockerfile/dockerfile2llb/convert.go | 6 +- .../dockerfile/dockerfile2llb/platform.go | 22 ++++ frontend/dockerfile/dockerfile_test.go | 103 ++++++++++++++++++ 3 files changed, 130 insertions(+), 1 deletion(-) diff --git a/frontend/dockerfile/dockerfile2llb/convert.go b/frontend/dockerfile/dockerfile2llb/convert.go index 40dd2875..3ecaee63 100644 --- a/frontend/dockerfile/dockerfile2llb/convert.go +++ b/frontend/dockerfile/dockerfile2llb/convert.go @@ -58,6 +58,11 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, platformOpt := buildPlatformOpt(&opt) + optMetaArgs := getPlatformArgs(platformOpt) + for i, arg := range optMetaArgs { + optMetaArgs[i] = setKVValue(arg, opt.BuildArgs) + } + dockerfile, err := parser.Parse(bytes.NewReader(dt)) if err != nil { return nil, nil, err @@ -70,7 +75,6 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, return nil, nil, err } - optMetaArgs := []instructions.KeyValuePairOptional{} for _, metaArg := range metaArgs { optMetaArgs = append(optMetaArgs, setKVValue(metaArg.KeyValuePairOptional, opt.BuildArgs)) } diff --git a/frontend/dockerfile/dockerfile2llb/platform.go b/frontend/dockerfile/dockerfile2llb/platform.go index 545f689b..e1ef78f8 100644 --- a/frontend/dockerfile/dockerfile2llb/platform.go +++ b/frontend/dockerfile/dockerfile2llb/platform.go @@ -2,6 +2,7 @@ package dockerfile2llb import ( "github.com/containerd/containerd/platforms" + "github.com/moby/buildkit/frontend/dockerfile/instructions" specs "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -34,3 +35,24 @@ func buildPlatformOpt(opt *ConvertOpt) *platformOpt { implicitTarget: implicitTargetPlatform, } } + +func getPlatformArgs(po *platformOpt) []instructions.KeyValuePairOptional { + bp := po.buildPlatforms[0] + tp := po.targetPlatform + m := map[string]string{ + "BUILDPLATFORM": platforms.Format(bp), + "BUILDOS": bp.OS, + "BUILDARCH": bp.Architecture, + "BUILDVARIANT": bp.Variant, + "TARGETPLATFORM": platforms.Format(tp), + "TARGETOS": tp.OS, + "TARGETARCH": tp.Architecture, + "TARGETVARIANT": tp.Variant, + } + opts := make([]instructions.KeyValuePairOptional, 0, len(m)) + for k, v := range m { + s := v + opts = append(opts, instructions.KeyValuePairOptional{Key: k, Value: &s}) + } + return opts +} diff --git a/frontend/dockerfile/dockerfile_test.go b/frontend/dockerfile/dockerfile_test.go index 9e4c0a0c..4a2653c8 100644 --- a/frontend/dockerfile/dockerfile_test.go +++ b/frontend/dockerfile/dockerfile_test.go @@ -13,6 +13,7 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "sort" "strings" "testing" @@ -69,6 +70,8 @@ func TestIntegration(t *testing.T) { testNoSnapshotLeak, testCopySymlinks, testContextChangeDirToFile, + testPlatformArgsImplicit, + testPlatformArgsExplicit, }) } @@ -2281,6 +2284,106 @@ COPY --from=s1 unique2 / require.NotEqual(t, string(unique2Dir1), string(unique2Dir3)) } +func testPlatformArgsImplicit(t *testing.T, sb integration.Sandbox) { + t.Parallel() + + dockerfile := []byte(fmt.Sprintf(` +FROM scratch AS build-%s +COPY foo bar +FROM build-${TARGETOS} +COPY foo2 bar2 +`, runtime.GOOS)) + + dir, err := tmpdir( + fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("foo", []byte("d0"), 0600), + fstest.CreateFile("foo2", []byte("d1"), 0600), + ) + require.NoError(t, err) + defer os.RemoveAll(dir) + + c, err := client.New(context.TODO(), sb.Address()) + require.NoError(t, err) + defer c.Close() + + destDir, err := ioutil.TempDir("", "buildkit") + require.NoError(t, err) + defer os.RemoveAll(destDir) + + opt := client.SolveOpt{ + Frontend: "dockerfile.v0", + Exporter: client.ExporterLocal, + ExporterOutputDir: destDir, + LocalDirs: map[string]string{ + builder.LocalNameDockerfile: dir, + builder.LocalNameContext: dir, + }, + } + + _, err = c.Solve(context.TODO(), nil, opt, nil) + require.NoError(t, err) + + dt, err := ioutil.ReadFile(filepath.Join(destDir, "bar")) + require.NoError(t, err) + require.Equal(t, "d0", string(dt)) + + dt, err = ioutil.ReadFile(filepath.Join(destDir, "bar2")) + require.NoError(t, err) + require.Equal(t, "d1", string(dt)) +} + +func testPlatformArgsExplicit(t *testing.T, sb integration.Sandbox) { + t.Parallel() + + dockerfile := []byte(` +FROM --platform=$BUILDPLATFORM busybox AS build +ARG TARGETPLATFORM +ARG TARGETOS +RUN mkdir /out && echo -n $TARGETPLATFORM > /out/platform && echo -n $TARGETOS > /out/os +FROM scratch +COPY --from=build out . +`) + + dir, err := tmpdir( + fstest.CreateFile("Dockerfile", dockerfile, 0600), + ) + require.NoError(t, err) + defer os.RemoveAll(dir) + + c, err := client.New(context.TODO(), sb.Address()) + require.NoError(t, err) + defer c.Close() + + destDir, err := ioutil.TempDir("", "buildkit") + require.NoError(t, err) + defer os.RemoveAll(destDir) + + opt := client.SolveOpt{ + Frontend: "dockerfile.v0", + Exporter: client.ExporterLocal, + FrontendAttrs: map[string]string{ + "platform": "darwin/ppc64le", + "build-arg:TARGETOS": "freebsd", + }, + ExporterOutputDir: destDir, + LocalDirs: map[string]string{ + builder.LocalNameDockerfile: dir, + builder.LocalNameContext: dir, + }, + } + + _, err = c.Solve(context.TODO(), nil, opt, nil) + require.NoError(t, err) + + dt, err := ioutil.ReadFile(filepath.Join(destDir, "platform")) + require.NoError(t, err) + require.Equal(t, "darwin/ppc64le", string(dt)) + + dt, err = ioutil.ReadFile(filepath.Join(destDir, "os")) + require.NoError(t, err) + require.Equal(t, "freebsd", string(dt)) +} + func testBuiltinArgs(t *testing.T, sb integration.Sandbox) { t.Parallel()