Skip to content

Commit 6aa440a

Browse files
committed
add trace command
1 parent 7f8807d commit 6aa440a

11 files changed

+796
-222
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[
2+
"github.com/openshift/origin/images",
3+
"github.com/openshift/origin/pkg/build/builder",
4+
"github.com/openshift/origin/cmd/cluster-capacity",
5+
"github.com/openshift/origin/cmd/service-catalog"
6+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[
2+
"github.com/openshift/origin/pkg/api",
3+
"github.com/openshift/origin/pkg/auth"
4+
]

tools/depcheck/pkg/cmd/cmd.go

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ func NewCmdDepCheck(name string, out, errout io.Writer) *cobra.Command {
2222
}
2323

2424
cmd.AddCommand(NewCmdPinImports(name, out, errout))
25+
cmd.AddCommand(NewCmdTraceImports(name, out, errout))
2526

2627
// add glog flags to our global flag set
2728
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)

tools/depcheck/pkg/cmd/trace.go

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"io"
6+
7+
"github.com/spf13/cobra"
8+
9+
"github.com/gonum/graph"
10+
"github.com/gonum/graph/encoding/dot"
11+
12+
depgraph "github.com/openshift/origin/tools/depcheck/pkg/graph"
13+
)
14+
15+
var traceImportsExample = `# create a dependency graph
16+
%[1]s trace --root=github.com/openshift/origin --entry="./cmd/..."
17+
18+
# create a dependency graph using OpenShift-specific settings
19+
%[1]s trace --root=github.com/openshift/origin --entry="./cmd/..." --openshift
20+
21+
# create a dependency graph and output in "dot" format
22+
%[1]s trace --root=github.com/openshift/origin --entry=pkg/foo/... --output=dot --openshift
23+
`
24+
25+
type TraceOptions struct {
26+
GraphOptions *depgraph.GraphOptions
27+
28+
outputGraphName string
29+
OutputFormat string
30+
31+
Out io.Writer
32+
ErrOut io.Writer
33+
}
34+
35+
type TraceFlags struct {
36+
GraphFlags *depgraph.GraphFlags
37+
38+
OutputFormat string
39+
}
40+
41+
func NewCmdTraceImports(parent string, out, errout io.Writer) *cobra.Command {
42+
traceFlags := &TraceFlags{
43+
GraphFlags: &depgraph.GraphFlags{},
44+
OutputFormat: "dot",
45+
}
46+
47+
cmd := &cobra.Command{
48+
Use: "trace --root=github.com/openshift/origin --entry=pkg/foo/...",
49+
Short: "Creates a dependency graph for a given repository",
50+
Long: "Creates a dependency graph for a given repository, for every Go package reachable from a set of --entry points into the codebase",
51+
Example: fmt.Sprintf(traceImportsExample, parent),
52+
RunE: func(c *cobra.Command, args []string) error {
53+
opts, err := traceFlags.ToOptions(out, errout)
54+
if err != nil {
55+
return err
56+
}
57+
58+
if err := opts.Complete(); err != nil {
59+
return err
60+
}
61+
if err := opts.Validate(); err != nil {
62+
return err
63+
}
64+
if err := opts.Run(); err != nil {
65+
return err
66+
}
67+
68+
return nil
69+
},
70+
}
71+
72+
traceFlags.GraphFlags.AddFlags(cmd)
73+
cmd.Flags().StringVarP(&traceFlags.OutputFormat, "output", "o", traceFlags.OutputFormat, "output generated dependency graph in specified format. One of: dot.")
74+
return cmd
75+
}
76+
77+
func (o *TraceOptions) Complete() error {
78+
return o.GraphOptions.Complete()
79+
}
80+
81+
func (o *TraceOptions) Validate() error {
82+
if err := o.GraphOptions.Validate(); err != nil {
83+
return err
84+
}
85+
86+
if len(o.OutputFormat) > 0 && o.OutputFormat != "dot" {
87+
return fmt.Errorf("invalid output format provided: %s", o.OutputFormat)
88+
}
89+
90+
return nil
91+
}
92+
93+
func (o *TraceFlags) ToOptions(out, errout io.Writer) (*TraceOptions, error) {
94+
graphOpts, err := o.GraphFlags.ToOptions(out, errout)
95+
if err != nil {
96+
return nil, err
97+
}
98+
99+
return &TraceOptions{
100+
GraphOptions: graphOpts,
101+
OutputFormat: o.OutputFormat,
102+
103+
outputGraphName: o.GraphFlags.RepoImportPath,
104+
105+
Out: out,
106+
ErrOut: errout,
107+
}, nil
108+
}
109+
110+
// Run creates a dependency graph using user-specified options.
111+
// Outputs graph contents in the format specified.
112+
func (o *TraceOptions) Run() error {
113+
g, err := o.GraphOptions.BuildGraph()
114+
if err != nil {
115+
return err
116+
}
117+
118+
return o.outputGraph(g)
119+
}
120+
121+
func (o *TraceOptions) outputGraph(g graph.Directed) error {
122+
if o.OutputFormat != "dot" {
123+
return fmt.Errorf("invalid output format provided: %s", o.OutputFormat)
124+
}
125+
126+
data, err := dot.Marshal(g, fmt.Sprintf("%q", o.outputGraphName), "", " ", false)
127+
if err != nil {
128+
return err
129+
}
130+
131+
fmt.Fprintf(o.Out, "%v\n", string(data))
132+
return nil
133+
}

