Skip to content
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
60 changes: 30 additions & 30 deletions cmd/depth/depth.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"os"
"strings"
"sync"

"github.com/KyleBanks/depth"
)
Expand All @@ -20,45 +21,44 @@ const (
var outputJSON bool

func main() {
t := parse(os.Args[1:])
if err := handlePkgs(t, flag.Args(), outputJSON); err != nil {
os.Exit(1)
ResolveInternal := flag.Bool("internal", false, "If set, resolves dependencies of internal (stdlib) packages.")
ResolveTest := flag.Bool("test", false, "If set, resolves dependencies used for testing.")
MaxDepth := flag.Int("max", 0, "Sets the maximum depth of dependencies to resolve.")
outputJSON := flag.Bool("json", false, "If set, outputs the depencies in JSON format.")
flag.Parse()

pkgs := flag.Args()
t := &depth.Tree{
ResolveInternal: *ResolveInternal,
ResolveTest: *ResolveTest,
MaxDepth: *MaxDepth,
}
}

// parse constructs a depth.Tree from command-line arguments.
func parse(args []string) *depth.Tree {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that you're using the WaitGroup and not channels I think you can keep the parse method + test

f := flag.NewFlagSet(os.Args[0], flag.ExitOnError)

var t depth.Tree
f.BoolVar(&t.ResolveInternal, "internal", false, "If set, resolves dependencies of internal (stdlib) packages.")
f.BoolVar(&t.ResolveTest, "test", false, "If set, resolves dependencies used for testing.")
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.Parse(args)
handlePkgs(t, pkgs, *outputJSON)

return &t
}

// 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) error {
func handlePkgs(t *depth.Tree, pkgs []string, outputJSON bool) {
var wg sync.WaitGroup
for _, pkg := range pkgs {
err := t.Resolve(pkg)
if err != nil {
fmt.Printf("'%v': FATAL: %v\n", pkg, err)
return err
}

if outputJSON {
writePkgJSON(os.Stdout, *t.Root)
continue
}
wg.Add(1)
go handlePkg(&wg, t, pkg, outputJSON)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure reusing the same Tree concurrently is going to be safe, because resolving modified properties on the tree itself. If you put the parse method back, you could call parse within this for-loop to get a fresh tree for each package

}
wg.Wait()
}

func handlePkg(wg *sync.WaitGroup, t *depth.Tree, pkg string, outputJSON bool) {
defer wg.Done()
err := t.Resolve(pkg)
if err != nil {
fmt.Printf("'%v': FATAL: %v\n", pkg, err)
return
}
if outputJSON {
writePkgJSON(os.Stdout, *t.Root)
} else {
writePkg(os.Stdout, *t.Root, 0, false)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last concern is printing, since this is going to happen concurrently the output may not always be cleanly separated by package, if that make sense. For example you may get halfway through printing PackageA's tree when PackageB starts printing

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I was using channels for solving this problem, where we send the tree struct with config and return the final filled tree to channel and then print it. In this approach problem was the pkg.go returns from multiple places, the channel needs to set for every return case to avoid a leak.

}

return nil
}

// writePkgJSON writes the full Pkg as JSON to the provided Writer.
Expand Down
41 changes: 2 additions & 39 deletions cmd/depth/depth_test.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,6 @@
package main

import (
"fmt"
"testing"

"github.com/KyleBanks/depth"
)

func Test_parse(t *testing.T) {
tests := []struct {
internal bool
test bool
depth int
json bool
}{
{true, true, 0, true},
{false, false, 10, false},
{true, false, 10, false},
{false, true, 5, true},
}

for idx, tt := range tests {
tr := parse([]string{
fmt.Sprintf("-internal=%v", tt.internal),
fmt.Sprintf("-test=%v", tt.test),
fmt.Sprintf("-max=%v", tt.depth),
fmt.Sprintf("-json=%v", tt.json),
})

if tr.ResolveInternal != tt.internal {
t.Fatalf("[%v] Unexpected ResolveInternal, expected=%v, got=%v", idx, tt.internal, tr.ResolveInternal)
} else if tr.ResolveTest != tt.test {
t.Fatalf("[%v] Unexpected ResolveTest, expected=%v, got=%v", idx, tt.test, tr.ResolveTest)
} else if tr.MaxDepth != tt.depth {
t.Fatalf("[%v] Unexpected MaxDepth, expected=%v, got=%v", idx, tt.depth, tr.MaxDepth)
} else if outputJSON != tt.json {
t.Fatalf("[%v] Unexpected outputJSON, expected=%v, got=%v", idx, tt.json, outputJSON)
}
}
}
import "github.com/KyleBanks/depth"

func Example_handlePkgsStrings() {
var t depth.Tree
Expand Down Expand Up @@ -85,6 +47,7 @@ func Example_handlePkgsDepth() {
// ├ io
// ├ os
// ├ strings
// ├ sync
// └ github.com/KyleBanks/depth
// ├ bytes
// ├ errors
Expand Down