Change the quiet flag behavior in the build command

Right now, the quiet (-q, --quiet) flag ignores the output
generated from within the container.

However, it ought to be quiet in a way that all kind
of diagnostic output should be ignored, unless the build
process fails.

This patch makes the quiet flag behave in the following way:
 1. If the build process succeeds, stdout contains the image ID
    and stderr is empty.
 2. If the build process fails, stdout is empty and stderr
    has the error message and the diagnostic output of that process.

If the quiet flag is not set, then everything goes to stdout
and error messages, if there are any, go to stderr.

Signed-off-by: Boaz Shuster <ripcurld.github@gmail.com>
Upstream-commit: 60b4db7eb17f4eb509be4a4968364ada2075d60c
Component: engine
This commit is contained in:
Boaz Shuster
2015-12-21 16:38:50 +02:00
committed by ripcurld00d
parent fc63a9d65d
commit 1c5df6581b
8 changed files with 201 additions and 45 deletions
@@ -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) {
testRequires(c, DaemonIsLinux)
// 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) {
testRequires(c, DaemonIsLinux)
name := "testbuildrunonejson"
@@ -1308,6 +1308,47 @@ func buildImageFromContextWithOut(name string, ctx *FakeContext, useCache bool,
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) {
args := []string{"build", "-t", name}
if !useCache {