add short summary for docker images
This commit is contained in:
parent
8023909dbb
commit
ced348b87c
3 changed files with 74 additions and 2 deletions
10
README.md
10
README.md
|
@ -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:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
36
images.go
36
images.go
|
@ -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.",
|
||||||
|
|
|
@ -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{}
|
||||||
|
|
Loading…
Reference in a new issue