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

Commit 13aa6fc

Browse files
committed
dep: add prune options to manifests
Signed-off-by: Ibrahim AshShohail <[email protected]>
1 parent 4724b1f commit 13aa6fc

File tree

5 files changed

+231
-29
lines changed

5 files changed

+231
-29
lines changed

Gopkg.toml

+5
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,8 @@
3030
[[constraint]]
3131
name = "github.com/golang/protobuf"
3232
branch = "master"
33+
34+
[prune]
35+
non-go = true
36+
go-tests = true
37+
unused-packages = true

analyzer_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func TestAnalyzerDeriveManifestAndLock(t *testing.T) {
3838
t.Fatal(err)
3939
}
4040
} else {
41-
t.Fatalf("expected %s\n got %s", want, string(got))
41+
t.Fatalf("(WNT):\n%s\n(GOT):\n%s", want, string(got))
4242
}
4343
}
4444

gps/prune.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ import (
1616
// PruneOptions represents the pruning options used to write the dependecy tree.
1717
type PruneOptions uint8
1818

19+
// PruneProjectOptions is map of prune options per project name.
20+
type PruneProjectOptions map[ProjectRoot]PruneOptions
21+
1922
const (
2023
// PruneNestedVendorDirs indicates if nested vendor directories should be pruned.
21-
PruneNestedVendorDirs = 1 << iota
24+
PruneNestedVendorDirs PruneOptions = 1 << iota
2225
// PruneUnusedPackages indicates if unused Go packages should be pruned.
2326
PruneUnusedPackages
2427
// PruneNonGoFiles indicates if non-Go files should be pruned.

manifest.go

+184-25
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,39 @@ const ManifestName = "Gopkg.toml"
2424

2525
// Errors
2626
var (
27-
errInvalidConstraint = errors.New("\"constraint\" must be a TOML array of tables")
28-
errInvalidOverride = errors.New("\"override\" must be a TOML array of tables")
29-
errInvalidRequired = errors.New("\"required\" must be a TOML list of strings")
30-
errInvalidIgnored = errors.New("\"ignored\" must be a TOML list of strings")
31-
errInvalidProjectRoot = errors.New("ProjectRoot name validation failed")
27+
errInvalidConstraint = errors.Errorf("%q must be a TOML array of tables", "constraint")
28+
errInvalidOverride = errors.Errorf("%q must be a TOML array of tables", "override")
29+
errInvalidRequired = errors.Errorf("%q must be a TOML list of strings", "required")
30+
errInvalidIgnored = errors.Errorf("%q must be a TOML list of strings", "ignored")
31+
errInvalidPrune = errors.Errorf("%q must be a TOML table of booleans", "prune")
32+
33+
errInvalidProjectRoot = errors.New("ProjectRoot name validation failed")
34+
errInvalidPruneValue = errors.New("prune options values must be booleans")
35+
errInvalidPruneProject = errors.Errorf("%q must be a TOML array of tables", "prune.project")
36+
errPruneSubProject = errors.New("prune projects should not contain sub projects")
37+
38+
errInvalidRootPruneValue = errors.New("root prune options must be omitted instead of being set to false")
39+
errInvalidPruneProjectName = errors.Errorf("%q in %q must be a string", "name", "prune.project")
3240
)
3341

3442
// Manifest holds manifest file data and implements gps.RootManifest.
3543
type Manifest struct {
3644
Constraints gps.ProjectConstraints
3745
Ovr gps.ProjectConstraints
38-
Ignored []string
39-
Required []string
46+
47+
Ignored []string
48+
Required []string
49+
50+
PruneOptions gps.PruneOptions
51+
PruneProjectOptions gps.PruneProjectOptions
4052
}
4153

4254
type rawManifest struct {
43-
Constraints []rawProject `toml:"constraint,omitempty"`
44-
Overrides []rawProject `toml:"override,omitempty"`
45-
Ignored []string `toml:"ignored,omitempty"`
46-
Required []string `toml:"required,omitempty"`
55+
Constraints []rawProject `toml:"constraint,omitempty"`
56+
Overrides []rawProject `toml:"override,omitempty"`
57+
Ignored []string `toml:"ignored,omitempty"`
58+
Required []string `toml:"required,omitempty"`
59+
PruneOptions rawPruneOptions `toml:"prune,omitempty"`
4760
}
4861

4962
type rawProject struct {
@@ -54,11 +67,33 @@ type rawProject struct {
5467
Source string `toml:"source,omitempty"`
5568
}
5669

57-
// NewManifest instantiates a new manifest.
70+
type rawPruneOptions struct {
71+
UnusedPackages bool `toml:"unused-packages,omitempty"`
72+
NonGoFiles bool `toml:"non-go,omitempty"`
73+
GoTests bool `toml:"go-tests,omitempty"`
74+
75+
Projects []rawPruneProjectOptions `toml:"project,omitempty"`
76+
}
77+
78+
type rawPruneProjectOptions struct {
79+
Name string `toml:"name"`
80+
UnusedPackages bool `toml:"unused-packages,omitempty"`
81+
NonGoFiles bool `toml:"non-go,omitempty"`
82+
GoTests bool `toml:"go-tests,omitempty"`
83+
}
84+
85+
const (
86+
pruneOptionUnusedPackages = "unused-packages"
87+
pruneOptionGoTests = "go-tests"
88+
pruneOptionNonGo = "non-go"
89+
)
90+
91+
// NewManifest instantites a new manifest.
5892
func NewManifest() *Manifest {
5993
return &Manifest{
60-
Constraints: make(gps.ProjectConstraints),
61-
Ovr: make(gps.ProjectConstraints),
94+
Constraints: make(gps.ProjectConstraints),
95+
Ovr: make(gps.ProjectConstraints),
96+
PruneOptions: gps.PruneNestedVendorDirs,
6297
}
6398
}
6499

@@ -151,6 +186,12 @@ func validateManifest(s string) ([]error, error) {
151186
return warns, errInvalidRequired
152187
}
153188
}
189+
case "prune":
190+
pruneWarns, err := validatePruneOptions(val, true)
191+
warns = append(warns, pruneWarns...)
192+
if err != nil {
193+
return warns, err
194+
}
154195
default:
155196
warns = append(warns, fmt.Errorf("unknown field in manifest: %v", prop))
156197
}
@@ -159,6 +200,70 @@ func validateManifest(s string) ([]error, error) {
159200
return warns, nil
160201
}
161202

203+
func validatePruneOptions(val interface{}, root bool) (warns []error, err error) {
204+
if reflect.TypeOf(val).Kind() != reflect.Map {
205+
return warns, errInvalidPrune
206+
}
207+
208+
for key, value := range val.(map[string]interface{}) {
209+
switch key {
210+
case pruneOptionNonGo, pruneOptionGoTests, pruneOptionUnusedPackages:
211+
if option, ok := value.(bool); !ok {
212+
return warns, errInvalidPruneValue
213+
} else if root && !option {
214+
return warns, errInvalidRootPruneValue
215+
}
216+
case "name":
217+
if root {
218+
warns = append(warns, errors.Errorf("%q should not include a name", "prune"))
219+
} else if _, ok := value.(string); !ok {
220+
return warns, errInvalidPruneProjectName
221+
}
222+
case "project":
223+
if !root {
224+
return warns, errPruneSubProject
225+
}
226+
if reflect.TypeOf(value).Kind() != reflect.Slice {
227+
return warns, errInvalidPruneProject
228+
}
229+
for _, project := range value.([]interface{}) {
230+
projectWarns, err := validatePruneOptions(project, false)
231+
warns = append(warns, projectWarns...)
232+
if err != nil {
233+
return nil, err
234+
}
235+
}
236+
237+
default:
238+
if root {
239+
warns = append(warns, errors.Errorf("unknown field %q in %q", key, "prune"))
240+
} else {
241+
warns = append(warns, errors.Errorf("unknown field %q in %q", key, "prune.project"))
242+
}
243+
}
244+
}
245+
246+
return warns, err
247+
}
248+
249+
func checkRedundantPruneOptions(raw rawManifest) (warns []error) {
250+
rootOptions := raw.PruneOptions
251+
252+
for _, project := range raw.PruneOptions.Projects {
253+
if rootOptions.GoTests && project.GoTests {
254+
warns = append(warns, errors.Errorf("redundant prune option %q set for %q", pruneOptionGoTests, project.Name))
255+
}
256+
if rootOptions.NonGoFiles && project.NonGoFiles {
257+
warns = append(warns, errors.Errorf("redundant prune option %q set for %q", pruneOptionNonGo, project.Name))
258+
}
259+
if rootOptions.UnusedPackages && project.UnusedPackages {
260+
warns = append(warns, errors.Errorf("redundant prune option %q set for %q", pruneOptionUnusedPackages, project.Name))
261+
}
262+
}
263+
264+
return warns
265+
}
266+
162267
// ValidateProjectRoots validates the project roots present in manifest.
163268
func ValidateProjectRoots(c *Ctx, m *Manifest, sm gps.SourceManager) error {
164269
// Channel to receive all the errors
@@ -184,6 +289,10 @@ func ValidateProjectRoots(c *Ctx, m *Manifest, sm gps.SourceManager) error {
184289
wg.Add(1)
185290
go validate(pr)
186291
}
292+
for pr := range m.PruneProjectOptions {
293+
wg.Add(1)
294+
go validate(pr)
295+
}
187296

188297
wg.Wait()
189298
close(errorCh)
@@ -220,6 +329,8 @@ func readManifest(r io.Reader) (*Manifest, []error, error) {
220329
return nil, warns, errors.Wrap(err, "unable to parse the manifest as TOML")
221330
}
222331

332+
warns = append(warns, checkRedundantPruneOptions(raw)...)
333+
223334
m, err := fromRawManifest(raw)
224335
return m, warns, err
225336
}
@@ -254,9 +365,43 @@ func fromRawManifest(raw rawManifest) (*Manifest, error) {
254365
m.Ovr[name] = prj
255366
}
256367

368+
m.PruneOptions, m.PruneProjectOptions = fromRawPruneOptions(raw.PruneOptions)
369+
257370
return m, nil
258371
}
259372

