Browse code

builder: Refactors according to @tiborvass's comments

Docker-DCO-1.1-Signed-off-by: Erik Hollensbe <github@hollensbe.org> (github: erikh)

Erik Hollensbe authored on 2014/08/27 04:25:44
Showing 6 changed files
1 1
deleted file mode 100644
... ...
@@ -1,15 +0,0 @@
1
-package builder
2
-
3
-import (
4
-	"github.com/docker/docker/runconfig"
5
-)
6
-
7
-// Create a new builder. See
8
-func NewBuilder(opts *BuildOpts) *BuildFile {
9
-	return &BuildFile{
10
-		Dockerfile:    nil,
11
-		Config:        &runconfig.Config{},
12
-		Options:       opts,
13
-		TmpContainers: map[string]struct{}{},
14
-	}
15
-}
... ...
@@ -18,7 +18,7 @@ import (
18 18
 )
19 19
 
20 20
 // dispatch with no layer / parsing. This is effectively not a command.
21
-func nullDispatch(b *BuildFile, args []string, attributes map[string]bool) error {
21
+func nullDispatch(b *Builder, args []string, attributes map[string]bool) error {
22 22
 	return nil
23 23
 }
24 24
 
... ...
@@ -27,7 +27,7 @@ func nullDispatch(b *BuildFile, args []string, attributes map[string]bool) error
27 27
 // Sets the environment variable foo to bar, also makes interpolation
28 28
 // in the dockerfile available from the next statement on via ${foo}.
29 29
 //
30
-func env(b *BuildFile, args []string, attributes map[string]bool) error {
30
+func env(b *Builder, args []string, attributes map[string]bool) error {
31 31
 	if len(args) != 2 {
32 32
 		return fmt.Errorf("ENV accepts two arguments")
33 33
 	}
... ...
@@ -48,7 +48,7 @@ func env(b *BuildFile, args []string, attributes map[string]bool) error {
48 48
 // MAINTAINER some text <maybe@an.email.address>
49 49
 //
50 50
 // Sets the maintainer metadata.
51
-func maintainer(b *BuildFile, args []string, attributes map[string]bool) error {
51
+func maintainer(b *Builder, args []string, attributes map[string]bool) error {
52 52
 	if len(args) != 1 {
53 53
 		return fmt.Errorf("MAINTAINER requires only one argument")
54 54
 	}
... ...
@@ -62,7 +62,7 @@ func maintainer(b *BuildFile, args []string, attributes map[string]bool) error {
62 62
 // Add the file 'foo' to '/path'. Tarball and Remote URL (git, http) handling
63 63
 // exist here. If you do not wish to have this automatic handling, use COPY.
64 64
 //
65
-func add(b *BuildFile, args []string, attributes map[string]bool) error {
65
+func add(b *Builder, args []string, attributes map[string]bool) error {
66 66
 	if len(args) != 2 {
67 67
 		return fmt.Errorf("ADD requires two arguments")
68 68
 	}
... ...
@@ -74,7 +74,7 @@ func add(b *BuildFile, args []string, attributes map[string]bool) error {
74 74
 //
75 75
 // Same as 'ADD' but without the tar and remote url handling.
76 76
 //
77
-func dispatchCopy(b *BuildFile, args []string, attributes map[string]bool) error {
77
+func dispatchCopy(b *Builder, args []string, attributes map[string]bool) error {
78 78
 	if len(args) != 2 {
79 79
 		return fmt.Errorf("COPY requires two arguments")
80 80
 	}
... ...
@@ -86,16 +86,16 @@ func dispatchCopy(b *BuildFile, args []string, attributes map[string]bool) error
86 86
 //
87 87
 // This sets the image the dockerfile will build on top of.
88 88
 //
89
-func from(b *BuildFile, args []string, attributes map[string]bool) error {
89
+func from(b *Builder, args []string, attributes map[string]bool) error {
90 90
 	if len(args) != 1 {
91 91
 		return fmt.Errorf("FROM requires one argument")
92 92
 	}
93 93
 
94 94
 	name := args[0]
95 95
 
96
-	image, err := b.Options.Daemon.Repositories().LookupImage(name)
96
+	image, err := b.Daemon.Repositories().LookupImage(name)
97 97
 	if err != nil {
98
-		if b.Options.Daemon.Graph().IsNotExist(err) {
98
+		if b.Daemon.Graph().IsNotExist(err) {
99 99
 			image, err = b.pullImage(name)
100 100
 		}
101 101
 
... ...
@@ -118,7 +118,7 @@ func from(b *BuildFile, args []string, attributes map[string]bool) error {
118 118
 // special cases. search for 'OnBuild' in internals.go for additional special
119 119
 // cases.
120 120
 //
121
-func onbuild(b *BuildFile, args []string, attributes map[string]bool) error {
121
+func onbuild(b *Builder, args []string, attributes map[string]bool) error {
122 122
 	triggerInstruction := strings.ToUpper(strings.TrimSpace(args[0]))
123 123
 	switch triggerInstruction {
124 124
 	case "ONBUILD":
... ...
@@ -137,7 +137,7 @@ func onbuild(b *BuildFile, args []string, attributes map[string]bool) error {
137 137
 //
138 138
 // Set the working directory for future RUN/CMD/etc statements.
139 139
 //
140
-func workdir(b *BuildFile, args []string, attributes map[string]bool) error {
140
+func workdir(b *Builder, args []string, attributes map[string]bool) error {
141 141
 	if len(args) != 1 {
142 142
 		return fmt.Errorf("WORKDIR requires exactly one argument")
143 143
 	}
... ...
@@ -165,7 +165,7 @@ func workdir(b *BuildFile, args []string, attributes map[string]bool) error {
165 165
 // RUN echo hi          # sh -c echo hi
166 166
 // RUN [ "echo", "hi" ] # echo hi
167 167
 //
168
-func run(b *BuildFile, args []string, attributes map[string]bool) error {
168
+func run(b *Builder, args []string, attributes map[string]bool) error {
169 169
 	args = handleJsonArgs(args, attributes)
170 170
 
171 171
 	if b.image == "" {
... ...
@@ -220,7 +220,7 @@ func run(b *BuildFile, args []string, attributes map[string]bool) error {
220 220
 // Set the default command to run in the container (which may be empty).
221 221
 // Argument handling is the same as RUN.
222 222
 //
223
-func cmd(b *BuildFile, args []string, attributes map[string]bool) error {
223
+func cmd(b *Builder, args []string, attributes map[string]bool) error {
224 224
 	b.Config.Cmd = handleJsonArgs(args, attributes)
225 225
 
226 226
 	if err := b.commit("", b.Config.Cmd, fmt.Sprintf("CMD %v", cmd)); err != nil {
... ...
@@ -239,7 +239,7 @@ func cmd(b *BuildFile, args []string, attributes map[string]bool) error {
239 239
 // Handles command processing similar to CMD and RUN, only b.Config.Entrypoint
240 240
 // is initialized at NewBuilder time instead of through argument parsing.
241 241
 //
242
-func entrypoint(b *BuildFile, args []string, attributes map[string]bool) error {
242
+func entrypoint(b *Builder, args []string, attributes map[string]bool) error {
243 243
 	b.Config.Entrypoint = handleJsonArgs(args, attributes)
244 244
 
245 245
 	// if there is no cmd in current Dockerfile - cleanup cmd
... ...
@@ -258,7 +258,7 @@ func entrypoint(b *BuildFile, args []string, attributes map[string]bool) error {
258 258
 // Expose ports for links and port mappings. This all ends up in
259 259
 // b.Config.ExposedPorts for runconfig.
260 260
 //
261
-func expose(b *BuildFile, args []string, attributes map[string]bool) error {
261
+func expose(b *Builder, args []string, attributes map[string]bool) error {
262 262
 	portsTab := args
263 263
 
264 264
 	if b.Config.ExposedPorts == nil {
... ...
@@ -285,7 +285,7 @@ func expose(b *BuildFile, args []string, attributes map[string]bool) error {
285 285
 // Set the user to 'foo' for future commands and when running the
286 286
 // ENTRYPOINT/CMD at container run time.
287 287
 //
288
-func user(b *BuildFile, args []string, attributes map[string]bool) error {
288
+func user(b *Builder, args []string, attributes map[string]bool) error {
289 289
 	if len(args) != 1 {
290 290
 		return fmt.Errorf("USER requires exactly one argument")
291 291
 	}
... ...
@@ -299,7 +299,7 @@ func user(b *BuildFile, args []string, attributes map[string]bool) error {
299 299
 // Expose the volume /foo for use. Will also accept the JSON form, but either
300 300
 // way requires exactly one argument.
301 301
 //
302
-func volume(b *BuildFile, args []string, attributes map[string]bool) error {
302
+func volume(b *Builder, args []string, attributes map[string]bool) error {
303 303
 	if len(args) != 1 {
304 304
 		return fmt.Errorf("Volume cannot be empty")
305 305
 	}
... ...
@@ -319,6 +319,6 @@ func volume(b *BuildFile, args []string, attributes map[string]bool) error {
319 319
 }
320 320
 
321 321
 // INSERT is no longer accepted, but we still parse it.
322
-func insert(b *BuildFile, args []string, attributes map[string]bool) error {
322
+func insert(b *Builder, args []string, attributes map[string]bool) error {
323 323
 	return fmt.Errorf("INSERT has been deprecated. Please use ADD instead")
324 324
 }
... ...
@@ -20,11 +20,9 @@
20 20
 package builder
21 21
 
22 22
 import (
23
-	"bytes"
24 23
 	"errors"
25 24
 	"fmt"
26 25
 	"io"
27
-	"io/ioutil"
28 26
 	"os"
29 27
 	"path"
30 28
 	"strings"
... ...
@@ -42,10 +40,10 @@ var (
42 42
 	ErrDockerfileEmpty = errors.New("Dockerfile cannot be empty")
43 43
 )
44 44
 
45
-var evaluateTable map[string]func(*BuildFile, []string, map[string]bool) error
45
+var evaluateTable map[string]func(*Builder, []string, map[string]bool) error
46 46
 
47 47
 func init() {
48
-	evaluateTable = map[string]func(*BuildFile, []string, map[string]bool) error{
48
+	evaluateTable = map[string]func(*Builder, []string, map[string]bool) error{
49 49
 		"env":            env,
50 50
 		"maintainer":     maintainer,
51 51
 		"add":            add,
... ...
@@ -66,23 +64,7 @@ func init() {
66 66
 
67 67
 // internal struct, used to maintain configuration of the Dockerfile's
68 68
 // processing as it evaluates the parsing result.
69
-type BuildFile struct {
70
-	Dockerfile *parser.Node      // the syntax tree of the dockerfile
71
-	Config     *runconfig.Config // runconfig for cmd, run, entrypoint etc.
72
-	Options    *BuildOpts        // see below
73
-
74
-	// both of these are controlled by the Remove and ForceRemove options in BuildOpts
75
-	TmpContainers map[string]struct{} // a map of containers used for removes
76
-
77
-	image       string         // image name for commit processing
78
-	maintainer  string         // maintainer name. could probably be removed.
79
-	cmdSet      bool           // indicates is CMD was set in current Dockerfile
80
-	context     *tarsum.TarSum // the context is a tarball that is uploaded by the client
81
-	contextPath string         // the path of the temporary directory the local context is unpacked to (server side)
82
-
83
-}
84
-
85
-type BuildOpts struct {
69
+type Builder struct {
86 70
 	Daemon *daemon.Daemon
87 71
 	Engine *engine.Engine
88 72
 
... ...
@@ -104,6 +86,19 @@ type BuildOpts struct {
104 104
 	// Deprecated, original writer used for ImagePull. To be removed.
105 105
 	OutOld          io.Writer
106 106
 	StreamFormatter *utils.StreamFormatter
107
+
108
+	Config *runconfig.Config // runconfig for cmd, run, entrypoint etc.
109
+
110
+	// both of these are controlled by the Remove and ForceRemove options in BuildOpts
111
+	TmpContainers map[string]struct{} // a map of containers used for removes
112
+
113
+	dockerfile  *parser.Node   // the syntax tree of the dockerfile
114
+	image       string         // image name for commit processing
115
+	maintainer  string         // maintainer name. could probably be removed.
116
+	cmdSet      bool           // indicates is CMD was set in current Dockerfile
117
+	context     *tarsum.TarSum // the context is a tarball that is uploaded by the client
118
+	contextPath string         // the path of the temporary directory the local context is unpacked to (server side)
119
+
107 120
 }
108 121
 
109 122
 // Run the builder with the context. This is the lynchpin of this package. This
... ...
@@ -118,38 +113,48 @@ type BuildOpts struct {
118 118
 //   processing.
119 119
 // * Print a happy message and return the image ID.
120 120
 //
121
-func (b *BuildFile) Run(context io.Reader) (string, error) {
121
+func (b *Builder) Run(context io.Reader) (string, error) {
122 122
 	if err := b.readContext(context); err != nil {
123 123
 		return "", err
124 124
 	}
125 125
 
126 126
 	filename := path.Join(b.contextPath, "Dockerfile")
127
-	if _, err := os.Stat(filename); os.IsNotExist(err) {
127
+
128
+	fi, err := os.Stat(filename)
129
+	if os.IsNotExist(err) {
128 130
 		return "", fmt.Errorf("Cannot build a directory without a Dockerfile")
129 131
 	}
130
-	fileBytes, err := ioutil.ReadFile(filename)
132
+	if fi.Size() == 0 {
133
+		return "", ErrDockerfileEmpty
134
+	}
135
+
136
+	f, err := os.Open(filename)
131 137
 	if err != nil {
132 138
 		return "", err
133 139
 	}
134
-	if len(fileBytes) == 0 {
135
-		return "", ErrDockerfileEmpty
136
-	}
137
-	ast, err := parser.Parse(bytes.NewReader(fileBytes))
140
+
141
+	defer f.Close()
142
+
143
+	ast, err := parser.Parse(f)
138 144
 	if err != nil {
139 145
 		return "", err
140 146
 	}
141 147
 
142
-	b.Dockerfile = ast
148
+	b.dockerfile = ast
149
+
150
+	// some initializations that would not have been supplied by the caller.
151
+	b.Config = &runconfig.Config{}
152
+	b.TmpContainers = map[string]struct{}{}
143 153
 
144
-	for i, n := range b.Dockerfile.Children {
154
+	for i, n := range b.dockerfile.Children {
145 155
 		if err := b.dispatch(i, n); err != nil {
146
-			if b.Options.ForceRemove {
156
+			if b.ForceRemove {
147 157
 				b.clearTmp()
148 158
 			}
149 159
 			return "", err
150 160
 		}
151
-		fmt.Fprintf(b.Options.OutStream, " ---> %s\n", utils.TruncateID(b.image))
152
-		if b.Options.Remove {
161
+		fmt.Fprintf(b.OutStream, " ---> %s\n", utils.TruncateID(b.image))
162
+		if b.Remove {
153 163
 			b.clearTmp()
154 164
 		}
155 165
 	}
... ...
@@ -158,7 +163,7 @@ func (b *BuildFile) Run(context io.Reader) (string, error) {
158 158
 		return "", fmt.Errorf("No image was generated. Is your Dockerfile empty?\n")
159 159
 	}
160 160
 
161
-	fmt.Fprintf(b.Options.OutStream, "Successfully built %s\n", utils.TruncateID(b.image))
161
+	fmt.Fprintf(b.OutStream, "Successfully built %s\n", utils.TruncateID(b.image))
162 162
 	return b.image, nil
163 163
 }
164 164
 
... ...
@@ -168,7 +173,7 @@ func (b *BuildFile) Run(context io.Reader) (string, error) {
168 168
 // Child[Node, Node, Node] where Child is from parser.Node.Children and each
169 169
 // node comes from parser.Node.Next. This forms a "line" with a statement and
170 170
 // arguments and we process them in this normalized form by hitting
171
-// evaluateTable with the leaf nodes of the command and the BuildFile object.
171
+// evaluateTable with the leaf nodes of the command and the Builder object.
172 172
 //
173 173
 // ONBUILD is a special case; in this case the parser will emit:
174 174
 // Child[Node, Child[Node, Node...]] where the first node is the literal
... ...
@@ -176,14 +181,13 @@ func (b *BuildFile) Run(context io.Reader) (string, error) {
176 176
 // such as `RUN` in ONBUILD RUN foo. There is special case logic in here to
177 177
 // deal with that, at least until it becomes more of a general concern with new
178 178
 // features.
179
-func (b *BuildFile) dispatch(stepN int, ast *parser.Node) error {
179
+func (b *Builder) dispatch(stepN int, ast *parser.Node) error {
180 180
 	cmd := ast.Value
181 181
 	attrs := ast.Attributes
182 182
 	strs := []string{}
183 183
 	msg := fmt.Sprintf("Step %d : %s", stepN, strings.ToUpper(cmd))
184 184
 
185 185
 	if cmd == "onbuild" {
186
-		fmt.Fprintf(b.Options.OutStream, "%#v\n", ast.Next.Children[0].Value)
187 186
 		ast = ast.Next.Children[0]
188 187
 		strs = append(strs, b.replaceEnv(ast.Value))
189 188
 		msg += " " + ast.Value
... ...
@@ -195,7 +199,7 @@ func (b *BuildFile) dispatch(stepN int, ast *parser.Node) error {
195 195
 		msg += " " + ast.Value
196 196
 	}
197 197
 
198
-	fmt.Fprintf(b.Options.OutStream, "%s\n", msg)
198
+	fmt.Fprintln(b.OutStream, msg)
199 199
 
200 200
 	// XXX yes, we skip any cmds that are not valid; the parser should have
201 201
 	// picked these out already.
... ...
@@ -203,7 +207,7 @@ func (b *BuildFile) dispatch(stepN int, ast *parser.Node) error {
203 203
 		return f(b, strs, attrs)
204 204
 	}
205 205
 
206
-	fmt.Fprintf(b.Options.ErrStream, "# Skipping unknown instruction %s\n", strings.ToUpper(cmd))
206
+	fmt.Fprintf(b.ErrStream, "# Skipping unknown instruction %s\n", strings.ToUpper(cmd))
207 207
 
208 208
 	return nil
209 209
 }
... ...
@@ -30,7 +30,7 @@ import (
30 30
 	"github.com/docker/docker/utils"
31 31
 )
32 32
 
33
-func (b *BuildFile) readContext(context io.Reader) error {
33
+func (b *Builder) readContext(context io.Reader) error {
34 34
 	tmpdirPath, err := ioutil.TempDir("", "docker-build")
35 35
 	if err != nil {
36 36
 		return err
... ...
@@ -50,7 +50,7 @@ func (b *BuildFile) readContext(context io.Reader) error {
50 50
 	return nil
51 51
 }
52 52
 
53
-func (b *BuildFile) commit(id string, autoCmd []string, comment string) error {
53
+func (b *Builder) commit(id string, autoCmd []string, comment string) error {
54 54
 	if b.image == "" {
55 55
 		return fmt.Errorf("Please provide a source image with `from` prior to commit")
56 56
 	}
... ...
@@ -68,15 +68,15 @@ func (b *BuildFile) commit(id string, autoCmd []string, comment string) error {
68 68
 			return nil
69 69
 		}
70 70
 
71
-		container, warnings, err := b.Options.Daemon.Create(b.Config, "")
71
+		container, warnings, err := b.Daemon.Create(b.Config, "")
72 72
 		if err != nil {
73 73
 			return err
74 74
 		}
75 75
 		for _, warning := range warnings {
76
-			fmt.Fprintf(b.Options.OutStream, " ---> [Warning] %s\n", warning)
76
+			fmt.Fprintf(b.OutStream, " ---> [Warning] %s\n", warning)
77 77
 		}
78 78
 		b.TmpContainers[container.ID] = struct{}{}
79
-		fmt.Fprintf(b.Options.OutStream, " ---> Running in %s\n", utils.TruncateID(container.ID))
79
+		fmt.Fprintf(b.OutStream, " ---> Running in %s\n", utils.TruncateID(container.ID))
80 80
 		id = container.ID
81 81
 
82 82
 		if err := container.Mount(); err != nil {
... ...
@@ -84,7 +84,7 @@ func (b *BuildFile) commit(id string, autoCmd []string, comment string) error {
84 84
 		}
85 85
 		defer container.Unmount()
86 86
 	}
87
-	container := b.Options.Daemon.Get(id)
87
+	container := b.Daemon.Get(id)
88 88
 	if container == nil {
89 89
 		return fmt.Errorf("An error occured while creating the container")
90 90
 	}
... ...
@@ -93,7 +93,7 @@ func (b *BuildFile) commit(id string, autoCmd []string, comment string) error {
93 93
 	autoConfig := *b.Config
94 94
 	autoConfig.Cmd = autoCmd
95 95
 	// Commit the container
96
-	image, err := b.Options.Daemon.Commit(container, "", "", "", b.maintainer, true, &autoConfig)
96
+	image, err := b.Daemon.Commit(container, "", "", "", b.maintainer, true, &autoConfig)
97 97
 	if err != nil {
98 98
 		return err
99 99
 	}
... ...
@@ -101,7 +101,7 @@ func (b *BuildFile) commit(id string, autoCmd []string, comment string) error {
101 101
 	return nil
102 102
 }
103 103
 
104
-func (b *BuildFile) runContextCommand(args []string, allowRemote bool, allowDecompression bool, cmdName string) error {
104
+func (b *Builder) runContextCommand(args []string, allowRemote bool, allowDecompression bool, cmdName string) error {
105 105
 	if b.context == nil {
106 106
 		return fmt.Errorf("No context given. Impossible to use %s", cmdName)
107 107
 	}
... ...
@@ -200,7 +200,7 @@ func (b *BuildFile) runContextCommand(args []string, allowRemote bool, allowDeco
200 200
 	}
201 201
 
202 202
 	// Hash path and check the cache
203
-	if b.Options.UtilizeCache {
203
+	if b.UtilizeCache {
204 204
 		var (
205 205
 			hash string
206 206
 			sums = b.context.GetSums()
... ...
@@ -244,7 +244,7 @@ func (b *BuildFile) runContextCommand(args []string, allowRemote bool, allowDeco
244 244
 	}
245 245
 
246 246
 	// Create the container
247
-	container, _, err := b.Options.Daemon.Create(b.Config, "")
247
+	container, _, err := b.Daemon.Create(b.Config, "")
248 248
 	if err != nil {
249 249
 		return err
250 250
 	}
... ...
@@ -268,27 +268,27 @@ func (b *BuildFile) runContextCommand(args []string, allowRemote bool, allowDeco
268 268
 	return nil
269 269
 }
270 270
 
271
-func (b *BuildFile) pullImage(name string) (*imagepkg.Image, error) {
271
+func (b *Builder) pullImage(name string) (*imagepkg.Image, error) {
272 272
 	remote, tag := parsers.ParseRepositoryTag(name)
273
-	pullRegistryAuth := b.Options.AuthConfig
274
-	if len(b.Options.AuthConfigFile.Configs) > 0 {
273
+	pullRegistryAuth := b.AuthConfig
274
+	if len(b.AuthConfigFile.Configs) > 0 {
275 275
 		// The request came with a full auth config file, we prefer to use that
276 276
 		endpoint, _, err := registry.ResolveRepositoryName(remote)
277 277
 		if err != nil {
278 278
 			return nil, err
279 279
 		}
280
-		resolvedAuth := b.Options.AuthConfigFile.ResolveAuthConfig(endpoint)
280
+		resolvedAuth := b.AuthConfigFile.ResolveAuthConfig(endpoint)
281 281
 		pullRegistryAuth = &resolvedAuth
282 282
 	}
283
-	job := b.Options.Engine.Job("pull", remote, tag)
284
-	job.SetenvBool("json", b.Options.StreamFormatter.Json())
283
+	job := b.Engine.Job("pull", remote, tag)
284
+	job.SetenvBool("json", b.StreamFormatter.Json())
285 285
 	job.SetenvBool("parallel", true)
286 286
 	job.SetenvJson("authConfig", pullRegistryAuth)
287
-	job.Stdout.Add(b.Options.OutOld)
287
+	job.Stdout.Add(b.OutOld)
288 288
 	if err := job.Run(); err != nil {
289 289
 		return nil, err
290 290
 	}
291
-	image, err := b.Options.Daemon.Repositories().LookupImage(name)
291
+	image, err := b.Daemon.Repositories().LookupImage(name)
292 292
 	if err != nil {
293 293
 		return nil, err
294 294
 	}
... ...
@@ -296,7 +296,7 @@ func (b *BuildFile) pullImage(name string) (*imagepkg.Image, error) {
296 296
 	return image, nil
297 297
 }
298 298
 
299
-func (b *BuildFile) processImageFrom(img *imagepkg.Image) error {
299
+func (b *Builder) processImageFrom(img *imagepkg.Image) error {
300 300
 	b.image = img.ID
301 301
 
302 302
 	if img.Config != nil {
... ...
@@ -309,7 +309,7 @@ func (b *BuildFile) processImageFrom(img *imagepkg.Image) error {
309 309
 
310 310
 	// Process ONBUILD triggers if they exist
311 311
 	if nTriggers := len(b.Config.OnBuild); nTriggers != 0 {
312
-		fmt.Fprintf(b.Options.ErrStream, "# Executing %d build triggers\n", nTriggers)
312
+		fmt.Fprintf(b.ErrStream, "# Executing %d build triggers\n", nTriggers)
313 313
 	}
314 314
 
315 315
 	// Copy the ONBUILD triggers, and remove them from the config, since the config will be commited.
... ...
@@ -330,7 +330,8 @@ func (b *BuildFile) processImageFrom(img *imagepkg.Image) error {
330 330
 		}
331 331
 
332 332
 		// FIXME we have to run the evaluator manually here. This does not belong
333
-		// in this function.
333
+		// in this function. Once removed, the init() in evaluator.go should no
334
+		// longer be necessary.
334 335
 
335 336
 		if f, ok := evaluateTable[strings.ToLower(stepInstruction)]; ok {
336 337
 			if err := f(b, splitStep[1:], nil); err != nil {
... ...
@@ -344,17 +345,17 @@ func (b *BuildFile) processImageFrom(img *imagepkg.Image) error {
344 344
 	return nil
345 345
 }
346 346
 
347
-// probeCache checks to see if image-caching is enabled (`b.Options.UtilizeCache`)
347
+// probeCache checks to see if image-caching is enabled (`b.UtilizeCache`)
348 348
 // and if so attempts to look up the current `b.image` and `b.Config` pair
349
-// in the current server `b.Options.Daemon`. If an image is found, probeCache returns
349
+// in the current server `b.Daemon`. If an image is found, probeCache returns
350 350
 // `(true, nil)`. If no image is found, it returns `(false, nil)`. If there
351 351
 // is any error, it returns `(false, err)`.
352
-func (b *BuildFile) probeCache() (bool, error) {
353
-	if b.Options.UtilizeCache {
354
-		if cache, err := b.Options.Daemon.ImageGetCached(b.image, b.Config); err != nil {
352
+func (b *Builder) probeCache() (bool, error) {
353
+	if b.UtilizeCache {
354
+		if cache, err := b.Daemon.ImageGetCached(b.image, b.Config); err != nil {
355 355
 			return false, err
356 356
 		} else if cache != nil {
357
-			fmt.Fprintf(b.Options.OutStream, " ---> Using cache\n")
357
+			fmt.Fprintf(b.OutStream, " ---> Using cache\n")
358 358
 			log.Debugf("[BUILDER] Use cached version")
359 359
 			b.image = cache.ID
360 360
 			return true, nil
... ...
@@ -365,19 +366,20 @@ func (b *BuildFile) probeCache() (bool, error) {
365 365
 	return false, nil
366 366
 }
367 367
 
368
-func (b *BuildFile) create() (*daemon.Container, error) {
368
+func (b *Builder) create() (*daemon.Container, error) {
369 369
 	if b.image == "" {
370 370
 		return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
371 371
 	}
372 372
 	b.Config.Image = b.image
373 373
 
374 374
 	// Create the container
375
-	c, _, err := b.Options.Daemon.Create(b.Config, "")
375
+	c, _, err := b.Daemon.Create(b.Config, "")
376 376
 	if err != nil {
377 377
 		return nil, err
378 378
 	}
379
+
379 380
 	b.TmpContainers[c.ID] = struct{}{}
380
-	fmt.Fprintf(b.Options.OutStream, " ---> Running in %s\n", utils.TruncateID(c.ID))
381
+	fmt.Fprintf(b.OutStream, " ---> Running in %s\n", utils.TruncateID(c.ID))
381 382
 
382 383
 	// override the entry point that may have been picked up from the base image
383 384
 	c.Path = b.Config.Cmd[0]
... ...
@@ -386,16 +388,16 @@ func (b *BuildFile) create() (*daemon.Container, error) {
386 386
 	return c, nil
387 387
 }
388 388
 
389
-func (b *BuildFile) run(c *daemon.Container) error {
389
+func (b *Builder) run(c *daemon.Container) error {
390 390
 	var errCh chan error
391
-	if b.Options.Verbose {
391
+	if b.Verbose {
392 392
 		errCh = utils.Go(func() error {
393 393
 			// FIXME: call the 'attach' job so that daemon.Attach can be made private
394 394
 			//
395 395
 			// FIXME (LK4D4): Also, maybe makes sense to call "logs" job, it is like attach
396 396
 			// but without hijacking for stdin. Also, with attach there can be race
397 397
 			// condition because of some output already was printed before it.
398
-			return <-b.Options.Daemon.Attach(c, nil, nil, b.Options.OutStream, b.Options.ErrStream)
398
+			return <-b.Daemon.Attach(c, nil, nil, b.OutStream, b.ErrStream)
399 399
 		})
400 400
 	}
401 401
 
... ...
@@ -422,7 +424,7 @@ func (b *BuildFile) run(c *daemon.Container) error {
422 422
 	return nil
423 423
 }
424 424
 
425
-func (b *BuildFile) checkPathForAddition(orig string) error {
425
+func (b *Builder) checkPathForAddition(orig string) error {
426 426
 	origPath := path.Join(b.contextPath, orig)
427 427
 	origPath, err := filepath.EvalSymlinks(origPath)
428 428
 	if err != nil {
... ...
@@ -443,7 +445,7 @@ func (b *BuildFile) checkPathForAddition(orig string) error {
443 443
 	return nil
444 444
 }
445 445
 
446
-func (b *BuildFile) addContext(container *daemon.Container, orig, dest string, decompress bool) error {
446
+func (b *Builder) addContext(container *daemon.Container, orig, dest string, decompress bool) error {
447 447
 	var (
448 448
 		err        error
449 449
 		destExists = true
... ...
@@ -548,14 +550,14 @@ func fixPermissions(destination string, uid, gid int) error {
548 548
 	})
549 549
 }
550 550
 
551
-func (b *BuildFile) clearTmp() {
551
+func (b *Builder) clearTmp() {
552 552
 	for c := range b.TmpContainers {
553
-		tmp := b.Options.Daemon.Get(c)
554
-		if err := b.Options.Daemon.Destroy(tmp); err != nil {
555
-			fmt.Fprintf(b.Options.OutStream, "Error removing intermediate container %s: %s\n", utils.TruncateID(c), err.Error())
553
+		tmp := b.Daemon.Get(c)
554
+		if err := b.Daemon.Destroy(tmp); err != nil {
555
+			fmt.Fprintf(b.OutStream, "Error removing intermediate container %s: %s\n", utils.TruncateID(c), err.Error())
556 556
 		} else {
557 557
 			delete(b.TmpContainers, c)
558
-			fmt.Fprintf(b.Options.OutStream, "Removing intermediate container %s\n", utils.TruncateID(c))
558
+			fmt.Fprintf(b.OutStream, "Removing intermediate container %s\n", utils.TruncateID(c))
559 559
 		}
560 560
 	}
561 561
 }
... ...
@@ -85,7 +85,7 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status {
85 85
 
86 86
 	sf := utils.NewStreamFormatter(job.GetenvBool("json"))
87 87
 
88
-	opts := &BuildOpts{
88
+	builder := &Builder{
89 89
 		Daemon: b.Daemon,
90 90
 		Engine: b.Engine,
91 91
 		OutStream: &utils.StdoutFormater{
... ...
@@ -106,7 +106,7 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status {
106 106
 		AuthConfigFile:  configFile,
107 107
 	}
108 108
 
109
-	id, err := NewBuilder(opts).Run(context)
109
+	id, err := builder.Run(context)
110 110
 	if err != nil {
111 111
 		return job.Error(err)
112 112
 	}
... ...
@@ -10,7 +10,7 @@ var (
10 10
 )
11 11
 
12 12
 // handle environment replacement. Used in dispatcher.
13
-func (b *BuildFile) replaceEnv(str string) string {
13
+func (b *Builder) replaceEnv(str string) string {
14 14
 	for _, match := range TOKEN_ENV_INTERPOLATION.FindAllString(str, -1) {
15 15
 		match = match[strings.Index(match, "$"):]
16 16
 		matchKey := strings.Trim(match, "${}")