Skip to content

Commit

Permalink
add nerdctl images --digests (compatible with Docker, unlike ID)
Browse files Browse the repository at this point in the history
While the image ID is different from Docker in most cases, the DIGEST value
always corresponds to Docker.

```console
$ docker  images --digests
REPOSITORY                          TAG       DIGEST                                                                    IMAGE ID       CREATED         SIZE
alpine                              latest    sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a   14119a10abf4   7 weeks ago     5.6MB

$ nerdctl images --digests
REPOSITORY    TAG       DIGEST                                                                     IMAGE ID        CREATED           SIZE
alpine        latest    sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a    e1c082e3d3c4    40 minutes ago    5.9 MiB
```

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
  • Loading branch information
AkihiroSuda committed Oct 19, 2021
1 parent de55345 commit f9eb1e5
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 18 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -629,14 +629,17 @@ Unimplemented `docker commit` flags: `--change`, `--pause`
### :whale: nerdctl images
List images

:warning: The image ID is usually different from Docker image ID.

Usage: `nerdctl images [OPTIONS] [REPOSITORY[:TAG]]`

Flags:
- :whale: `-q, --quiet`: Only show numeric IDs
- :whale: `--no-trunc`: Don't truncate output
- :whale: `--format`: Format the output using the given Go template, e.g, `{{json .}}`
- :whale: `--digests`: Show digests (compatible with Docker, unlike ID)

Unimplemented `docker images` flags: `--all`, `--digests`, `--filter`
Unimplemented `docker images` flags: `--all`, `--filter`

### :whale: nerdctl pull
Pull an image from a registry.
Expand Down
59 changes: 43 additions & 16 deletions cmd/nerdctl/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,12 @@ import (
)

func newImagesCommand() *cobra.Command {
shortHelp := "List images"
longHelp := shortHelp + "\nNOTE: The image ID is usually different from Docker image ID."
var imagesCommand = &cobra.Command{
Use: "images",
Short: "List images",
Short: shortHelp,
Long: longHelp,
Args: cobra.MaximumNArgs(1),
RunE: imagesAction,
ValidArgsFunction: imagesShellComplete,
Expand All @@ -57,6 +60,7 @@ func newImagesCommand() *cobra.Command {
imagesCommand.Flags().Bool("no-trunc", false, "Don't truncate output")
// Alias "-f" is reserved for "--filter"
imagesCommand.Flags().String("format", "", "Format the output using the given Go template, e.g, '{{json .}}'")
imagesCommand.Flags().Bool("digests", false, "Show digests (compatible with Docker, unlike ID)")

return imagesCommand
}
Expand Down Expand Up @@ -99,11 +103,11 @@ type imagePrintable struct {
// TODO: "Containers"
CreatedAt string
CreatedSince string
// TODO: "Digest" (only when --digests is set)
ID string
Repository string
Tag string
Size string
Digest string // "<none>" or image target digest (i.e., index digest or manifest digest)
ID string // image target digest (not config digest, unlike Docker), or its short form
Repository string
Tag string
Size string
// TODO: "SharedSize", "UniqueSize", "VirtualSize"
}

Expand All @@ -116,6 +120,10 @@ func printImages(ctx context.Context, cmd *cobra.Command, client *containerd.Cli
if err != nil {
return err
}
digestsFlag, err := cmd.Flags().GetBool("digests")
if err != nil {
return err
}
var w io.Writer
w = os.Stdout
format, err := cmd.Flags().GetString("format")
Expand All @@ -127,7 +135,11 @@ func printImages(ctx context.Context, cmd *cobra.Command, client *containerd.Cli
case "", "table":
w = tabwriter.NewWriter(w, 4, 8, 4, ' ', 0)
if !quiet {
fmt.Fprintln(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tSIZE")
if digestsFlag {
fmt.Fprintln(w, "REPOSITORY\tTAG\tDIGEST\tIMAGE ID\tCREATED\tSIZE")
} else {
fmt.Fprintln(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tSIZE")
}
}
case "raw":
return errors.New("unsupported format: \"raw\"")
Expand Down Expand Up @@ -159,13 +171,15 @@ func printImages(ctx context.Context, cmd *cobra.Command, client *containerd.Cli
p := imagePrintable{
CreatedAt: img.CreatedAt.Round(time.Second).Local().String(), // format like "2021-08-07 02:19:45 +0900 JST"
CreatedSince: formatter.TimeSinceInHuman(img.CreatedAt),
Digest: img.Target.Digest.String(),
ID: img.Target.Digest.String(),
Repository: repository,
Tag: tag,
Size: progress.Bytes(size).String(),
}
if !noTrunc {
p.ID = strings.Split(img.Target.Digest.String(), ":")[1][:12]
// p.Digest does not need to be truncated
p.ID = strings.Split(p.ID, ":")[1][:12]
}
if tmpl != nil {
var b bytes.Buffer
Expand All @@ -180,14 +194,27 @@ func printImages(ctx context.Context, cmd *cobra.Command, client *containerd.Cli
return err
}
} else {
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n",
repository,
tag,
p.ID,
p.CreatedSince,
p.Size,
); err != nil {
return err
if digestsFlag {
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\n",
repository,
tag,
p.Digest,
p.ID,
p.CreatedSince,
p.Size,
); err != nil {
return err
}
} else {
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n",
repository,
tag,
p.ID,
p.CreatedSince,
p.Size,
); err != nil {
return err
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/inspecttypes/dockercompat/dockercompat.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ func ImageFromNative(n *native.Image) (*Image, error) {
ExposedPorts: portSet,
}

i.ID = n.ImageConfigDesc.Digest.String()
i.ID = n.ImageConfigDesc.Digest.String() // Docker ID (digest of config), not containerd ID (digest of index or manifest)

repository, tag := imgutil.ParseRepoTag(n.Image.Name)

Expand Down

0 comments on commit f9eb1e5

Please sign in to comment.