This repository has been archived by the owner on Sep 9, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1932 from sdboyer/dep-check
dep: Introduce dep check subcommand
- Loading branch information
Showing
76 changed files
with
766 additions
and
120 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
// Copyright 2018 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package main | ||
|
||
import ( | ||
"bytes" | ||
"flag" | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
"sort" | ||
"strings" | ||
|
||
"github.com/golang/dep" | ||
"github.com/golang/dep/gps" | ||
"github.com/golang/dep/gps/verify" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
const checkShortHelp = `Check if imports, Gopkg.toml, and Gopkg.lock are in sync` | ||
const checkLongHelp = ` | ||
Check determines if your project is in a good state. If problems are found, it | ||
prints a description of each issue, then exits 1. Passing -q suppresses output. | ||
Flags control which specific checks will be run. By default, dep check verifies | ||
that Gopkg.lock is in sync with Gopkg.toml and the imports in your project's .go | ||
files, and that the vendor directory is in sync with Gopkg.lock. These checks | ||
can be disabled with -skip-lock and -skip-vendor, respectively. | ||
(See https://golang.github.io/dep/docs/ensure-mechanics.html#staying-in-sync for | ||
more information on what it means to be "in sync.") | ||
` | ||
|
||
type checkCommand struct { | ||
quiet bool | ||
skiplock, skipvendor bool | ||
} | ||
|
||
func (cmd *checkCommand) Name() string { return "check" } | ||
func (cmd *checkCommand) Args() string { | ||
return "[-q] [-skip-lock] [-skip-vendor]" | ||
} | ||
func (cmd *checkCommand) ShortHelp() string { return checkShortHelp } | ||
func (cmd *checkCommand) LongHelp() string { return checkLongHelp } | ||
func (cmd *checkCommand) Hidden() bool { return false } | ||
|
||
func (cmd *checkCommand) Register(fs *flag.FlagSet) { | ||
fs.BoolVar(&cmd.skiplock, "skip-lock", false, "Skip checking that imports and Gopkg.toml are in sync with Gopkg.lock") | ||
fs.BoolVar(&cmd.skipvendor, "skip-vendor", false, "Skip checking that vendor is in sync with Gopkg.lock") | ||
fs.BoolVar(&cmd.quiet, "q", false, "Suppress non-error output") | ||
} | ||
|
||
func (cmd *checkCommand) Run(ctx *dep.Ctx, args []string) error { | ||
logger := ctx.Out | ||
if cmd.quiet { | ||
logger = log.New(ioutil.Discard, "", 0) | ||
} | ||
|
||
p, err := ctx.LoadProject() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
sm, err := ctx.SourceManager() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
sm.UseDefaultSignalHandling() | ||
defer sm.Release() | ||
|
||
var fail bool | ||
if !cmd.skiplock { | ||
if p.Lock == nil { | ||
return errors.New("Gopkg.lock does not exist, cannot check it against imports and Gopkg.toml") | ||
} | ||
|
||
lsat := verify.LockSatisfiesInputs(p.Lock, p.Manifest, p.RootPackageTree) | ||
delta := verify.DiffLocks(p.Lock, p.ChangedLock) | ||
sat, changed := lsat.Satisfied(), delta.Changed(verify.PruneOptsChanged|verify.HashVersionChanged) | ||
|
||
if changed || !sat { | ||
fail = true | ||
logger.Println("# Gopkg.lock is out of sync:") | ||
if !sat { | ||
logger.Printf("%s\n", sprintLockUnsat(lsat)) | ||
} | ||
if changed { | ||
// Sort, for deterministic output. | ||
var ordered []string | ||
for pr := range delta.ProjectDeltas { | ||
ordered = append(ordered, string(pr)) | ||
} | ||
sort.Strings(ordered) | ||
|
||
for _, pr := range ordered { | ||
lpd := delta.ProjectDeltas[gps.ProjectRoot(pr)] | ||
// Only two possible changes right now are prune opts | ||
// changing or a missing hash digest (for old Gopkg.lock | ||
// files) | ||
if lpd.PruneOptsChanged() { | ||
// Override what's on the lockdiff with the extra info we have; | ||
// this lets us excise PruneNestedVendorDirs and get the real | ||
// value from the input param in place. | ||
old := lpd.PruneOptsBefore & ^gps.PruneNestedVendorDirs | ||
new := lpd.PruneOptsAfter & ^gps.PruneNestedVendorDirs | ||
logger.Printf("%s: prune options changed (%s -> %s)\n", pr, old, new) | ||
} | ||
if lpd.HashVersionWasZero() { | ||
logger.Printf("%s: no hash digest in lock\n", pr) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
if !cmd.skipvendor { | ||
if p.Lock == nil { | ||
return errors.New("Gopkg.lock does not exist, cannot check vendor against it") | ||
} | ||
|
||
statuses, err := p.VerifyVendor() | ||
if err != nil { | ||
return errors.Wrap(err, "error while verifying vendor") | ||
} | ||
|
||
if fail { | ||
logger.Println() | ||
} | ||
|
||
var vendorfail bool | ||
// One full pass through, to see if we need to print the header, and to | ||
// create an array of names to sort for deterministic output. | ||
var ordered []string | ||
for path, status := range statuses { | ||
ordered = append(ordered, path) | ||
if status != verify.NoMismatch { | ||
fail = true | ||
if !vendorfail { | ||
vendorfail = true | ||
logger.Println("# vendor is out of sync:") | ||
} | ||
} | ||
} | ||
sort.Strings(ordered) | ||
|
||
for _, pr := range ordered { | ||
status := statuses[pr] | ||
switch status { | ||
case verify.NotInTree: | ||
logger.Printf("%s: missing from vendor\n", pr) | ||
case verify.NotInLock: | ||
fi, err := os.Stat(filepath.Join(p.AbsRoot, "vendor", pr)) | ||
if err != nil { | ||
return errors.Wrap(err, "could not stat file that VerifyVendor claimed existed") | ||
} | ||
|
||
if fi.IsDir() { | ||
logger.Printf("%s: unused project\n", pr) | ||
} else { | ||
logger.Printf("%s: orphaned file\n", pr) | ||
} | ||
case verify.DigestMismatchInLock: | ||
logger.Printf("%s: hash of vendored tree didn't match digest in Gopkg.lock\n", pr) | ||
case verify.HashVersionMismatch: | ||
// This will double-print if the hash version is zero, but | ||
// that's a rare case that really only occurs before the first | ||
// run with a version of dep >=0.5.0, so it's fine. | ||
logger.Printf("%s: hash algorithm mismatch, want version %v\n", pr, verify.HashVersion) | ||
} | ||
} | ||
} | ||
|
||
if fail { | ||
return silentfail{} | ||
} | ||
return nil | ||
} | ||
|
||
func sprintLockUnsat(lsat verify.LockSatisfaction) string { | ||
var buf bytes.Buffer | ||
sort.Strings(lsat.MissingImports) | ||
for _, missing := range lsat.MissingImports { | ||
fmt.Fprintf(&buf, "%s: missing from input-imports\n", missing) | ||
} | ||
|
||
sort.Strings(lsat.ExcessImports) | ||
for _, excess := range lsat.ExcessImports { | ||
fmt.Fprintf(&buf, "%s: in input-imports, but not imported\n", excess) | ||
} | ||
|
||
var ordered []string | ||
for pr := range lsat.UnmetOverrides { | ||
ordered = append(ordered, string(pr)) | ||
} | ||
sort.Strings(ordered) | ||
for _, pr := range ordered { | ||
unmatched := lsat.UnmetOverrides[gps.ProjectRoot(pr)] | ||
fmt.Fprintf(&buf, "%s@%s: not allowed by override %s\n", pr, unmatched.V, unmatched.C) | ||
} | ||
|
||
ordered = ordered[:0] | ||
for pr := range lsat.UnmetConstraints { | ||
ordered = append(ordered, string(pr)) | ||
} | ||
sort.Strings(ordered) | ||
for _, pr := range ordered { | ||
unmatched := lsat.UnmetConstraints[gps.ProjectRoot(pr)] | ||
fmt.Fprintf(&buf, "%s@%s: not allowed by constraint %s\n", pr, unmatched.V, unmatched.C) | ||
} | ||
return strings.TrimSpace(buf.String()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
cmd/dep/testdata/harness_tests/check/excess_inputs/final/Gopkg.lock
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Empty file.
12 changes: 12 additions & 0 deletions
12
cmd/dep/testdata/harness_tests/check/excess_inputs/initial/Gopkg.lock
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Empty file.
12 changes: 12 additions & 0 deletions
12
cmd/dep/testdata/harness_tests/check/excess_inputs/initial/main.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// Copyright 2017 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package main | ||
|
||
import ( | ||
_ "github.com/sdboyer/deptestdos" | ||
) | ||
|
||
func main() { | ||
} |
3 changes: 3 additions & 0 deletions
3
cmd/dep/testdata/harness_tests/check/excess_inputs/stdout.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Gopkg.lock is out of sync: | ||
github.com/sdboyer/deptest: in input-imports, but not imported | ||
|
7 changes: 7 additions & 0 deletions
7
cmd/dep/testdata/harness_tests/check/excess_inputs/testcase.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"commands": [ | ||
["check"] | ||
], | ||
"exit-code": 1, | ||
"vendor-final": [] | ||
} |
Oops, something went wrong.