From 7387346196a6172018dd081ea9834f580941a940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Mon, 20 Jun 2022 15:25:29 +0200 Subject: [PATCH] Fix determining the current executable under Homebrew for Linux We need to use `os.Lstat` instead of `os.Stat` if we are going to manually inspect files for whether they are a symlink. On macOS, it looks like `os.Stat` returns information about the symlink itself. --- pkg/cmdutil/factory.go | 2 +- pkg/cmdutil/factory_test.go | 59 +++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 pkg/cmdutil/factory_test.go diff --git a/pkg/cmdutil/factory.go b/pkg/cmdutil/factory.go index 73cee489a..668cd637c 100644 --- a/pkg/cmdutil/factory.go +++ b/pkg/cmdutil/factory.go @@ -68,7 +68,7 @@ func executable(fallbackName string) string { if err != nil { continue } - f, err := os.Stat(p) + f, err := os.Lstat(p) if err != nil { continue } diff --git a/pkg/cmdutil/factory_test.go b/pkg/cmdutil/factory_test.go new file mode 100644 index 000000000..d0d5cf7f4 --- /dev/null +++ b/pkg/cmdutil/factory_test.go @@ -0,0 +1,59 @@ +package cmdutil + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func Test_executable(t *testing.T) { + testExe, err := os.Executable() + if err != nil { + t.Fatal(err) + } + + testExeName := filepath.Base(testExe) + + // Create 3 extra PATH entries that each contain an executable with the same name as the running test + // process. The first is a symlink, but to an unrelated executable, the second is a symlink to our test + // process and thus represents the result we want, and the third one is an unrelated executable. + dir := t.TempDir() + bin1 := filepath.Join(dir, "bin1") + bin1Exe := filepath.Join(bin1, testExeName) + bin2 := filepath.Join(dir, "bin2") + bin2Exe := filepath.Join(bin2, testExeName) + bin3 := filepath.Join(dir, "bin3") + bin3Exe := filepath.Join(bin3, testExeName) + + if err := os.MkdirAll(bin1, 0755); err != nil { + t.Fatal(err) + } + if err := os.MkdirAll(bin2, 0755); err != nil { + t.Fatal(err) + } + if err := os.MkdirAll(bin3, 0755); err != nil { + t.Fatal(err) + } + if f, err := os.OpenFile(bin3Exe, os.O_CREATE, 0755); err == nil { + f.Close() + } else { + t.Fatal(err) + } + if err := os.Symlink(testExe, bin2Exe); err != nil { + t.Fatal(err) + } + if err := os.Symlink(bin3Exe, bin1Exe); err != nil { + t.Fatal(err) + } + + oldPath := os.Getenv("PATH") + t.Cleanup(func() { + os.Setenv("PATH", oldPath) + }) + os.Setenv("PATH", strings.Join([]string{bin1, bin2, bin3, oldPath}, string(os.PathListSeparator))) + + if got := executable(""); got != bin2Exe { + t.Errorf("executable() = %q, want %q", got, bin2Exe) + } +}