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

Commit cb6d779

Browse files
committed
internal/gps: add PruneOptions and update WriteDepTree
This commit changes gps.WriteDepTree to be a method on gps.SourceManager. It also updates the signature to accept a PruneOptions instead of a bool. The manfiest is updated to accept a new table, prune. This table defines pruning options accepted by dep. By default, dep will always prune nested vendor directories. The user can define 3 additional rules: * non-go: Prune non-Go files (will keep LICENSE & COPYING files) * go-tests: Prune Go test files * unused-packages: Prune unused Go packages from dependencies. The implementation of these flags is not part of this commit. Signed-off-by: Ibrahim AshShohail <[email protected]>
1 parent 7a91b79 commit cb6d779

14 files changed

+213
-141
lines changed

Gopkg.toml

+5
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,8 @@
1717
[[constraint]]
1818
name = "github.com/pkg/errors"
1919
version = "0.8.0"
20+
21+
[prune]
22+
non-go = true
23+
go-tests = true
24+
unused-packages = true

cmd/dep/prune.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func pruneProject(p *dep.Project, sm gps.SourceManager, logger *log.Logger) erro
9797
}
9898
defer os.RemoveAll(td)
9999

100-
if err := gps.WriteDepTree(td, p.Lock, sm, true); err != nil {
100+
if err := sm.WriteDepTree(td, p.Lock, gps.PruneNestedVendorDirs); err != nil {
101101
return err
102102
}
103103

internal/gps/bridge.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ type sourceBridge interface {
2323
RevisionPresentIn(ProjectIdentifier, Revision) (bool, error)
2424
ListPackages(ProjectIdentifier, Version) (pkgtree.PackageTree, error)
2525
GetManifestAndLock(ProjectIdentifier, Version, ProjectAnalyzer) (Manifest, Lock, error)
26-
ExportProject(ProjectIdentifier, Version, string) error
2726
DeduceProjectRoot(ip string) (ProjectRoot, error)
27+
ExportProject(ProjectIdentifier, Version, string) error
28+
WriteDepTree(basedir string, l Lock, opts PruneOptions) error
2829

2930
//sourceExists(ProjectIdentifier) (bool, error)
3031
//syncSourceFor(ProjectIdentifier) error
@@ -165,6 +166,10 @@ func (b *bridge) ExportProject(id ProjectIdentifier, v Version, path string) err
165166
panic("bridge should never be used to ExportProject")
166167
}
167168

169+
func (b *bridge) WriteDepTree(basedir string, l Lock, opts PruneOptions) error {
170+
panic("bridge should never be used to WriteDepTree")
171+
}
172+
168173
// verifyRoot ensures that the provided path to the project root is in good
169174
// working condition. This check is made only once, at the beginning of a solve
170175
// run.

internal/gps/example.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func main() {
5454
// If no failure, blow away the vendor dir and write a new one out,
5555
// stripping nested vendor directories as we go.
5656
os.RemoveAll(filepath.Join(root, "vendor"))
57-
gps.WriteDepTree(filepath.Join(root, "vendor"), solution, sourcemgr, true)
57+
sourcemgr.WriteDepTree(filepath.Join(root, "vendor"), solution, true)
5858
}
5959
}
6060

internal/gps/manager_test.go

