Skip to content
This repository has been archived by the owner on Sep 9, 2020. It is now read-only.

Commit

Permalink
prune: Remove spurious types, fix tests
Browse files Browse the repository at this point in the history
All old types are now gone, tests are fixed, and test coverage should be
adequate for emergency purposes.
  • Loading branch information
sdboyer committed Jan 24, 2018
1 parent 42ebf4a commit 53bd31c
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 170 deletions.
2 changes: 1 addition & 1 deletion cmd/dep/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (cmd *initCommand) Run(ctx *dep.Ctx, args []string) error {
}

// Set default prune options for go-tests and unused-packages
p.Manifest.PruneOptions.PruneOptions = gps.PruneNestedVendorDirs + gps.PruneGoTestFiles + gps.PruneUnusedPackages
p.Manifest.PruneOptions.DefaultOptions = gps.PruneNestedVendorDirs | gps.PruneGoTestFiles | gps.PruneUnusedPackages

if cmd.gopath {
gs := newGopathScanner(ctx, directDeps, sm)
Expand Down
121 changes: 51 additions & 70 deletions gps/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,70 +18,84 @@ import (
// PruneOptions represents the pruning options used to write the dependecy tree.
type PruneOptions uint8

// PruneProjectOptions is map of prune options per project name.
type PruneProjectOptions map[ProjectRoot]PruneOptions
type PruneProjectOptions2 map[ProjectRoot]PruneOptionSet
const (
// PruneNestedVendorDirs indicates if nested vendor directories should be pruned.
PruneNestedVendorDirs PruneOptions = 1 << iota
// PruneUnusedPackages indicates if unused Go packages should be pruned.
PruneUnusedPackages
// PruneNonGoFiles indicates if non-Go files should be pruned.
// Files matching licenseFilePrefixes and legalFileSubstrings are kept in
// an attempt to comply with legal requirements.
PruneNonGoFiles
// PruneGoTestFiles indicates if Go test files should be pruned.
PruneGoTestFiles
)

// PruneOptionSet represents trinary distinctions for each of the types of
// prune rules (as expressed via PruneOptions): nested vendor directories,
// unused packages, non-go files, and go test files.
//
// The three-way distinction is between "none", "true", and "false", represented
// by uint8 values of 0, 1, and 2, respectively.
//
// This trinary distinction is necessary in order to record, with full fidelity,
// a cascading tree of pruning values, as expressed in CascadingPruneOptions; a
// simple boolean cannot delineate between "false" and "none".
type PruneOptionSet struct {
NestedVendor PruneValue
UnusedPackages PruneValue
NonGoFiles PruneValue
GoTests PruneValue
}

// RootPruneOptions represents the root prune options for the project.
// It contains the global options and a map of options per project.
type RootPruneOptions struct {
PruneOptions PruneOptions
ProjectOptions PruneProjectOptions
NestedVendor uint8
UnusedPackages uint8
NonGoFiles uint8
GoTests uint8
}

// CascadingPruneOptions is a set of rules for pruning a dependency tree.
//
// The DefaultOptions are the global default pruning rules, expressed as a
// single PruneOptions bitfield. These global rules will cascade down to
// individual project rules, unless superseded.
type CascadingPruneOptions struct {
DefaultPruneOptions PruneOptions
PerProjectOptions PruneProjectOptions2
DefaultOptions PruneOptions
PerProjectOptions map[ProjectRoot]PruneOptionSet
}

type PruneValue uint8

const (
PruneValueAbsent PruneValue = iota
PruneValueTrue
PruneValueFalse
)

// PruneOptionsFor returns the PruneOptions bits for the given project,
// indicating which pruning rules should be applied to the project's code.
//
// It computes the cascade from default to project-specific options (if any) on
// the fly.
func (o CascadingPruneOptions) PruneOptionsFor(pr ProjectRoot) PruneOptions {
po, has := o.PerProjectOptions[pr]
if !has {
return o.DefaultPruneOptions
return o.DefaultOptions
}

ops := o.DefaultPruneOptions
if po.NestedVendor != PruneValueAbsent {
if po.NestedVendor == PruneValueTrue {
ops := o.DefaultOptions
if po.NestedVendor != 0 {
if po.NestedVendor == 1 {
ops |= PruneNestedVendorDirs
} else {
ops &^= PruneNestedVendorDirs
}
}

if po.UnusedPackages != PruneValueAbsent {
if po.UnusedPackages == PruneValueTrue {
if po.UnusedPackages != 0 {
if po.UnusedPackages == 1 {
ops |= PruneUnusedPackages
} else {
ops &^= PruneUnusedPackages
}
}

if po.NonGoFiles != PruneValueAbsent {
if po.NonGoFiles == PruneValueTrue {
if po.NonGoFiles != 0 {
if po.NonGoFiles == 1 {
ops |= PruneNonGoFiles
} else {
ops &^= PruneNonGoFiles
}
}

if po.GoTests != PruneValueAbsent {
if po.GoTests == PruneValueTrue {
if po.GoTests != 0 {
if po.GoTests == 1 {
ops |= PruneGoTestFiles
} else {
ops &^= PruneGoTestFiles
Expand All @@ -91,46 +105,13 @@ func (o CascadingPruneOptions) PruneOptionsFor(pr ProjectRoot) PruneOptions {
return ops
}

const (
// PruneNestedVendorDirs indicates if nested vendor directories should be pruned.
PruneNestedVendorDirs PruneOptions = 1 << iota
// PruneUnusedPackages indicates if unused Go packages should be pruned.
PruneUnusedPackages
// PruneNonGoFiles indicates if non-Go files should be pruned.
// Files matching licenseFilePrefixes and legalFileSubstrings are kept in
// an attempt to comply with legal requirements.
PruneNonGoFiles
// PruneGoTestFiles indicates if Go test files should be pruned.
PruneGoTestFiles
)

// DefaultRootPruneOptions instantiates a copy of the default root prune options.
func DefaultRootPruneOptions() RootPruneOptions {
return RootPruneOptions{
PruneOptions: PruneNestedVendorDirs,
ProjectOptions: PruneProjectOptions{},
}
}

func DefaultCascadingPruneOptions() CascadingPruneOptions {
func defaultCascadingPruneOptions() CascadingPruneOptions {
return CascadingPruneOptions{
DefaultPruneOptions: PruneNestedVendorDirs,
PerProjectOptions: PruneProjectOptions2{},
DefaultOptions: PruneNestedVendorDirs,
PerProjectOptions: map[ProjectRoot]PruneOptionSet{},
}
}

// PruneOptionsFor returns the prune options for the passed project root.
//
// It will return the root prune options if the project does not have specific
// options or if it does not exist in the manifest.
func (o *RootPruneOptions) PruneOptionsFor(pr ProjectRoot) PruneOptions {
if po, ok := o.ProjectOptions[pr]; ok {
return po
}

return o.PruneOptions
}

var (
// licenseFilePrefixes is a list of name prefixes for license files.
licenseFilePrefixes = []string{
Expand Down
94 changes: 85 additions & 9 deletions gps/prune_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,94 @@ import (
"github.com/golang/dep/internal/test"
)

func TestRootPruneOptions_PruneOptionsFor(t *testing.T) {
pr := ProjectRoot("github.com/golang/dep")

o := RootPruneOptions{
PruneOptions: PruneNestedVendorDirs,
ProjectOptions: PruneProjectOptions{
pr: PruneGoTestFiles,
func TestCascadingPruneOptions(t *testing.T) {
cases := []struct {
name string
co CascadingPruneOptions
results map[ProjectRoot]PruneOptions
}{
{
name: "all empty values",
co: CascadingPruneOptions{
DefaultOptions: PruneNestedVendorDirs,
PerProjectOptions: map[ProjectRoot]PruneOptionSet{
ProjectRoot("github.com/golang/dep"): {},
},
},
results: map[ProjectRoot]PruneOptions{
ProjectRoot("github.com/golang/dep"): PruneNestedVendorDirs,
},
},
{
name: "all overriden",
co: CascadingPruneOptions{
DefaultOptions: PruneNestedVendorDirs,
PerProjectOptions: map[ProjectRoot]PruneOptionSet{
ProjectRoot("github.com/golang/dep"): {
NestedVendor: 2,
UnusedPackages: 1,
NonGoFiles: 1,
GoTests: 1,
},
},
},
results: map[ProjectRoot]PruneOptions{
ProjectRoot("github.com/golang/dep"): PruneUnusedPackages | PruneNonGoFiles | PruneGoTestFiles,
},
},
{
name: "all redundant",
co: CascadingPruneOptions{
DefaultOptions: PruneNestedVendorDirs,
PerProjectOptions: map[ProjectRoot]PruneOptionSet{
ProjectRoot("github.com/golang/dep"): {
NestedVendor: 1,
UnusedPackages: 2,
NonGoFiles: 2,
GoTests: 2,
},
},
},
results: map[ProjectRoot]PruneOptions{
ProjectRoot("github.com/golang/dep"): PruneNestedVendorDirs,
},
},
{
name: "multiple projects, all combos",
co: CascadingPruneOptions{
DefaultOptions: PruneNestedVendorDirs,
PerProjectOptions: map[ProjectRoot]PruneOptionSet{
ProjectRoot("github.com/golang/dep"): {
NestedVendor: 1,
UnusedPackages: 2,
NonGoFiles: 2,
GoTests: 2,
},
ProjectRoot("github.com/other/one"): {
NestedVendor: 2,
UnusedPackages: 1,
NonGoFiles: 1,
GoTests: 1,
},
},
},
results: map[ProjectRoot]PruneOptions{
ProjectRoot("github.com/golang/dep"): PruneNestedVendorDirs,
ProjectRoot("github.com/other/one"): PruneUnusedPackages | PruneNonGoFiles | PruneGoTestFiles,
ProjectRoot("not/there"): PruneNestedVendorDirs,
},
},
}

if (o.PruneOptionsFor(pr) & PruneGoTestFiles) != PruneGoTestFiles {
t.Fatalf("invalid prune options.\n\t(GOT): %d\n\t(WNT): %d", o.PruneOptionsFor(pr), PruneGoTestFiles)
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
for pr, wanted := range c.results {
if c.co.PruneOptionsFor(pr) != wanted {
t.Fatalf("did not get expected final PruneOptions value from cascade:\n\t(GOT): %d\n\t(WNT): %d", c.co.PruneOptionsFor(pr), wanted)
}

}
})
}
}

Expand Down
4 changes: 2 additions & 2 deletions gps/solution.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const concurrentWriters = 16
//
// It requires a SourceManager to do the work. Prune options are read from the
// passed manifest.
func WriteDepTree(basedir string, l Lock, sm SourceManager, rpo RootPruneOptions, logger *log.Logger) error {
func WriteDepTree(basedir string, l Lock, sm SourceManager, co CascadingPruneOptions, logger *log.Logger) error {
if l == nil {
return fmt.Errorf("must provide non-nil Lock to WriteDepTree")
}
Expand Down Expand Up @@ -95,7 +95,7 @@ func WriteDepTree(basedir string, l Lock, sm SourceManager, rpo RootPruneOptions
return errors.Wrapf(err, "failed to export %s", projectRoot)
}

err := PruneProject(to, p, rpo.PruneOptionsFor(ident.ProjectRoot), logger)
err := PruneProject(to, p, co.PruneOptionsFor(ident.ProjectRoot), logger)
if err != nil {
return errors.Wrapf(err, "failed to prune %s", projectRoot)
}
Expand Down
6 changes: 3 additions & 3 deletions gps/solution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@ func testWriteDepTree(t *testing.T) {
}

// nil lock/result should err immediately
err = WriteDepTree(tmp, nil, sm, DefaultRootPruneOptions(), discardLogger())
err = WriteDepTree(tmp, nil, sm, defaultCascadingPruneOptions(), discardLogger())
if err == nil {
t.Errorf("Should error if nil lock is passed to WriteDepTree")
}

err = WriteDepTree(tmp, r, sm, DefaultRootPruneOptions(), discardLogger())
err = WriteDepTree(tmp, r, sm, defaultCascadingPruneOptions(), discardLogger())
if err != nil {
t.Errorf("Unexpected error while creating vendor tree: %s", err)
}
Expand Down Expand Up @@ -166,7 +166,7 @@ func BenchmarkCreateVendorTree(b *testing.B) {
// ease manual inspection
os.RemoveAll(exp)
b.StartTimer()
err = WriteDepTree(exp, r, sm, DefaultRootPruneOptions(), logger)
err = WriteDepTree(exp, r, sm, defaultCascadingPruneOptions(), logger)
b.StopTimer()
if err != nil {
b.Errorf("unexpected error after %v iterations: %s", i, err)
Expand Down
Loading

0 comments on commit 53bd31c

Please sign in to comment.