mirror of https://github.com/docker/docs.git
Merge pull request #17428 from ripcurld00d/cli_ninja_build
Change the quiet flag behavior in the build command [closes #17623]
This commit is contained in:
commit
f4ea3b2cb1
|
|
@ -3,6 +3,7 @@ package client
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
@ -42,7 +43,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
||||||
cmd := Cli.Subcmd("build", []string{"PATH | URL | -"}, Cli.DockerCommands["build"].Description, true)
|
cmd := Cli.Subcmd("build", []string{"PATH | URL | -"}, Cli.DockerCommands["build"].Description, true)
|
||||||
flTags := opts.NewListOpts(validateTag)
|
flTags := opts.NewListOpts(validateTag)
|
||||||
cmd.Var(&flTags, []string{"t", "-tag"}, "Name and optionally a tag in the 'name:tag' format")
|
cmd.Var(&flTags, []string{"t", "-tag"}, "Name and optionally a tag in the 'name:tag' format")
|
||||||
suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers")
|
suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the build output and print image ID on success")
|
||||||
noCache := cmd.Bool([]string{"-no-cache"}, false, "Do not use cache when building the image")
|
noCache := cmd.Bool([]string{"-no-cache"}, false, "Do not use cache when building the image")
|
||||||
rm := cmd.Bool([]string{"-rm"}, true, "Remove intermediate containers after a successful build")
|
rm := cmd.Bool([]string{"-rm"}, true, "Remove intermediate containers after a successful build")
|
||||||
forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers")
|
forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers")
|
||||||
|
|
@ -87,20 +88,32 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
||||||
contextDir string
|
contextDir string
|
||||||
tempDir string
|
tempDir string
|
||||||
relDockerfile string
|
relDockerfile string
|
||||||
|
progBuff io.Writer
|
||||||
|
buildBuff io.Writer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
progBuff = cli.out
|
||||||
|
buildBuff = cli.out
|
||||||
|
if *suppressOutput {
|
||||||
|
progBuff = bytes.NewBuffer(nil)
|
||||||
|
buildBuff = bytes.NewBuffer(nil)
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case specifiedContext == "-":
|
case specifiedContext == "-":
|
||||||
tempDir, relDockerfile, err = getContextFromReader(cli.in, *dockerfileName)
|
tempDir, relDockerfile, err = getContextFromReader(cli.in, *dockerfileName)
|
||||||
case urlutil.IsGitURL(specifiedContext) && hasGit:
|
case urlutil.IsGitURL(specifiedContext) && hasGit:
|
||||||
tempDir, relDockerfile, err = getContextFromGitURL(specifiedContext, *dockerfileName)
|
tempDir, relDockerfile, err = getContextFromGitURL(specifiedContext, *dockerfileName)
|
||||||
case urlutil.IsURL(specifiedContext):
|
case urlutil.IsURL(specifiedContext):
|
||||||
tempDir, relDockerfile, err = getContextFromURL(cli.out, specifiedContext, *dockerfileName)
|
tempDir, relDockerfile, err = getContextFromURL(progBuff, specifiedContext, *dockerfileName)
|
||||||
default:
|
default:
|
||||||
contextDir, relDockerfile, err = getContextFromLocalDir(specifiedContext, *dockerfileName)
|
contextDir, relDockerfile, err = getContextFromLocalDir(specifiedContext, *dockerfileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if *suppressOutput && urlutil.IsURL(specifiedContext) {
|
||||||
|
fmt.Fprintln(cli.err, progBuff)
|
||||||
|
}
|
||||||
return fmt.Errorf("unable to prepare context: %s", err)
|
return fmt.Errorf("unable to prepare context: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,7 +182,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
||||||
context = replaceDockerfileTarWrapper(context, newDockerfile, relDockerfile)
|
context = replaceDockerfileTarWrapper(context, newDockerfile, relDockerfile)
|
||||||
|
|
||||||
// Setup an upload progress bar
|
// Setup an upload progress bar
|
||||||
progressOutput := streamformatter.NewStreamFormatter().NewProgressOutput(cli.out, true)
|
progressOutput := streamformatter.NewStreamFormatter().NewProgressOutput(progBuff, true)
|
||||||
|
|
||||||
var body io.Reader = progress.NewProgressReader(context, progressOutput, 0, "", "Sending build context to Docker daemon")
|
var body io.Reader = progress.NewProgressReader(context, progressOutput, 0, "", "Sending build context to Docker daemon")
|
||||||
|
|
||||||
|
|
@ -230,13 +243,16 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = jsonmessage.DisplayJSONMessagesStream(response.Body, cli.out, cli.outFd, cli.isTerminalOut)
|
err = jsonmessage.DisplayJSONMessagesStream(response.Body, buildBuff, cli.outFd, cli.isTerminalOut)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if jerr, ok := err.(*jsonmessage.JSONError); ok {
|
if jerr, ok := err.(*jsonmessage.JSONError); ok {
|
||||||
// If no error code is set, default to 1
|
// If no error code is set, default to 1
|
||||||
if jerr.Code == 0 {
|
if jerr.Code == 0 {
|
||||||
jerr.Code = 1
|
jerr.Code = 1
|
||||||
}
|
}
|
||||||
|
if *suppressOutput {
|
||||||
|
fmt.Fprintf(cli.err, "%s%s", progBuff, buildBuff)
|
||||||
|
}
|
||||||
return Cli.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
|
return Cli.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -246,6 +262,11 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
||||||
fmt.Fprintln(cli.err, `SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.`)
|
fmt.Fprintln(cli.err, `SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Everything worked so if -q was provided the output from the daemon
|
||||||
|
// should be just the image ID and we'll print that to stdout.
|
||||||
|
if *suppressOutput {
|
||||||
|
fmt.Fprintf(cli.out, "%s", buildBuff)
|
||||||
|
}
|
||||||
// Since the build was successful, now we must tag any of the resolved
|
// Since the build was successful, now we must tag any of the resolved
|
||||||
// images from the above Dockerfile rewrite.
|
// images from the above Dockerfile rewrite.
|
||||||
for _, resolved := range resolvedTags {
|
for _, resolved := range resolvedTags {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
@ -72,6 +73,7 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
|
||||||
authConfigs = map[string]types.AuthConfig{}
|
authConfigs = map[string]types.AuthConfig{}
|
||||||
authConfigsEncoded = r.Header.Get("X-Registry-Config")
|
authConfigsEncoded = r.Header.Get("X-Registry-Config")
|
||||||
buildConfig = &dockerfile.Config{}
|
buildConfig = &dockerfile.Config{}
|
||||||
|
notVerboseBuffer = bytes.NewBuffer(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
if authConfigsEncoded != "" {
|
if authConfigsEncoded != "" {
|
||||||
|
|
@ -90,6 +92,9 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
|
||||||
defer output.Close()
|
defer output.Close()
|
||||||
sf := streamformatter.NewJSONStreamFormatter()
|
sf := streamformatter.NewJSONStreamFormatter()
|
||||||
errf := func(err error) error {
|
errf := func(err error) error {
|
||||||
|
if !buildConfig.Verbose && notVerboseBuffer.Len() > 0 {
|
||||||
|
output.Write(notVerboseBuffer.Bytes())
|
||||||
|
}
|
||||||
// Do not write the error in the http output if it's still empty.
|
// Do not write the error in the http output if it's still empty.
|
||||||
// This prevents from writing a 200(OK) when there is an internal error.
|
// This prevents from writing a 200(OK) when there is an internal error.
|
||||||
if !output.Flushed() {
|
if !output.Flushed() {
|
||||||
|
|
@ -170,6 +175,9 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
|
||||||
// Look at code in DetectContextFromRemoteURL for more information.
|
// Look at code in DetectContextFromRemoteURL for more information.
|
||||||
createProgressReader := func(in io.ReadCloser) io.ReadCloser {
|
createProgressReader := func(in io.ReadCloser) io.ReadCloser {
|
||||||
progressOutput := sf.NewProgressOutput(output, true)
|
progressOutput := sf.NewProgressOutput(output, true)
|
||||||
|
if !buildConfig.Verbose {
|
||||||
|
progressOutput = sf.NewProgressOutput(notVerboseBuffer, true)
|
||||||
|
}
|
||||||
return progress.NewProgressReader(in, progressOutput, r.ContentLength, "Downloading context", remoteURL)
|
return progress.NewProgressReader(in, progressOutput, r.ContentLength, "Downloading context", remoteURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,6 +207,9 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
|
||||||
AuthConfigs: authConfigs,
|
AuthConfigs: authConfigs,
|
||||||
Archiver: defaultArchiver,
|
Archiver: defaultArchiver,
|
||||||
}
|
}
|
||||||
|
if !buildConfig.Verbose {
|
||||||
|
docker.OutOld = notVerboseBuffer
|
||||||
|
}
|
||||||
|
|
||||||
b, err := dockerfile.NewBuilder(buildConfig, docker, builder.DockerIgnoreContext{ModifiableContext: context}, nil)
|
b, err := dockerfile.NewBuilder(buildConfig, docker, builder.DockerIgnoreContext{ModifiableContext: context}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -206,6 +217,10 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
|
||||||
}
|
}
|
||||||
b.Stdout = &streamformatter.StdoutFormatter{Writer: output, StreamFormatter: sf}
|
b.Stdout = &streamformatter.StdoutFormatter{Writer: output, StreamFormatter: sf}
|
||||||
b.Stderr = &streamformatter.StderrFormatter{Writer: output, StreamFormatter: sf}
|
b.Stderr = &streamformatter.StderrFormatter{Writer: output, StreamFormatter: sf}
|
||||||
|
if !buildConfig.Verbose {
|
||||||
|
b.Stdout = &streamformatter.StdoutFormatter{Writer: notVerboseBuffer, StreamFormatter: sf}
|
||||||
|
b.Stderr = &streamformatter.StderrFormatter{Writer: notVerboseBuffer, StreamFormatter: sf}
|
||||||
|
}
|
||||||
|
|
||||||
if closeNotifier, ok := w.(http.CloseNotifier); ok {
|
if closeNotifier, ok := w.(http.CloseNotifier); ok {
|
||||||
finished := make(chan struct{})
|
finished := make(chan struct{})
|
||||||
|
|
@ -235,5 +250,12 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Everything worked so if -q was provided the output from the daemon
|
||||||
|
// should be just the image ID and we'll print that to stdout.
|
||||||
|
if !buildConfig.Verbose {
|
||||||
|
stdout := &streamformatter.StdoutFormatter{Writer: output, StreamFormatter: sf}
|
||||||
|
fmt.Fprintf(stdout, "%s\n", string(imgID))
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -524,11 +524,9 @@ func (b *Builder) create() (string, error) {
|
||||||
|
|
||||||
func (b *Builder) run(cID string) (err error) {
|
func (b *Builder) run(cID string) (err error) {
|
||||||
errCh := make(chan error)
|
errCh := make(chan error)
|
||||||
if b.Verbose {
|
go func() {
|
||||||
go func() {
|
errCh <- b.docker.ContainerAttach(cID, nil, b.Stdout, b.Stderr, true)
|
||||||
errCh <- b.docker.ContainerAttach(cID, nil, b.Stdout, b.Stderr, true)
|
}()
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
finished := make(chan struct{})
|
finished := make(chan struct{})
|
||||||
defer close(finished)
|
defer close(finished)
|
||||||
|
|
@ -546,11 +544,9 @@ func (b *Builder) run(cID string) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.Verbose {
|
// Block on reading output from container, stop on err or chan closed
|
||||||
// Block on reading output from container, stop on err or chan closed
|
if err := <-errCh; err != nil {
|
||||||
if err := <-errCh; err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ret, _ := b.docker.ContainerWait(cID, -1); ret != 0 {
|
if ret, _ := b.docker.ContainerWait(cID, -1); ret != 0 {
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l force-rm -d '
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l help -d 'Print usage'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l help -d 'Print usage'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l no-cache -d 'Do not use cache when building the image'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l no-cache -d 'Do not use cache when building the image'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l pull -d 'Always attempt to pull a newer version of the image'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l pull -d 'Always attempt to pull a newer version of the image'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s q -l quiet -d 'Suppress the verbose output generated by the containers'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s q -l quiet -d 'Suppress the build output and print image ID on success'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l rm -d 'Remove intermediate containers after a successful build'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l rm -d 'Remove intermediate containers after a successful build'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s t -l tag -d 'Repository name (and optionally a tag) to be applied to the resulting image in case of success'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s t -l tag -d 'Repository name (and optionally a tag) to be applied to the resulting image in case of success'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ parent = "smn_cli"
|
||||||
--memory-swap="" Total memory (memory + swap), `-1` to disable swap
|
--memory-swap="" Total memory (memory + swap), `-1` to disable swap
|
||||||
--no-cache=false Do not use cache when building the image
|
--no-cache=false Do not use cache when building the image
|
||||||
--pull=false Always attempt to pull a newer version of the image
|
--pull=false Always attempt to pull a newer version of the image
|
||||||
-q, --quiet=false Suppress the verbose output generated by the containers
|
-q, --quiet=false Suppress the build output and print image ID on success
|
||||||
--rm=true Remove intermediate containers after a successful build
|
--rm=true Remove intermediate containers after a successful build
|
||||||
--shm-size=[] Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`.
|
--shm-size=[] Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`.
|
||||||
-t, --tag=[] Name and optionally a tag in the 'name:tag' format
|
-t, --tag=[] Name and optionally a tag in the 'name:tag' format
|
||||||
|
|
|
||||||
|
|
@ -4941,6 +4941,110 @@ func (s *DockerSuite) TestBuildLabelsCache(c *check.C) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestBuildNotVerboseSuccess(c *check.C) {
|
||||||
|
testRequires(c, DaemonIsLinux)
|
||||||
|
// This test makes sure that -q works correctly when build is successful:
|
||||||
|
// stdout has only the image ID (long image ID) and stderr is empty.
|
||||||
|
var stdout, stderr string
|
||||||
|
var err error
|
||||||
|
outRegexp := regexp.MustCompile("^(sha256:|)[a-z0-9]{64}\\n$")
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
Name string
|
||||||
|
BuildFunc func(string)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "quiet_build_stdin_success",
|
||||||
|
BuildFunc: func(name string) {
|
||||||
|
_, stdout, stderr, err = buildImageWithStdoutStderr(name, "FROM busybox", true, "-q", "--force-rm", "--rm")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "quiet_build_ctx_success",
|
||||||
|
BuildFunc: func(name string) {
|
||||||
|
ctx, err := fakeContext("FROM busybox", map[string]string{
|
||||||
|
"quiet_build_success_fctx": "test",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Failed to create context: %s", err.Error())
|
||||||
|
}
|
||||||
|
defer ctx.Close()
|
||||||
|
_, stdout, stderr, err = buildImageFromContextWithStdoutStderr(name, ctx, true, "-q", "--force-rm", "--rm")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "quiet_build_git_success",
|
||||||
|
BuildFunc: func(name string) {
|
||||||
|
git, err := newFakeGit("repo", map[string]string{
|
||||||
|
"Dockerfile": "FROM busybox",
|
||||||
|
}, true)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Failed to create the git repo: %s", err.Error())
|
||||||
|
}
|
||||||
|
defer git.Close()
|
||||||
|
_, stdout, stderr, err = buildImageFromGitWithStdoutStderr(name, git, true, "-q", "--force-rm", "--rm")
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, te := range tt {
|
||||||
|
te.BuildFunc(te.Name)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Test %s shouldn't fail, but got the following error: %s", te.Name, err.Error())
|
||||||
|
}
|
||||||
|
if outRegexp.Find([]byte(stdout)) == nil {
|
||||||
|
c.Fatalf("Test %s expected stdout to match the [%v] regexp, but it is [%v]", te.Name, outRegexp, stdout)
|
||||||
|
}
|
||||||
|
if stderr != "" {
|
||||||
|
c.Fatalf("Test %s expected stderr to be empty, but it is [%#v]", te.Name, stderr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestBuildNotVerboseFailure(c *check.C) {
|
||||||
|
testRequires(c, DaemonIsLinux)
|
||||||
|
// This test makes sure that -q works correctly when build fails by
|
||||||
|
// comparing between the stderr output in quiet mode and in stdout
|
||||||
|
// and stderr output in verbose mode
|
||||||
|
tt := []struct {
|
||||||
|
TestName string
|
||||||
|
BuildCmds string
|
||||||
|
}{
|
||||||
|
{"quiet_build_no_from_at_the_beginning", "RUN whoami"},
|
||||||
|
{"quiet_build_unknown_instr", "FROMD busybox"},
|
||||||
|
{"quiet_build_not_exists_image", "FROM busybox11"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, te := range tt {
|
||||||
|
_, _, qstderr, qerr := buildImageWithStdoutStderr(te.TestName, te.BuildCmds, false, "-q", "--force-rm", "--rm")
|
||||||
|
_, vstdout, vstderr, verr := buildImageWithStdoutStderr(te.TestName, te.BuildCmds, false, "--force-rm", "--rm")
|
||||||
|
if verr == nil || qerr == nil {
|
||||||
|
c.Fatal(fmt.Errorf("Test [%s] expected to fail but didn't", te.TestName))
|
||||||
|
}
|
||||||
|
if qstderr != vstdout+vstderr {
|
||||||
|
c.Fatal(fmt.Errorf("Test[%s] expected that quiet stderr and verbose stdout are equal; quiet [%v], verbose [%v]", te.TestName, qstderr, vstdout))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestBuildNotVerboseFailureRemote(c *check.C) {
|
||||||
|
testRequires(c, DaemonIsLinux)
|
||||||
|
// This test ensures that when given a wrong URL, stderr in quiet mode and
|
||||||
|
// stdout and stderr in verbose mode are identical.
|
||||||
|
URL := "http://bla.bla.com"
|
||||||
|
Name := "quiet_build_wrong_remote"
|
||||||
|
_, _, qstderr, qerr := buildImageWithStdoutStderr(Name, "", false, "-q", "--force-rm", "--rm", URL)
|
||||||
|
_, vstdout, vstderr, verr := buildImageWithStdoutStderr(Name, "", false, "--force-rm", "--rm", URL)
|
||||||
|
if qerr == nil || verr == nil {
|
||||||
|
c.Fatal(fmt.Errorf("Test [%s] expected to fail but didn't", Name))
|
||||||
|
}
|
||||||
|
if qstderr != vstdout+vstderr {
|
||||||
|
c.Fatal(fmt.Errorf("Test[%s] expected that quiet stderr and verbose stdout are equal; quiet [%v], verbose [%v]", Name, qstderr, vstdout))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DockerSuite) TestBuildStderr(c *check.C) {
|
func (s *DockerSuite) TestBuildStderr(c *check.C) {
|
||||||
testRequires(c, DaemonIsLinux)
|
testRequires(c, DaemonIsLinux)
|
||||||
// This test just makes sure that no non-error output goes
|
// This test just makes sure that no non-error output goes
|
||||||
|
|
@ -5589,34 +5693,6 @@ func (s *DockerSuite) TestBuildDotDotFile(c *check.C) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DockerSuite) TestBuildNotVerbose(c *check.C) {
|
|
||||||
testRequires(c, DaemonIsLinux)
|
|
||||||
ctx, err := fakeContext("FROM busybox\nENV abc=hi\nRUN echo $abc there", map[string]string{})
|
|
||||||
if err != nil {
|
|
||||||
c.Fatal(err)
|
|
||||||
}
|
|
||||||
defer ctx.Close()
|
|
||||||
|
|
||||||
// First do it w/verbose - baseline
|
|
||||||
out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "--no-cache", "-t", "verbose", ".")
|
|
||||||
if err != nil {
|
|
||||||
c.Fatalf("failed to build the image w/o -q: %s, %v", out, err)
|
|
||||||
}
|
|
||||||
if !strings.Contains(out, "hi there") {
|
|
||||||
c.Fatalf("missing output:%s\n", out)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now do it w/o verbose
|
|
||||||
out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "--no-cache", "-q", "-t", "verbose", ".")
|
|
||||||
if err != nil {
|
|
||||||
c.Fatalf("failed to build the image w/ -q: %s, %v", out, err)
|
|
||||||
}
|
|
||||||
if strings.Contains(out, "hi there") {
|
|
||||||
c.Fatalf("Bad output, should not contain 'hi there':%s", out)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DockerSuite) TestBuildRUNoneJSON(c *check.C) {
|
func (s *DockerSuite) TestBuildRUNoneJSON(c *check.C) {
|
||||||
testRequires(c, DaemonIsLinux)
|
testRequires(c, DaemonIsLinux)
|
||||||
name := "testbuildrunonejson"
|
name := "testbuildrunonejson"
|
||||||
|
|
|
||||||
|
|
@ -1308,6 +1308,47 @@ func buildImageFromContextWithOut(name string, ctx *FakeContext, useCache bool,
|
||||||
return id, out, nil
|
return id, out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildImageFromContextWithStdoutStderr(name string, ctx *FakeContext, useCache bool, buildFlags ...string) (string, string, string, error) {
|
||||||
|
args := []string{"build", "-t", name}
|
||||||
|
if !useCache {
|
||||||
|
args = append(args, "--no-cache")
|
||||||
|
}
|
||||||
|
args = append(args, buildFlags...)
|
||||||
|
args = append(args, ".")
|
||||||
|
buildCmd := exec.Command(dockerBinary, args...)
|
||||||
|
buildCmd.Dir = ctx.Dir
|
||||||
|
|
||||||
|
stdout, stderr, exitCode, err := runCommandWithStdoutStderr(buildCmd)
|
||||||
|
if err != nil || exitCode != 0 {
|
||||||
|
return "", stdout, stderr, fmt.Errorf("failed to build the image: %s", stdout)
|
||||||
|
}
|
||||||
|
id, err := getIDByName(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", stdout, stderr, err
|
||||||
|
}
|
||||||
|
return id, stdout, stderr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildImageFromGitWithStdoutStderr(name string, ctx *fakeGit, useCache bool, buildFlags ...string) (string, string, string, error) {
|
||||||
|
args := []string{"build", "-t", name}
|
||||||
|
if !useCache {
|
||||||
|
args = append(args, "--no-cache")
|
||||||
|
}
|
||||||
|
args = append(args, buildFlags...)
|
||||||
|
args = append(args, ctx.RepoURL)
|
||||||
|
buildCmd := exec.Command(dockerBinary, args...)
|
||||||
|
|
||||||
|
stdout, stderr, exitCode, err := runCommandWithStdoutStderr(buildCmd)
|
||||||
|
if err != nil || exitCode != 0 {
|
||||||
|
return "", stdout, stderr, fmt.Errorf("failed to build the image: %s", stdout)
|
||||||
|
}
|
||||||
|
id, err := getIDByName(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", stdout, stderr, err
|
||||||
|
}
|
||||||
|
return id, stdout, stderr, nil
|
||||||
|
}
|
||||||
|
|
||||||
func buildImageFromPath(name, path string, useCache bool, buildFlags ...string) (string, error) {
|
func buildImageFromPath(name, path string, useCache bool, buildFlags ...string) (string, error) {
|
||||||
args := []string{"build", "-t", name}
|
args := []string{"build", "-t", name}
|
||||||
if !useCache {
|
if !useCache {
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ set as the **URL**, the repository is cloned locally and then sent as the contex
|
||||||
Always attempt to pull a newer version of the image. The default is *false*.
|
Always attempt to pull a newer version of the image. The default is *false*.
|
||||||
|
|
||||||
**-q**, **--quiet**=*true*|*false*
|
**-q**, **--quiet**=*true*|*false*
|
||||||
Suppress the verbose output generated by the containers. The default is *false*.
|
Suppress the build output and print image ID on success. The default is *false*.
|
||||||
|
|
||||||
**--rm**=*true*|*false*
|
**--rm**=*true*|*false*
|
||||||
Remove intermediate containers after a successful build. The default is *true*.
|
Remove intermediate containers after a successful build. The default is *true*.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue