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:
parent
305f735080
commit
2ef1dec7e8
6 changed files with 106 additions and 115 deletions
|
@ -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{}{},
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// dispatch with no layer / parsing. This is effectively not a command.
|
// 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
|
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
|
// Sets the environment variable foo to bar, also makes interpolation
|
||||||
// in the dockerfile available from the next statement on via ${foo}.
|
// 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 {
|
if len(args) != 2 {
|
||||||
return fmt.Errorf("ENV accepts two arguments")
|
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>
|
// MAINTAINER some text <maybe@an.email.address>
|
||||||
//
|
//
|
||||||
// Sets the maintainer metadata.
|
// 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 {
|
if len(args) != 1 {
|
||||||
return fmt.Errorf("MAINTAINER requires only one argument")
|
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
|
// 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.
|
// 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 {
|
if len(args) != 2 {
|
||||||
return fmt.Errorf("ADD requires two arguments")
|
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.
|
// 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 {
|
if len(args) != 2 {
|
||||||
return fmt.Errorf("COPY requires two arguments")
|
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.
|
// 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 {
|
if len(args) != 1 {
|
||||||
return fmt.Errorf("FROM requires one argument")
|
return fmt.Errorf("FROM requires one argument")
|
||||||
}
|
}
|
||||||
|
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
||||||
image, err := b.Options.Daemon.Repositories().LookupImage(name)
|
image, err := b.Daemon.Repositories().LookupImage(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if b.Options.Daemon.Graph().IsNotExist(err) {
|
if b.Daemon.Graph().IsNotExist(err) {
|
||||||
image, err = b.pullImage(name)
|
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
|
// special cases. search for 'OnBuild' in internals.go for additional special
|
||||||
// cases.
|
// 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]))
|
triggerInstruction := strings.ToUpper(strings.TrimSpace(args[0]))
|
||||||
switch triggerInstruction {
|
switch triggerInstruction {
|
||||||
case "ONBUILD":
|
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.
|
// 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 {
|
if len(args) != 1 {
|
||||||
return fmt.Errorf("WORKDIR requires exactly one argument")
|
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 # sh -c echo hi
|
||||||
// RUN [ "echo", "hi" ] # 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)
|
args = handleJsonArgs(args, attributes)
|
||||||
|
|
||||||
if b.image == "" {
|
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).
|
// Set the default command to run in the container (which may be empty).
|
||||||
// Argument handling is the same as RUN.
|
// 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)
|
b.Config.Cmd = handleJsonArgs(args, attributes)
|
||||||
|
|
||||||
if err := b.commit("", b.Config.Cmd, fmt.Sprintf("CMD %v", cmd)); err != nil {
|
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
|
// Handles command processing similar to CMD and RUN, only b.Config.Entrypoint
|
||||||
// is initialized at NewBuilder time instead of through argument parsing.
|
// 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)
|
b.Config.Entrypoint = handleJsonArgs(args, attributes)
|
||||||
|
|
||||||
// if there is no cmd in current Dockerfile - cleanup cmd
|
// 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
|
// Expose ports for links and port mappings. This all ends up in
|
||||||
// b.Config.ExposedPorts for runconfig.
|
// 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
|
portsTab := args
|
||||||
|
|
||||||
if b.Config.ExposedPorts == nil {
|
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
|
// Set the user to 'foo' for future commands and when running the
|
||||||
// ENTRYPOINT/CMD at container run time.
|
// 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 {
|
if len(args) != 1 {
|
||||||
return fmt.Errorf("USER requires exactly one argument")
|
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
|
// Expose the volume /foo for use. Will also accept the JSON form, but either
|
||||||
// way requires exactly one argument.
|
// 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 {
|
if len(args) != 1 {
|
||||||
return fmt.Errorf("Volume cannot be empty")
|
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.
|
// 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")
|
return fmt.Errorf("INSERT has been deprecated. Please use ADD instead")
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,9 @@
|
||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -42,10 +40,10 @@ var (
|
||||||
ErrDockerfileEmpty = errors.New("Dockerfile cannot be empty")
|
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() {
|
func init() {
|
||||||
evaluateTable = map[string]func(*BuildFile, []string, map[string]bool) error{
|
evaluateTable = map[string]func(*Builder, []string, map[string]bool) error{
|
||||||
"env": env,
|
"env": env,
|
||||||
"maintainer": maintainer,
|
"maintainer": maintainer,
|
||||||
"add": add,
|
"add": add,
|
||||||
|
@ -66,23 +64,7 @@ func init() {
|
||||||
|
|
||||||
// internal struct, used to maintain configuration of the Dockerfile's
|
// internal struct, used to maintain configuration of the Dockerfile's
|
||||||
// processing as it evaluates the parsing result.
|
// processing as it evaluates the parsing result.
|
||||||
type BuildFile struct {
|
type Builder 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 {
|
|
||||||
Daemon *daemon.Daemon
|
Daemon *daemon.Daemon
|
||||||
Engine *engine.Engine
|
Engine *engine.Engine
|
||||||
|
|
||||||
|
@ -104,6 +86,19 @@ type BuildOpts struct {
|
||||||
// Deprecated, original writer used for ImagePull. To be removed.
|
// Deprecated, original writer used for ImagePull. To be removed.
|
||||||
OutOld io.Writer
|
OutOld io.Writer
|
||||||
StreamFormatter *utils.StreamFormatter
|
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
|
// Run the builder with the context. This is the lynchpin of this package. This
|
||||||
|
@ -118,38 +113,48 @@ type BuildOpts struct {
|
||||||
// processing.
|
// processing.
|
||||||
// * Print a happy message and return the image ID.
|
// * 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 {
|
if err := b.readContext(context); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
filename := path.Join(b.contextPath, "Dockerfile")
|
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")
|
return "", fmt.Errorf("Cannot build a directory without a Dockerfile")
|
||||||
}
|
}
|
||||||
fileBytes, err := ioutil.ReadFile(filename)
|
if fi.Size() == 0 {
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if len(fileBytes) == 0 {
|
|
||||||
return "", ErrDockerfileEmpty
|
return "", ErrDockerfileEmpty
|
||||||
}
|
}
|
||||||
ast, err := parser.Parse(bytes.NewReader(fileBytes))
|
|
||||||
|
f, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
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 err := b.dispatch(i, n); err != nil {
|
||||||
if b.Options.ForceRemove {
|
if b.ForceRemove {
|
||||||
b.clearTmp()
|
b.clearTmp()
|
||||||
}
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(b.Options.OutStream, " ---> %s\n", utils.TruncateID(b.image))
|
fmt.Fprintf(b.OutStream, " ---> %s\n", utils.TruncateID(b.image))
|
||||||
if b.Options.Remove {
|
if b.Remove {
|
||||||
b.clearTmp()
|
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")
|
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
|
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
|
// 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
|
// 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
|
// 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:
|
// ONBUILD is a special case; in this case the parser will emit:
|
||||||
// Child[Node, Child[Node, Node...]] where the first node is the literal
|
// 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
|
// 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
|
// deal with that, at least until it becomes more of a general concern with new
|
||||||
// features.
|
// features.
|
||||||
func (b *BuildFile) dispatch(stepN int, ast *parser.Node) error {
|
func (b *Builder) dispatch(stepN int, ast *parser.Node) error {
|
||||||
cmd := ast.Value
|
cmd := ast.Value
|
||||||
attrs := ast.Attributes
|
attrs := ast.Attributes
|
||||||
strs := []string{}
|
strs := []string{}
|
||||||
msg := fmt.Sprintf("Step %d : %s", stepN, strings.ToUpper(cmd))
|
msg := fmt.Sprintf("Step %d : %s", stepN, strings.ToUpper(cmd))
|
||||||
|
|
||||||
if cmd == "onbuild" {
|
if cmd == "onbuild" {
|
||||||
fmt.Fprintf(b.Options.OutStream, "%#v\n", ast.Next.Children[0].Value)
|
|
||||||
ast = ast.Next.Children[0]
|
ast = ast.Next.Children[0]
|
||||||
strs = append(strs, b.replaceEnv(ast.Value))
|
strs = append(strs, b.replaceEnv(ast.Value))
|
||||||
msg += " " + ast.Value
|
msg += " " + ast.Value
|
||||||
|
@ -195,7 +199,7 @@ func (b *BuildFile) dispatch(stepN int, ast *parser.Node) error {
|
||||||
msg += " " + ast.Value
|
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
|
// XXX yes, we skip any cmds that are not valid; the parser should have
|
||||||
// picked these out already.
|
// picked these out already.
|
||||||
|
@ -203,7 +207,7 @@ func (b *BuildFile) dispatch(stepN int, ast *parser.Node) error {
|
||||||
return f(b, strs, attrs)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import (
|
||||||
"github.com/docker/docker/utils"
|
"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")
|
tmpdirPath, err := ioutil.TempDir("", "docker-build")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -50,7 +50,7 @@ func (b *BuildFile) readContext(context io.Reader) error {
|
||||||
return nil
|
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 == "" {
|
if b.image == "" {
|
||||||
return fmt.Errorf("Please provide a source image with `from` prior to commit")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
container, warnings, err := b.Options.Daemon.Create(b.Config, "")
|
container, warnings, err := b.Daemon.Create(b.Config, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, warning := range warnings {
|
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{}{}
|
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
|
id = container.ID
|
||||||
|
|
||||||
if err := container.Mount(); err != nil {
|
if err := container.Mount(); err != nil {
|
||||||
|
@ -84,7 +84,7 @@ func (b *BuildFile) commit(id string, autoCmd []string, comment string) error {
|
||||||
}
|
}
|
||||||
defer container.Unmount()
|
defer container.Unmount()
|
||||||
}
|
}
|
||||||
container := b.Options.Daemon.Get(id)
|
container := b.Daemon.Get(id)
|
||||||
if container == nil {
|
if container == nil {
|
||||||
return fmt.Errorf("An error occured while creating the container")
|
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 := *b.Config
|
||||||
autoConfig.Cmd = autoCmd
|
autoConfig.Cmd = autoCmd
|
||||||
// Commit the container
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ func (b *BuildFile) commit(id string, autoCmd []string, comment string) error {
|
||||||
return nil
|
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 {
|
if b.context == nil {
|
||||||
return fmt.Errorf("No context given. Impossible to use %s", cmdName)
|
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
|
// Hash path and check the cache
|
||||||
if b.Options.UtilizeCache {
|
if b.UtilizeCache {
|
||||||
var (
|
var (
|
||||||
hash string
|
hash string
|
||||||
sums = b.context.GetSums()
|
sums = b.context.GetSums()
|
||||||
|
@ -244,7 +244,7 @@ func (b *BuildFile) runContextCommand(args []string, allowRemote bool, allowDeco
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the container
|
// Create the container
|
||||||
container, _, err := b.Options.Daemon.Create(b.Config, "")
|
container, _, err := b.Daemon.Create(b.Config, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -268,27 +268,27 @@ func (b *BuildFile) runContextCommand(args []string, allowRemote bool, allowDeco
|
||||||
return nil
|
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)
|
remote, tag := parsers.ParseRepositoryTag(name)
|
||||||
pullRegistryAuth := b.Options.AuthConfig
|
pullRegistryAuth := b.AuthConfig
|
||||||
if len(b.Options.AuthConfigFile.Configs) > 0 {
|
if len(b.AuthConfigFile.Configs) > 0 {
|
||||||
// The request came with a full auth config file, we prefer to use that
|
// The request came with a full auth config file, we prefer to use that
|
||||||
endpoint, _, err := registry.ResolveRepositoryName(remote)
|
endpoint, _, err := registry.ResolveRepositoryName(remote)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resolvedAuth := b.Options.AuthConfigFile.ResolveAuthConfig(endpoint)
|
resolvedAuth := b.AuthConfigFile.ResolveAuthConfig(endpoint)
|
||||||
pullRegistryAuth = &resolvedAuth
|
pullRegistryAuth = &resolvedAuth
|
||||||
}
|
}
|
||||||
job := b.Options.Engine.Job("pull", remote, tag)
|
job := b.Engine.Job("pull", remote, tag)
|
||||||
job.SetenvBool("json", b.Options.StreamFormatter.Json())
|
job.SetenvBool("json", b.StreamFormatter.Json())
|
||||||
job.SetenvBool("parallel", true)
|
job.SetenvBool("parallel", true)
|
||||||
job.SetenvJson("authConfig", pullRegistryAuth)
|
job.SetenvJson("authConfig", pullRegistryAuth)
|
||||||
job.Stdout.Add(b.Options.OutOld)
|
job.Stdout.Add(b.OutOld)
|
||||||
if err := job.Run(); err != nil {
|
if err := job.Run(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
image, err := b.Options.Daemon.Repositories().LookupImage(name)
|
image, err := b.Daemon.Repositories().LookupImage(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -296,7 +296,7 @@ func (b *BuildFile) pullImage(name string) (*imagepkg.Image, error) {
|
||||||
return image, nil
|
return image, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BuildFile) processImageFrom(img *imagepkg.Image) error {
|
func (b *Builder) processImageFrom(img *imagepkg.Image) error {
|
||||||
b.image = img.ID
|
b.image = img.ID
|
||||||
|
|
||||||
if img.Config != nil {
|
if img.Config != nil {
|
||||||
|
@ -309,7 +309,7 @@ func (b *BuildFile) processImageFrom(img *imagepkg.Image) error {
|
||||||
|
|
||||||
// Process ONBUILD triggers if they exist
|
// Process ONBUILD triggers if they exist
|
||||||
if nTriggers := len(b.Config.OnBuild); nTriggers != 0 {
|
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.
|
// 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
|
// 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 f, ok := evaluateTable[strings.ToLower(stepInstruction)]; ok {
|
||||||
if err := f(b, splitStep[1:], nil); err != nil {
|
if err := f(b, splitStep[1:], nil); err != nil {
|
||||||
|
@ -344,17 +345,17 @@ func (b *BuildFile) processImageFrom(img *imagepkg.Image) error {
|
||||||
return nil
|
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
|
// 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
|
// `(true, nil)`. If no image is found, it returns `(false, nil)`. If there
|
||||||
// is any error, it returns `(false, err)`.
|
// is any error, it returns `(false, err)`.
|
||||||
func (b *BuildFile) probeCache() (bool, error) {
|
func (b *Builder) probeCache() (bool, error) {
|
||||||
if b.Options.UtilizeCache {
|
if b.UtilizeCache {
|
||||||
if cache, err := b.Options.Daemon.ImageGetCached(b.image, b.Config); err != nil {
|
if cache, err := b.Daemon.ImageGetCached(b.image, b.Config); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
} else if cache != nil {
|
} 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")
|
log.Debugf("[BUILDER] Use cached version")
|
||||||
b.image = cache.ID
|
b.image = cache.ID
|
||||||
return true, nil
|
return true, nil
|
||||||
|
@ -365,19 +366,20 @@ func (b *BuildFile) probeCache() (bool, error) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BuildFile) create() (*daemon.Container, error) {
|
func (b *Builder) create() (*daemon.Container, error) {
|
||||||
if b.image == "" {
|
if b.image == "" {
|
||||||
return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
|
return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
|
||||||
}
|
}
|
||||||
b.Config.Image = b.image
|
b.Config.Image = b.image
|
||||||
|
|
||||||
// Create the container
|
// Create the container
|
||||||
c, _, err := b.Options.Daemon.Create(b.Config, "")
|
c, _, err := b.Daemon.Create(b.Config, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
b.TmpContainers[c.ID] = struct{}{}
|
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
|
// override the entry point that may have been picked up from the base image
|
||||||
c.Path = b.Config.Cmd[0]
|
c.Path = b.Config.Cmd[0]
|
||||||
|
@ -386,16 +388,16 @@ func (b *BuildFile) create() (*daemon.Container, error) {
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BuildFile) run(c *daemon.Container) error {
|
func (b *Builder) run(c *daemon.Container) error {
|
||||||
var errCh chan error
|
var errCh chan error
|
||||||
if b.Options.Verbose {
|
if b.Verbose {
|
||||||
errCh = utils.Go(func() error {
|
errCh = utils.Go(func() error {
|
||||||
// FIXME: call the 'attach' job so that daemon.Attach can be made private
|
// 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
|
// 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
|
// but without hijacking for stdin. Also, with attach there can be race
|
||||||
// condition because of some output already was printed before it.
|
// 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BuildFile) checkPathForAddition(orig string) error {
|
func (b *Builder) checkPathForAddition(orig string) error {
|
||||||
origPath := path.Join(b.contextPath, orig)
|
origPath := path.Join(b.contextPath, orig)
|
||||||
origPath, err := filepath.EvalSymlinks(origPath)
|
origPath, err := filepath.EvalSymlinks(origPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -443,7 +445,7 @@ func (b *BuildFile) checkPathForAddition(orig string) error {
|
||||||
return nil
|
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 (
|
var (
|
||||||
err error
|
err error
|
||||||
destExists = true
|
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 {
|
for c := range b.TmpContainers {
|
||||||
tmp := b.Options.Daemon.Get(c)
|
tmp := b.Daemon.Get(c)
|
||||||
if err := b.Options.Daemon.Destroy(tmp); err != nil {
|
if err := b.Daemon.Destroy(tmp); err != nil {
|
||||||
fmt.Fprintf(b.Options.OutStream, "Error removing intermediate container %s: %s\n", utils.TruncateID(c), err.Error())
|
fmt.Fprintf(b.OutStream, "Error removing intermediate container %s: %s\n", utils.TruncateID(c), err.Error())
|
||||||
} else {
|
} else {
|
||||||
delete(b.TmpContainers, c)
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status {
|
||||||
|
|
||||||
sf := utils.NewStreamFormatter(job.GetenvBool("json"))
|
sf := utils.NewStreamFormatter(job.GetenvBool("json"))
|
||||||
|
|
||||||
opts := &BuildOpts{
|
builder := &Builder{
|
||||||
Daemon: b.Daemon,
|
Daemon: b.Daemon,
|
||||||
Engine: b.Engine,
|
Engine: b.Engine,
|
||||||
OutStream: &utils.StdoutFormater{
|
OutStream: &utils.StdoutFormater{
|
||||||
|
@ -106,7 +106,7 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status {
|
||||||
AuthConfigFile: configFile,
|
AuthConfigFile: configFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := NewBuilder(opts).Run(context)
|
id, err := builder.Run(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return job.Error(err)
|
return job.Error(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// handle environment replacement. Used in dispatcher.
|
// 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) {
|
for _, match := range TOKEN_ENV_INTERPOLATION.FindAllString(str, -1) {
|
||||||
match = match[strings.Index(match, "$"):]
|
match = match[strings.Index(match, "$"):]
|
||||||
matchKey := strings.Trim(match, "${}")
|
matchKey := strings.Trim(match, "${}")
|
||||||
|
|
Loading…
Add table
Reference in a new issue