Skip to content

Commit 5c3e93b

Browse files
committed
Improve helper
- Fix bug with unable to `completions -U` on zsh/fish - zsh completion now has our helpers - refactor the helper code Fixes: #360
1 parent 08025db commit 5c3e93b

File tree

5 files changed

+134
-89
lines changed

5 files changed

+134
-89
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66

77
* Auto-completion is now context sensitive to the `--sso`, `--account`, and
88
`--role` flags and filters results accordingly.
9+
* Add zsh support for shell helpers #360
910

1011
### Bugs
1112

13+
* Fix broken `completions` for zsh and fish
14+
1215
## [v1.9.1] - 2022-05-09
1316

1417
## Bugs

docs/commands.md

+7-6
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ Flags:
311311

312312
* `--install` -- Install the new v1.9+ shell completions scripts
313313
* `--uninstall` -- Uninstall the new v1.9+ shell completions scripts
314-
* `--uninstall-pre-19` -- Uninstall the legacy pre-v1.9 scripts
314+
* `--uninstall-pre-19` -- Uninstall the legacy pre-v1.9 scripts
315315
* `--shell <shell>` -- Override the detected shell
316316
* `--shell-script <file>` -- Override the default shell script file to modify
317317

@@ -384,16 +384,17 @@ functions, please see the [quickstart](quickstart.md) page.
384384
and you should _NOT_ prefix them with `aws-sso`.
385385

386386
By default, these commands uses your default AWS SSO instance, but you can override
387-
this by first exporting `AWS_SSO` to the value you want to use.
387+
this by first exporting `AWS_SSO` to the value you want to use.
388388

389-
If you want to pass specific args to `aws-sso-profile` you can use the
390-
`$AWS_SSO_HELPER_ARGS` environment variable. If nothing is set, then
389+
If you want to pass specific args to `aws-sso-profile` you can use the
390+
`$AWS_SSO_HELPER_ARGS` environment variable. If nothing is set, then
391391
`--level error` is used.
392392

393393
Currently the following shells are fully supported:
394394

