From 51a012d5816a1de2d59a32f8111c30d8a8fc9852 Mon Sep 17 00:00:00 2001 From: Philippe Llerena Date: Fri, 9 Aug 2024 09:35:48 +0200 Subject: [PATCH 01/12] add nushell support start 0.97.0+ Signed-off-by: Philippe Llerena --- crates/spfs/src/bootstrap.rs | 44 ++++++++++++++++++- crates/spfs/src/graph/mod.rs | 10 +---- crates/spfs/src/runtime/config.nu | 4 ++ crates/spfs/src/runtime/config_nu.rs | 13 ++++++ crates/spfs/src/runtime/env.nu | 65 ++++++++++++++++++++++++++++ crates/spfs/src/runtime/env_nu.rs | 13 ++++++ crates/spfs/src/runtime/mod.rs | 19 ++------ crates/spfs/src/runtime/storage.rs | 19 +++++++- crates/spk-build/src/build/binary.rs | 11 ++++- crates/spk-schema/src/environ.rs | 34 +++++++++++++++ 10 files changed, 205 insertions(+), 27 deletions(-) create mode 100644 crates/spfs/src/runtime/config.nu create mode 100644 crates/spfs/src/runtime/config_nu.rs create mode 100644 crates/spfs/src/runtime/env.nu create mode 100644 crates/spfs/src/runtime/env_nu.rs diff --git a/crates/spfs/src/bootstrap.rs b/crates/spfs/src/bootstrap.rs index 5836fcc41c..fb74c20246 100644 --- a/crates/spfs/src/bootstrap.rs +++ b/crates/spfs/src/bootstrap.rs @@ -186,6 +186,16 @@ pub fn build_interactive_shell_command( ], vars: vec![shell_message], }), + Shell::Nushell(nu) => Ok(Command { + executable: nu.into(), + args: vec![ + "--env-config".into(), + rt.config.nu_env_file.as_os_str().to_owned(), + "--config".into(), + rt.config.nu_config_file.as_os_str().to_owned(), + ], + vars: vec![shell_message], + }), #[cfg(windows)] Shell::Powershell(ps1) => Ok(Command { executable: ps1.into(), @@ -221,6 +231,26 @@ where let startup_file = match shell.kind() { ShellKind::Bash => &runtime.config.sh_startup_file, ShellKind::Tcsh => &runtime.config.csh_startup_file, + ShellKind::Nushell => { + let mut cmd = command.into(); + for arg in args.into_iter().map(Into::into) { + cmd.push(" "); + cmd.push(arg); + } + let args = vec![ + "--env-config".into(), + runtime.config.nu_env_file.as_os_str().to_owned(), + "--config".into(), + runtime.config.nu_config_file.as_os_str().to_owned(), + "-c".into(), + cmd, + ]; + return Ok(Command { + executable: shell.executable().into(), + args, + vars: vec![], + }); + } ShellKind::Powershell => { let mut cmd = command.into(); for arg in args.into_iter().map(Into::into) { @@ -244,7 +274,6 @@ where let mut shell_args = vec![startup_file.into(), command.into()]; shell_args.extend(args.into_iter().map(Into::into)); - Ok(Command { executable: shell.executable().into(), args: shell_args, @@ -385,6 +414,7 @@ pub enum ShellKind { Bash, Tcsh, Powershell, + Nushell, } impl AsRef for ShellKind { @@ -392,6 +422,7 @@ impl AsRef for ShellKind { match self { Self::Bash => "bash", Self::Tcsh => "tcsh", + Self::Nushell => "nu", Self::Powershell => "powershell.exe", } } @@ -404,6 +435,7 @@ pub enum Shell { Bash(PathBuf), #[cfg(unix)] Tcsh(PathBuf), + Nushell(PathBuf), #[cfg(windows)] Powershell(PathBuf), } @@ -415,6 +447,7 @@ impl Shell { Self::Bash(_) => ShellKind::Bash, #[cfg(unix)] Self::Tcsh(_) => ShellKind::Tcsh, + Self::Nushell(_) => ShellKind::Nushell, #[cfg(windows)] Self::Powershell(_) => ShellKind::Powershell, } @@ -427,6 +460,7 @@ impl Shell { Self::Bash(p) => p, #[cfg(unix)] Self::Tcsh(p) => p, + Self::Nushell(p) => p, #[cfg(windows)] Self::Powershell(p) => p, } @@ -442,6 +476,7 @@ impl Shell { Some(n) if n == ShellKind::Bash.as_ref() => Ok(Self::Bash(path.to_owned())), #[cfg(unix)] Some(n) if n == ShellKind::Tcsh.as_ref() => Ok(Self::Tcsh(path.to_owned())), + Some(n) if n == ShellKind::Nushell.as_ref() => Ok(Self::Nushell(path.to_owned())), #[cfg(windows)] Some(n) if n == ShellKind::Powershell.as_ref() => Ok(Self::Powershell(path.to_owned())), Some(_) => Err(Error::new(format!("Unsupported shell: {path:?}"))), @@ -477,7 +512,12 @@ impl Shell { } } - for kind in &[ShellKind::Bash, ShellKind::Tcsh, ShellKind::Powershell] { + for kind in &[ + ShellKind::Bash, + ShellKind::Tcsh, + ShellKind::Powershell, + ShellKind::Nushell, + ] { if let Some(path) = which(kind) { if let Ok(shell) = Shell::from_path(path) { return Ok(shell); diff --git a/crates/spfs/src/graph/mod.rs b/crates/spfs/src/graph/mod.rs index 8a26800e69..e5c87ad0a4 100644 --- a/crates/spfs/src/graph/mod.rs +++ b/crates/spfs/src/graph/mod.rs @@ -20,17 +20,11 @@ mod tree; use std::cell::RefCell; pub use annotation::{ - Annotation, - AnnotationValue, - DEFAULT_SPFS_ANNOTATION_LAYER_MAX_STRING_VALUE_SIZE, + Annotation, AnnotationValue, DEFAULT_SPFS_ANNOTATION_LAYER_MAX_STRING_VALUE_SIZE, }; pub use blob::Blob; pub use database::{ - Database, - DatabaseIterator, - DatabaseView, - DatabaseWalker, - DigestSearchCriteria, + Database, DatabaseIterator, DatabaseView, DatabaseWalker, DigestSearchCriteria, }; pub use entry::Entry; pub use kind::{HasKind, Kind, ObjectKind}; diff --git a/crates/spfs/src/runtime/config.nu b/crates/spfs/src/runtime/config.nu new file mode 100644 index 0000000000..2bb7cea2cb --- /dev/null +++ b/crates/spfs/src/runtime/config.nu @@ -0,0 +1,4 @@ +$env.config = { + show_banner: false, +} +print $env.SPFS_SHELL_MESSAGE? \ No newline at end of file diff --git a/crates/spfs/src/runtime/config_nu.rs b/crates/spfs/src/runtime/config_nu.rs new file mode 100644 index 0000000000..072499801c --- /dev/null +++ b/crates/spfs/src/runtime/config_nu.rs @@ -0,0 +1,13 @@ +// Copyright (c) Contributors to the SPK project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/spkenv/spk +// Warning Nuhshell version >=0.96 + +use std::fs; + +pub fn source(_tmpdir: Option<&T>) -> String +where + T: AsRef, +{ + fs::read_to_string("/home/philippe.llerena/workspace/github.com/doubleailes/spk/crates/spfs/src/runtime/config.nu").unwrap() +} diff --git a/crates/spfs/src/runtime/env.nu b/crates/spfs/src/runtime/env.nu new file mode 100644 index 0000000000..1edbfde818 --- /dev/null +++ b/crates/spfs/src/runtime/env.nu @@ -0,0 +1,65 @@ +def create_left_prompt [] { + let dir = match (do --ignore-shell-errors { $env.PWD | path relative-to $nu.home-path }) { + null => $env.PWD + '' => '~' + $relative_pwd => ([~ $relative_pwd] | path join) + } + + let path_color = (if (is-admin) { ansi red_bold } else { ansi green_bold }) + let separator_color = (if (is-admin) { ansi light_red_bold } else { ansi light_green_bold }) + let path_segment = $"($path_color)($dir)(ansi reset)" + + $path_segment | str replace --all (char path_sep) $"($separator_color)(char path_sep)($path_color)" +} + +def create_right_prompt [] { + # create a right prompt in magenta with green separators and am/pm underlined + let time_segment = ([ + (ansi reset) + (ansi magenta) + (date now | format date '%x %X') # try to respect user's locale + ] | str join | str replace --regex --all "([/:])" $"(ansi green)${1}(ansi magenta)" | + str replace --regex --all "([AP]M)" $"(ansi magenta_underline)${1}") + + let last_exit_code = if ($env.LAST_EXIT_CODE != 0) {([ + (ansi rb) + ($env.LAST_EXIT_CODE) + ] | str join) + } else { "" } + + ([$last_exit_code, (char space), $time_segment] | str join) +} + +# Use nushell functions to define your right and left prompt +$env.PROMPT_COMMAND = {|| create_left_prompt } +# FIXME: This default is not implemented in rust code as of 2023-09-08. +$env.PROMPT_COMMAND_RIGHT = {|| create_right_prompt } + +# The prompt indicators are environmental variables that represent +# the state of the prompt +$env.PROMPT_INDICATOR = {|| "> " } +$env.PROMPT_INDICATOR_VI_INSERT = {|| ": " } +$env.PROMPT_INDICATOR_VI_NORMAL = {|| "> " } +$env.PROMPT_MULTILINE_INDICATOR = {|| "::: " } + + +$env.ENV_CONVERSIONS = { + "PATH": { + from_string: { |s| $s | split row (char esep) | path expand --no-symlink } + to_string: { |v| $v | path expand --no-symlink | str join (char esep) } + } + "Path": { + from_string: { |s| $s | split row (char esep) | path expand --no-symlink } + to_string: { |v| $v | path expand --no-symlink | str join (char esep) } + } +} + +let $spfs_startup_dir = if $nu.os-info.name == "windows" { + "C:/spfs/etc/spfs/startup.d" +} else if $nu.os-info.name == "linux" { + "/spfs/etc/spfs/startup.d" +} else { + exit 1 +} + +$env.NU_VENDOR_AUTOLOAD_DIR = ($spfs_startup_dir) \ No newline at end of file diff --git a/crates/spfs/src/runtime/env_nu.rs b/crates/spfs/src/runtime/env_nu.rs new file mode 100644 index 0000000000..12f2bc0dc5 --- /dev/null +++ b/crates/spfs/src/runtime/env_nu.rs @@ -0,0 +1,13 @@ +// Copyright (c) Contributors to the SPK project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/spkenv/spk +// Warning Nuhshell version >=0.96 + +use std::fs; + +pub fn source(_tmpdir: Option<&T>) -> String +where + T: AsRef, +{ + fs::read_to_string("/home/philippe.llerena/workspace/github.com/doubleailes/spk/crates/spfs/src/runtime/env.nu").unwrap() +} \ No newline at end of file diff --git a/crates/spfs/src/runtime/mod.rs b/crates/spfs/src/runtime/mod.rs index 0ee10a9bac..d06734ba11 100644 --- a/crates/spfs/src/runtime/mod.rs +++ b/crates/spfs/src/runtime/mod.rs @@ -4,6 +4,8 @@ //! Handles the setup and initialization of runtime environments +mod config_nu; +mod env_nu; #[cfg(unix)] pub mod overlayfs; #[cfg(unix)] @@ -19,21 +21,8 @@ pub mod winfsp; #[cfg(unix)] pub use overlayfs::is_removed_entry; pub use storage::{ - makedirs_with_perms, - Author, - BindMount, - Config, - Data, - KeyValuePair, - KeyValuePairBuf, - LiveLayer, - LiveLayerFile, - MountBackend, - OwnedRuntime, - Runtime, - Status, - Storage, - STARTUP_FILES_LOCATION, + makedirs_with_perms, Author, BindMount, Config, Data, KeyValuePair, KeyValuePairBuf, LiveLayer, + LiveLayerFile, MountBackend, OwnedRuntime, Runtime, Status, Storage, STARTUP_FILES_LOCATION, }; #[cfg(windows)] pub use winfsp::is_removed_entry; diff --git a/crates/spfs/src/runtime/storage.rs b/crates/spfs/src/runtime/storage.rs index 002fe1f038..56204864d9 100644 --- a/crates/spfs/src/runtime/storage.rs +++ b/crates/spfs/src/runtime/storage.rs @@ -27,7 +27,7 @@ use tokio::io::AsyncReadExt; #[cfg(windows)] use super::startup_ps; #[cfg(unix)] -use super::{startup_csh, startup_sh}; +use super::{config_nu, env_nu, startup_csh, startup_sh}; use crate::encoding::Digest; use crate::env::SPFS_DIR_PREFIX; use crate::graph::object::Enum; @@ -379,6 +379,9 @@ pub struct Config { pub sh_startup_file: PathBuf, /// The location of the startup script for csh-based shells pub csh_startup_file: PathBuf, + /// The location of the startup script for nushell-based shells + pub nu_env_file: PathBuf, + pub nu_config_file: PathBuf, /// The location of the expect utility script used for csh-based shell environments /// \[DEPRECATED\] This field still exists for spk/spfs interop but is unused #[serde(skip_deserializing, default = "Config::default_csh_expect_file")] @@ -420,6 +423,8 @@ impl Config { const SH_STARTUP_FILE: &'static str = "startup.sh"; const CSH_STARTUP_FILE: &'static str = ".cshrc"; const PS_STARTUP_FILE: &'static str = "startup.ps1"; + const NU_ENV_FILE: &'static str = "env.nu"; + const NU_CONFIG_FILE: &'static str = "config.nu"; const DEV_NULL: &'static str = "/dev/null"; /// Return a dummy value for the legacy csh_expect_file field. @@ -440,6 +445,8 @@ impl Config { csh_startup_file: root.join(Self::CSH_STARTUP_FILE), csh_expect_file: Self::default_csh_expect_file(), ps_startup_file: temp_dir().join(Self::PS_STARTUP_FILE), + nu_env_file: temp_dir().join(Self::NU_ENV_FILE), + nu_config_file: temp_dir().join(Self::NU_CONFIG_FILE), runtime_dir: Some(root), tmpfs_size, mount_namespace: None, @@ -1035,6 +1042,16 @@ impl Runtime { startup_csh::source(tmpdir_value_for_child_process), ) .map_err(|err| Error::RuntimeWriteError(self.config.csh_startup_file.clone(), err))?; + std::fs::write( + &self.config.nu_env_file, + env_nu::source(tmpdir_value_for_child_process), + ) + .map_err(|err| Error::RuntimeWriteError(self.config.nu_env_file.clone(), err))?; + std::fs::write( + &self.config.nu_config_file, + config_nu::source(tmpdir_value_for_child_process), + ) + .map_err(|err| Error::RuntimeWriteError(self.config.nu_config_file.clone(), err))?; #[cfg(windows)] std::fs::write( &self.config.ps_startup_file, diff --git a/crates/spk-build/src/build/binary.rs b/crates/spk-build/src/build/binary.rs index 2b1719cde1..8b043d42e5 100644 --- a/crates/spk-build/src/build/binary.rs +++ b/crates/spk-build/src/build/binary.rs @@ -688,23 +688,29 @@ where let mut startup_file_csh = startup_dir.join(format!("spk_{}.csh", package.name())); let mut startup_file_sh = startup_dir.join(format!("spk_{}.sh", package.name())); + let mut startup_file_nu = startup_dir.join(format!("spk_{}.nu", package.name())); let mut csh_file = std::fs::File::create(&startup_file_csh) .map_err(|err| Error::FileOpenError(startup_file_csh.to_owned(), err))?; let mut sh_file = std::fs::File::create(&startup_file_sh) .map_err(|err| Error::FileOpenError(startup_file_sh.to_owned(), err))?; - + let mut nu_file = std::fs::File::create(&startup_file_nu) + .map_err(|err| Error::FileOpenError(startup_file_nu.to_owned(), err))?; for op in ops { if let Some(priority) = op.priority() { let original_startup_file_sh_name = startup_file_sh.clone(); let original_startup_file_csh_name = startup_file_csh.clone(); + let original_startup_file_nu_name = startup_file_nu.clone(); startup_file_sh.set_file_name(format!("{priority:02}_spk_{}.sh", package.name())); startup_file_csh.set_file_name(format!("{priority:02}_spk_{}.csh", package.name())); + startup_file_nu.set_file_name(format!("{priority:02}_spk_{}.nu", package.name())); std::fs::rename(original_startup_file_sh_name, &startup_file_sh) .map_err(|err| Error::FileWriteError(startup_file_sh.to_owned(), err))?; std::fs::rename(original_startup_file_csh_name, &startup_file_csh) .map_err(|err| Error::FileWriteError(startup_file_csh.to_owned(), err))?; + std::fs::rename(original_startup_file_nu_name, &startup_file_nu) + .map_err(|err| Error::FileWriteError(startup_file_nu.to_owned(), err))?; continue; } @@ -715,6 +721,9 @@ where sh_file .write_fmt(format_args!("{}\n", op.bash_source())) .map_err(|err| Error::FileWriteError(startup_file_sh.to_owned(), err))?; + nu_file + .write_fmt(format_args!("{}\n", op.nushell_source())) + .map_err(|err| Error::FileWriteError(startup_file_nu.to_owned(), err))?; } Ok(()) } diff --git a/crates/spk-schema/src/environ.rs b/crates/spk-schema/src/environ.rs index 74515e25cd..67690e7d8d 100644 --- a/crates/spk-schema/src/environ.rs +++ b/crates/spk-schema/src/environ.rs @@ -63,6 +63,7 @@ impl EnvOp { spfs::ShellKind::Bash => self.bash_source(), spfs::ShellKind::Tcsh => self.tcsh_source(), spfs::ShellKind::Powershell => self.powershell_source(), + spfs::ShellKind::Nushell => self.nushell_source(), } } @@ -148,6 +149,17 @@ impl EnvOp { pub fn powershell_source(&self) -> String { todo!() } + + /// Construct the nushell source representation for this operation + pub fn nushell_source(&self) -> String { + match self { + Self::Append(op) => op.nu_source(), + Self::Comment(op) => op.nu_source(), + Self::Prepend(op) => op.nu_source(), + Self::Priority(op) => op.nu_source(), + Self::Set(op) => op.nu_source(), + } + } } impl<'de> Deserialize<'de> for EnvOp { @@ -358,6 +370,12 @@ impl AppendEnv { ] .join("\n") } + pub fn nu_source(&self) -> String { + format!( + "$env.{} = (\"{}\" | append $env.{}?)", + self.append, self.append, self.value + ) + } } /// Adds a comment to the generated environment script @@ -376,6 +394,10 @@ impl EnvComment { // Both bash and tcsh source use the same comment syntax self.bash_source() } + pub fn nu_source(&self) -> String { + // Nushell use the same comment syntax as bash + self.bash_source() + } } /// Assigns a priority to the generated environment script @@ -398,6 +420,9 @@ impl EnvPriority { pub fn priority(&self) -> u8 { self.priority } + pub fn nu_source(&self) -> String { + String::from("") + } } /// Operates on an environment variable by prepending to the beginning @@ -447,6 +472,12 @@ impl PrependEnv { ] .join("\n") } + pub fn nu_source(&self) -> String { + format!( + "$env.{} = ($env.{}? | prepend \"{}\")", + self.prepend, self.prepend, self.value + ) + } } /// Operates on an environment variable by setting it to a value @@ -465,4 +496,7 @@ impl SetEnv { pub fn tcsh_source(&self) -> String { format!("setenv {} \"{}\"", self.set, self.value) } + pub fn nu_source(&self) -> String { + format!("$env.{} = \"{}\"", self.set, self.value) + } } From 9677350abd6317c8d9647bef35f54d5aa3eab639 Mon Sep 17 00:00:00 2001 From: Philippe Llerena Date: Wed, 14 Aug 2024 15:36:54 +0200 Subject: [PATCH 02/12] fix: separate nu startup from unix shell to be ok with Windows Signed-off-by: Philippe Llerena --- crates/spfs/src/runtime/storage.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/spfs/src/runtime/storage.rs b/crates/spfs/src/runtime/storage.rs index 56204864d9..4ddeca576e 100644 --- a/crates/spfs/src/runtime/storage.rs +++ b/crates/spfs/src/runtime/storage.rs @@ -27,7 +27,8 @@ use tokio::io::AsyncReadExt; #[cfg(windows)] use super::startup_ps; #[cfg(unix)] -use super::{config_nu, env_nu, startup_csh, startup_sh}; +use super::{startup_csh, startup_sh}; +use super::{config_nu, env_nu}; use crate::encoding::Digest; use crate::env::SPFS_DIR_PREFIX; use crate::graph::object::Enum; From 483ae1360179cfabf6373d4613307c17d4c4afb1 Mon Sep 17 00:00:00 2001 From: Philippe Llerena Date: Sat, 17 Aug 2024 13:58:50 +0200 Subject: [PATCH 03/12] Clean config Signed-off-by: Philippe Llerena --- crates/spfs/src/runtime/config.nu | 4 -- crates/spfs/src/runtime/config_nu.rs | 14 +++-- crates/spfs/src/runtime/env.nu | 65 ------------------------ crates/spfs/src/runtime/env_nu.rs | 76 ++++++++++++++++++++++++++-- 4 files changed, 81 insertions(+), 78 deletions(-) delete mode 100644 crates/spfs/src/runtime/config.nu delete mode 100644 crates/spfs/src/runtime/env.nu diff --git a/crates/spfs/src/runtime/config.nu b/crates/spfs/src/runtime/config.nu deleted file mode 100644 index 2bb7cea2cb..0000000000 --- a/crates/spfs/src/runtime/config.nu +++ /dev/null @@ -1,4 +0,0 @@ -$env.config = { - show_banner: false, -} -print $env.SPFS_SHELL_MESSAGE? \ No newline at end of file diff --git a/crates/spfs/src/runtime/config_nu.rs b/crates/spfs/src/runtime/config_nu.rs index 072499801c..c7ca1b2d1d 100644 --- a/crates/spfs/src/runtime/config_nu.rs +++ b/crates/spfs/src/runtime/config_nu.rs @@ -3,11 +3,17 @@ // https://github.com/spkenv/spk // Warning Nuhshell version >=0.96 -use std::fs; pub fn source(_tmpdir: Option<&T>) -> String where T: AsRef, -{ - fs::read_to_string("/home/philippe.llerena/workspace/github.com/doubleailes/spk/crates/spfs/src/runtime/config.nu").unwrap() -} + { + r#" + $env.config = { + show_banner: false, + } + $env.SPFS_SHELL_MESSAGE? | print + "# + .to_string() + } + diff --git a/crates/spfs/src/runtime/env.nu b/crates/spfs/src/runtime/env.nu deleted file mode 100644 index 1edbfde818..0000000000 --- a/crates/spfs/src/runtime/env.nu +++ /dev/null @@ -1,65 +0,0 @@ -def create_left_prompt [] { - let dir = match (do --ignore-shell-errors { $env.PWD | path relative-to $nu.home-path }) { - null => $env.PWD - '' => '~' - $relative_pwd => ([~ $relative_pwd] | path join) - } - - let path_color = (if (is-admin) { ansi red_bold } else { ansi green_bold }) - let separator_color = (if (is-admin) { ansi light_red_bold } else { ansi light_green_bold }) - let path_segment = $"($path_color)($dir)(ansi reset)" - - $path_segment | str replace --all (char path_sep) $"($separator_color)(char path_sep)($path_color)" -} - -def create_right_prompt [] { - # create a right prompt in magenta with green separators and am/pm underlined - let time_segment = ([ - (ansi reset) - (ansi magenta) - (date now | format date '%x %X') # try to respect user's locale - ] | str join | str replace --regex --all "([/:])" $"(ansi green)${1}(ansi magenta)" | - str replace --regex --all "([AP]M)" $"(ansi magenta_underline)${1}") - - let last_exit_code = if ($env.LAST_EXIT_CODE != 0) {([ - (ansi rb) - ($env.LAST_EXIT_CODE) - ] | str join) - } else { "" } - - ([$last_exit_code, (char space), $time_segment] | str join) -} - -# Use nushell functions to define your right and left prompt -$env.PROMPT_COMMAND = {|| create_left_prompt } -# FIXME: This default is not implemented in rust code as of 2023-09-08. -$env.PROMPT_COMMAND_RIGHT = {|| create_right_prompt } - -# The prompt indicators are environmental variables that represent -# the state of the prompt -$env.PROMPT_INDICATOR = {|| "> " } -$env.PROMPT_INDICATOR_VI_INSERT = {|| ": " } -$env.PROMPT_INDICATOR_VI_NORMAL = {|| "> " } -$env.PROMPT_MULTILINE_INDICATOR = {|| "::: " } - - -$env.ENV_CONVERSIONS = { - "PATH": { - from_string: { |s| $s | split row (char esep) | path expand --no-symlink } - to_string: { |v| $v | path expand --no-symlink | str join (char esep) } - } - "Path": { - from_string: { |s| $s | split row (char esep) | path expand --no-symlink } - to_string: { |v| $v | path expand --no-symlink | str join (char esep) } - } -} - -let $spfs_startup_dir = if $nu.os-info.name == "windows" { - "C:/spfs/etc/spfs/startup.d" -} else if $nu.os-info.name == "linux" { - "/spfs/etc/spfs/startup.d" -} else { - exit 1 -} - -$env.NU_VENDOR_AUTOLOAD_DIR = ($spfs_startup_dir) \ No newline at end of file diff --git a/crates/spfs/src/runtime/env_nu.rs b/crates/spfs/src/runtime/env_nu.rs index 12f2bc0dc5..0518915837 100644 --- a/crates/spfs/src/runtime/env_nu.rs +++ b/crates/spfs/src/runtime/env_nu.rs @@ -3,11 +3,77 @@ // https://github.com/spkenv/spk // Warning Nuhshell version >=0.96 -use std::fs; - pub fn source(_tmpdir: Option<&T>) -> String where T: AsRef, -{ - fs::read_to_string("/home/philippe.llerena/workspace/github.com/doubleailes/spk/crates/spfs/src/runtime/env.nu").unwrap() -} \ No newline at end of file + { + r#" + def create_left_prompt [] { + let dir = match (do --ignore-shell-errors { $env.PWD | path relative-to $nu.home-path }) { + null => $env.PWD + '' => '~' + $relative_pwd => ([~ $relative_pwd] | path join) + } + + let path_color = (if (is-admin) { ansi red_bold } else { ansi green_bold }) + let separator_color = (if (is-admin) { ansi light_red_bold } else { ansi light_green_bold }) + let path_segment = $"($path_color)($dir)(ansi reset)" + + $path_segment | str replace --all (char path_sep) $"($separator_color)(char path_sep)($path_color)" + } + + def create_right_prompt [] { + # create a right prompt in magenta with green separators and am/pm underlined + let time_segment = ([ + (ansi reset) + (ansi magenta) + (date now | format date '%x %X') # try to respect user's locale + ] | str join | str replace --regex --all "([/:])" $"(ansi green)${1}(ansi magenta)" | + str replace --regex --all "([AP]M)" $"(ansi magenta_underline)${1}") + + let last_exit_code = if ($env.LAST_EXIT_CODE != 0) {([ + (ansi rb) + ($env.LAST_EXIT_CODE) + ] | str join) + } else { "" } + + ([$last_exit_code, (char space), $time_segment] | str join) + } + + # Use nushell functions to define your right and left prompt + $env.PROMPT_COMMAND = {|| create_left_prompt } + # FIXME: This default is not implemented in rust code as of 2023-09-08. + $env.PROMPT_COMMAND_RIGHT = {|| create_right_prompt } + + # The prompt indicators are environmental variables that represent + # the state of the prompt + $env.PROMPT_INDICATOR = {|| "> " } + $env.PROMPT_INDICATOR_VI_INSERT = {|| ": " } + $env.PROMPT_INDICATOR_VI_NORMAL = {|| "> " } + $env.PROMPT_MULTILINE_INDICATOR = {|| "::: " } + + + $env.ENV_CONVERSIONS = { + "PATH": { + from_string: { |s| $s | split row (char esep) | path expand --no-symlink } + to_string: { |v| $v | path expand --no-symlink | str join (char esep) } + } + "Path": { + from_string: { |s| $s | split row (char esep) | path expand --no-symlink } + to_string: { |v| $v | path expand --no-symlink | str join (char esep) } + } + } + + let $spfs_startup_dir = if $nu.os-info.name == "windows" { + "C:/spfs/etc/spfs/startup.d" + } else if $nu.os-info.name == "linux" { + "/spfs/etc/spfs/startup.d" + } else { + exit 1 + } + + $env.NU_VENDOR_AUTOLOAD_DIR = ($spfs_startup_dir) + "# + .to_string() + } + \ No newline at end of file From 9fa89ef369443d6fc8cc41ecb8e281bbde53b61e Mon Sep 17 00:00:00 2001 From: Philippe Llerena Date: Sat, 17 Aug 2024 16:43:55 +0200 Subject: [PATCH 04/12] Type fix and add Nushell, esep, AUTOLOAD to spellcheck Signed-off-by: Philippe Llerena --- crates/spfs/src/runtime/config_nu.rs | 2 +- crates/spfs/src/runtime/env_nu.rs | 2 +- cspell.json | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/spfs/src/runtime/config_nu.rs b/crates/spfs/src/runtime/config_nu.rs index c7ca1b2d1d..25ef526eb8 100644 --- a/crates/spfs/src/runtime/config_nu.rs +++ b/crates/spfs/src/runtime/config_nu.rs @@ -1,7 +1,7 @@ // Copyright (c) Contributors to the SPK project. // SPDX-License-Identifier: Apache-2.0 // https://github.com/spkenv/spk -// Warning Nuhshell version >=0.96 +// Warning Nushell version >=0.97 pub fn source(_tmpdir: Option<&T>) -> String diff --git a/crates/spfs/src/runtime/env_nu.rs b/crates/spfs/src/runtime/env_nu.rs index 0518915837..42b326384e 100644 --- a/crates/spfs/src/runtime/env_nu.rs +++ b/crates/spfs/src/runtime/env_nu.rs @@ -1,7 +1,7 @@ // Copyright (c) Contributors to the SPK project. // SPDX-License-Identifier: Apache-2.0 // https://github.com/spkenv/spk -// Warning Nuhshell version >=0.96 +// Warning Nushell version >=0.97 pub fn source(_tmpdir: Option<&T>) -> String where diff --git a/cspell.json b/cspell.json index 975da1b413..d2e789e392 100644 --- a/cspell.json +++ b/cspell.json @@ -30,6 +30,7 @@ "ASWF", "atexit", "autogen", + "AUTOLOAD", "automounter", "autopoint", "autoreconf", @@ -201,6 +202,7 @@ "errexit", "Errno", "esac", + "esep", "ESRCH", "euid", "evenmoredata", @@ -449,6 +451,8 @@ "NQCYJ", "NTSTATUS", "numpy", + "nushell", + "Nushell", "nvcc", "NVPTX", "NZFA", From e66c0cca3075aee1df579a9216a39087c2053e74 Mon Sep 17 00:00:00 2001 From: Philippe Llerena Date: Mon, 2 Sep 2024 14:19:54 +0200 Subject: [PATCH 05/12] quality: run cargo fmt --- crates/spfs/src/graph/mod.rs | 10 ++++++++-- crates/spfs/src/runtime/config_nu.rs | 10 ++++------ crates/spfs/src/runtime/env_nu.rs | 7 +++---- crates/spfs/src/runtime/mod.rs | 17 +++++++++++++++-- crates/spfs/src/runtime/storage.rs | 2 +- 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/crates/spfs/src/graph/mod.rs b/crates/spfs/src/graph/mod.rs index e5c87ad0a4..8a26800e69 100644 --- a/crates/spfs/src/graph/mod.rs +++ b/crates/spfs/src/graph/mod.rs @@ -20,11 +20,17 @@ mod tree; use std::cell::RefCell; pub use annotation::{ - Annotation, AnnotationValue, DEFAULT_SPFS_ANNOTATION_LAYER_MAX_STRING_VALUE_SIZE, + Annotation, + AnnotationValue, + DEFAULT_SPFS_ANNOTATION_LAYER_MAX_STRING_VALUE_SIZE, }; pub use blob::Blob; pub use database::{ - Database, DatabaseIterator, DatabaseView, DatabaseWalker, DigestSearchCriteria, + Database, + DatabaseIterator, + DatabaseView, + DatabaseWalker, + DigestSearchCriteria, }; pub use entry::Entry; pub use kind::{HasKind, Kind, ObjectKind}; diff --git a/crates/spfs/src/runtime/config_nu.rs b/crates/spfs/src/runtime/config_nu.rs index 25ef526eb8..bedb90757d 100644 --- a/crates/spfs/src/runtime/config_nu.rs +++ b/crates/spfs/src/runtime/config_nu.rs @@ -3,17 +3,15 @@ // https://github.com/spkenv/spk // Warning Nushell version >=0.97 - pub fn source(_tmpdir: Option<&T>) -> String where T: AsRef, - { - r#" +{ + r#" $env.config = { show_banner: false, } $env.SPFS_SHELL_MESSAGE? | print "# - .to_string() - } - + .to_string() +} diff --git a/crates/spfs/src/runtime/env_nu.rs b/crates/spfs/src/runtime/env_nu.rs index 42b326384e..16b1f98d0c 100644 --- a/crates/spfs/src/runtime/env_nu.rs +++ b/crates/spfs/src/runtime/env_nu.rs @@ -6,8 +6,8 @@ pub fn source(_tmpdir: Option<&T>) -> String where T: AsRef, - { - r#" +{ + r#" def create_left_prompt [] { let dir = match (do --ignore-shell-errors { $env.PWD | path relative-to $nu.home-path }) { null => $env.PWD @@ -75,5 +75,4 @@ where $env.NU_VENDOR_AUTOLOAD_DIR = ($spfs_startup_dir) "# .to_string() - } - \ No newline at end of file +} diff --git a/crates/spfs/src/runtime/mod.rs b/crates/spfs/src/runtime/mod.rs index d06734ba11..d15c649ef2 100644 --- a/crates/spfs/src/runtime/mod.rs +++ b/crates/spfs/src/runtime/mod.rs @@ -21,8 +21,21 @@ pub mod winfsp; #[cfg(unix)] pub use overlayfs::is_removed_entry; pub use storage::{ - makedirs_with_perms, Author, BindMount, Config, Data, KeyValuePair, KeyValuePairBuf, LiveLayer, - LiveLayerFile, MountBackend, OwnedRuntime, Runtime, Status, Storage, STARTUP_FILES_LOCATION, + makedirs_with_perms, + Author, + BindMount, + Config, + Data, + KeyValuePair, + KeyValuePairBuf, + LiveLayer, + LiveLayerFile, + MountBackend, + OwnedRuntime, + Runtime, + Status, + Storage, + STARTUP_FILES_LOCATION, }; #[cfg(windows)] pub use winfsp::is_removed_entry; diff --git a/crates/spfs/src/runtime/storage.rs b/crates/spfs/src/runtime/storage.rs index 4ddeca576e..9dea30dd9e 100644 --- a/crates/spfs/src/runtime/storage.rs +++ b/crates/spfs/src/runtime/storage.rs @@ -26,9 +26,9 @@ use tokio::io::AsyncReadExt; #[cfg(windows)] use super::startup_ps; +use super::{config_nu, env_nu}; #[cfg(unix)] use super::{startup_csh, startup_sh}; -use super::{config_nu, env_nu}; use crate::encoding::Digest; use crate::env::SPFS_DIR_PREFIX; use crate::graph::object::Enum; From aff3a2bf5e2b31ff44e8452d69305fb33ac7e206 Mon Sep 17 00:00:00 2001 From: Philippe Llerena Date: Thu, 5 Sep 2024 17:50:01 +0200 Subject: [PATCH 06/12] fix: replace by the root value to match bash behavior --- crates/spfs/src/runtime/storage.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/spfs/src/runtime/storage.rs b/crates/spfs/src/runtime/storage.rs index 9dea30dd9e..163ce87b7b 100644 --- a/crates/spfs/src/runtime/storage.rs +++ b/crates/spfs/src/runtime/storage.rs @@ -446,8 +446,8 @@ impl Config { csh_startup_file: root.join(Self::CSH_STARTUP_FILE), csh_expect_file: Self::default_csh_expect_file(), ps_startup_file: temp_dir().join(Self::PS_STARTUP_FILE), - nu_env_file: temp_dir().join(Self::NU_ENV_FILE), - nu_config_file: temp_dir().join(Self::NU_CONFIG_FILE), + nu_env_file: root.join(Self::NU_ENV_FILE), + nu_config_file: root.join(Self::NU_CONFIG_FILE), runtime_dir: Some(root), tmpfs_size, mount_namespace: None, From 429edce99190d3126308a801b46dc8a383877bb5 Mon Sep 17 00:00:00 2001 From: Philippe Llerena Date: Fri, 9 Aug 2024 09:35:48 +0200 Subject: [PATCH 07/12] add nushell support start 0.97.0+ Signed-off-by: Philippe Llerena --- crates/spfs/src/bootstrap.rs | 44 ++++++++++++++++++- crates/spfs/src/graph/mod.rs | 10 +---- crates/spfs/src/runtime/config.nu | 4 ++ crates/spfs/src/runtime/config_nu.rs | 13 ++++++ crates/spfs/src/runtime/env.nu | 65 ++++++++++++++++++++++++++++ crates/spfs/src/runtime/env_nu.rs | 13 ++++++ crates/spfs/src/runtime/mod.rs | 19 ++------ crates/spfs/src/runtime/storage.rs | 19 +++++++- crates/spk-build/src/build/binary.rs | 11 ++++- crates/spk-schema/src/environ.rs | 34 +++++++++++++++ 10 files changed, 205 insertions(+), 27 deletions(-) create mode 100644 crates/spfs/src/runtime/config.nu create mode 100644 crates/spfs/src/runtime/config_nu.rs create mode 100644 crates/spfs/src/runtime/env.nu create mode 100644 crates/spfs/src/runtime/env_nu.rs diff --git a/crates/spfs/src/bootstrap.rs b/crates/spfs/src/bootstrap.rs index 5836fcc41c..fb74c20246 100644 --- a/crates/spfs/src/bootstrap.rs +++ b/crates/spfs/src/bootstrap.rs @@ -186,6 +186,16 @@ pub fn build_interactive_shell_command( ], vars: vec![shell_message], }), + Shell::Nushell(nu) => Ok(Command { + executable: nu.into(), + args: vec![ + "--env-config".into(), + rt.config.nu_env_file.as_os_str().to_owned(), + "--config".into(), + rt.config.nu_config_file.as_os_str().to_owned(), + ], + vars: vec![shell_message], + }), #[cfg(windows)] Shell::Powershell(ps1) => Ok(Command { executable: ps1.into(), @@ -221,6 +231,26 @@ where let startup_file = match shell.kind() { ShellKind::Bash => &runtime.config.sh_startup_file, ShellKind::Tcsh => &runtime.config.csh_startup_file, + ShellKind::Nushell => { + let mut cmd = command.into(); + for arg in args.into_iter().map(Into::into) { + cmd.push(" "); + cmd.push(arg); + } + let args = vec![ + "--env-config".into(), + runtime.config.nu_env_file.as_os_str().to_owned(), + "--config".into(), + runtime.config.nu_config_file.as_os_str().to_owned(), + "-c".into(), + cmd, + ]; + return Ok(Command { + executable: shell.executable().into(), + args, + vars: vec![], + }); + } ShellKind::Powershell => { let mut cmd = command.into(); for arg in args.into_iter().map(Into::into) { @@ -244,7 +274,6 @@ where let mut shell_args = vec![startup_file.into(), command.into()]; shell_args.extend(args.into_iter().map(Into::into)); - Ok(Command { executable: shell.executable().into(), args: shell_args, @@ -385,6 +414,7 @@ pub enum ShellKind { Bash, Tcsh, Powershell, + Nushell, } impl AsRef for ShellKind { @@ -392,6 +422,7 @@ impl AsRef for ShellKind { match self { Self::Bash => "bash", Self::Tcsh => "tcsh", + Self::Nushell => "nu", Self::Powershell => "powershell.exe", } } @@ -404,6 +435,7 @@ pub enum Shell { Bash(PathBuf), #[cfg(unix)] Tcsh(PathBuf), + Nushell(PathBuf), #[cfg(windows)] Powershell(PathBuf), } @@ -415,6 +447,7 @@ impl Shell { Self::Bash(_) => ShellKind::Bash, #[cfg(unix)] Self::Tcsh(_) => ShellKind::Tcsh, + Self::Nushell(_) => ShellKind::Nushell, #[cfg(windows)] Self::Powershell(_) => ShellKind::Powershell, } @@ -427,6 +460,7 @@ impl Shell { Self::Bash(p) => p, #[cfg(unix)] Self::Tcsh(p) => p, + Self::Nushell(p) => p, #[cfg(windows)] Self::Powershell(p) => p, } @@ -442,6 +476,7 @@ impl Shell { Some(n) if n == ShellKind::Bash.as_ref() => Ok(Self::Bash(path.to_owned())), #[cfg(unix)] Some(n) if n == ShellKind::Tcsh.as_ref() => Ok(Self::Tcsh(path.to_owned())), + Some(n) if n == ShellKind::Nushell.as_ref() => Ok(Self::Nushell(path.to_owned())), #[cfg(windows)] Some(n) if n == ShellKind::Powershell.as_ref() => Ok(Self::Powershell(path.to_owned())), Some(_) => Err(Error::new(format!("Unsupported shell: {path:?}"))), @@ -477,7 +512,12 @@ impl Shell { } } - for kind in &[ShellKind::Bash, ShellKind::Tcsh, ShellKind::Powershell] { + for kind in &[ + ShellKind::Bash, + ShellKind::Tcsh, + ShellKind::Powershell, + ShellKind::Nushell, + ] { if let Some(path) = which(kind) { if let Ok(shell) = Shell::from_path(path) { return Ok(shell); diff --git a/crates/spfs/src/graph/mod.rs b/crates/spfs/src/graph/mod.rs index 8a26800e69..e5c87ad0a4 100644 --- a/crates/spfs/src/graph/mod.rs +++ b/crates/spfs/src/graph/mod.rs @@ -20,17 +20,11 @@ mod tree; use std::cell::RefCell; pub use annotation::{ - Annotation, - AnnotationValue, - DEFAULT_SPFS_ANNOTATION_LAYER_MAX_STRING_VALUE_SIZE, + Annotation, AnnotationValue, DEFAULT_SPFS_ANNOTATION_LAYER_MAX_STRING_VALUE_SIZE, }; pub use blob::Blob; pub use database::{ - Database, - DatabaseIterator, - DatabaseView, - DatabaseWalker, - DigestSearchCriteria, + Database, DatabaseIterator, DatabaseView, DatabaseWalker, DigestSearchCriteria, }; pub use entry::Entry; pub use kind::{HasKind, Kind, ObjectKind}; diff --git a/crates/spfs/src/runtime/config.nu b/crates/spfs/src/runtime/config.nu new file mode 100644 index 0000000000..2bb7cea2cb --- /dev/null +++ b/crates/spfs/src/runtime/config.nu @@ -0,0 +1,4 @@ +$env.config = { + show_banner: false, +} +print $env.SPFS_SHELL_MESSAGE? \ No newline at end of file diff --git a/crates/spfs/src/runtime/config_nu.rs b/crates/spfs/src/runtime/config_nu.rs new file mode 100644 index 0000000000..072499801c --- /dev/null +++ b/crates/spfs/src/runtime/config_nu.rs @@ -0,0 +1,13 @@ +// Copyright (c) Contributors to the SPK project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/spkenv/spk +// Warning Nuhshell version >=0.96 + +use std::fs; + +pub fn source(_tmpdir: Option<&T>) -> String +where + T: AsRef, +{ + fs::read_to_string("/home/philippe.llerena/workspace/github.com/doubleailes/spk/crates/spfs/src/runtime/config.nu").unwrap() +} diff --git a/crates/spfs/src/runtime/env.nu b/crates/spfs/src/runtime/env.nu new file mode 100644 index 0000000000..1edbfde818 --- /dev/null +++ b/crates/spfs/src/runtime/env.nu @@ -0,0 +1,65 @@ +def create_left_prompt [] { + let dir = match (do --ignore-shell-errors { $env.PWD | path relative-to $nu.home-path }) { + null => $env.PWD + '' => '~' + $relative_pwd => ([~ $relative_pwd] | path join) + } + + let path_color = (if (is-admin) { ansi red_bold } else { ansi green_bold }) + let separator_color = (if (is-admin) { ansi light_red_bold } else { ansi light_green_bold }) + let path_segment = $"($path_color)($dir)(ansi reset)" + + $path_segment | str replace --all (char path_sep) $"($separator_color)(char path_sep)($path_color)" +} + +def create_right_prompt [] { + # create a right prompt in magenta with green separators and am/pm underlined + let time_segment = ([ + (ansi reset) + (ansi magenta) + (date now | format date '%x %X') # try to respect user's locale + ] | str join | str replace --regex --all "([/:])" $"(ansi green)${1}(ansi magenta)" | + str replace --regex --all "([AP]M)" $"(ansi magenta_underline)${1}") + + let last_exit_code = if ($env.LAST_EXIT_CODE != 0) {([ + (ansi rb) + ($env.LAST_EXIT_CODE) + ] | str join) + } else { "" } + + ([$last_exit_code, (char space), $time_segment] | str join) +} + +# Use nushell functions to define your right and left prompt +$env.PROMPT_COMMAND = {|| create_left_prompt } +# FIXME: This default is not implemented in rust code as of 2023-09-08. +$env.PROMPT_COMMAND_RIGHT = {|| create_right_prompt } + +# The prompt indicators are environmental variables that represent +# the state of the prompt +$env.PROMPT_INDICATOR = {|| "> " } +$env.PROMPT_INDICATOR_VI_INSERT = {|| ": " } +$env.PROMPT_INDICATOR_VI_NORMAL = {|| "> " } +$env.PROMPT_MULTILINE_INDICATOR = {|| "::: " } + + +$env.ENV_CONVERSIONS = { + "PATH": { + from_string: { |s| $s | split row (char esep) | path expand --no-symlink } + to_string: { |v| $v | path expand --no-symlink | str join (char esep) } + } + "Path": { + from_string: { |s| $s | split row (char esep) | path expand --no-symlink } + to_string: { |v| $v | path expand --no-symlink | str join (char esep) } + } +} + +let $spfs_startup_dir = if $nu.os-info.name == "windows" { + "C:/spfs/etc/spfs/startup.d" +} else if $nu.os-info.name == "linux" { + "/spfs/etc/spfs/startup.d" +} else { + exit 1 +} + +$env.NU_VENDOR_AUTOLOAD_DIR = ($spfs_startup_dir) \ No newline at end of file diff --git a/crates/spfs/src/runtime/env_nu.rs b/crates/spfs/src/runtime/env_nu.rs new file mode 100644 index 0000000000..12f2bc0dc5 --- /dev/null +++ b/crates/spfs/src/runtime/env_nu.rs @@ -0,0 +1,13 @@ +// Copyright (c) Contributors to the SPK project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/spkenv/spk +// Warning Nuhshell version >=0.96 + +use std::fs; + +pub fn source(_tmpdir: Option<&T>) -> String +where + T: AsRef, +{ + fs::read_to_string("/home/philippe.llerena/workspace/github.com/doubleailes/spk/crates/spfs/src/runtime/env.nu").unwrap() +} \ No newline at end of file diff --git a/crates/spfs/src/runtime/mod.rs b/crates/spfs/src/runtime/mod.rs index 0ee10a9bac..d06734ba11 100644 --- a/crates/spfs/src/runtime/mod.rs +++ b/crates/spfs/src/runtime/mod.rs @@ -4,6 +4,8 @@ //! Handles the setup and initialization of runtime environments +mod config_nu; +mod env_nu; #[cfg(unix)] pub mod overlayfs; #[cfg(unix)] @@ -19,21 +21,8 @@ pub mod winfsp; #[cfg(unix)] pub use overlayfs::is_removed_entry; pub use storage::{ - makedirs_with_perms, - Author, - BindMount, - Config, - Data, - KeyValuePair, - KeyValuePairBuf, - LiveLayer, - LiveLayerFile, - MountBackend, - OwnedRuntime, - Runtime, - Status, - Storage, - STARTUP_FILES_LOCATION, + makedirs_with_perms, Author, BindMount, Config, Data, KeyValuePair, KeyValuePairBuf, LiveLayer, + LiveLayerFile, MountBackend, OwnedRuntime, Runtime, Status, Storage, STARTUP_FILES_LOCATION, }; #[cfg(windows)] pub use winfsp::is_removed_entry; diff --git a/crates/spfs/src/runtime/storage.rs b/crates/spfs/src/runtime/storage.rs index 002fe1f038..56204864d9 100644 --- a/crates/spfs/src/runtime/storage.rs +++ b/crates/spfs/src/runtime/storage.rs @@ -27,7 +27,7 @@ use tokio::io::AsyncReadExt; #[cfg(windows)] use super::startup_ps; #[cfg(unix)] -use super::{startup_csh, startup_sh}; +use super::{config_nu, env_nu, startup_csh, startup_sh}; use crate::encoding::Digest; use crate::env::SPFS_DIR_PREFIX; use crate::graph::object::Enum; @@ -379,6 +379,9 @@ pub struct Config { pub sh_startup_file: PathBuf, /// The location of the startup script for csh-based shells pub csh_startup_file: PathBuf, + /// The location of the startup script for nushell-based shells + pub nu_env_file: PathBuf, + pub nu_config_file: PathBuf, /// The location of the expect utility script used for csh-based shell environments /// \[DEPRECATED\] This field still exists for spk/spfs interop but is unused #[serde(skip_deserializing, default = "Config::default_csh_expect_file")] @@ -420,6 +423,8 @@ impl Config { const SH_STARTUP_FILE: &'static str = "startup.sh"; const CSH_STARTUP_FILE: &'static str = ".cshrc"; const PS_STARTUP_FILE: &'static str = "startup.ps1"; + const NU_ENV_FILE: &'static str = "env.nu"; + const NU_CONFIG_FILE: &'static str = "config.nu"; const DEV_NULL: &'static str = "/dev/null"; /// Return a dummy value for the legacy csh_expect_file field. @@ -440,6 +445,8 @@ impl Config { csh_startup_file: root.join(Self::CSH_STARTUP_FILE), csh_expect_file: Self::default_csh_expect_file(), ps_startup_file: temp_dir().join(Self::PS_STARTUP_FILE), + nu_env_file: temp_dir().join(Self::NU_ENV_FILE), + nu_config_file: temp_dir().join(Self::NU_CONFIG_FILE), runtime_dir: Some(root), tmpfs_size, mount_namespace: None, @@ -1035,6 +1042,16 @@ impl Runtime { startup_csh::source(tmpdir_value_for_child_process), ) .map_err(|err| Error::RuntimeWriteError(self.config.csh_startup_file.clone(), err))?; + std::fs::write( + &self.config.nu_env_file, + env_nu::source(tmpdir_value_for_child_process), + ) + .map_err(|err| Error::RuntimeWriteError(self.config.nu_env_file.clone(), err))?; + std::fs::write( + &self.config.nu_config_file, + config_nu::source(tmpdir_value_for_child_process), + ) + .map_err(|err| Error::RuntimeWriteError(self.config.nu_config_file.clone(), err))?; #[cfg(windows)] std::fs::write( &self.config.ps_startup_file, diff --git a/crates/spk-build/src/build/binary.rs b/crates/spk-build/src/build/binary.rs index 2b1719cde1..8b043d42e5 100644 --- a/crates/spk-build/src/build/binary.rs +++ b/crates/spk-build/src/build/binary.rs @@ -688,23 +688,29 @@ where let mut startup_file_csh = startup_dir.join(format!("spk_{}.csh", package.name())); let mut startup_file_sh = startup_dir.join(format!("spk_{}.sh", package.name())); + let mut startup_file_nu = startup_dir.join(format!("spk_{}.nu", package.name())); let mut csh_file = std::fs::File::create(&startup_file_csh) .map_err(|err| Error::FileOpenError(startup_file_csh.to_owned(), err))?; let mut sh_file = std::fs::File::create(&startup_file_sh) .map_err(|err| Error::FileOpenError(startup_file_sh.to_owned(), err))?; - + let mut nu_file = std::fs::File::create(&startup_file_nu) + .map_err(|err| Error::FileOpenError(startup_file_nu.to_owned(), err))?; for op in ops { if let Some(priority) = op.priority() { let original_startup_file_sh_name = startup_file_sh.clone(); let original_startup_file_csh_name = startup_file_csh.clone(); + let original_startup_file_nu_name = startup_file_nu.clone(); startup_file_sh.set_file_name(format!("{priority:02}_spk_{}.sh", package.name())); startup_file_csh.set_file_name(format!("{priority:02}_spk_{}.csh", package.name())); + startup_file_nu.set_file_name(format!("{priority:02}_spk_{}.nu", package.name())); std::fs::rename(original_startup_file_sh_name, &startup_file_sh) .map_err(|err| Error::FileWriteError(startup_file_sh.to_owned(), err))?; std::fs::rename(original_startup_file_csh_name, &startup_file_csh) .map_err(|err| Error::FileWriteError(startup_file_csh.to_owned(), err))?; + std::fs::rename(original_startup_file_nu_name, &startup_file_nu) + .map_err(|err| Error::FileWriteError(startup_file_nu.to_owned(), err))?; continue; } @@ -715,6 +721,9 @@ where sh_file .write_fmt(format_args!("{}\n", op.bash_source())) .map_err(|err| Error::FileWriteError(startup_file_sh.to_owned(), err))?; + nu_file + .write_fmt(format_args!("{}\n", op.nushell_source())) + .map_err(|err| Error::FileWriteError(startup_file_nu.to_owned(), err))?; } Ok(()) } diff --git a/crates/spk-schema/src/environ.rs b/crates/spk-schema/src/environ.rs index 74515e25cd..67690e7d8d 100644 --- a/crates/spk-schema/src/environ.rs +++ b/crates/spk-schema/src/environ.rs @@ -63,6 +63,7 @@ impl EnvOp { spfs::ShellKind::Bash => self.bash_source(), spfs::ShellKind::Tcsh => self.tcsh_source(), spfs::ShellKind::Powershell => self.powershell_source(), + spfs::ShellKind::Nushell => self.nushell_source(), } } @@ -148,6 +149,17 @@ impl EnvOp { pub fn powershell_source(&self) -> String { todo!() } + + /// Construct the nushell source representation for this operation + pub fn nushell_source(&self) -> String { + match self { + Self::Append(op) => op.nu_source(), + Self::Comment(op) => op.nu_source(), + Self::Prepend(op) => op.nu_source(), + Self::Priority(op) => op.nu_source(), + Self::Set(op) => op.nu_source(), + } + } } impl<'de> Deserialize<'de> for EnvOp { @@ -358,6 +370,12 @@ impl AppendEnv { ] .join("\n") } + pub fn nu_source(&self) -> String { + format!( + "$env.{} = (\"{}\" | append $env.{}?)", + self.append, self.append, self.value + ) + } } /// Adds a comment to the generated environment script @@ -376,6 +394,10 @@ impl EnvComment { // Both bash and tcsh source use the same comment syntax self.bash_source() } + pub fn nu_source(&self) -> String { + // Nushell use the same comment syntax as bash + self.bash_source() + } } /// Assigns a priority to the generated environment script @@ -398,6 +420,9 @@ impl EnvPriority { pub fn priority(&self) -> u8 { self.priority } + pub fn nu_source(&self) -> String { + String::from("") + } } /// Operates on an environment variable by prepending to the beginning @@ -447,6 +472,12 @@ impl PrependEnv { ] .join("\n") } + pub fn nu_source(&self) -> String { + format!( + "$env.{} = ($env.{}? | prepend \"{}\")", + self.prepend, self.prepend, self.value + ) + } } /// Operates on an environment variable by setting it to a value @@ -465,4 +496,7 @@ impl SetEnv { pub fn tcsh_source(&self) -> String { format!("setenv {} \"{}\"", self.set, self.value) } + pub fn nu_source(&self) -> String { + format!("$env.{} = \"{}\"", self.set, self.value) + } } From e35e76401f6b947a602a378d3b150f95778f0c54 Mon Sep 17 00:00:00 2001 From: Philippe Llerena Date: Wed, 14 Aug 2024 15:36:54 +0200 Subject: [PATCH 08/12] fix: separate nu startup from unix shell to be ok with Windows Signed-off-by: Philippe Llerena --- crates/spfs/src/runtime/storage.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/spfs/src/runtime/storage.rs b/crates/spfs/src/runtime/storage.rs index 56204864d9..4ddeca576e 100644 --- a/crates/spfs/src/runtime/storage.rs +++ b/crates/spfs/src/runtime/storage.rs @@ -27,7 +27,8 @@ use tokio::io::AsyncReadExt; #[cfg(windows)] use super::startup_ps; #[cfg(unix)] -use super::{config_nu, env_nu, startup_csh, startup_sh}; +use super::{startup_csh, startup_sh}; +use super::{config_nu, env_nu}; use crate::encoding::Digest; use crate::env::SPFS_DIR_PREFIX; use crate::graph::object::Enum; From 1752a8e2800f621f5481bd4448f4604d3e2f2845 Mon Sep 17 00:00:00 2001 From: Philippe Llerena Date: Sat, 17 Aug 2024 13:58:50 +0200 Subject: [PATCH 09/12] Clean config Signed-off-by: Philippe Llerena --- crates/spfs/src/runtime/config.nu | 4 -- crates/spfs/src/runtime/config_nu.rs | 14 +++-- crates/spfs/src/runtime/env.nu | 65 ------------------------ crates/spfs/src/runtime/env_nu.rs | 76 ++++++++++++++++++++++++++-- 4 files changed, 81 insertions(+), 78 deletions(-) delete mode 100644 crates/spfs/src/runtime/config.nu delete mode 100644 crates/spfs/src/runtime/env.nu diff --git a/crates/spfs/src/runtime/config.nu b/crates/spfs/src/runtime/config.nu deleted file mode 100644 index 2bb7cea2cb..0000000000 --- a/crates/spfs/src/runtime/config.nu +++ /dev/null @@ -1,4 +0,0 @@ -$env.config = { - show_banner: false, -} -print $env.SPFS_SHELL_MESSAGE? \ No newline at end of file diff --git a/crates/spfs/src/runtime/config_nu.rs b/crates/spfs/src/runtime/config_nu.rs index 072499801c..c7ca1b2d1d 100644 --- a/crates/spfs/src/runtime/config_nu.rs +++ b/crates/spfs/src/runtime/config_nu.rs @@ -3,11 +3,17 @@ // https://github.com/spkenv/spk // Warning Nuhshell version >=0.96 -use std::fs; pub fn source(_tmpdir: Option<&T>) -> String where T: AsRef, -{ - fs::read_to_string("/home/philippe.llerena/workspace/github.com/doubleailes/spk/crates/spfs/src/runtime/config.nu").unwrap() -} + { + r#" + $env.config = { + show_banner: false, + } + $env.SPFS_SHELL_MESSAGE? | print + "# + .to_string() + } + diff --git a/crates/spfs/src/runtime/env.nu b/crates/spfs/src/runtime/env.nu deleted file mode 100644 index 1edbfde818..0000000000 --- a/crates/spfs/src/runtime/env.nu +++ /dev/null @@ -1,65 +0,0 @@ -def create_left_prompt [] { - let dir = match (do --ignore-shell-errors { $env.PWD | path relative-to $nu.home-path }) { - null => $env.PWD - '' => '~' - $relative_pwd => ([~ $relative_pwd] | path join) - } - - let path_color = (if (is-admin) { ansi red_bold } else { ansi green_bold }) - let separator_color = (if (is-admin) { ansi light_red_bold } else { ansi light_green_bold }) - let path_segment = $"($path_color)($dir)(ansi reset)" - - $path_segment | str replace --all (char path_sep) $"($separator_color)(char path_sep)($path_color)" -} - -def create_right_prompt [] { - # create a right prompt in magenta with green separators and am/pm underlined - let time_segment = ([ - (ansi reset) - (ansi magenta) - (date now | format date '%x %X') # try to respect user's locale - ] | str join | str replace --regex --all "([/:])" $"(ansi green)${1}(ansi magenta)" | - str replace --regex --all "([AP]M)" $"(ansi magenta_underline)${1}") - - let last_exit_code = if ($env.LAST_EXIT_CODE != 0) {([ - (ansi rb) - ($env.LAST_EXIT_CODE) - ] | str join) - } else { "" } - - ([$last_exit_code, (char space), $time_segment] | str join) -} - -# Use nushell functions to define your right and left prompt -$env.PROMPT_COMMAND = {|| create_left_prompt } -# FIXME: This default is not implemented in rust code as of 2023-09-08. -$env.PROMPT_COMMAND_RIGHT = {|| create_right_prompt } - -# The prompt indicators are environmental variables that represent -# the state of the prompt -$env.PROMPT_INDICATOR = {|| "> " } -$env.PROMPT_INDICATOR_VI_INSERT = {|| ": " } -$env.PROMPT_INDICATOR_VI_NORMAL = {|| "> " } -$env.PROMPT_MULTILINE_INDICATOR = {|| "::: " } - - -$env.ENV_CONVERSIONS = { - "PATH": { - from_string: { |s| $s | split row (char esep) | path expand --no-symlink } - to_string: { |v| $v | path expand --no-symlink | str join (char esep) } - } - "Path": { - from_string: { |s| $s | split row (char esep) | path expand --no-symlink } - to_string: { |v| $v | path expand --no-symlink | str join (char esep) } - } -} - -let $spfs_startup_dir = if $nu.os-info.name == "windows" { - "C:/spfs/etc/spfs/startup.d" -} else if $nu.os-info.name == "linux" { - "/spfs/etc/spfs/startup.d" -} else { - exit 1 -} - -$env.NU_VENDOR_AUTOLOAD_DIR = ($spfs_startup_dir) \ No newline at end of file diff --git a/crates/spfs/src/runtime/env_nu.rs b/crates/spfs/src/runtime/env_nu.rs index 12f2bc0dc5..0518915837 100644 --- a/crates/spfs/src/runtime/env_nu.rs +++ b/crates/spfs/src/runtime/env_nu.rs @@ -3,11 +3,77 @@ // https://github.com/spkenv/spk // Warning Nuhshell version >=0.96 -use std::fs; - pub fn source(_tmpdir: Option<&T>) -> String where T: AsRef, -{ - fs::read_to_string("/home/philippe.llerena/workspace/github.com/doubleailes/spk/crates/spfs/src/runtime/env.nu").unwrap() -} \ No newline at end of file + { + r#" + def create_left_prompt [] { + let dir = match (do --ignore-shell-errors { $env.PWD | path relative-to $nu.home-path }) { + null => $env.PWD + '' => '~' + $relative_pwd => ([~ $relative_pwd] | path join) + } + + let path_color = (if (is-admin) { ansi red_bold } else { ansi green_bold }) + let separator_color = (if (is-admin) { ansi light_red_bold } else { ansi light_green_bold }) + let path_segment = $"($path_color)($dir)(ansi reset)" + + $path_segment | str replace --all (char path_sep) $"($separator_color)(char path_sep)($path_color)" + } + + def create_right_prompt [] { + # create a right prompt in magenta with green separators and am/pm underlined + let time_segment = ([ + (ansi reset) + (ansi magenta) + (date now | format date '%x %X') # try to respect user's locale + ] | str join | str replace --regex --all "([/:])" $"(ansi green)${1}(ansi magenta)" | + str replace --regex --all "([AP]M)" $"(ansi magenta_underline)${1}") + + let last_exit_code = if ($env.LAST_EXIT_CODE != 0) {([ + (ansi rb) + ($env.LAST_EXIT_CODE) + ] | str join) + } else { "" } + + ([$last_exit_code, (char space), $time_segment] | str join) + } + + # Use nushell functions to define your right and left prompt + $env.PROMPT_COMMAND = {|| create_left_prompt } + # FIXME: This default is not implemented in rust code as of 2023-09-08. + $env.PROMPT_COMMAND_RIGHT = {|| create_right_prompt } + + # The prompt indicators are environmental variables that represent + # the state of the prompt + $env.PROMPT_INDICATOR = {|| "> " } + $env.PROMPT_INDICATOR_VI_INSERT = {|| ": " } + $env.PROMPT_INDICATOR_VI_NORMAL = {|| "> " } + $env.PROMPT_MULTILINE_INDICATOR = {|| "::: " } + + + $env.ENV_CONVERSIONS = { + "PATH": { + from_string: { |s| $s | split row (char esep) | path expand --no-symlink } + to_string: { |v| $v | path expand --no-symlink | str join (char esep) } + } + "Path": { + from_string: { |s| $s | split row (char esep) | path expand --no-symlink } + to_string: { |v| $v | path expand --no-symlink | str join (char esep) } + } + } + + let $spfs_startup_dir = if $nu.os-info.name == "windows" { + "C:/spfs/etc/spfs/startup.d" + } else if $nu.os-info.name == "linux" { + "/spfs/etc/spfs/startup.d" + } else { + exit 1 + } + + $env.NU_VENDOR_AUTOLOAD_DIR = ($spfs_startup_dir) + "# + .to_string() + } + \ No newline at end of file From 496d9751a9577d0895cfbcec1e4dee6a82260871 Mon Sep 17 00:00:00 2001 From: Philippe Llerena Date: Sat, 17 Aug 2024 16:43:55 +0200 Subject: [PATCH 10/12] Type fix and add Nushell, esep, AUTOLOAD to spellcheck Signed-off-by: Philippe Llerena --- crates/spfs/src/runtime/config_nu.rs | 2 +- crates/spfs/src/runtime/env_nu.rs | 2 +- cspell.json | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/spfs/src/runtime/config_nu.rs b/crates/spfs/src/runtime/config_nu.rs index c7ca1b2d1d..25ef526eb8 100644 --- a/crates/spfs/src/runtime/config_nu.rs +++ b/crates/spfs/src/runtime/config_nu.rs @@ -1,7 +1,7 @@ // Copyright (c) Contributors to the SPK project. // SPDX-License-Identifier: Apache-2.0 // https://github.com/spkenv/spk -// Warning Nuhshell version >=0.96 +// Warning Nushell version >=0.97 pub fn source(_tmpdir: Option<&T>) -> String diff --git a/crates/spfs/src/runtime/env_nu.rs b/crates/spfs/src/runtime/env_nu.rs index 0518915837..42b326384e 100644 --- a/crates/spfs/src/runtime/env_nu.rs +++ b/crates/spfs/src/runtime/env_nu.rs @@ -1,7 +1,7 @@ // Copyright (c) Contributors to the SPK project. // SPDX-License-Identifier: Apache-2.0 // https://github.com/spkenv/spk -// Warning Nuhshell version >=0.96 +// Warning Nushell version >=0.97 pub fn source(_tmpdir: Option<&T>) -> String where diff --git a/cspell.json b/cspell.json index 975da1b413..d2e789e392 100644 --- a/cspell.json +++ b/cspell.json @@ -30,6 +30,7 @@ "ASWF", "atexit", "autogen", + "AUTOLOAD", "automounter", "autopoint", "autoreconf", @@ -201,6 +202,7 @@ "errexit", "Errno", "esac", + "esep", "ESRCH", "euid", "evenmoredata", @@ -449,6 +451,8 @@ "NQCYJ", "NTSTATUS", "numpy", + "nushell", + "Nushell", "nvcc", "NVPTX", "NZFA", From 1ddc869a9cfdef1d31673a725a9d9430edae0007 Mon Sep 17 00:00:00 2001 From: Philippe Llerena Date: Sat, 17 Aug 2024 22:46:13 +0200 Subject: [PATCH 11/12] reorg auto-completion and add nushell completion Signed-off-by: Philippe Llerena --- Cargo.lock | 15 ++++- Cargo.toml | 2 +- crates/spk-cli/group1/Cargo.toml | 1 + crates/spk-cli/group1/src/cmd_completion.rs | 63 ++++++++++++++++++--- 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10e357aad6..e164431b7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -587,13 +587,23 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.3" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ae8ba90b9d8b007efe66e55e48fb936272f5ca00349b5b0e89877520d35ea7" +checksum = "b5a2d6eec27fce550d708b2be5d798797e5a55b246b323ef36924a0001996352" dependencies = [ "clap 4.5.0", ] +[[package]] +name = "clap_complete_nushell" +version = "4.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fe32110e006bccf720f8c9af3fee1ba7db290c724eab61544e1d3295be3a40e" +dependencies = [ + "clap 4.5.0", + "clap_complete", +] + [[package]] name = "clap_derive" version = "4.5.0" @@ -3985,6 +3995,7 @@ dependencies = [ "async-trait", "clap 4.5.0", "clap_complete", + "clap_complete_nushell", "colored", "futures", "itertools 0.12.0", diff --git a/Cargo.toml b/Cargo.toml index 9106164c72..2b64dffaab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ bytes = "1.5" cached = "0.48.1" chrono = { version = "0.4.34", features = ["serde"] } clap = { version = "4.5", features = ["derive", "env"] } -clap_complete = "4.3" +clap_complete = "4.5" colored = "2.0.0" config = "0.14.0" console = "0.15.8" diff --git a/crates/spk-cli/group1/Cargo.toml b/crates/spk-cli/group1/Cargo.toml index 822834a9fb..57efdb0941 100644 --- a/crates/spk-cli/group1/Cargo.toml +++ b/crates/spk-cli/group1/Cargo.toml @@ -34,6 +34,7 @@ spk-storage = { workspace = true } strip-ansi-escapes = { version = "0.1.1" } tokio = { workspace = true, features = ["rt"] } tracing = { workspace = true } +clap_complete_nushell ={ version = "4.5"} [dev-dependencies] rstest = { workspace = true } diff --git a/crates/spk-cli/group1/src/cmd_completion.rs b/crates/spk-cli/group1/src/cmd_completion.rs index 84caf2751d..4ea58fda85 100644 --- a/crates/spk-cli/group1/src/cmd_completion.rs +++ b/crates/spk-cli/group1/src/cmd_completion.rs @@ -8,25 +8,70 @@ use std::io::Write; use clap::{value_parser, Command, Parser}; use clap_complete; -use clap_complete::Shell; +use clap_complete::{Generator, Shell}; +use clap_complete_nushell::Nushell; +use clap::ValueEnum; use miette::Result; use spk_cli_common::CommandArgs; +#[derive(Clone, Debug, ValueEnum)] +enum ShellCompletion { + /// Bourne Again SHell (bash) + Bash, + /// Friendly Interactive SHell (fish) + Fish, + /// PowerShell + Zsh, + /// Nushell + Nushell, +} +impl ToString for ShellCompletion { + fn to_string(&self) -> String { + match self { + ShellCompletion::Bash => "bash".to_string(), + ShellCompletion::Fish => "fish".to_string(), + ShellCompletion::Zsh => "zsh".to_string(), + ShellCompletion::Nushell => "nu".to_string(), + } + } +} + +impl Generator for ShellCompletion { + /// Generate the file name for the completion script. + fn file_name(&self, name: &str) -> String { + match self { + ShellCompletion::Bash => Shell::Bash.file_name(name), + ShellCompletion::Fish => Shell::Fish.file_name(name), + ShellCompletion::Zsh => Shell::Zsh.file_name(name), + ShellCompletion::Nushell => Nushell.file_name(name), + } + } + + /// Generate the completion script for the shell. + fn generate(&self, cmd: &clap::Command, buf: &mut dyn std::io::Write) { + match self { + ShellCompletion::Bash => Shell::Bash.generate(cmd, buf), + ShellCompletion::Fish => Shell::Fish.generate(cmd, buf), + ShellCompletion::Zsh => Shell::Zsh.generate(cmd, buf), + ShellCompletion::Nushell => Nushell.generate(cmd, buf), + } + } +} + /// Generate shell completions for "spk" #[derive(Parser, Clone, Debug)] #[command(author, about, long_about)] pub struct Completion { /// Shell syntax to emit - #[arg(default_value_t = Shell::Bash, value_parser = value_parser!(Shell))] - pub shell: Shell, + #[arg(default_value_t = ShellCompletion::Bash, value_parser = value_parser!(ShellCompletion))] + shell: ShellCompletion, } impl Completion { pub fn run(&self, mut cmd: Command) -> Result { let mut buf = vec![]; - clap_complete::generate(self.shell, &mut cmd, "spk", &mut buf); + clap_complete::generate(self.shell.clone(), &mut cmd, "spk", &mut buf); std::io::stdout().write_all(&buf).unwrap_or(()); - Ok(0) } } @@ -34,10 +79,10 @@ impl Completion { impl CommandArgs for Completion { fn get_positional_args(&self) -> Vec { let args: Vec = vec![match self.shell { - Shell::Bash => "bash".to_string(), - Shell::Fish => "fish".to_string(), - Shell::Zsh => "zsh".to_string(), - _ => todo!(), // Shell is non-exhaustive. + ShellCompletion::Bash => "bash".to_string(), + ShellCompletion::Fish => "fish".to_string(), + ShellCompletion::Zsh => "zsh".to_string(), + ShellCompletion::Nushell => "nu".to_string(), }]; args From 856cfba0e681b33e7825a44fad7eb140a0a2e537 Mon Sep 17 00:00:00 2001 From: Philippe Llerena Date: Mon, 9 Sep 2024 10:44:51 +0200 Subject: [PATCH 12/12] quality: fmt --- crates/spfs/src/graph/mod.rs | 10 ++++++++-- crates/spfs/src/runtime/mod.rs | 17 ++++++++++++++-- crates/spfs/src/runtime/storage.rs | 2 +- crates/spk-cli/group1/src/cmd_completion.rs | 22 ++++++++++----------- 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/crates/spfs/src/graph/mod.rs b/crates/spfs/src/graph/mod.rs index e5c87ad0a4..8a26800e69 100644 --- a/crates/spfs/src/graph/mod.rs +++ b/crates/spfs/src/graph/mod.rs @@ -20,11 +20,17 @@ mod tree; use std::cell::RefCell; pub use annotation::{ - Annotation, AnnotationValue, DEFAULT_SPFS_ANNOTATION_LAYER_MAX_STRING_VALUE_SIZE, + Annotation, + AnnotationValue, + DEFAULT_SPFS_ANNOTATION_LAYER_MAX_STRING_VALUE_SIZE, }; pub use blob::Blob; pub use database::{ - Database, DatabaseIterator, DatabaseView, DatabaseWalker, DigestSearchCriteria, + Database, + DatabaseIterator, + DatabaseView, + DatabaseWalker, + DigestSearchCriteria, }; pub use entry::Entry; pub use kind::{HasKind, Kind, ObjectKind}; diff --git a/crates/spfs/src/runtime/mod.rs b/crates/spfs/src/runtime/mod.rs index d06734ba11..d15c649ef2 100644 --- a/crates/spfs/src/runtime/mod.rs +++ b/crates/spfs/src/runtime/mod.rs @@ -21,8 +21,21 @@ pub mod winfsp; #[cfg(unix)] pub use overlayfs::is_removed_entry; pub use storage::{ - makedirs_with_perms, Author, BindMount, Config, Data, KeyValuePair, KeyValuePairBuf, LiveLayer, - LiveLayerFile, MountBackend, OwnedRuntime, Runtime, Status, Storage, STARTUP_FILES_LOCATION, + makedirs_with_perms, + Author, + BindMount, + Config, + Data, + KeyValuePair, + KeyValuePairBuf, + LiveLayer, + LiveLayerFile, + MountBackend, + OwnedRuntime, + Runtime, + Status, + Storage, + STARTUP_FILES_LOCATION, }; #[cfg(windows)] pub use winfsp::is_removed_entry; diff --git a/crates/spfs/src/runtime/storage.rs b/crates/spfs/src/runtime/storage.rs index 072e5f47e6..163ce87b7b 100644 --- a/crates/spfs/src/runtime/storage.rs +++ b/crates/spfs/src/runtime/storage.rs @@ -26,9 +26,9 @@ use tokio::io::AsyncReadExt; #[cfg(windows)] use super::startup_ps; +use super::{config_nu, env_nu}; #[cfg(unix)] use super::{startup_csh, startup_sh}; -use super::{config_nu, env_nu}; use crate::encoding::Digest; use crate::env::SPFS_DIR_PREFIX; use crate::graph::object::Enum; diff --git a/crates/spk-cli/group1/src/cmd_completion.rs b/crates/spk-cli/group1/src/cmd_completion.rs index 4ea58fda85..ef8b51828c 100644 --- a/crates/spk-cli/group1/src/cmd_completion.rs +++ b/crates/spk-cli/group1/src/cmd_completion.rs @@ -4,13 +4,13 @@ //! Generate shell completions for "spk" +use std::fmt; use std::io::Write; -use clap::{value_parser, Command, Parser}; +use clap::{value_parser, Command, Parser, ValueEnum}; use clap_complete; use clap_complete::{Generator, Shell}; use clap_complete_nushell::Nushell; -use clap::ValueEnum; use miette::Result; use spk_cli_common::CommandArgs; @@ -25,17 +25,17 @@ enum ShellCompletion { /// Nushell Nushell, } -impl ToString for ShellCompletion { - fn to_string(&self) -> String { - match self { - ShellCompletion::Bash => "bash".to_string(), - ShellCompletion::Fish => "fish".to_string(), - ShellCompletion::Zsh => "zsh".to_string(), - ShellCompletion::Nushell => "nu".to_string(), - } +impl fmt::Display for ShellCompletion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + ShellCompletion::Bash => "bash", + ShellCompletion::Fish => "fish", + ShellCompletion::Zsh => "zsh", + ShellCompletion::Nushell => "nu", + }; + write!(f, "{}", s) } } - impl Generator for ShellCompletion { /// Generate the file name for the completion script. fn file_name(&self, name: &str) -> String {