diff --git a/README.md b/README.md index 8cbdd6a1801..fcf9836d44a 100644 --- a/README.md +++ b/README.md @@ -715,8 +715,9 @@ Flags: - :nerd_face: Unlike Docker, this flag can be specified multiple times (`--platform=amd64 --platform=arm64`) - :nerd_face: `--all-platforms`: Pull content for all platforms - :nerd_face: `--unpack`: Unpack the image for the current single platform (auto/true/false) +- :whale: `-q, --quiet`: Suppress verbose output -Unimplemented `docker pull` flags: `--all-tags`, `--disable-content-trust` (default true), `--quiet` +Unimplemented `docker pull` flags: `--all-tags`, `--disable-content-trust` (default true) ### :whale: nerdctl push Push an image to a registry. @@ -1081,8 +1082,9 @@ Flags: - :whale: `--no-log-prefix`: Don't print prefix in logs - :whale: `--build`: Build images before starting containers. - :nerd_face: `--ipfs`: Build images with pulling base images from IPFS. See [`./docs/ipfs.md`](./docs/ipfs.md) for details. +- :whale: `--quiet-pull`: Pull without printing progress information -Unimplemented `docker-compose up` (V1) flags: `--quiet-pull`, `--no-deps`, `--force-recreate`, `--always-recreate-deps`, `--no-recreate`, +Unimplemented `docker-compose up` (V1) flags: `--no-deps`, `--force-recreate`, `--always-recreate-deps`, `--no-recreate`, `--no-start`, `--abort-on-container-exit`, `--attach-dependencies`, `--timeout`, `--renew-anon-volumes`, `--remove-orphans`, `--exit-code-from`, `--scale` @@ -1138,7 +1140,10 @@ Pull service images Usage: `nerdctl compose pull` -Unimplemented `docker-compose pull` (V1) flags: `--ignore-pull-failures`, `--parallel`, `--no-parallel`, `quiet`, `include-deps` +Flags: +- :whale: `-q, --quiet`: Pull without printing progress information + +Unimplemented `docker-compose pull` (V1) flags: `--ignore-pull-failures`, `--parallel`, `--no-parallel`, `include-deps` ### :whale: nerdctl compose push Push service images diff --git a/cmd/nerdctl/compose.go b/cmd/nerdctl/compose.go index 584d47363a9..f7517b3ab87 100644 --- a/cmd/nerdctl/compose.go +++ b/cmd/nerdctl/compose.go @@ -166,7 +166,7 @@ func getComposer(cmd *cobra.Command, client *containerd.Client) (*composer.Compo return true, nil } - o.EnsureImage = func(ctx context.Context, imageName, pullMode, platform string) error { + o.EnsureImage = func(ctx context.Context, imageName, pullMode, platform string, quiet bool) error { ocispecPlatforms := []ocispec.Platform{platforms.DefaultSpec()} if platform != "" { parsed, err := platforms.Parse(platform) @@ -182,10 +182,10 @@ func getComposer(cmd *cobra.Command, client *containerd.Client) (*composer.Compo return err } _, imgErr = ipfs.EnsureImage(ctx, client, ipfsClient, cmd.OutOrStdout(), cmd.ErrOrStderr(), snapshotter, scheme, ref, - pullMode, ocispecPlatforms, nil) + pullMode, ocispecPlatforms, nil, quiet) } else { _, imgErr = imgutil.EnsureImage(ctx, client, cmd.OutOrStdout(), cmd.ErrOrStderr(), snapshotter, imageName, - pullMode, insecure, ocispecPlatforms, nil) + pullMode, insecure, ocispecPlatforms, nil, quiet) } return imgErr } diff --git a/cmd/nerdctl/compose_pull.go b/cmd/nerdctl/compose_pull.go index 904a0477f2c..a643204c6c6 100644 --- a/cmd/nerdctl/compose_pull.go +++ b/cmd/nerdctl/compose_pull.go @@ -31,6 +31,7 @@ func newComposePullCommand() *cobra.Command { SilenceUsage: true, SilenceErrors: true, } + composePullCommand.Flags().BoolP("quiet", "q", false, "Pull without printing progress information") return composePullCommand } @@ -50,6 +51,12 @@ func composePullAction(cmd *cobra.Command, args []string) error { if err != nil { return err } - po := composer.PullOptions{} + quiet, err := cmd.Flags().GetBool("quiet") + if err != nil { + return err + } + po := composer.PullOptions{ + Quiet: quiet, + } return c.Pull(ctx, po) } diff --git a/cmd/nerdctl/compose_up.go b/cmd/nerdctl/compose_up.go index 88594cdd40f..7c1ad0ead9e 100644 --- a/cmd/nerdctl/compose_up.go +++ b/cmd/nerdctl/compose_up.go @@ -37,6 +37,7 @@ func newComposeUpCommand() *cobra.Command { composeUpCommand.Flags().Bool("no-log-prefix", false, "Don't print prefix in logs") composeUpCommand.Flags().Bool("build", false, "Build images before starting containers.") composeUpCommand.Flags().Bool("ipfs", false, "Allow pulling base images from IPFS during build") + composeUpCommand.Flags().Bool("quiet-pull", false, "Pull without printing progress information") return composeUpCommand } @@ -68,6 +69,10 @@ func composeUpAction(cmd *cobra.Command, services []string) error { if err != nil { return err } + quietPull, err := cmd.Flags().GetBool("quiet-pull") + if err != nil { + return err + } client, ctx, cancel, err := newClient(cmd) if err != nil { @@ -86,6 +91,7 @@ func composeUpAction(cmd *cobra.Command, services []string) error { NoLogPrefix: noLogPrefix, ForceBuild: build, IPFS: enableIPFS, + QuietPull: quietPull, } return c.Up(ctx, uo, services) } diff --git a/cmd/nerdctl/pull.go b/cmd/nerdctl/pull.go index f7d2579d446..f2c787232f0 100644 --- a/cmd/nerdctl/pull.go +++ b/cmd/nerdctl/pull.go @@ -48,6 +48,7 @@ func newPullCommand() *cobra.Command { pullCommand.RegisterFlagCompletionFunc("platform", shellCompletePlatforms) pullCommand.Flags().Bool("all-platforms", false, "Pull content for all platforms") // #endregion + pullCommand.Flags().BoolP("quiet", "q", false, "Suppress verbose output") return pullCommand } @@ -90,6 +91,10 @@ func pullAction(cmd *cobra.Command, args []string) error { if err != nil { return err } + quiet, err := cmd.Flags().GetBool("quiet") + if err != nil { + return err + } if scheme, ref, err := referenceutil.ParseIPFSRefWithScheme(args[0]); err == nil { ipfsClient, err := httpapi.NewLocalApi() @@ -97,11 +102,11 @@ func pullAction(cmd *cobra.Command, args []string) error { return err } _, err = ipfs.EnsureImage(ctx, client, ipfsClient, cmd.OutOrStdout(), cmd.ErrOrStderr(), snapshotter, scheme, ref, - "always", ocispecPlatforms, unpack) + "always", ocispecPlatforms, unpack, quiet) return err } _, err = imgutil.EnsureImage(ctx, client, cmd.OutOrStdout(), cmd.ErrOrStderr(), snapshotter, args[0], - "always", insecure, ocispecPlatforms, unpack) + "always", insecure, ocispecPlatforms, unpack, quiet) return err } diff --git a/cmd/nerdctl/run.go b/cmd/nerdctl/run.go index 2f9b70e27e7..95a3a563112 100644 --- a/cmd/nerdctl/run.go +++ b/cmd/nerdctl/run.go @@ -719,13 +719,13 @@ func generateRootfsOpts(ctx context.Context, client *containerd.Client, platform if err != nil { return nil, nil, nil, err } - ensured, err = ipfs.EnsureImage(ctx, client, ipfsClient, cmd.OutOrStdout(), cmd.ErrOrStderr(), snapshotter, scheme, ref, pull, ocispecPlatforms, nil) + ensured, err = ipfs.EnsureImage(ctx, client, ipfsClient, cmd.OutOrStdout(), cmd.ErrOrStderr(), snapshotter, scheme, ref, pull, ocispecPlatforms, nil, false) if err != nil { return nil, nil, nil, err } } else { ensured, err = imgutil.EnsureImage(ctx, client, cmd.OutOrStdout(), cmd.ErrOrStderr(), snapshotter, args[0], - pull, insecureRegistry, ocispecPlatforms, nil) + pull, insecureRegistry, ocispecPlatforms, nil, false) if err != nil { return nil, nil, nil, err } diff --git a/pkg/composer/composer.go b/pkg/composer/composer.go index 3cfb91e4231..c769332c198 100644 --- a/pkg/composer/composer.go +++ b/pkg/composer/composer.go @@ -46,7 +46,7 @@ type Options struct { NetworkExists func(string) (bool, error) VolumeExists func(string) (bool, error) ImageExists func(ctx context.Context, imageName string) (bool, error) - EnsureImage func(ctx context.Context, imageName, pullMode, platform string) error + EnsureImage func(ctx context.Context, imageName, pullMode, platform string, quiet bool) error DebugPrintFull bool // full debug print, may leak secret env var to logs } diff --git a/pkg/composer/pull.go b/pkg/composer/pull.go index d7fd3fb192e..aac1dbbafe2 100644 --- a/pkg/composer/pull.go +++ b/pkg/composer/pull.go @@ -28,6 +28,7 @@ import ( ) type PullOptions struct { + Quiet bool } func (c *Composer) Pull(ctx context.Context, po PullOptions) error { @@ -47,6 +48,9 @@ func (c *Composer) pullServiceImage(ctx context.Context, image string, platform if platform != "" { args = append(args, "--platform="+platform) } + if po.Quiet { + args = append(args, "--quiet") + } args = append(args, image) cmd := c.createNerdctlCmd(ctx, append([]string{"pull"}, args...)...) diff --git a/pkg/composer/up.go b/pkg/composer/up.go index 902ad261052..bd763d41cab 100644 --- a/pkg/composer/up.go +++ b/pkg/composer/up.go @@ -35,6 +35,7 @@ type UpOptions struct { NoLogPrefix bool ForceBuild bool IPFS bool + QuietPull bool } func (c *Composer) Up(ctx context.Context, uo UpOptions, services []string) error { diff --git a/pkg/composer/up_service.go b/pkg/composer/up_service.go index 20293a80a97..92249a208f0 100644 --- a/pkg/composer/up_service.go +++ b/pkg/composer/up_service.go @@ -38,7 +38,7 @@ func (c *Composer) upServices(ctx context.Context, parsedServices []*servicepars // TODO: parallelize loop for ensuring images (make sure not to mess up tty) for _, ps := range parsedServices { - if err := c.ensureServiceImage(ctx, ps, !uo.NoBuild, uo.ForceBuild, BuildOptions{IPFS: uo.IPFS}); err != nil { + if err := c.ensureServiceImage(ctx, ps, !uo.NoBuild, uo.ForceBuild, BuildOptions{IPFS: uo.IPFS}, uo.QuietPull); err != nil { return err } } @@ -99,7 +99,7 @@ func (c *Composer) upServices(ctx context.Context, parsedServices []*servicepars return nil } -func (c *Composer) ensureServiceImage(ctx context.Context, ps *serviceparser.Service, allowBuild, forceBuild bool, bo BuildOptions) error { +func (c *Composer) ensureServiceImage(ctx context.Context, ps *serviceparser.Service, allowBuild, forceBuild bool, bo BuildOptions, quiet bool) error { if ps.Build != nil && allowBuild { if ps.Build.Force || forceBuild { return c.buildServiceImage(ctx, ps.Image, ps.Build, ps.Unparsed.Platform, bo) @@ -116,7 +116,7 @@ func (c *Composer) ensureServiceImage(ctx context.Context, ps *serviceparser.Ser // even when c.ImageExists returns true, we need to call c.EnsureImage // because ps.PullMode can be "always". logrus.Infof("Ensuring image %s", ps.Image) - if err := c.EnsureImage(ctx, ps.Image, ps.PullMode, ps.Unparsed.Platform); err != nil { + if err := c.EnsureImage(ctx, ps.Image, ps.PullMode, ps.Unparsed.Platform, quiet); err != nil { return err } return nil diff --git a/pkg/imgutil/imgutil.go b/pkg/imgutil/imgutil.go index ff67febfb0a..ea597d2ca33 100644 --- a/pkg/imgutil/imgutil.go +++ b/pkg/imgutil/imgutil.go @@ -100,7 +100,7 @@ func GetExistingImage(ctx context.Context, client *containerd.Client, snapshotte // EnsureImage ensures the image. // // When insecure is set, skips verifying certs, and also falls back to HTTP when the registry does not speak HTTPS -func EnsureImage(ctx context.Context, client *containerd.Client, stdout, stderr io.Writer, snapshotter, rawRef string, mode PullMode, insecure bool, ocispecPlatforms []ocispec.Platform, unpack *bool) (*EnsuredImage, error) { +func EnsureImage(ctx context.Context, client *containerd.Client, stdout, stderr io.Writer, snapshotter, rawRef string, mode PullMode, insecure bool, ocispecPlatforms []ocispec.Platform, unpack *bool, quiet bool) (*EnsuredImage, error) { switch mode { case "always", "missing", "never": // NOP @@ -139,7 +139,7 @@ func EnsureImage(ctx context.Context, client *containerd.Client, stdout, stderr return nil, err } - img, err := PullImage(ctx, client, stdout, stderr, snapshotter, resolver, ref, ocispecPlatforms, unpack) + img, err := PullImage(ctx, client, stdout, stderr, snapshotter, resolver, ref, ocispecPlatforms, unpack, quiet) if err != nil { if !IsErrHTTPResponseToHTTPSClient(err) { return nil, err @@ -151,7 +151,7 @@ func EnsureImage(ctx context.Context, client *containerd.Client, stdout, stderr if err != nil { return nil, err } - return PullImage(ctx, client, stdout, stderr, snapshotter, resolver, ref, ocispecPlatforms, unpack) + return PullImage(ctx, client, stdout, stderr, snapshotter, resolver, ref, ocispecPlatforms, unpack, quiet) } else { logrus.WithError(err).Errorf("server %q does not seem to support HTTPS", refDomain) logrus.Info("Hint: you may want to try --insecure-registry to allow plain HTTP (if you are in a trusted network)") @@ -171,7 +171,7 @@ func IsErrHTTPResponseToHTTPSClient(err error) bool { } // PullImage pulls an image using the specified resolver. -func PullImage(ctx context.Context, client *containerd.Client, stdout, stderr io.Writer, snapshotter string, resolver remotes.Resolver, ref string, ocispecPlatforms []ocispec.Platform, unpack *bool) (*EnsuredImage, error) { +func PullImage(ctx context.Context, client *containerd.Client, stdout, stderr io.Writer, snapshotter string, resolver remotes.Resolver, ref string, ocispecPlatforms []ocispec.Platform, unpack *bool, quiet bool) (*EnsuredImage, error) { ctx, done, err := client.WithLease(ctx) if err != nil { return nil, err @@ -180,10 +180,12 @@ func PullImage(ctx context.Context, client *containerd.Client, stdout, stderr io var containerdImage containerd.Image config := &pull.Config{ - Resolver: resolver, - ProgressOutput: stderr, - RemoteOpts: []containerd.RemoteOpt{}, - Platforms: ocispecPlatforms, // empty for all-platforms + Resolver: resolver, + RemoteOpts: []containerd.RemoteOpt{}, + Platforms: ocispecPlatforms, // empty for all-platforms + } + if !quiet { + config.ProgressOutput = stderr } var unpackB bool diff --git a/pkg/ipfs/image.go b/pkg/ipfs/image.go index a9471e41a7a..57770ce5433 100644 --- a/pkg/ipfs/image.go +++ b/pkg/ipfs/image.go @@ -39,7 +39,7 @@ import ( ) // EnsureImage pull the specified image from IPFS. -func EnsureImage(ctx context.Context, client *containerd.Client, ipfsClient iface.CoreAPI, stdout, stderr io.Writer, snapshotter string, scheme string, ref string, mode imgutil.PullMode, ocispecPlatforms []ocispec.Platform, unpack *bool) (*imgutil.EnsuredImage, error) { +func EnsureImage(ctx context.Context, client *containerd.Client, ipfsClient iface.CoreAPI, stdout, stderr io.Writer, snapshotter string, scheme string, ref string, mode imgutil.PullMode, ocispecPlatforms []ocispec.Platform, unpack *bool, quiet bool) (*imgutil.EnsuredImage, error) { switch mode { case "always", "missing", "never": // NOP @@ -72,7 +72,7 @@ func EnsureImage(ctx context.Context, client *containerd.Client, ipfsClient ifac if err != nil { return nil, err } - return imgutil.PullImage(ctx, client, stdout, stderr, snapshotter, r, ref, ocispecPlatforms, unpack) + return imgutil.PullImage(ctx, client, stdout, stderr, snapshotter, r, ref, ocispecPlatforms, unpack, quiet) } // Push pushes the specified image to IPFS.