mirror of
https://github.com/nushell/nushell
synced 2024-12-27 05:23:11 +00:00
add sys command
This commit is contained in:
parent
000db46618
commit
503939dcbe
6 changed files with 483 additions and 4 deletions
114
Cargo.lock
generated
114
Cargo.lock
generated
|
@ -123,6 +123,56 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.21.0"
|
||||
|
@ -299,9 +349,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.102"
|
||||
version = "0.2.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
|
@ -337,6 +387,15 @@ version = "2.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miette"
|
||||
version = "3.0.0"
|
||||
|
@ -441,6 +500,7 @@ dependencies = [
|
|||
"nu-json",
|
||||
"nu-protocol",
|
||||
"nu-table",
|
||||
"sysinfo",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
@ -519,6 +579,16 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.26.2"
|
||||
|
@ -683,6 +753,31 @@ dependencies = [
|
|||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"crossbeam-deque",
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
|
@ -886,6 +981,21 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.20.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffff4a02fa61eee51f95210fc9c98ea6eeb46bb071adeafd61e1a0b9b22c6a6d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"ntapi",
|
||||
"once_cell",
|
||||
"rayon",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.2.0"
|
||||
|
|
|
@ -14,3 +14,4 @@ nu-table = { path = "../nu-table" }
|
|||
# Potential dependencies for extras
|
||||
glob = "0.3.0"
|
||||
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())
|
||||
|
|
Loading…
Reference in a new issue