-
Notifications
You must be signed in to change notification settings - Fork 1k
Dep status tree visualisation dot output #271
Conversation
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.
Great first steps, thanks for doing this! A few things to work through before we can merge.
cmd/dep/status.go
Outdated
@@ -49,6 +55,7 @@ func (cmd *statusCommand) Register(fs *flag.FlagSet) { | |||
fs.BoolVar(&cmd.detailed, "detailed", false, "report more detailed status") | |||
fs.BoolVar(&cmd.json, "json", false, "output in JSON format") | |||
fs.StringVar(&cmd.template, "f", "", "output in text/template format") | |||
fs.StringVar(&cmd.output, "o", "output.svg", "output file") |
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.
Instead of -o
, let's have -dot
, then simply compute dot output as a string and print that to stdout. That'll be much more flexible for end-users.
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.
If we are only printing dot output to stdout this parameter is not necessary
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.
It is necessary - we're not printing dot output in the default case. The parameter is needed to indicate that dot output is desired. (So, a bool
instead of a string
)
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.
-dot
flag was in the code before: https://github.com/golang/dep/blob/master/cmd/dep/status.go#L52
This is a newly created flag for saving generated dot
string into the file which is not necessary if we're stdout string
now.
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.
Hah, so it was. That was in our spec, but we never actually implemented it, so I figured it wasn't there. Didn't bother to check!
So then, yes, it's simply a matter of dropping the -o
param you added.
cmd/dep/status.go
Outdated
@@ -150,6 +158,123 @@ func (out *jsonOutput) MissingFooter() { | |||
json.NewEncoder(out.w).Encode(out.missing) | |||
} | |||
|
|||
type dotProject struct { |
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.
I think everything related to generating graphviz output could be safely put into its own, separate file - graphviz.go
cmd/dep/status.go
Outdated
out.bsh[dp.project] = dp.hash() | ||
|
||
// Create name boxes, and name them using hashes | ||
// to avoid encoding name conflicts |
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.
nit: either use just a couple clarifying words, or a complete sentence (including a period) in comments, please
cmd/dep/status.go
Outdated
fmt.Printf("%v", err) | ||
} | ||
|
||
defer syscall.Unlink(tf.Name()) |
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.
This should all go away when switching to just printing to stdout instead of a tmp file, but for future - os.Remove
is the call to make here.
cmd/dep/status.go
Outdated
switch out.(type) { | ||
case *dotOutput: | ||
r := filepath.Join(p.AbsRoot, "vendor", string(proj.Ident().ProjectRoot)) | ||
ptr, err := gps.ListPackages(r, string(proj.Ident().ProjectRoot)) |
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.
Instead of reading from vendor
here, use a SourceManager
's version of ListPackages()
. That'll take care of ensuring the files are present, unmodified, and at the right version (which you'll have to pass in). At some point, it'll also get caching for free, too.
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.
Also, side note - by placing this within the branch of the if where the memo matches, we create a potentially confusing situation for users where they ask for dot output, but just don't get if the memos don't match. I'm undecided if it's out of scope to handle in this PR, but if we don't, then we need a follow-up issue.
} | ||
|
||
prm, _ := ptr.ToReachMap(true, false, false, nil) | ||
bs.Children = prm.Flatten(false) |
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.
bump |
Hi @sdboyer, Sorry for late response and Thanks for review. |
We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for the commit author(s). If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google. |
Please rebase instead of merging when catching up with the mainline. |
CLAs look good, thanks! |
(And please rewrite the history to remove that merge commit, 4275dd0, which should be unnecessary post-rebase) |
@Rhymond let me know if I can help. |
@sdboyer merge commit was removed |
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.
Sorry for slow review, very busy week. Almost there, I think - just one bug to fix!
cmd/dep/graphviz.go
Outdated
for _, dp := range g.ps { | ||
for _, bsc := range dp.children { | ||
for pr, hsh := range g.h { | ||
if strings.HasPrefix(bsc, pr) { |
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 a small bug here. We need to check not only that there's a prefix match, but that the next character in the bsc
is a slash. This comes up a lot in this problem space; there's an (unexported) helper for it in gps. It'd probably be fine to just copy the func over to here - though if you do, please adjust comments accordingly.
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.
Thanks!
Is status.go correct place for isPathPrefixOrEqual
or it should be in graphviz.go?
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.
Let's keep it as a helper just in graphviz.go for now. If/when we see wider use for it, we can move it into a more general location.
Oh, also looks like Travis is complaining about some |
Fixed |
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.
Couple nits, rearrangements.
Also, I think we need some tests for this. It'd be fine to limit the tests just to the graphviz
type - no need to mock up a real project for it to analyze.
cmd/dep/graphviz.go
Outdated
@@ -91,3 +91,24 @@ func (dp gvnode) label() string { | |||
|
|||
return strings.Join(label, "\n") | |||
} | |||
|
|||
// Ensure that the literal string prefix is a path tree match and |
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.
Even though this isn't exported, it should follow the Go standard of having the comment block begin with the func name.
cmd/dep/graphviz.go
Outdated
// Verify that 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 isPathPrefixOrEqual(pre, path string) bool { |
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.
Now that I'm looking at this here, I realize the change in parameter order is terrible. Let's flip them so that it's the same as strings.HasPrefix() - string first, prefix second.
cmd/dep/graphviz.go
Outdated
@@ -48,7 +48,7 @@ func (g graphviz) output() bytes.Buffer { | |||
for _, dp := range g.ps { | |||
for _, bsc := range dp.children { | |||
for pr, hsh := range g.h { | |||
if strings.HasPrefix(bsc, pr) { | |||
if strings.HasPrefix(bsc, pr) && isPathPrefixOrEqual(pr, bsc) { |
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.
I was imagining this as a standalone implementation - move the strings.HasPrefix()
call inside isPathPrefixOrEqual
, rather than requiring two calls out here.
cmd/dep/graphviz.go
Outdated
return false | ||
} | ||
|
||
// we assume something else (a trie) has done equality check up to the point |
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.
This comment should go away when strings.HasPrefix()
moves into the func.
Hi, sorry for late response. |
Removed strings.HasPrefix() usage
Hi @sdboyer, |
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.
just two tiny things 😄
cmd/dep/graphviz.go
Outdated
// path separator.) | ||
func isPathPrefix(path, pre string) bool { | ||
pathlen, prflen := len(path), len(pre) | ||
if pathlen < prflen || path[0:prflen] != pre || pathlen == prflen+1 { |
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.
That last check, pathlen == prflen+1
, was useful because the use pattern in gps guaranteed that trailing slashes were not a possibility on the path
input. Does the same apply here? If not, we should drop that check.
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.
Yes you're right, it's unnecessary check, because there is no possibilities to have trailing slashes in manifest either in imports.
cmd/dep/graphviz_test.go
Outdated
defer h.Cleanup() | ||
|
||
b := g.output() | ||
expected := h.GetTestFileString("graphviz/empty.dot") |
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.
nit: use want
instead of expected
Remove unnecessary check IsPathPrefix()
looks like it needs a rebase. |
OK, I think we're finally ready to merge this in. Thanks so much! |
Dep status tree visualisation dot output
Couple of real life examples:
github.com/asciimoo/wuzz

github.com/wallix/awless

gopkg.in/kataras/iris.v6

REF