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

Commit aace561

Browse files
authored
Merge pull request #1932 from sdboyer/dep-check
dep: Introduce dep check subcommand
2 parents e7149d5 + 683164a commit aace561

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+766
-120
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ NEW FEATURES:
1212
* `dep ensure` now explains what changes to the code or Gopkg.toml have induced solving ([#1912](https://github.com/golang/dep/pull/1912)).
1313
* Hash digests of vendor contents are now stored in `Gopkg.lock`, and the contents of vendor are only rewritten on change or hash mismatch ([#1912](https://github.com/golang/dep/pull/1912)).
1414
* Added support for ppc64/ppc64le.
15+
* New subcommand `dep check` quickly reports if imports, Gopkg.toml, Gopkg.lock, and vendor are out of sync ([#1932](https://github.com/golang/dep/pull/1932)).
1516

1617
BUG FIXES:
1718

@@ -23,6 +24,7 @@ IMPROVEMENTS:
2324
* Reduce network access by trusting local source information and only pulling from upstream when necessary ([#1250](https://github.com/golang/dep/pull/1250)).
2425
* Update our dependency on Masterminds/semver to follow upstream again now that [Masterminds/semver#67](https://github.com/Masterminds/semver/pull/67) is merged([#1792](https://github.com/golang/dep/pull/1792)).
2526
* `inputs-digest` was removed from `Gopkg.lock` ([#1912](https://github.com/golang/dep/pull/1912)).
27+
* Hash digests of vendor contents are now stored in `Gopkg.lock`, and the contents of vendor are only rewritten on change or hash mismatch ([#1912](https://github.com/golang/dep/pull/1912)).
2628
* Don't exclude `Godeps` folder ([#1822](https://github.com/golang/dep/issues/1822)).
2729
* Add project-package relationship graph support in graphviz ([#1588](https://github.com/golang/dep/pull/1588)).
2830

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ licenseok:
1818
go build -o licenseok ./hack/licenseok/main.go
1919

2020
validate: build licenseok
21+
./dep check
2122
./hack/lint.bash
22-
./hack/validate-vendor.bash
2323
./hack/validate-licence.bash
2424

2525
test: build

cmd/dep/check.go

+216
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
// Copyright 2018 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 main
6+
7+
import (
8+
"bytes"
9+
"flag"
10+
"fmt"
11+
"io/ioutil"
12+
"log"
13+
"os"
14+
"path/filepath"
15+
"sort"
16+
"strings"
17+
18+
"github.com/golang/dep"
19+
"github.com/golang/dep/gps"
20+
"github.com/golang/dep/gps/verify"
21+
"github.com/pkg/errors"
22+
)
23+
24+
const checkShortHelp = `Check if imports, Gopkg.toml, and Gopkg.lock are in sync`
25+
const checkLongHelp = `
26+
Check determines if your project is in a good state. If problems are found, it
27+
prints a description of each issue, then exits 1. Passing -q suppresses output.
28+
29+
Flags control which specific checks will be run. By default, dep check verifies
30+
that Gopkg.lock is in sync with Gopkg.toml and the imports in your project's .go
31+
files, and that the vendor directory is in sync with Gopkg.lock. These checks
32+
can be disabled with -skip-lock and -skip-vendor, respectively.
33+
34+
(See https://golang.github.io/dep/docs/ensure-mechanics.html#staying-in-sync for
35+
more information on what it means to be "in sync.")
36+
`
37+
38+
type checkCommand struct {
39+
quiet bool
40+
skiplock, skipvendor bool
41+
}
42+
43+
func (cmd *checkCommand) Name() string { return "check" }
44+
func (cmd *checkCommand) Args() string {
45+
return "[-q] [-skip-lock] [-skip-vendor]"
46+
}
47+
func (cmd *checkCommand) ShortHelp() string { return checkShortHelp }
48+
func (cmd *checkCommand) LongHelp() string { return checkLongHelp }
49+
func (cmd *checkCommand) Hidden() bool { return false }
50+
51+
func (cmd *checkCommand) Register(fs *flag.FlagSet) {
52+
fs.BoolVar(&cmd.skiplock, "skip-lock", false, "Skip checking that imports and Gopkg.toml are in sync with Gopkg.lock")
53+
fs.BoolVar(&cmd.skipvendor, "skip-vendor", false, "Skip checking that vendor is in sync with Gopkg.lock")
54+
fs.BoolVar(&cmd.quiet, "q", false, "Suppress non-error output")
55+
}
56+
57+
func (cmd *checkCommand) Run(ctx *dep.Ctx, args []string) error {
58+
logger := ctx.Out
59+
if cmd.quiet {
60+
logger = log.New(ioutil.Discard, "", 0)
61+
}
62+
63+
p, err := ctx.LoadProject()
64+
if err != nil {
65+
return err
66+
}
67+
68+
sm, err := ctx.SourceManager()
69+
if err != nil {
70+
return err
71+
}
72+
73+
sm.UseDefaultSignalHandling()
74+
defer sm.Release()
75+
76+
var fail bool
77+
if !cmd.skiplock {
78+
if p.Lock == nil {
79+
return errors.New("Gopkg.lock does not exist, cannot check it against imports and Gopkg.toml")
80+
}
81+
82+
lsat := verify.LockSatisfiesInputs(p.Lock, p.Manifest, p.RootPackageTree)
83+
delta := verify.DiffLocks(p.Lock, p.ChangedLock)
84+
sat, changed := lsat.Satisfied(), delta.Changed(verify.PruneOptsChanged|verify.HashVersionChanged)
85+
86+
if changed || !sat {
87+
fail = true
88+
logger.Println("# Gopkg.lock is out of sync:")
89+
if !sat {
90+
logger.Printf("%s\n", sprintLockUnsat(lsat))
91+
}
92+
if changed {
93+
// Sort, for deterministic output.
94+
var ordered []string
95+
for pr := range delta.ProjectDeltas {
96+
ordered = append(ordered, string(pr))
97+
}
98+
sort.Strings(ordered)
99+
100+
for _, pr := range ordered {
101+
lpd := delta.ProjectDeltas[gps.ProjectRoot(pr)]
102+
// Only two possible changes right now are prune opts
103+
// changing or a missing hash digest (for old Gopkg.lock
104+
// files)
105+
if lpd.PruneOptsChanged() {
106+
// Override what's on the lockdiff with the extra info we have;
107+
// this lets us excise PruneNestedVendorDirs and get the real
108+
// value from the input param in place.
109+
old := lpd.PruneOptsBefore & ^gps.PruneNestedVendorDirs
110+
new := lpd.PruneOptsAfter & ^gps.PruneNestedVendorDirs
111+
logger.Printf("%s: prune options changed (%s -> %s)\n", pr, old, new)
112+
}
113+
if lpd.HashVersionWasZero() {
114+
logger.Printf("%s: no hash digest in lock\n", pr)
115+
}
116+
}
117+
}
118+
}
119+
}
120+
121+
if !cmd.skipvendor {
122+
if p.Lock == nil {
123+
return errors.New("Gopkg.lock does not exist, cannot check vendor against it")
124+
}
125+
126+
statuses, err := p.VerifyVendor()
127+
if err != nil {
128+
return errors.Wrap(err, "error while verifying vendor")
129+
}
130+
131+
if fail {
132+
logger.Println()
133+
}
134+
135+
var vendorfail bool
136+
// One full pass through, to see if we need to print the header, and to
137+
// create an array of names to sort for deterministic output.
138+
var ordered []string
139+
for path, status := range statuses {
140+
ordered = append(ordered, path)
141+
if status != verify.NoMismatch {
142+
fail = true
143+
if !vendorfail {
144+
vendorfail = true
145+
logger.Println("# vendor is out of sync:")
146+
}
147+
}
148+
}
149+
sort.Strings(ordered)
150+
151+
for _, pr := range ordered {
152+
status := statuses[pr]
153+
switch status {
154+
case verify.NotInTree:
155+
logger.Printf("%s: missing from vendor\n", pr)
156+
case verify.NotInLock:
157+
fi, err := os.Stat(filepath.Join(p.AbsRoot, "vendor", pr))
158+
if err != nil {
159+
return errors.Wrap(err, "could not stat file that VerifyVendor claimed existed")
160+
}
161+
162+
if fi.IsDir() {
163+
logger.Printf("%s: unused project\n", pr)
164+
} else {
165+
logger.Printf("%s: orphaned file\n", pr)
166+
}
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)
174+
}
175+
}
176+
}
177+
178+
if fail {
179+
return silentfail{}
180+
}
181+
return nil
182+
}
183+
184+
func sprintLockUnsat(lsat verify.LockSatisfaction) string {
185+
var buf bytes.Buffer
186+
sort.Strings(lsat.MissingImports)
187+
for _, missing := range lsat.MissingImports {
188+
fmt.Fprintf(&buf, "%s: missing from input-imports\n", missing)
189+
}
190+
191+
sort.Strings(lsat.ExcessImports)
192+
for _, excess := range lsat.ExcessImports {
193+
fmt.Fprintf(&buf, "%s: in input-imports, but not imported\n", excess)
194+
}
195+
196+
var ordered []string
197+
for pr := range lsat.UnmetOverrides {
198+
ordered = append(ordered, string(pr))
199+
}
200+
sort.Strings(ordered)
201+
for _, pr := range ordered {
202+
unmatched := lsat.UnmetOverrides[gps.ProjectRoot(pr)]
203+
fmt.Fprintf(&buf, "%s@%s: not allowed by override %s\n", pr, unmatched.V, unmatched.C)
204+
}
205+
206+
ordered = ordered[:0]
207+
for pr := range lsat.UnmetConstraints {
208+
ordered = append(ordered, string(pr))
209+
}
210+
sort.Strings(ordered)
211+
for _, pr := range ordered {
212+
unmatched := lsat.UnmetConstraints[gps.ProjectRoot(pr)]
213+
fmt.Fprintf(&buf, "%s@%s: not allowed by constraint %s\n", pr, unmatched.V, unmatched.C)
214+
}
215+
return strings.TrimSpace(buf.String())
216+
}

cmd/dep/ensure.go

+2-15
Original file line numberDiff line numberDiff line change
@@ -261,20 +261,7 @@ func (cmd *ensureCommand) runDefault(ctx *dep.Ctx, args []string, p *dep.Project
261261
lsat := verify.LockSatisfiesInputs(p.Lock, p.Manifest, params.RootPackageTree)
262262
if !lsat.Satisfied() {
263263
if ctx.Verbose {
264-
ctx.Out.Println("# Gopkg.lock is out of sync with Gopkg.toml and project code:")
265-
for _, missing := range lsat.MissingImports {
266-
ctx.Out.Printf("%s: missing from input-imports\n", missing)
267-
}
268-
for _, excess := range lsat.ExcessImports {
269-
ctx.Out.Printf("%s: in input-imports, but isn't imported\n", excess)
270-
}
271-
for pr, unmatched := range lsat.UnmetOverrides {
272-
ctx.Out.Printf("%s@%s: not allowed by override %s\n", pr, unmatched.V, unmatched.C)
273-
}
274-
for pr, unmatched := range lsat.UnmetConstraints {
275-
ctx.Out.Printf("%s@%s: not allowed by constraint %s\n", pr, unmatched.V, unmatched.C)
276-
}
277-
ctx.Out.Println()
264+
ctx.Out.Printf("# Gopkg.lock is out of sync with Gopkg.toml and project imports:\n%s\n\n", sprintLockUnsat(lsat))
278265
}
279266
solve = true
280267
} else if cmd.noVendor {
@@ -329,7 +316,7 @@ func (cmd *ensureCommand) runVendorOnly(ctx *dep.Ctx, args []string, p *dep.Proj
329316

330317
// Pass the same lock as old and new so that the writer will observe no
331318
// difference, and write out only ncessary vendor/ changes.
332-
dw, err := dep.NewSafeWriter(nil, p.Lock, p.Lock, dep.VendorAlways, p.Manifest.PruneOptions)
319+
dw, err := dep.NewSafeWriter(nil, p.Lock, p.Lock, dep.VendorAlways, p.Manifest.PruneOptions, nil)
333320
//dw, err := dep.NewDeltaWriter(p.Lock, p.Lock, p.Manifest.PruneOptions, filepath.Join(p.AbsRoot, "vendor"), dep.VendorAlways)
334321
if err != nil {
335322
return err

cmd/dep/init.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ func (cmd *initCommand) Run(ctx *dep.Ctx, args []string) error {
170170
ctx.Err.Printf("Old vendor backed up to %v", vendorbak)
171171
}
172172

173-
sw, err := dep.NewSafeWriter(p.Manifest, nil, p.Lock, dep.VendorAlways, p.Manifest.PruneOptions)
173+
sw, err := dep.NewSafeWriter(p.Manifest, nil, p.Lock, dep.VendorAlways, p.Manifest.PruneOptions, nil)
174174
if err != nil {
175175
return errors.Wrap(err, "init failed: unable to create a SafeWriter")
176176
}

cmd/dep/main.go

+19-3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ type command interface {
3939
Run(*dep.Ctx, []string) error
4040
}
4141

42+
// Helper type so that commands can fail without generating any additional
43+
// ouptut.
44+
type silentfail struct{}
45+
46+
func (silentfail) Error() string {
47+
return ""
48+
}
49+
4250
func main() {
4351
p := &profile{}
4452

@@ -139,7 +147,12 @@ func (c *Config) Run() int {
139147
// Build flag set with global flags in there.
140148
flags := flag.NewFlagSet(cmdName, flag.ContinueOnError)
141149
flags.SetOutput(c.Stderr)
142-
verbose := flags.Bool("v", false, "enable verbose logging")
150+
151+
var verbose bool
152+
// No verbose for verify
153+
if cmdName != "check" {
154+
flags.BoolVar(&verbose, "v", false, "enable verbose logging")
155+
}
143156

144157
// Register the subcommand flags in there, too.
145158
cmd.Register(flags)
@@ -186,7 +199,7 @@ func (c *Config) Run() int {
186199
ctx := &dep.Ctx{
187200
Out: outLogger,
188201
Err: errLogger,
189-
Verbose: *verbose,
202+
Verbose: verbose,
190203
DisableLocking: getEnv(c.Env, "DEPNOLOCK") != "",
191204
Cachedir: cachedir,
192205
CacheAge: cacheAge,
@@ -197,7 +210,9 @@ func (c *Config) Run() int {
197210

198211
// Run the command with the post-flag-processing args.
199212
if err := cmd.Run(ctx, flags.Args()); err != nil {
200-
errLogger.Printf("%v\n", err)
213+
if _, ok := err.(silentfail); !ok {
214+
errLogger.Printf("%v\n", err)
215+
}
201216
return errorExitCode
202217
}
203218

@@ -222,6 +237,7 @@ func commandList() []command {
222237
&ensureCommand{},
223238
&pruneCommand{},
224239
&versionCommand{},
240+
&checkCommand{},
225241
}
226242
}
227243

cmd/dep/testdata/harness_tests/check/excess_inputs/final/Gopkg.lock

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/dep/testdata/harness_tests/check/excess_inputs/final/Gopkg.toml

Whitespace-only changes.

cmd/dep/testdata/harness_tests/check/excess_inputs/initial/Gopkg.lock

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/dep/testdata/harness_tests/check/excess_inputs/initial/Gopkg.toml

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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 main
6+
7+
import (
8+
_ "github.com/sdboyer/deptestdos"
9+
)
10+
11+
func main() {
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Gopkg.lock is out of sync:
2+
github.com/sdboyer/deptest: in input-imports, but not imported
3+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"commands": [
3+
["check"]
4+
],
5+
"exit-code": 1,
6+
"vendor-final": []
7+
}

0 commit comments

Comments
 (0)