373+
func fromRawPruneOptions(raw rawPruneOptions) (gps.PruneOptions, gps.PruneProjectOptions) {
374+
rootOptions := gps.PruneNestedVendorDirs
375+
pruneProjects := make(gps.PruneProjectOptions)
376+
377+
if raw.UnusedPackages {
378+
rootOptions |= gps.PruneUnusedPackages
379+
}
380+
if raw.GoTests {
381+
rootOptions |= gps.PruneGoTestFiles
382+
}
383+
if raw.NonGoFiles {
384+
rootOptions |= gps.PruneNonGoFiles
385+
}
386+
387+
for _, p := range raw.Projects {
388+
pr := gps.ProjectRoot(p.Name)
389+
pruneProjects[pr] = gps.PruneNestedVendorDirs
390+
391+
if raw.UnusedPackages {
392+
pruneProjects[pr] |= gps.PruneUnusedPackages
393+
}
394+
if raw.GoTests {
395+
pruneProjects[pr] |= gps.PruneGoTestFiles
396+
}
397+
if raw.NonGoFiles {
398+
pruneProjects[pr] |= gps.PruneNonGoFiles
399+
}
400+
}
401+
402+
return rootOptions, pruneProjects
403+
}
404+
260405
// toProject interprets the string representations of project information held in
261406
// a rawProject, converting them into a proper gps.ProjectProperties. An
262407
// error is returned if the rawProject contains some invalid combination -
@@ -288,17 +433,27 @@ func toProject(raw rawProject) (n gps.ProjectRoot, pp gps.ProjectProperties, err
288433
}
289434

