diff --git a/go.mod b/go.mod index 5c8d3056..05eeb512 100644 --- a/go.mod +++ b/go.mod @@ -4,5 +4,6 @@ go 1.19 require ( golang.org/x/mod v0.9.0 + golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f golang.org/x/tools v0.1.12 ) diff --git a/go.sum b/go.sum index 0c7672cb..d8a340c0 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,6 @@ golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= diff --git a/testscript/clonefile.go b/testscript/clonefile.go new file mode 100644 index 00000000..0ae053f2 --- /dev/null +++ b/testscript/clonefile.go @@ -0,0 +1,12 @@ +//go:build unix && !darwin +// +build unix,!darwin + +package testscript + +import "golang.org/x/sys/unix" + +// cloneFile creates to as a hard link to the from file. +// If there is an error, it will be of type *LinkError. +func cloneFile(from, to string) error { + return os.Link(from, to) +} diff --git a/testscript/clonefile_darwin.go b/testscript/clonefile_darwin.go new file mode 100644 index 00000000..c0e7a9e6 --- /dev/null +++ b/testscript/clonefile_darwin.go @@ -0,0 +1,8 @@ +package testscript + +import "golang.org/x/sys/unix" + +// cloneFile clones the file from to the file to. +func cloneFile(from, to string) error { + return unix.Clonefile(from, to, 0) +} diff --git a/testscript/clonefile_other.go b/testscript/clonefile_other.go new file mode 100644 index 00000000..a53b344a --- /dev/null +++ b/testscript/clonefile_other.go @@ -0,0 +1,11 @@ +//go:build !unix +// +build !unix + +package testscript + +import "os" + +// We don't want to use hard links on Windows, as that can lead to "access denied" errors when removing. +func cloneFile(from, to string) error { + return fmt.Errorf("unavailable") +} diff --git a/testscript/exe.go b/testscript/exe.go index ed6bd98d..475ab70f 100644 --- a/testscript/exe.go +++ b/testscript/exe.go @@ -122,10 +122,8 @@ func RunMain(m TestingM, commands map[string]func() int) (exitCode int) { // system's temporary directory, like we do. We don't use hard links on Windows, // as that can lead to "access denied" errors when removing. func copyBinary(from, to string) error { - if runtime.GOOS != "windows" { - if err := os.Link(from, to); err == nil { - return nil - } + if err := cloneFile(from, to); err == nil { + return nil } writer, err := os.OpenFile(to, os.O_WRONLY|os.O_CREATE, 0o777) if err != nil {