summaryrefslogtreecommitdiff
path: root/libgo/go/cmd/go/internal/modfetch/fetch.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd/go/internal/modfetch/fetch.go')
-rw-r--r--libgo/go/cmd/go/internal/modfetch/fetch.go216
1 files changed, 129 insertions, 87 deletions
diff --git a/libgo/go/cmd/go/internal/modfetch/fetch.go b/libgo/go/cmd/go/internal/modfetch/fetch.go
index 51a56028c4a..54fbd92b43e 100644
--- a/libgo/go/cmd/go/internal/modfetch/fetch.go
+++ b/libgo/go/cmd/go/internal/modfetch/fetch.go
@@ -7,6 +7,7 @@ package modfetch
import (
"archive/zip"
"bytes"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -18,10 +19,13 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
- "cmd/go/internal/dirhash"
- "cmd/go/internal/module"
+ "cmd/go/internal/lockedfile"
"cmd/go/internal/par"
"cmd/go/internal/renameio"
+
+ "golang.org/x/mod/module"
+ "golang.org/x/mod/sumdb/dirhash"
+ modzip "golang.org/x/mod/zip"
)
var downloadCache par.Cache
@@ -69,10 +73,6 @@ func download(mod module.Version, dir string) (err error) {
return err
}
- if cfg.CmdName != "mod download" {
- fmt.Fprintf(os.Stderr, "go: extracting %s %s\n", mod.Path, mod.Version)
- }
-
unlock, err := lockVersion(mod)
if err != nil {
return err
@@ -114,8 +114,7 @@ func download(mod module.Version, dir string) (err error) {
}
}()
- modpath := mod.Path + "@" + mod.Version
- if err := Unzip(tmpDir, zipfile, modpath, 0); err != nil {
+ if err := modzip.Unzip(tmpDir, mod, zipfile); err != nil {
fmt.Fprintf(os.Stderr, "-> %s\n", err)
return err
}
@@ -124,9 +123,11 @@ func download(mod module.Version, dir string) (err error) {
return err
}
- // Make dir read-only only *after* renaming it.
- // os.Rename was observed to fail for read-only directories on macOS.
- makeDirsReadOnly(dir)
+ if !cfg.ModCacheRW {
+ // Make dir read-only only *after* renaming it.
+ // os.Rename was observed to fail for read-only directories on macOS.
+ makeDirsReadOnly(dir)
+ }
return nil
}
@@ -249,7 +250,9 @@ func downloadZip(mod module.Version, zipfile string) (err error) {
if err != nil {
return err
}
- checkModSum(mod, hash)
+ if err := checkModSum(mod, hash); err != nil {
+ return err
+ }
if err := renameio.WriteFile(zipfile+"hash", []byte(hash), 0666); err != nil {
return err
@@ -263,6 +266,45 @@ func downloadZip(mod module.Version, zipfile string) (err error) {
return nil
}
+// makeDirsReadOnly makes a best-effort attempt to remove write permissions for dir
+// and its transitive contents.
+func makeDirsReadOnly(dir string) {
+ type pathMode struct {
+ path string
+ mode os.FileMode
+ }
+ var dirs []pathMode // in lexical order
+ filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ if err == nil && info.Mode()&0222 != 0 {
+ if info.IsDir() {
+ dirs = append(dirs, pathMode{path, info.Mode()})
+ }
+ }
+ return nil
+ })
+
+ // Run over list backward to chmod children before parents.
+ for i := len(dirs) - 1; i >= 0; i-- {
+ os.Chmod(dirs[i].path, dirs[i].mode&^0222)
+ }
+}
+
+// RemoveAll removes a directory written by Download or Unzip, first applying
+// any permission changes needed to do so.
+func RemoveAll(dir string) error {
+ // Module cache has 0555 directories; make them writable in order to remove content.
+ filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return nil // ignore errors walking in file system
+ }
+ if info.IsDir() {
+ os.Chmod(path, 0777)
+ }
+ return nil
+ })
+ return os.RemoveAll(dir)
+}
+
var GoSumFile string // path to go.sum; set by package modload
type modSum struct {
@@ -281,21 +323,22 @@ var goSum struct {
}
// initGoSum initializes the go.sum data.
-// It reports whether use of go.sum is now enabled.
+// The boolean it returns reports whether the
+// use of go.sum is now enabled.
// The goSum lock must be held.
-func initGoSum() bool {
+func initGoSum() (bool, error) {
if GoSumFile == "" {
- return false
+ return false, nil
}
if goSum.m != nil {
- return true
+ return true, nil
}
goSum.m = make(map[module.Version][]string)
goSum.checked = make(map[modSum]bool)
- data, err := renameio.ReadFile(GoSumFile)
+ data, err := lockedfile.Read(GoSumFile)
if err != nil && !os.IsNotExist(err) {
- base.Fatalf("go: %v", err)
+ return false, err
}
goSum.enabled = true
readGoSum(goSum.m, GoSumFile, data)
@@ -313,7 +356,7 @@ func initGoSum() bool {
}
goSum.modverify = alt
}
- return true
+ return true, nil
}
// emptyGoModHash is the hash of a 1-file tree containing a 0-length go.mod.
@@ -323,7 +366,7 @@ const emptyGoModHash = "h1:G7mAYYxgmS0lVkHyy2hEOLQCFB0DlQFTMLWggykrydY="
// readGoSum parses data, which is the content of file,
// and adds it to goSum.m. The goSum lock must be held.
-func readGoSum(dst map[module.Version][]string, file string, data []byte) {
+func readGoSum(dst map[module.Version][]string, file string, data []byte) error {
lineno := 0
for len(data) > 0 {
var line []byte
@@ -340,7 +383,7 @@ func readGoSum(dst map[module.Version][]string, file string, data []byte) {
continue
}
if len(f) != 3 {
- base.Fatalf("go: malformed go.sum:\n%s:%d: wrong number of fields %v", file, lineno, len(f))
+ return fmt.Errorf("malformed go.sum:\n%s:%d: wrong number of fields %v", file, lineno, len(f))
}
if f[2] == emptyGoModHash {
// Old bug; drop it.
@@ -349,6 +392,7 @@ func readGoSum(dst map[module.Version][]string, file string, data []byte) {
mod := module.Version{Path: f[0], Version: f[1]}
dst[mod] = append(dst[mod], f[2])
}
+ return nil
}
// checkMod checks the given module's checksum.
@@ -361,22 +405,24 @@ func checkMod(mod module.Version) {
// Do the file I/O before acquiring the go.sum lock.
ziphash, err := CachePath(mod, "ziphash")
if err != nil {
- base.Fatalf("verifying %s@%s: %v", mod.Path, mod.Version, err)
+ base.Fatalf("verifying %v", module.VersionError(mod, err))
}
data, err := renameio.ReadFile(ziphash)
if err != nil {
- if os.IsNotExist(err) {
+ if errors.Is(err, os.ErrNotExist) {
// This can happen if someone does rm -rf GOPATH/src/cache/download. So it goes.
return
}
- base.Fatalf("verifying %s@%s: %v", mod.Path, mod.Version, err)
+ base.Fatalf("verifying %v", module.VersionError(mod, err))
}
h := strings.TrimSpace(string(data))
if !strings.HasPrefix(h, "h1:") {
- base.Fatalf("verifying %s@%s: unexpected ziphash: %q", mod.Path, mod.Version, h)
+ base.Fatalf("verifying %v", module.VersionError(mod, fmt.Errorf("unexpected ziphash: %q", h)))
}
- checkModSum(mod, h)
+ if err := checkModSum(mod, h); err != nil {
+ base.Fatalf("%s", err)
+ }
}
// goModSum returns the checksum for the go.mod contents.
@@ -388,17 +434,17 @@ func goModSum(data []byte) (string, error) {
// checkGoMod checks the given module's go.mod checksum;
// data is the go.mod content.
-func checkGoMod(path, version string, data []byte) {
+func checkGoMod(path, version string, data []byte) error {
h, err := goModSum(data)
if err != nil {
- base.Fatalf("verifying %s %s go.mod: %v", path, version, err)
+ return &module.ModuleError{Path: path, Version: version, Err: fmt.Errorf("verifying go.mod: %v", err)}
}
- checkModSum(module.Version{Path: path, Version: version + "/go.mod"}, h)
+ return checkModSum(module.Version{Path: path, Version: version + "/go.mod"}, h)
}
// checkModSum checks that the recorded checksum for mod is h.
-func checkModSum(mod module.Version, h string) {
+func checkModSum(mod module.Version, h string) error {
// We lock goSum when manipulating it,
// but we arrange to release the lock when calling checkSumDB,
// so that parallel calls to checkModHash can execute parallel calls
@@ -406,19 +452,24 @@ func checkModSum(mod module.Version, h string) {
// Check whether mod+h is listed in go.sum already. If so, we're done.
goSum.mu.Lock()
- inited := initGoSum()
+ inited, err := initGoSum()
+ if err != nil {
+ return err
+ }
done := inited && haveModSumLocked(mod, h)
goSum.mu.Unlock()
if done {
- return
+ return nil
}
// Not listed, so we want to add them.
// Consult checksum database if appropriate.
if useSumDB(mod) {
// Calls base.Fatalf if mismatch detected.
- checkSumDB(mod, h)
+ if err := checkSumDB(mod, h); err != nil {
+ return err
+ }
}
// Add mod+h to go.sum, if it hasn't appeared already.
@@ -427,6 +478,7 @@ func checkModSum(mod module.Version, h string) {
addModSumLocked(mod, h)
goSum.mu.Unlock()
}
+ return nil
}
// haveModSumLocked reports whether the pair mod,h is already listed in go.sum.
@@ -460,22 +512,23 @@ func addModSumLocked(mod module.Version, h string) {
// checkSumDB checks the mod, h pair against the Go checksum database.
// It calls base.Fatalf if the hash is to be rejected.
-func checkSumDB(mod module.Version, h string) {
+func checkSumDB(mod module.Version, h string) error {
db, lines, err := lookupSumDB(mod)
if err != nil {
- base.Fatalf("verifying %s@%s: %v", mod.Path, mod.Version, err)
+ return module.VersionError(mod, fmt.Errorf("verifying module: %v", err))
}
have := mod.Path + " " + mod.Version + " " + h
prefix := mod.Path + " " + mod.Version + " h1:"
for _, line := range lines {
if line == have {
- return
+ return nil
}
if strings.HasPrefix(line, prefix) {
- base.Fatalf("verifying %s@%s: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+sumdbMismatch, mod.Path, mod.Version, h, db, line[len(prefix)-len("h1:"):])
+ return module.VersionError(mod, fmt.Errorf("verifying module: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+sumdbMismatch, h, db, line[len(prefix)-len("h1:"):]))
}
}
+ return nil
}
// Sum returns the checksum for the downloaded copy of the given module,
@@ -516,60 +569,45 @@ func WriteGoSum() {
base.Fatalf("go: updates to go.sum needed, disabled by -mod=readonly")
}
- // We want to avoid races between creating the lockfile and deleting it, but
- // we also don't want to leave a permanent lockfile in the user's repository.
- //
- // On top of that, if we crash while writing go.sum, we don't want to lose the
- // sums that were already present in the file, so it's important that we write
- // the file by renaming rather than truncating — which means that we can't
- // lock the go.sum file itself.
- //
- // Instead, we'll lock a distinguished file in the cache directory: that will
- // only race if the user runs `go clean -modcache` concurrently with a command
- // that updates go.sum, and that's already racy to begin with.
- //
- // We'll end up slightly over-synchronizing go.sum writes if the user runs a
- // bunch of go commands that update sums in separate modules simultaneously,
- // but that's unlikely to matter in practice.
-
- unlock := SideLock()
- defer unlock()
+ // Make a best-effort attempt to acquire the side lock, only to exclude
+ // previous versions of the 'go' command from making simultaneous edits.
+ if unlock, err := SideLock(); err == nil {
+ defer unlock()
+ }
- if !goSum.overwrite {
- // Re-read the go.sum file to incorporate any sums added by other processes
- // in the meantime.
- data, err := renameio.ReadFile(GoSumFile)
- if err != nil && !os.IsNotExist(err) {
- base.Fatalf("go: re-reading go.sum: %v", err)
- }
-
- // Add only the sums that we actually checked: the user may have edited or
- // truncated the file to remove erroneous hashes, and we shouldn't restore
- // them without good reason.
- goSum.m = make(map[module.Version][]string, len(goSum.m))
- readGoSum(goSum.m, GoSumFile, data)
- for ms := range goSum.checked {
- addModSumLocked(ms.mod, ms.sum)
- goSum.dirty = true
+ err := lockedfile.Transform(GoSumFile, func(data []byte) ([]byte, error) {
+ if !goSum.overwrite {
+ // Incorporate any sums added by other processes in the meantime.
+ // Add only the sums that we actually checked: the user may have edited or
+ // truncated the file to remove erroneous hashes, and we shouldn't restore
+ // them without good reason.
+ goSum.m = make(map[module.Version][]string, len(goSum.m))
+ readGoSum(goSum.m, GoSumFile, data)
+ for ms := range goSum.checked {
+ addModSumLocked(ms.mod, ms.sum)
+ goSum.dirty = true
+ }
}
- }
- var mods []module.Version
- for m := range goSum.m {
- mods = append(mods, m)
- }
- module.Sort(mods)
- var buf bytes.Buffer
- for _, m := range mods {
- list := goSum.m[m]
- sort.Strings(list)
- for _, h := range list {
- fmt.Fprintf(&buf, "%s %s %s\n", m.Path, m.Version, h)
+ var mods []module.Version
+ for m := range goSum.m {
+ mods = append(mods, m)
}
- }
+ module.Sort(mods)
+
+ var buf bytes.Buffer
+ for _, m := range mods {
+ list := goSum.m[m]
+ sort.Strings(list)
+ for _, h := range list {
+ fmt.Fprintf(&buf, "%s %s %s\n", m.Path, m.Version, h)
+ }
+ }
+ return buf.Bytes(), nil
+ })
- if err := renameio.WriteFile(GoSumFile, buf.Bytes(), 0666); err != nil {
- base.Fatalf("go: writing go.sum: %v", err)
+ if err != nil {
+ base.Fatalf("go: updating go.sum: %v", err)
}
goSum.checked = make(map[modSum]bool)
@@ -585,7 +623,11 @@ func WriteGoSum() {
func TrimGoSum(keep map[module.Version]bool) {
goSum.mu.Lock()
defer goSum.mu.Unlock()
- if !initGoSum() {
+ inited, err := initGoSum()
+ if err != nil {
+ base.Fatalf("%s", err)
+ }
+ if !inited {
return
}