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

Commit b1e2532

Browse files
committed
dep: Introduce noverify field to Gopkg.toml
This field allows bypassing of vendor verification on a project-by-project basis. When set, `dep check` will ignore any hash verification problems with the directory, and `dep ensure` will not rewrite the dependency unless it is absent from vendor entirely, pruning rules change, or solving changes one of the other, higher-order properties.
1 parent 5cd267f commit b1e2532

File tree

4 files changed

+102
-58
lines changed

4 files changed

+102
-58
lines changed

cmd/dep/check.go

+32-11
Original file line numberDiff line numberDiff line change
@@ -132,18 +132,32 @@ func (cmd *checkCommand) Run(ctx *dep.Ctx, args []string) error {
132132
logger.Println()
133133
}
134134

135+
noverify := make(map[string]bool)
136+
for _, skip := range p.Manifest.NoVerify {
137+
noverify[skip] = true
138+
}
139+
135140
var vendorfail bool
136141
// One full pass through, to see if we need to print the header, and to
137142
// create an array of names to sort for deterministic output.
138143
var ordered []string
139144
for path, status := range statuses {
140145
ordered = append(ordered, path)
141-
if status != verify.NoMismatch {
146+
147+
switch status {
148+
case verify.DigestMismatchInLock, verify.HashVersionMismatch, verify.EmptyDigestInLock:
149+
// NoVerify applies only to these three cases.
150+
if noverify[path] {
151+
continue
152+
}
153+
fallthrough
154+
case verify.NotInTree, verify.NotInLock:
142155
fail = true
143156
if !vendorfail {
144157
vendorfail = true
145158
logger.Println("# vendor is out of sync:")
146159
}
160+
147161
}
148162
}
149163
sort.Strings(ordered)
@@ -158,19 +172,26 @@ func (cmd *checkCommand) Run(ctx *dep.Ctx, args []string) error {
158172
if err != nil {
159173
return errors.Wrap(err, "could not stat file that VerifyVendor claimed existed")
160174
}
161-
162175
if fi.IsDir() {
163176
logger.Printf("%s: unused project\n", pr)
164177
} else {
165178
logger.Printf("%s: orphaned file\n", pr)
166179
}
167-
case verify.DigestMismatchInLock:
168-
logger.Printf("%s: hash of vendored tree didn't match digest in Gopkg.lock\n", pr)
169-
case verify.HashVersionMismatch:
170-
// This will double-print if the hash version is zero, but
171-
// that's a rare case that really only occurs before the first
172-
// run with a version of dep >=0.5.0, so it's fine.
173-
logger.Printf("%s: hash algorithm mismatch, want version %v\n", pr, verify.HashVersion)
180+
case verify.DigestMismatchInLock, verify.HashVersionMismatch, verify.EmptyDigestInLock:
181+
// NoVerify applies only to these three cases.
182+
if !noverify[pr] {
183+
switch status {
184+
case verify.DigestMismatchInLock:
185+
logger.Printf("%s: hash of vendored tree not equal to digest in Gopkg.lock\n", pr)
186+
case verify.EmptyDigestInLock:
187+
logger.Printf("%s: no digest in Gopkg.lock to compare against hash of vendored tree\n", pr)
188+
case verify.HashVersionMismatch:
189+
// This will double-print if the hash version is zero, but
190+
// that's a rare case that really only occurs before the first
191+
// run with a version of dep >=0.5.0, so it's fine.
192+
logger.Printf("%s: hash algorithm mismatch, want version %v\n", pr, verify.HashVersion)
193+
}
194+
}
174195
}
175196
}
176197
}
@@ -185,12 +206,12 @@ func sprintLockUnsat(lsat verify.LockSatisfaction) string {
185206
var buf bytes.Buffer
186207
sort.Strings(lsat.MissingImports)
187208
for _, missing := range lsat.MissingImports {
188-
fmt.Fprintf(&buf, "%s: missing from input-imports\n", missing)
209+
fmt.Fprintf(&buf, "%s: imported or required, but missing from Gopkg.lock's input-imports\n", missing)
189210
}
190211

191212
sort.Strings(lsat.ExcessImports)
192213
for _, excess := range lsat.ExcessImports {
193-
fmt.Fprintf(&buf, "%s: in input-imports, but not imported\n", excess)
214+
fmt.Fprintf(&buf, "%s: in Gopkg.lock's input-imports, but neither imported nor required\n", excess)
194215
}
195216

196217
var ordered []string

cmd/dep/ensure.go

+3-20
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,7 @@ func (cmd *ensureCommand) runDefault(ctx *dep.Ctx, args []string, p *dep.Project
285285
lock = dep.LockFromSolution(solution, p.Manifest.PruneOptions)
286286
}
287287

288-
status, err := p.VerifyVendor()
289-
if err != nil {
290-
return errors.Wrap(err, "error while verifying vendor directory")
291-
}
292-
dw, err := dep.NewDeltaWriter(p.Lock, lock, status, p.Manifest.PruneOptions, filepath.Join(p.AbsRoot, "vendor"), cmd.vendorBehavior())
288+
dw, err := dep.NewDeltaWriter(p, lock, cmd.vendorBehavior())
293289
if err != nil {
294290
return err
295291
}
@@ -365,11 +361,7 @@ func (cmd *ensureCommand) runUpdate(ctx *dep.Ctx, args []string, p *dep.Project,
365361
return handleAllTheFailuresOfTheWorld(err)
366362
}
367363

368-
status, err := p.VerifyVendor()
369-
if err != nil {
370-
return errors.Wrap(err, "error while verifying vendor directory")
371-
}
372-
dw, err := dep.NewDeltaWriter(p.Lock, dep.LockFromSolution(solution, p.Manifest.PruneOptions), status, p.Manifest.PruneOptions, filepath.Join(p.AbsRoot, "vendor"), cmd.vendorBehavior())
364+
dw, err := dep.NewDeltaWriter(p, dep.LockFromSolution(solution, p.Manifest.PruneOptions), cmd.vendorBehavior())
373365
if err != nil {
374366
return err
375367
}
@@ -411,11 +403,6 @@ func (cmd *ensureCommand) runAdd(ctx *dep.Ctx, args []string, p *dep.Project, sm
411403
}
412404
}
413405

