1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

builder: Refactors according to @tiborvass's comments

Docker-DCO-1.1-Signed-off-by: Erik Hollensbe <github@hollensbe.org> (github: erikh)
This commit is contained in:
Erik Hollensbe 2014-08-26 12:25:44 -07:00
parent 305f735080
commit 2ef1dec7e8
6 changed files with 106 additions and 115 deletions

View file

@ -1,15 +0,0 @@
package builder
import (
"github.com/docker/docker/runconfig"
)
// Create a new builder. See
func NewBuilder(opts *BuildOpts) *BuildFile {
return &BuildFile{
Dockerfile: nil,
Config: &runconfig.Config{},
Options: opts,
TmpContainers: map[string]struct{}{},
}
}

View file

@ -18,7 +18,7 @@ import (
)
// dispatch with no layer / parsing. This is effectively not a command.
func nullDispatch(b *BuildFile, args []string, attributes map[string]bool) error {
func nullDispatch(b *Builder, args []string, attributes map[string]bool) error {
return nil
}
@ -27,7 +27,7 @@ func nullDispatch(b *BuildFile, args []string, attributes map[string]bool) error
// Sets the environment variable foo to bar, also makes interpolation
// in the dockerfile available from the next statement on via ${foo}.
//
func env(b *BuildFile, args []string, attributes map[string]bool) error {
func env(b *Builder, args []string, attributes map[string]bool) error {
if len(args) != 2 {
return fmt.Errorf("ENV accepts two arguments")
}
@ -48,7 +48,7 @@ func env(b *BuildFile, args []string, attributes map[string]bool) error {
// MAINTAINER some text <maybe@an.email.address>
//
// Sets the maintainer metadata.
func maintainer(b *BuildFile, args []string, attributes map[string]bool) error {
func maintainer(b *Builder, args []string, attributes map[string]bool) error {
if len(args) != 1 {
return fmt.Errorf("MAINTAINER requires only one argument")
}
@ -62,7 +62,7 @@ func maintainer(b *BuildFile, args []string, attributes map[string]bool) error {
// Add the file 'foo' to '/path'. Tarball and Remote URL (git, http) handling
// exist here. If you do not wish to have this automatic handling, use COPY.
//
func add(b *BuildFile, args []string, attributes map[string]bool) error {
func add(b *Builder, args []string, attributes map[string]bool) error {
if len(args) != 2 {
return fmt.Errorf("ADD requires two arguments")
}
@ -74,7 +74,7 @@ func add(b *BuildFile, args []string, attributes map[string]bool) error {
//
// Same as 'ADD' but without the tar and remote url handling.
//
func dispatchCopy(b *BuildFile, args []string, attributes map[string]bool) error {
func dispatchCopy(b *Builder, args []string, attributes map[string]bool) error {
if len(args) != 2 {
return fmt.Errorf("COPY requires two arguments")
}
@ -86,16 +86,16 @@ func dispatchCopy(b *BuildFile, args []string, attributes map[string]bool) error
//
// This sets the image the dockerfile will build on top of.
//
func from(b *BuildFile, args []string, attributes map[string]bool) error {
func from(b *Builder, args []string, attributes map[string]bool) error {
if len(args) != 1 {
return fmt.Errorf("FROM requires one argument")
}
name := args[0]
image, err := b.Options.Daemon.Repositories().LookupImage(name)
image, err := b.Daemon.Repositories().LookupImage(name)
if err != nil {
if b.Options.Daemon.Graph().IsNotExist(err) {
if b.Daemon.Graph().IsNotExist(err) {
image, err = b.pullImage(name)
}
@ -118,7 +118,7 @@ func from(b *BuildFile, args []string, attributes map[string]bool) error {
// special cases. search for 'OnBuild' in internals.go for additional special
// cases.
//
func onbuild(b *BuildFile, args []string, attributes map[string]bool) error {
func onbuild(b *Builder, args []string, attributes map[string]bool) error {
triggerInstruction := strings.ToUpper(strings.TrimSpace(args[0]))
switch triggerInstruction {
case "ONBUILD":
@ -137,7 +137,7 @@ func onbuild(b *BuildFile, args []string, attributes map[string]bool) error {
//
// Set the working directory for future RUN/CMD/etc statements.
//
func workdir(b *BuildFile, args []string, attributes map[string]bool) error {
func workdir(b *Builder, args []string, attributes map[string]bool) error {
if len(args) != 1 {
return fmt.Errorf("WORKDIR requires exactly one argument")
}
@ -165,7 +165,7 @@ func workdir(b *BuildFile, args []string, attributes map[string]bool) error {
// RUN echo hi # sh -c echo hi
// RUN [ "echo", "hi" ] # echo hi
//
func run(b *BuildFile, args []string, attributes map[string]bool) error {
func run(b *Builder, args []string, attributes map[string]bool) error {
args = handleJsonArgs(args, attributes)
if b.image == "" {
@ -220,7 +220,7 @@ func run(b *BuildFile, args []string, attributes map[string]bool) error {
// Set the default command to run in the container (which may be empty).
// Argument handling is the same as RUN.
//
func cmd(b *BuildFile, args []string, attributes map[string]bool) error {
func cmd(b *Builder, args []string, attributes map[string]bool) error {
b.Config.Cmd = handleJsonArgs(args, attributes)
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 {
// Handles command processing similar to CMD and RUN, only b.Config.Entrypoint
// is initialized at NewBuilder time instead of through argument parsing.
//
func entrypoint(b *BuildFile, args []string, attributes map[string]bool) error {
func entrypoint(b *Builder, args []string, attributes map[string]bool) error {
b.Config.Entrypoint = handleJsonArgs(args, attributes)
// 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 {
// Expose ports for links and port mappings. This all ends up in
// b.Config.ExposedPorts for runconfig.
//
func expose(b *BuildFile, args []string, attributes map[string]bool) error {
func expose(b *Builder, args []string, attributes map[string]bool) error {
portsTab := args
if b.Config.ExposedPorts == nil {
@ -285,7 +285,7 @@ func expose(b *BuildFile, args []string, attributes map[string]bool) error {
// Set the user to 'foo' for future commands and when running the
// ENTRYPOINT/CMD at container run time.
//
func user(b *BuildFile, args []string, attributes map[string]bool) error {
func user(b *Builder, args []string, attributes map[string]bool) error {
if len(args) != 1 {
return fmt.Errorf("USER requires exactly one argument")
}
@ -299,7 +299,7 @@ func user(b *BuildFile, args []string, attributes map[string]bool) error {
// Expose the volume /foo for use. Will also accept the JSON form, but either
// way requires exactly one argument.
//
func volume(b *BuildFile, args []string, attributes map[string]bool) error {
func volume(b *Builder, args []string, attributes map[string]bool) error {
if len(args) != 1 {
return fmt.Errorf("Volume cannot be empty")
}
@ -319,6 +319,6 @@ func volume(b *BuildFile, args []string, attributes map[string]bool) error {
}
// INSERT is no longer accepted, but we still parse it.
func insert(b *BuildFile, args []string, attributes map[string]bool) error {
func insert(b *Builder, args []string, attributes map[string]bool) error {
return fmt.Errorf("INSERT has been deprecated. Please use ADD instead")
}

View file

@ -20,11 +20,9 @@
package builder
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"strings"
@ -42,10 +40,10 @@ var (
ErrDockerfileEmpty = errors.New("Dockerfile cannot be empty")
)
var evaluateTable map[string]func(*BuildFile, []string, map[string]bool) error
var evaluateTable map[string]func(*Builder, []string, map[string]bool) error
func init() {
evaluateTable = map[string]func(*BuildFile, []string, map[string]bool) error{
evaluateTable = map[string]func(*Builder, []string, map[string]bool) error{
"env": env,
"maintainer": maintainer,
"add": add,
@ -66,23 +64,7 @@ func init() {
// internal struct, used to maintain configuration of the Dockerfile's
// processing as it evaluates the parsing result.
type BuildFile struct {
Dockerfile *parser.Node // the syntax tree of the dockerfile
Config *runconfig.Config // runconfig for cmd, run, entrypoint etc.
Options *BuildOpts // see below
// both of these are controlled by the Remove and ForceRemove options in BuildOpts
TmpContainers map[string]struct{} // a map of containers used for removes
image string // image name for commit processing
maintainer string // maintainer name. could probably be removed.
cmdSet bool // indicates is CMD was set in current Dockerfile
context *tarsum.TarSum // the context is a tarball that is uploaded by the client
contextPath string // the path of the temporary directory the local context is unpacked to (server side)
}
type BuildOpts struct {
type Builder struct {
Daemon *daemon.Daemon
Engine *engine.Engine
@ -104,6 +86,19 @@ type BuildOpts struct {
// Deprecated, original writer used for ImagePull. To be removed.
OutOld io.Writer
StreamFormatter *utils.StreamFormatter
Config *runconfig.Config // runconfig for cmd, run, entrypoint etc.
// both of these are controlled by the Remove and ForceRemove options in BuildOpts
TmpContainers map[string]struct{} // a map of containers used for removes
dockerfile *parser.Node // the syntax tree of the dockerfile
image string // image name for commit processing
maintainer string // maintainer name. could probably be removed.
cmdSet bool // indicates is CMD was set in current Dockerfile
context *tarsum.TarSum // the context is a tarball that is uploaded by the client
contextPath string // the path of the temporary directory the local context is unpacked to (server side)
}
// Run the builder with the context. This is the lynchpin of this package. This
@ -118,38 +113,48 @@ type BuildOpts struct {
// processing.
// * Print a happy message and return the image ID.
//
func (b *BuildFile) Run(context io.Reader) (string, error) {
func (b *Builder) Run(context io.Reader) (string, error) {
if err := b.readContext(context); err != nil {
return "", err
}
filename := path.Join(b.contextPath, "Dockerfile")
if _, err := os.Stat(filename); os.IsNotExist(err) {
fi, err := os.Stat(filename)
if os.IsNotExist(err) {
return "", fmt.Errorf("Cannot build a directory without a Dockerfile")
}
fileBytes, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
if len(fileBytes) == 0 {
if fi.Size() == 0 {
return "", ErrDockerfileEmpty
}
ast, err := parser.Parse(bytes.NewReader(fileBytes))
f, err := os.Open(filename)
if err != nil {
return "", err
}
b.Dockerfile = ast
defer f.Close()
for i, n := range b.Dockerfile.Children {
ast, err := parser.Parse(f)
if err != nil {
return "", err
}
b.dockerfile = ast
// some initializations that would not have been supplied by the caller.
b.Config = &runconfig.Config{}
b.TmpContainers = map[string]struct{}{}
for i, n := range b.dockerfile.Children {
if err := b.dispatch(i, n); err != nil {
if b.Options.ForceRemove {
if b.ForceRemove {
b.clearTmp()
}
return "", err
}
fmt.Fprintf(b.Options.OutStream, " ---> %s\n", utils.TruncateID(b.image))
if b.Options.Remove {
fmt.Fprintf(b.OutStream, " ---> %s\n", utils.TruncateID(b.image))
if b.Remove {
b.clearTmp()
}
}
@ -158,7 +163,7 @@ func (b *BuildFile) Run(context io.Reader) (string, error) {
return "", fmt.Errorf("No image was generated. Is your Dockerfile empty?\n")
}
fmt.Fprintf(b.Options.OutStream, "Successfully built %s\n", utils.TruncateID(b.image))
fmt.Fprintf(b.OutStream, "Successfully built %s\n", utils.TruncateID(b.image))
return b.image, nil
}
@ -168,7 +173,7 @@ func (b *BuildFile) Run(context io.Reader) (string, error) {
// Child[Node, Node, Node] where Child is from parser.Node.Children and each
// node comes from parser.Node.Next. This forms a "line" with a statement and
// arguments and we process them in this normalized form by hitting
// evaluateTable with the leaf nodes of the command and the BuildFile object.
// evaluateTable with the leaf nodes of the command and the Builder object.
//
// ONBUILD is a special case; in this case the parser will emit:
// 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) {
// such as `RUN` in ONBUILD RUN foo. There is special case logic in here to
// deal with that, at least until it becomes more of a general concern with new
// features.
func (b *BuildFile) dispatch(stepN int, ast *parser.Node) error {
func (b *Builder) dispatch(stepN int, ast *parser.Node) error {
cmd := ast.Value
attrs := ast.Attributes
strs := []string{}
msg := fmt.Sprintf("Step %d : %s", stepN, strings.ToUpper(cmd))
if cmd == "onbuild" {
fmt.Fprintf(b.Options.OutStream, "%#v\n", ast.Next.Children[0].Value)
ast = ast.Next.Children[0]
strs = append(strs, b.replaceEnv(ast.Value))
msg += " " + ast.Value
@ -195,7 +199,7 @@ func (b *BuildFile) dispatch(stepN int, ast *parser.Node) error {
msg += " " + ast.Value
}
fmt.Fprintf(b.Options.OutStream, "%s\n", msg)
fmt.Fprintln(b.OutStream, msg)
// XXX yes, we skip any cmds that are not valid; the parser should have
// picked these out already.
@ -203,7 +207,7 @@ func (b *BuildFile) dispatch(stepN int, ast *parser.Node) error {
return f(b, strs, attrs)
}
fmt.Fprintf(b.Options.ErrStream, "# Skipping unknown instruction %s\n", strings.ToUpper(cmd))
fmt.Fprintf(b.ErrStream, "# Skipping unknown instruction %s\n", strings.ToUpper(cmd))
return nil
}

View file

@ -30,7 +30,7 @@ import (
"github.com/docker/docker/utils"
)
func (b *BuildFile) readContext(context io.Reader) error {
func (b *Builder) readContext(context io.Reader) error {
tmpdirPath, err := ioutil.TempDir("", "docker-build")
if err != nil {
return err
@ -50,7 +50,7 @@ func (b *BuildFile) readContext(context io.Reader) error {
return nil
}
func (b *BuildFile) commit(id string, autoCmd []string, comment string) error {
func (b *Builder) commit(id string, autoCmd []string, comment string) error {
if b.image == "" {
return fmt.Errorf("Please provide a source image with `from` prior to commit")
}
@ -68,15 +68,15 @@ func (b *BuildFile) commit(id string, autoCmd []string, comment string) error {
return nil
}
container, warnings, err := b.Options.Daemon.Create(b.Config, "")
container, warnings, err := b.Daemon.Create(b.Config, "")
if err != nil {
return err
}
for _, warning := range warnings {
fmt.Fprintf(b.Options.OutStream, " ---> [Warning] %s\n", warning)
fmt.Fprintf(b.OutStream, " ---> [Warning] %s\n", warning)
}
b.TmpContainers[container.ID] = struct{}{}
fmt.Fprintf(b.Options.OutStream, " ---> Running in %s\n", utils.TruncateID(container.ID))
fmt.Fprintf(b.OutStream, " ---> Running in %s\n", utils.TruncateID(container.ID))
id = container.ID
if err := container.Mount(); err != nil {
@ -84,7 +84,7 @@ func (b *BuildFile) commit(id string, autoCmd []string, comment string) error {
}
defer container.Unmount()
}
container := b.Options.Daemon.Get(id)
container := b.Daemon.Get(id)
if container == nil {
return fmt.Errorf("An error occured while creating the container")
}
@ -93,7 +93,7 @@ func (b *BuildFile) commit(id string, autoCmd []string, comment string) error {
autoConfig := *b.Config
autoConfig.Cmd = autoCmd
// Commit the container
image, err := b.Options.Daemon.Commit(container, "", "", "", b.maintainer, true, &autoConfig)
image, err := b.Daemon.Commit(container, "", "", "", b.maintainer, true, &autoConfig)
if err != nil {
return err
}
@ -101,7 +101,7 @@ func (b *BuildFile) commit(id string, autoCmd []string, comment string) error {
return nil
}
func (b *BuildFile) runContextCommand(args []string, allowRemote bool, allowDecompression bool, cmdName string) error {
func (b *Builder) runContextCommand(args []string, allowRemote bool, allowDecompression bool, cmdName string) error {
if b.context == nil {
return fmt.Errorf("No context given. Impossible to use %s", cmdName)
}
@ -200,7 +200,7 @@ func (b *BuildFile) runContextCommand(args []string, allowRemote bool, allowDeco
}
// Hash path and check the cache
if b.Options.UtilizeCache {
if b.UtilizeCache {
var (
hash string
sums = b.context.GetSums()
@ -244,7 +244,7 @@ func (b *BuildFile) runContextCommand(args []string, allowRemote bool, allowDeco
}
// Create the container
container, _, err := b.Options.Daemon.Create(b.Config, "")
container, _, err := b.Daemon.Create(b.Config, "")
if err != nil {
return err
}
@ -268,27 +268,27 @@ func (b *BuildFile) runContextCommand(args []string, allowRemote bool, allowDeco
return nil
}
func (b *BuildFile) pullImage(name string) (*imagepkg.Image, error) {
func (b *Builder) pullImage(name string) (*imagepkg.Image, error) {
remote, tag := parsers.ParseRepositoryTag(name)
pullRegistryAuth := b.Options.AuthConfig
if len(b.Options.AuthConfigFile.Configs) > 0 {
pullRegistryAuth := b.AuthConfig
if len(b.AuthConfigFile.Configs) > 0 {
// The request came with a full auth config file, we prefer to use that
endpoint, _, err := registry.ResolveRepositoryName(remote)
if err != nil {
return nil, err
}
resolvedAuth := b.Options.AuthConfigFile.ResolveAuthConfig(endpoint)
resolvedAuth := b.AuthConfigFile.ResolveAuthConfig(endpoint)
pullRegistryAuth = &resolvedAuth
}
job := b.Options.Engine.Job("pull", remote, tag)
job.SetenvBool("json", b.Options.StreamFormatter.Json())
job := b.Engine.Job("pull", remote, tag)
job.SetenvBool("json", b.StreamFormatter.Json())
job.SetenvBool("parallel", true)
job.SetenvJson("authConfig", pullRegistryAuth)
job.Stdout.Add(b.Options.OutOld)
job.Stdout.Add(b.OutOld)
if err := job.Run(); err != nil {
return nil, err
}
image, err := b.Options.Daemon.Repositories().LookupImage(name)
image, err := b.Daemon.Repositories().LookupImage(name)
if err != nil {
return nil, err
}
@ -296,7 +296,7 @@ func (b *BuildFile) pullImage(name string) (*imagepkg.Image, error) {
return image, nil
}
func (b *BuildFile) processImageFrom(img *imagepkg.Image) error {
func (b *Builder) processImageFrom(img *imagepkg.Image) error {
b.image = img.ID
if img.Config != nil {
@ -309,7 +309,7 @@ func (b *BuildFile) processImageFrom(img *imagepkg.Image) error {
// Process ONBUILD triggers if they exist
if nTriggers := len(b.Config.OnBuild); nTriggers != 0 {
fmt.Fprintf(b.Options.ErrStream, "# Executing %d build triggers\n", nTriggers)
fmt.Fprintf(b.ErrStream, "# Executing %d build triggers\n", nTriggers)
}
// 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 {
}
// FIXME we have to run the evaluator manually here. This does not belong
// in this function.
// in this function. Once removed, the init() in evaluator.go should no
// longer be necessary.
if f, ok := evaluateTable[strings.ToLower(stepInstruction)]; ok {
if err := f(b, splitStep[1:], nil); err != nil {
@ -344,17 +345,17 @@ func (b *BuildFile) processImageFrom(img *imagepkg.Image) error {
return nil
}
// probeCache checks to see if image-caching is enabled (`b.Options.UtilizeCache`)
// probeCache checks to see if image-caching is enabled (`b.UtilizeCache`)
// and if so attempts to look up the current `b.image` and `b.Config` pair
// in the current server `b.Options.Daemon`. If an image is found, probeCache returns
// in the current server `b.Daemon`. If an image is found, probeCache returns
// `(true, nil)`. If no image is found, it returns `(false, nil)`. If there
// is any error, it returns `(false, err)`.
func (b *BuildFile) probeCache() (bool, error) {
if b.Options.UtilizeCache {
if cache, err := b.Options.Daemon.ImageGetCached(b.image, b.Config); err != nil {
func (b *Builder) probeCache() (bool, error) {
if b.UtilizeCache {
if cache, err := b.Daemon.ImageGetCached(b.image, b.Config); err != nil {
return false, err
} else if cache != nil {
fmt.Fprintf(b.Options.OutStream, " ---> Using cache\n")
fmt.Fprintf(b.OutStream, " ---> Using cache\n")
log.Debugf("[BUILDER] Use cached version")
b.image = cache.ID
return true, nil
@ -365,19 +366,20 @@ func (b *BuildFile) probeCache() (bool, error) {
return false, nil
}
func (b *BuildFile) create() (*daemon.Container, error) {
func (b *Builder) create() (*daemon.Container, error) {
if b.image == "" {
return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
}
b.Config.Image = b.image
// Create the container
c, _, err := b.Options.Daemon.Create(b.Config, "")
c, _, err := b.Daemon.Create(b.Config, "")
if err != nil {
return nil, err
}
b.TmpContainers[c.ID] = struct{}{}
fmt.Fprintf(b.Options.OutStream, " ---> Running in %s\n", utils.TruncateID(c.ID))
fmt.Fprintf(b.OutStream, " ---> Running in %s\n", utils.TruncateID(c.ID))
// override the entry point that may have been picked up from the base image
c.Path = b.Config.Cmd[0]
@ -386,16 +388,16 @@ func (b *BuildFile) create() (*daemon.Container, error) {
return c, nil
}
func (b *BuildFile) run(c *daemon.Container) error {
func (b *Builder) run(c *daemon.Container) error {
var errCh chan error
if b.Options.Verbose {
if b.Verbose {
errCh = utils.Go(func() error {
// FIXME: call the 'attach' job so that daemon.Attach can be made private
//
// FIXME (LK4D4): Also, maybe makes sense to call "logs" job, it is like attach
// but without hijacking for stdin. Also, with attach there can be race
// condition because of some output already was printed before it.
return <-b.Options.Daemon.Attach(c, nil, nil, b.Options.OutStream, b.Options.ErrStream)
return <-b.Daemon.Attach(c, nil, nil, b.OutStream, b.ErrStream)
})
}
@ -422,7 +424,7 @@ func (b *BuildFile) run(c *daemon.Container) error {
return nil
}
func (b *BuildFile) checkPathForAddition(orig string) error {
func (b *Builder) checkPathForAddition(orig string) error {
origPath := path.Join(b.contextPath, orig)
origPath, err := filepath.EvalSymlinks(origPath)
if err != nil {
@ -443,7 +445,7 @@ func (b *BuildFile) checkPathForAddition(orig string) error {
return nil
}
func (b *BuildFile) addContext(container *daemon.Container, orig, dest string, decompress bool) error {
func (b *Builder) addContext(container *daemon.Container, orig, dest string, decompress bool) error {
var (
err error
destExists = true
@ -548,14 +550,14 @@ func fixPermissions(destination string, uid, gid int) error {
})
}
func (b *BuildFile) clearTmp() {
func (b *Builder) clearTmp() {
for c := range b.TmpContainers {
tmp := b.Options.Daemon.Get(c)
if err := b.Options.Daemon.Destroy(tmp); err != nil {
fmt.Fprintf(b.Options.OutStream, "Error removing intermediate container %s: %s\n", utils.TruncateID(c), err.Error())
tmp := b.Daemon.Get(c)
if err := b.Daemon.Destroy(tmp); err != nil {
fmt.Fprintf(b.OutStream, "Error removing intermediate container %s: %s\n", utils.TruncateID(c), err.Error())
} else {
delete(b.TmpContainers, c)
fmt.Fprintf(b.Options.OutStream, "Removing intermediate container %s\n", utils.TruncateID(c))
fmt.Fprintf(b.OutStream, "Removing intermediate container %s\n", utils.TruncateID(c))
}
}
}

View file

@ -85,7 +85,7 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status {
sf := utils.NewStreamFormatter(job.GetenvBool("json"))
opts := &BuildOpts{
builder := &Builder{
Daemon: b.Daemon,
Engine: b.Engine,
OutStream: &utils.StdoutFormater{
@ -106,7 +106,7 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status {
AuthConfigFile: configFile,
}
id, err := NewBuilder(opts).Run(context)
id, err := builder.Run(context)
if err != nil {
return job.Error(err)
}

View file

@ -10,7 +10,7 @@ var (
)
// handle environment replacement. Used in dispatcher.
func (b *BuildFile) replaceEnv(str string) string {
func (b *Builder) replaceEnv(str string) string {
for _, match := range TOKEN_ENV_INTERPOLATION.FindAllString(str, -1) {
match = match[strings.Index(match, "$"):]
matchKey := strings.Trim(match, "${}")