tools/depcheck/pkg/graph/filter.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ func FilterPackages(g *MutableDirectedGraph, packagePrefixes []string) (*Mutable
3131
err := collapsedGraph.AddNode(&Node{
3232
UniqueName: collapsedNodeName,
3333
Id: n.ID(),
34-
LabelName: labelNameForNode(collapsedNodeName),
3534
})
3635
if err != nil {
3736
return nil, err
@@ -83,7 +82,15 @@ func FilterPackages(g *MutableDirectedGraph, packagePrefixes []string) (*Mutable
8382

8483
func getFilteredNodeName(collapsedPrefixes []string, packageName string) string {
8584
for _, prefix := range collapsedPrefixes {
86-
if strings.HasPrefix(packageName, prefix) {
85+
// ensure that each prefix ends in a slash
86+
// otherwise, we will incorrectly squash packages
87+
// like "api" and "apimachinery" into eachother.
88+
prefixWithSlash := prefix
89+
if string(prefix[len(prefix)-1]) != "/" {
90+
prefixWithSlash = prefixWithSlash + "/"
91+
}
92+
93+
if strings.HasPrefix(packageName+"/", prefixWithSlash) {
8794
return prefix
8895
}
8996
}

tools/depcheck/pkg/graph/filter_test.go

+16-14
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ type testFilterNode struct {
1515
func getVendorNodes() []*testFilterNode {
1616
return []*testFilterNode{
1717
{
18-
name: "github.com/test/repo/vendor/github.com/testvendor/prefix1",
18+
name: "github.com/test/repo/vendor/github.com/testvendor/prefix",
1919
outboundEdges: []string{
20-
"github.com/test/repo/vendor/github.com/testvendor/prefix1/one",
20+
"github.com/test/repo/vendor/github.com/testvendor/prefix/one",
2121
},
2222
},
2323
{
24-
name: "github.com/test/repo/vendor/github.com/testvendor/prefix1/one",
24+
name: "github.com/test/repo/vendor/github.com/testvendor/prefix/one",
2525
outboundEdges: []string{
2626
"github.com/test/repo/vendor/github.com/testvendor/prefix2/one",
2727
},
@@ -58,15 +58,15 @@ func getVendorNodes() []*testFilterNode {
5858
func getNonVendorNodes() []*testFilterNode {
5959
return []*testFilterNode{
6060
{
61-
name: "github.com/test/repo/pkg/prefix1",
61+
name: "github.com/test/repo/pkg/prefix",
6262
outboundEdges: []string{
63-
"github.com/test/repo/pkg/prefix1/one",
63+
"github.com/test/repo/pkg/prefix/one",
6464
},
6565
},
6666
{
67-
name: "github.com/test/repo/pkg/prefix1/one",
67+
name: "github.com/test/repo/pkg/prefix/one",
6868
outboundEdges: []string{
69-
"github.com/test/repo/vendor/github.com/testvendor/prefix1",
69+
"github.com/test/repo/vendor/github.com/testvendor/prefix",
7070
},
7171
},
7272
{
@@ -132,7 +132,7 @@ func TestVendorPackagesCollapsedIntoRepo(t *testing.T) {
132132
}
133133

134134
vendorRoots := []string{
135-
"github.com/test/repo/vendor/github.com/testvendor/prefix1",
135+
"github.com/test/repo/vendor/github.com/testvendor/prefix",
136136
"github.com/test/repo/vendor/github.com/testvendor/prefix2",
137137
"github.com/test/repo/vendor/github.com/google/glog",
138138
"github.com/test/repo/vendor/github.com/docker/docker-test-util",
@@ -190,7 +190,7 @@ func TestVendorPackagesCollapsedIntoRepo(t *testing.T) {
190190
"github.com/test/repo/vendor/github.com/docker/docker-test-util": {
191191
"github.com/test/repo/vendor/github.com/google/glog",
192192
},
193-
"github.com/test/repo/vendor/github.com/testvendor/prefix1": {
193+
"github.com/test/repo/vendor/github.com/testvendor/prefix": {
194194
"github.com/test/repo/vendor/github.com/testvendor/prefix2",
195195
},
196196
}
@@ -249,7 +249,9 @@ func TestCollapsedGraphPreservesNonVendorNodes(t *testing.T) {
249249
}
250250

251251
vendorRoots := []string{
252-
"github.com/test/repo/vendor/github.com/testvendor/prefix1",
252+
// having this prefix come first tests that "prefix2" does
253+
// not end up getting accidentally squashed into "testvendor/prefix"
254+
"github.com/test/repo/vendor/github.com/testvendor/prefix",
253255
"github.com/test/repo/vendor/github.com/testvendor/prefix2",
254256
"github.com/test/repo/vendor/github.com/google/glog",
255257
"github.com/test/repo/vendor/github.com/docker/docker-test-util",
@@ -280,11 +282,11 @@ func TestCollapsedGraphPreservesNonVendorNodes(t *testing.T) {
280282
}
281283

282284
expectedOutgoingEdges := map[string][]string{
283-
"github.com/test/repo/pkg/prefix1": {
284-
"github.com/test/repo/pkg/prefix1/one",
285+
"github.com/test/repo/pkg/prefix": {
286+
"github.com/test/repo/pkg/prefix/one",
285287
},
286-
"github.com/test/repo/pkg/prefix1/one": {
287-
"github.com/test/repo/vendor/github.com/testvendor/prefix1",
288+
"github.com/test/repo/pkg/prefix/one": {
289+
"github.com/test/repo/vendor/github.com/testvendor/prefix",
288290
},
289291
}
290292

0 commit comments

Comments
 (0)