414-
//exrmap, err := p.GetDirectDependencyNames(sm)
415-
//if err != nil {
416-
//return err
417-
//}
418-
419406
// Note: these flags are only partially used by the latter parts of the
420407
// algorithm; rather, it relies on inference. However, they remain in their
421408
// entirety as future needs may make further use of them, being a handy,
@@ -643,11 +630,7 @@ func (cmd *ensureCommand) runAdd(ctx *dep.Ctx, args []string, p *dep.Project, sm
643630
}
644631
sort.Strings(reqlist)
645632

646-
status, err := p.VerifyVendor()
647-
if err != nil {
648-
return errors.Wrap(err, "error while verifying vendor directory")
649-
}
650-
dw, err := dep.NewDeltaWriter(p.Lock, dep.LockFromSolution(solution, p.Manifest.PruneOptions), status, p.Manifest.PruneOptions, filepath.Join(p.AbsRoot, "vendor"), cmd.vendorBehavior())
633+
dw, err := dep.NewDeltaWriter(p, dep.LockFromSolution(solution, p.Manifest.PruneOptions), cmd.vendorBehavior())
651634
if err != nil {
652635
return err
653636
}

manifest.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ var (
2828
errInvalidOverride = errors.Errorf("%q must be a TOML array of tables", "override")
2929
errInvalidRequired = errors.Errorf("%q must be a TOML list of strings", "required")
3030
errInvalidIgnored = errors.Errorf("%q must be a TOML list of strings", "ignored")
31+
errInvalidNoVerify = errors.Errorf("%q must be a TOML list of strings", "noverify")
3132
errInvalidPrune = errors.Errorf("%q must be a TOML table of booleans", "prune")
3233
errInvalidPruneProject = errors.Errorf("%q must be a TOML array of tables", "prune.project")
3334
errInvalidMetadata = errors.New("metadata should be a TOML table")
@@ -51,6 +52,8 @@ type Manifest struct {
5152
Ignored []string
5253
Required []string
5354

55+
NoVerify []string
56+
5457
PruneOptions gps.CascadingPruneOptions
5558
}
5659

@@ -59,6 +62,7 @@ type rawManifest struct {
5962
Overrides []rawProject `toml:"override,omitempty"`
6063
Ignored []string `toml:"ignored,omitempty"`
6164
Required []string `toml:"required,omitempty"`
65+
NoVerify []string `toml:"noverify,omitempty"`
6266
PruneOptions rawPruneOptions `toml:"prune,omitempty"`
6367
}
6468

@@ -85,7 +89,7 @@ const (
8589
pruneOptionNonGo = "non-go"
8690
)
8791

88-
// Constants to represents per-project prune uint8 values.
92+
// Constants representing per-project prune uint8 values.
8993
const (
9094
pvnone uint8 = 0 // No per-project prune value was set in Gopkg.toml.
9195
pvtrue uint8 = 1 // Per-project prune value was explicitly set to true.
@@ -182,7 +186,7 @@ func validateManifest(s string) ([]error, error) {
182186
return warns, errInvalidOverride
183187
}
184188
}
185-
case "ignored", "required":
189+
case "ignored", "required", "noverify":
186190
valid := true
187191
if rawList, ok := val.([]interface{}); ok {
188192
// Check element type of the array. TOML doesn't let mixing of types in
@@ -201,6 +205,9 @@ func validateManifest(s string) ([]error, error) {
201205
if prop == "required" {
202206
return warns, errInvalidRequired
203207
}
208+
if prop == "noverify" {
209+
return warns, errInvalidNoVerify
210+
}
204211
}
205212
case "prune":
206213
pruneWarns, err := validatePruneOptions(val, true)
@@ -368,6 +375,7 @@ func fromRawManifest(raw rawManifest, buf *bytes.Buffer) (*Manifest, error) {
368375
m.Ovr = make(gps.ProjectConstraints, len(raw.Overrides))
369376
m.Ignored = raw.Ignored
370377
m.Required = raw.Required
378+
m.NoVerify = raw.NoVerify
371379

372380
for i := 0; i < len(raw.Constraints); i++ {
373381
name, prj, err := toProject(raw.Constraints[i])
@@ -532,6 +540,7 @@ func (m *Manifest) toRaw() rawManifest {
532540
Overrides: make([]rawProject, 0, len(m.Ovr)),
533541
Ignored: m.Ignored,
534542
Required: m.Required,
543+
NoVerify: m.NoVerify,
535544
}
536545

537546
for n, prj := range m.Constraints {

txn_writer.go

+56-25
Original file line numberDiff line numberDiff line change
@@ -423,10 +423,11 @@ type DeltaWriter struct {
423423
type changeType uint8
424424

425425
const (
426-
solveChanged changeType = iota + 1
427-
hashMismatch
426+
hashMismatch changeType = iota + 1
428427
hashVersionMismatch
429428
hashAbsent
429+
noVerify
430+
solveChanged
430431
pruneOptsChanged
431432
missingFromTree
432433
projectAdded
@@ -437,10 +438,10 @@ const (
437438
// directory by writing out only those projects that actually need to be written
438439
// out - they have changed in some way, or they lack the necessary hash
439440
// information to be verified.
440-
func NewDeltaWriter(oldLock, newLock *Lock, status map[string]verify.VendorStatus, prune gps.CascadingPruneOptions, vendorDir string, behavior VendorBehavior) (TreeWriter, error) {
441-
sw := &DeltaWriter{
441+
func NewDeltaWriter(p *Project, newLock *Lock, behavior VendorBehavior) (TreeWriter, error) {
442+
dw := &DeltaWriter{
442443
lock: newLock,
443-
vendorDir: vendorDir,
444+
vendorDir: filepath.Join(p.AbsRoot, "vendor"),
444445
changed: make(map[gps.ProjectRoot]changeType),
445446
behavior: behavior,
446447
}
@@ -449,27 +450,35 @@ func NewDeltaWriter(oldLock, newLock *Lock, status map[string]verify.VendorStatu
449450
return nil, errors.New("must provide a non-nil newlock")
450451
}
451452

452-
_, err := os.Stat(vendorDir)
453-
if err != nil && os.IsNotExist(err) {
454-
// Provided dir does not exist, so there's no disk contents to compare
455-
// against. Fall back to the old SafeWriter.
456-
return NewSafeWriter(nil, oldLock, newLock, behavior, prune, status)
453+
status, err := p.VerifyVendor()
454+
if err != nil {
455+
return nil, err
457456
}
458457

459-
sw.lockDiff = verify.DiffLocks(oldLock, newLock)
458+
_, err = os.Stat(dw.vendorDir)
459+
if err != nil {
460+
if os.IsNotExist(err) {
461+
// Provided dir does not exist, so there's no disk contents to compare
462+
// against. Fall back to the old SafeWriter.
463+
return NewSafeWriter(nil, p.Lock, newLock, behavior, p.Manifest.PruneOptions, status)
464+
}
465+
return nil, err
466+
}
460467

461-
for pr, lpd := range sw.lockDiff.ProjectDeltas {
468+
dw.lockDiff = verify.DiffLocks(p.Lock, newLock)
469+
470+
for pr, lpd := range dw.lockDiff.ProjectDeltas {
462471
// Hash changes aren't relevant at this point, as they could be empty
463472
// in the new lock, and therefore a symptom of a solver change.
464473
if lpd.Changed(anyExceptHash) {
465474
if lpd.WasAdded() {
466-
sw.changed[pr] = projectAdded
475+
dw.changed[pr] = projectAdded
467476
} else if lpd.WasRemoved() {
468-
sw.changed[pr] = projectRemoved
477+
dw.changed[pr] = projectRemoved
469478
} else if lpd.PruneOptsChanged() {
470-
sw.changed[pr] = pruneOptsChanged
479+
dw.changed[pr] = pruneOptsChanged
471480
} else {
472-
sw.changed[pr] = solveChanged
481+
dw.changed[pr] = solveChanged
473482
}
474483
}
475484
}
@@ -478,23 +487,44 @@ func NewDeltaWriter(oldLock, newLock *Lock, status map[string]verify.VendorStatu
478487
pr := gps.ProjectRoot(spr)
479488
// These cases only matter if there was no change already recorded via
480489
// the differ.
481-
if _, has := sw.changed[pr]; !has {
490+
if _, has := dw.changed[pr]; !has {
482491
switch stat {
483492
case verify.NotInTree:
484-
sw.changed[pr] = missingFromTree
493+
dw.changed[pr] = missingFromTree
485494
case verify.NotInLock:
486-
sw.changed[pr] = projectRemoved
495+
dw.changed[pr] = projectRemoved
487496
case verify.DigestMismatchInLock:
488-
sw.changed[pr] = hashMismatch
497+
dw.changed[pr] = hashMismatch
489498
case verify.HashVersionMismatch:
490-
sw.changed[pr] = hashVersionMismatch
499+
dw.changed[pr] = hashVersionMismatch
491500
case verify.EmptyDigestInLock:
492-
sw.changed[pr] = hashAbsent
501+
dw.changed[pr] = hashAbsent
493502
}
494503
}
495504
}
496505

497-
return sw, nil
506+
// Apply noverify last, as it should only supersede changeTypes with lower
507+
// values. It is NOT applied if no existing change is registered.
508+
for _, spr := range p.Manifest.NoVerify {
509+
pr := gps.ProjectRoot(spr)
510+
// We don't validate this field elsewhere as it can be difficult to know
511+
// at the beginning of a dep ensure command whether or not the noverify
512+
// project actually will exist as part of the Lock by the end of the
513+
// run. So, only apply if it's in the lockdiff, and isn't a removal.
514+
if _, has := dw.lockDiff.ProjectDeltas[pr]; has {
515+
if typ, has := dw.changed[pr]; has && typ < noVerify {
516+
// Avoid writing noverify projects at all for the lower change
517+
// types.
518+
delete(dw.changed, pr)
519+
520+
// Uncomment this if we want to switch to the safer behavior,
521+
// where we ALWAYS write noverify projects.
522+
//dw.changed[pr] = noVerify
523+
}
524+
}
525+
}
526+
527+
return dw, nil
498528
}
499529

500530
// Write executes the planned changes.
@@ -659,6 +689,8 @@ func (dw *DeltaWriter) Write(path string, sm gps.SourceManager, examples bool, l
659689
// possible changeType.
660690
func changeExplanation(c changeType, lpd verify.LockedProjectDelta) string {
661691
switch c {
692+
case noVerify:
693+
return "verification is disabled"
662694
case solveChanged:
663695
if lpd.SourceChanged() {
664696
return fmt.Sprintf("source changed (%s -> %s)", lpd.SourceBefore, lpd.SourceAfter)
@@ -675,9 +707,8 @@ func changeExplanation(c changeType, lpd verify.LockedProjectDelta) string {
675707
return fmt.Sprintf("packages changed (%v added, %v removed)", la, lr)
676708
} else if la > 0 {
677709
return fmt.Sprintf("packages changed (%v added)", la)
678-
} else {
679-
return fmt.Sprintf("packages changed (%v removed)", lr)
680710
}
711+
return fmt.Sprintf("packages changed (%v removed)", lr)
681712
}
682713
case pruneOptsChanged:
683714
// Override what's on the lockdiff with the extra info we have;

0 commit comments

Comments
 (0)