diff --git a/cmd/nerdctl/image/image_pull.go b/cmd/nerdctl/image/image_pull.go index 9b1f961d8e1..cedef1af639 100644 --- a/cmd/nerdctl/image/image_pull.go +++ b/cmd/nerdctl/image/image_pull.go @@ -129,8 +129,9 @@ func processPullCommandFlags(cmd *cobra.Command) (types.ImagePullOptions, error) RFlags: types.RemoteSnapshotterFlags{ SociIndexDigest: sociIndexDigest, }, - Stdout: cmd.OutOrStdout(), - Stderr: cmd.OutOrStderr(), + Stdout: cmd.OutOrStdout(), + Stderr: cmd.OutOrStderr(), + ProgressOutputToStdout: true, }, nil } diff --git a/cmd/nerdctl/image/image_pull_linux_test.go b/cmd/nerdctl/image/image_pull_linux_test.go index 28aa8b0cb9f..c350d1e71a4 100644 --- a/cmd/nerdctl/image/image_pull_linux_test.go +++ b/cmd/nerdctl/image/image_pull_linux_test.go @@ -236,3 +236,36 @@ func TestImagePullSoci(t *testing.T) { testCase.Run(t) } + +func TestImagePullProcessOutput(t *testing.T) { + nerdtest.Setup() + + testCase := &test.Case{ + SubTests: []*test.Case{ + { + Description: "Pull Image - output should be in stdout", + NoParallel: true, + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rmi", "-f", testutil.BusyboxImage) + }, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("pull", testutil.BusyboxImage) + }, + Expected: test.Expects(0, nil, test.Contains(testutil.BusyboxImage)), + }, + { + Description: "Run Container with image pull - output should be in stderr", + NoParallel: true, + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rmi", "-f", testutil.BusyboxImage) + }, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("run", "--rm", testutil.BusyboxImage) + }, + Expected: test.Expects(0, nil, test.DoesNotContain(testutil.BusyboxImage)), + }, + }, + } + + testCase.Run(t) +} diff --git a/pkg/api/types/image_types.go b/pkg/api/types/image_types.go index 30e0d65c31c..0a723ca2cd2 100644 --- a/pkg/api/types/image_types.go +++ b/pkg/api/types/image_types.go @@ -189,8 +189,11 @@ type RemoteSnapshotterFlags struct { // ImagePullOptions specifies options for `nerdctl (image) pull`. type ImagePullOptions struct { - Stdout io.Writer - Stderr io.Writer + Stdout io.Writer + Stderr io.Writer + // ProgressOutputToStdout directs progress output to stdout instead of stderr + ProgressOutputToStdout bool + GOptions GlobalCommandOptions VerifyOptions ImageVerifyOptions // Unpack the image for the current single platform. diff --git a/pkg/imgutil/imgutil.go b/pkg/imgutil/imgutil.go index 09ca283b5dc..3f8076df9f4 100644 --- a/pkg/imgutil/imgutil.go +++ b/pkg/imgutil/imgutil.go @@ -207,6 +207,9 @@ func PullImage(ctx context.Context, client *containerd.Client, resolver remotes. } if !options.Quiet { config.ProgressOutput = options.Stderr + if options.ProgressOutputToStdout { + config.ProgressOutput = options.Stdout + } } // unpack(B) if given 1 platform unless specified by `unpack`