Compare commits
No commits in common. "b87a4d5637bafeadae5e0cae5e0e09269e3f39f3" and "f20218e43a16e4c82ee14a545ebe081d1a27d9d9" have entirely different histories.
b87a4d5637
...
f20218e43a
7 changed files with 37 additions and 1368 deletions
57
README.md
57
README.md
|
@ -11,28 +11,12 @@ different ways, to help you understand what's going on inside the system.
|
||||||
* Download the [latest release](https://github.com/justone/dockviz/releases).
|
* Download the [latest release](https://github.com/justone/dockviz/releases).
|
||||||
* Set up an alias to run it from the (5.8 MB) docker image:
|
* Set up an alias to run it from the (5.8 MB) docker image:
|
||||||
|
|
||||||
```
|
```
|
||||||
# if docker client using local unix socket
|
alias dockviz="docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock nate/dockviz"
|
||||||
alias dockviz="docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock nate/dockviz"
|
```
|
||||||
|
|
||||||
# if docker client using tcp
|
|
||||||
alias dockviz="docker run -it --rm -e DOCKER_HOST='tcp://127.0.0.1:2375' nate/dockviz"
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Visualize images by running `dockviz images -t`, which has similar output to `docker images -t`.
|
2. Visualize images by running `dockviz images -t`, which has similar output to `docker images -t`.
|
||||||
* Image can be visualized as [Graphviz](http://www.graphviz.org), or as a tree or short summary in the terminal. Only Graphviz output has been implemented for containers.
|
|
||||||
* If you would like to visualize outside the container you will have to install [Graphviz](http://www.graphviz.org) first.
|
|
||||||
|
|
||||||
```
|
Image can be visualized as [Graphviz](http://www.graphviz.org), or as a tree or short summary in the terminal. Only Graphviz output has been implemented for containers.
|
||||||
apt-get update && apt-get install graphviz
|
|
||||||
```
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```
|
|
||||||
brew update && brew install graphviz
|
|
||||||
```
|
|
||||||
|
|
||||||
# Output Examples
|
# Output Examples
|
||||||
|
|
||||||
|
@ -41,11 +25,7 @@ brew update && brew install graphviz
|
||||||
Currently, containers are visualized with labelled lines for links. Containers that aren't running are greyed out.
|
Currently, containers are visualized with labelled lines for links. Containers that aren't running are greyed out.
|
||||||
|
|
||||||
```
|
```
|
||||||
# show all containers
|
|
||||||
$ dockviz containers -d | dot -Tpng -o containers.png
|
$ dockviz containers -d | dot -Tpng -o containers.png
|
||||||
|
|
||||||
# only show running containers
|
|
||||||
$ dockviz containers -d -r | dot -Tpng -o containers.png
|
|
||||||
```
|
```
|
||||||
|
|
||||||
![](sample/containers.png "Container")
|
![](sample/containers.png "Container")
|
||||||
|
@ -56,6 +36,8 @@ Image info is visualized with lines indicating parent images:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ dockviz images -d | dot -Tpng -o images.png
|
$ dockviz images -d | dot -Tpng -o images.png
|
||||||
|
OR
|
||||||
|
$ dockviz images --dot | dot -Tpng -o images.png
|
||||||
```
|
```
|
||||||
|
|
||||||
![](sample/images.png "Image")
|
![](sample/images.png "Image")
|
||||||
|
@ -207,15 +189,11 @@ $ dockviz images -t -i -c
|
||||||
└─316b678ddf48 Size: 70822908 Tags: ubuntu:13.04, ubuntu:raring
|
└─316b678ddf48 Size: 70822908 Tags: ubuntu:13.04, ubuntu:raring
|
||||||
```
|
```
|
||||||
|
|
||||||
It is also possible to show the image's CreatedBy field, for help identifying
|
|
||||||
image layers when they show up with "<missing>" image Ids.
|
|
||||||
|
|
||||||
# Running
|
# Running
|
||||||
|
|
||||||
Dockviz supports connecting to the Docker daemon directly. It defaults to `unix:///var/run/docker.sock`, but respects the following as well:
|
Dockviz supports connecting to the Docker daemon directly. It defaults to `unix:///var/run/docker.sock`, but respects the following as well:
|
||||||
|
|
||||||
* The `DOCKER_HOST`, `DOCKER_CERT_PATH`, and `DOCKER_TLS_VERIFY` environment variables, as set up by [boot2docker](http://boot2docker.io/) or [docker-machine](https://docs.docker.com/machine/).
|
* The `DOCKER_HOST`, `DOCKER_CERT_PATH`, and `DOCKER_TLS_VERIFY` environment variables, as set up by [boot2docker](http://boot2docker.io/) or [docker-machine](https://docs.docker.com/machine/).
|
||||||
|
|
||||||
* Command line arguments (e.g. `--tlscacert`), like those that Docker itself supports.
|
* Command line arguments (e.g. `--tlscacert`), like those that Docker itself supports.
|
||||||
|
|
||||||
Dockviz also supports receiving Docker image or container json data on standard input.
|
Dockviz also supports receiving Docker image or container json data on standard input.
|
||||||
|
@ -238,27 +216,6 @@ See the [releases](https://github.com/justone/dockviz/releases) area for binarie
|
||||||
# Build
|
# Build
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# install graphviz in host environment for rendering (Debian example)
|
go get ./...
|
||||||
sudo apt-get install git graphviz -y
|
|
||||||
|
|
||||||
# pull latest code
|
|
||||||
mkdir -p $GOPATH/src/github.com/nate/ && cd $GOPATH/src/github.com/nate/
|
|
||||||
git clone https://github.com/nate/dockviz.git && cd dockviz
|
|
||||||
|
|
||||||
# force static compilation for go language
|
|
||||||
export CGO_ENABLED=0
|
|
||||||
|
|
||||||
# fetch vendored dependencies
|
|
||||||
govendor sync
|
|
||||||
|
|
||||||
# build
|
|
||||||
go build
|
go build
|
||||||
|
|
||||||
# build docker image
|
|
||||||
docker build --no-cache=true -t "nate/dockviz:1.0" -t "nate/dockviz:latest" .
|
|
||||||
|
|
||||||
# push to docker hub
|
|
||||||
docker login --username=mygituser --password=xxxxxxx
|
|
||||||
docker push nate/dockviz
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
2
cli.go
2
cli.go
|
@ -20,7 +20,7 @@ type GlobalOptions struct {
|
||||||
var globalOptions GlobalOptions
|
var globalOptions GlobalOptions
|
||||||
var parser = flags.NewParser(&globalOptions, flags.Default)
|
var parser = flags.NewParser(&globalOptions, flags.Default)
|
||||||
|
|
||||||
var version = "v0.6.4"
|
var version = "v0.5.0"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
globalOptions.Version = func() {
|
globalOptions.Version = func() {
|
||||||
|
|
|
@ -24,7 +24,6 @@ type Container struct {
|
||||||
type ContainersCommand struct {
|
type ContainersCommand struct {
|
||||||
Dot bool `short:"d" long:"dot" description:"Show container information as Graphviz dot."`
|
Dot bool `short:"d" long:"dot" description:"Show container information as Graphviz dot."`
|
||||||
NoTruncate bool `short:"n" long:"no-trunc" description:"Don't truncate the container IDs."`
|
NoTruncate bool `short:"n" long:"no-trunc" description:"Don't truncate the container IDs."`
|
||||||
OnlyRunning bool `short:"r" long:"running" description:"Only show running containers, not Exited"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var containersCommand ContainersCommand
|
var containersCommand ContainersCommand
|
||||||
|
@ -82,7 +81,7 @@ func (x *ContainersCommand) Execute(args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if containersCommand.Dot {
|
if containersCommand.Dot {
|
||||||
fmt.Printf(jsonContainersToDot(containers, containersCommand.OnlyRunning))
|
fmt.Printf(jsonContainersToDot(containers))
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("Please specify --dot")
|
return fmt.Errorf("Please specify --dot")
|
||||||
}
|
}
|
||||||
|
@ -116,53 +115,24 @@ func parseContainersJSON(rawJSON []byte) (*[]Container, error) {
|
||||||
return &containers, nil
|
return &containers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func jsonContainersToDot(containers *[]Container,OnlyRunning bool) string {
|
func jsonContainersToDot(containers *[]Container) string {
|
||||||
|
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
buffer.WriteString("digraph docker {\n")
|
buffer.WriteString("digraph docker {\n")
|
||||||
|
|
||||||
// build list of all primary container names
|
|
||||||
// this is so we can throw away links to
|
|
||||||
// non-primary container name
|
|
||||||
var PrimaryContainerNames map[string]string
|
|
||||||
PrimaryContainerNames = make(map[string]string)
|
|
||||||
for _, container := range *containers {
|
for _, container := range *containers {
|
||||||
for _, name := range container.Names {
|
|
||||||
if strings.Count(name, "/") == 1 {
|
|
||||||
PrimaryContainerNames[name[1:]] = name[1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// stores ony first value of link to avoid duplicates
|
|
||||||
var LinkMap map[string]string
|
|
||||||
LinkMap = make(map[string]string)
|
|
||||||
|
|
||||||
for _, container := range *containers {
|
|
||||||
if OnlyRunning && strings.HasPrefix(container.Status,"Exit") { continue }
|
|
||||||
|
|
||||||
var containerName string
|
var containerName string
|
||||||
|
|
||||||
//fmt.Printf("container status/Names %s/%s\n",container.Status,container.Names)
|
|
||||||
for _, name := range container.Names {
|
for _, name := range container.Names {
|
||||||
if strings.Count(name, "/") == 1 {
|
if strings.Count(name, "/") == 1 {
|
||||||
containerName = name[1:]
|
containerName = name[1:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range container.Names {
|
for _, name := range container.Names {
|
||||||
nameParts := strings.Split(name, "/")
|
nameParts := strings.Split(name, "/")
|
||||||
if len(nameParts) > 2 {
|
if len(nameParts) > 2 {
|
||||||
//fmt.Printf("\t%s to %s\n",containerName,nameParts[1])
|
buffer.WriteString(fmt.Sprintf(" \"%s\" -> \"%s\" [label = \" %s\" ]\n", containerName, nameParts[1], nameParts[len(nameParts)-1]))
|
||||||
// source and dest should be primary container names
|
|
||||||
if IsPrimaryContainerName(containerName,PrimaryContainerNames) && IsPrimaryContainerName(nameParts[1],PrimaryContainerNames) {
|
|
||||||
|
|
||||||
// only create link if none exists already
|
|
||||||
if _,ok := LinkMap[containerName + "-" + nameParts[1]]; !ok {
|
|
||||||
LinkMap[containerName + "-" + nameParts[1]] = "exists"
|
|
||||||
buffer.WriteString(fmt.Sprintf(" \"%s\" -> \"%s\" [label = \" %s\" ]\n", containerName, nameParts[1], nameParts[len(nameParts)-1] ))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,7 +144,7 @@ func jsonContainersToDot(containers *[]Container,OnlyRunning bool) string {
|
||||||
containerBackground = "paleturquoise"
|
containerBackground = "paleturquoise"
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.WriteString(fmt.Sprintf(" \"%s\" [label=\"%s\\n%s\\n%s\",shape=box,fillcolor=\"%s\",style=\"filled,rounded\"];\n", containerName, container.Image, containerName, truncate(container.Id, 12), containerBackground))
|
buffer.WriteString(fmt.Sprintf(" \"%s\" [label=\"%s\\n%s\",shape=box,fillcolor=\"%s\",style=\"filled,rounded\"];\n", containerName, containerName, truncate(container.Id, 12), containerBackground))
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.WriteString("}\n")
|
buffer.WriteString("}\n")
|
||||||
|
@ -182,11 +152,6 @@ func jsonContainersToDot(containers *[]Container,OnlyRunning bool) string {
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsPrimaryContainerName(Name string,PrimaryContainerNames map[string]string) bool {
|
|
||||||
_,ok := PrimaryContainerNames[Name]
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
parser.AddCommand("containers",
|
parser.AddCommand("containers",
|
||||||
"Visualize docker containers.",
|
"Visualize docker containers.",
|
||||||
|
|
41
go.mod
41
go.mod
|
@ -1,41 +0,0 @@
|
||||||
module github.com/justone/dockviz
|
|
||||||
|
|
||||||
go 1.19
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/fsouza/go-dockerclient v1.8.3
|
|
||||||
github.com/jessevdk/go-flags v1.5.0
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
|
||||||
github.com/Microsoft/go-winio v0.6.0 // indirect
|
|
||||||
github.com/Microsoft/hcsshim v0.9.4 // indirect
|
|
||||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
|
||||||
github.com/containerd/cgroups v1.0.4 // indirect
|
|
||||||
github.com/containerd/containerd v1.6.8 // indirect
|
|
||||||
github.com/containerd/continuity v0.3.0 // indirect
|
|
||||||
github.com/docker/docker v20.10.18+incompatible // indirect
|
|
||||||
github.com/docker/go-connections v0.4.0 // indirect
|
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
|
||||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
|
|
||||||
github.com/moby/sys/mount v0.3.3 // indirect
|
|
||||||
github.com/moby/sys/mountinfo v0.6.2 // indirect
|
|
||||||
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect
|
|
||||||
github.com/morikuni/aec v1.0.0 // indirect
|
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
|
||||||
github.com/opencontainers/image-spec v1.1.0-rc1 // indirect
|
|
||||||
github.com/opencontainers/runc v1.1.4 // indirect
|
|
||||||
github.com/opencontainers/selinux v1.10.2 // indirect
|
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
|
||||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
|
||||||
go.opencensus.io v0.23.0 // indirect
|
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
|
||||||
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b // indirect
|
|
||||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
|
|
||||||
golang.org/x/tools v0.1.12 // indirect
|
|
||||||
gotest.tools v2.2.0+incompatible // indirect
|
|
||||||
)
|
|
100
images.go
100
images.go
|
@ -26,21 +26,19 @@ type Image struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImagesCommand struct {
|
type ImagesCommand struct {
|
||||||
Dot bool `short:"d" long:"dot" description:"Show image information as Graphviz dot. You can add a start image id or name -d/--dot [id/name]"`
|
Dot bool `short:"d" long:"dot" description:"Show image information as Graphviz dot. You can add a start image id or name -d/--dot [id/name]"`
|
||||||
Tree bool `short:"t" long:"tree" description:"Show image information as tree. You can add a start image id or name -t/--tree [id/name]"`
|
Tree bool `short:"t" long:"tree" description:"Show image information as tree. You can add a start image id or name -t/--tree [id/name]"`
|
||||||
Short bool `short:"s" long:"short" description:"Show short summary of images (repo name and list of tags)."`
|
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 (only works with tree mode)."`
|
NoTruncate bool `short:"n" long:"no-trunc" description:"Don't truncate the image IDs (only works with tree mode)."`
|
||||||
Incremental bool `short:"i" long:"incremental" description:"Display image size as incremental rather than cumulative."`
|
Incremental bool `short:"i" long:"incremental" description:"Display image size as incremental rather than cumulative."`
|
||||||
OnlyLabelled bool `short:"l" long:"only-labelled" description:"Print only labelled images/containers."`
|
OnlyLabelled bool `short:"l" long:"only-labelled" description:"Print only labelled images/containers."`
|
||||||
ShowCreatedBy bool `long:"show-created-by" description:"Show the image 'CreatedBy' to help identify layers."`
|
NoHuman bool `short:"c" long:"no-human" description:"Don't humanize the sizes."`
|
||||||
NoHuman bool `short:"c" long:"no-human" description:"Don't humanize the sizes."`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type DisplayOpts struct {
|
type DisplayOpts struct {
|
||||||
NoTruncate bool
|
NoTruncate bool
|
||||||
Incremental bool
|
Incremental bool
|
||||||
NoHuman bool
|
NoHuman bool
|
||||||
ShowCreatedBy bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var imagesCommand ImagesCommand
|
var imagesCommand ImagesCommand
|
||||||
|
@ -158,17 +156,16 @@ func (x *ImagesCommand) Execute(args []string) error {
|
||||||
*images, imagesByParent = filterImages(images, &imagesByParent)
|
*images, imagesByParent = filterImages(images, &imagesByParent)
|
||||||
}
|
}
|
||||||
|
|
||||||
dispOpts := DisplayOpts{
|
|
||||||
imagesCommand.NoTruncate,
|
|
||||||
imagesCommand.Incremental,
|
|
||||||
imagesCommand.NoHuman,
|
|
||||||
imagesCommand.ShowCreatedBy,
|
|
||||||
}
|
|
||||||
if imagesCommand.Tree {
|
if imagesCommand.Tree {
|
||||||
|
dispOpts := DisplayOpts{
|
||||||
|
imagesCommand.NoTruncate,
|
||||||
|
imagesCommand.Incremental,
|
||||||
|
imagesCommand.NoHuman,
|
||||||
|
}
|
||||||
fmt.Print(jsonToTree(roots, imagesByParent, dispOpts))
|
fmt.Print(jsonToTree(roots, imagesByParent, dispOpts))
|
||||||
}
|
}
|
||||||
if imagesCommand.Dot {
|
if imagesCommand.Dot {
|
||||||
fmt.Print(jsonToDot(roots, imagesByParent, dispOpts))
|
fmt.Print(jsonToDot(roots, imagesByParent))
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if imagesCommand.Short {
|
} else if imagesCommand.Short {
|
||||||
|
@ -285,11 +282,11 @@ func jsonToTree(images []Image, byParent map[string][]Image, dispOpts DisplayOpt
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func jsonToDot(roots []Image, byParent map[string][]Image, dispOpts DisplayOpts) string {
|
func jsonToDot(roots []Image, byParent map[string][]Image) string {
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
buffer.WriteString("digraph docker {\n")
|
buffer.WriteString("digraph docker {\n")
|
||||||
imagesToDot(&buffer, roots, byParent, dispOpts)
|
imagesToDot(&buffer, roots, byParent)
|
||||||
buffer.WriteString(" base [style=invisible]\n}\n")
|
buffer.WriteString(" base [style=invisible]\n}\n")
|
||||||
|
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
|
@ -402,12 +399,10 @@ func PrintTreeNode(buffer *bytes.Buffer, image Image, dispOpts DisplayOpts, pref
|
||||||
|
|
||||||
buffer.WriteString(fmt.Sprintf("%s%s %s: %s", prefix, imageID, sizeLabel, sizeStr))
|
buffer.WriteString(fmt.Sprintf("%s%s %s: %s", prefix, imageID, sizeLabel, sizeStr))
|
||||||
if image.RepoTags[0] != "<none>:<none>" {
|
if image.RepoTags[0] != "<none>:<none>" {
|
||||||
buffer.WriteString(fmt.Sprintf(" Tags: %s", strings.Join(image.RepoTags, ", ")))
|
buffer.WriteString(fmt.Sprintf(" Tags: %s\n", strings.Join(image.RepoTags, ", ")))
|
||||||
|
} else {
|
||||||
|
buffer.WriteString(fmt.Sprintf("\n"))
|
||||||
}
|
}
|
||||||
if dispOpts.ShowCreatedBy {
|
|
||||||
buffer.WriteString(fmt.Sprintf(" (%s)", SanitizeCommand(image.CreatedBy, 100)))
|
|
||||||
}
|
|
||||||
buffer.WriteString(fmt.Sprintf("\n"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func megabytes(bytes int64) float64 {
|
func megabytes(bytes int64) float64 {
|
||||||
|
@ -462,45 +457,20 @@ func parseImagesJSON(rawJSON []byte) (*[]Image, error) {
|
||||||
return &images, nil
|
return &images, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func imagesToDot(buffer *bytes.Buffer, images []Image, byParent map[string][]Image, dispOpts DisplayOpts) {
|
func imagesToDot(buffer *bytes.Buffer, images []Image, byParent map[string][]Image) {
|
||||||
for _, image := range images {
|
for _, image := range images {
|
||||||
|
|
||||||
if image.ParentId == "" {
|
if image.ParentId == "" {
|
||||||
buffer.WriteString(fmt.Sprintf(" base -> \"%s\" [style=invis]\n", truncate(image.Id, 12)))
|
buffer.WriteString(fmt.Sprintf(" base -> \"%s\" [style=invis]\n", truncate(image.Id, 12)))
|
||||||
} else {
|
} else {
|
||||||
buffer.WriteString(fmt.Sprintf(" \"%s\" -> \"%s\"\n", truncate(image.ParentId, 12), truncate(image.Id, 12)))
|
buffer.WriteString(fmt.Sprintf(" \"%s\" -> \"%s\"\n", truncate(image.ParentId, 12), truncate(image.Id, 12)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if image.RepoTags[0] != "<none>:<none>" {
|
if image.RepoTags[0] != "<none>:<none>" {
|
||||||
buffer.WriteString(fmt.Sprintf(" \"%s\" [label=\"%s\\n%s\",area=%f,shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n", truncate(image.Id, 12), truncate(stripPrefix(image.OrigId), 12), strings.Join(image.RepoTags, "\\n"), megabytes(image.Size)))
|
buffer.WriteString(fmt.Sprintf(" \"%s\" [label=\"%s\\n%s\",area=%f,shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n", truncate(image.Id, 12), truncate(stripPrefix(image.OrigId), 12), strings.Join(image.RepoTags, "\\n"), megabytes(image.Size)))
|
||||||
} else {
|
} else {
|
||||||
labelParts := []string{truncate(stripPrefix(image.OrigId), 12)}
|
buffer.WriteString(fmt.Sprintf(" \"%s\" [label=\"%s\",area=%f]\n", truncate(image.Id, 12), truncate(stripPrefix(image.OrigId), 12), megabytes(image.Size)))
|
||||||
if dispOpts.ShowCreatedBy {
|
|
||||||
labelParts = append(labelParts, SanitizeCommand(image.CreatedBy, 30))
|
|
||||||
}
|
|
||||||
|
|
||||||
var size int64
|
|
||||||
var sizeLabel string
|
|
||||||
if dispOpts.Incremental {
|
|
||||||
sizeLabel = "Size"
|
|
||||||
size = image.Size
|
|
||||||
} else {
|
|
||||||
sizeLabel = "Virtual Size"
|
|
||||||
size = image.VirtualSize
|
|
||||||
}
|
|
||||||
|
|
||||||
var sizeStr string
|
|
||||||
if dispOpts.NoHuman {
|
|
||||||
sizeStr = strconv.FormatInt(size, 10)
|
|
||||||
} else {
|
|
||||||
sizeStr = humanSize(size)
|
|
||||||
}
|
|
||||||
labelParts = append(labelParts, fmt.Sprintf("%s: %s", sizeLabel, sizeStr))
|
|
||||||
|
|
||||||
buffer.WriteString(fmt.Sprintf(" \"%s\" [label=\"%s\",area=%f]\n", truncate(image.Id, 12), strings.Join(labelParts, "\n"), megabytes(image.Size)))
|
|
||||||
}
|
}
|
||||||
if subimages, exists := byParent[image.Id]; exists {
|
if subimages, exists := byParent[image.Id]; exists {
|
||||||
imagesToDot(buffer, subimages, byParent, dispOpts)
|
imagesToDot(buffer, subimages, byParent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -536,28 +506,6 @@ func jsonToShort(images *[]Image) string {
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func SanitizeCommand(CommandStr string, MaxLength int) string {
|
|
||||||
|
|
||||||
temp := CommandStr
|
|
||||||
|
|
||||||
// remove prefixes that don't add meaning
|
|
||||||
if strings.HasPrefix(temp, "/bin/sh -c") {
|
|
||||||
temp = strings.TrimSpace(temp[10:])
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(temp, "#(nop)") {
|
|
||||||
temp = strings.TrimSpace(temp[6:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove double and single quotes which make dot format invalid
|
|
||||||
temp = strings.Replace(temp, "\"", " ", -1)
|
|
||||||
temp = strings.Replace(temp, "'", " ", -1)
|
|
||||||
|
|
||||||
// remove double spaces inside
|
|
||||||
temp = strings.Join(strings.Fields(temp), " ")
|
|
||||||
|
|
||||||
return truncate(temp, MaxLength)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
parser.AddCommand("images",
|
parser.AddCommand("images",
|
||||||
"Visualize docker images.",
|
"Visualize docker images.",
|
||||||
|
|
63
release.sh
63
release.sh
|
@ -1,63 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
ORG=justone
|
|
||||||
NAME=dockviz
|
|
||||||
ARCHS="darwin/amd64 linux/amd64 windows/amd64"
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
if [[ ! $(type -P gox) ]]; then
|
|
||||||
echo "Error: gox not found."
|
|
||||||
echo "To fix: run 'go get github.com/mitchellh/gox', and/or add \$GOPATH/bin to \$PATH"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z $GITHUB_TOKEN ]]; then
|
|
||||||
echo "Error: GITHUB_TOKEN not set."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $(type -P github-release) ]]; then
|
|
||||||
echo "Error: github-release not found."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
VER=$1
|
|
||||||
|
|
||||||
if [[ -z $VER ]]; then
|
|
||||||
echo "Need to specify version."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
PRE_ARG=
|
|
||||||
if [[ $VER =~ pre ]]; then
|
|
||||||
PRE_ARG="--pre-release"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# git tag $VER
|
|
||||||
|
|
||||||
echo "Building $VER"
|
|
||||||
echo
|
|
||||||
|
|
||||||
rm -v ${NAME}* || true
|
|
||||||
gox -ldflags "-X main.version=$VER" -osarch="$ARCHS"
|
|
||||||
|
|
||||||
echo "* " > desc
|
|
||||||
echo "" >> desc
|
|
||||||
|
|
||||||
echo "\`\`\`" >> desc
|
|
||||||
echo "$ sha1sum ${NAME}_*" >> desc
|
|
||||||
sha1sum ${NAME}_* >> desc
|
|
||||||
echo "$ sha256sum ${NAME}_*" >> desc
|
|
||||||
sha256sum ${NAME}_* >> desc
|
|
||||||
echo "\`\`\`" >> desc
|
|
||||||
|
|
||||||
vi desc
|
|
||||||
|
|
||||||
git push --tags
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
cat desc | github-release release $PRE_ARG --user ${ORG} --repo ${NAME} --tag $VER --name $VER --description -
|
|
||||||
for file in ${NAME}_*; do
|
|
||||||
github-release upload --user ${ORG} --repo ${NAME} --tag $VER --name $file --file $file
|
|
||||||
done
|
|
Loading…
Reference in a new issue