diff --git a/cmd/skopeo/completions.go b/cmd/skopeo/completions.go index 672abc4b1..e62272943 100644 --- a/cmd/skopeo/completions.go +++ b/cmd/skopeo/completions.go @@ -1,13 +1,55 @@ package main import ( + "github.com/containers/image/v5/directory" + "github.com/containers/image/v5/docker" + dockerArchive "github.com/containers/image/v5/docker/archive" + ociArchive "github.com/containers/image/v5/oci/archive" + oci "github.com/containers/image/v5/oci/layout" + "github.com/containers/image/v5/sif" "github.com/containers/image/v5/tarball" "github.com/containers/image/v5/transports" "github.com/spf13/cobra" + "os" + "path" + "path/filepath" + "strings" ) -// autocompleteSupportedTransports list all supported transports with the colon suffix. -func autocompleteSupportedTransports(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) { +func autocompleteImageNames(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) { + transport, details, haveTransport := strings.Cut(toComplete, ":") + if !haveTransport { + transports := supportedTransportSuggestions() + return transports, cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp + } + switch transport { + case ociArchive.Transport.Name(), dockerArchive.Transport.Name(), sif.Transport.Name(), oci.Transport.Name(): + return nil, cobra.ShellCompDirectiveNoSpace + case directory.Transport.Name(): + // just ShellCompDirectiveFilterDirs is more correct, but doesn't work here in bash, see https://github.com/spf13/cobra/issues/2242. Instead we get the directories ourselves. + curDir := filepath.Dir(details) + entries, err := os.ReadDir(curDir) + if err != nil { + cobra.CompErrorln("Failed ReadDir at " + curDir) + // Fallback to whatever the shell gives us + return nil, cobra.ShellCompDirectiveFilterDirs + } + suggestions := make([]cobra.Completion, 0, len(entries)) + for _, e := range entries { + if e.IsDir() { + suggestions = append(suggestions, transport+":"+path.Join(curDir, e.Name())+"/") + } + } + return suggestions, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace + } + if transport == docker.Transport.Name() && details == "" { + return []cobra.Completion{transport + "://"}, cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp + } + return nil, cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp +} + +// supportedTransportSuggestions list all supported transports with the colon suffix. +func supportedTransportSuggestions() []string { tps := transports.ListNames() suggestions := make([]cobra.Completion, 0, len(tps)) for _, tp := range tps { @@ -18,5 +60,5 @@ func autocompleteSupportedTransports(cmd *cobra.Command, args []string, toComple suggestions = append(suggestions, tp+":") } } - return suggestions, cobra.ShellCompDirectiveNoFileComp + return suggestions } diff --git a/cmd/skopeo/copy.go b/cmd/skopeo/copy.go index db13c998e..9d47a5c4a 100644 --- a/cmd/skopeo/copy.go +++ b/cmd/skopeo/copy.go @@ -71,7 +71,7 @@ See skopeo(1) section "IMAGE NAMES" for the expected format `, strings.Join(transports.ListNames(), ", ")), RunE: commandAction(opts.run), Example: `skopeo copy docker://quay.io/skopeo/stable:latest docker://registry.example.com/skopeo:latest`, - ValidArgsFunction: autocompleteSupportedTransports, + ValidArgsFunction: autocompleteImageNames, } adjustUsage(cmd) flags := cmd.Flags() diff --git a/cmd/skopeo/delete.go b/cmd/skopeo/delete.go index 84ed5f972..ddfc2cbee 100644 --- a/cmd/skopeo/delete.go +++ b/cmd/skopeo/delete.go @@ -37,7 +37,7 @@ See skopeo(1) section "IMAGE NAMES" for the expected format `, strings.Join(transports.ListNames(), ", ")), RunE: commandAction(opts.run), Example: `skopeo delete docker://registry.example.com/example/pause:latest`, - ValidArgsFunction: autocompleteSupportedTransports, + ValidArgsFunction: autocompleteImageNames, } adjustUsage(cmd) flags := cmd.Flags() diff --git a/cmd/skopeo/inspect.go b/cmd/skopeo/inspect.go index e969caa4c..92bdfd43f 100644 --- a/cmd/skopeo/inspect.go +++ b/cmd/skopeo/inspect.go @@ -53,7 +53,7 @@ See skopeo(1) section "IMAGE NAMES" for the expected format Example: `skopeo inspect docker://registry.fedoraproject.org/fedora skopeo inspect --config docker://docker.io/alpine skopeo inspect --format "Name: {{.Name}} Digest: {{.Digest}}" docker://registry.access.redhat.com/ubi8`, - ValidArgsFunction: autocompleteSupportedTransports, + ValidArgsFunction: autocompleteImageNames, } adjustUsage(cmd) flags := cmd.Flags()