diff --git a/components/engine/builder/dockerfile/dispatchers.go b/components/engine/builder/dockerfile/dispatchers.go index 99d4aa627e..38e6f768c4 100644 --- a/components/engine/builder/dockerfile/dispatchers.go +++ b/components/engine/builder/dockerfile/dispatchers.go @@ -148,7 +148,7 @@ func (d *dispatchRequest) getImageMount(imageRefOrID string) (*imageMount, error return d.builder.imageSources.Get(imageRefOrID, localOnly) } -// FROM imagename[:tag | @digest] [AS build-stage-name] +// FROM [--platform=platform] imagename[:tag | @digest] [AS build-stage-name] // func initializeStage(d dispatchRequest, cmd *instructions.Stage) error { d.builder.imageProber.Reset() diff --git a/components/engine/builder/dockerfile/instructions/commands.go b/components/engine/builder/dockerfile/instructions/commands.go index d4f55ceb43..44382dc61e 100644 --- a/components/engine/builder/dockerfile/instructions/commands.go +++ b/components/engine/builder/dockerfile/instructions/commands.go @@ -357,10 +357,11 @@ type ShellCommand struct { // Stage represents a single stage in a multi-stage build type Stage struct { - Name string - Commands []Command - BaseName string - SourceCode string + Name string + Commands []Command + BaseName string + SourceCode string + OperatingSystem string } // AddCommand to the stage diff --git a/components/engine/builder/dockerfile/instructions/parse.go b/components/engine/builder/dockerfile/instructions/parse.go index 9226f4d46e..9b94ee3660 100644 --- a/components/engine/builder/dockerfile/instructions/parse.go +++ b/components/engine/builder/dockerfile/instructions/parse.go @@ -3,6 +3,7 @@ package instructions // import "github.com/docker/docker/builder/dockerfile/inst import ( "fmt" "regexp" + "runtime" "sort" "strconv" "strings" @@ -12,6 +13,7 @@ import ( "github.com/docker/docker/api/types/strslice" "github.com/docker/docker/builder/dockerfile/command" "github.com/docker/docker/builder/dockerfile/parser" + "github.com/docker/docker/pkg/system" "github.com/pkg/errors" ) @@ -271,16 +273,31 @@ func parseFrom(req parseRequest) (*Stage, error) { return nil, err } + flPlatform := req.flags.AddString("platform", "") if err := req.flags.Parse(); err != nil { return nil, err } + specPlatform := system.ParsePlatform(flPlatform.Value) + if specPlatform.OS == "" { + specPlatform.OS = runtime.GOOS + } + if err := system.ValidatePlatform(specPlatform); err != nil { + return nil, fmt.Errorf("invalid platform %q on FROM", flPlatform.Value) + } + if !system.IsOSSupported(specPlatform.OS) { + return nil, fmt.Errorf("unsupported platform %q on FROM", flPlatform.Value) + } + if err != nil { + return nil, err + } code := strings.TrimSpace(req.original) - + fmt.Println("JJH", specPlatform.OS) return &Stage{ - BaseName: req.args[0], - Name: stageName, - SourceCode: code, - Commands: []Command{}, + BaseName: req.args[0], + Name: stageName, + SourceCode: code, + Commands: []Command{}, + OperatingSystem: specPlatform.OS, }, nil } diff --git a/components/engine/builder/dockerfile/instructions/parse_test.go b/components/engine/builder/dockerfile/instructions/parse_test.go index ffd6d4f45c..0c27f203d0 100644 --- a/components/engine/builder/dockerfile/instructions/parse_test.go +++ b/components/engine/builder/dockerfile/instructions/parse_test.go @@ -1,6 +1,8 @@ package instructions // import "github.com/docker/docker/builder/dockerfile/instructions" import ( + "fmt" + "runtime" "strings" "testing" @@ -184,6 +186,16 @@ func TestErrorCases(t *testing.T) { dockerfile: `foo bar`, expectedError: "unknown instruction: FOO", }, + { + name: "Invalid platform", + dockerfile: `FROM --platform=invalid busybox`, + expectedError: `invalid platform "invalid"`, + }, + { + name: "Only OS", + dockerfile: fmt.Sprintf(`FROM --platform=%s/%s busybox`, runtime.GOOS, runtime.GOARCH), + expectedError: `invalid platform`, + }, } for _, c := range cases { r := strings.NewReader(c.dockerfile) @@ -196,5 +208,4 @@ func TestErrorCases(t *testing.T) { _, err = ParseInstruction(n) testutil.ErrorContains(t, err, c.expectedError) } - }