mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Factor out functions from builder/dockerfile/builder.go:Builder.build()
Remove the block comment which is stale, and redundant now that the function is just as readable as the comment. Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
parent
c7fad9b750
commit
bfcd95817a
4 changed files with 90 additions and 74 deletions
|
@ -185,17 +185,6 @@ func sanitizeRepoAndTags(names []string) ([]reference.Named, error) {
|
||||||
|
|
||||||
// build runs the Dockerfile builder from a context and a docker object that allows to make calls
|
// build runs the Dockerfile builder from a context and a docker object that allows to make calls
|
||||||
// to Docker.
|
// to Docker.
|
||||||
//
|
|
||||||
// This will (barring errors):
|
|
||||||
//
|
|
||||||
// * read the dockerfile from context
|
|
||||||
// * parse the dockerfile if not already parsed
|
|
||||||
// * walk the AST and execute it by dispatching to handlers. If Remove
|
|
||||||
// or ForceRemove is set, additional cleanup around containers happens after
|
|
||||||
// processing.
|
|
||||||
// * Tag image, if applicable.
|
|
||||||
// * Print a happy message and return the image ID.
|
|
||||||
//
|
|
||||||
func (b *Builder) build(stdout io.Writer, stderr io.Writer, out io.Writer) (string, error) {
|
func (b *Builder) build(stdout io.Writer, stderr io.Writer, out io.Writer) (string, error) {
|
||||||
defer b.imageContexts.unmount()
|
defer b.imageContexts.unmount()
|
||||||
|
|
||||||
|
@ -203,7 +192,7 @@ func (b *Builder) build(stdout io.Writer, stderr io.Writer, out io.Writer) (stri
|
||||||
b.Stderr = stderr
|
b.Stderr = stderr
|
||||||
b.Output = out
|
b.Output = out
|
||||||
|
|
||||||
dockerfile, err := b.readDockerfile()
|
dockerfile, err := b.readAndParseDockerfile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -215,14 +204,37 @@ func (b *Builder) build(stdout io.Writer, stderr io.Writer, out io.Writer) (stri
|
||||||
|
|
||||||
addNodesForLabelOption(dockerfile, b.options.Labels)
|
addNodesForLabelOption(dockerfile, b.options.Labels)
|
||||||
|
|
||||||
var shortImgID string
|
if err := checkDispatchDockerfile(dockerfile); err != nil {
|
||||||
total := len(dockerfile.Children)
|
return "", err
|
||||||
for _, n := range dockerfile.Children {
|
}
|
||||||
if err := b.checkDispatch(n, false); err != nil {
|
|
||||||
return "", errors.Wrapf(err, "Dockerfile parse error line %d", n.StartLine)
|
shortImageID, err := b.dispatchDockerfileWithCancellation(dockerfile)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.warnOnUnusedBuildArgs()
|
||||||
|
|
||||||
|
if b.image == "" {
|
||||||
|
return "", errors.New("No image was generated. Is your Dockerfile empty?")
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.options.Squash {
|
||||||
|
if err := b.squashBuild(); err != nil {
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(b.Stdout, "Successfully built %s\n", shortImageID)
|
||||||
|
if err := b.tagImages(repoAndTags); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return b.image, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) dispatchDockerfileWithCancellation(dockerfile *parser.Node) (string, error) {
|
||||||
|
total := len(dockerfile.Children)
|
||||||
|
var shortImgID string
|
||||||
for i, n := range dockerfile.Children {
|
for i, n := range dockerfile.Children {
|
||||||
select {
|
select {
|
||||||
case <-b.clientCtx.Done():
|
case <-b.clientCtx.Done():
|
||||||
|
@ -255,34 +267,20 @@ func (b *Builder) build(stdout io.Writer, stderr io.Writer, out io.Writer) (stri
|
||||||
return "", errors.Errorf("failed to reach build target %s in Dockerfile", b.options.Target)
|
return "", errors.Errorf("failed to reach build target %s in Dockerfile", b.options.Target)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.warnOnUnusedBuildArgs()
|
return shortImgID, nil
|
||||||
|
}
|
||||||
|
|
||||||
if b.image == "" {
|
func (b *Builder) squashBuild() error {
|
||||||
return "", errors.New("No image was generated. Is your Dockerfile empty?")
|
var fromID string
|
||||||
|
var err error
|
||||||
|
if b.from != nil {
|
||||||
|
fromID = b.from.ImageID()
|
||||||
}
|
}
|
||||||
|
b.image, err = b.docker.SquashImage(b.image, fromID)
|
||||||
if b.options.Squash {
|
if err != nil {
|
||||||
var fromID string
|
return errors.Wrap(err, "error squashing image")
|
||||||
if b.from != nil {
|
|
||||||
fromID = b.from.ImageID()
|
|
||||||
}
|
|
||||||
b.image, err = b.docker.SquashImage(b.image, fromID)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err, "error squashing image")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
fmt.Fprintf(b.Stdout, "Successfully built %s\n", shortImgID)
|
|
||||||
|
|
||||||
imageID := image.ID(b.image)
|
|
||||||
for _, rt := range repoAndTags {
|
|
||||||
if err := b.docker.TagImageWithReference(imageID, rt); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
fmt.Fprintf(b.Stdout, "Successfully tagged %s\n", reference.FamiliarString(rt))
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.image, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addNodesForLabelOption(dockerfile *parser.Node, labels map[string]string) {
|
func addNodesForLabelOption(dockerfile *parser.Node, labels map[string]string) {
|
||||||
|
@ -303,6 +301,17 @@ func (b *Builder) warnOnUnusedBuildArgs() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Builder) tagImages(repoAndTags []reference.Named) error {
|
||||||
|
imageID := image.ID(b.image)
|
||||||
|
for _, rt := range repoAndTags {
|
||||||
|
if err := b.docker.TagImageWithReference(imageID, rt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintf(b.Stdout, "Successfully tagged %s\n", reference.FamiliarString(rt))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// hasFromImage returns true if the builder has processed a `FROM <image>` line
|
// hasFromImage returns true if the builder has processed a `FROM <image>` line
|
||||||
func (b *Builder) hasFromImage() bool {
|
func (b *Builder) hasFromImage() bool {
|
||||||
return b.image != "" || b.noBaseImage
|
return b.image != "" || b.noBaseImage
|
||||||
|
@ -345,18 +354,31 @@ func BuildFromConfig(config *container.Config, changes []string) (*container.Con
|
||||||
b.Stderr = ioutil.Discard
|
b.Stderr = ioutil.Discard
|
||||||
b.disableCommit = true
|
b.disableCommit = true
|
||||||
|
|
||||||
total := len(ast.Children)
|
if err := checkDispatchDockerfile(ast); err != nil {
|
||||||
for _, n := range ast.Children {
|
return nil, err
|
||||||
if err := b.checkDispatch(n, false); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, n := range ast.Children {
|
if err := dispatchFromDockerfile(b, ast); err != nil {
|
||||||
if err := b.dispatch(i, total, n); err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.runConfig, nil
|
return b.runConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkDispatchDockerfile(dockerfile *parser.Node) error {
|
||||||
|
for _, n := range dockerfile.Children {
|
||||||
|
if err := checkDispatch(n); err != nil {
|
||||||
|
return errors.Wrapf(err, "Dockerfile parse error line %d", n.StartLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dispatchFromDockerfile(b *Builder, ast *parser.Node) error {
|
||||||
|
total := len(ast.Children)
|
||||||
|
for i, n := range ast.Children {
|
||||||
|
if err := b.dispatch(i, total, n); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -206,8 +206,7 @@ func (b *Builder) runConfigEnvMapping() map[string]string {
|
||||||
// arg, env, etc., this syntax check will not be complete and could not replace
|
// arg, env, etc., this syntax check will not be complete and could not replace
|
||||||
// the runtime check. Instead, this function is only a helper that allows
|
// the runtime check. Instead, this function is only a helper that allows
|
||||||
// user to find out the obvious error in Dockerfile earlier on.
|
// user to find out the obvious error in Dockerfile earlier on.
|
||||||
// onbuild bool: indicate if instruction XXX is part of `ONBUILD XXX` trigger
|
func checkDispatch(ast *parser.Node) error {
|
||||||
func (b *Builder) checkDispatch(ast *parser.Node, onbuild bool) error {
|
|
||||||
cmd := ast.Value
|
cmd := ast.Value
|
||||||
upperCasedCmd := strings.ToUpper(cmd)
|
upperCasedCmd := strings.ToUpper(cmd)
|
||||||
|
|
||||||
|
@ -225,16 +224,6 @@ func (b *Builder) checkDispatch(ast *parser.Node, onbuild bool) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The instruction is part of ONBUILD trigger (not the instruction itself)
|
|
||||||
if onbuild {
|
|
||||||
switch upperCasedCmd {
|
|
||||||
case "ONBUILD":
|
|
||||||
return errors.New("Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed")
|
|
||||||
case "MAINTAINER", "FROM":
|
|
||||||
return fmt.Errorf("%s isn't allowed as an ONBUILD trigger", upperCasedCmd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := evaluateTable[cmd]; ok {
|
if _, ok := evaluateTable[cmd]; ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -467,19 +467,24 @@ func (b *Builder) processImageFrom(img builder.Image) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
total := len(ast.Children)
|
|
||||||
for _, n := range ast.Children {
|
for _, n := range ast.Children {
|
||||||
if err := b.checkDispatch(n, true); err != nil {
|
if err := checkDispatch(n); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
upperCasedCmd := strings.ToUpper(n.Value)
|
||||||
|
switch upperCasedCmd {
|
||||||
|
case "ONBUILD":
|
||||||
|
return errors.New("Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed")
|
||||||
|
case "MAINTAINER", "FROM":
|
||||||
|
return errors.Errorf("%s isn't allowed as an ONBUILD trigger", upperCasedCmd)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for i, n := range ast.Children {
|
|
||||||
if err := b.dispatch(i, total, n); err != nil {
|
if err := dispatchFromDockerfile(b, ast); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,8 +649,8 @@ func (b *Builder) clearTmp() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// readDockerfile reads a Dockerfile from the current context.
|
// readAndParseDockerfile reads a Dockerfile from the current context.
|
||||||
func (b *Builder) readDockerfile() (*parser.Node, error) {
|
func (b *Builder) readAndParseDockerfile() (*parser.Node, error) {
|
||||||
// If no -f was specified then look for 'Dockerfile'. If we can't find
|
// If no -f was specified then look for 'Dockerfile'. If we can't find
|
||||||
// that then look for 'dockerfile'. If neither are found then default
|
// that then look for 'dockerfile'. If neither are found then default
|
||||||
// back to 'Dockerfile' and use that in the error message.
|
// back to 'Dockerfile' and use that in the error message.
|
||||||
|
|
|
@ -77,6 +77,6 @@ func readAndCheckDockerfile(t *testing.T, testName, contextDir, dockerfilePath,
|
||||||
|
|
||||||
b := &Builder{options: options, context: context}
|
b := &Builder{options: options, context: context}
|
||||||
|
|
||||||
_, err = b.readDockerfile()
|
_, err = b.readAndParseDockerfile()
|
||||||
assert.Error(t, err, expectedError)
|
assert.Error(t, err, expectedError)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue