Skip to content

Commit 87029d9

Browse files
committed
fastwalk: add MSYS/MSYS2 detection to DefaultToSlash
This change updates DefaultToSlash to also check if we're running in a MSYS/MSYS2 enviroment since they also use forward slashes.
1 parent 76f9295 commit 87029d9

File tree

3 files changed

+93
-55
lines changed

3 files changed

+93
-55
lines changed

fastwalk.go

Lines changed: 24 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ package fastwalk
3737
*/
3838

3939
import (
40-
"bytes"
4140
"errors"
4241
"io/fs"
4342
"os"
@@ -88,66 +87,36 @@ func DefaultNumWorkers() int {
8887
return numCPU
8988
}
9089

91-
var underWSL struct {
92-
once sync.Once
93-
wsl bool
94-
}
95-
96-
// runningUnderWSL returns if we're a Widows executable running in WSL.
97-
// See [DefaultToSlash] for an explanation of the heuristics used here.
98-
func runningUnderWSL() bool {
99-
if runtime.GOOS != "windows" {
100-
return false
101-
}
102-
w := &underWSL
103-
w.once.Do(func() {
104-
w.wsl = func() bool {
105-
// Best check (but not super fast)
106-
if _, err := os.Lstat("/proc/sys/fs/binfmt_misc/WSLInterop"); err == nil {
107-
return true
108-
}
109-
// Fast check, but could provide a false positive if the user sets
110-
// this on the Windows side.
111-
if os.Getenv("WSL_DISTRO_NAME") != "" {
112-
return true
113-
}
114-
// If the binary is compiled for Windows and we're running under Linux
115-
// then honestly just the presence of "/proc/version" should be enough
116-
// to determine that we're running under WSL, but check the version
117-
// string just to be pedantic.
118-
data, _ := os.ReadFile("/proc/version")
119-
return bytes.Contains(data, []byte("microsoft")) ||
120-
bytes.Contains(data, []byte("Microsoft"))
121-
}()
122-
})
123-
return w.wsl
124-
}
125-
126-
// DefaultToSlash returns the default ToSlash value used by the global config
127-
// and only applies to Windows. For any other OS this function is a no-op.
90+
// DefaultToSlash returns true if this is a Go program compiled for Windows
91+
// running in an environment ([WSL] or [MSYS/MSYS2]) that uses forward slashes
92+
// as the path separator instead of the native backslash.
93+
// On all other platforms this is a no-op and returns false since the native
94+
// path separator is a forward slash and does not need to be converted.
12895
//
129-
// On Windows, this function attempts to detect if this is a Go program compiled
130-
// for Windows but running in the Windows Subsystem for Linux (WSL). In this
131-
// case, we want to use a forward-slash as the separator instead of a backslash
132-
// since tools like FZF may directly send paths to the terminal/shell (which
133-
// being a *nix shell will treat backslashes as the start of an escape sequence).
96+
// This check does not apply to programs compiled in [WSL] [MSYS/MSYS2] or for
97+
// Linux (GOOS=linux). It only applies to Go programs compiled for Windows
98+
// (GOOS=windows) that are executed from [WSL] or [MSYS/MSYS2].
13499
//
135-
// This does not apply to programs compiled in WSL for Linux. It only applies to
136-
// Go programs compiled for Windows (.exe) that are executed from WSL. On all
137-
// other platforms it is a no-op.
100+
// To detect if we're running in [MSYS/MSYS2] we check that "MSYSTEM" environment
101+
// variable is either "MINGW64", "MINGW32", or "MSYS".
138102
//
139-
// The following heuristics are used to detect if we're a Windows executable
140-
// running in WSL (NOTE: if [runtime.GOOS] != "windows" this a no-op and returns
141-
// false):
103+
// The following heuristics are used to detect if we're running in [WSL]:
142104
//
143105
// - Existence of "/proc/sys/fs/binfmt_misc/WSLInterop".
144106
// - If the "WSL_DISTRO_NAME" environment variable is set.
145107
// - If "/proc/version" contains either "Microsoft" or "microsoft".
146108
//
147-
// Additionally, the result of this function is cached the cached value will be
148-
// returned on all subsequent calls.
109+
// The result of the WSL check is cached for performance reasons.
110+
//
111+
// See: https://github.com/junegunn/fzf/issues/3859
112+
//
113+
// [WSL]: https://learn.microsoft.com/en-us/windows/wsl/about
114+
// [MSYS/MSYS2]: https://www.msys2.org/
149115
func DefaultToSlash() bool {
150-
return runtime.GOOS == "windows" && runningUnderWSL()
116+
if runtime.GOOS != "windows" {
117+
return false
118+
}
119+
return useForwardSlash()
151120
}
152121

153122
// DefaultConfig is the default Config used when none is supplied.
@@ -269,7 +238,7 @@ func Walk(conf *Config, root string, walkFn fs.WalkDirFunc) error {
269238
resc: make(chan error, numWorkers),
270239

271240
follow: conf.Follow,
272-
ToSlash: conf.ToSlash,
241+
toSlash: conf.ToSlash,
273242
}
274243
if w.follow {
275244
w.ignoredDirs = append(w.ignoredDirs, fi)
@@ -350,7 +319,7 @@ type walker struct {
350319

351320
ignoredDirs []os.FileInfo
352321
follow bool
353-
ToSlash bool
322+
toSlash bool
354323
}
355324

356325
type walkItem struct {
@@ -412,7 +381,7 @@ func (w *walker) joinPaths(dir, base string) string {
412381
}
413382
return dir + "/" + base
414383
}
415-
if w.ToSlash {
384+
if w.toSlash {
416385
return dir + "/" + base
417386
}
418387
return dir + string(os.PathSeparator) + base

path_portable.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//go:build !windows
2+
3+
package fastwalk
4+
5+
func useForwardSlash() bool {
6+
return false
7+
}

path_windows.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//go:build windows
2+
3+
package fastwalk
4+
5+
import (
6+
"bytes"
7+
"os"
8+
"runtime"
9+
"sync"
10+
)
11+
12+
func useForwardSlash() bool {
13+
// Use a forward slash as the path separator if this a Windows executable
14+
// running in either MSYS/MSYS2 or WSL.
15+
return runningUnderMSYS() || runningUnderWSL()
16+
}
17+
18+
// runningUnderMSYS reports if we're running in a MSYS/MSYS2 enviroment.
19+
//
20+
// See: https://github.com/sharkdp/fd/pull/730
21+
func runningUnderMSYS() bool {
22+
switch os.Getenv("MSYSTEM") {
23+
case "MINGW64", "MINGW32", "MSYS":
24+
return true
25+
}
26+
return false
27+
}
28+
29+
var underWSL struct {
30+
once sync.Once
31+
wsl bool
32+
}
33+
34+
// runningUnderWSL returns if we're a Widows executable running in WSL.
35+
// See [DefaultToSlash] for an explanation of the heuristics used here.
36+
func runningUnderWSL() bool {
37+
if runtime.GOOS != "windows" {
38+
return false
39+
}
40+
w := &underWSL
41+
w.once.Do(func() {
42+
w.wsl = func() bool {
43+
// Best check (but not super fast)
44+
if _, err := os.Lstat("/proc/sys/fs/binfmt_misc/WSLInterop"); err == nil {
45+
return true
46+
}
47+
// Fast check, but could provide a false positive if the user sets
48+
// this on the Windows side.
49+
if os.Getenv("WSL_DISTRO_NAME") != "" {
50+
return true
51+
}
52+
// If the binary is compiled for Windows and we're running under Linux
53+
// then honestly just the presence of "/proc/version" should be enough
54+
// to determine that we're running under WSL, but check the version
55+
// string just to be pedantic.
56+
data, _ := os.ReadFile("/proc/version")
57+
return bytes.Contains(data, []byte("microsoft")) ||
58+
bytes.Contains(data, []byte("Microsoft"))
59+
}()
60+
})
61+
return w.wsl
62+
}

0 commit comments

Comments
 (0)