From 1038c64f803ec2579e6b0733f2832a89c9f5df50 Mon Sep 17 00:00:00 2001 From: Ian Manske Date: Mon, 6 May 2024 23:20:27 +0000 Subject: [PATCH] Add `sys` subcommands (#12747) # Description Adds subcommands to `sys` corresponding to each column of the record returned by `sys`. This is to alleviate the fact that `sys` now returns a regular record, meaning that it must compute every column which might take a noticeable amount of time. The subcommands, on the other hand, only need to compute and return a subset of the data which should be much faster. In fact, it should be as fast as before, since this is how the lazy record worked (it would compute only each column as necessary). I choose to add subcommands instead of having an optional cell-path parameter on `sys`, since the cell-path parameter would: - increase the code complexity (can access any value at any row or nested column) - prevents discovery with tab-completion - hinders type checking and allows users to pass potentially invalid columns # User-Facing Changes Deprecates `sys` in favor of the new `sys` subcommands. --- crates/nu-command/src/default_context.rs | 6 + crates/nu-command/src/filters/get.rs | 5 - crates/nu-command/src/help/help_.rs | 4 +- crates/nu-command/src/system/mod.rs | 2 +- crates/nu-command/src/system/sys.rs | 269 --------------------- crates/nu-command/src/system/sys/cpu.rs | 39 +++ crates/nu-command/src/system/sys/disks.rs | 39 +++ crates/nu-command/src/system/sys/host.rs | 39 +++ crates/nu-command/src/system/sys/mem.rs | 39 +++ crates/nu-command/src/system/sys/mod.rs | 205 ++++++++++++++++ crates/nu-command/src/system/sys/net.rs | 39 +++ crates/nu-command/src/system/sys/sys_.rs | 64 +++++ crates/nu-command/src/system/sys/temp.rs | 43 ++++ crates/nu-command/tests/commands/select.rs | 2 +- crates/nu-explore/src/explore.rs | 4 +- crates/nu-std/std/help.nu | 4 +- crates/nu-std/testing.nu | 2 +- 17 files changed, 522 insertions(+), 283 deletions(-) delete mode 100644 crates/nu-command/src/system/sys.rs create mode 100644 crates/nu-command/src/system/sys/cpu.rs create mode 100644 crates/nu-command/src/system/sys/disks.rs create mode 100644 crates/nu-command/src/system/sys/host.rs create mode 100644 crates/nu-command/src/system/sys/mem.rs create mode 100644 crates/nu-command/src/system/sys/mod.rs create mode 100644 crates/nu-command/src/system/sys/net.rs create mode 100644 crates/nu-command/src/system/sys/sys_.rs create mode 100644 crates/nu-command/src/system/sys/temp.rs diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index eb7c795f5f..d8307be84d 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -119,6 +119,12 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState { Exec, NuCheck, Sys, + SysCpu, + SysDisks, + SysHost, + SysMem, + SysNet, + SysTemp, UName, }; diff --git a/crates/nu-command/src/filters/get.rs b/crates/nu-command/src/filters/get.rs index c6232b80fc..c30ad1f3a4 100644 --- a/crates/nu-command/src/filters/get.rs +++ b/crates/nu-command/src/filters/get.rs @@ -124,11 +124,6 @@ If multiple cell paths are given, this will produce a list of values."# example: "ls | get 2.name", result: None, }, - Example { - description: "Extract the cpu list from the sys information record", - example: "sys | get cpu", - result: None, - }, Example { description: "Getting Path/PATH in a case insensitive way", example: "$env | get paTH", diff --git a/crates/nu-command/src/help/help_.rs b/crates/nu-command/src/help/help_.rs index 730afae267..819d3c7dd9 100644 --- a/crates/nu-command/src/help/help_.rs +++ b/crates/nu-command/src/help/help_.rs @@ -66,8 +66,8 @@ Each stage in the pipeline works together to load, parse, and display informatio List the files in the current directory, sorted by size: ls | sort-by size -Get information about the current system: - sys | get host +Get the current system host name: + sys host | get hostname Get the processes on your system actively using CPU: ps | where cpu > 0 diff --git a/crates/nu-command/src/system/mod.rs b/crates/nu-command/src/system/mod.rs index 32141832e9..788e1b7740 100644 --- a/crates/nu-command/src/system/mod.rs +++ b/crates/nu-command/src/system/mod.rs @@ -30,6 +30,6 @@ pub use ps::Ps; #[cfg(windows)] pub use registry_query::RegistryQuery; pub use run_external::{External, ExternalCommand}; -pub use sys::Sys; +pub use sys::*; pub use uname::UName; pub use which_::Which; diff --git a/crates/nu-command/src/system/sys.rs b/crates/nu-command/src/system/sys.rs deleted file mode 100644 index 0a836f894a..0000000000 --- a/crates/nu-command/src/system/sys.rs +++ /dev/null @@ -1,269 +0,0 @@ -use chrono::{DateTime, Local}; -use nu_engine::command_prelude::*; -use std::time::{Duration, UNIX_EPOCH}; -use sysinfo::{ - Components, CpuRefreshKind, Disks, Networks, System, Users, MINIMUM_CPU_UPDATE_INTERVAL, -}; - -#[derive(Clone)] -pub struct Sys; - -impl Command for Sys { - fn name(&self) -> &str { - "sys" - } - - fn signature(&self) -> Signature { - Signature::build("sys") - .filter() - .category(Category::System) - .input_output_types(vec![(Type::Nothing, Type::record())]) - } - - fn usage(&self) -> &str { - "View information about the system." - } - - fn run( - &self, - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - _input: PipelineData, - ) -> Result { - Ok(all_columns(call.head).into_pipeline_data()) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Show info about the system", - example: "sys", - result: None, - }, - Example { - description: "Show the os system name with get", - example: "(sys).host | get name", - result: None, - }, - Example { - description: "Show the os system name", - example: "(sys).host.name", - result: None, - }, - ] - } -} - -#[derive(Debug, Clone)] -pub struct SysResult { - pub span: Span, -} - -fn all_columns(span: Span) -> Value { - Value::record( - record! { - "host" => host(span), - "cpu" => cpu(span), - "disks" => disks(span), - "mem" => mem(span), - "temp" => temp(span), - "net" => net(span), - }, - span, - ) -} - -pub fn trim_cstyle_null(s: String) -> String { - s.trim_matches(char::from(0)).to_string() -} - -pub fn disks(span: Span) -> Value { - let disks = Disks::new_with_refreshed_list(); - - let mut output = vec![]; - for disk in disks.list() { - let device = trim_cstyle_null(disk.name().to_string_lossy().to_string()); - let typ = trim_cstyle_null(disk.file_system().to_string_lossy().to_string()); - - let record = record! { - "device" => Value::string(device, span), - "type" => Value::string(typ, span), - "mount" => Value::string(disk.mount_point().to_string_lossy(), span), - "total" => Value::filesize(disk.total_space() as i64, span), - "free" => Value::filesize(disk.available_space() as i64, span), - "removable" => Value::bool(disk.is_removable(), span), - "kind" => Value::string(format!("{:?}", disk.kind()), span), - }; - - output.push(Value::record(record, span)); - } - Value::list(output, span) -} - -pub fn net(span: Span) -> Value { - let networks = Networks::new_with_refreshed_list(); - - let mut output = vec![]; - for (iface, data) in networks.list() { - let record = record! { - "name" => Value::string(trim_cstyle_null(iface.to_string()), span), - "sent" => Value::filesize(data.total_transmitted() as i64, span), - "recv" => Value::filesize(data.total_received() as i64, span), - }; - - output.push(Value::record(record, span)); - } - Value::list(output, span) -} - -pub fn cpu(span: Span) -> Value { - let mut sys = System::new(); - sys.refresh_cpu_specifics(CpuRefreshKind::everything()); - // We must refresh the CPU twice a while apart to get valid usage data. - // In theory we could just sleep MINIMUM_CPU_UPDATE_INTERVAL, but I've noticed that - // that gives poor results (error of ~5%). Decided to wait 2x that long, somewhat arbitrarily - std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL * 2); - sys.refresh_cpu_specifics(CpuRefreshKind::new().with_cpu_usage()); - - let mut output = vec![]; - for cpu in sys.cpus() { - // sysinfo CPU usage numbers are not very precise unless you wait a long time between refreshes. - // Round to 1DP (chosen somewhat arbitrarily) so people aren't misled by high-precision floats. - let rounded_usage = (cpu.cpu_usage() * 10.0).round() / 10.0; - - let load_avg = System::load_average(); - let load_avg = trim_cstyle_null(format!( - "{:.2}, {:.2}, {:.2}", - load_avg.one, load_avg.five, load_avg.fifteen - )); - - let record = record! { - "name" => Value::string(trim_cstyle_null(cpu.name().to_string()), span), - "brand" => Value::string(trim_cstyle_null(cpu.brand().to_string()), span), - "freq" => Value::int(cpu.frequency() as i64, span), - "cpu_usage" => Value::float(rounded_usage as f64, span), - "load_average" => Value::string(load_avg, span), - "vendor_id" => Value::string(trim_cstyle_null(cpu.vendor_id().to_string()), span), - }; - - output.push(Value::record(record, span)); - } - - Value::list(output, span) -} - -pub fn mem(span: Span) -> Value { - let mut sys = System::new(); - sys.refresh_memory(); - - let total_mem = sys.total_memory(); - let free_mem = sys.free_memory(); - let used_mem = sys.used_memory(); - let avail_mem = sys.available_memory(); - - let total_swap = sys.total_swap(); - let free_swap = sys.free_swap(); - let used_swap = sys.used_swap(); - - let record = record! { - "total" => Value::filesize(total_mem as i64, span), - "free" => Value::filesize(free_mem as i64, span), - "used" => Value::filesize(used_mem as i64, span), - "available" => Value::filesize(avail_mem as i64, span), - "swap total" => Value::filesize(total_swap as i64, span), - "swap free" => Value::filesize(free_swap as i64, span), - "swap used" => Value::filesize(used_swap as i64, span), - }; - - Value::record(record, span) -} - -pub fn host(span: Span) -> Value { - let mut record = Record::new(); - - if let Some(name) = System::name() { - record.push("name", Value::string(trim_cstyle_null(name), span)); - } - if let Some(version) = System::os_version() { - record.push("os_version", Value::string(trim_cstyle_null(version), span)); - } - - if let Some(long_version) = System::long_os_version() { - record.push( - "long_os_version", - Value::string(trim_cstyle_null(long_version), span), - ); - } - - if let Some(version) = System::kernel_version() { - record.push( - "kernel_version", - Value::string(trim_cstyle_null(version), span), - ); - } - if let Some(hostname) = System::host_name() { - record.push("hostname", Value::string(trim_cstyle_null(hostname), span)); - } - - record.push( - "uptime", - Value::duration(1000000000 * System::uptime() as i64, span), - ); - - // Creates a new SystemTime from the specified number of whole seconds - let d = UNIX_EPOCH + Duration::from_secs(System::boot_time()); - // Create DateTime from SystemTime - let datetime = DateTime::::from(d); - // Convert to local time and then rfc3339 - let timestamp_str = datetime.with_timezone(datetime.offset()).to_rfc3339(); - - record.push("boot_time", Value::string(timestamp_str, span)); - - let users = Users::new_with_refreshed_list(); - - let mut users_list = vec![]; - for user in users.list() { - let mut groups = vec![]; - for group in user.groups() { - groups.push(Value::string( - trim_cstyle_null(group.name().to_string()), - span, - )); - } - - let record = record! { - "name" => Value::string(trim_cstyle_null(user.name().to_string()), span), - "groups" => Value::list(groups, span), - }; - - users_list.push(Value::record(record, span)); - } - - if !users.is_empty() { - record.push("sessions", Value::list(users_list, span)); - } - - Value::record(record, span) -} - -pub fn temp(span: Span) -> Value { - let components = Components::new_with_refreshed_list(); - - let mut output = vec![]; - - for component in components.list() { - let mut record = record! { - "unit" => Value::string(component.label(), span), - "temp" => Value::float(component.temperature() as f64, span), - "high" => Value::float(component.max() as f64, span), - }; - - if let Some(critical) = component.critical() { - record.push("critical", Value::float(critical as f64, span)); - } - output.push(Value::record(record, span)); - } - - Value::list(output, span) -} diff --git a/crates/nu-command/src/system/sys/cpu.rs b/crates/nu-command/src/system/sys/cpu.rs new file mode 100644 index 0000000000..b2f6d6afa6 --- /dev/null +++ b/crates/nu-command/src/system/sys/cpu.rs @@ -0,0 +1,39 @@ +use nu_engine::command_prelude::*; + +#[derive(Clone)] +pub struct SysCpu; + +impl Command for SysCpu { + fn name(&self) -> &str { + "sys cpu" + } + + fn signature(&self) -> Signature { + Signature::build("sys cpu") + .filter() + .category(Category::System) + .input_output_types(vec![(Type::Nothing, Type::table())]) + } + + fn usage(&self) -> &str { + "View information about the system CPUs." + } + + fn run( + &self, + _engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + _input: PipelineData, + ) -> Result { + Ok(super::cpu(call.head).into_pipeline_data()) + } + + fn examples(&self) -> Vec { + vec![Example { + description: "Show info about the system CPUs", + example: "sys cpu", + result: None, + }] + } +} diff --git a/crates/nu-command/src/system/sys/disks.rs b/crates/nu-command/src/system/sys/disks.rs new file mode 100644 index 0000000000..66991c9087 --- /dev/null +++ b/crates/nu-command/src/system/sys/disks.rs @@ -0,0 +1,39 @@ +use nu_engine::command_prelude::*; + +#[derive(Clone)] +pub struct SysDisks; + +impl Command for SysDisks { + fn name(&self) -> &str { + "sys disks" + } + + fn signature(&self) -> Signature { + Signature::build("sys disks") + .filter() + .category(Category::System) + .input_output_types(vec![(Type::Nothing, Type::table())]) + } + + fn usage(&self) -> &str { + "View information about the system disks." + } + + fn run( + &self, + _engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + _input: PipelineData, + ) -> Result { + Ok(super::disks(call.head).into_pipeline_data()) + } + + fn examples(&self) -> Vec { + vec![Example { + description: "Show info about the system disks", + example: "sys disks", + result: None, + }] + } +} diff --git a/crates/nu-command/src/system/sys/host.rs b/crates/nu-command/src/system/sys/host.rs new file mode 100644 index 0000000000..23508b5b6e --- /dev/null +++ b/crates/nu-command/src/system/sys/host.rs @@ -0,0 +1,39 @@ +use nu_engine::command_prelude::*; + +#[derive(Clone)] +pub struct SysHost; + +impl Command for SysHost { + fn name(&self) -> &str { + "sys host" + } + + fn signature(&self) -> Signature { + Signature::build("sys host") + .filter() + .category(Category::System) + .input_output_types(vec![(Type::Nothing, Type::record())]) + } + + fn usage(&self) -> &str { + "View information about the system host." + } + + fn run( + &self, + _engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + _input: PipelineData, + ) -> Result { + Ok(super::host(call.head).into_pipeline_data()) + } + + fn examples(&self) -> Vec { + vec![Example { + description: "Show info about the system host", + example: "sys host", + result: None, + }] + } +} diff --git a/crates/nu-command/src/system/sys/mem.rs b/crates/nu-command/src/system/sys/mem.rs new file mode 100644 index 0000000000..e5dc36e1b7 --- /dev/null +++ b/crates/nu-command/src/system/sys/mem.rs @@ -0,0 +1,39 @@ +use nu_engine::command_prelude::*; + +#[derive(Clone)] +pub struct SysMem; + +impl Command for SysMem { + fn name(&self) -> &str { + "sys mem" + } + + fn signature(&self) -> Signature { + Signature::build("sys mem") + .filter() + .category(Category::System) + .input_output_types(vec![(Type::Nothing, Type::record())]) + } + + fn usage(&self) -> &str { + "View information about the system memory." + } + + fn run( + &self, + _engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + _input: PipelineData, + ) -> Result { + Ok(super::mem(call.head).into_pipeline_data()) + } + + fn examples(&self) -> Vec { + vec![Example { + description: "Show info about the system memory", + example: "sys mem", + result: None, + }] + } +} diff --git a/crates/nu-command/src/system/sys/mod.rs b/crates/nu-command/src/system/sys/mod.rs new file mode 100644 index 0000000000..0c61543e7d --- /dev/null +++ b/crates/nu-command/src/system/sys/mod.rs @@ -0,0 +1,205 @@ +mod cpu; +mod disks; +mod host; +mod mem; +mod net; +mod sys_; +mod temp; + +pub use cpu::SysCpu; +pub use disks::SysDisks; +pub use host::SysHost; +pub use mem::SysMem; +pub use net::SysNet; +pub use sys_::Sys; +pub use temp::SysTemp; + +use chrono::{DateTime, Local}; +use nu_protocol::{record, Record, Span, Value}; +use std::time::{Duration, UNIX_EPOCH}; +use sysinfo::{ + Components, CpuRefreshKind, Disks, Networks, System, Users, MINIMUM_CPU_UPDATE_INTERVAL, +}; + +pub fn trim_cstyle_null(s: impl AsRef) -> String { + s.as_ref().trim_matches('\0').into() +} + +pub fn disks(span: Span) -> Value { + let disks = Disks::new_with_refreshed_list() + .iter() + .map(|disk| { + let device = trim_cstyle_null(disk.name().to_string_lossy()); + let typ = trim_cstyle_null(disk.file_system().to_string_lossy()); + + let record = record! { + "device" => Value::string(device, span), + "type" => Value::string(typ, span), + "mount" => Value::string(disk.mount_point().to_string_lossy(), span), + "total" => Value::filesize(disk.total_space() as i64, span), + "free" => Value::filesize(disk.available_space() as i64, span), + "removable" => Value::bool(disk.is_removable(), span), + "kind" => Value::string(disk.kind().to_string(), span), + }; + + Value::record(record, span) + }) + .collect(); + + Value::list(disks, span) +} + +pub fn net(span: Span) -> Value { + let networks = Networks::new_with_refreshed_list() + .iter() + .map(|(iface, data)| { + let record = record! { + "name" => Value::string(trim_cstyle_null(iface), span), + "sent" => Value::filesize(data.total_transmitted() as i64, span), + "recv" => Value::filesize(data.total_received() as i64, span), + }; + + Value::record(record, span) + }) + .collect(); + + Value::list(networks, span) +} + +pub fn cpu(span: Span) -> Value { + let mut sys = System::new(); + sys.refresh_cpu_specifics(CpuRefreshKind::everything()); + // We must refresh the CPU twice a while apart to get valid usage data. + // In theory we could just sleep MINIMUM_CPU_UPDATE_INTERVAL, but I've noticed that + // that gives poor results (error of ~5%). Decided to wait 2x that long, somewhat arbitrarily + std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL * 2); + sys.refresh_cpu_specifics(CpuRefreshKind::new().with_cpu_usage()); + + let cpus = sys + .cpus() + .iter() + .map(|cpu| { + // sysinfo CPU usage numbers are not very precise unless you wait a long time between refreshes. + // Round to 1DP (chosen somewhat arbitrarily) so people aren't misled by high-precision floats. + let rounded_usage = (cpu.cpu_usage() * 10.0).round() / 10.0; + + let load_avg = System::load_average(); + let load_avg = format!( + "{:.2}, {:.2}, {:.2}", + load_avg.one, load_avg.five, load_avg.fifteen + ); + + let record = record! { + "name" => Value::string(trim_cstyle_null(cpu.name()), span), + "brand" => Value::string(trim_cstyle_null(cpu.brand()), span), + "freq" => Value::int(cpu.frequency() as i64, span), + "cpu_usage" => Value::float(rounded_usage.into(), span), + "load_average" => Value::string(load_avg, span), + "vendor_id" => Value::string(trim_cstyle_null(cpu.vendor_id()), span), + }; + + Value::record(record, span) + }) + .collect(); + + Value::list(cpus, span) +} + +pub fn mem(span: Span) -> Value { + let mut sys = System::new(); + sys.refresh_memory(); + + let record = record! { + "total" => Value::filesize(sys.total_memory() as i64, span), + "free" => Value::filesize(sys.free_memory() as i64, span), + "used" => Value::filesize(sys.used_memory() as i64, span), + "available" => Value::filesize(sys.available_memory() as i64, span), + "swap total" => Value::filesize(sys.total_swap() as i64, span), + "swap free" => Value::filesize(sys.free_swap() as i64, span), + "swap used" => Value::filesize(sys.used_swap() as i64, span), + }; + + Value::record(record, span) +} + +pub fn host(span: Span) -> Value { + let mut record = Record::new(); + + if let Some(name) = System::name() { + record.push("name", Value::string(trim_cstyle_null(name), span)); + } + if let Some(version) = System::os_version() { + record.push("os_version", Value::string(trim_cstyle_null(version), span)); + } + if let Some(long_version) = System::long_os_version() { + record.push( + "long_os_version", + Value::string(trim_cstyle_null(long_version), span), + ); + } + if let Some(version) = System::kernel_version() { + record.push( + "kernel_version", + Value::string(trim_cstyle_null(version), span), + ); + } + if let Some(hostname) = System::host_name() { + record.push("hostname", Value::string(trim_cstyle_null(hostname), span)); + } + + record.push( + "uptime", + Value::duration(1000000000 * System::uptime() as i64, span), + ); + + // Creates a new SystemTime from the specified number of whole seconds + let d = UNIX_EPOCH + Duration::from_secs(System::boot_time()); + // Create DateTime from SystemTime + let datetime = DateTime::::from(d); + // Convert to local time and then rfc3339 + let timestamp_str = datetime.with_timezone(datetime.offset()).to_rfc3339(); + record.push("boot_time", Value::string(timestamp_str, span)); + + let users = Users::new_with_refreshed_list() + .iter() + .map(|user| { + let groups = user + .groups() + .iter() + .map(|group| Value::string(trim_cstyle_null(group.name()), span)) + .collect(); + + let record = record! { + "name" => Value::string(trim_cstyle_null(user.name()), span), + "groups" => Value::list(groups, span), + }; + + Value::record(record, span) + }) + .collect(); + + record.push("sessions", Value::list(users, span)); + + Value::record(record, span) +} + +pub fn temp(span: Span) -> Value { + let components = Components::new_with_refreshed_list() + .iter() + .map(|component| { + let mut record = record! { + "unit" => Value::string(component.label(), span), + "temp" => Value::float(component.temperature().into(), span), + "high" => Value::float(component.max().into(), span), + }; + + if let Some(critical) = component.critical() { + record.push("critical", Value::float(critical.into(), span)); + } + + Value::record(record, span) + }) + .collect(); + + Value::list(components, span) +} diff --git a/crates/nu-command/src/system/sys/net.rs b/crates/nu-command/src/system/sys/net.rs new file mode 100644 index 0000000000..98dca1bc2f --- /dev/null +++ b/crates/nu-command/src/system/sys/net.rs @@ -0,0 +1,39 @@ +use nu_engine::command_prelude::*; + +#[derive(Clone)] +pub struct SysNet; + +impl Command for SysNet { + fn name(&self) -> &str { + "sys net" + } + + fn signature(&self) -> Signature { + Signature::build("sys net") + .filter() + .category(Category::System) + .input_output_types(vec![(Type::Nothing, Type::table())]) + } + + fn usage(&self) -> &str { + "View information about the system network interfaces." + } + + fn run( + &self, + _engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + _input: PipelineData, + ) -> Result { + Ok(super::net(call.head).into_pipeline_data()) + } + + fn examples(&self) -> Vec { + vec![Example { + description: "Show info about the system network", + example: "sys net", + result: None, + }] + } +} diff --git a/crates/nu-command/src/system/sys/sys_.rs b/crates/nu-command/src/system/sys/sys_.rs new file mode 100644 index 0000000000..39dc2d419b --- /dev/null +++ b/crates/nu-command/src/system/sys/sys_.rs @@ -0,0 +1,64 @@ +use nu_engine::command_prelude::*; + +#[derive(Clone)] +pub struct Sys; + +impl Command for Sys { + fn name(&self) -> &str { + "sys" + } + + fn signature(&self) -> Signature { + Signature::build("sys") + .filter() + .category(Category::System) + .input_output_types(vec![(Type::Nothing, Type::record())]) + } + + fn usage(&self) -> &str { + "View information about the system." + } + + fn extra_usage(&self) -> &str { + "Note that this command may take a noticeable amount of time to run. To reduce the time taken, you can use the various `sys` sub commands to get the subset of information you are interested in." + } + + fn run( + &self, + engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + _input: PipelineData, + ) -> Result { + nu_protocol::report_error_new( + engine_state, + &ShellError::GenericError { + error: "Deprecated command".into(), + msg: "the `sys` command is deprecated, please use the new subcommands (`sys host`, `sys mem`, etc.)." + .into(), + span: Some(call.head), + help: None, + inner: vec![], + }, + ); + + let head = call.head; + let record = record! { + "host" => super::host(head), + "cpu" => super::cpu(head), + "disks" => super::disks(head), + "mem" => super::mem(head), + "temp" => super::temp(head), + "net" => super::net(head), + }; + Ok(Value::record(record, head).into_pipeline_data()) + } + + fn examples(&self) -> Vec { + vec![Example { + description: "Show info about the system", + example: "sys", + result: None, + }] + } +} diff --git a/crates/nu-command/src/system/sys/temp.rs b/crates/nu-command/src/system/sys/temp.rs new file mode 100644 index 0000000000..eaf1ed05db --- /dev/null +++ b/crates/nu-command/src/system/sys/temp.rs @@ -0,0 +1,43 @@ +use nu_engine::command_prelude::*; + +#[derive(Clone)] +pub struct SysTemp; + +impl Command for SysTemp { + fn name(&self) -> &str { + "sys temp" + } + + fn signature(&self) -> Signature { + Signature::build("sys temp") + .filter() + .category(Category::System) + .input_output_types(vec![(Type::Nothing, Type::table())]) + } + + fn usage(&self) -> &str { + "View the temperatures of system components." + } + + fn extra_usage(&self) -> &str { + "Some system components do not support temperature readings, so this command may return an empty list if no components support temperature." + } + + fn run( + &self, + _engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + _input: PipelineData, + ) -> Result { + Ok(super::temp(call.head).into_pipeline_data()) + } + + fn examples(&self) -> Vec { + vec![Example { + description: "Show the system temperatures", + example: "sys temp", + result: None, + }] + } +} diff --git a/crates/nu-command/tests/commands/select.rs b/crates/nu-command/tests/commands/select.rs index 8039dad9d0..741386998a 100644 --- a/crates/nu-command/tests/commands/select.rs +++ b/crates/nu-command/tests/commands/select.rs @@ -172,7 +172,7 @@ fn select_ignores_errors_successfully2() { #[test] fn select_ignores_errors_successfully3() { - let actual = nu!("sys | select invalid_key? | to nuon"); + let actual = nu!("{foo: bar} | select invalid_key? | to nuon"); assert_eq!(actual.out, "{invalid_key: null}".to_string()); assert!(actual.err.is_empty()); diff --git a/crates/nu-explore/src/explore.rs b/crates/nu-explore/src/explore.rs index 6b9797bfa5..15a7b94041 100644 --- a/crates/nu-explore/src/explore.rs +++ b/crates/nu-explore/src/explore.rs @@ -110,8 +110,8 @@ impl Command for Explore { fn examples(&self) -> Vec { vec![ Example { - description: "Explore the system information record", - example: r#"sys | explore"#, + description: "Explore the system host information record", + example: r#"sys host | explore"#, result: None, }, Example { diff --git a/crates/nu-std/std/help.nu b/crates/nu-std/std/help.nu index 0170fd78fc..4e08597691 100644 --- a/crates/nu-std/std/help.nu +++ b/crates/nu-std/std/help.nu @@ -739,8 +739,8 @@ Each stage in the pipeline works together to load, parse, and display informatio List the files in the current directory, sorted by size > ('ls | sort-by size' | nu-highlight) - Get information about the current system - > ('sys | get host' | nu-highlight) + Get the current system host name + > ('sys host | get hostname' | nu-highlight) Get the processes on your system actively using CPU > ('ps | where cpu > 0' | nu-highlight) diff --git a/crates/nu-std/testing.nu b/crates/nu-std/testing.nu index 5335fd44e9..ddae1d371e 100644 --- a/crates/nu-std/testing.nu +++ b/crates/nu-std/testing.nu @@ -1,7 +1,7 @@ use std log def "nu-complete threads" [] { - seq 1 (sys|get cpu|length) + seq 1 (sys cpu | length) } # Here we store the map of annotations internal names and the annotation actually used during test creation