cli/command: internalize constructing ManifestStore

The CLI.ManifestStore method is a shallow wrapper around manifeststore.NewStore
and has no dependency on the CLI itself. However, due to its signature resulted
in various dependencies becoming a dependency of the "command" package.
Consequence of this was that cli-plugins, which need the cli/command package,
would also get those dependencies.

- This patch inlines the code to produce the store, skipping the wrapper.
- Define a local interface for some tests where a dummy store was used.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2025-03-01 02:33:48 +01:00
parent c775585e6c
commit 3b5dff2783
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
6 changed files with 28 additions and 9 deletions

View File

@ -2,9 +2,11 @@ package manifest
import ( import (
"fmt" "fmt"
"path/filepath"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/manifest/store" "github.com/docker/cli/cli/manifest/store"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -21,6 +23,23 @@ type annotateOptions struct {
osVersion string 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
}
// 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"))
}
// NewAnnotateCommand creates a new `docker manifest annotate` command // NewAnnotateCommand creates a new `docker manifest annotate` command
func newAnnotateCommand(dockerCli command.Cli) *cobra.Command { func newAnnotateCommand(dockerCli command.Cli) *cobra.Command {
var opts annotateOptions var opts annotateOptions
@ -47,7 +66,7 @@ func newAnnotateCommand(dockerCli command.Cli) *cobra.Command {
return cmd return cmd
} }
func runManifestAnnotate(dockerCli command.Cli, opts annotateOptions) error { func runManifestAnnotate(dockerCLI command.Cli, opts annotateOptions) error {
targetRef, err := normalizeReference(opts.target) targetRef, err := normalizeReference(opts.target)
if err != nil { if err != nil {
return errors.Wrapf(err, "annotate: error parsing name for manifest list %s", opts.target) return errors.Wrapf(err, "annotate: error parsing name for manifest list %s", opts.target)
@ -57,7 +76,7 @@ func runManifestAnnotate(dockerCli command.Cli, opts annotateOptions) error {
return errors.Wrapf(err, "annotate: error parsing name for manifest %s", opts.image) 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) imageManifest, err := manifestStore.Get(targetRef, imgRef)
switch { switch {
case store.IsNotFound(err): case store.IsNotFound(err):

View File

@ -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) return errors.Wrapf(err, "error parsing name for manifest list %s", newRef)
} }
manifestStore := dockerCLI.ManifestStore() manifestStore := newManifestStore(dockerCLI)
_, err = manifestStore.GetList(targetRef) _, err = manifestStore.GetList(targetRef)
switch { switch {
case store.IsNotFound(err): case store.IsNotFound(err):

View File

@ -61,7 +61,7 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions)
return err return err
} }
imageManifest, err := dockerCli.ManifestStore().Get(listRef, namedRef) imageManifest, err := newManifestStore(dockerCli).Get(listRef, namedRef)
if err != nil { if err != nil {
return err return err
} }
@ -69,7 +69,7 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions)
} }
// Try a local manifest list first // Try a local manifest list first
localManifestList, err := dockerCli.ManifestStore().GetList(namedRef) localManifestList, err := newManifestStore(dockerCli).GetList(namedRef)
if err == nil { if err == nil {
return printManifestList(dockerCli, namedRef, localManifestList, opts) return printManifestList(dockerCli, namedRef, localManifestList, opts)
} }

View File

@ -68,7 +68,7 @@ func runPush(ctx context.Context, dockerCli command.Cli, opts pushOpts) error {
return err return err
} }
manifests, err := dockerCli.ManifestStore().GetList(targetRef) manifests, err := newManifestStore(dockerCli).GetList(targetRef)
if err != nil { if err != nil {
return err return err
} }
@ -85,7 +85,7 @@ func runPush(ctx context.Context, dockerCli command.Cli, opts pushOpts) error {
return err return err
} }
if opts.purge { if opts.purge {
return dockerCli.ManifestStore().Remove(targetRef) return newManifestStore(dockerCli).Remove(targetRef)
} }
return nil return nil
} }

View File

@ -16,7 +16,7 @@ func newRmManifestListCommand(dockerCLI command.Cli) *cobra.Command {
Short: "Delete one or more manifest lists from local storage", Short: "Delete one or more manifest lists from local storage",
Args: cli.RequiresMinArgs(1), Args: cli.RequiresMinArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runRemove(cmd.Context(), dockerCLI.ManifestStore(), args) return runRemove(cmd.Context(), newManifestStore(dockerCLI), args)
}, },
} }

View File

@ -70,7 +70,7 @@ func normalizeReference(ref string) (reference.Named, error) {
// getManifest from the local store, and fallback to the remote registry if it // getManifest from the local store, and fallback to the remote registry if it
// doesn't exist locally // doesn't exist locally
func getManifest(ctx context.Context, dockerCli command.Cli, listRef, namedRef reference.Named, insecure bool) (types.ImageManifest, error) { func getManifest(ctx context.Context, dockerCli command.Cli, listRef, namedRef reference.Named, insecure bool) (types.ImageManifest, error) {
data, err := dockerCli.ManifestStore().Get(listRef, namedRef) data, err := newManifestStore(dockerCli).Get(listRef, namedRef)
switch { switch {
case store.IsNotFound(err): case store.IsNotFound(err):
return dockerCli.RegistryClient(insecure).GetManifest(ctx, namedRef) return dockerCli.RegistryClient(insecure).GetManifest(ctx, namedRef)