diff --git a/crates/nu-command/Cargo.toml b/crates/nu-command/Cargo.toml index 2a9749c7fd..b47f9c8fe5 100644 --- a/crates/nu-command/Cargo.toml +++ b/crates/nu-command/Cargo.toml @@ -2,6 +2,8 @@ name = "nu-command" version = "0.1.0" edition = "2018" +build = "build.rs" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -56,12 +58,12 @@ zip = { version="0.5.9", optional=true } lazy_static = "1.4.0" strip-ansi-escapes = "0.1.1" crossterm = "0.22.1" +shadow-rs = "0.8.1" quick-xml = "0.22" digest = "0.10.0" md5 = { package = "md-5", version = "0.10.0" } sha2 = "0.10.0" base64 = "0.13.0" - num = { version = "0.4.0", optional = true } [dependencies.polars] @@ -73,3 +75,6 @@ features = ["default", "parquet", "json", "serde", "object", "checked_arithmetic trash-support = ["trash"] plugin = ["nu-parser/plugin"] dataframe = ["polars", "num"] + +[build-dependencies] +shadow-rs = "0.8.1" \ No newline at end of file diff --git a/crates/nu-command/build.rs b/crates/nu-command/build.rs new file mode 100644 index 0000000000..4a0dfc4591 --- /dev/null +++ b/crates/nu-command/build.rs @@ -0,0 +1,3 @@ +fn main() -> shadow_rs::SdResult<()> { + shadow_rs::new() +} diff --git a/crates/nu-command/src/core_commands/mod.rs b/crates/nu-command/src/core_commands/mod.rs index 28f1700024..3c90680226 100644 --- a/crates/nu-command/src/core_commands/mod.rs +++ b/crates/nu-command/src/core_commands/mod.rs @@ -15,6 +15,7 @@ mod let_; mod module; mod source; mod use_; +mod version; pub use alias::Alias; pub use debug::Debug; @@ -33,7 +34,7 @@ pub use let_::Let; pub use module::Module; pub use source::Source; pub use use_::Use; - +pub use version::Version; #[cfg(feature = "plugin")] mod register; diff --git a/crates/nu-command/src/core_commands/version.rs b/crates/nu-command/src/core_commands/version.rs new file mode 100644 index 0000000000..dd4d98bb6a --- /dev/null +++ b/crates/nu-command/src/core_commands/version.rs @@ -0,0 +1,369 @@ +use indexmap::IndexMap; +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::{Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Value}; + +pub mod shadow { + include!(concat!(env!("OUT_DIR"), "/shadow.rs")); +} + +#[derive(Clone)] +pub struct Version; + +impl Command for Version { + fn name(&self) -> &str { + "version" + } + + fn signature(&self) -> Signature { + Signature::build("version") + } + + fn usage(&self) -> &str { + "Display Nu version." + } + + fn run( + &self, + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + version(engine_state, stack, call, input) + } + + fn examples(&self) -> Vec { + vec![Example { + description: "Display Nu version", + example: "version", + result: None, + }] + } +} + +pub fn version( + engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + _input: PipelineData, +) -> Result { + let tag = call.head; + + let mut indexmap = IndexMap::with_capacity(4); + + indexmap.insert( + "version".to_string(), + Value::String { + val: env!("CARGO_PKG_VERSION").to_string(), + span: tag, + }, + ); + + let branch: Option<&str> = Some(shadow::BRANCH).filter(|x| !x.is_empty()); + if let Some(branch) = branch { + indexmap.insert( + "branch".to_string(), + Value::String { + val: branch.to_string(), + span: Span::unknown(), + }, + ); + } + + let short_commit: Option<&str> = Some(shadow::SHORT_COMMIT).filter(|x| !x.is_empty()); + if let Some(short_commit) = short_commit { + indexmap.insert( + "short_commit".to_string(), + Value::String { + val: short_commit.to_string(), + span: Span::unknown(), + }, + ); + } + let commit_hash: Option<&str> = Some(shadow::COMMIT_HASH).filter(|x| !x.is_empty()); + if let Some(commit_hash) = commit_hash { + indexmap.insert( + "commit_hash".to_string(), + Value::String { + val: commit_hash.to_string(), + span: Span::unknown(), + }, + ); + } + let commit_date: Option<&str> = Some(shadow::COMMIT_DATE).filter(|x| !x.is_empty()); + if let Some(commit_date) = commit_date { + indexmap.insert( + "commit_date".to_string(), + Value::String { + val: commit_date.to_string(), + span: Span::unknown(), + }, + ); + } + + let build_os: Option<&str> = Some(shadow::BUILD_OS).filter(|x| !x.is_empty()); + if let Some(build_os) = build_os { + indexmap.insert( + "build_os".to_string(), + Value::String { + val: build_os.to_string(), + span: Span::unknown(), + }, + ); + } + + let rust_version: Option<&str> = Some(shadow::RUST_VERSION).filter(|x| !x.is_empty()); + if let Some(rust_version) = rust_version { + indexmap.insert( + "rust_version".to_string(), + Value::String { + val: rust_version.to_string(), + span: Span::unknown(), + }, + ); + } + + let rust_channel: Option<&str> = Some(shadow::RUST_CHANNEL).filter(|x| !x.is_empty()); + if let Some(rust_channel) = rust_channel { + indexmap.insert( + "rust_channel".to_string(), + Value::String { + val: rust_channel.to_string(), + span: Span::unknown(), + }, + ); + } + + let cargo_version: Option<&str> = Some(shadow::CARGO_VERSION).filter(|x| !x.is_empty()); + if let Some(cargo_version) = cargo_version { + indexmap.insert( + "cargo_version".to_string(), + Value::String { + val: cargo_version.to_string(), + span: Span::unknown(), + }, + ); + } + + let pkg_version: Option<&str> = Some(shadow::PKG_VERSION).filter(|x| !x.is_empty()); + if let Some(pkg_version) = pkg_version { + indexmap.insert( + "pkg_version".to_string(), + Value::String { + val: pkg_version.to_string(), + span: Span::unknown(), + }, + ); + } + + let build_time: Option<&str> = Some(shadow::BUILD_TIME).filter(|x| !x.is_empty()); + if let Some(build_time) = build_time { + indexmap.insert( + "build_time".to_string(), + Value::String { + val: build_time.to_string(), + span: Span::unknown(), + }, + ); + } + + let build_rust_channel: Option<&str> = + Some(shadow::BUILD_RUST_CHANNEL).filter(|x| !x.is_empty()); + if let Some(build_rust_channel) = build_rust_channel { + indexmap.insert( + "build_rust_channel".to_string(), + Value::String { + val: build_rust_channel.to_string(), + span: Span::unknown(), + }, + ); + } + + indexmap.insert( + "features".to_string(), + Value::String { + val: features_enabled().join(", "), + span: Span::unknown(), + }, + ); + + // Manually create a list of all possible plugin names + // Don't think we need this anymore. Leaving it here, just in case we do actually need it. + // let all_plugins = vec![ + // "fetch", + // "inc", + // "match", + // "post", + // "ps", + // "sys", + // "textview", + // "binaryview", + // "chart bar", + // "chart line", + // "from bson", + // "from sqlite", + // "query json", + // "s3", + // "selector", + // "start", + // "to bson", + // "to sqlite", + // "tree", + // "xpath", + // ]; + + // Get a list of command names and check for plugins + let installed_plugins = engine_state + .plugin_decls() + .into_iter() + .filter(|x| x.is_plugin().is_some()) + .map(|x| x.name()) + .collect::>(); + + indexmap.insert( + "installed_plugins".to_string(), + Value::String { + val: installed_plugins.join(", "), + span: Span::unknown(), + }, + ); + + let cols = indexmap.keys().cloned().collect::>(); + let vals = indexmap.values().cloned().collect::>(); + + Ok(Value::List { + vals: vec![Value::Record { + cols, + vals, + span: Span::unknown(), + }], + span: Span::unknown(), + } + .into_pipeline_data()) +} + +fn features_enabled() -> Vec { + let mut names = vec!["default".to_string()]; + + // NOTE: There should be another way to know + // features on. + #[cfg(feature = "ctrlc")] + { + names.push("ctrlc".to_string()); + } + + // #[cfg(feature = "rich-benchmark")] + // { + // names.push("rich-benchmark".to_string()); + // } + + #[cfg(feature = "rustyline-support")] + { + names.push("rustyline".to_string()); + } + + #[cfg(feature = "term")] + { + names.push("term".to_string()); + } + + #[cfg(feature = "uuid_crate")] + { + names.push("uuid".to_string()); + } + + #[cfg(feature = "which")] + { + names.push("which".to_string()); + } + + #[cfg(feature = "zip")] + { + names.push("zip".to_string()); + } + + #[cfg(feature = "clipboard-cli")] + { + names.push("clipboard-cli".to_string()); + } + + #[cfg(feature = "trash-support")] + { + names.push("trash".to_string()); + } + + #[cfg(feature = "dataframe")] + { + names.push("dataframe".to_string()); + } + + #[cfg(feature = "table-pager")] + { + names.push("table-pager".to_string()); + } + + // #[cfg(feature = "binaryview")] + // { + // names.push("binaryview".to_string()); + // } + + // #[cfg(feature = "start")] + // { + // names.push("start".to_string()); + // } + + // #[cfg(feature = "bson")] + // { + // names.push("bson".to_string()); + // } + + // #[cfg(feature = "sqlite")] + // { + // names.push("sqlite".to_string()); + // } + + // #[cfg(feature = "s3")] + // { + // names.push("s3".to_string()); + // } + + // #[cfg(feature = "chart")] + // { + // names.push("chart".to_string()); + // } + + // #[cfg(feature = "xpath")] + // { + // names.push("xpath".to_string()); + // } + + // #[cfg(feature = "selector")] + // { + // names.push("selector".to_string()); + // } + + // #[cfg(feature = "extra")] + // { + // names.push("extra".to_string()); + // } + + // #[cfg(feature = "preserve_order")] + // { + // names.push("preserve_order".to_string()); + // } + + // #[cfg(feature = "wee_alloc")] + // { + // names.push("wee_alloc".to_string()); + // } + + // #[cfg(feature = "console_error_panic_hook")] + // { + // names.push("console_error_panic_hook".to_string()); + // } + + names.sort(); + + names +} diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 9a62c05d8a..2fa6483d25 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -40,6 +40,7 @@ pub fn create_default_context() -> EngineState { Module, Source, Use, + Version, }; // Filters @@ -173,6 +174,11 @@ pub fn create_default_context() -> EngineState { ToMd, ToToml, ToTsv, + ToCsv, + Touch, + Use, + Update, + Where, ToUrl, ToXml, ToYaml,