+63
Original file line numberDiff line numberDiff line change
@@ -883,3 +883,66 @@ func TestSupervisor(t *testing.T) {
883883
return nil
884884
})
885885
}
886+
887+
func testWriteDepTree(t *testing.T) {
888+
t.Parallel()
889+
890+
// This test is a bit slow, skip it on -short
891+
if testing.Short() {
892+
t.Skip("Skipping dep tree writing test in short mode")
893+
}
894+
requiresBins(t, "git", "hg", "bzr")
895+
896+
tmp, err := ioutil.TempDir("", "writetree")
897+
if err != nil {
898+
t.Fatalf("Failed to create temp dir: %s", err)
899+
}
900+
defer os.RemoveAll(tmp)
901+
902+
r := solution{
903+
att: 1,
904+
p: []LockedProject{
905+
pa2lp(atom{
906+
id: pi("github.com/sdboyer/testrepo"),
907+
v: NewBranch("master").Pair(Revision("4d59fb584b15a94d7401e356d2875c472d76ef45")),
908+
}, nil),
909+
pa2lp(atom{
910+
id: pi("launchpad.net/govcstestbzrrepo"),
911+
v: NewVersion("1.0.0").Pair(Revision("[email protected]")),
912+
}, nil),
913+
pa2lp(atom{
914+
id: pi("bitbucket.org/sdboyer/withbm"),
915+
v: NewVersion("v1.0.0").Pair(Revision("aa110802a0c64195d0a6c375c9f66668827c90b4")),
916+
}, nil),
917+
},
918+
}
919+
920+
sm, clean := mkNaiveSM(t)
921+
defer clean()
922+
923+
// Trigger simultaneous fetch of all three to speed up test execution time
924+
for _, p := range r.p {
925+
go func(pi ProjectIdentifier) {
926+
sm.SyncSourceFor(pi)
927+
}(p.pi)
928+
}
929+
930+
// nil lock/result should err immediately
931+
if err := sm.WriteDepTree(tmp, nil, PruneNestedVendorDirs); err == nil {
932+
t.Errorf("Should error if nil lock is passed to WriteDepTree")
933+
}
934+
935+
if err := sm.WriteDepTree(tmp, r, PruneNestedVendorDirs); err != nil {
936+
t.Errorf("Unexpected error while creating vendor tree: %s", err)
937+
}
938+
939+
if _, err = os.Stat(filepath.Join(tmp, "github.com", "sdboyer", "testrepo")); err != nil {
940+
t.Errorf("Directory for github.com/sdboyer/testrepo does not exist")
941+
}
942+
if _, err = os.Stat(filepath.Join(tmp, "launchpad.net", "govcstestbzrrepo")); err != nil {
943+
t.Errorf("Directory for launchpad.net/govcstestbzrrepo does not exist")
944+
}
945+
if _, err = os.Stat(filepath.Join(tmp, "bitbucket.org", "sdboyer", "withbm")); err != nil {
946+
t.Errorf("Directory for bitbucket.org/sdboyer/withbm does not exist")
947+
}
948+
}

internal/gps/prune.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2017 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package gps
6+
7+
// PruneOptions represents the pruning options used to write the dependecy tree.
8+
type PruneOptions uint8
9+
10+
const (
11+
// PruneNestedVendorDirs indicates if nested vendor directories should be pruned.
12+
PruneNestedVendorDirs = 1 << iota
13+
// PruneNonGoFiles indicates if non-Go files should be pruned.
14+
// LICENSE & COPYING files are kept for convience.
15+
PruneNonGoFiles
16+
// PruneGoTestFiles indicates if Go test files should be pruned.
17+
PruneGoTestFiles
18+
// PruneUnusedPackages indicates if unused Go packages should be pruned.
19+
PruneUnusedPackages
20+
)

internal/gps/result.go

-42
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@
44

55
package gps
66