290435
pp.Source = raw.Source
436+
291437
return n, pp, nil
292438
}
293439

440+
// MarshalTOML serializes this manifest into TOML via an intermediate raw form.
441+
func (m *Manifest) MarshalTOML() ([]byte, error) {
442+
raw := m.toRaw()
443+
result, err := toml.Marshal(raw)
444+
return result, errors.Wrap(err, "unable to marshal the lock to a TOML string")
445+
}
446+
294447
// toRaw converts the manifest into a representation suitable to write to the manifest file
295448
func (m *Manifest) toRaw() rawManifest {
296449
raw := rawManifest{
297-
Constraints: make([]rawProject, 0, len(m.Constraints)),
298-
Overrides: make([]rawProject, 0, len(m.Ovr)),
299-
Ignored: m.Ignored,
300-
Required: m.Required,
450+
Constraints: make([]rawProject, 0, len(m.Constraints)),
451+
Overrides: make([]rawProject, 0, len(m.Ovr)),
452+
Ignored: m.Ignored,
453+
Required: m.Required,
454+
PruneOptions: rawPruneOptions{},
301455
}
456+
302457
for n, prj := range m.Constraints {
303458
raw.Constraints = append(raw.Constraints, toRawProject(n, prj))
304459
}
@@ -309,6 +464,8 @@ func (m *Manifest) toRaw() rawManifest {
309464
}
310465
sort.Sort(sortedRawProjects(raw.Overrides))
311466

467+
// TODO(ibrasho): write out prune options.
468+
312469
return raw
313470
}
314471

@@ -329,13 +486,6 @@ func (s sortedRawProjects) Less(i, j int) bool {
329486
return l.Source < r.Source
330487
}
331488

332-
// MarshalTOML serializes this manifest into TOML via an intermediate raw form.
333-
func (m *Manifest) MarshalTOML() ([]byte, error) {
334-
raw := m.toRaw()
335-
result, err := toml.Marshal(raw)
336-
return result, errors.Wrap(err, "Unable to marshal the lock to a TOML string")
337-
}
338-
339489
func toRawProject(name gps.ProjectRoot, project gps.ProjectProperties) rawProject {
340490
raw := rawProject{
341491
Name: string(name),
@@ -363,6 +513,7 @@ func toRawProject(name gps.ProjectRoot, project gps.ProjectProperties) rawProjec
363513
// Has to be a semver range.
364514
raw.Version = project.Constraint.ImpliedCaretString()
365515
}
516+
366517
return raw
367518
}
368519

@@ -407,3 +558,11 @@ func (m *Manifest) RequiredPackages() map[string]bool {
407558

408559
return mp
409560
}
561+
562+
func (m *Manifest) PruneOptionsFor(pr gps.ProjectRoot) gps.PruneOptions {
563+
if po, ok := m.PruneProjectOptions[pr]; ok {
564+
return po
565+
}
566+
567+
return m.PruneOptions
568+
}

0 commit comments

Comments
 (0)