libgo: update to Go1.14beta1
[platform/upstream/gcc.git] / libgo / go / cmd / go / internal / modfetch / fetch.go
index 51a5602..54fbd92 100644 (file)
@@ -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
        }