diff --git a/README.md b/README.md index 575751c..2f3254b 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,4 @@ these packages importable, but everything is otherwise unchanged. ## Re-extracting -The `extract/` directory contains the code to do this. Run the Go program, then -copy the contents of the `out/github.com/dependabot/gomodules-extracted` -directory to the top level of this repo. +Run `script/extract`. diff --git a/cmd/go/_internal_/cfg/zdefaultcc.go b/cmd/go/_internal_/cfg/zdefaultcc.go index 5f45a57..7297f75 100644 --- a/cmd/go/_internal_/cfg/zdefaultcc.go +++ b/cmd/go/_internal_/cfg/zdefaultcc.go @@ -7,10 +7,10 @@ const DefaultPkgConfig = `pkg-config` func DefaultCC(goos, goarch string) string { switch goos + `/` + goarch { } - return "gcc" + return "clang" } func DefaultCXX(goos, goarch string) string { switch goos + `/` + goarch { } - return "g++" + return "clang++" } diff --git a/cmd/go/_internal_/robustio/robustio_darwin.go b/cmd/go/_internal_/robustio/robustio_darwin.go new file mode 100644 index 0000000..99fd8eb --- /dev/null +++ b/cmd/go/_internal_/robustio/robustio_darwin.go @@ -0,0 +1,21 @@ +// Copyright 2019 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 robustio + +import ( + "errors" + "syscall" +) + +const errFileNotFound = syscall.ENOENT + +// isEphemeralError returns true if err may be resolved by waiting. +func isEphemeralError(err error) bool { + var errno syscall.Errno + if errors.As(err, &errno) { + return errno == errFileNotFound + } + return false +} diff --git a/cmd/go/_internal_/robustio/robustio_flaky.go b/cmd/go/_internal_/robustio/robustio_flaky.go new file mode 100644 index 0000000..3f0d75e --- /dev/null +++ b/cmd/go/_internal_/robustio/robustio_flaky.go @@ -0,0 +1,92 @@ +// Copyright 2019 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. + +// +build windows darwin + +package robustio + +import ( + "errors" + "io/ioutil" + "math/rand" + "os" + "syscall" + "time" +) + +const arbitraryTimeout = 2000 * time.Millisecond + +// retry retries ephemeral errors from f up to an arbitrary timeout +// to work around filesystem flakiness on Windows and Darwin. +func retry(f func() (err error, mayRetry bool)) error { + var ( + bestErr error + lowestErrno syscall.Errno + start time.Time + nextSleep time.Duration = 1 * time.Millisecond + ) + for { + err, mayRetry := f() + if err == nil || !mayRetry { + return err + } + + var errno syscall.Errno + if errors.As(err, &errno) && (lowestErrno == 0 || errno < lowestErrno) { + bestErr = err + lowestErrno = errno + } else if bestErr == nil { + bestErr = err + } + + if start.IsZero() { + start = time.Now() + } else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout { + break + } + time.Sleep(nextSleep) + nextSleep += time.Duration(rand.Int63n(int64(nextSleep))) + } + + return bestErr +} + +// rename is like os.Rename, but retries ephemeral errors. +// +// On Windows it wraps os.Rename, which (as of 2019-06-04) uses MoveFileEx with +// MOVEFILE_REPLACE_EXISTING. +// +// Windows also provides a different system call, ReplaceFile, +// that provides similar semantics, but perhaps preserves more metadata. (The +// documentation on the differences between the two is very sparse.) +// +// Empirical error rates with MoveFileEx are lower under modest concurrency, so +// for now we're sticking with what the os package already provides. +func rename(oldpath, newpath string) (err error) { + return retry(func() (err error, mayRetry bool) { + err = os.Rename(oldpath, newpath) + return err, isEphemeralError(err) + }) +} + +// readFile is like ioutil.ReadFile, but retries ephemeral errors. +func readFile(filename string) ([]byte, error) { + var b []byte + err := retry(func() (err error, mayRetry bool) { + b, err = ioutil.ReadFile(filename) + + // Unlike in rename, we do not retry errFileNotFound here: it can occur + // as a spurious error, but the file may also genuinely not exist, so the + // increase in robustness is probably not worth the extra latency. + return err, isEphemeralError(err) && !errors.Is(err, errFileNotFound) + }) + return b, err +} + +func removeAll(path string) error { + return retry(func() (err error, mayRetry bool) { + err = os.RemoveAll(path) + return err, isEphemeralError(err) + }) +} diff --git a/script/extract b/script/extract new file mode 100755 index 0000000..dcd166e --- /dev/null +++ b/script/extract @@ -0,0 +1,7 @@ +#!/bin/sh + +(cd extract && go run .) && rsync -rcv extract/out/github.com/dependabot/gomodules-extracted/* . + +curl -sL https://raw.githubusercontent.com/golang/go/master/LICENSE | tee _internal_/LICENSE > cmd/LICENSE +git add _internal_ cmd +