395395
* `bash`
396-
* [zsh - TBD](https://github.com/synfinatic/aws-sso-cli/issues/360)
396+
* `zsh` (requires manual `# autoload -U +X bashcompinit && bashcompinit`
397+
for bash completion support)
397398
* [fish - TBD](https://github.com/synfinatic/aws-sso-cli/issues/361)
398399

399400
**Note:** Please reach out if you can help with adding support for your favorite shell!
@@ -406,7 +407,7 @@ This shell command enables you to assume an AWS SSO role by the profile name
406407
_in the current shell and with auto-complete functionality_. Basically it is a
407408
wrapper around `eval $(aws-sso eval --profile XXXX)` but with auto-complete.
408409

409-
This command will export the same [environment variables](#managed-variables)
410+
This command will export the same [environment variables](#managed-variables)
410411
as the [eval](#eval) command.
411412

412413
**Note:** This command will overwrite existing environment variables, but will

internal/helper/bash_profile.sh

+25-25
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
1-
_aws_sso_profile_complete(){
2-
COMPREPLY=()
3-
local _args=${AWS_SSO_HELPER_ARGS:- -L error}
4-
local cur
5-
_get_comp_words_by_ref -n : cur
1+
__aws_sso_profile_complete() {
2+
COMPREPLY=()
3+
local _args=${AWS_SSO_HELPER_ARGS:- -L error}
4+
local cur
5+
_get_comp_words_by_ref -n : cur
66

7-
COMPREPLY=($(compgen -W '$({{ .Executable }} $_args list --csv -P "$cur" Profile)' -- ""))
7+
COMPREPLY=($(compgen -W '$({{ .Executable }} $_args list --csv -P "$cur" Profile)' -- ""))
88

9-
__ltrim_colon_completions "$cur"
9+
__ltrim_colon_completions "$cur"
1010
}
1111

12-
aws-sso-profile(){
13-
local _args=${AWS_SSO_HELPER_ARGS:- -L error}
14-
if [ -n "$AWS_PROFILE" ]; then
15-
echo "Unable to assume a role while AWS_PROFILE is set"
16-
return 1
17-
fi
18-
eval $({{ .Executable }} $_args eval -p "$1")
19-
if [ "$AWS_SSO_PROFILE" != "$1" ]; then
20-
return 1
21-
fi
12+
aws-sso-profile() {
13+
local _args=${AWS_SSO_HELPER_ARGS:- -L error}
14+
if [ -n "$AWS_PROFILE" ]; then
15+
echo "Unable to assume a role while AWS_PROFILE is set"
16+
return 1
17+
fi
18+
eval $({{ .Executable }} $_args eval -p "$1")
19+
if [ "$AWS_SSO_PROFILE" != "$1" ]; then
20+
return 1
21+
fi
2222
}
2323

24-
aws-sso-clear(){
25-
local _args=${AWS_SSO_HELPER_ARGS:- -L error}
26-
if [ -z "$AWS_SSO_PROFILE" ]; then
27-
echo "AWS_SSO_PROFILE is not set"
28-
return 1
29-
fi
30-
eval $(aws-sso eval $_args -c)
24+
aws-sso-clear() {
25+
local _args=${AWS_SSO_HELPER_ARGS:- -L error}
26+
if [ -z "$AWS_SSO_PROFILE" ]; then
27+
echo "AWS_SSO_PROFILE is not set"
28+
return 1
29+
fi
30+
eval $(aws-sso eval $_args -c)
3131
}
3232

33-
complete -F _aws_sso_profile_complete aws-sso-profile
33+
complete -F __aws_sso_profile_complete aws-sso-profile
3434
complete -C {{ .Executable }} aws-sso

internal/helper/helper.go

+60-57
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package helper
1919
*/
2020

2121
import (
22+
"embed"
2223
"fmt"
2324
"os"
2425
"path"
@@ -27,98 +28,99 @@ import (
2728
"github.com/synfinatic/aws-sso-cli/internal/utils"
2829
)
2930

30-
import _ "embed"
31+
//go:embed bash_profile.sh zshrc.sh aws-sso.fish
32+
var embedFiles embed.FS
3133

32-
//go:embed bash_profile.sh
33-
var BASH_PROFILE string
34-
35-
//go:embed zshrc.sh
36-
var ZSH_SCRIPT string
37-
38-
//go:embed aws-sso.fish
39-
var FISH_SCRIPT string
34+
type fileMap struct {
35+
Key string
36+
Path string
37+
}
4038

4139
// map of shells to their file we edit by default
42-
var SHELL_SCRIPTS = map[string]string{
43-
"bash": "~/.bash_profile",
44-
"zsh": "~/.zshrc",
45-
"fish": getFishScript(),
40+
var SHELL_SCRIPTS = map[string]fileMap{
41+
"bash": {
42+
Key: "bash_profile.sh",
43+
Path: "~/.bash_profile",
44+
},
45+
"zsh": {
46+
Key: "zshrc.sh",
47+
Path: "~/.zshrc",
48+
},
49+
"fish": {
50+
Key: "aws-sso.fish",
51+
Path: getFishScript(),
52+
},
4653
}
4754

4855
// ConfigFiles returns a list of all the config files we might edit
4956
func ConfigFiles() []string {
5057
ret := []string{}
5158

5259
for _, v := range SHELL_SCRIPTS {
53-
ret = append(ret, utils.GetHomePath(v))
60+
ret = append(ret, utils.GetHomePath(v.Path))
5461
}
5562
return ret
5663
}
5764

58-
// InstallHelper installs any helper code into our shell startup script(s)
59-
func InstallHelper(shell, script string) error {
65+
// getScript takes a shell and returns the contents & path to the shell script
66+
func getScript(shell string) ([]byte, string, error) {
6067
var err error
68+
var bytes []byte
69+
var shellFile fileMap
6170
var ok bool
62-
var shellFile string
6371

6472
if shell == "" {
6573
if shell, err = detectShell(); err != nil {
66-
return err
74+
return bytes, "", err
6775
}
6876
}
77+
log.Debugf("using %s as our shell", shell)
6978

70-
if script == "" {
71-
if shellFile, ok = SHELL_SCRIPTS[shell]; !ok {
72-
return fmt.Errorf("unsupported shell: %s", shell)
73-
}
74-
script = utils.GetHomePath(shellFile)
79+
if shellFile, ok = SHELL_SCRIPTS[shell]; !ok {
80+
return bytes, "", fmt.Errorf("unsupported shell: %s", shell)
7581
}
7682

77-
switch shell {
78-
case "bash":
79-
err = installConfigFile(script, BASH_PROFILE)
80-
case "zsh":
81-
err = installConfigFile(script, ZSH_SCRIPT)
82-
case "fish":
83-
err = installConfigFile(script, FISH_SCRIPT)
84-
default:
85-
err = fmt.Errorf("unsupported shell: %s", shell)
83+
path := utils.GetHomePath(shellFile.Path)
84+
bytes, err = embedFiles.ReadFile(shellFile.Key)
85+
if err != nil {
86+
return bytes, "", err
8687
}
87-
88-
return err
88+
return bytes, path, nil
8989
}
9090

91-
// UninstallHelper removes any helper code from our shell startup script(s)
92-
func UninstallHelper(shell, script string) error {
93-
var err error
94-
var ok bool
95-
var shellFile string
96-
97-
if shell == "" {
98-
if shell, err = detectShell(); err != nil {
99-
return err
100-
}
91+
// InstallHelper installs any helper code into our shell startup script(s)
92+
func InstallHelper(shell string, path string) error {
93+
c, defaultPath, err := getScript(shell)
94+
if err != nil {
95+
return err
10196
}
10297

103-
if script == "" {
104-
if shellFile, ok = SHELL_SCRIPTS[shell]; !ok {
105-
return fmt.Errorf("unsupported shell: %s", shell)
106-
}
107-
script = utils.GetHomePath(shellFile)
98+
if path == "" {
99+
err = installConfigFile(defaultPath, c)
100+
} else {
101+
err = installConfigFile(path, c)
108102
}
109103

110-
switch shell {
111-
case "bash":
112-
err = uninstallConfigFile(script, BASH_PROFILE)
113-
default:
114-
err = fmt.Errorf("unsupported shell: %s", shell)
104+
return err
105+
}
106+
107+
// UninstallHelper removes any helper code from our shell startup script(s)
108+
func UninstallHelper(shell string, path string) error {
109+
c, defaultPath, err := getScript(shell)
110+
if err != nil {
111+
return err
115112
}
116113

114+
if path == "" {
115+
err = uninstallConfigFile(defaultPath, c)
116+
} else {
117+
err = uninstallConfigFile(path, c)
118+
}
117119
return err
118120
}
119121

120122
// installConfigFile adds our blob to the given file
121-
func installConfigFile(path, contents string) error {
123+
func installConfigFile(path string, contents []byte) error {
122124
var err error
123125
var exec string
124126
var fe *utils.FileEdit
@@ -131,7 +133,7 @@ func installConfigFile(path, contents string) error {
131133
"Executable": exec,
132134
}
133135

134-
if fe, err = utils.NewFileEdit(BASH_PROFILE, args); err != nil {
136+
if fe, err = utils.NewFileEdit(string(contents), args); err != nil {
135137
return err
136138
}
137139

@@ -143,7 +145,7 @@ func installConfigFile(path, contents string) error {
143145
}
144146

145147
// uninstallConfigFile removes our blob from the given file
146-
func uninstallConfigFile(path, contents string) error {
148+
func uninstallConfigFile(path string, contents []byte) error {
147149
var err error
148150
var fe *utils.FileEdit
149151

@@ -168,6 +170,7 @@ func detectShell() (string, error) {
168170
}
169171

170172
_, shell := path.Split(shellPath)
173+
log.Debugf("detected configured shell as: %s", shell)
171174
return shell, nil
172175
}
173176

internal/helper/zshrc.sh

+39-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,39 @@
1-
complete -o nospace -C {{ .Executable }} aws-sso
1+
2+
# AWS SSO requires `bashcompinit` which needs to be enabled once and
3+
# only once in your shell. Hence we do not include the two lines:
4+
#
5+
# autoload -Uz +X compinit && compinit
6+
# autoload -Uz +X bashcompinit && bashcompinit
7+
#
8+
# If you do not already have these lines, you must COPY the lines
9+
# above, place it OUTSIDE of the BEGIN/END_AWS_SSO_CLI markers
10+
# and of course uncomment it
11+
12+
__aws_sso_profile_complete() {
13+
local _args=${AWS_SSO_HELPER_ARGS:- -L error}
14+
_multi_parts : "($({{ .Executable }} list --csv $_args Profile))"
15+
}
16+
17+
aws-sso-profile() {
18+
local _args=${AWS_SSO_HELPER_ARGS:- -L error}
19+
if [ -n "$AWS_PROFILE" ]; then
20+
echo "Unable to assume a role while AWS_PROFILE is set"
21+
return 1
22+
fi
23+
eval $({{ .Executable }} $_args eval -p "$1")
24+
if [ "$AWS_SSO_PROFILE" != "$1" ]; then
25+
return 1
26+
fi
27+
}
28+
29+
aws-sso-clear() {
30+
local _args=${AWS_SSO_HELPER_ARGS:- -L error}
31+
if [ -z "$AWS_SSO_PROFILE" ]; then
32+
echo "AWS_SSO_PROFILE is not set"
33+
return 1
34+
fi
35+
eval $({{ .Executable }} -sso eval $_args -c)
36+
}
37+
38+
compdef __aws_sso_profile_complete aws-sso-profile
39+
complete -C {{ .Executable }} aws-sso

0 commit comments

Comments
 (0)