7-
import (
8-
"fmt"
9-
"os"
10-
"path/filepath"
11-
)
12-
137
// A Solution is returned by a solver run. It is mostly just a Lock, with some
148
// additional methods that report information about the solve run.
159
type Solution interface {
@@ -42,42 +36,6 @@ type solution struct {
4236
solv Solver
4337
}
4438

45-
// WriteDepTree takes a basedir and a Lock, and exports all the projects
46-
// listed in the lock to the appropriate target location within the basedir.
47-
//
48-
// If the goal is to populate a vendor directory, basedir should be the absolute
49-
// path to that vendor directory, not its parent (a project root, typically).
50-
//
51-
// It requires a SourceManager to do the work, and takes a flag indicating
52-
// whether or not to strip vendor directories contained in the exported
53-
// dependencies.
54-
func WriteDepTree(basedir string, l Lock, sm SourceManager, sv bool) error {
55-
if l == nil {
56-
return fmt.Errorf("must provide non-nil Lock to WriteDepTree")
57-
}
58-
59-
err := os.MkdirAll(basedir, 0777)
60-
if err != nil {
61-
return err
62-
}
63-
64-
// TODO(sdboyer) parallelize
65-
for _, p := range l.Projects() {
66-
to := filepath.FromSlash(filepath.Join(basedir, string(p.Ident().ProjectRoot)))
67-
68-
err = sm.ExportProject(p.Ident(), p.Version(), to)
69-
if err != nil {
70-
removeAll(basedir)
71-
return fmt.Errorf("error while exporting %s: %s", p.Ident().ProjectRoot, err)
72-
}
73-
if sv {
74-
filepath.Walk(to, stripVendor)
75-
}
76-
}
77-
78-
return nil
79-
}
80-
8139
func (r solution) Projects() []LockedProject {
8240
return r.p
8341
}

internal/gps/result_test.go

+1-68
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@
55
package gps
66

77
import (
8-
"io/ioutil"
98
"os"
109
"path"
11-
"path/filepath"
1210
"testing"
1311
)
1412

@@ -46,71 +44,6 @@ func init() {
4644
*/
4745
}
4846

49-
func testWriteDepTree(t *testing.T) {
50-
t.Parallel()
51-
52-
// This test is a bit slow, skip it on -short
53-
if testing.Short() {
54-
t.Skip("Skipping dep tree writing test in short mode")
55-
}
56-
requiresBins(t, "git", "hg", "bzr")
57-
58-
tmp, err := ioutil.TempDir("", "writetree")
59-
if err != nil {
60-
t.Fatalf("Failed to create temp dir: %s", err)
61-
}
62-
defer os.RemoveAll(tmp)
63-
64-
r := solution{
65-
att: 1,
66-
p: []LockedProject{
67-
pa2lp(atom{
68-
id: pi("github.com/sdboyer/testrepo"),
69-
v: NewBranch("master").Pair(Revision("4d59fb584b15a94d7401e356d2875c472d76ef45")),
70-
}, nil),
71-
pa2lp(atom{
72-
id: pi("launchpad.net/govcstestbzrrepo"),
73-
v: NewVersion("1.0.0").Pair(Revision("[email protected]")),
74-
}, nil),
75-
pa2lp(atom{
76-
id: pi("bitbucket.org/sdboyer/withbm"),
77-
v: NewVersion("v1.0.0").Pair(Revision("aa110802a0c64195d0a6c375c9f66668827c90b4")),
78-
}, nil),
79-
},
80-
}
81-
82-
sm, clean := mkNaiveSM(t)
83-
defer clean()
84-
85-
// Trigger simultaneous fetch of all three to speed up test execution time
86-
for _, p := range r.p {
87-
go func(pi ProjectIdentifier) {
88-
sm.SyncSourceFor(pi)
89-
}(p.pi)
90-
}
91-
92-
// nil lock/result should err immediately
93-
err = WriteDepTree(tmp, nil, sm, true)
94-
if err == nil {
95-
t.Errorf("Should error if nil lock is passed to WriteDepTree")
96-
}
97-
98-
err = WriteDepTree(tmp, r, sm, true)
99-
if err != nil {
100-
t.Errorf("Unexpected error while creating vendor tree: %s", err)
101-
}
102-
103-
if _, err = os.Stat(filepath.Join(tmp, "github.com", "sdboyer", "testrepo")); err != nil {
104-
t.Errorf("Directory for github.com/sdboyer/testrepo does not exist")
105-
}
106-
if _, err = os.Stat(filepath.Join(tmp, "launchpad.net", "govcstestbzrrepo")); err != nil {
107-
t.Errorf("Directory for launchpad.net/govcstestbzrrepo does not exist")
108-
}
109-
if _, err = os.Stat(filepath.Join(tmp, "bitbucket.org", "sdboyer", "withbm")); err != nil {
110-
t.Errorf("Directory for bitbucket.org/sdboyer/withbm does not exist")
111-
}
112-
}
113-
11447
func BenchmarkCreateVendorTree(b *testing.B) {
11548
// We're fs-bound here, so restrict to single parallelism
11649
b.SetParallelism(1)
@@ -143,7 +76,7 @@ func BenchmarkCreateVendorTree(b *testing.B) {
14376
// ease manual inspection
14477
os.RemoveAll(exp)
14578
b.StartTimer()
146-
err = WriteDepTree(exp, r, sm, true)
79+
err = sm.WriteDepTree(exp, r, PruneNestedVendorDirs)
14780
b.StopTimer()
14881
if err != nil {
14982
b.Errorf("unexpected error after %v iterations: %s", i, err)

internal/gps/solve_basic_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,10 @@ func (sm *depspecSourceManager) ExportProject(id ProjectIdentifier, v Version, t
14721472
return fmt.Errorf("dummy sm doesn't support exporting")
14731473
}
14741474

1475+
func (sm *depspecSourceManager) WriteDepTree(basedir string, l Lock, options PruneOptions) error {
1476+
return fmt.Errorf("dummy sm doesn't support WriteDepTree")
1477+
}
1478+
14751479
func (sm *depspecSourceManager) DeduceProjectRoot(ip string) (ProjectRoot, error) {
14761480
for _, ds := range sm.allSpecs() {
14771481
n := string(ds.n)

internal/gps/source_manager.go

+48-4
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,6 @@ type SourceManager interface {
6464
// repository root.
6565
GetManifestAndLock(ProjectIdentifier, Version, ProjectAnalyzer) (Manifest, Lock, error)
6666

67-
// ExportProject writes out the tree of the provided import path, at the
68-
// provided version, to the provided directory.
69-
ExportProject(ProjectIdentifier, Version, string) error
70-
7167
// DeduceRootProject takes an import path and deduces the corresponding
7268
// project/source root.
7369
DeduceProjectRoot(ip string) (ProjectRoot, error)
@@ -80,6 +76,14 @@ type SourceManager interface {
8076
// InferConstraint tries to puzzle out what kind of version is given in a string -
8177
// semver, a revision, or as a fallback, a plain tag
8278
InferConstraint(s string, pi ProjectIdentifier) (Constraint, error)
79+
80+
// ExportProject writes out the tree of the provided import path, at the
81+
// provided version, to the provided directory.
82+
ExportProject(ProjectIdentifier, Version, string) error
83+
84+
// WriteDepTree takes a basedir, a Lock and a PruneOptions, and exports all the
85+
// projects listed in the lock to the appropriate target location within basedir.
86+
WriteDepTree(basedir string, l Lock, opts PruneOptions) error
8387
}
8488

8589
// A ProjectAnalyzer is responsible for analyzing a given path for Manifest and
@@ -482,6 +486,46 @@ func (sm *SourceMgr) ExportProject(id ProjectIdentifier, v Version, to string) e
482486
return srcg.exportVersionTo(context.TODO(), v, to)
483487
}
484488

489+
// WriteDepTree takes a basedir, a Lock and a PruneOptions, and exports all the
490+
// projects listed in the lock to the appropriate target location within basedir.
491+
//
492+
// If the goal is to populate a vendor directory, basedir should be the absolute
493+
// path to that vendor directory, not its parent (a project root, typically).
494+
func (sm *SourceMgr) WriteDepTree(basedir string, l Lock, options PruneOptions) error {
495+
if l == nil {
496+
return fmt.Errorf("must provide non-nil Lock to WriteDepTree")
497+
}
498+
499+
if err := os.MkdirAll(basedir, 0777); err != nil {
500+
return err
501+
}
502+
503+
// TODO(sdboyer) parallelize
504+
for _, p := range l.Projects() {
505+
to := filepath.FromSlash(filepath.Join(basedir, string(p.Ident().ProjectRoot)))
506+
507+
if err := sm.ExportProject(p.Ident(), p.Version(), to); err != nil {
508+
removeAll(basedir)
509+
return fmt.Errorf("error while exporting %s: %s", p.Ident().ProjectRoot, err)
510+
}
511+
512+
if (options & PruneNestedVendorDirs) != 0 {
513+
filepath.Walk(to, stripVendor)
514+
}
515+
if (options & PruneNonGoFiles) != 0 {
516+
// TODO: prune non Go files
517+
}
518+
if (options & PruneGoTestFiles) != 0 {
519+
// TODO: prune Go test files
520+
}
521+
if (options & PruneUnusedPackages) != 0 {
522+
// TODO: prune unused packages
523+
}
524+
}
525+
526+
return nil
527+
}
528+
485529
// DeduceProjectRoot takes an import path and deduces the corresponding
486530
// project/source root.
487531
//

internal/gps/version_unifier_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ func (lb lvFixBridge) ExportProject(ProjectIdentifier, Version, string) error {
125125
panic("not implemented")
126126
}
127127

128+
func (lb lvFixBridge) WriteDepTree(basedir string, l Lock, opts PruneOptions) error {
129+
panic("not implemented")
130+
}
131+
128132
func (lb lvFixBridge) DeduceProjectRoot(ip string) (ProjectRoot, error) {
129133
panic("not implemented")
130134
}

0 commit comments

Comments
 (0)