diff --git a/dispatchers.go b/dispatchers.go index ff365848..3d62a388 100644 --- a/dispatchers.go +++ b/dispatchers.go @@ -21,12 +21,34 @@ import ( "github.com/openshift/imagebuilder/signal" "github.com/openshift/imagebuilder/strslice" + "github.com/containerd/containerd/platforms" ) var ( obRgex = regexp.MustCompile(`(?i)^\s*ONBUILD\s*`) ) +var localspec = platforms.DefaultSpec() + +// https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope +var builtinBuildArgs = map[string]string{ + "TARGETPLATFORM": localspec.OS + "/" + localspec.Architecture, + "TARGETOS": localspec.OS, + "TARGETARCH": localspec.Architecture, + "TARGETVARIANT": localspec.Variant, + "BUILDPLATFORM": localspec.OS + "/" + localspec.Architecture, + "BUILDOS": localspec.OS, + "BUILDARCH": localspec.Architecture, + "BUILDVARIANT": localspec.Variant, +} + +func init() { + if localspec.Variant != "" { + builtinBuildArgs["TARGETPLATFORM"] = builtinBuildArgs["TARGETPLATFORM"] + "/" + localspec.Variant + builtinBuildArgs["BUILDPLATFORM"] = builtinBuildArgs["BUILDPLATFORM"] + "/" + localspec.Variant + } +} + // ENV foo bar // // Sets the environment variable foo to bar, also makes interpolation @@ -516,6 +538,9 @@ func healthcheck(b *Builder, args []string, attributes map[string]bool, flagArgs return nil } + +var targetArgs = []string {"TARGETOS", "TARGETARCH", "TARGETVARIANT"} + // ARG name[=value] // // Adds the variable foo to the trusted list of variables that can be passed @@ -543,6 +568,26 @@ func arg(b *Builder, args []string, attributes map[string]bool, flagArgs []strin name = parts[0] value = parts[1] hasDefault = true + if name == "TARGETPLATFORM" { + p, err := platforms.Parse(value) + if err != nil { + return fmt.Errorf("error parsing TARGETPLATFORM argument") + } + for _, val := range targetArgs { + b.AllowedArgs[val] = true + } + b.Args["TARGETPLATFORM"] = p.OS + "/" + p.Architecture + b.Args["TARGETOS"] = p.OS + b.Args["TARGETARCH"] = p.Architecture + b.Args["TARGETVARIANT"] = p.Variant + if p.Variant != "" { + b.Args["TARGETPLATFORM"] = b.Args["TARGETPLATFORM"] + "/" + p.Variant + } + } + } else if val, ok := builtinBuildArgs[arg]; ok { + name = arg + value = val + hasDefault = true } else { name = arg hasDefault = false diff --git a/dispatchers_test.go b/dispatchers_test.go index 9a80d320..fa04c671 100644 --- a/dispatchers_test.go +++ b/dispatchers_test.go @@ -3,10 +3,64 @@ package imagebuilder import ( "reflect" "testing" + "sort" + "errors" + "github.com/containerd/containerd/platforms" docker "github.com/fsouza/go-dockerclient" ) +func TestDispatchArgDefaultBuiltins(t *testing.T) { + mybuilder := *NewBuilder(make(map[string]string)) + args := []string{"TARGETPLATFORM"} + if err := arg(&mybuilder, args, nil, nil, ""); err != nil { + t.Errorf("arg error: %v", err) + } + args = []string{"BUILDARCH"} + if err := arg(&mybuilder, args, nil, nil, ""); err != nil { + t.Errorf("arg(2) error: %v", err) + } + localspec := platforms.DefaultSpec() + expectedArgs := []string { + "BUILDARCH=" + localspec.Architecture, + "TARGETPLATFORM=" + localspec.OS + "/" + localspec.Architecture, + } + got := mybuilder.Arguments() + sort.Strings(got) + if !reflect.DeepEqual(got, expectedArgs) { + t.Errorf("Expected %v, got %v\n", expectedArgs, got) + } +} + +func TestDispatchArgTargetPlatform(t *testing.T) { + mybuilder := *NewBuilder(make(map[string]string)) + args := []string{"TARGETPLATFORM=linux/arm/v7"} + if err := arg(&mybuilder, args, nil, nil, ""); err != nil { + t.Errorf("arg error: %v", err) + } + expectedArgs := []string { + "TARGETARCH=arm", + "TARGETOS=linux", + "TARGETPLATFORM=linux/arm/v7", + "TARGETVARIANT=v7", + } + got := mybuilder.Arguments() + sort.Strings(got) + if !reflect.DeepEqual(got, expectedArgs) { + t.Errorf("Expected %v, got %v\n", expectedArgs, got) + } +} + +func TestDispatchArgTargetPlatformBad(t *testing.T) { + mybuilder := *NewBuilder(make(map[string]string)) + args := []string{"TARGETPLATFORM=bozo"} + err := arg(&mybuilder, args, nil, nil, "") + expectedErr := errors.New("error parsing TARGETPLATFORM argument") + if !reflect.DeepEqual(err, expectedErr) { + t.Errorf("Expected %v, got %v\n", expectedErr, err) + } +} + func TestDispatchCopy(t *testing.T) { mybuilder := Builder{ RunConfig: docker.Config{