From 312cb8c8494720721c093693c29fcadb54bda00b Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Tue, 13 Feb 2024 20:22:10 -0800 Subject: [PATCH] shell: specify an interactive shell using "garden.interactive-shell" Allow the interactive shell to be configured separately via the "garden.interactive-shell" configuration value. This allows custom commands to be configured in "garden.shell" that take command strings while specifying an interactive shell command via "garden.interactive-shell". --- doc/src/changelog.md | 21 +++++++++++++++++++++ doc/src/commands.md | 18 ++++++++++++++++++ src/cmds/shell.rs | 8 ++++++-- src/config/reader.rs | 13 +++++++++++++ src/constants.rs | 5 +++++ src/model.rs | 4 ++++ tests/data/shell/custom.yaml | 1 + 7 files changed, 68 insertions(+), 2 deletions(-) diff --git a/doc/src/changelog.md b/doc/src/changelog.md index e3b4fed..76e2c68 100644 --- a/doc/src/changelog.md +++ b/doc/src/changelog.md @@ -29,6 +29,27 @@ `garden -z | --no-wordsplit` option to opt-out of this behavior. ([#25](https://github.com/davvid/garden/pull/25)) +- `garden.shell` can now be configured to use arbitrary commands for executing + command strings. Garden uses the configured `garden.shell` as-is and does + not augment its options (e.g. `-e` or `-o shwordsplit`) when a custom command + is used. Custom commands are identified as commands that expand to 2 or more + command-line arguments. Thus, `python3` is not considered a custom command + and `garden` will run `python3 -c ` to run commands. On the other + hand, specifying `ruby -e` *is* considered a custom command because it + expands to `["ruby", "-e"]` under the hood. If you need to use a custom + command that takes no additional command-line arguments then you can + use `env` as an extra argument to have it be considered as a custom shell. + For example, `env custom-shell` will cause `garden` to run + `env custom-shell `, which is equivalent to `custom-shell `. + Using just `custom-shell` would have resulted in `garden` running + `custom-shell -c ` instead, which may not be desired. + ([#26](https://github.com/davvid/garden/pull/26)) + +- The `garden shell` command can now be configured to use an interactive command shell + that is distinct from the command specified in the `garden.shell` configuration by + configuring the `garden.interactive-shell` value. + ([#26](https://github.com/davvid/garden/pull/26)) + ## v1.2.1 diff --git a/doc/src/commands.md b/doc/src/commands.md index 48e540c..482f31b 100644 --- a/doc/src/commands.md +++ b/doc/src/commands.md @@ -698,6 +698,24 @@ The optional tree argument is not needed for the case where a garden and tree share a name -- garden will chdir into that same-named tree when creating the shell. +If you would like to customize the command to use for `garden shell` then +you can configure `garden.interactive-shell`. This value overrides `garden.shell` +and is only used by the `garden shell` command. + +```yaml +# Launch a fish login shell for "garden shell". +garden: + interactive-shell: fish +``` + +Arbitrary command interpreters can be specified. + +```yaml +# Launch a python interpreter for "garden shell". +garden: + interactive-shell: python3 -B +``` + ## garden ls diff --git a/src/cmds/shell.rs b/src/cmds/shell.rs index 1a99dd2..9b5d536 100644 --- a/src/cmds/shell.rs +++ b/src/cmds/shell.rs @@ -55,12 +55,16 @@ pub fn main(app_context: &model::ApplicationContext, options: &ShellOptions) -> // Evaluate garden.shell let graft_config = context.config.map(|id| app_context.get_config(id)); - let shell_expr = config.shell.clone(); + let shell_expr = if config.interactive_shell.is_empty() { + &config.shell + } else { + &config.interactive_shell + }; let shell = eval::tree_value( app_context, config, graft_config, - &shell_expr, + shell_expr, &context.tree, context.garden.as_ref(), ); diff --git a/src/config/reader.rs b/src/config/reader.rs index 72d213e..5b87fec 100644 --- a/src/config/reader.rs +++ b/src/config/reader.rs @@ -64,6 +64,19 @@ fn parse_recursive( if get_str(&doc[constants::GARDEN][constants::SHELL], &mut config.shell) && config_verbose > 0 { debug!("config: {} = {}", constants::GARDEN_SHELL, config.shell); } + // garden.interactive-shell + if get_str( + &doc[constants::GARDEN][constants::INTERACTIVE_SHELL], + &mut config.interactive_shell, + ) && config_verbose > 0 + { + debug!( + "config: {} = {}", + constants::GARDEN_INTERACTIVE_SHELL, + config.interactive_shell + ); + } + // garden.shell-errexit if get_bool( &doc[constants::GARDEN][constants::SHELL_ERREXIT], diff --git a/src/constants.rs b/src/constants.rs index 8c82b8b..e73c8c9 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -75,6 +75,7 @@ pub const GARDEN_CONFIG_DIR_EXPR: &str = "${GARDEN_CONFIG_DIR}"; pub const GARDEN_ROOT: &str = "GARDEN_ROOT"; /// Command-line defines for overriding configurable behavior. +pub(crate) const GARDEN_INTERACTIVE_SHELL: &str = "garden.interactive-shell"; pub(crate) const GARDEN_SHELL: &str = "garden.shell"; pub(crate) const GARDEN_SHELL_ERREXIT: &str = "garden.shell-errexit"; pub(crate) const GARDEN_SHELL_WORDSPLIT: &str = "garden.shell-wordsplit"; @@ -95,6 +96,10 @@ pub const GROUPS: &str = "groups"; /// files directly into the configuration. pub const INCLUDES: &str = "includes"; +/// The "interactive-shell" key in the garden block overrides the +/// command used by interactive "garden shell" sessions. +pub const INTERACTIVE_SHELL: &str = "interactive-shell"; + /// The "links" key in a tree block defines URLs displayed by "garden ls". pub const LINKS: &str = "links"; diff --git a/src/model.rs b/src/model.rs index d7803ac..83119f7 100644 --- a/src/model.rs +++ b/src/model.rs @@ -494,6 +494,7 @@ pub struct Configuration { pub root_is_dynamic: bool, pub root_path: std::path::PathBuf, pub shell: String, + pub interactive_shell: String, pub templates: HashMap, pub tree_search_path: Vec, pub trees: IndexMap, @@ -670,6 +671,9 @@ impl Configuration { } // Allow overridding garden. using "garden -D garden.=false". match name.as_str() { + constants::GARDEN_INTERACTIVE_SHELL => { + self.interactive_shell = expr; + } constants::GARDEN_SHELL => { self.shell = expr; } diff --git a/tests/data/shell/custom.yaml b/tests/data/shell/custom.yaml index afd5747..621236c 100644 --- a/tests/data/shell/custom.yaml +++ b/tests/data/shell/custom.yaml @@ -1,5 +1,6 @@ garden: shell: zsh -c + interactive-shell: zsh commands: shell-words: |