From 4975a4eb2007bbe2f89e93f959892b8afa539d6a Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Fri, 13 Sep 2024 22:39:10 -0700 Subject: [PATCH 1/3] start implementation for which and uname --- Cargo.lock | 63 +++++++++++++++++++ crates/shell/Cargo.toml | 2 + .../src/{commands.rs => commands/mod.rs} | 7 +++ crates/shell/src/commands/uname.rs | 50 +++++++++++++++ crates/shell/src/commands/which.rs | 30 +++++++++ crates/shell/src/main.rs | 8 +++ 6 files changed, 160 insertions(+) rename crates/shell/src/{commands.rs => commands/mod.rs} (97%) create mode 100644 crates/shell/src/commands/uname.rs create mode 100644 crates/shell/src/commands/which.rs diff --git a/Cargo.lock b/Cargo.lock index 84f3629..1404326 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -913,6 +913,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "platform-info" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5ff316b9c4642feda973c18f0decd6c8b0919d4722566f6e4337cce0dd88217" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "pretty_assertions" version = "1.4.0" @@ -1091,6 +1101,8 @@ dependencies = [ "rustyline", "tokio", "uu_ls", + "uu_uname", + "which", ] [[package]] @@ -1322,6 +1334,17 @@ dependencies = [ "uutils_term_grid", ] +[[package]] +name = "uu_uname" +version = "0.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1ca90f9b292bccaad0de70e6feccac5182c6713a5e1ca72d97bf3555b608b4" +dependencies = [ + "clap", + "platform-info", + "uucore", +] + [[package]] name = "uucore" version = "0.0.27" @@ -1437,6 +1460,18 @@ version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +[[package]] +name = "which" +version = "6.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" +dependencies = [ + "either", + "home", + "rustix", + "winsafe", +] + [[package]] name = "wild" version = "2.2.1" @@ -1446,6 +1481,22 @@ dependencies = [ "glob", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.9" @@ -1455,6 +1506,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows" version = "0.52.0" @@ -1622,6 +1679,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "xattr" version = "1.3.1" diff --git a/crates/shell/Cargo.toml b/crates/shell/Cargo.toml index a48bbe5..61413a7 100644 --- a/crates/shell/Cargo.toml +++ b/crates/shell/Cargo.toml @@ -27,6 +27,8 @@ rustyline = { version = "14.0.0", features = ["derive"] } tokio = "1.40.0" uu_ls = "0.0.27" dirs = "5.0.1" +which = "6.0.3" +uu_uname = "0.0.27" [package.metadata.release] # Dont publish the binary diff --git a/crates/shell/src/commands.rs b/crates/shell/src/commands/mod.rs similarity index 97% rename from crates/shell/src/commands.rs rename to crates/shell/src/commands/mod.rs index 5304be2..5918a6e 100644 --- a/crates/shell/src/commands.rs +++ b/crates/shell/src/commands/mod.rs @@ -6,6 +6,13 @@ use futures::{future::LocalBoxFuture, FutureExt}; use uu_ls::uumain as uu_ls; use crate::execute; + +pub mod uname; +pub mod which; + +pub use uname::UnameCommand; +pub use which::WhichCommand; + pub struct LsCommand; pub struct AliasCommand; diff --git a/crates/shell/src/commands/uname.rs b/crates/shell/src/commands/uname.rs new file mode 100644 index 0000000..9a7923f --- /dev/null +++ b/crates/shell/src/commands/uname.rs @@ -0,0 +1,50 @@ +use deno_task_shell::{ExecuteResult, ShellCommand, ShellCommandContext}; +use futures::future::LocalBoxFuture; +use uu_uname::{options, UNameOutput}; +pub struct UnameCommand; + +fn display(uname: &UNameOutput) -> String { + let mut output = String::new(); + for name in [ + uname.kernel_name.as_ref(), + uname.nodename.as_ref(), + uname.kernel_release.as_ref(), + uname.kernel_version.as_ref(), + uname.machine.as_ref(), + uname.os.as_ref(), + uname.processor.as_ref(), + uname.hardware_platform.as_ref(), + ] + .into_iter() + .flatten() + { + output.push_str(name); + output.push(' '); + } + output +} + +impl ShellCommand for UnameCommand { + fn execute(&self, mut context: ShellCommandContext) -> LocalBoxFuture<'static, ExecuteResult> { + let matches = uu_uname::uu_app() + .no_binary_name(true) + .try_get_matches_from(context.args).unwrap(); + + let options = uu_uname::Options { + all: matches.get_flag(options::ALL), + kernel_name: matches.get_flag(options::KERNEL_NAME), + nodename: matches.get_flag(options::NODENAME), + kernel_release: matches.get_flag(options::KERNEL_RELEASE), + kernel_version: matches.get_flag(options::KERNEL_VERSION), + machine: matches.get_flag(options::MACHINE), + processor: matches.get_flag(options::PROCESSOR), + hardware_platform: matches.get_flag(options::HARDWARE_PLATFORM), + os: matches.get_flag(options::OS), + }; + + let uname = UNameOutput::new(&options).unwrap(); + context.stdout.write_line(&format!("{}", display(&uname).trim_end())); + + return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(0))); + } +} \ No newline at end of file diff --git a/crates/shell/src/commands/which.rs b/crates/shell/src/commands/which.rs new file mode 100644 index 0000000..c2beeac --- /dev/null +++ b/crates/shell/src/commands/which.rs @@ -0,0 +1,30 @@ +use std::os::macos::raw::stat; + +use deno_task_shell::{ExecuteResult, ShellCommand, ShellCommandContext}; +use futures::future::LocalBoxFuture; + +pub struct WhichCommand; + +impl ShellCommand for WhichCommand { + fn execute(&self, mut context: ShellCommandContext) -> LocalBoxFuture<'static, ExecuteResult> { + if context.args.len() != 1 { + context.stderr.write_line("Expected one argument.").unwrap(); + } + let arg = &context.args[0]; + + if let Some(alias) = context.state.alias_map().get(arg) { + context.stdout.write_line(&format!("alias: \"{}\"", alias.join(" "))).unwrap(); + return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(0))); + } + + if let Some(function) = context.state.resolve_custom_command(&arg) { + context.stdout.write_line("").unwrap(); + return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(0))); + } + + if let Ok(p) = which::which(arg) { + context.stdout.write_line(&p.to_string_lossy()).unwrap(); + } + return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(0))); + } +} diff --git a/crates/shell/src/main.rs b/crates/shell/src/main.rs index 8bcebbf..6b5af5f 100644 --- a/crates/shell/src/main.rs +++ b/crates/shell/src/main.rs @@ -34,6 +34,14 @@ fn commands() -> HashMap> { "source".to_string(), Rc::new(commands::SourceCommand) as Rc, ), + ( + "which".to_string(), + Rc::new(commands::WhichCommand) as Rc, + ), + ( + "uname".to_string(), + Rc::new(commands::UnameCommand) as Rc, + ), ]) } From 431368a4e2d0810890129542ba318b49e4480389 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Fri, 13 Sep 2024 22:41:46 -0700 Subject: [PATCH 2/3] fix --- crates/shell/src/commands/uname.rs | 12 ++++++++---- crates/shell/src/commands/which.rs | 12 +++++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/crates/shell/src/commands/uname.rs b/crates/shell/src/commands/uname.rs index 9a7923f..0d956ba 100644 --- a/crates/shell/src/commands/uname.rs +++ b/crates/shell/src/commands/uname.rs @@ -28,7 +28,8 @@ impl ShellCommand for UnameCommand { fn execute(&self, mut context: ShellCommandContext) -> LocalBoxFuture<'static, ExecuteResult> { let matches = uu_uname::uu_app() .no_binary_name(true) - .try_get_matches_from(context.args).unwrap(); + .try_get_matches_from(context.args) + .unwrap(); let options = uu_uname::Options { all: matches.get_flag(options::ALL), @@ -43,8 +44,11 @@ impl ShellCommand for UnameCommand { }; let uname = UNameOutput::new(&options).unwrap(); - context.stdout.write_line(&format!("{}", display(&uname).trim_end())); + context + .stdout + .write_line(display(&uname).trim_end()) + .unwrap(); - return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(0))); + Box::pin(futures::future::ready(ExecuteResult::from_exit_code(0))) } -} \ No newline at end of file +} diff --git a/crates/shell/src/commands/which.rs b/crates/shell/src/commands/which.rs index c2beeac..450c268 100644 --- a/crates/shell/src/commands/which.rs +++ b/crates/shell/src/commands/which.rs @@ -1,5 +1,3 @@ -use std::os::macos::raw::stat; - use deno_task_shell::{ExecuteResult, ShellCommand, ShellCommandContext}; use futures::future::LocalBoxFuture; @@ -13,11 +11,14 @@ impl ShellCommand for WhichCommand { let arg = &context.args[0]; if let Some(alias) = context.state.alias_map().get(arg) { - context.stdout.write_line(&format!("alias: \"{}\"", alias.join(" "))).unwrap(); + context + .stdout + .write_line(&format!("alias: \"{}\"", alias.join(" "))) + .unwrap(); return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(0))); } - if let Some(function) = context.state.resolve_custom_command(&arg) { + if context.state.resolve_custom_command(arg).is_some() { context.stdout.write_line("").unwrap(); return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(0))); } @@ -25,6 +26,7 @@ impl ShellCommand for WhichCommand { if let Ok(p) = which::which(arg) { context.stdout.write_line(&p.to_string_lossy()).unwrap(); } - return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(0))); + + Box::pin(futures::future::ready(ExecuteResult::from_exit_code(0))) } } From 94cb14d35137af1190065fbe911d3e5b773652d0 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Sat, 14 Sep 2024 07:06:36 -0700 Subject: [PATCH 3/3] improve which implementation --- crates/shell/src/commands/which.rs | 56 +++++++++++++++++++----------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/crates/shell/src/commands/which.rs b/crates/shell/src/commands/which.rs index 450c268..ac796ad 100644 --- a/crates/shell/src/commands/which.rs +++ b/crates/shell/src/commands/which.rs @@ -4,29 +4,45 @@ use futures::future::LocalBoxFuture; pub struct WhichCommand; impl ShellCommand for WhichCommand { - fn execute(&self, mut context: ShellCommandContext) -> LocalBoxFuture<'static, ExecuteResult> { - if context.args.len() != 1 { - context.stderr.write_line("Expected one argument.").unwrap(); - } - let arg = &context.args[0]; - - if let Some(alias) = context.state.alias_map().get(arg) { - context - .stdout - .write_line(&format!("alias: \"{}\"", alias.join(" "))) - .unwrap(); - return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(0))); - } + fn execute(&self, context: ShellCommandContext) -> LocalBoxFuture<'static, ExecuteResult> { + Box::pin(futures::future::ready(execute_which(context))) + } +} - if context.state.resolve_custom_command(arg).is_some() { - context.stdout.write_line("").unwrap(); - return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(0))); - } +fn execute_which(mut context: ShellCommandContext) -> ExecuteResult { + if context.args.len() != 1 { + context.stderr.write_line("Expected one argument.").unwrap(); + return ExecuteResult::from_exit_code(1); + } + let arg = &context.args[0]; - if let Ok(p) = which::which(arg) { + if let Some(alias) = context.state.alias_map().get(arg) { + context + .stdout + .write_line(&format!("alias: \"{}\"", alias.join(" "))) + .unwrap(); + return ExecuteResult::from_exit_code(0); + } + + if context.state.resolve_custom_command(arg).is_some() { + context.stdout.write_line("").unwrap(); + return ExecuteResult::from_exit_code(0); + } + + if let Some(path) = context.state.env_vars().get("PATH") { + let path = std::ffi::OsString::from(path); + let which_result = which::which_in_global(arg, Some(path)) + .and_then(|mut i| i.next().ok_or(which::Error::CannotFindBinaryPath)); + + if let Ok(p) = which_result { context.stdout.write_line(&p.to_string_lossy()).unwrap(); + return ExecuteResult::from_exit_code(0); } - - Box::pin(futures::future::ready(ExecuteResult::from_exit_code(0))) } + + context + .stderr + .write_line(&format!("{} not found", arg)) + .unwrap(); + ExecuteResult::from_exit_code(1) }