From 1cb4ccc8ef52221225993e3349a5a137fd5e1b03 Mon Sep 17 00:00:00 2001 From: rsteube Date: Thu, 10 Oct 2024 21:40:58 +0200 Subject: [PATCH] actionPath: fix symlinks --- example/cmd/action_test.go | 47 ++++++++++++++++++++++++++++++++++++++ internalActions.go | 16 ++++++++----- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/example/cmd/action_test.go b/example/cmd/action_test.go index 3e288319..bfd75d4b 100644 --- a/example/cmd/action_test.go +++ b/example/cmd/action_test.go @@ -1,6 +1,8 @@ package cmd import ( + "os" + "runtime" "testing" "github.com/carapace-sh/carapace" @@ -350,3 +352,48 @@ func TestActionMultipartsN(t *testing.T) { Usage("ActionMultiPartsN()")) }) } + +func TestSymlink(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("no symlink support on windows") + } + + sandbox.Package(t, "github.com/carapace-sh/carapace/example")(func(s *sandbox.Sandbox) { + s.Files( + "dirA/file1.txt", "", + "dirA/file2.png", "", + "dirB/dirC/file3.go", "", + "dirB/file4.md", "", + "file5.go", "", + ) + c := s.NewContext() + if err := os.Symlink(c.Dir+"/dirA", c.Dir+"/symA"); err != nil { + t.Error(err.Error()) + } + if err := os.Symlink(c.Dir+"/missing", c.Dir+"/symB"); err != nil { + t.Error(err.Error()) + } + + s.Run("action", "--directories", ""). + Expect(carapace.ActionValues("dirA/", "dirB/", "symA/"). + Tag("directories"). + StyleF(style.ForPath). + NoSpace('/'). + Usage("ActionDirectories()")) + + s.Run("action", "--files", "symA/"). + Expect(carapace.ActionValues("file1.txt", "file2.png"). + Prefix("symA/"). + Tag("files"). + StyleF(style.ForPath). + NoSpace('/'). + Usage("ActionFiles()")) + + s.Run("action", "--files", "s"). + Expect(carapace.ActionValues("symA/", "symB"). + Tag("files"). + StyleF(style.ForPath). + NoSpace('/'). + Usage("ActionFiles()")) + }) +} diff --git a/internalActions.go b/internalActions.go index 03a38ff1..054f10d9 100644 --- a/internalActions.go +++ b/internalActions.go @@ -47,19 +47,23 @@ func actionPath(fileSuffixes []string, dirOnly bool) Action { continue } - resolvedFile, err := file.Info() + info, err := file.Info() if err != nil { return ActionMessage(err.Error()) } - if resolved, err := filepath.EvalSymlinks(actualFolder + file.Name()); err == nil { - if stat, err := os.Stat(resolved); err == nil { - resolvedFile = stat + symlinkedDir := false + if evaluatedPath, err := filepath.EvalSymlinks(actualFolder + "/" + file.Name()); err == nil { + if evaluatedInfo, err := os.Stat(evaluatedPath); err == nil { + symlinkedDir = evaluatedInfo.IsDir() } } - if resolvedFile.IsDir() { + switch { + case info.IsDir(): vals = append(vals, displayFolder+file.Name()+"/", style.ForPath(filepath.Clean(actualFolder+"/"+file.Name()+"/"), c)) - } else if !dirOnly { + case symlinkedDir: + vals = append(vals, displayFolder+file.Name()+"/", style.ForPath(filepath.Clean(actualFolder+"/"+file.Name()), c)) // TODO colorist not returning the symlink color + case !dirOnly: if len(fileSuffixes) == 0 { fileSuffixes = []string{""} }