Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

graphviz intergration #25

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,17 @@ $ depth -json github.com/KyleBanks/depth/cmd/depth
}
```

#### `-graph`

The `-graph` flag instructs `depth` to render the dependencies into a png file using graphviz

```sh
$ depth -graph github.com/KyleBanks/depth/cmd/depth
```

![graph.png](graph.png)


### Integrating With Your Project

The `depth` package can easily be used to retrieve the dependency tree for a particular package in your own project. For example, here's how you would retrieve the dependency tree for the `strings` package:
Expand Down
92 changes: 90 additions & 2 deletions cmd/depth/depth.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package main

import (
"bytes"
"encoding/json"
"flag"
"fmt"
"github.com/goccy/go-graphviz"
"io"
"log"
"os"
"strings"

Expand All @@ -20,6 +23,7 @@ const (

var outputJSON bool
var explainPkg string
var outputGraph bool

type summary struct {
numInternal int
Expand All @@ -29,7 +33,7 @@ type summary struct {

func main() {
t, pkgs := parse(os.Args[1:])
if err := handlePkgs(t, pkgs, outputJSON, explainPkg); err != nil {
if err := handlePkgs(t, pkgs, outputJSON, explainPkg, outputGraph); err != nil {
os.Exit(1)
}
}
Expand All @@ -45,14 +49,15 @@ func parse(args []string) (*depth.Tree, []string) {
f.IntVar(&t.MaxDepth, "max", 0, "Sets the maximum depth of dependencies to resolve.")
f.BoolVar(&outputJSON, "json", false, "If set, outputs the depencies in JSON format.")
f.StringVar(&explainPkg, "explain", "", "If set, show which packages import the specified target")
f.BoolVar(&outputGraph, "graph", false, "If set, renders the dependencies in a graph and outputs as a png file")
f.Parse(args)

return &t, f.Args()
}

// handlePkgs takes a slice of package names, resolves a Tree on them,
// and outputs each Tree to Stdout.
func handlePkgs(t *depth.Tree, pkgs []string, outputJSON bool, explainPkg string) error {
func handlePkgs(t *depth.Tree, pkgs []string, outputJSON bool, explainPkg string, outputGraph bool) error {
for _, pkg := range pkgs {

err := t.Resolve(pkg)
Expand All @@ -71,6 +76,11 @@ func handlePkgs(t *depth.Tree, pkgs []string, outputJSON bool, explainPkg string
continue
}

if outputGraph {
generateGraph(*t.Root)
continue
}

writePkg(os.Stdout, *t.Root)
writePkgSummary(os.Stdout, *t.Root)
}
Expand Down Expand Up @@ -161,3 +171,81 @@ func writeExplain(w io.Writer, pkg depth.Pkg, stack []string, explain string) {
writeExplain(w, p, stack, explain)
}
}

// generateGraph creates a node graph and renders it as a file
func generateGraph(pkg depth.Pkg) {

//adjacency list
adjlist := make(map[string][]string)
for _, p := range pkg.Deps {

_, parentok := adjlist[p.Parent.Name]
if !parentok {
adjlist[p.Parent.Name] = make([]string, 0)
}
adjlist[p.Parent.Name] = append(adjlist[p.Parent.Name], p.Name)

_, ok := adjlist[p.Name]
if !ok {
adjlist[p.Name] = make([]string, 0)
}

generateGraphRec(p, p.Name, adjlist)
}

g := graphviz.New()
graph, err := g.Graph()

defer func() {
if err := graph.Close(); err != nil {
log.Fatal(err)
}
g.Close()
}()

if err != nil {
log.Fatal(err)
}

for parent, children := range adjlist {
n, err := graph.CreateNode(parent)
if err != nil {
log.Fatal(err)
}

for _, child := range children {
c, err := graph.CreateNode(child)
if err != nil {
log.Fatal(err)
}

_, err = graph.CreateEdge("", n, c)
if err != nil {
log.Fatal(err)
}

}
}

var buf bytes.Buffer
if err := g.Render(graph, "dot", &buf); err != nil {
log.Fatal(err)
}

if err := g.RenderFilename(graph, graphviz.PNG, "graph.png"); err != nil {
log.Fatal(err)
}
}

func generateGraphRec(pkg depth.Pkg, parent string, adjlist map[string][]string) {

for _, p := range pkg.Deps {
_, ok := adjlist[p.Name]
if !ok {
adjlist[p.Name] = make([]string, 0)
}

adjlist[parent] = append(adjlist[parent], p.Name)
generateGraphRec(p, p.Name, adjlist)
}
}
Binary file added graph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.