This repository was archived by the owner on Sep 9, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1k
Dep status tree visualisation dot output #271
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
a7c6fa8
Children field in BasicStatus struct to store child data for tree/gra…
Rhymond 1aa5000
Merge branch 'master' of https://github.com/golang/dep into status_pr…
Rhymond a70afb5
Create graphiv (dot) package
Rhymond 80d8fc2
Whitespace
Rhymond 08e23ec
Merge branch 'master' of https://github.com/golang/dep into dot_output
Rhymond 408c3aa
remove not used errorf
Rhymond 3ff1f50
go imports
Rhymond 5d3174f
Graphviz code moved from status.go to graphviz.go
Rhymond 20fcfef
Remove incorect comment
Rhymond 5427779
Transfer and use isPathPrefixOrEqual for checking if string is matchi…
Rhymond 70d8108
Merge branch 'master' of https://github.com/golang/dep into dot_output
Rhymond 1a64b30
Test cases for graphviz
Rhymond b519dfa
Rename expected to want
Rhymond 7fa0203
Change gps -> pkgtree
Rhymond File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// Copyright 2016 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package main | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"hash/fnv" | ||
"strings" | ||
) | ||
|
||
type graphviz struct { | ||
ps []*gvnode | ||
b bytes.Buffer | ||
h map[string]uint32 | ||
} | ||
|
||
type gvnode struct { | ||
project string | ||
version string | ||
children []string | ||
} | ||
|
||
func (g graphviz) New() *graphviz { | ||
ga := &graphviz{ | ||
ps: []*gvnode{}, | ||
h: make(map[string]uint32), | ||
} | ||
return ga | ||
} | ||
|
||
func (g graphviz) output() bytes.Buffer { | ||
g.b.WriteString("digraph {\n\tnode [shape=box];") | ||
|
||
for _, gvp := range g.ps { | ||
// Create node string | ||
g.b.WriteString(fmt.Sprintf("\n\t%d [label=\"%s\"];", gvp.hash(), gvp.label())) | ||
} | ||
|
||
// Store relations to avoid duplication | ||
rels := make(map[string]bool) | ||
|
||
// Create relations | ||
for _, dp := range g.ps { | ||
for _, bsc := range dp.children { | ||
for pr, hsh := range g.h { | ||
if isPathPrefix(bsc, pr) { | ||
r := fmt.Sprintf("\n\t%d -> %d", g.h[dp.project], hsh) | ||
|
||
if _, ex := rels[r]; !ex { | ||
g.b.WriteString(r + ";") | ||
rels[r] = true | ||
} | ||
|
||
} | ||
} | ||
} | ||
} | ||
|
||
g.b.WriteString("\n}") | ||
return g.b | ||
} | ||
|
||
func (g *graphviz) createNode(project, version string, children []string) { | ||
pr := &gvnode{ | ||
project: project, | ||
version: version, | ||
children: children, | ||
} | ||
|
||
g.h[pr.project] = pr.hash() | ||
g.ps = append(g.ps, pr) | ||
} | ||
|
||
func (dp gvnode) hash() uint32 { | ||
h := fnv.New32a() | ||
h.Write([]byte(dp.project)) | ||
return h.Sum32() | ||
} | ||
|
||
func (dp gvnode) label() string { | ||
label := []string{dp.project} | ||
|
||
if dp.version != "" { | ||
label = append(label, dp.version) | ||
} | ||
|
||
return strings.Join(label, "\\n") | ||
} | ||
|
||
// isPathPrefix ensures that the literal string prefix is a path tree match and | ||
// guards against possibilities like this: | ||
// | ||
// github.com/sdboyer/foo | ||
// github.com/sdboyer/foobar/baz | ||
// | ||
// Verify that prefix is path match and either the input is the same length as | ||
// the match (in which case we know they're equal), or that the next character | ||
// is a "/". (Import paths are defined to always use "/", not the OS-specific | ||
// path separator.) | ||
func isPathPrefix(path, pre string) bool { | ||
pathlen, prflen := len(path), len(pre) | ||
if pathlen < prflen || path[0:prflen] != pre { | ||
return false | ||
} | ||
|
||
return prflen == pathlen || strings.Index(path[prflen:], "/") == 0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// Copyright 2016 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package main | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/golang/dep/test" | ||
) | ||
|
||
func TestEmptyProject(t *testing.T) { | ||
g := new(graphviz).New() | ||
h := test.NewHelper(t) | ||
defer h.Cleanup() | ||
|
||
b := g.output() | ||
want := h.GetTestFileString("graphviz/empty.dot") | ||
|
||
if b.String() != want { | ||
t.Fatalf("expected '%v', got '%v'", want, b.String()) | ||
} | ||
} | ||
|
||
func TestSimpleProject(t *testing.T) { | ||
g := new(graphviz).New() | ||
h := test.NewHelper(t) | ||
defer h.Cleanup() | ||
|
||
g.createNode("project", "", []string{"foo", "bar"}) | ||
g.createNode("foo", "master", []string{"bar"}) | ||
g.createNode("bar", "dev", []string{}) | ||
|
||
b := g.output() | ||
want := h.GetTestFileString("graphviz/case1.dot") | ||
if b.String() != want { | ||
t.Fatalf("expected '%v', got '%v'", want, b.String()) | ||
} | ||
} | ||
|
||
func TestNoLinks(t *testing.T) { | ||
g := new(graphviz).New() | ||
h := test.NewHelper(t) | ||
defer h.Cleanup() | ||
|
||
g.createNode("project", "", []string{}) | ||
|
||
b := g.output() | ||
want := h.GetTestFileString("graphviz/case2.dot") | ||
if b.String() != want { | ||
t.Fatalf("expected '%v', got '%v'", want, b.String()) | ||
} | ||
} | ||
|
||
func TestIsPathPrefix(t *testing.T) { | ||
tcs := []struct { | ||
path string | ||
pre string | ||
want bool | ||
}{ | ||
{"github.com/sdboyer/foo/bar", "github.com/sdboyer/foo", true}, | ||
{"github.com/sdboyer/foobar", "github.com/sdboyer/foo", false}, | ||
{"github.com/sdboyer/bar/foo", "github.com/sdboyer/foo", false}, | ||
{"golang.org/sdboyer/bar/foo", "github.com/sdboyer/foo", false}, | ||
{"golang.org/sdboyer/FOO", "github.com/sdboyer/foo", false}, | ||
} | ||
|
||
for _, tc := range tcs { | ||
r := isPathPrefix(tc.path, tc.pre) | ||
if tc.want != r { | ||
t.Fatalf("expected '%v', got '%v'", tc.want, r) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
digraph { | ||
node [shape=box]; | ||
4106060478 [label="project"]; | ||
2851307223 [label="foo\nmaster"]; | ||
1991736602 [label="bar\ndev"]; | ||
4106060478 -> 2851307223; | ||
4106060478 -> 1991736602; | ||
2851307223 -> 1991736602; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
digraph { | ||
node [shape=box]; | ||
4106060478 [label="project"]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
digraph { | ||
node [shape=box]; | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's some filtering that needs to be done here. Simply calling
Flatten
will get you the imports of ALL the packages in a ptree. We need only the subset of imports that come from the packages we're actually importing from a project.The lock should contain the imported package list for each project, though, so this shouldn't be that bad to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sdboyer we are doing some sort of "filtering".
https://github.com/golang/dep/pull/271/files#diff-0d223b461ecb49bf384a2c75a3893558R51
When we are generating Graphviz nodes we are only working with packages which are presented in the lock in this way we're excluding other packages.