From dd3407b6cc0054a73ef4910dd1b468620eeff400 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Wed, 19 Dec 2018 13:48:41 +0100 Subject: [PATCH] Add option to pull images quietly Add `--quiet` to the `docker image pull` subcommand that will not pull the image quietly. ``` $ docker pull -q golang Using default tag: latest ``` Signed-off-by: Vincent Demeester --- cli/command/image/pull.go | 9 +++++--- cli/command/image/pull_test.go | 9 ++++++++ .../pull-command-success.simple-no-tag.golden | 1 + .../pull-command-success.simple-quiet.golden | 2 ++ .../pull-command-success.simple.golden | 1 + cli/command/image/trust.go | 22 ++++++++++++++----- docs/reference/commandline/pull.md | 1 + e2e/image/pull_test.go | 9 ++++++++ .../testdata/pull-with-content-trust.golden | 1 + 9 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 cli/command/image/testdata/pull-command-success.simple-quiet.golden diff --git a/cli/command/image/pull.go b/cli/command/image/pull.go index 9ac382c39535..cf15fca70607 100644 --- a/cli/command/image/pull.go +++ b/cli/command/image/pull.go @@ -18,6 +18,7 @@ type PullOptions struct { remote string all bool platform string + quiet bool untrusted bool } @@ -38,6 +39,7 @@ func NewPullCommand(dockerCli command.Cli) *cobra.Command { flags := cmd.Flags() flags.BoolVarP(&opts.all, "all-tags", "a", false, "Download all tagged images in the repository") + flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress verbose output") command.AddPlatformFlag(flags, &opts.platform) command.AddTrustVerificationFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled()) @@ -55,7 +57,7 @@ func RunPull(cli command.Cli, opts PullOptions) error { return errors.New("tag can't be used with --all-tags/-a") case !opts.all && reference.IsNameOnly(distributionRef): distributionRef = reference.TagNameOnly(distributionRef) - if tagged, ok := distributionRef.(reference.Tagged); ok { + if tagged, ok := distributionRef.(reference.Tagged); ok && !opts.quiet { fmt.Fprintf(cli.Out(), "Using default tag: %s\n", tagged.Tag()) } } @@ -69,9 +71,9 @@ func RunPull(cli command.Cli, opts PullOptions) error { // Check if reference has a digest _, isCanonical := distributionRef.(reference.Canonical) if !opts.untrusted && !isCanonical { - err = trustedPull(ctx, cli, imgRefAndAuth, opts.platform) + err = trustedPull(ctx, cli, imgRefAndAuth, opts) } else { - err = imagePullPrivileged(ctx, cli, imgRefAndAuth, opts.all, opts.platform) + err = imagePullPrivileged(ctx, cli, imgRefAndAuth, opts) } if err != nil { if strings.Contains(err.Error(), "when fetching 'plugin'") { @@ -79,5 +81,6 @@ func RunPull(cli command.Cli, opts PullOptions) error { } return err } + fmt.Fprintln(cli.Out(), imgRefAndAuth.Reference().String()) return nil } diff --git a/cli/command/image/pull_test.go b/cli/command/image/pull_test.go index c5ae75608a51..4cb1ca10c419 100644 --- a/cli/command/image/pull_test.go +++ b/cli/command/image/pull_test.go @@ -50,6 +50,7 @@ func TestNewPullCommandSuccess(t *testing.T) { testCases := []struct { name string args []string + flags map[string]string expectedTag string }{ { @@ -62,6 +63,14 @@ func TestNewPullCommandSuccess(t *testing.T) { args: []string{"image"}, expectedTag: "image:latest", }, + { + name: "simple-quiet", + args: []string{"image"}, + flags: map[string]string{ + "quiet": "true", + }, + expectedTag: "image:latest", + }, } for _, tc := range testCases { cli := test.NewFakeCli(&fakeClient{ diff --git a/cli/command/image/testdata/pull-command-success.simple-no-tag.golden b/cli/command/image/testdata/pull-command-success.simple-no-tag.golden index 946de409a466..d8b73fcc6286 100644 --- a/cli/command/image/testdata/pull-command-success.simple-no-tag.golden +++ b/cli/command/image/testdata/pull-command-success.simple-no-tag.golden @@ -1 +1,2 @@ Using default tag: latest +docker.io/library/image:latest diff --git a/cli/command/image/testdata/pull-command-success.simple-quiet.golden b/cli/command/image/testdata/pull-command-success.simple-quiet.golden new file mode 100644 index 000000000000..d8b73fcc6286 --- /dev/null +++ b/cli/command/image/testdata/pull-command-success.simple-quiet.golden @@ -0,0 +1,2 @@ +Using default tag: latest +docker.io/library/image:latest diff --git a/cli/command/image/testdata/pull-command-success.simple.golden b/cli/command/image/testdata/pull-command-success.simple.golden index e69de29bb2d1..42b61f09344d 100644 --- a/cli/command/image/testdata/pull-command-success.simple.golden +++ b/cli/command/image/testdata/pull-command-success.simple.golden @@ -0,0 +1 @@ +docker.io/library/image:tag diff --git a/cli/command/image/trust.go b/cli/command/image/trust.go index 230420d8627c..3278fa815c85 100644 --- a/cli/command/image/trust.go +++ b/cli/command/image/trust.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io" + "io/ioutil" "sort" "github.com/docker/cli/cli/command" @@ -180,7 +181,7 @@ func imagePushPrivileged(ctx context.Context, cli command.Cli, authConfig types. } // trustedPull handles content trust pulling of an image -func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, platform string) error { +func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, opts PullOptions) error { refs, err := getTrustedPullTargets(cli, imgRefAndAuth) if err != nil { return err @@ -202,7 +203,12 @@ func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.Image if err != nil { return err } - if err := imagePullPrivileged(ctx, cli, updatedImgRefAndAuth, false, platform); err != nil { + if err := imagePullPrivileged(ctx, cli, updatedImgRefAndAuth, PullOptions{ + all: false, + platform: opts.platform, + quiet: opts.quiet, + remote: opts.remote, + }); err != nil { return err } @@ -268,7 +274,7 @@ func getTrustedPullTargets(cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth) } // imagePullPrivileged pulls the image and displays it to the output -func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, all bool, platform string) error { +func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, opts PullOptions) error { ref := reference.FamiliarString(imgRefAndAuth.Reference()) encodedAuth, err := command.EncodeAuthToBase64(*imgRefAndAuth.AuthConfig()) @@ -279,8 +285,8 @@ func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth tru options := types.ImagePullOptions{ RegistryAuth: encodedAuth, PrivilegeFunc: requestPrivilege, - All: all, - Platform: platform, + All: opts.all, + Platform: opts.platform, } responseBody, err := cli.Client().ImagePull(ctx, ref, options) if err != nil { @@ -288,7 +294,11 @@ func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth tru } defer responseBody.Close() - return jsonmessage.DisplayJSONMessagesToStream(responseBody, cli.Out(), nil) + out := cli.Out() + if opts.quiet { + out = command.NewOutStream(ioutil.Discard) + } + return jsonmessage.DisplayJSONMessagesToStream(responseBody, out, nil) } // TrustedReference returns the canonical trusted reference for an image reference diff --git a/docs/reference/commandline/pull.md b/docs/reference/commandline/pull.md index 6487b2e09c27..0e49d904588f 100644 --- a/docs/reference/commandline/pull.md +++ b/docs/reference/commandline/pull.md @@ -24,6 +24,7 @@ Options: -a, --all-tags Download all tagged images in the repository --disable-content-trust Skip image verification (default true) --help Print usage + -q, --quiet Suppress verbose output ``` ## Description diff --git a/e2e/image/pull_test.go b/e2e/image/pull_test.go index 625ccd5993ce..2d06a51c1848 100644 --- a/e2e/image/pull_test.go +++ b/e2e/image/pull_test.go @@ -5,6 +5,8 @@ import ( "github.com/docker/cli/e2e/internal/fixtures" "github.com/docker/cli/internal/test/environment" + "gotest.tools/assert" + is "gotest.tools/assert/cmp" "gotest.tools/golden" "gotest.tools/icmd" "gotest.tools/skip" @@ -32,6 +34,13 @@ func TestPullWithContentTrust(t *testing.T) { golden.Assert(t, result.Stdout(), "pull-with-content-trust.golden") } +func TestPullQuiet(t *testing.T) { + result := icmd.RunCommand("docker", "pull", "--quiet", fixtures.AlpineImage) + result.Assert(t, icmd.Success) + assert.Check(t, is.Equal(result.Stdout(), "registry:5000/alpine:3.6\n")) + assert.Check(t, is.Equal(result.Stderr(), "")) +} + func TestPullWithContentTrustUsesCacheWhenNotaryUnavailable(t *testing.T) { skip.If(t, environment.RemoteDaemon()) diff --git a/e2e/image/testdata/pull-with-content-trust.golden b/e2e/image/testdata/pull-with-content-trust.golden index ea30b56d2673..9cb9a92a1714 100644 --- a/e2e/image/testdata/pull-with-content-trust.golden +++ b/e2e/image/testdata/pull-with-content-trust.golden @@ -2,3 +2,4 @@ Pull (1 of 1): registry:5000/trust-pull:latest@sha256:641b95ddb2ea9dc2af1a0113b6 sha256:641b95ddb2ea9dc2af1a0113b6b348ebc20872ba615204fbe12148e98fd6f23d: Pulling from trust-pull Digest: sha256:641b95ddb2ea9dc2af1a0113b6b348ebc20872ba615204fbe12148e98fd6f23d Status: Downloaded newer image for registry:5000/trust-pull@sha256:641b95ddb2ea9dc2af1a0113b6b348ebc20872ba615204fbe12148e98fd6f23d +registry:5000/trust-pull:latest