mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Extract commitContainer from commit() to separate the distinct branches
Remove unused arguments to commit. This will allow us to remove all the runConfig mutate+revert code that is scattered around builder dispatchers/internals Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
parent
eabee4d47b
commit
0d9e66b98a
3 changed files with 146 additions and 82 deletions
|
@ -73,7 +73,7 @@ func env(req dispatchRequest) error {
|
|||
}
|
||||
}
|
||||
|
||||
return req.builder.commit("", req.runConfig.Cmd, commitMessage.String())
|
||||
return req.builder.commit(commitMessage.String())
|
||||
}
|
||||
|
||||
// MAINTAINER some text <maybe@an.email.address>
|
||||
|
@ -90,7 +90,7 @@ func maintainer(req dispatchRequest) error {
|
|||
|
||||
maintainer := req.args[0]
|
||||
req.builder.maintainer = maintainer
|
||||
return req.builder.commit("", req.runConfig.Cmd, "MAINTAINER "+maintainer)
|
||||
return req.builder.commit("MAINTAINER " + maintainer)
|
||||
}
|
||||
|
||||
// LABEL some json data describing the image
|
||||
|
@ -130,7 +130,7 @@ func label(req dispatchRequest) error {
|
|||
req.runConfig.Labels[req.args[j]] = req.args[j+1]
|
||||
j++
|
||||
}
|
||||
return req.builder.commit("", req.runConfig.Cmd, commitStr)
|
||||
return req.builder.commit(commitStr)
|
||||
}
|
||||
|
||||
// ADD foo /path
|
||||
|
@ -281,7 +281,7 @@ func onbuild(req dispatchRequest) error {
|
|||
|
||||
original := regexp.MustCompile(`(?i)^\s*ONBUILD\s*`).ReplaceAllString(req.original, "")
|
||||
req.runConfig.OnBuild = append(req.runConfig.OnBuild, original)
|
||||
return req.builder.commit("", req.runConfig.Cmd, fmt.Sprintf("ONBUILD %s", original))
|
||||
return req.builder.commit("ONBUILD " + original)
|
||||
}
|
||||
|
||||
// WORKDIR /tmp
|
||||
|
@ -321,10 +321,9 @@ func workdir(req dispatchRequest) error {
|
|||
req.runConfig.Cmd = strslice.StrSlice(append(getShell(req.runConfig), "#(nop) "+comment))
|
||||
defer func(cmd strslice.StrSlice) { req.runConfig.Cmd = cmd }(cmd)
|
||||
|
||||
if hit, err := req.builder.probeCache(); err != nil {
|
||||
// TODO: this should pass a copy of runConfig
|
||||
if hit, err := req.builder.probeCache(req.builder.image, req.runConfig); err != nil || hit {
|
||||
return err
|
||||
} else if hit {
|
||||
return nil
|
||||
}
|
||||
|
||||
req.runConfig.Image = req.builder.image
|
||||
|
@ -341,7 +340,7 @@ func workdir(req dispatchRequest) error {
|
|||
return err
|
||||
}
|
||||
|
||||
return req.builder.commit(container.ID, cmd, comment)
|
||||
return req.builder.commitContainer(container.ID, copyRunConfig(req.runConfig, withCmd(cmd)))
|
||||
}
|
||||
|
||||
// RUN some command yo
|
||||
|
@ -402,13 +401,10 @@ func run(req dispatchRequest) error {
|
|||
}
|
||||
|
||||
req.runConfig.Cmd = saveCmd
|
||||
hit, err := req.builder.probeCache()
|
||||
if err != nil {
|
||||
hit, err := req.builder.probeCache(req.builder.image, req.runConfig)
|
||||
if err != nil || hit {
|
||||
return err
|
||||
}
|
||||
if hit {
|
||||
return nil
|
||||
}
|
||||
|
||||
// set Cmd manually, this is special case only for Dockerfiles
|
||||
req.runConfig.Cmd = config.Cmd
|
||||
|
@ -419,7 +415,11 @@ func run(req dispatchRequest) error {
|
|||
|
||||
logrus.Debugf("[BUILDER] Command to be executed: %v", req.runConfig.Cmd)
|
||||
|
||||
cID, err := req.builder.create()
|
||||
// TODO: this was previously in b.create(), why is it necessary?
|
||||
req.builder.runConfig.Image = req.builder.image
|
||||
|
||||
// TODO: should pass a copy of runConfig
|
||||
cID, err := req.builder.create(req.runConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -451,7 +451,7 @@ func run(req dispatchRequest) error {
|
|||
saveCmd = strslice.StrSlice(append(tmpEnv, saveCmd...))
|
||||
}
|
||||
req.runConfig.Cmd = saveCmd
|
||||
return req.builder.commit(cID, cmd, "run")
|
||||
return req.builder.commitContainer(cID, copyRunConfig(req.runConfig, withCmd(cmd)))
|
||||
}
|
||||
|
||||
// CMD foo
|
||||
|
@ -474,7 +474,7 @@ func cmd(req dispatchRequest) error {
|
|||
// set config as already being escaped, this prevents double escaping on windows
|
||||
req.runConfig.ArgsEscaped = true
|
||||
|
||||
if err := req.builder.commit("", req.runConfig.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil {
|
||||
if err := req.builder.commit(fmt.Sprintf("CMD %q", cmdSlice)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -590,7 +590,7 @@ func healthcheck(req dispatchRequest) error {
|
|||
req.runConfig.Healthcheck = &healthcheck
|
||||
}
|
||||
|
||||
return req.builder.commit("", req.runConfig.Cmd, fmt.Sprintf("HEALTHCHECK %q", req.runConfig.Healthcheck))
|
||||
return req.builder.commit(fmt.Sprintf("HEALTHCHECK %q", req.runConfig.Healthcheck))
|
||||
}
|
||||
|
||||
// ENTRYPOINT /usr/sbin/nginx
|
||||
|
@ -626,11 +626,7 @@ func entrypoint(req dispatchRequest) error {
|
|||
req.runConfig.Cmd = nil
|
||||
}
|
||||
|
||||
if err := req.builder.commit("", req.runConfig.Cmd, fmt.Sprintf("ENTRYPOINT %q", req.runConfig.Entrypoint)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return req.builder.commit(fmt.Sprintf("ENTRYPOINT %q", req.runConfig.Entrypoint))
|
||||
}
|
||||
|
||||
// EXPOSE 6667/tcp 7000/tcp
|
||||
|
@ -671,7 +667,7 @@ func expose(req dispatchRequest) error {
|
|||
i++
|
||||
}
|
||||
sort.Strings(portList)
|
||||
return req.builder.commit("", req.runConfig.Cmd, fmt.Sprintf("EXPOSE %s", strings.Join(portList, " ")))
|
||||
return req.builder.commit("EXPOSE " + strings.Join(portList, " "))
|
||||
}
|
||||
|
||||
// USER foo
|
||||
|
@ -689,7 +685,7 @@ func user(req dispatchRequest) error {
|
|||
}
|
||||
|
||||
req.runConfig.User = req.args[0]
|
||||
return req.builder.commit("", req.runConfig.Cmd, fmt.Sprintf("USER %v", req.args))
|
||||
return req.builder.commit(fmt.Sprintf("USER %v", req.args))
|
||||
}
|
||||
|
||||
// VOLUME /foo
|
||||
|
@ -715,10 +711,7 @@ func volume(req dispatchRequest) error {
|
|||
}
|
||||
req.runConfig.Volumes[v] = struct{}{}
|
||||
}
|
||||
if err := req.builder.commit("", req.runConfig.Cmd, fmt.Sprintf("VOLUME %v", req.args)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return req.builder.commit(fmt.Sprintf("VOLUME %v", req.args))
|
||||
}
|
||||
|
||||
// STOPSIGNAL signal
|
||||
|
@ -736,7 +729,7 @@ func stopSignal(req dispatchRequest) error {
|
|||
}
|
||||
|
||||
req.runConfig.StopSignal = sig
|
||||
return req.builder.commit("", req.runConfig.Cmd, fmt.Sprintf("STOPSIGNAL %v", req.args))
|
||||
return req.builder.commit(fmt.Sprintf("STOPSIGNAL %v", req.args))
|
||||
}
|
||||
|
||||
// ARG name[=value]
|
||||
|
@ -786,7 +779,7 @@ func arg(req dispatchRequest) error {
|
|||
req.builder.buildArgs.AddMetaArg(name, value)
|
||||
return nil
|
||||
}
|
||||
return req.builder.commit("", req.runConfig.Cmd, fmt.Sprintf("ARG %s", arg))
|
||||
return req.builder.commit("ARG " + arg)
|
||||
}
|
||||
|
||||
// SHELL powershell -command
|
||||
|
@ -808,7 +801,7 @@ func shell(req dispatchRequest) error {
|
|||
// SHELL powershell -command - not JSON
|
||||
return errNotJSON("SHELL", req.original)
|
||||
}
|
||||
return req.builder.commit("", req.runConfig.Cmd, fmt.Sprintf("SHELL %v", shellSlice))
|
||||
return req.builder.commit(fmt.Sprintf("SHELL %v", shellSlice))
|
||||
}
|
||||
|
||||
func errAtLeastOneArgument(command string) error {
|
||||
|
@ -831,15 +824,6 @@ func errTooManyArguments(command string) error {
|
|||
return fmt.Errorf("Bad input to %s, too many arguments", command)
|
||||
}
|
||||
|
||||
// getShell is a helper function which gets the right shell for prefixing the
|
||||
// shell-form of RUN, ENTRYPOINT and CMD instructions
|
||||
func getShell(c *container.Config) []string {
|
||||
if 0 == len(c.Shell) {
|
||||
return append([]string{}, defaultShell[:]...)
|
||||
}
|
||||
return append([]string{}, c.Shell[:]...)
|
||||
}
|
||||
|
||||
// mountByRef creates an imageMount from a reference. pulling the image if needed.
|
||||
func mountByRef(b *Builder, name string) (*imageMount, error) {
|
||||
image, err := pullOrGetImage(b, name)
|
||||
|
|
|
@ -36,41 +36,39 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (b *Builder) commit(id string, autoCmd strslice.StrSlice, comment string) error {
|
||||
func (b *Builder) commit(comment string) error {
|
||||
if b.disableCommit {
|
||||
return nil
|
||||
}
|
||||
if !b.hasFromImage() {
|
||||
return errors.New("Please provide a source image with `from` prior to commit")
|
||||
}
|
||||
// TODO: why is this set here?
|
||||
b.runConfig.Image = b.image
|
||||
|
||||
if id == "" {
|
||||
cmd := b.runConfig.Cmd
|
||||
b.runConfig.Cmd = strslice.StrSlice(append(getShell(b.runConfig), "#(nop) ", comment))
|
||||
defer func(cmd strslice.StrSlice) { b.runConfig.Cmd = cmd }(cmd)
|
||||
|
||||
hit, err := b.probeCache()
|
||||
if err != nil {
|
||||
return err
|
||||
} else if hit {
|
||||
return nil
|
||||
}
|
||||
id, err = b.create()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
runConfigWithCommentCmd := copyRunConfig(b.runConfig, withCmdComment(comment))
|
||||
hit, err := b.probeCache(b.image, runConfigWithCommentCmd)
|
||||
if err != nil || hit {
|
||||
return err
|
||||
}
|
||||
id, err := b.create(runConfigWithCommentCmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Note: Actually copy the struct
|
||||
autoConfig := *b.runConfig
|
||||
autoConfig.Cmd = autoCmd
|
||||
return b.commitContainer(id, b.runConfig)
|
||||
}
|
||||
|
||||
func (b *Builder) commitContainer(id string, runConfig *container.Config) error {
|
||||
if b.disableCommit {
|
||||
return nil
|
||||
}
|
||||
|
||||
commitCfg := &backend.ContainerCommitConfig{
|
||||
ContainerCommitConfig: types.ContainerCommitConfig{
|
||||
Author: b.maintainer,
|
||||
Pause: true,
|
||||
Config: &autoConfig,
|
||||
Config: runConfig,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -80,8 +78,10 @@ func (b *Builder) commit(id string, autoCmd strslice.StrSlice, comment string) e
|
|||
return err
|
||||
}
|
||||
|
||||
// TODO: this function should return imageID and runConfig instead of setting
|
||||
// then on the builder
|
||||
b.image = imageID
|
||||
b.imageContexts.update(imageID, &autoConfig)
|
||||
b.imageContexts.update(imageID, runConfig)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -148,11 +148,9 @@ func (b *Builder) runContextCommand(args []string, allowRemote bool, allowLocalD
|
|||
// For backwards compat, if there's just one info then use it as the
|
||||
// cache look-up string, otherwise hash 'em all into one
|
||||
var srcHash string
|
||||
var origPaths string
|
||||
|
||||
if len(infos) == 1 {
|
||||
info := infos[0]
|
||||
origPaths = info.path
|
||||
srcHash = info.hash
|
||||
} else {
|
||||
var hashs []string
|
||||
|
@ -164,17 +162,16 @@ func (b *Builder) runContextCommand(args []string, allowRemote bool, allowLocalD
|
|||
hasher := sha256.New()
|
||||
hasher.Write([]byte(strings.Join(hashs, ",")))
|
||||
srcHash = "multi:" + hex.EncodeToString(hasher.Sum(nil))
|
||||
origPaths = strings.Join(origs, " ")
|
||||
}
|
||||
|
||||
cmd := b.runConfig.Cmd
|
||||
// TODO: should this have been using origPaths instead of srcHash in the comment?
|
||||
b.runConfig.Cmd = strslice.StrSlice(append(getShell(b.runConfig), fmt.Sprintf("#(nop) %s %s in %s ", cmdName, srcHash, dest)))
|
||||
defer func(cmd strslice.StrSlice) { b.runConfig.Cmd = cmd }(cmd)
|
||||
|
||||
if hit, err := b.probeCache(); err != nil {
|
||||
// TODO: this should pass a copy of runConfig
|
||||
if hit, err := b.probeCache(b.image, b.runConfig); err != nil || hit {
|
||||
return err
|
||||
} else if hit {
|
||||
return nil
|
||||
}
|
||||
|
||||
container, err := b.docker.ContainerCreate(types.ContainerCreateConfig{
|
||||
|
@ -187,8 +184,6 @@ func (b *Builder) runContextCommand(args []string, allowRemote bool, allowLocalD
|
|||
}
|
||||
b.tmpContainers[container.ID] = struct{}{}
|
||||
|
||||
comment := fmt.Sprintf("%s %s in %s", cmdName, origPaths, dest)
|
||||
|
||||
// Twiddle the destination when it's a relative path - meaning, make it
|
||||
// relative to the WORKINGDIR
|
||||
if dest, err = normaliseDest(cmdName, b.runConfig.WorkingDir, dest); err != nil {
|
||||
|
@ -201,7 +196,44 @@ func (b *Builder) runContextCommand(args []string, allowRemote bool, allowLocalD
|
|||
}
|
||||
}
|
||||
|
||||
return b.commit(container.ID, cmd, comment)
|
||||
return b.commitContainer(container.ID, copyRunConfig(b.runConfig, withCmd(cmd)))
|
||||
}
|
||||
|
||||
type runConfigModifier func(*container.Config)
|
||||
|
||||
func copyRunConfig(runConfig *container.Config, modifiers ...runConfigModifier) *container.Config {
|
||||
copy := *runConfig
|
||||
for _, modifier := range modifiers {
|
||||
modifier(©)
|
||||
}
|
||||
return ©
|
||||
}
|
||||
|
||||
func withCmd(cmd []string) runConfigModifier {
|
||||
return func(runConfig *container.Config) {
|
||||
runConfig.Cmd = cmd
|
||||
}
|
||||
}
|
||||
|
||||
func withCmdComment(comment string) runConfigModifier {
|
||||
return func(runConfig *container.Config) {
|
||||
runConfig.Cmd = append(getShell(runConfig), "#(nop) ", comment)
|
||||
}
|
||||
}
|
||||
|
||||
func withEnv(env []string) runConfigModifier {
|
||||
return func(runConfig *container.Config) {
|
||||
runConfig.Env = env
|
||||
}
|
||||
}
|
||||
|
||||
// getShell is a helper function which gets the right shell for prefixing the
|
||||
// shell-form of RUN, ENTRYPOINT and CMD instructions
|
||||
func getShell(c *container.Config) []string {
|
||||
if 0 == len(c.Shell) {
|
||||
return append([]string{}, defaultShell[:]...)
|
||||
}
|
||||
return append([]string{}, c.Shell[:]...)
|
||||
}
|
||||
|
||||
func (b *Builder) download(srcURL string) (remote builder.Source, p string, err error) {
|
||||
|
@ -498,35 +530,33 @@ func (b *Builder) processImageFrom(img builder.Image) error {
|
|||
// 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 *Builder) probeCache() (bool, error) {
|
||||
func (b *Builder) probeCache(imageID string, runConfig *container.Config) (bool, error) {
|
||||
c := b.imageCache
|
||||
if c == nil || b.options.NoCache || b.cacheBusted {
|
||||
return false, nil
|
||||
}
|
||||
cache, err := c.GetCache(b.image, b.runConfig)
|
||||
cache, err := c.GetCache(imageID, runConfig)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(cache) == 0 {
|
||||
logrus.Debugf("[BUILDER] Cache miss: %s", b.runConfig.Cmd)
|
||||
logrus.Debugf("[BUILDER] Cache miss: %s", runConfig.Cmd)
|
||||
b.cacheBusted = true
|
||||
return false, nil
|
||||
}
|
||||
|
||||
fmt.Fprint(b.Stdout, " ---> Using cache\n")
|
||||
logrus.Debugf("[BUILDER] Use cached version: %s", b.runConfig.Cmd)
|
||||
logrus.Debugf("[BUILDER] Use cached version: %s", runConfig.Cmd)
|
||||
b.image = string(cache)
|
||||
b.imageContexts.update(b.image, b.runConfig)
|
||||
b.imageContexts.update(b.image, runConfig)
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (b *Builder) create() (string, error) {
|
||||
func (b *Builder) create(runConfig *container.Config) (string, error) {
|
||||
if !b.hasFromImage() {
|
||||
return "", errors.New("Please provide a source image with `from` prior to run")
|
||||
}
|
||||
b.runConfig.Image = b.image
|
||||
|
||||
resources := container.Resources{
|
||||
CgroupParent: b.options.CgroupParent,
|
||||
CPUShares: b.options.CPUShares,
|
||||
|
@ -551,11 +581,9 @@ func (b *Builder) create() (string, error) {
|
|||
ExtraHosts: b.options.ExtraHosts,
|
||||
}
|
||||
|
||||
config := *b.runConfig
|
||||
|
||||
// Create the container
|
||||
c, err := b.docker.ContainerCreate(types.ContainerCreateConfig{
|
||||
Config: b.runConfig,
|
||||
Config: runConfig,
|
||||
HostConfig: hostConfig,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -569,7 +597,7 @@ func (b *Builder) create() (string, error) {
|
|||
fmt.Fprintf(b.Stdout, " ---> Running in %s\n", stringid.TruncateID(c.ID))
|
||||
|
||||
// override the entry point that may have been picked up from the base image
|
||||
if err := b.docker.ContainerUpdateCmdOnBuild(c.ID, config.Cmd); err != nil {
|
||||
if err := b.docker.ContainerUpdateCmdOnBuild(c.ID, runConfig.Cmd); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/builder/remotecontext"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
|
@ -71,3 +72,54 @@ func readAndCheckDockerfile(t *testing.T, testName, contextDir, dockerfilePath,
|
|||
_, _, err = remotecontext.Detect(context.Background(), "", dockerfilePath, tarStream, nil)
|
||||
assert.EqualError(t, err, expectedError)
|
||||
}
|
||||
|
||||
func TestCopyRunConfig(t *testing.T) {
|
||||
defaultEnv := []string{"foo=1"}
|
||||
defaultCmd := []string{"old"}
|
||||
|
||||
var testcases = []struct {
|
||||
doc string
|
||||
modifiers []runConfigModifier
|
||||
expected *container.Config
|
||||
}{
|
||||
{
|
||||
doc: "Set the command",
|
||||
modifiers: []runConfigModifier{withCmd([]string{"new"})},
|
||||
expected: &container.Config{
|
||||
Cmd: []string{"new"},
|
||||
Env: defaultEnv,
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: "Set the command to a comment",
|
||||
modifiers: []runConfigModifier{withCmdComment("comment")},
|
||||
expected: &container.Config{
|
||||
Cmd: append(defaultShell, "#(nop) ", "comment"),
|
||||
Env: defaultEnv,
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: "Set the command and env",
|
||||
modifiers: []runConfigModifier{
|
||||
withCmd([]string{"new"}),
|
||||
withEnv([]string{"one", "two"}),
|
||||
},
|
||||
expected: &container.Config{
|
||||
Cmd: []string{"new"},
|
||||
Env: []string{"one", "two"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testcase := range testcases {
|
||||
runConfig := &container.Config{
|
||||
Cmd: defaultCmd,
|
||||
Env: defaultEnv,
|
||||
}
|
||||
runConfigCopy := copyRunConfig(runConfig, testcase.modifiers...)
|
||||
assert.Equal(t, testcase.expected, runConfigCopy, testcase.doc)
|
||||
// Assert the original was not modified
|
||||
assert.NotEqual(t, runConfig, runConfigCopy, testcase.doc)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue