Skip to content

Commit

Permalink
Tree implementation for podman images
Browse files Browse the repository at this point in the history
Signed-off-by: Kunal Kushwaha <[email protected]>
  • Loading branch information
kunalkushwaha committed Oct 17, 2018
1 parent 2c4f3d6 commit 6bb59b5
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 1 deletion.
1 change: 1 addition & 0 deletions cmd/podman/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var (
rmImageCommand,
saveCommand,
tagCommand,
treeCommand,
}

imageDescription = "Manage images"
Expand Down
2 changes: 1 addition & 1 deletion cmd/podman/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"fmt"
"log/syslog"
"os"
"os/exec"
"runtime/pprof"
Expand All @@ -17,7 +18,6 @@ import (
"github.com/sirupsen/logrus"
lsyslog "github.com/sirupsen/logrus/hooks/syslog"
"github.com/urfave/cli"
"log/syslog"
)

// This is populated by the Makefile from the VERSION file
Expand Down
53 changes: 53 additions & 0 deletions cmd/podman/tree.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package main

import (
"context"
"fmt"

"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/pkg/errors"
"github.com/urfave/cli"
)

var (
treeDescription = "Displays the dependent layers of an image. The information is printed in tree format"

treeCommand = cli.Command{
Name: "tree",
Usage: "Show dependent layers of a specified image in tree format",
Description: treeDescription,
Action: treeCmd,
ArgsUsage: "",
UseShortOptionHandling: true,
}
)

func treeCmd(c *cli.Context) error {

runtime, err := libpodruntime.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)

args := c.Args()
if len(args) == 0 {
return errors.Errorf("an image name must be specified")
}
if len(args) > 1 {
return errors.Errorf("podman tree takes at most 1 argument")
}

image, err := runtime.ImageRuntime().NewFromLocal(args[0])
if err != nil {
return err
}

out, err := image.Tree(context.Background())
if err != nil {
return errors.Wrapf(err, "error getting dependencies of image %q", image.InputName)
}
fmt.Println(out)

return nil
}
1 change: 1 addition & 0 deletions docs/podman-image.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ The image command allows you to manage images
| rm | [podman-rm(1)](podman-rmi.1.md) | Removes one or more locally stored images. |
| save | [podman-save(1)](podman-save.1.md) | Save an image to docker-archive or oci. |
| tag | [podman-tag(1)](podman-tag.1.md) | Add an additional name to a local image. |
| tree | [podman-tree(1)](podman-tree.1.md) | Show dependent layers of a specified image in tree format |

## SEE ALSO
podman
33 changes: 33 additions & 0 deletions docs/podman-tree.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
% podman-tree "1"

## NAME
podman\-tree - Show dependent layers of a specified image in tree format

## SYNOPSIS
**podman tree** [*image*:*tag*]**|**[*image-id*]
[**--help**|**-h**]

## DESCRIPTION
Displays the dependent layers of an image. The information is printed in tree format.
If you do not provide *tag*, podman will default to `latest` for the *image*.

## OPTIONS

**--help**, **-h**

Print usage statement

## EXAMPLES

```
$ podman tree fedora:latest
$ podman tree 243d869d10ea
```


## SEE ALSO
podman(1), crio(8)

## HISTORY
Oct 2018, Originally compiled by Kunal Kushwaha <[email protected]>
61 changes: 61 additions & 0 deletions libpod/image/image.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package image

import (
"bytes"
"context"
"encoding/json"
"fmt"
Expand All @@ -25,6 +26,7 @@ import (
"github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
"github.com/containers/storage/pkg/reexec"
"github.com/docker/go-units"
"github.com/opencontainers/go-digest"
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
Expand Down Expand Up @@ -1075,3 +1077,62 @@ func (i *Image) Comment(ctx context.Context, manifestType string) (string, error
}
return ociv1Img.History[0].Comment, nil
}

// Tree gets dependencies of image
func (i *Image) Tree(ctx context.Context) (*bytes.Buffer, error) {
treeDepth := 1
rootImage := i

//Traverse to the root(base) image
parent, err := i.GetParent()
if err != nil {
return nil, err
}

for parent != nil {
rootImage = parent
parent, err = parent.GetParent()
if err != nil {
break
}
treeDepth++
}

var buffer bytes.Buffer
//Print all subtree(peers) to the depth of input image
err = printSubTree(&buffer, rootImage, 0, "└─ ", treeDepth)

return &buffer, err
}

func printSubTree(buffer *bytes.Buffer, root *Image, rootSize uint64, prefix string, treeDepth int) error {
if treeDepth == 0 {
return nil
}
size, err := root.Size(context.Background())
if err != nil {
return err
}
//Size of current layer will be current layer size minus upper layer
buffer.WriteString(fmt.Sprintf("%s ID: %s Tags: %v VirtualSize: %s\n",
prefix,
root.ID()[:12],
root.Names(),
units.HumanSizeWithPrecision(float64(*size-rootSize), 4)),
)

children, err := root.GetChildren()
if err != nil {
return nil
}

for _, child := range children {
img, err := root.imageruntime.getImage(child)
if err != nil {
break
}
nextPrefix := " "
printSubTree(buffer, img, *size, nextPrefix+prefix, treeDepth-1)
}
return nil
}

0 comments on commit 6bb59b5

Please sign in to comment.