add short summary for docker images

This commit is contained in:
Nate Jones 2015-02-26 21:06:24 -08:00
parent 8023909dbb
commit ced348b87c
3 changed files with 74 additions and 2 deletions

View file

@ -5,7 +5,7 @@ Visualizing Docker Data
This command takes the raw Docker JSON and visualizes it in various ways. This command takes the raw Docker JSON and visualizes it in various ways.
For image information, output can be formatted as For image information, output can be formatted as
[Graphviz](http://www.graphviz.org) or as a tree in the terminal. [Graphviz](http://www.graphviz.org), as a tree in the terminal, or in a short summary.
For container information, only Graphviz output has been implemented. For container information, only Graphviz output has been implemented.
@ -23,6 +23,14 @@ Image info is visualized with lines indicating parent images:
![](sample/images.png "Image") ![](sample/images.png "Image")
Or in short form:
```
nate/mongodb: latest
redis: latest
ubuntu: 12.04, precise, 12.10, quantal, 13.04, raring
```
Or as a tree in the terminal: Or as a tree in the terminal:
``` ```

View file

@ -21,6 +21,7 @@ type Image struct {
type ImagesCommand struct { type ImagesCommand struct {
Dot bool `short:"d" long:"dot" description:"Show image information as Graphviz dot."` Dot bool `short:"d" long:"dot" description:"Show image information as Graphviz dot."`
Tree bool `short:"t" long:"tree" description:"Show image information as tree."` Tree bool `short:"t" long:"tree" description:"Show image information as tree."`
Short bool `short:"s" long:"short" description:"Show short summary of images (repo name and list of tags)."`
NoTruncate bool `short:"n" long:"no-trunc" description:"Don't truncate the image IDs."` NoTruncate bool `short:"n" long:"no-trunc" description:"Don't truncate the image IDs."`
} }
@ -49,8 +50,10 @@ func (x *ImagesCommand) Execute(args []string) error {
} }
fmt.Printf(jsonToTree(images, startImageArg, imagesCommand.NoTruncate)) fmt.Printf(jsonToTree(images, startImageArg, imagesCommand.NoTruncate))
} else if imagesCommand.Short {
fmt.Printf(jsonToShort(images))
} else { } else {
return fmt.Errorf("Please specify either --dot or --tree") return fmt.Errorf("Please specify either --dot, --tree, or --short")
} }
return nil return nil
@ -193,6 +196,37 @@ func jsonToDot(images *[]Image) string {
return buffer.String() return buffer.String()
} }
func jsonToShort(images *[]Image) string {
var buffer bytes.Buffer
var byRepo = make(map[string][]string)
for _, image := range *images {
for _, repotag := range image.RepoTags {
if repotag != "<none>:<none>" {
// parse the repo name and tag name out
// tag is after the last colon
lastColonIndex := strings.LastIndex(repotag, ":")
tagname := repotag[lastColonIndex+1:]
reponame := repotag[0:lastColonIndex]
if tags, exists := byRepo[reponame]; exists {
byRepo[reponame] = append(tags, tagname)
} else {
byRepo[reponame] = []string{tagname}
}
}
}
}
for repo, tags := range byRepo {
buffer.WriteString(fmt.Sprintf("%s: %s\n", repo, strings.Join(tags, ", ")))
}
return buffer.String()
}
func init() { func init() {
parser.AddCommand("images", parser.AddCommand("images",
"Visualize docker images.", "Visualize docker images.",

View file

@ -10,6 +10,11 @@ type DotTest struct {
regexps []string regexps []string
} }
type ShortTest struct {
json string
regexps []string
}
type TreeTest struct { type TreeTest struct {
json string json string
startImage string startImage string
@ -114,6 +119,31 @@ func Test_Tree(t *testing.T) {
} }
} }
func Test_Short(t *testing.T) {
shortJSON := `[ { "VirtualSize": 662553464, "Size": 0, "RepoTags": [ "foo:latest" ], "ParentId": "735f5db5626147582d2ae3f2c87be8e5e697c088574c5faaf8d4d1bccab99470", "Id": "c87be8e5e697c735f5db5626147582d2ae3f2088574c5faaf8d4d1bccab99470", "Created": 1386142123 }, { "VirtualSize": 682553464, "Size": 0, "RepoTags": [ "foo:1.0" ], "ParentId": "4c1208b690c68af3476b437e7bc2bcc460f062bda2094d2d8f21a7e70368d358", "Id": "626147582d2ae3735f5db5f2c87be8e5e697c088574c5faaf8d4d1bccab99470", "Created": 1386142123 }, { "VirtualSize": 712553464, "Size": 0, "RepoTags": [ "foo:2.0" ], "ParentId": "626147582d2ae3735f5db5f2c87be8e5e697c088574c5faaf8d4d1bccab99470", "Id": "574c5faaf8d4d1bccab994626147582d2ae3735f5db5f2c87be8e5e697c08870", "Created": 1386142123 }, { "VirtualSize": 752553464, "Size": 0, "RepoTags": [ "private.repo.com:5000:latest" ], "ParentId": "574c5faaf8d4d1bccab994626147582d2ae3735f5db5f2c87be8e5e697c08870", "Id": "aaf8d4d1bccab994574c5f626147582d2ae3735f5db5f2c87be8e5e697c08870", "Created": 1386142123 }, { "VirtualSize": 662553464, "Size": 0, "RepoTags": [ "<none>:<none>" ], "ParentId": "4c1208b690c68af3476b437e7bc2bcc460f062bda2094d2d8f21a7e70368d358", "Id": "735f5db5626147582d2ae3f2c87be8e5e697c088574c5faaf8d4d1bccab99470", "Created": 1386142123 }, { "VirtualSize": 662553464, "Size": 662553464, "RepoTags": [ "<none>:<none>" ], "ParentId": "", "Id": "4c1208b690c68af3476b437e7bc2bcc460f062bda2094d2d8f21a7e70368d358", "Created": 1386114144 } ]`
shortTests := []ShortTest{
ShortTest{
json: shortJSON,
regexps: []string{
`(?m)foo: latest, 1.0, 2.0`,
`(?m)private.repo.com:5000: latest`,
},
},
}
for _, shortTest := range shortTests {
im, _ := parseImagesJSON([]byte(shortTest.json))
result := jsonToShort(im)
for _, regexp := range compileRegexps(t, shortTest.regexps) {
if !regexp.MatchString(result) {
t.Fatalf("images short content '%s' did not match regexp '%s'", result, regexp)
}
}
}
}
func compileRegexps(t *testing.T, regexpStrings []string) []*regexp.Regexp { func compileRegexps(t *testing.T, regexpStrings []string) []*regexp.Regexp {
compiledRegexps := []*regexp.Regexp{} compiledRegexps := []*regexp.Regexp{}