diff options
Diffstat (limited to 'cmd/podman/images')
-rw-r--r-- | cmd/podman/images/exists.go | 1 | ||||
-rw-r--r-- | cmd/podman/images/history.go | 20 | ||||
-rw-r--r-- | cmd/podman/images/image.go | 3 | ||||
-rw-r--r-- | cmd/podman/images/images.go | 13 | ||||
-rw-r--r-- | cmd/podman/images/inspect.go | 92 | ||||
-rw-r--r-- | cmd/podman/images/list.go | 75 | ||||
-rw-r--r-- | cmd/podman/images/prune.go | 3 | ||||
-rw-r--r-- | cmd/podman/images/pull.go | 12 | ||||
-rw-r--r-- | cmd/podman/images/push.go | 12 | ||||
-rw-r--r-- | cmd/podman/images/rm.go | 5 | ||||
-rw-r--r-- | cmd/podman/images/search.go | 27 |
11 files changed, 116 insertions, 147 deletions
diff --git a/cmd/podman/images/exists.go b/cmd/podman/images/exists.go index 6464e6cd8..13191113f 100644 --- a/cmd/podman/images/exists.go +++ b/cmd/podman/images/exists.go @@ -15,6 +15,7 @@ var ( RunE: exists, Example: `podman image exists ID podman image exists IMAGE && podman pull IMAGE`, + DisableFlagsInUseLine: true, } ) diff --git a/cmd/podman/images/history.go b/cmd/podman/images/history.go index b8d216cc1..ce153aa46 100644 --- a/cmd/podman/images/history.go +++ b/cmd/podman/images/history.go @@ -89,22 +89,20 @@ func history(cmd *cobra.Command, args []string) error { hdr := "ID\tCREATED\tCREATED BY\tSIZE\tCOMMENT\n" row := "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n" - if len(opts.format) > 0 { + switch { + case len(opts.format) > 0: hdr = "" row = opts.format if !strings.HasSuffix(opts.format, "\n") { row += "\n" } - } else { - switch { - case opts.human: - row = "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n" - case opts.noTrunc: - row = "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n" - case opts.quiet: - hdr = "" - row = "{{.ID}}\n" - } + case opts.quiet: + hdr = "" + row = "{{.ID}}\n" + case opts.human: + row = "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n" + case opts.noTrunc: + row = "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n" } format := hdr + "{{range . }}" + row + "{{end}}" diff --git a/cmd/podman/images/image.go b/cmd/podman/images/image.go index 604f49251..790c16c05 100644 --- a/cmd/podman/images/image.go +++ b/cmd/podman/images/image.go @@ -2,6 +2,7 @@ package images import ( "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/validate" "github.com/containers/libpod/pkg/domain/entities" "github.com/spf13/cobra" ) @@ -16,7 +17,7 @@ var ( Short: "Manage images", Long: "Manage images", TraverseChildren: true, - RunE: registry.SubCommandExists, + RunE: validate.SubCommandExists, } ) diff --git a/cmd/podman/images/images.go b/cmd/podman/images/images.go index fd3ede26a..96ef344bf 100644 --- a/cmd/podman/images/images.go +++ b/cmd/podman/images/images.go @@ -11,12 +11,13 @@ import ( var ( // podman _images_ Alias for podman image _list_ imagesCmd = &cobra.Command{ - Use: strings.Replace(listCmd.Use, "list", "images", 1), - Args: listCmd.Args, - Short: listCmd.Short, - Long: listCmd.Long, - RunE: listCmd.RunE, - Example: strings.Replace(listCmd.Example, "podman image list", "podman images", -1), + Use: strings.Replace(listCmd.Use, "list", "images", 1), + Args: listCmd.Args, + Short: listCmd.Short, + Long: listCmd.Long, + RunE: listCmd.RunE, + Example: strings.Replace(listCmd.Example, "podman image list", "podman images", -1), + DisableFlagsInUseLine: true, } ) diff --git a/cmd/podman/images/inspect.go b/cmd/podman/images/inspect.go index 91c9445eb..8c727eb07 100644 --- a/cmd/podman/images/inspect.go +++ b/cmd/podman/images/inspect.go @@ -1,18 +1,9 @@ package images import ( - "context" - "fmt" - "os" - "strings" - "text/tabwriter" - "text/template" - - "github.com/containers/buildah/pkg/formats" - "github.com/containers/libpod/cmd/podman/common" + "github.com/containers/libpod/cmd/podman/inspect" "github.com/containers/libpod/cmd/podman/registry" "github.com/containers/libpod/pkg/domain/entities" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -21,8 +12,8 @@ var ( inspectCmd = &cobra.Command{ Use: "inspect [flags] IMAGE", Short: "Display the configuration of an image", - Long: `Displays the low-level information on an image identified by name or ID.`, - RunE: inspect, + Long: `Displays the low-level information of an image identified by name or ID.`, + RunE: inspectExec, Example: `podman inspect alpine podman inspect --format "imageId: {{.Id}} size: {{.Size}}" alpine podman inspect --format "image: {{.ImageName}} driver: {{.Driver}}" myctr`, @@ -36,78 +27,11 @@ func init() { Command: inspectCmd, Parent: imageCmd, }) - inspectOpts = common.AddInspectFlagSet(inspectCmd) -} - -func inspect(cmd *cobra.Command, args []string) error { - if inspectOpts.Size { - return fmt.Errorf("--size can only be used for containers") - } - if inspectOpts.Latest { - return fmt.Errorf("--latest can only be used for containers") - } - if len(args) == 0 { - return errors.Errorf("image name must be specified: podman image inspect [options [...]] name") - } - - results, err := registry.ImageEngine().Inspect(context.Background(), args, *inspectOpts) - if err != nil { - return err - } - - if len(results.Images) > 0 { - if inspectOpts.Format == "" { - buf, err := json.MarshalIndent(results.Images, "", " ") - if err != nil { - return err - } - fmt.Println(string(buf)) - - for id, e := range results.Errors { - fmt.Fprintf(os.Stderr, "%s: %s\n", id, e.Error()) - } - return nil - } - row := inspectFormat(inspectOpts.Format) - format := "{{range . }}" + row + "{{end}}" - tmpl, err := template.New("inspect").Parse(format) - if err != nil { - return err - } - - w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0) - defer func() { _ = w.Flush() }() - err = tmpl.Execute(w, results.Images) - if err != nil { - return err - } - } - - var lastErr error - for id, e := range results.Errors { - if lastErr != nil { - fmt.Fprintf(os.Stderr, "%s: %s\n", id, lastErr.Error()) - } - lastErr = e - } - return lastErr -} - -func inspectFormat(row string) string { - r := strings.NewReplacer("{{.Id}}", formats.IDString, - ".Src", ".Source", - ".Dst", ".Destination", - ".ImageID", ".Image", - ) - row = r.Replace(row) - - if !strings.HasSuffix(row, "\n") { - row += "\n" - } - return row + inspectOpts = inspect.AddInspectFlagSet(inspectCmd) + flags := inspectCmd.Flags() + _ = flags.MarkHidden("latest") // Shared with container-inspect but not wanted here. } -func Inspect(cmd *cobra.Command, args []string, options *entities.InspectOptions) error { - inspectOpts = options - return inspect(cmd, args) +func inspectExec(cmd *cobra.Command, args []string) error { + return inspect.Inspect(args, *inspectOpts) } diff --git a/cmd/podman/images/list.go b/cmd/podman/images/list.go index b979cb6af..83c039ed3 100644 --- a/cmd/podman/images/list.go +++ b/cmd/podman/images/list.go @@ -32,7 +32,7 @@ type listFlagType struct { var ( // Command: podman image _list_ listCmd = &cobra.Command{ - Use: "list [flag] [IMAGE]", + Use: "list [FLAGS] [IMAGE]", Aliases: []string{"ls"}, Args: cobra.MaximumNArgs(1), Short: "List images in local storage", @@ -41,6 +41,7 @@ var ( Example: `podman image list --format json podman image list --sort repository --format "table {{.ID}} {{.Repository}} {{.Tag}}" podman image list --filter dangling=true`, + DisableFlagsInUseLine: true, } // Options to pull data @@ -98,14 +99,29 @@ func images(cmd *cobra.Command, args []string) error { return err } - imageS := summaries - sort.Slice(imageS, sortFunc(listFlag.sort, imageS)) + switch { + case listFlag.quiet: + return writeId(summaries) + case cmd.Flag("format").Changed && listFlag.format == "json": + return writeJSON(summaries) + default: + return writeTemplate(summaries) + } +} - if cmd.Flag("format").Changed && listFlag.format == "json" { - return writeJSON(imageS) - } else { - return writeTemplate(imageS, err) +func writeId(imageS []*entities.ImageSummary) error { + var ids = map[string]struct{}{} + for _, e := range imageS { + i := "sha256:" + e.ID + if !listFlag.noTrunc { + i = fmt.Sprintf("%12.12s", e.ID) + } + ids[i] = struct{}{} } + for k := range ids { + fmt.Fprint(os.Stdout, k+"\n") + } + return nil } func writeJSON(imageS []*entities.ImageSummary) error { @@ -130,7 +146,7 @@ func writeJSON(imageS []*entities.ImageSummary) error { return enc.Encode(imgs) } -func writeTemplate(imageS []*entities.ImageSummary, err error) error { +func writeTemplate(imageS []*entities.ImageSummary) error { var ( hdr, row string ) @@ -142,10 +158,11 @@ func writeTemplate(imageS []*entities.ImageSummary, err error) error { h.Repository, h.Tag = tokenRepoTag(tag) imgs = append(imgs, h) } - if e.IsReadOnly() { - listFlag.readOnly = true - } + listFlag.readOnly = e.IsReadOnly() } + + sort.Slice(imgs, sortFunc(listFlag.sort, imgs)) + if len(listFlag.format) < 1 { hdr, row = imageListFormat(listFlag) } else { @@ -175,37 +192,33 @@ func tokenRepoTag(tag string) (string, string) { } } -func sortFunc(key string, data []*entities.ImageSummary) func(i, j int) bool { +func sortFunc(key string, data []imageReporter) func(i, j int) bool { switch key { case "id": return func(i, j int) bool { - return data[i].ID < data[j].ID + return data[i].ID() < data[j].ID() } case "repository": return func(i, j int) bool { - return data[i].RepoTags[0] < data[j].RepoTags[0] + return data[i].Repository < data[j].Repository } case "size": return func(i, j int) bool { - return data[i].Size < data[j].Size + return data[i].size() < data[j].size() } case "tag": return func(i, j int) bool { - return data[i].RepoTags[0] < data[j].RepoTags[0] + return data[i].Tag < data[j].Tag } default: // case "created": return func(i, j int) bool { - return data[i].Created.After(data[j].Created) + return data[i].created().After(data[j].created()) } } } func imageListFormat(flags listFlagType) (string, string) { - if flags.quiet { - return "", "{{.ID}}\n" - } - // Defaults hdr := "REPOSITORY\tTAG" row := "{{.Repository}}\t{{if .Tag}}{{.Tag}}{{else}}<none>{{end}}" @@ -262,6 +275,10 @@ func (i imageReporter) Created() string { return units.HumanDuration(time.Since(i.ImageSummary.Created)) + " ago" } +func (i imageReporter) created() time.Time { + return i.ImageSummary.Created +} + func (i imageReporter) Size() string { s := units.HumanSizeWithPrecision(float64(i.ImageSummary.Size), 3) j := strings.LastIndexFunc(s, unicode.IsNumber) @@ -271,3 +288,19 @@ func (i imageReporter) Size() string { func (i imageReporter) History() string { return strings.Join(i.ImageSummary.History, ", ") } + +func (i imageReporter) CreatedAt() string { + return i.ImageSummary.Created.String() +} + +func (i imageReporter) CreatedSince() string { + return i.Created() +} + +func (i imageReporter) CreatedTime() string { + return i.CreatedAt() +} + +func (i imageReporter) size() int64 { + return i.ImageSummary.Size +} diff --git a/cmd/podman/images/prune.go b/cmd/podman/images/prune.go index b90d889be..53a1966c1 100644 --- a/cmd/podman/images/prune.go +++ b/cmd/podman/images/prune.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/validate" "github.com/containers/libpod/pkg/domain/entities" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -18,7 +19,7 @@ var ( If an image is not being used by a container, it will be removed from the system.` pruneCmd = &cobra.Command{ Use: "prune", - Args: cobra.NoArgs, + Args: validate.NoArgs, Short: "Remove unused images", Long: pruneDescription, RunE: prune, diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go index f996d0681..9f4cbc50e 100644 --- a/cmd/podman/images/pull.go +++ b/cmd/podman/images/pull.go @@ -45,6 +45,7 @@ var ( Short: pullCmd.Short, Long: pullCmd.Long, RunE: pullCmd.RunE, + Args: cobra.ExactArgs(1), Example: `podman image pull imageName podman image pull fedora:latest`, } @@ -93,23 +94,22 @@ func pullFlags(flags *pflag.FlagSet) { // imagePull is implement the command for pulling images. func imagePull(cmd *cobra.Command, args []string) error { - pullOptsAPI := pullOptions.ImagePullOptions // TLS verification in c/image is controlled via a `types.OptionalBool` // which allows for distinguishing among set-true, set-false, unspecified // which is important to implement a sane way of dealing with defaults of // boolean CLI flags. if cmd.Flags().Changed("tls-verify") { - pullOptsAPI.TLSVerify = types.NewOptionalBool(pullOptions.TLSVerifyCLI) + pullOptions.SkipTLSVerify = types.NewOptionalBool(!pullOptions.TLSVerifyCLI) } - if pullOptsAPI.Authfile != "" { - if _, err := os.Stat(pullOptsAPI.Authfile); err != nil { - return errors.Wrapf(err, "error getting authfile %s", pullOptsAPI.Authfile) + if pullOptions.Authfile != "" { + if _, err := os.Stat(pullOptions.Authfile); err != nil { + return errors.Wrapf(err, "error getting authfile %s", pullOptions.Authfile) } } // Let's do all the remaining Yoga in the API to prevent us from // scattering logic across (too) many parts of the code. - pullReport, err := registry.ImageEngine().Pull(registry.GetContext(), args[0], pullOptsAPI) + pullReport, err := registry.ImageEngine().Pull(registry.GetContext(), args[0], pullOptions.ImagePullOptions) if err != nil { return err } diff --git a/cmd/podman/images/push.go b/cmd/podman/images/push.go index ef2ffd0d7..0b3502d61 100644 --- a/cmd/podman/images/push.go +++ b/cmd/podman/images/push.go @@ -98,6 +98,7 @@ func imagePush(cmd *cobra.Command, args []string) error { switch len(args) { case 1: source = args[0] + destination = args[0] case 2: source = args[0] destination = args[1] @@ -107,22 +108,21 @@ func imagePush(cmd *cobra.Command, args []string) error { return errors.New("push requires at least one image name, or optionally a second to specify a different destination") } - pushOptsAPI := pushOptions.ImagePushOptions // TLS verification in c/image is controlled via a `types.OptionalBool` // which allows for distinguishing among set-true, set-false, unspecified // which is important to implement a sane way of dealing with defaults of // boolean CLI flags. if cmd.Flags().Changed("tls-verify") { - pushOptsAPI.TLSVerify = types.NewOptionalBool(pushOptions.TLSVerifyCLI) + pushOptions.SkipTLSVerify = types.NewOptionalBool(!pushOptions.TLSVerifyCLI) } - if pushOptsAPI.Authfile != "" { - if _, err := os.Stat(pushOptsAPI.Authfile); err != nil { - return errors.Wrapf(err, "error getting authfile %s", pushOptsAPI.Authfile) + if pushOptions.Authfile != "" { + if _, err := os.Stat(pushOptions.Authfile); err != nil { + return errors.Wrapf(err, "error getting authfile %s", pushOptions.Authfile) } } // Let's do all the remaining Yoga in the API to prevent us from scattering // logic across (too) many parts of the code. - return registry.ImageEngine().Push(registry.GetContext(), source, destination, pushOptsAPI) + return registry.ImageEngine().Push(registry.GetContext(), source, destination, pushOptions.ImagePushOptions) } diff --git a/cmd/podman/images/rm.go b/cmd/podman/images/rm.go index da6a90d2b..1cf5fa365 100644 --- a/cmd/podman/images/rm.go +++ b/cmd/podman/images/rm.go @@ -54,7 +54,10 @@ func rm(cmd *cobra.Command, args []string) error { fmt.Println("Untagged: " + u) } for _, d := range report.Deleted { - fmt.Println("Deleted: " + d) + // Make sure an image was deleted (and not just untagged); else print it + if len(d) > 0 { + fmt.Println("Deleted: " + d) + } } registry.SetExitCode(report.ExitCode) } diff --git a/cmd/podman/images/search.go b/cmd/podman/images/search.go index fdad94d45..a8abfb339 100644 --- a/cmd/podman/images/search.go +++ b/cmd/podman/images/search.go @@ -1,6 +1,7 @@ package images import ( + "os" "reflect" "strings" @@ -47,14 +48,15 @@ var ( // Command: podman image search imageSearchCmd = &cobra.Command{ - Use: searchCmd.Use, - Short: searchCmd.Short, - Long: searchCmd.Long, - RunE: searchCmd.RunE, - Args: searchCmd.Args, + Use: searchCmd.Use, + Short: searchCmd.Short, + Long: searchCmd.Long, + RunE: searchCmd.RunE, + Args: searchCmd.Args, + Annotations: searchCmd.Annotations, Example: `podman image search --filter=is-official --limit 3 alpine - podman image search registry.fedoraproject.org/ # only works with v2 registries - podman image search --format "table {{.Index}} {{.Name}}" registry.fedoraproject.org/fedora`, + podman image search registry.fedoraproject.org/ # only works with v2 registries + podman image search --format "table {{.Index}} {{.Name}}" registry.fedoraproject.org/fedora`, } ) @@ -103,16 +105,21 @@ func imageSearch(cmd *cobra.Command, args []string) error { return errors.Errorf("search requires exactly one argument") } - sarchOptsAPI := searchOptions.ImageSearchOptions // TLS verification in c/image is controlled via a `types.OptionalBool` // which allows for distinguishing among set-true, set-false, unspecified // which is important to implement a sane way of dealing with defaults of // boolean CLI flags. if cmd.Flags().Changed("tls-verify") { - sarchOptsAPI.TLSVerify = types.NewOptionalBool(pullOptions.TLSVerifyCLI) + searchOptions.SkipTLSVerify = types.NewOptionalBool(!searchOptions.TLSVerifyCLI) } - searchReport, err := registry.ImageEngine().Search(registry.GetContext(), searchTerm, sarchOptsAPI) + if searchOptions.Authfile != "" { + if _, err := os.Stat(searchOptions.Authfile); err != nil { + return errors.Wrapf(err, "error getting authfile %s", searchOptions.Authfile) + } + } + + searchReport, err := registry.ImageEngine().Search(registry.GetContext(), searchTerm, searchOptions.ImageSearchOptions) if err != nil { return err } |