diff --git a/cli/command/cli.go b/cli/command/cli.go index 289ca7f822..3cf576b112 100644 --- a/cli/command/cli.go +++ b/cli/command/cli.go @@ -8,7 +8,6 @@ import ( "fmt" "io" "os" - "path/filepath" "runtime" "strconv" "sync" @@ -21,14 +20,11 @@ import ( "github.com/docker/cli/cli/context/store" "github.com/docker/cli/cli/debug" cliflags "github.com/docker/cli/cli/flags" - manifeststore "github.com/docker/cli/cli/manifest/store" - registryclient "github.com/docker/cli/cli/registry/client" "github.com/docker/cli/cli/streams" "github.com/docker/cli/cli/version" dopts "github.com/docker/cli/opts" "github.com/docker/docker/api" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/registry" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/client" "github.com/pkg/errors" @@ -54,8 +50,6 @@ type Cli interface { ServerInfo() ServerInfo DefaultVersion() string CurrentVersion() string - ManifestStore() manifeststore.Store - RegistryClient(bool) registryclient.RegistryClient ContentTrustEnabled() bool BuildKitEnabled() (bool, error) ContextStore() store.Store @@ -63,6 +57,7 @@ type Cli interface { DockerEndpoint() docker.Endpoint TelemetryClient DeprecatedNotaryClient + DeprecatedManifestClient } // DockerCli is an instance the docker command line client. @@ -227,21 +222,6 @@ func (cli *DockerCli) HooksEnabled() bool { return false } -// ManifestStore returns a store for local manifests -func (*DockerCli) ManifestStore() manifeststore.Store { - // TODO: support override default location from config file - return manifeststore.NewStore(filepath.Join(config.Dir(), "manifests")) -} - -// RegistryClient returns a client for communicating with a Docker distribution -// registry -func (cli *DockerCli) RegistryClient(allowInsecure bool) registryclient.RegistryClient { - resolver := func(ctx context.Context, index *registry.IndexInfo) registry.AuthConfig { - return ResolveAuthConfig(cli.ConfigFile(), index) - } - return registryclient.NewRegistryClient(resolver, UserAgent(), allowInsecure) -} - // WithInitializeClient is passed to DockerCli.Initialize by callers who wish to set a particular API Client for use by the CLI. func WithInitializeClient(makeClient func(dockerCli *DockerCli) (client.APIClient, error)) CLIOption { return func(dockerCli *DockerCli) error { diff --git a/cli/command/cli_deprecated.go b/cli/command/cli_deprecated.go index d179f42f22..15fac1a6e3 100644 --- a/cli/command/cli_deprecated.go +++ b/cli/command/cli_deprecated.go @@ -1,7 +1,14 @@ package command import ( + "context" + "path/filepath" + + "github.com/docker/cli/cli/config" + manifeststore "github.com/docker/cli/cli/manifest/store" + registryclient "github.com/docker/cli/cli/registry/client" "github.com/docker/cli/cli/trust" + "github.com/docker/docker/api/types/registry" notaryclient "github.com/theupdateframework/notary/client" ) @@ -12,7 +19,38 @@ type DeprecatedNotaryClient interface { NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) } +type DeprecatedManifestClient interface { + // ManifestStore returns a store for local manifests + // + // Deprecated: use [manifeststore.NewStore] instead. This method is no longer used and will be removed in the next release. + ManifestStore() manifeststore.Store + + // RegistryClient returns a client for communicating with a Docker distribution + // registry. + // + // Deprecated: use [registryclient.NewRegistryClient]. This method is no longer used and will be removed in the next release. + RegistryClient(bool) registryclient.RegistryClient +} + // NotaryClient provides a Notary Repository to interact with signed metadata for an image func (cli *DockerCli) NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) { return trust.GetNotaryRepository(cli.In(), cli.Out(), UserAgent(), imgRefAndAuth.RepoInfo(), imgRefAndAuth.AuthConfig(), actions...) } + +// ManifestStore returns a store for local manifests +// +// Deprecated: use [manifeststore.NewStore] instead. This method is no longer used and will be removed in the next release. +func (*DockerCli) ManifestStore() manifeststore.Store { + return manifeststore.NewStore(filepath.Join(config.Dir(), "manifests")) +} + +// RegistryClient returns a client for communicating with a Docker distribution +// registry +// +// Deprecated: use [registryclient.NewRegistryClient]. This method is no longer used and will be removed in the next release. +func (cli *DockerCli) RegistryClient(allowInsecure bool) registryclient.RegistryClient { + resolver := func(ctx context.Context, index *registry.IndexInfo) registry.AuthConfig { + return ResolveAuthConfig(cli.ConfigFile(), index) + } + return registryclient.NewRegistryClient(resolver, UserAgent(), allowInsecure) +} diff --git a/cli/command/manifest/annotate.go b/cli/command/manifest/annotate.go index c12b69d823..0f2a10aade 100644 --- a/cli/command/manifest/annotate.go +++ b/cli/command/manifest/annotate.go @@ -1,11 +1,16 @@ package manifest import ( + "context" "fmt" + "path/filepath" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" + "github.com/docker/cli/cli/config" "github.com/docker/cli/cli/manifest/store" + registryclient "github.com/docker/cli/cli/registry/client" + "github.com/docker/docker/api/types/registry" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -21,6 +26,37 @@ type annotateOptions struct { osVersion string } +// manifestStoreProvider is used in tests to provide a dummy store. +type manifestStoreProvider interface { + // ManifestStore returns a store for local manifests + ManifestStore() store.Store + RegistryClient(bool) registryclient.RegistryClient +} + +// newManifestStore returns a store for local manifests +func newManifestStore(dockerCLI command.Cli) store.Store { + if msp, ok := dockerCLI.(manifestStoreProvider); ok { + // manifestStoreProvider is used in tests to provide a dummy store. + return msp.ManifestStore() + } + + // TODO: support override default location from config file + return store.NewStore(filepath.Join(config.Dir(), "manifests")) +} + +// newRegistryClient returns a client for communicating with a Docker distribution +// registry +func newRegistryClient(dockerCLI command.Cli, allowInsecure bool) registryclient.RegistryClient { + if msp, ok := dockerCLI.(manifestStoreProvider); ok { + // manifestStoreProvider is used in tests to provide a dummy store. + return msp.RegistryClient(allowInsecure) + } + resolver := func(ctx context.Context, index *registry.IndexInfo) registry.AuthConfig { + return command.ResolveAuthConfig(dockerCLI.ConfigFile(), index) + } + return registryclient.NewRegistryClient(resolver, command.UserAgent(), allowInsecure) +} + // NewAnnotateCommand creates a new `docker manifest annotate` command func newAnnotateCommand(dockerCli command.Cli) *cobra.Command { var opts annotateOptions @@ -47,7 +83,7 @@ func newAnnotateCommand(dockerCli command.Cli) *cobra.Command { return cmd } -func runManifestAnnotate(dockerCli command.Cli, opts annotateOptions) error { +func runManifestAnnotate(dockerCLI command.Cli, opts annotateOptions) error { targetRef, err := normalizeReference(opts.target) if err != nil { return errors.Wrapf(err, "annotate: error parsing name for manifest list %s", opts.target) @@ -57,7 +93,7 @@ func runManifestAnnotate(dockerCli command.Cli, opts annotateOptions) error { return errors.Wrapf(err, "annotate: error parsing name for manifest %s", opts.image) } - manifestStore := dockerCli.ManifestStore() + manifestStore := newManifestStore(dockerCLI) imageManifest, err := manifestStore.Get(targetRef, imgRef) switch { case store.IsNotFound(err): diff --git a/cli/command/manifest/create_list.go b/cli/command/manifest/create_list.go index 5a399d5758..58c18124df 100644 --- a/cli/command/manifest/create_list.go +++ b/cli/command/manifest/create_list.go @@ -41,7 +41,7 @@ func createManifestList(ctx context.Context, dockerCLI command.Cli, args []strin return errors.Wrapf(err, "error parsing name for manifest list %s", newRef) } - manifestStore := dockerCLI.ManifestStore() + manifestStore := newManifestStore(dockerCLI) _, err = manifestStore.GetList(targetRef) switch { case store.IsNotFound(err): diff --git a/cli/command/manifest/inspect.go b/cli/command/manifest/inspect.go index 23ea2e69c6..217383a07f 100644 --- a/cli/command/manifest/inspect.go +++ b/cli/command/manifest/inspect.go @@ -61,7 +61,7 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) return err } - imageManifest, err := dockerCli.ManifestStore().Get(listRef, namedRef) + imageManifest, err := newManifestStore(dockerCli).Get(listRef, namedRef) if err != nil { return err } @@ -69,13 +69,13 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) } // Try a local manifest list first - localManifestList, err := dockerCli.ManifestStore().GetList(namedRef) + localManifestList, err := newManifestStore(dockerCli).GetList(namedRef) if err == nil { return printManifestList(dockerCli, namedRef, localManifestList, opts) } // Next try a remote manifest - registryClient := dockerCli.RegistryClient(opts.insecure) + registryClient := newRegistryClient(dockerCli, opts.insecure) imageManifest, err := registryClient.GetManifest(ctx, namedRef) if err == nil { return printManifest(dockerCli, imageManifest, opts) diff --git a/cli/command/manifest/push.go b/cli/command/manifest/push.go index 9b214eeaa7..ccfa84cd6c 100644 --- a/cli/command/manifest/push.go +++ b/cli/command/manifest/push.go @@ -68,7 +68,7 @@ func runPush(ctx context.Context, dockerCli command.Cli, opts pushOpts) error { return err } - manifests, err := dockerCli.ManifestStore().GetList(targetRef) + manifests, err := newManifestStore(dockerCli).GetList(targetRef) if err != nil { return err } @@ -85,7 +85,7 @@ func runPush(ctx context.Context, dockerCli command.Cli, opts pushOpts) error { return err } if opts.purge { - return dockerCli.ManifestStore().Remove(targetRef) + return newManifestStore(dockerCli).Remove(targetRef) } return nil } @@ -248,7 +248,7 @@ func buildPutManifestRequest(imageManifest types.ImageManifest, targetRef refere } func pushList(ctx context.Context, dockerCLI command.Cli, req pushRequest) error { - rclient := dockerCLI.RegistryClient(req.insecure) + rclient := newRegistryClient(dockerCLI, req.insecure) if err := mountBlobs(ctx, rclient, req.targetRef, req.manifestBlobs); err != nil { return err diff --git a/cli/command/manifest/rm.go b/cli/command/manifest/rm.go index e59b716cd3..dda4e3e489 100644 --- a/cli/command/manifest/rm.go +++ b/cli/command/manifest/rm.go @@ -16,7 +16,7 @@ func newRmManifestListCommand(dockerCLI command.Cli) *cobra.Command { Short: "Delete one or more manifest lists from local storage", Args: cli.RequiresMinArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRemove(cmd.Context(), dockerCLI.ManifestStore(), args) + return runRemove(cmd.Context(), newManifestStore(dockerCLI), args) }, } diff --git a/cli/command/manifest/util.go b/cli/command/manifest/util.go index f89116d96c..be9fe9ea1b 100644 --- a/cli/command/manifest/util.go +++ b/cli/command/manifest/util.go @@ -69,15 +69,15 @@ func normalizeReference(ref string) (reference.Named, error) { // getManifest from the local store, and fallback to the remote registry if it // doesn't exist locally -func getManifest(ctx context.Context, dockerCli command.Cli, listRef, namedRef reference.Named, insecure bool) (types.ImageManifest, error) { - data, err := dockerCli.ManifestStore().Get(listRef, namedRef) +func getManifest(ctx context.Context, dockerCLI command.Cli, listRef, namedRef reference.Named, insecure bool) (types.ImageManifest, error) { + data, err := newManifestStore(dockerCLI).Get(listRef, namedRef) switch { case store.IsNotFound(err): - return dockerCli.RegistryClient(insecure).GetManifest(ctx, namedRef) + return newRegistryClient(dockerCLI, insecure).GetManifest(ctx, namedRef) case err != nil: return types.ImageManifest{}, err case len(data.Raw) == 0: - return dockerCli.RegistryClient(insecure).GetManifest(ctx, namedRef) + return newRegistryClient(dockerCLI, insecure).GetManifest(ctx, namedRef) default: return data, nil }