From 07f280bf38c60b0711d7407bd52c98631b336068 Mon Sep 17 00:00:00 2001 From: Chapman Pendery Date: Thu, 28 Sep 2023 14:21:07 -0700 Subject: [PATCH] fix: change cache folder & kept all shell bindings stored in cache folder Signed-off-by: Chapman Pendery --- autocomplete/result.go | 28 ++++++++--- cmd/bind.go | 2 - go.mod | 3 +- go.sum | 7 --- shell/shell.go | 110 +++++++++++++++++++++++------------------ utils/folder.go | 23 +++++++++ 6 files changed, 106 insertions(+), 67 deletions(-) create mode 100644 utils/folder.go diff --git a/autocomplete/result.go b/autocomplete/result.go index deb41a3..b65b402 100644 --- a/autocomplete/result.go +++ b/autocomplete/result.go @@ -4,20 +4,34 @@ package autocomplete import ( + "errors" "io" "os" + "path/filepath" "log/slog" - "github.com/adrg/xdg" + "github.com/microsoft/clac/utils" ) -const ( - cacheFilePath = "clac/clac.cache" -) +func cacheFile() (string, error) { + folder, err := utils.ClacFolder() + if err != nil { + return "", err + } + cacheFile := filepath.Join(folder, "clac.cache") + if _, err := os.Stat(cacheFile); errors.Is(err, os.ErrNotExist) { + f, err := os.Create(cacheFile) + if err != nil { + return "", err + } + defer f.Close() + } + return cacheFile, nil +} func CacheResult(result string) { - path, err := xdg.CacheFile(cacheFilePath) + path, err := cacheFile() if err != nil { slog.Error("unable to create cache file", slog.String("error", err.Error())) return @@ -33,7 +47,7 @@ func CacheResult(result string) { } func ReadResult() string { - path, err := xdg.CacheFile(cacheFilePath) + path, err := cacheFile() if err != nil { slog.Error("unable to create cache file", slog.String("error", err.Error())) return "" @@ -52,7 +66,7 @@ func ReadResult() string { } func ClearResult() { - path, err := xdg.CacheFile(cacheFilePath) + path, err := cacheFile() if err != nil { slog.Error("failed to load cache file", slog.String("error", err.Error())) } diff --git a/cmd/bind.go b/cmd/bind.go index 1f077a6..88aab8d 100644 --- a/cmd/bind.go +++ b/cmd/bind.go @@ -43,8 +43,6 @@ func runBindCmd(_ *cobra.Command, args []string) error { return shell.CreateWindowsPowershellBinding() case "powershell": return shell.CreatePowershellBinding() - case "zsh": - return shell.CreateZshBinding() } return nil } diff --git a/go.mod b/go.mod index ebff8a0..71edcf5 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/microsoft/clac go 1.21.0 require ( - github.com/adrg/xdg v0.4.0 + github.com/bradleyjkemp/cupaloy v2.3.0+incompatible github.com/charmbracelet/bubbles v0.16.1 github.com/charmbracelet/bubbletea v0.24.2 github.com/charmbracelet/lipgloss v0.8.0 @@ -19,7 +19,6 @@ require ( require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/bradleyjkemp/cupaloy v2.3.0+incompatible // indirect github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/go.sum b/go.sum index e8e0240..6677574 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= -github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= @@ -15,7 +13,6 @@ github.com/charmbracelet/lipgloss v0.8.0/go.mod h1:p4eYUZZJ/0oXTuCQKFF8mqyKCz0ja github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= @@ -51,8 +48,6 @@ github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -71,7 +66,6 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -98,6 +92,5 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/shell/shell.go b/shell/shell.go index 8a613f0..92aef12 100644 --- a/shell/shell.go +++ b/shell/shell.go @@ -6,12 +6,13 @@ package shell import ( _ "embed" "fmt" + "io" "os" - "path" + "path/filepath" "runtime" "strings" - "github.com/adrg/xdg" + "github.com/microsoft/clac/utils" ) var ( @@ -34,70 +35,81 @@ var powershellBindings []byte var zshBindings []byte func CreateBashBinding() error { - return createShBinding("key-bindings.bash", ".bashrc", bashBindings) + keyBindingFilename := "key-bindings.bash" + bindingsPath := fmt.Sprintf("~/.clac/%s", keyBindingFilename) + bindScript := fmt.Sprintf("[ -f %s ] && source %s", bindingsPath, bindingsPath) + return createBinding(keyBindingFilename, ".bashrc", bindScript, bashBindings) } -func CreateZshBinding() error { - return createShBinding("key-bindings.zsh", ".zshrc", zshBindings) -} - -func createShBinding(keyBindingFilename, rcFilename string, bindingData []byte) error { - if err := os.MkdirAll(path.Join(xdg.Home, clacHomeFolder), 0770); err != nil { - return fmt.Errorf("unable to create .clac folder: %w", err) +func createBinding(keyBindingFilename, shellConfigFile, bindScript string, bindingData []byte) error { + clacFolderPath, err := utils.ClacFolder() + if err != nil { + return err } - f, err := os.Create(path.Join(xdg.Home, clacHomeFolder, keyBindingFilename)) + f, err := os.Create(filepath.Join(clacFolderPath, keyBindingFilename)) if err != nil { return fmt.Errorf("unable to create keybindings file: %w", err) } + defer f.Close() - if _, err = f.Write(bashBindings); err != nil { + if _, err = f.Write(bindingData); err != nil { return fmt.Errorf("unable to write to keybindings file: %w", err) } - f, err = os.OpenFile(path.Join(xdg.Home, rcFilename), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) - if err != nil { - return fmt.Errorf("unable to append to rc file: %w", err) - } - - bindingsPath := fmt.Sprintf("~/.clac/%s", keyBindingFilename) - if _, err := fmt.Fprintf(f, "\n[ -f %s ] && source %s", bindingsPath, bindingsPath); err != nil { - return fmt.Errorf("unable to append to rc file: %w", err) - } - - return err -} - -func CreateWindowsPowershellBinding() error { homeDir, _ := os.UserHomeDir() - profilePath := path.Join(homeDir, "Documents", "WindowsPowershell") - return createPShellBinding(profilePath, "Microsoft.PowerShell_profile.ps1") -} - -func CreatePowershellBinding() error { - homeDir, _ := os.UserHomeDir() - profilePath := "" - switch runtime.GOOS { - case "windows": - profilePath = path.Join(homeDir, "Documents", "Powershell") - case "linux", "darwin": - profilePath = path.Join("~", ".config", "powershell") + shellConfigPath := filepath.Join(homeDir, shellConfigFile) + if _, err := os.Stat(shellConfigPath); err == nil { + f, err = os.Open(shellConfigPath) + if err != nil { + return fmt.Errorf("unable to read shell config file: %w", err) + } + b, err := io.ReadAll(f) + if err != nil { + return fmt.Errorf("unable to read shell config file: %w", err) + } + if err := f.Close(); err != nil { + return fmt.Errorf("unable to close shell config file: %w", err) + } + if strings.Contains(string(b), bindScript) { + return nil + } } - return createPShellBinding(profilePath, "Microsoft.PowerShell_profile.ps1") -} -func createPShellBinding(profileLocation string, profileFile string) error { - if err := os.MkdirAll(profileLocation, 0600); err != nil { - return fmt.Errorf("unable to create powershell's profile directory: %w", err) - } - profilePath := path.Join(profileLocation, profileFile) - f, err := os.OpenFile(profilePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + f, err = os.OpenFile(filepath.Join(homeDir, shellConfigFile), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) if err != nil { - return fmt.Errorf("unable to open/create powershell's profile file: %w", err) + return fmt.Errorf("unable to append to shell config file: %w", err) } + defer f.Close() - if _, err := f.Write(powershellBindings); err != nil { - return fmt.Errorf("unable to append keybindings to powershell's profile: %w", err) + if _, err := fmt.Fprintf(f, "\n%s", bindScript); err != nil { + return fmt.Errorf("unable to append to rc file: %w", err) } return nil } + +func CreateWindowsPowershellBinding() error { + return createPShellBinding(filepath.Join("Documents", "WindowsPowershell", "Microsoft.PowerShell_profile.ps1")) +} + +func CreatePowershellBinding() error { + profilePath := "" + switch runtime.GOOS { + case "windows": + profilePath = filepath.Join("Documents", "Powershell") + case "linux", "darwin": + profilePath = filepath.Join(".config", "powershell") + } + return createPShellBinding(filepath.Join(profilePath, "Microsoft.PowerShell_profile.ps1")) +} + +func createPShellBinding(profileFile string) error { + keyBindingFilename := "key-bindings.ps1" + clacFolderPath, err := utils.ClacFolder() + if err != nil { + return err + } + bindingsPath := filepath.Join(clacFolderPath, keyBindingFilename) + bindScript := fmt.Sprintf("if(Test-Path '%s' -PathType Leaf){. %s}", bindingsPath, bindingsPath) + return createBinding(keyBindingFilename, profileFile, bindScript, powershellBindings) +} diff --git a/utils/folder.go b/utils/folder.go new file mode 100644 index 0000000..fdc6bdd --- /dev/null +++ b/utils/folder.go @@ -0,0 +1,23 @@ +package utils + +import ( + "fmt" + "os" + "path" +) + +const ( + clacHomeFolder = ".clac" +) + +func ClacFolder() (string, error) { + homeDir, err := os.UserHomeDir() + if err != nil { + return "", fmt.Errorf("unable to detect home dir: %w", err) + } + clacFolderPath := path.Join(homeDir, clacHomeFolder) + if err := os.MkdirAll(clacFolderPath, 0770); err != nil { + return "", fmt.Errorf("unable to create .clac folder: %w", err) + } + return clacFolderPath, nil +}