Browse code

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

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2017/02/25 07:19:45
Showing 3 changed files
... ...
@@ -72,7 +72,7 @@ type Builder struct {
72 72
 	tmpContainers    map[string]struct{}
73 73
 	image            string         // imageID
74 74
 	imageContexts    *imageContexts // helper for storing contexts from builds
75
-	noBaseImage      bool
75
+	noBaseImage      bool           // A flag to track the use of `scratch` as the base image
76 76
 	maintainer       string
77 77
 	cmdSet           bool
78 78
 	disableCommit    bool
... ...
@@ -328,6 +328,11 @@ func (b *Builder) warnOnUnusedBuildArgs() {
328 328
 	}
329 329
 }
330 330
 
331
+// hasFromImage returns true if the builder has processed a `FROM <image>` line
332
+func (b *Builder) hasFromImage() bool {
333
+	return b.image != "" || b.noBaseImage
334
+}
335
+
331 336
 // Cancel cancels an ongoing Dockerfile build.
332 337
 func (b *Builder) Cancel() {
333 338
 	b.cancel()
... ...
@@ -22,6 +22,7 @@ import (
22 22
 	"github.com/docker/docker/api/types/container"
23 23
 	"github.com/docker/docker/api/types/strslice"
24 24
 	"github.com/docker/docker/builder"
25
+	"github.com/docker/docker/pkg/shellvar"
25 26
 	"github.com/docker/docker/pkg/signal"
26 27
 	"github.com/docker/go-connections/nat"
27 28
 	"github.com/pkg/errors"
... ...
@@ -218,7 +219,17 @@ func from(b *Builder, args []string, attributes map[string]bool, original string
218 218
 		return err
219 219
 	}
220 220
 
221
-	name := args[0]
221
+	getBuildArg := func(key string) (string, bool) {
222
+		value, ok := b.options.BuildArgs[key]
223
+		if value != nil {
224
+			return *value, ok
225
+		}
226
+		return "", ok
227
+	}
228
+	name, err := shellvar.Substitute(args[0], getBuildArg)
229
+	if err != nil {
230
+		return err
231
+	}
222 232
 
223 233
 	var image builder.Image
224 234
 
... ...
@@ -360,7 +371,7 @@ func workdir(b *Builder, args []string, attributes map[string]bool, original str
360 360
 // RUN [ "echo", "hi" ] # echo hi
361 361
 //
362 362
 func run(b *Builder, args []string, attributes map[string]bool, original string) error {
363
-	if b.image == "" && !b.noBaseImage {
363
+	if !b.hasFromImage() {
364 364
 		return errors.New("Please provide a source image with `from` prior to run")
365 365
 	}
366 366
 
... ...
@@ -790,6 +801,10 @@ func arg(b *Builder, args []string, attributes map[string]bool, original string)
790 790
 	}
791 791
 	b.allowedBuildArgs[name] = value
792 792
 
793
+	// Arg before FROM doesn't add a layer
794
+	if !b.hasFromImage() {
795
+		return nil
796
+	}
793 797
 	return b.commit("", b.runConfig.Cmd, fmt.Sprintf("ARG %s", arg))
794 798
 }
795 799
 
... ...
@@ -44,7 +44,7 @@ func (b *Builder) commit(id string, autoCmd strslice.StrSlice, comment string) e
44 44
 	if b.disableCommit {
45 45
 		return nil
46 46
 	}
47
-	if b.image == "" && !b.noBaseImage {
47
+	if !b.hasFromImage() {
48 48
 		return errors.New("Please provide a source image with `from` prior to commit")
49 49
 	}
50 50
 	b.runConfig.Image = b.image
... ...
@@ -503,7 +503,7 @@ func (b *Builder) probeCache() (bool, error) {
503 503
 }
504 504
 
505 505
 func (b *Builder) create() (string, error) {
506
-	if b.image == "" && !b.noBaseImage {
506
+	if !b.hasFromImage() {
507 507
 		return "", errors.New("Please provide a source image with `from` prior to run")
508 508
 	}
509 509
 	b.runConfig.Image = b.image