diff -Nru golang-github-rogpeppe-go-internal-1.11.0/.github/workflows/test.yml golang-github-rogpeppe-go-internal-1.12.0/.github/workflows/test.yml --- golang-github-rogpeppe-go-internal-1.11.0/.github/workflows/test.yml 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/.github/workflows/test.yml 2023-12-13 11:29:26.000000000 +0000 @@ -12,8 +12,8 @@ fail-fast: false matrix: go-version: - - '1.19.x' - '1.20.x' + - '1.21.x' os: - ubuntu-latest - macos-latest @@ -21,7 +21,7 @@ runs-on: ${{ matrix.os }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Go uses: actions/setup-go@v4 with: @@ -33,7 +33,7 @@ go test -race ./... - name: Tidy - if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.20.x' # no need to do this everywhere + if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.21.x' # no need to do this everywhere run: | go mod tidy diff -Nru golang-github-rogpeppe-go-internal-1.11.0/cmd/testscript/testdata/noproxy.txt golang-github-rogpeppe-go-internal-1.12.0/cmd/testscript/testdata/noproxy.txt --- golang-github-rogpeppe-go-internal-1.11.0/cmd/testscript/testdata/noproxy.txt 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/cmd/testscript/testdata/noproxy.txt 2023-12-13 11:29:26.000000000 +0000 @@ -1,10 +1,12 @@ # With no .gomodproxy supporting files, we use the GOPROXY from # the environment. +# Note that Go 1.21 started quoting with single quotes in "go env", +# where older versions used double quotes. env GOPROXY=0.1.2.3 unquote file.txt testscript -v file.txt -- file.txt -- >go env ->[!windows] stdout '^GOPROXY="0.1.2.3"$' +>[!windows] stdout '^GOPROXY=[''"]0.1.2.3[''"]$' >[windows] stdout '^set GOPROXY=0.1.2.3$' diff -Nru golang-github-rogpeppe-go-internal-1.11.0/cmd/txtar-addmod/addmod.go golang-github-rogpeppe-go-internal-1.12.0/cmd/txtar-addmod/addmod.go --- golang-github-rogpeppe-go-internal-1.11.0/cmd/txtar-addmod/addmod.go 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/cmd/txtar-addmod/addmod.go 2023-12-13 11:29:26.000000000 +0000 @@ -21,7 +21,6 @@ "bytes" "flag" "fmt" - "io/ioutil" "log" "os" "os/exec" @@ -82,7 +81,7 @@ log.SetFlags(0) var err error - tmpdir, err = ioutil.TempDir("", "txtar-addmod-") + tmpdir, err = os.MkdirTemp("", "txtar-addmod-") if err != nil { log.Fatal(err) } @@ -106,7 +105,7 @@ exitCode := 0 for _, arg := range modules { - if err := ioutil.WriteFile(filepath.Join(tmpdir, "go.mod"), []byte("module m\n"), 0o666); err != nil { + if err := os.WriteFile(filepath.Join(tmpdir, "go.mod"), []byte("module m\n"), 0o666); err != nil { fatalf("%v", err) } run(goCmd, "get", "-d", arg) @@ -130,13 +129,13 @@ } path = encpath - mod, err := ioutil.ReadFile(filepath.Join(gopath, "pkg/mod/cache/download", path, "@v", vers+".mod")) + mod, err := os.ReadFile(filepath.Join(gopath, "pkg/mod/cache/download", path, "@v", vers+".mod")) if err != nil { log.Printf("%s: %v", arg, err) exitCode = 1 continue } - info, err := ioutil.ReadFile(filepath.Join(gopath, "pkg/mod/cache/download", path, "@v", vers+".info")) + info, err := os.ReadFile(filepath.Join(gopath, "pkg/mod/cache/download", path, "@v", vers+".info")) if err != nil { log.Printf("%s: %v", arg, err) exitCode = 1 @@ -149,7 +148,7 @@ title += "@" + vers } dir = filepath.Clean(dir) - modDir := strings.Replace(path, "/", "_", -1) + "_" + vers + modDir := strings.ReplaceAll(path, "/", "_") + "_" + vers filePrefix := "" if targetDir == "-" { filePrefix = ".gomodproxy/" + modDir + "/" @@ -162,6 +161,9 @@ {Name: filePrefix + ".info", Data: info}, } err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } if !info.Mode().IsRegular() { return nil } @@ -177,7 +179,7 @@ // not including all files via -all return nil } - data, err := ioutil.ReadFile(path) + data, err := os.ReadFile(path) if err != nil { return err } @@ -201,7 +203,7 @@ break } } else { - if err := ioutil.WriteFile(filepath.Join(targetDir, modDir+".txtar"), data, 0o666); err != nil { + if err := os.WriteFile(filepath.Join(targetDir, modDir+".txtar"), data, 0o666); err != nil { log.Printf("%s: %v", arg, err) exitCode = 1 continue diff -Nru golang-github-rogpeppe-go-internal-1.11.0/cmd/txtar-c/savedir.go golang-github-rogpeppe-go-internal-1.12.0/cmd/txtar-c/savedir.go --- golang-github-rogpeppe-go-internal-1.11.0/cmd/txtar-c/savedir.go 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/cmd/txtar-c/savedir.go 2023-12-13 11:29:26.000000000 +0000 @@ -16,7 +16,6 @@ "bytes" stdflag "flag" "fmt" - "io/ioutil" "log" "os" "path/filepath" @@ -59,7 +58,10 @@ a := new(txtar.Archive) dir = filepath.Clean(dir) - filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } if path == dir { return nil } @@ -73,9 +75,9 @@ if !info.Mode().IsRegular() { return nil } - data, err := ioutil.ReadFile(path) + data, err := os.ReadFile(path) if err != nil { - log.Fatal(err) + return err } if !utf8.Valid(data) { log.Printf("%s: ignoring file with invalid UTF-8 data", path) @@ -103,7 +105,9 @@ Data: data, }) return nil - }) + }); err != nil { + log.Fatal(err) + } data := txtar.Format(a) os.Stdout.Write(data) diff -Nru golang-github-rogpeppe-go-internal-1.11.0/cmd/txtar-x/extract.go golang-github-rogpeppe-go-internal-1.12.0/cmd/txtar-x/extract.go --- golang-github-rogpeppe-go-internal-1.11.0/cmd/txtar-x/extract.go 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/cmd/txtar-x/extract.go 2023-12-13 11:29:26.000000000 +0000 @@ -15,7 +15,7 @@ import ( "flag" "fmt" - "io/ioutil" + "io" "log" "os" @@ -47,7 +47,7 @@ var a *txtar.Archive if flag.NArg() == 0 { - data, err := ioutil.ReadAll(os.Stdin) + data, err := io.ReadAll(os.Stdin) if err != nil { log.Printf("cannot read stdin: %v", err) return 1 diff -Nru golang-github-rogpeppe-go-internal-1.11.0/cmd/txtar-x/extract_test.go golang-github-rogpeppe-go-internal-1.12.0/cmd/txtar-x/extract_test.go --- golang-github-rogpeppe-go-internal-1.11.0/cmd/txtar-x/extract_test.go 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/cmd/txtar-x/extract_test.go 2023-12-13 11:29:26.000000000 +0000 @@ -6,7 +6,6 @@ import ( "bytes" - "io/ioutil" "os" "testing" @@ -34,11 +33,11 @@ } for _, arg := range args { file := ts.MkAbs(arg) - data, err := ioutil.ReadFile(file) + data, err := os.ReadFile(file) ts.Check(err) data = bytes.Replace(data, []byte("\n>"), []byte("\n"), -1) data = bytes.TrimPrefix(data, []byte(">")) - err = ioutil.WriteFile(file, data, 0o666) + err = os.WriteFile(file, data, 0o666) ts.Check(err) } } diff -Nru golang-github-rogpeppe-go-internal-1.11.0/debian/changelog golang-github-rogpeppe-go-internal-1.12.0/debian/changelog --- golang-github-rogpeppe-go-internal-1.11.0/debian/changelog 2023-10-23 11:28:09.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/debian/changelog 2024-03-02 18:58:34.000000000 +0000 @@ -1,8 +1,32 @@ -golang-github-rogpeppe-go-internal (1.11.0-1~bpo22.04+1) jammy; urgency=medium +golang-github-rogpeppe-go-internal (1.12.0-3~bpo22.04+1) jammy; urgency=medium * Rebuild for jammy. - -- Mateusz Łukasik Mon, 23 Oct 2023 13:28:09 +0200 + -- Mateusz Łukasik Sat, 02 Mar 2024 19:58:34 +0100 + +golang-github-rogpeppe-go-internal (1.12.0-3) unstable; urgency=medium + + [ Jérémy Lal ] + * Revert "Patch to skip failing pty test on s390x" + * Patch: testscript: fix ptyName() on s390x + + -- Anthony Fok Mon, 19 Feb 2024 08:19:25 -0700 + +golang-github-rogpeppe-go-internal (1.12.0-2) unstable; urgency=medium + + * Team upload + * Patch to skip failing pty test on s390x + + -- Jérémy Lal Fri, 16 Feb 2024 10:14:13 +0100 + +golang-github-rogpeppe-go-internal (1.12.0-1) unstable; urgency=medium + + * New upstream version 1.12.0 + * Bump build-dependency golang-any (>= 2:1.20~) as per go.mod + * Remove 0001-Fix-test-with-golang-1.21.patch + as upstream has updated the test for go 1.21 + + -- Anthony Fok Wed, 31 Jan 2024 05:43:33 -0700 golang-github-rogpeppe-go-internal (1.11.0-1) unstable; urgency=medium diff -Nru golang-github-rogpeppe-go-internal-1.11.0/debian/control golang-github-rogpeppe-go-internal-1.12.0/debian/control --- golang-github-rogpeppe-go-internal-1.11.0/debian/control 2023-07-28 09:12:15.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/debian/control 2024-01-31 12:37:27.000000000 +0000 @@ -7,7 +7,7 @@ Build-Depends: ca-certificates, debhelper-compat (= 13), dh-sequence-golang, - golang-any (>= 2:1.19~), + golang-any (>= 2:1.20~), golang-golang-x-mod-dev (>= 0.9.0), golang-golang-x-sys-dev (>= 0.0~git20220722.8c9f86f), golang-golang-x-tools-dev (>= 1:0.1.12) diff -Nru golang-github-rogpeppe-go-internal-1.11.0/debian/patches/0001-Fix-test-with-golang-1.21.patch golang-github-rogpeppe-go-internal-1.12.0/debian/patches/0001-Fix-test-with-golang-1.21.patch --- golang-github-rogpeppe-go-internal-1.11.0/debian/patches/0001-Fix-test-with-golang-1.21.patch 2023-07-28 09:12:15.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/debian/patches/0001-Fix-test-with-golang-1.21.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -From: Shengjing Zhu -Date: Fri, 28 Jul 2023 17:11:26 +0800 -Subject: Fix test with golang-1.21 - ---- - cmd/testscript/testdata/noproxy.txt | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/cmd/testscript/testdata/noproxy.txt b/cmd/testscript/testdata/noproxy.txt -index f725a27..4ae1f05 100644 ---- a/cmd/testscript/testdata/noproxy.txt -+++ b/cmd/testscript/testdata/noproxy.txt -@@ -6,5 +6,6 @@ testscript -v file.txt - - -- file.txt -- - >go env -->[!windows] stdout '^GOPROXY="0.1.2.3"$' -+>[!windows] [!go1.21] stdout '^GOPROXY="0.1.2.3"$' -+>[!windows] [go1.21] stdout '^GOPROXY=''0.1.2.3''$' - >[windows] stdout '^set GOPROXY=0.1.2.3$' diff -Nru golang-github-rogpeppe-go-internal-1.11.0/debian/patches/246.patch golang-github-rogpeppe-go-internal-1.12.0/debian/patches/246.patch --- golang-github-rogpeppe-go-internal-1.11.0/debian/patches/246.patch 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/debian/patches/246.patch 2024-02-16 10:38:22.000000000 +0000 @@ -0,0 +1,29 @@ +From 86ed44b264645993e4cb1e31e7995e4b21097f3d Mon Sep 17 00:00:00 2001 +From: Anthony Fok +Date: Fri, 16 Feb 2024 02:50:21 -0700 +Subject: [PATCH] testscript: fix ptyName() returning /dev/pts/4294967296 on + s390x + +Use uint32 instead of uint (64-bit in Go on s390x) to store the return +value of the TIOCGPTN syscall. This is to avoid the 32-bit value from +being stored into a 64-bit buffer and get left-shifted by 32 when +dereferencing, turning what should be /dev/pts/1 to /dev/pts/4294967296 +on big-endian architectures such as s390x. + +Special thanks to the explanation and a similar bug fix provided at +https://github.com/containerd/console/pull/51 +--- + testscript/internal/pty/pty_linux.go | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/testscript/internal/pty/pty_linux.go ++++ b/testscript/internal/pty/pty_linux.go +@@ -8,7 +8,7 @@ + ) + + func ptyName(f *os.File) (string, error) { +- var out uint ++ var out uint32 + err := ioctl(f, "TIOCGPTN", syscall.TIOCGPTN, uintptr(unsafe.Pointer(&out))) + if err != nil { + return "", err diff -Nru golang-github-rogpeppe-go-internal-1.11.0/debian/patches/series golang-github-rogpeppe-go-internal-1.12.0/debian/patches/series --- golang-github-rogpeppe-go-internal-1.11.0/debian/patches/series 2023-07-28 09:12:15.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/debian/patches/series 2024-02-16 10:38:22.000000000 +0000 @@ -1 +1 @@ -0001-Fix-test-with-golang-1.21.patch +246.patch diff -Nru golang-github-rogpeppe-go-internal-1.11.0/go.mod golang-github-rogpeppe-go-internal-1.12.0/go.mod --- golang-github-rogpeppe-go-internal-1.11.0/go.mod 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/go.mod 2023-12-13 11:29:26.000000000 +0000 @@ -1,6 +1,6 @@ module github.com/rogpeppe/go-internal -go 1.19 +go 1.20 require ( golang.org/x/mod v0.9.0 diff -Nru golang-github-rogpeppe-go-internal-1.11.0/goproxytest/proxy.go golang-github-rogpeppe-go-internal-1.12.0/goproxytest/proxy.go --- golang-github-rogpeppe-go-internal-1.11.0/goproxytest/proxy.go 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/goproxytest/proxy.go 2023-12-13 11:29:26.000000000 +0000 @@ -26,7 +26,7 @@ "bytes" "encoding/json" "fmt" - "io/ioutil" + "io/fs" "log" "net" "net/http" @@ -91,18 +91,18 @@ } func (srv *Server) readModList() error { - infos, err := ioutil.ReadDir(srv.dir) + entries, err := os.ReadDir(srv.dir) if err != nil { return err } - for _, info := range infos { - name := info.Name() + for _, entry := range entries { + name := entry.Name() switch { case strings.HasSuffix(name, ".txt"): name = strings.TrimSuffix(name, ".txt") case strings.HasSuffix(name, ".txtar"): name = strings.TrimSuffix(name, ".txtar") - case info.IsDir(): + case entry.IsDir(): default: continue } @@ -110,7 +110,7 @@ if i < 0 { continue } - encPath := strings.Replace(name[:i], "_", "/", -1) + encPath := strings.ReplaceAll(name[:i], "_", "/") path, err := module.UnescapePath(encPath) if err != nil { return fmt.Errorf("cannot decode module path in %q: %v", name, err) @@ -286,7 +286,7 @@ return nil } - prefix := strings.Replace(enc, "/", "_", -1) + prefix := strings.ReplaceAll(enc, "/", "_") name := filepath.Join(srv.dir, prefix+"_"+encVers) txtName := name + ".txt" txtarName := name + ".txtar" @@ -300,18 +300,18 @@ // fall back to trying a directory a = new(txtar.Archive) - err = filepath.Walk(name, func(path string, info os.FileInfo, err error) error { + err = filepath.WalkDir(name, func(path string, entry fs.DirEntry, err error) error { if err != nil { return err } - if path == name && !info.IsDir() { + if path == name && !entry.IsDir() { return fmt.Errorf("expected a directory root") } - if info.IsDir() { + if entry.IsDir() { return nil } arpath := filepath.ToSlash(strings.TrimPrefix(path, name+string(os.PathSeparator))) - data, err := ioutil.ReadFile(path) + data, err := os.ReadFile(path) if err != nil { return err } diff -Nru golang-github-rogpeppe-go-internal-1.11.0/gotooltest/testdata/cover.txt golang-github-rogpeppe-go-internal-1.12.0/gotooltest/testdata/cover.txt --- golang-github-rogpeppe-go-internal-1.11.0/gotooltest/testdata/cover.txt 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/gotooltest/testdata/cover.txt 2023-12-13 11:29:26.000000000 +0000 @@ -13,12 +13,9 @@ # Then, a 'go test' run with -coverprofile. # The total coverage after merging profiles should end up being 100%. # Marking all printlns as covered requires all edge cases to work well. -# Go 1.20 learned to produce and merge multiple coverage profiles, -# so versions before then report a shallow 0% coverage. go test -vet=off -coverprofile=cover.out -v stdout 'PASS' -[go1.20] stdout 'coverage: 100\.0%' -[!go1.20] stdout 'coverage: 0\.0%' +stdout 'coverage: 100\.0%' ! stdout 'malformed coverage' # written by "go test" if cover.out is invalid exists cover.out diff -Nru golang-github-rogpeppe-go-internal-1.11.0/robustio/robustio.go golang-github-rogpeppe-go-internal-1.12.0/robustio/robustio.go --- golang-github-rogpeppe-go-internal-1.11.0/robustio/robustio.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/robustio/robustio.go 2023-12-13 11:29:26.000000000 +0000 @@ -0,0 +1,53 @@ +// 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 wraps I/O functions that are prone to failure on Windows, +// transparently retrying errors up to an arbitrary timeout. +// +// Errors are classified heuristically and retries are bounded, so the functions +// in this package do not completely eliminate spurious errors. However, they do +// significantly reduce the rate of failure in practice. +// +// If so, the error will likely wrap one of: +// The functions in this package do not completely eliminate spurious errors, +// but substantially reduce their rate of occurrence in practice. +package robustio + +// Rename is like os.Rename, but on Windows retries errors that may occur if the +// file is concurrently read or overwritten. +// +// (See golang.org/issue/31247 and golang.org/issue/32188.) +func Rename(oldpath, newpath string) error { + return rename(oldpath, newpath) +} + +// ReadFile is like os.ReadFile, but on Windows retries errors that may +// occur if the file is concurrently replaced. +// +// (See golang.org/issue/31247 and golang.org/issue/32188.) +func ReadFile(filename string) ([]byte, error) { + return readFile(filename) +} + +// RemoveAll is like os.RemoveAll, but on Windows retries errors that may occur +// if an executable file in the directory has recently been executed. +// +// (See golang.org/issue/19491.) +func RemoveAll(path string) error { + return removeAll(path) +} + +// IsEphemeralError reports whether err is one of the errors that the functions +// in this package attempt to mitigate. +// +// Errors considered ephemeral include: +// - syscall.ERROR_ACCESS_DENIED +// - syscall.ERROR_FILE_NOT_FOUND +// - internal/syscall/windows.ERROR_SHARING_VIOLATION +// +// This set may be expanded in the future; programs must not rely on the +// non-ephemerality of any given error. +func IsEphemeralError(err error) bool { + return isEphemeralError(err) +} diff -Nru golang-github-rogpeppe-go-internal-1.11.0/robustio/robustio_darwin.go golang-github-rogpeppe-go-internal-1.12.0/robustio/robustio_darwin.go --- golang-github-rogpeppe-go-internal-1.11.0/robustio/robustio_darwin.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/robustio/robustio_darwin.go 2023-12-13 11:29:26.000000000 +0000 @@ -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 -Nru golang-github-rogpeppe-go-internal-1.11.0/robustio/robustio_flaky.go golang-github-rogpeppe-go-internal-1.12.0/robustio/robustio_flaky.go --- golang-github-rogpeppe-go-internal-1.11.0/robustio/robustio_flaky.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/robustio/robustio_flaky.go 2023-12-13 11:29:26.000000000 +0000 @@ -0,0 +1,91 @@ +// 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. + +//go:build windows || darwin + +package robustio + +import ( + "errors" + "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 os.ReadFile, but retries ephemeral errors. +func readFile(filename string) ([]byte, error) { + var b []byte + err := retry(func() (err error, mayRetry bool) { + b, err = os.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 -Nru golang-github-rogpeppe-go-internal-1.11.0/robustio/robustio_other.go golang-github-rogpeppe-go-internal-1.12.0/robustio/robustio_other.go --- golang-github-rogpeppe-go-internal-1.11.0/robustio/robustio_other.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/robustio/robustio_other.go 2023-12-13 11:29:26.000000000 +0000 @@ -0,0 +1,27 @@ +// 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. + +//go:build !windows && !darwin + +package robustio + +import ( + "os" +) + +func rename(oldpath, newpath string) error { + return os.Rename(oldpath, newpath) +} + +func readFile(filename string) ([]byte, error) { + return os.ReadFile(filename) +} + +func removeAll(path string) error { + return os.RemoveAll(path) +} + +func isEphemeralError(err error) bool { + return false +} diff -Nru golang-github-rogpeppe-go-internal-1.11.0/robustio/robustio_windows.go golang-github-rogpeppe-go-internal-1.12.0/robustio/robustio_windows.go --- golang-github-rogpeppe-go-internal-1.11.0/robustio/robustio_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/robustio/robustio_windows.go 2023-12-13 11:29:26.000000000 +0000 @@ -0,0 +1,28 @@ +// 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" + + "github.com/rogpeppe/go-internal/internal/syscall/windows" +) + +const errFileNotFound = syscall.ERROR_FILE_NOT_FOUND + +// isEphemeralError returns true if err may be resolved by waiting. +func isEphemeralError(err error) bool { + var errno syscall.Errno + if errors.As(err, &errno) { + switch errno { + case syscall.ERROR_ACCESS_DENIED, + syscall.ERROR_FILE_NOT_FOUND, + windows.ERROR_SHARING_VIOLATION: + return true + } + } + return false +} diff -Nru golang-github-rogpeppe-go-internal-1.11.0/testscript/cmd.go golang-github-rogpeppe-go-internal-1.12.0/testscript/cmd.go --- golang-github-rogpeppe-go-internal-1.11.0/testscript/cmd.go 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/testscript/cmd.go 2023-12-13 11:29:26.000000000 +0000 @@ -13,10 +13,12 @@ "os/exec" "path/filepath" "regexp" + "runtime" "strconv" "strings" "github.com/rogpeppe/go-internal/diff" + "github.com/rogpeppe/go-internal/testscript/internal/pty" "github.com/rogpeppe/go-internal/txtar" ) @@ -41,6 +43,8 @@ "stderr": (*TestScript).cmdStderr, "stdin": (*TestScript).cmdStdin, "stdout": (*TestScript).cmdStdout, + "ttyin": (*TestScript).cmdTtyin, + "ttyout": (*TestScript).cmdTtyout, "stop": (*TestScript).cmdStop, "symlink": (*TestScript).cmdSymlink, "unix2dos": (*TestScript).cmdUNIX2DOS, @@ -178,6 +182,10 @@ src = arg data = []byte(ts.stderr) mode = 0o666 + case "ttyout": + src = arg + data = []byte(ts.ttyout) + mode = 0o666 default: src = ts.MkAbs(arg) info, err := os.Stat(src) @@ -382,6 +390,9 @@ if len(args) != 1 { ts.Fatalf("usage: stdin filename") } + if ts.stdinPty { + ts.Fatalf("conflicting use of 'stdin' and 'ttyin -stdin'") + } ts.stdin = ts.ReadFile(args[0]) } @@ -401,6 +412,37 @@ scriptMatch(ts, neg, args, "", "grep") } +func (ts *TestScript) cmdTtyin(neg bool, args []string) { + if !pty.Supported { + ts.Fatalf("unsupported: ttyin on %s", runtime.GOOS) + } + if neg { + ts.Fatalf("unsupported: ! ttyin") + } + switch len(args) { + case 1: + ts.ttyin = ts.ReadFile(args[0]) + case 2: + if args[0] != "-stdin" { + ts.Fatalf("usage: ttyin [-stdin] filename") + } + if ts.stdin != "" { + ts.Fatalf("conflicting use of 'stdin' and 'ttyin -stdin'") + } + ts.stdinPty = true + ts.ttyin = ts.ReadFile(args[1]) + default: + ts.Fatalf("usage: ttyin [-stdin] filename") + } + if ts.ttyin == "" { + ts.Fatalf("tty input file is empty") + } +} + +func (ts *TestScript) cmdTtyout(neg bool, args []string) { + scriptMatch(ts, neg, args, ts.ttyout, "ttyout") +} + // stop stops execution of the test (marking it passed). func (ts *TestScript) cmdStop(neg bool, args []string) { if neg { diff -Nru golang-github-rogpeppe-go-internal-1.11.0/testscript/doc.go golang-github-rogpeppe-go-internal-1.12.0/testscript/doc.go --- golang-github-rogpeppe-go-internal-1.11.0/testscript/doc.go 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/testscript/doc.go 2023-12-13 11:29:26.000000000 +0000 @@ -205,6 +205,16 @@ Apply the grep command (see above) to the standard output from the most recent exec or wait command. + - ttyin [-stdin] file + Attach the next exec command to a controlling pseudo-terminal, and use the + contents of the given file as the raw terminal input. If -stdin is specified, + also attach the terminal to standard input. + Note that this does not attach the terminal to standard output/error. + + - [!] ttyout [-count=N] pattern + Apply the grep command (see above) to the raw controlling terminal output + from the most recent exec command. + - stop [message] Stop the test early (marking it as passing), including the message if given. diff -Nru golang-github-rogpeppe-go-internal-1.11.0/testscript/envvarname.go golang-github-rogpeppe-go-internal-1.12.0/testscript/envvarname.go --- golang-github-rogpeppe-go-internal-1.11.0/testscript/envvarname.go 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/testscript/envvarname.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -//go:build !windows - -package testscript - -func envvarname(k string) string { - return k -} diff -Nru golang-github-rogpeppe-go-internal-1.11.0/testscript/envvarname_windows.go golang-github-rogpeppe-go-internal-1.12.0/testscript/envvarname_windows.go --- golang-github-rogpeppe-go-internal-1.11.0/testscript/envvarname_windows.go 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/testscript/envvarname_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -package testscript - -import "strings" - -func envvarname(k string) string { - return strings.ToLower(k) -} diff -Nru golang-github-rogpeppe-go-internal-1.11.0/testscript/internal/pty/pty.go golang-github-rogpeppe-go-internal-1.12.0/testscript/internal/pty/pty.go --- golang-github-rogpeppe-go-internal-1.11.0/testscript/internal/pty/pty.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/testscript/internal/pty/pty.go 2023-12-13 11:29:26.000000000 +0000 @@ -0,0 +1,62 @@ +//go:build linux || darwin +// +build linux darwin + +package pty + +import ( + "fmt" + "os" + "os/exec" + "syscall" +) + +const Supported = true + +func SetCtty(cmd *exec.Cmd, tty *os.File) { + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setctty: true, + Setsid: true, + Ctty: 3, + } + cmd.ExtraFiles = []*os.File{tty} +} + +func Open() (pty, tty *os.File, err error) { + p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0) + if err != nil { + return nil, nil, fmt.Errorf("failed to open pty multiplexer: %v", err) + } + defer func() { + if err != nil { + p.Close() + } + }() + + name, err := ptyName(p) + if err != nil { + return nil, nil, fmt.Errorf("failed to obtain tty name: %v", err) + } + + if err := ptyGrant(p); err != nil { + return nil, nil, fmt.Errorf("failed to grant pty: %v", err) + } + + if err := ptyUnlock(p); err != nil { + return nil, nil, fmt.Errorf("failed to unlock pty: %v", err) + } + + t, err := os.OpenFile(name, os.O_RDWR|syscall.O_NOCTTY, 0) + if err != nil { + return nil, nil, fmt.Errorf("failed to open TTY: %v", err) + } + + return p, t, nil +} + +func ioctl(f *os.File, name string, cmd, ptr uintptr) error { + _, _, err := syscall.Syscall(syscall.SYS_IOCTL, f.Fd(), cmd, ptr) + if err != 0 { + return fmt.Errorf("%s ioctl failed: %v", name, err) + } + return nil +} diff -Nru golang-github-rogpeppe-go-internal-1.11.0/testscript/internal/pty/pty_darwin.go golang-github-rogpeppe-go-internal-1.12.0/testscript/internal/pty/pty_darwin.go --- golang-github-rogpeppe-go-internal-1.11.0/testscript/internal/pty/pty_darwin.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/testscript/internal/pty/pty_darwin.go 2023-12-13 11:29:26.000000000 +0000 @@ -0,0 +1,32 @@ +package pty + +import ( + "bytes" + "os" + "syscall" + "unsafe" +) + +func ptyName(f *os.File) (string, error) { + // Parameter length is encoded in the low 13 bits of the top word. + // See https://github.com/apple/darwin-xnu/blob/2ff845c2e0/bsd/sys/ioccom.h#L69-L77 + const IOCPARM_MASK = 0x1fff + const TIOCPTYGNAME_PARM_LEN = (syscall.TIOCPTYGNAME >> 16) & IOCPARM_MASK + out := make([]byte, TIOCPTYGNAME_PARM_LEN) + + err := ioctl(f, "TIOCPTYGNAME", syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&out[0]))) + if err != nil { + return "", err + } + + i := bytes.IndexByte(out, 0x00) + return string(out[:i]), nil +} + +func ptyGrant(f *os.File) error { + return ioctl(f, "TIOCPTYGRANT", syscall.TIOCPTYGRANT, 0) +} + +func ptyUnlock(f *os.File) error { + return ioctl(f, "TIOCPTYUNLK", syscall.TIOCPTYUNLK, 0) +} diff -Nru golang-github-rogpeppe-go-internal-1.11.0/testscript/internal/pty/pty_linux.go golang-github-rogpeppe-go-internal-1.12.0/testscript/internal/pty/pty_linux.go --- golang-github-rogpeppe-go-internal-1.11.0/testscript/internal/pty/pty_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/testscript/internal/pty/pty_linux.go 2023-12-13 11:29:26.000000000 +0000 @@ -0,0 +1,26 @@ +package pty + +import ( + "os" + "strconv" + "syscall" + "unsafe" +) + +func ptyName(f *os.File) (string, error) { + var out uint + err := ioctl(f, "TIOCGPTN", syscall.TIOCGPTN, uintptr(unsafe.Pointer(&out))) + if err != nil { + return "", err + } + return "/dev/pts/" + strconv.Itoa(int(out)), nil +} + +func ptyGrant(f *os.File) error { + return nil +} + +func ptyUnlock(f *os.File) error { + var zero int + return ioctl(f, "TIOCSPTLCK", syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&zero))) +} diff -Nru golang-github-rogpeppe-go-internal-1.11.0/testscript/internal/pty/pty_unsupported.go golang-github-rogpeppe-go-internal-1.12.0/testscript/internal/pty/pty_unsupported.go --- golang-github-rogpeppe-go-internal-1.11.0/testscript/internal/pty/pty_unsupported.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/testscript/internal/pty/pty_unsupported.go 2023-12-13 11:29:26.000000000 +0000 @@ -0,0 +1,21 @@ +//go:build !linux && !darwin +// +build !linux,!darwin + +package pty + +import ( + "fmt" + "os" + "os/exec" + "runtime" +) + +const Supported = false + +func SetCtty(cmd *exec.Cmd, tty *os.File) error { + panic("SetCtty called on unsupported platform") +} + +func Open() (pty, tty *os.File, err error) { + return nil, nil, fmt.Errorf("pty unsupported on %s", runtime.GOOS) +} diff -Nru golang-github-rogpeppe-go-internal-1.11.0/testscript/testdata/pty.txt golang-github-rogpeppe-go-internal-1.12.0/testscript/testdata/pty.txt --- golang-github-rogpeppe-go-internal-1.11.0/testscript/testdata/pty.txt 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/testscript/testdata/pty.txt 2023-12-13 11:29:26.000000000 +0000 @@ -0,0 +1,11 @@ +[!linux] [!darwin] skip +[darwin] skip # https://go.dev/issue/61779 + +ttyin secretwords.txt +terminalprompt +ttyout 'magic words' +! stderr . +! stdout . + +-- secretwords.txt -- +SQUEAMISHOSSIFRAGE diff -Nru golang-github-rogpeppe-go-internal-1.11.0/testscript/testscript.go golang-github-rogpeppe-go-internal-1.12.0/testscript/testscript.go --- golang-github-rogpeppe-go-internal-1.11.0/testscript/testscript.go 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/testscript/testscript.go 2023-12-13 11:29:26.000000000 +0000 @@ -16,7 +16,6 @@ "go/build" "io" "io/fs" - "io/ioutil" "os" "os/exec" "path/filepath" @@ -34,6 +33,7 @@ "github.com/rogpeppe/go-internal/internal/os/execpath" "github.com/rogpeppe/go-internal/par" "github.com/rogpeppe/go-internal/testenv" + "github.com/rogpeppe/go-internal/testscript/internal/pty" "github.com/rogpeppe/go-internal/txtar" ) @@ -100,6 +100,13 @@ return "" } +func envvarname(k string) string { + if runtime.GOOS == "windows" { + return strings.ToLower(k) + } + return k +} + // Setenv sets the value of the environment variable named by the key. It // panics if key is invalid. func (e *Env) Setenv(key, value string) { @@ -254,14 +261,14 @@ } testTempDir := p.WorkdirRoot if testTempDir == "" { - testTempDir, err = ioutil.TempDir(os.Getenv("GOTMPDIR"), "go-test-script") + testTempDir, err = os.MkdirTemp(os.Getenv("GOTMPDIR"), "go-test-script") if err != nil { t.Fatal(err) } } else { p.TestWork = true } - // The temp dir returned by ioutil.TempDir might be a sym linked dir (default + // The temp dir returned by os.MkdirTemp might be a sym linked dir (default // behaviour in macOS). That could mess up matching that includes $WORK if, // for example, an external program outputs resolved paths. Evaluating the // dir here will ensure consistency. @@ -357,6 +364,9 @@ stdin string // standard input to next 'go' command; set by 'stdin' command. stdout string // standard output from last 'go' command; for 'stdout' command stderr string // standard error from last 'go' command; for 'stderr' command + ttyin string // terminal input; set by 'ttyin' command + stdinPty bool // connect pty to standard input; set by 'ttyin -stdin' command + ttyout string // terminal output; for 'ttyout' command stopped bool // test wants to stop early start time.Time // time phase started background []backgroundCmd // backgrounded 'exec' and 'go' commands @@ -403,6 +413,9 @@ return nil } +// Name returns the short name or basename of the test script. +func (ts *TestScript) Name() string { return ts.name } + // setup sets up the test execution temporary directory and environment. // It returns the comment section of the txtar archive. func (ts *TestScript) setup() string { @@ -434,16 +447,27 @@ "/=" + string(os.PathSeparator), ":=" + string(os.PathListSeparator), "$=$", - - // If we are collecting coverage profiles for merging into the main one, - // ensure the environment variable is forwarded to sub-processes. - "GOCOVERDIR=" + os.Getenv("GOCOVERDIR"), }, WorkDir: ts.workdir, Values: make(map[interface{}]interface{}), Cd: ts.workdir, ts: ts, } + + // These env vars affect how a Go program behaves at run-time; + // If the user or `go test` wrapper set them, we should propagate them + // so that sub-process commands run via the test binary see them as well. + for _, name := range []string{ + // If we are collecting coverage profiles, e.g. `go test -coverprofile`. + "GOCOVERDIR", + // If the user set GORACE when running a command like `go test -race`, + // such as GORACE=atexit_sleep_ms=10 to avoid the default 1s sleeps. + "GORACE", + } { + if val := os.Getenv(name); val != "" { + env.Vars = append(env.Vars, name+"="+val) + } + } // Must preserve SYSTEMROOT on Windows: https://github.com/golang/go/issues/25513 et al if runtime.GOOS == "windows" { env.Vars = append(env.Vars, @@ -769,7 +793,7 @@ panic("script update file not found") } } - if err := ioutil.WriteFile(ts.file, txtar.Format(ts.archive), 0o666); err != nil { + if err := os.WriteFile(ts.file, txtar.Format(ts.archive), 0o666); err != nil { ts.t.Fatal("cannot update script: ", err) } ts.Logf("%s updated", ts.file) @@ -940,16 +964,49 @@ var stdoutBuf, stderrBuf strings.Builder cmd.Stdout = &stdoutBuf cmd.Stderr = &stderrBuf + if ts.ttyin != "" { + ctrl, tty, err := pty.Open() + if err != nil { + return "", "", err + } + doneR, doneW := make(chan struct{}), make(chan struct{}) + var ptyBuf strings.Builder + go func() { + io.Copy(ctrl, strings.NewReader(ts.ttyin)) + ctrl.Write([]byte{4 /* EOT */}) + close(doneW) + }() + go func() { + io.Copy(&ptyBuf, ctrl) + close(doneR) + }() + defer func() { + tty.Close() + ctrl.Close() + <-doneR + <-doneW + ts.ttyin = "" + ts.ttyout = ptyBuf.String() + }() + pty.SetCtty(cmd, tty) + if ts.stdinPty { + cmd.Stdin = tty + } + } if err = cmd.Start(); err == nil { err = waitOrStop(ts.ctxt, cmd, ts.gracePeriod) } ts.stdin = "" + ts.stdinPty = false return stdoutBuf.String(), stderrBuf.String(), err } // execBackground starts the given command line (an actual subprocess, not simulated) // in ts.cd with environment ts.env. func (ts *TestScript) execBackground(command string, args ...string) (*exec.Cmd, error) { + if ts.ttyin != "" { + return nil, errors.New("ttyin is not supported by background commands") + } cmd, err := ts.buildExecCmd(command, args...) if err != nil { return nil, err @@ -1126,9 +1183,11 @@ return ts.stdout case "stderr": return ts.stderr + case "ttyout": + return ts.ttyout default: file = ts.MkAbs(file) - data, err := ioutil.ReadFile(file) + data, err := os.ReadFile(file) ts.Check(err) return string(data) } @@ -1209,11 +1268,11 @@ func removeAll(dir string) error { // module cache has 0o444 directories; // make them writable in order to remove content. - filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + filepath.WalkDir(dir, func(path string, entry fs.DirEntry, err error) error { if err != nil { return nil // ignore errors walking in file system } - if info.IsDir() { + if entry.IsDir() { os.Chmod(path, 0o777) } return nil diff -Nru golang-github-rogpeppe-go-internal-1.11.0/testscript/testscript_test.go golang-github-rogpeppe-go-internal-1.12.0/testscript/testscript_test.go --- golang-github-rogpeppe-go-internal-1.11.0/testscript/testscript_test.go 2023-05-24 17:50:51.000000000 +0000 +++ golang-github-rogpeppe-go-internal-1.12.0/testscript/testscript_test.go 2023-12-13 11:29:26.000000000 +0000 @@ -58,6 +58,22 @@ return 0 } +func terminalPrompt() int { + tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0) + if err != nil { + fmt.Println(err) + return 1 + } + tty.WriteString("The magic words are: ") + var words string + fmt.Fscanln(tty, &words) + if words != "SQUEAMISHOSSIFRAGE" { + fmt.Println(words) + return 42 + } + return 0 +} + func TestMain(m *testing.M) { timeSince = func(t time.Time) time.Duration { return 0 @@ -65,10 +81,11 @@ showVerboseEnv = false os.Exit(RunMain(m, map[string]func() int{ - "printargs": printArgs, - "fprintargs": fprintArgs, - "status": exitWithStatus, - "signalcatcher": signalCatcher, + "printargs": printArgs, + "fprintargs": fprintArgs, + "status": exitWithStatus, + "signalcatcher": signalCatcher, + "terminalprompt": terminalPrompt, })) }