chef-workstation
chef-workstation copied to clipboard
Simplify and Improve Shell Init
Currently, we use the 'chef shell-init SHELL_NAME' command to generate shell-specific chef setup commands. This generation is performed once by the user and they add the output to their shell RC init script. There's a few problems with the current approach:
- Since the 'chef shell-init' command is written in ruby it's very slow and we can't have users include it directly in their shell rc scripts. Instead we have to instruct the user to add the output to their RC script, which adds more complexity
- Since the process of adding the content to the rc script is a one-time process we can't update the content (including auto-completes) later. When we change chef CLI commands the auto completes will be wrong
- The shell init command requires the user to know their shell (bash vs. zsh vs. fish), which many users don't know
Proposed solution
Include a new shell init shell script at /opt/chef-workstation/bin/chef-shell-init and symlink it to the appropriate dirs to match our other commands. This will be a shell script instead of a Ruby command and will run on bash, zsh, and fish shells. It will autodetect the currently running shell and output the correct shell init commands. The commands will match the current output of the 'chef shell-init' command for each shell.
The usage on the command line to modify the env vars of the current shell should be:
shell% . chef-shell-init
There should probably be a flag to make it permanent that just appends that command to the right rc file based on the users shell:
shell% . chef-shell-init --permanent
The script should probably live in both /opt/chef-workstation/bin
and /opt/chef-workstation/embedded/bin
along with a symlink into /usr/bin
(or /usr/local/bin
for mac or whatever, whatever we do on the given platform)
This ensures that the script is always going to be in the users PATH.
Requirements driving this design:
- The dot is necessary in order to modify the currently running subshell, and this keeps it easy for users to opt-in only for a subshell
- The user knowing their shell or knowing where their rc files are is not required (this generally takes a PhD)
- Not using ruby
- Short commands that are easy to document and/or memorize
I updated the description to reference the bin dir and the symlinks. I'm not sure if this is something we'd expect most users to run directly although they totally could. I kind of want to avoid yet another totally different command that folks need to know since that's been a pretty common complaint with customers. We can make the existing chef shell-init
sub command execute the chef-shell-init
shell script if no args were passed and if --permanent
was passed it would handle shoving the chef-shell-init
into the appropriate rc file. That way the shell script can remain 100% focused on the env var and autocomplete setup and fun things like parsing existing rc scripts can be done in a nice language.
There maybe a couple more I haven't found yet, but see also:
https://github.com/chef/chef-workstation/issues/1505 https://github.com/chef/chef-workstation/issues/1698
Best if we could get this script generated in an automated way based on current CLI state. It would go well with work in flight to convert the tooling to use cobra
for CLI help and info, because that framework can generate shell completion scripts for all platforms (including windows). Some work to be done to see if it can do it all ahead of time, as it seems mostly intended to be interactive.
If we can't auto-generate, we'll need to make sure updating it doesn't fall through the cracks as the shape of the CLI evolves
Phase 1 of this work:
Create a new omnibus software definition that creates a chef-shell-autocompletions
script. This script will include just the autocompletion logic for sh, bash, fish, and zsh with appropriate shell logic to add the right autocomplete based on shell. The existing chef shell-init
command will then get updated to reference this new script instead of spitting out all the autocompletions via ruby.