mirror of
https://github.com/nushell/nushell.git
synced 2025-06-30 06:30:08 +02:00
add sys command
This commit is contained in:
@ -13,4 +13,5 @@ nu-table = { path = "../nu-table" }
|
||||
|
||||
# Potential dependencies for extras
|
||||
glob = "0.3.0"
|
||||
thiserror = "1.0.29"
|
||||
thiserror = "1.0.29"
|
||||
sysinfo = "0.20.4"
|
@ -7,7 +7,7 @@ use nu_protocol::{
|
||||
|
||||
use crate::{
|
||||
Alias, Benchmark, BuildString, Def, Do, Each, External, For, From, FromJson, Git, GitCheckout,
|
||||
If, Length, Let, LetEnv, Lines, ListGitBranches, Ls, Module, Table, Use, Where,
|
||||
If, Length, Let, LetEnv, Lines, ListGitBranches, Ls, Module, Sys, Table, Use, Where,
|
||||
};
|
||||
|
||||
pub fn create_default_context() -> Rc<RefCell<EngineState>> {
|
||||
@ -37,6 +37,7 @@ pub fn create_default_context() -> Rc<RefCell<EngineState>> {
|
||||
working_set.add_decl(Box::new(Lines));
|
||||
working_set.add_decl(Box::new(Ls));
|
||||
working_set.add_decl(Box::new(Module));
|
||||
working_set.add_decl(Box::new(Sys));
|
||||
working_set.add_decl(Box::new(Table));
|
||||
working_set.add_decl(Box::new(Use));
|
||||
working_set.add_decl(Box::new(Where));
|
||||
|
@ -1,5 +1,7 @@
|
||||
mod benchmark;
|
||||
mod run_external;
|
||||
mod sys;
|
||||
|
||||
pub use benchmark::Benchmark;
|
||||
pub use run_external::{External, ExternalCommand};
|
||||
pub use sys::Sys;
|
||||
|
356
crates/nu-command/src/system/sys.rs
Normal file
356
crates/nu-command/src/system/sys.rs
Normal file
@ -0,0 +1,356 @@
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EvaluationContext},
|
||||
ShellError, Signature, Span, Value,
|
||||
};
|
||||
use sysinfo::{ComponentExt, DiskExt, NetworkExt, ProcessorExt, System, SystemExt, UserExt};
|
||||
|
||||
pub struct Sys;
|
||||
|
||||
impl Command for Sys {
|
||||
fn name(&self) -> &str {
|
||||
"sys"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("sys")
|
||||
.desc("View information about the current system.")
|
||||
.filter()
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"View information about the system."
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_context: &EvaluationContext,
|
||||
call: &Call,
|
||||
_input: Value,
|
||||
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
|
||||
run_sys(call)
|
||||
}
|
||||
|
||||
// fn examples(&self) -> Vec<Example> {
|
||||
// vec![Example {
|
||||
// description: "Show info about the system",
|
||||
// example: "sys",
|
||||
// result: None,
|
||||
// }]
|
||||
// }
|
||||
}
|
||||
|
||||
fn run_sys(call: &Call) -> Result<Value, ShellError> {
|
||||
let span = call.head;
|
||||
let mut sys = System::new();
|
||||
|
||||
let mut headers = vec![];
|
||||
let mut values = vec![];
|
||||
|
||||
if let Some(value) = host(&mut sys, span) {
|
||||
headers.push("host".into());
|
||||
values.push(value);
|
||||
}
|
||||
if let Some(value) = cpu(&mut sys, span) {
|
||||
headers.push("cpu".into());
|
||||
values.push(value);
|
||||
}
|
||||
if let Some(value) = disks(&mut sys, span) {
|
||||
headers.push("disks".into());
|
||||
values.push(value);
|
||||
}
|
||||
if let Some(value) = mem(&mut sys, span) {
|
||||
headers.push("mem".into());
|
||||
values.push(value);
|
||||
}
|
||||
if let Some(value) = temp(&mut sys, span) {
|
||||
headers.push("temp".into());
|
||||
values.push(value);
|
||||
}
|
||||
if let Some(value) = net(&mut sys, span) {
|
||||
headers.push("net".into());
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
Ok(Value::Record {
|
||||
cols: headers,
|
||||
vals: values,
|
||||
span,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn trim_cstyle_null(s: String) -> String {
|
||||
s.trim_matches(char::from(0)).to_string()
|
||||
}
|
||||
|
||||
pub fn disks(sys: &mut System, span: Span) -> Option<Value> {
|
||||
sys.refresh_disks();
|
||||
sys.refresh_disks_list();
|
||||
|
||||
let mut output = vec![];
|
||||
for disk in sys.disks() {
|
||||
let mut cols = vec![];
|
||||
let mut vals = vec![];
|
||||
|
||||
cols.push("device".into());
|
||||
vals.push(Value::String {
|
||||
val: trim_cstyle_null(disk.name().to_string_lossy().to_string()),
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("type".into());
|
||||
vals.push(Value::String {
|
||||
val: trim_cstyle_null(String::from_utf8_lossy(disk.file_system()).to_string()),
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("mount".into());
|
||||
vals.push(Value::String {
|
||||
val: disk.mount_point().to_string_lossy().to_string(),
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("total".into());
|
||||
vals.push(Value::Filesize {
|
||||
val: disk.total_space(),
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("free".into());
|
||||
vals.push(Value::Filesize {
|
||||
val: disk.available_space(),
|
||||
span,
|
||||
});
|
||||
|
||||
output.push(Value::Record { cols, vals, span });
|
||||
}
|
||||
if !output.is_empty() {
|
||||
Some(Value::List { vals: output, span })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn net(sys: &mut System, span: Span) -> Option<Value> {
|
||||
sys.refresh_networks();
|
||||
sys.refresh_networks_list();
|
||||
|
||||
let mut output = vec![];
|
||||
for (iface, data) in sys.networks() {
|
||||
let mut cols = vec![];
|
||||
let mut vals = vec![];
|
||||
|
||||
cols.push("name".into());
|
||||
vals.push(Value::String {
|
||||
val: trim_cstyle_null(iface.to_string()),
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("sent".into());
|
||||
vals.push(Value::Filesize {
|
||||
val: data.total_transmitted(),
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("recv".into());
|
||||
vals.push(Value::Filesize {
|
||||
val: data.total_received(),
|
||||
span,
|
||||
});
|
||||
|
||||
output.push(Value::Record { cols, vals, span });
|
||||
}
|
||||
if !output.is_empty() {
|
||||
Some(Value::List { vals: output, span })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cpu(sys: &mut System, span: Span) -> Option<Value> {
|
||||
sys.refresh_cpu();
|
||||
|
||||
let mut output = vec![];
|
||||
for cpu in sys.processors() {
|
||||
let mut cols = vec![];
|
||||
let mut vals = vec![];
|
||||
|
||||
cols.push("name".into());
|
||||
vals.push(Value::String {
|
||||
val: trim_cstyle_null(cpu.name().to_string()),
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("brand".into());
|
||||
vals.push(Value::String {
|
||||
val: trim_cstyle_null(cpu.brand().to_string()),
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("freq".into());
|
||||
vals.push(Value::Int {
|
||||
val: cpu.frequency() as i64,
|
||||
span,
|
||||
});
|
||||
|
||||
output.push(Value::Record { cols, vals, span });
|
||||
}
|
||||
if !output.is_empty() {
|
||||
Some(Value::List { vals: output, span })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mem(sys: &mut System, span: Span) -> Option<Value> {
|
||||
sys.refresh_memory();
|
||||
|
||||
let mut cols = vec![];
|
||||
let mut vals = vec![];
|
||||
|
||||
let total_mem = sys.total_memory();
|
||||
let free_mem = sys.free_memory();
|
||||
let total_swap = sys.total_swap();
|
||||
let free_swap = sys.free_swap();
|
||||
|
||||
cols.push("total".into());
|
||||
vals.push(Value::Filesize {
|
||||
val: total_mem * 1000,
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("free".into());
|
||||
vals.push(Value::Filesize {
|
||||
val: free_mem * 1000,
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("swap total".into());
|
||||
vals.push(Value::Filesize {
|
||||
val: total_swap * 1000,
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("swap free".into());
|
||||
vals.push(Value::Filesize {
|
||||
val: free_swap * 1000,
|
||||
span,
|
||||
});
|
||||
|
||||
Some(Value::Record { cols, vals, span })
|
||||
}
|
||||
|
||||
pub fn host(sys: &mut System, span: Span) -> Option<Value> {
|
||||
sys.refresh_users_list();
|
||||
|
||||
let mut cols = vec![];
|
||||
let mut vals = vec![];
|
||||
|
||||
if let Some(name) = sys.name() {
|
||||
cols.push("name".into());
|
||||
vals.push(Value::String {
|
||||
val: trim_cstyle_null(name),
|
||||
span,
|
||||
});
|
||||
}
|
||||
if let Some(version) = sys.os_version() {
|
||||
cols.push("os version".into());
|
||||
vals.push(Value::String {
|
||||
val: trim_cstyle_null(version),
|
||||
span,
|
||||
});
|
||||
}
|
||||
if let Some(version) = sys.kernel_version() {
|
||||
cols.push("kernel version".into());
|
||||
vals.push(Value::String {
|
||||
val: trim_cstyle_null(version),
|
||||
span,
|
||||
});
|
||||
}
|
||||
if let Some(hostname) = sys.host_name() {
|
||||
cols.push("hostname".into());
|
||||
vals.push(Value::String {
|
||||
val: trim_cstyle_null(hostname),
|
||||
span,
|
||||
});
|
||||
}
|
||||
// dict.insert_untagged(
|
||||
// "uptime",
|
||||
// UntaggedValue::duration(1000000000 * sys.uptime() as i64),
|
||||
// );
|
||||
|
||||
let mut users = vec![];
|
||||
for user in sys.users() {
|
||||
let mut cols = vec![];
|
||||
let mut vals = vec![];
|
||||
|
||||
cols.push("name".into());
|
||||
vals.push(Value::String {
|
||||
val: trim_cstyle_null(user.name().to_string()),
|
||||
span,
|
||||
});
|
||||
|
||||
let mut groups = vec![];
|
||||
for group in user.groups() {
|
||||
groups.push(Value::String {
|
||||
val: trim_cstyle_null(group.to_string()),
|
||||
span,
|
||||
});
|
||||
}
|
||||
|
||||
cols.push("groups".into());
|
||||
vals.push(Value::List { vals: groups, span });
|
||||
|
||||
users.push(Value::Record { cols, vals, span });
|
||||
}
|
||||
if !users.is_empty() {
|
||||
cols.push("sessions".into());
|
||||
vals.push(Value::List { vals: users, span });
|
||||
}
|
||||
|
||||
Some(Value::Record { cols, vals, span })
|
||||
}
|
||||
|
||||
pub fn temp(sys: &mut System, span: Span) -> Option<Value> {
|
||||
sys.refresh_components();
|
||||
sys.refresh_components_list();
|
||||
|
||||
let mut output = vec![];
|
||||
|
||||
for component in sys.components() {
|
||||
let mut cols = vec![];
|
||||
let mut vals = vec![];
|
||||
|
||||
cols.push("unit".into());
|
||||
vals.push(Value::String {
|
||||
val: component.label().to_string(),
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("temp".into());
|
||||
vals.push(Value::Float {
|
||||
val: component.temperature() as f64,
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("high".into());
|
||||
vals.push(Value::Float {
|
||||
val: component.max() as f64,
|
||||
span,
|
||||
});
|
||||
|
||||
if let Some(critical) = component.critical() {
|
||||
cols.push("critical".into());
|
||||
vals.push(Value::Float {
|
||||
val: critical as f64,
|
||||
span,
|
||||
});
|
||||
}
|
||||
output.push(Value::Record { cols, vals, span });
|
||||
}
|
||||
if !output.is_empty() {
|
||||
Some(Value::List { vals: output, span })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
@ -25,6 +25,10 @@ pub enum Value {
|
||||
val: i64,
|
||||
span: Span,
|
||||
},
|
||||
Filesize {
|
||||
val: u64,
|
||||
span: Span,
|
||||
},
|
||||
Range {
|
||||
val: Box<Range>,
|
||||
span: Span,
|
||||
@ -81,6 +85,7 @@ impl Value {
|
||||
Value::Bool { span, .. } => *span,
|
||||
Value::Int { span, .. } => *span,
|
||||
Value::Float { span, .. } => *span,
|
||||
Value::Filesize { span, .. } => *span,
|
||||
Value::Range { span, .. } => *span,
|
||||
Value::String { span, .. } => *span,
|
||||
Value::Record { span, .. } => *span,
|
||||
@ -98,6 +103,7 @@ impl Value {
|
||||
Value::Bool { span, .. } => *span = new_span,
|
||||
Value::Int { span, .. } => *span = new_span,
|
||||
Value::Float { span, .. } => *span = new_span,
|
||||
Value::Filesize { span, .. } => *span = new_span,
|
||||
Value::Range { span, .. } => *span = new_span,
|
||||
Value::String { span, .. } => *span = new_span,
|
||||
Value::Record { span, .. } => *span = new_span,
|
||||
@ -118,6 +124,7 @@ impl Value {
|
||||
Value::Bool { .. } => Type::Bool,
|
||||
Value::Int { .. } => Type::Int,
|
||||
Value::Float { .. } => Type::Float,
|
||||
Value::Filesize { .. } => Type::Filesize,
|
||||
Value::Range { .. } => Type::Range,
|
||||
Value::String { .. } => Type::String,
|
||||
Value::Record { cols, vals, .. } => {
|
||||
@ -138,6 +145,7 @@ impl Value {
|
||||
Value::Bool { val, .. } => val.to_string(),
|
||||
Value::Int { val, .. } => val.to_string(),
|
||||
Value::Float { val, .. } => val.to_string(),
|
||||
Value::Filesize { val, .. } => format!("{} bytes", val),
|
||||
Value::Range { val, .. } => {
|
||||
format!(
|
||||
"range: [{}]",
|
||||
@ -176,6 +184,7 @@ impl Value {
|
||||
Value::Bool { val, .. } => val.to_string(),
|
||||
Value::Int { val, .. } => val.to_string(),
|
||||
Value::Float { val, .. } => val.to_string(),
|
||||
Value::Filesize { val, .. } => format!("{} bytes", val),
|
||||
Value::Range { val, .. } => val
|
||||
.into_iter()
|
||||
.map(|x| x.into_string())
|
||||
|
Reference in New Issue
Block a user