Browse Source

Allow ARG to come before FROM to support variables in FROM.

Signed-off-by: Daniel Nephin <dnephin@docker.com>
Daniel Nephin 8 years ago
parent
commit
f0a9c2e3f4

+ 6 - 1
builder/dockerfile/builder.go

@@ -72,7 +72,7 @@ type Builder struct {
 	tmpContainers    map[string]struct{}
 	tmpContainers    map[string]struct{}
 	image            string         // imageID
 	image            string         // imageID
 	imageContexts    *imageContexts // helper for storing contexts from builds
 	imageContexts    *imageContexts // helper for storing contexts from builds
-	noBaseImage      bool
+	noBaseImage      bool           // A flag to track the use of `scratch` as the base image
 	maintainer       string
 	maintainer       string
 	cmdSet           bool
 	cmdSet           bool
 	disableCommit    bool
 	disableCommit    bool
@@ -328,6 +328,11 @@ func (b *Builder) warnOnUnusedBuildArgs() {
 	}
 	}
 }
 }
 
 
+// hasFromImage returns true if the builder has processed a `FROM <image>` line
+func (b *Builder) hasFromImage() bool {
+	return b.image != "" || b.noBaseImage
+}
+
 // Cancel cancels an ongoing Dockerfile build.
 // Cancel cancels an ongoing Dockerfile build.
 func (b *Builder) Cancel() {
 func (b *Builder) Cancel() {
 	b.cancel()
 	b.cancel()

+ 17 - 2
builder/dockerfile/dispatchers.go

@@ -22,6 +22,7 @@ import (
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/strslice"
 	"github.com/docker/docker/api/types/strslice"
 	"github.com/docker/docker/builder"
 	"github.com/docker/docker/builder"
+	"github.com/docker/docker/pkg/shellvar"
 	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/go-connections/nat"
 	"github.com/docker/go-connections/nat"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
@@ -218,7 +219,17 @@ func from(b *Builder, args []string, attributes map[string]bool, original string
 		return err
 		return err
 	}
 	}
 
 
-	name := args[0]
+	getBuildArg := func(key string) (string, bool) {
+		value, ok := b.options.BuildArgs[key]
+		if value != nil {
+			return *value, ok
+		}
+		return "", ok
+	}
+	name, err := shellvar.Substitute(args[0], getBuildArg)
+	if err != nil {
+		return err
+	}
 
 
 	var image builder.Image
 	var image builder.Image
 
 
@@ -360,7 +371,7 @@ func workdir(b *Builder, args []string, attributes map[string]bool, original str
 // RUN [ "echo", "hi" ] # echo hi
 // RUN [ "echo", "hi" ] # echo hi
 //
 //
 func run(b *Builder, args []string, attributes map[string]bool, original string) error {
 func run(b *Builder, args []string, attributes map[string]bool, original string) error {
-	if b.image == "" && !b.noBaseImage {
+	if !b.hasFromImage() {
 		return errors.New("Please provide a source image with `from` prior to run")
 		return errors.New("Please provide a source image with `from` prior to run")
 	}
 	}
 
 
@@ -790,6 +801,10 @@ func arg(b *Builder, args []string, attributes map[string]bool, original string)
 	}
 	}
 	b.allowedBuildArgs[name] = value
 	b.allowedBuildArgs[name] = value
 
 
+	// Arg before FROM doesn't add a layer
+	if !b.hasFromImage() {
+		return nil
+	}
 	return b.commit("", b.runConfig.Cmd, fmt.Sprintf("ARG %s", arg))
 	return b.commit("", b.runConfig.Cmd, fmt.Sprintf("ARG %s", arg))
 }
 }
 
 

+ 2 - 2
builder/dockerfile/internals.go

@@ -44,7 +44,7 @@ func (b *Builder) commit(id string, autoCmd strslice.StrSlice, comment string) e
 	if b.disableCommit {
 	if b.disableCommit {
 		return nil
 		return nil
 	}
 	}
-	if b.image == "" && !b.noBaseImage {
+	if !b.hasFromImage() {
 		return errors.New("Please provide a source image with `from` prior to commit")
 		return errors.New("Please provide a source image with `from` prior to commit")
 	}
 	}
 	b.runConfig.Image = b.image
 	b.runConfig.Image = b.image
@@ -503,7 +503,7 @@ func (b *Builder) probeCache() (bool, error) {
 }
 }
 
 
 func (b *Builder) create() (string, error) {
 func (b *Builder) create() (string, error) {
-	if b.image == "" && !b.noBaseImage {
+	if !b.hasFromImage() {
 		return "", errors.New("Please provide a source image with `from` prior to run")
 		return "", errors.New("Please provide a source image with `from` prior to run")
 	}
 	}
 	b.runConfig.Image = b.image
 	b.runConfig.Image = b.image