mirror of git://gcc.gnu.org/git/gcc.git
129 lines
3.3 KiB
Go
129 lines
3.3 KiB
Go
// 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 modcmd
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"runtime"
|
|
|
|
"cmd/go/internal/base"
|
|
"cmd/go/internal/modfetch"
|
|
"cmd/go/internal/modload"
|
|
|
|
"golang.org/x/mod/module"
|
|
"golang.org/x/mod/sumdb/dirhash"
|
|
)
|
|
|
|
var cmdVerify = &base.Command{
|
|
UsageLine: "go mod verify",
|
|
Short: "verify dependencies have expected content",
|
|
Long: `
|
|
Verify checks that the dependencies of the current module,
|
|
which are stored in a local downloaded source cache, have not been
|
|
modified since being downloaded. If all the modules are unmodified,
|
|
verify prints "all modules verified." Otherwise it reports which
|
|
modules have been changed and causes 'go mod' to exit with a
|
|
non-zero status.
|
|
|
|
See https://golang.org/ref/mod#go-mod-verify for more about 'go mod verify'.
|
|
`,
|
|
Run: runVerify,
|
|
}
|
|
|
|
func init() {
|
|
base.AddModCommonFlags(&cmdVerify.Flag)
|
|
}
|
|
|
|
func runVerify(ctx context.Context, cmd *base.Command, args []string) {
|
|
if len(args) != 0 {
|
|
// NOTE(rsc): Could take a module pattern.
|
|
base.Fatalf("go mod verify: verify takes no arguments")
|
|
}
|
|
modload.ForceUseModules = true
|
|
modload.RootMode = modload.NeedRoot
|
|
|
|
// Only verify up to GOMAXPROCS zips at once.
|
|
type token struct{}
|
|
sem := make(chan token, runtime.GOMAXPROCS(0))
|
|
|
|
// Use a slice of result channels, so that the output is deterministic.
|
|
mods := modload.LoadAllModules(ctx)[1:]
|
|
errsChans := make([]<-chan []error, len(mods))
|
|
|
|
for i, mod := range mods {
|
|
sem <- token{}
|
|
errsc := make(chan []error, 1)
|
|
errsChans[i] = errsc
|
|
mod := mod // use a copy to avoid data races
|
|
go func() {
|
|
errsc <- verifyMod(mod)
|
|
<-sem
|
|
}()
|
|
}
|
|
|
|
ok := true
|
|
for _, errsc := range errsChans {
|
|
errs := <-errsc
|
|
for _, err := range errs {
|
|
base.Errorf("%s", err)
|
|
ok = false
|
|
}
|
|
}
|
|
if ok {
|
|
fmt.Printf("all modules verified\n")
|
|
}
|
|
}
|
|
|
|
func verifyMod(mod module.Version) []error {
|
|
var errs []error
|
|
zip, zipErr := modfetch.CachePath(mod, "zip")
|
|
if zipErr == nil {
|
|
_, zipErr = os.Stat(zip)
|
|
}
|
|
dir, dirErr := modfetch.DownloadDir(mod)
|
|
data, err := os.ReadFile(zip + "hash")
|
|
if err != nil {
|
|
if zipErr != nil && errors.Is(zipErr, fs.ErrNotExist) &&
|
|
dirErr != nil && errors.Is(dirErr, fs.ErrNotExist) {
|
|
// Nothing downloaded yet. Nothing to verify.
|
|
return nil
|
|
}
|
|
errs = append(errs, fmt.Errorf("%s %s: missing ziphash: %v", mod.Path, mod.Version, err))
|
|
return errs
|
|
}
|
|
h := string(bytes.TrimSpace(data))
|
|
|
|
if zipErr != nil && errors.Is(zipErr, fs.ErrNotExist) {
|
|
// ok
|
|
} else {
|
|
hZ, err := dirhash.HashZip(zip, dirhash.DefaultHash)
|
|
if err != nil {
|
|
errs = append(errs, fmt.Errorf("%s %s: %v", mod.Path, mod.Version, err))
|
|
return errs
|
|
} else if hZ != h {
|
|
errs = append(errs, fmt.Errorf("%s %s: zip has been modified (%v)", mod.Path, mod.Version, zip))
|
|
}
|
|
}
|
|
if dirErr != nil && errors.Is(dirErr, fs.ErrNotExist) {
|
|
// ok
|
|
} else {
|
|
hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash)
|
|
if err != nil {
|
|
|
|
errs = append(errs, fmt.Errorf("%s %s: %v", mod.Path, mod.Version, err))
|
|
return errs
|
|
}
|
|
if hD != h {
|
|
errs = append(errs, fmt.Errorf("%s %s: dir has been modified (%v)", mod.Path, mod.Version, dir))
|
|
}
|
|
}
|
|
return errs
|
|
}
|