Extract ps and sys subcrates. Move helper methods to UntaggedValue

This commit is contained in:
Jonathan Turner
2019-12-05 08:52:31 +13:00
parent a4bb5d4ff5
commit d12c16a331
84 changed files with 673 additions and 600 deletions

View File

@ -1,4 +1,4 @@
use nu::{serve_plugin, value, Plugin};
use nu::{serve_plugin, Plugin};
use nu_errors::{CoerceInto, ShellError};
use nu_protocol::{
CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, UntaggedValue, Value,
@ -27,7 +27,7 @@ impl Average {
value: UntaggedValue::Primitive(Primitive::Int(j)),
tag,
}) => {
self.total = Some(value::int(i + j).into_value(tag));
self.total = Some(UntaggedValue::int(i + j).into_value(tag));
self.count += 1;
Ok(())
}
@ -47,7 +47,7 @@ impl Average {
value: UntaggedValue::Primitive(Primitive::Bytes(j)),
tag,
}) => {
self.total = Some(value::bytes(b + j).into_value(tag));
self.total = Some(UntaggedValue::bytes(b + j).into_value(tag));
self.count += 1;
Ok(())
}

View File

@ -1,7 +1,7 @@
#[macro_use]
extern crate indexmap;
use nu::{serve_plugin, value, Plugin};
use nu::{serve_plugin, Plugin};
use nu_errors::ShellError;
use nu_protocol::{
CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, SpannedTypeName, SyntaxShape,
@ -35,7 +35,7 @@ impl Embed {
self.are_all_rows = false;
self.values.push(
value::row(indexmap! {
UntaggedValue::row(indexmap! {
match &self.field {
Some(key) => key.clone(),
None => "Column".into()
@ -81,11 +81,11 @@ impl Plugin for Embed {
fn end_filter(&mut self) -> Result<Vec<ReturnValue>, ShellError> {
if self.are_all_rows {
let row = value::row(indexmap! {
let row = UntaggedValue::row(indexmap! {
match &self.field {
Some(key) => key.clone(),
None => "Column".into(),
} => value::table(&self.values).into_value(Tag::unknown()),
} => UntaggedValue::table(&self.values).into_value(Tag::unknown()),
})
.into_untagged_value();

View File

@ -1,4 +1,4 @@
use nu::{serve_plugin, value, Plugin};
use nu::{serve_plugin, Plugin};
use nu_errors::ShellError;
use nu_protocol::{
CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, SyntaxShape, UntaggedValue, Value,
@ -115,7 +115,7 @@ impl Plugin for Format {
}
return Ok(vec![ReturnSuccess::value(
value::string(output).into_untagged_value(),
UntaggedValue::string(output).into_untagged_value(),
)]);
}
_ => {}

View File

@ -1,4 +1,4 @@
use nu::{did_you_mean, serve_plugin, value, Plugin, ValueExt};
use nu::{did_you_mean, serve_plugin, Plugin, ValueExt};
use nu_errors::ShellError;
use nu_protocol::{
CallInfo, ColumnPath, Primitive, ReturnSuccess, ReturnValue, ShellTypeName, Signature,
@ -37,7 +37,7 @@ impl Inc {
Some(Action::SemVerAction(act_on)) => {
let mut ver = match semver::Version::parse(&input) {
Ok(parsed_ver) => parsed_ver,
Err(_) => return Ok(value::string(input.to_string())),
Err(_) => return Ok(UntaggedValue::string(input.to_string())),
};
match act_on {
@ -46,11 +46,11 @@ impl Inc {
SemVerAction::Patch => ver.increment_patch(),
}
value::string(ver.to_string())
UntaggedValue::string(ver.to_string())
}
Some(Action::Default) | None => match input.parse::<u64>() {
Ok(v) => value::string(format!("{}", v + 1)),
Err(_) => value::string(input),
Ok(v) => UntaggedValue::string(format!("{}", v + 1)),
Err(_) => UntaggedValue::string(input),
},
};
@ -80,10 +80,10 @@ impl Inc {
fn inc(&self, value: Value) -> Result<Value, ShellError> {
match &value.value {
UntaggedValue::Primitive(Primitive::Int(i)) => {
Ok(value::int(i + 1).into_value(value.tag()))
Ok(UntaggedValue::int(i + 1).into_value(value.tag()))
}
UntaggedValue::Primitive(Primitive::Bytes(b)) => {
Ok(value::bytes(b + 1 as u64).into_value(value.tag()))
Ok(UntaggedValue::bytes(b + 1 as u64).into_value(value.tag()))
}
UntaggedValue::Primitive(Primitive::String(ref s)) => {
Ok(self.apply(&s)?.into_value(value.tag()))
@ -226,7 +226,7 @@ mod tests {
use super::{Inc, SemVerAction};
use indexmap::IndexMap;
use nu::{value, Plugin, TaggedDictBuilder};
use nu::{Plugin, TaggedDictBuilder};
use nu_protocol::{
CallInfo, EvaluatedArgs, PathMember, ReturnSuccess, UnspannedPathMember, UntaggedValue,
Value,
@ -249,7 +249,7 @@ mod tests {
fn with_long_flag(&mut self, name: &str) -> &mut Self {
self.flags.insert(
name.to_string(),
value::boolean(true).into_value(Tag::unknown()),
UntaggedValue::boolean(true).into_value(Tag::unknown()),
);
self
}
@ -263,7 +263,7 @@ mod tests {
.collect();
self.positionals
.push(value::column_path(fields).into_untagged_value());
.push(UntaggedValue::column_path(fields).into_untagged_value());
self
}
@ -277,7 +277,7 @@ mod tests {
fn cargo_sample_record(with_version: &str) -> Value {
let mut package = TaggedDictBuilder::new(Tag::unknown());
package.insert_untagged("version", value::string(with_version));
package.insert_untagged("version", UntaggedValue::string(with_version));
package.into_value()
}
@ -360,21 +360,21 @@ mod tests {
fn incs_major() {
let mut inc = Inc::new();
inc.for_semver(SemVerAction::Major);
assert_eq!(inc.apply("0.1.3").unwrap(), value::string("1.0.0"));
assert_eq!(inc.apply("0.1.3").unwrap(), UntaggedValue::string("1.0.0"));
}
#[test]
fn incs_minor() {
let mut inc = Inc::new();
inc.for_semver(SemVerAction::Minor);
assert_eq!(inc.apply("0.1.3").unwrap(), value::string("0.2.0"));
assert_eq!(inc.apply("0.1.3").unwrap(), UntaggedValue::string("0.2.0"));
}
#[test]
fn incs_patch() {
let mut inc = Inc::new();
inc.for_semver(SemVerAction::Patch);
assert_eq!(inc.apply("0.1.3").unwrap(), value::string("0.1.4"));
assert_eq!(inc.apply("0.1.3").unwrap(), UntaggedValue::string("0.1.4"));
}
#[test]
@ -399,7 +399,7 @@ mod tests {
..
}) => assert_eq!(
*o.get_data(&String::from("version")).borrow(),
value::string(String::from("1.0.0")).into_untagged_value()
UntaggedValue::string(String::from("1.0.0")).into_untagged_value()
),
_ => {}
}
@ -427,7 +427,7 @@ mod tests {
..
}) => assert_eq!(
*o.get_data(&String::from("version")).borrow(),
value::string(String::from("0.2.0")).into_untagged_value()
UntaggedValue::string(String::from("0.2.0")).into_untagged_value()
),
_ => {}
}
@ -456,7 +456,7 @@ mod tests {
..
}) => assert_eq!(
*o.get_data(&field).borrow(),
value::string(String::from("0.1.4")).into_untagged_value()
UntaggedValue::string(String::from("0.1.4")).into_untagged_value()
),
_ => {}
}

View File

@ -1,4 +1,4 @@
use nu::{serve_plugin, value, Plugin, TaggedDictBuilder};
use nu::{serve_plugin, Plugin, TaggedDictBuilder};
use nu_errors::ShellError;
use nu_protocol::{
CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, SyntaxShape, UntaggedValue, Value,
@ -134,7 +134,10 @@ impl Plugin for Parse {
let mut dict = TaggedDictBuilder::new(input.tag());
for (idx, column_name) in self.column_names.iter().enumerate() {
dict.insert_untagged(column_name, value::string(&cap[idx + 1].to_string()));
dict.insert_untagged(
column_name,
UntaggedValue::string(&cap[idx + 1].to_string()),
);
}
results.push(ReturnSuccess::value(dict.into_value()));

View File

@ -1,81 +0,0 @@
use futures::executor::block_on;
use futures::stream::{StreamExt, TryStreamExt};
use heim::process::{self as process, Process, ProcessResult};
use heim::units::{ratio, Ratio};
use std::usize;
use nu::{serve_plugin, value, Plugin, TaggedDictBuilder};
use nu_errors::ShellError;
use nu_protocol::{CallInfo, ReturnSuccess, ReturnValue, Signature, Value};
use nu_source::Tag;
use std::time::Duration;
struct Ps;
impl Ps {
fn new() -> Ps {
Ps
}
}
async fn usage(process: Process) -> ProcessResult<(process::Process, Ratio)> {
let usage_1 = process.cpu_usage().await?;
futures_timer::Delay::new(Duration::from_millis(100)).await;
let usage_2 = process.cpu_usage().await?;
Ok((process, usage_2 - usage_1))
}
async fn ps(tag: Tag) -> Vec<Value> {
let processes = process::processes()
.map_ok(|process| {
// Note that there is no `.await` here,
// as we want to pass the returned future
// into the `.try_buffer_unordered`.
usage(process)
})
.try_buffer_unordered(usize::MAX);
pin_utils::pin_mut!(processes);
let mut output = vec![];
while let Some(res) = processes.next().await {
if let Ok((process, usage)) = res {
let mut dict = TaggedDictBuilder::new(&tag);
dict.insert_untagged("pid", value::int(process.pid()));
if let Ok(name) = process.name().await {
dict.insert_untagged("name", value::string(name));
}
if let Ok(status) = process.status().await {
dict.insert_untagged("status", value::string(format!("{:?}", status)));
}
dict.insert_untagged("cpu", value::number(usage.get::<ratio::percent>()));
output.push(dict.into_value());
}
}
output
}
impl Plugin for Ps {
fn config(&mut self) -> Result<Signature, ShellError> {
Ok(Signature::build("ps")
.desc("View information about system processes.")
.filter())
}
fn begin_filter(&mut self, callinfo: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
Ok(block_on(ps(callinfo.name_tag))
.into_iter()
.map(ReturnSuccess::value)
.collect())
}
fn filter(&mut self, _: Value) -> Result<Vec<ReturnValue>, ShellError> {
Ok(vec![])
}
}
fn main() {
serve_plugin(&mut Ps::new());
}

View File

@ -1,4 +1,4 @@
use nu::{did_you_mean, serve_plugin, value, Plugin, ValueExt};
use nu::{did_you_mean, serve_plugin, Plugin, ValueExt};
use nu_errors::ShellError;
use nu_protocol::{
CallInfo, ColumnPath, Primitive, ReturnSuccess, ReturnValue, ShellTypeName, Signature,
@ -41,15 +41,15 @@ impl Str {
fn apply(&self, input: &str) -> Result<UntaggedValue, ShellError> {
let applied = match self.action.as_ref() {
Some(Action::Downcase) => value::string(input.to_ascii_lowercase()),
Some(Action::Upcase) => value::string(input.to_ascii_uppercase()),
Some(Action::Downcase) => UntaggedValue::string(input.to_ascii_lowercase()),
Some(Action::Upcase) => UntaggedValue::string(input.to_ascii_uppercase()),
Some(Action::Substring(s, e)) => {
let end: usize = cmp::min(*e, input.len());
let start: usize = *s;
if start > input.len() - 1 {
value::string("")
UntaggedValue::string("")
} else {
value::string(
UntaggedValue::string(
&input
.chars()
.skip(start)
@ -59,23 +59,25 @@ impl Str {
}
}
Some(Action::Replace(mode)) => match mode {
ReplaceAction::Direct(replacement) => value::string(replacement.as_str()),
ReplaceAction::Direct(replacement) => UntaggedValue::string(replacement.as_str()),
ReplaceAction::FindAndReplace(find, replacement) => {
let regex = Regex::new(find.as_str());
match regex {
Ok(re) => value::string(re.replace(input, replacement.as_str()).to_owned()),
Err(_) => value::string(input),
Ok(re) => UntaggedValue::string(
re.replace(input, replacement.as_str()).to_owned(),
),
Err(_) => UntaggedValue::string(input),
}
}
},
Some(Action::ToInteger) => match input.trim() {
other => match other.parse::<i64>() {
Ok(v) => value::int(v),
Err(_) => value::string(input),
Ok(v) => UntaggedValue::int(v),
Err(_) => UntaggedValue::string(input),
},
},
None => value::string(input),
None => UntaggedValue::string(input),
};
Ok(applied)
@ -315,17 +317,17 @@ fn main() {
mod tests {
use super::{Action, ReplaceAction, Str};
use indexmap::IndexMap;
use nu::{value, Plugin, TaggedDictBuilder, ValueExt};
use nu::{Plugin, TaggedDictBuilder, ValueExt};
use nu_protocol::{CallInfo, EvaluatedArgs, Primitive, ReturnSuccess, UntaggedValue, Value};
use nu_source::Tag;
use num_bigint::BigInt;
fn string(input: impl Into<String>) -> Value {
value::string(input.into()).into_untagged_value()
UntaggedValue::string(input.into()).into_untagged_value()
}
fn table(list: &Vec<Value>) -> Value {
value::table(list).into_untagged_value()
UntaggedValue::table(list).into_untagged_value()
}
fn column_path(paths: &Vec<Value>) -> Value {
@ -358,7 +360,7 @@ mod tests {
fn with_long_flag(&mut self, name: &str) -> &mut Self {
self.flags.insert(
name.to_string(),
value::boolean(true).into_value(Tag::unknown()),
UntaggedValue::boolean(true).into_value(Tag::unknown()),
);
self
}
@ -366,7 +368,7 @@ mod tests {
fn with_parameter(&mut self, name: &str) -> &mut Self {
let fields: Vec<Value> = name
.split(".")
.map(|s| value::string(s.to_string()).into_value(Tag::unknown()))
.map(|s| UntaggedValue::string(s.to_string()).into_value(Tag::unknown()))
.collect();
self.positionals.push(column_path(&fields));
@ -383,12 +385,12 @@ mod tests {
fn structured_sample_record(key: &str, value: &str) -> Value {
let mut record = TaggedDictBuilder::new(Tag::unknown());
record.insert_untagged(key.clone(), value::string(value));
record.insert_untagged(key.clone(), UntaggedValue::string(value));
record.into_value()
}
fn unstructured_sample_record(value: &str) -> Value {
value::string(value).into_value(Tag::unknown())
UntaggedValue::string(value).into_value(Tag::unknown())
}
#[test]
@ -530,21 +532,30 @@ mod tests {
fn str_downcases() {
let mut strutils = Str::new();
strutils.for_downcase();
assert_eq!(strutils.apply("ANDRES").unwrap(), value::string("andres"));
assert_eq!(
strutils.apply("ANDRES").unwrap(),
UntaggedValue::string("andres")
);
}
#[test]
fn str_upcases() {
let mut strutils = Str::new();
strutils.for_upcase();
assert_eq!(strutils.apply("andres").unwrap(), value::string("ANDRES"));
assert_eq!(
strutils.apply("andres").unwrap(),
UntaggedValue::string("ANDRES")
);
}
#[test]
fn str_to_int() {
let mut strutils = Str::new();
strutils.for_to_int();
assert_eq!(strutils.apply("9999").unwrap(), value::int(9999 as i64));
assert_eq!(
strutils.apply("9999").unwrap(),
UntaggedValue::int(9999 as i64)
);
}
#[test]
@ -552,7 +563,10 @@ mod tests {
let mut strutils = Str::new();
strutils.for_replace(ReplaceAction::Direct("robalino".to_string()));
assert_eq!(strutils.apply("andres").unwrap(), value::string("robalino"));
assert_eq!(
strutils.apply("andres").unwrap(),
UntaggedValue::string("robalino")
);
}
#[test]
@ -564,7 +578,7 @@ mod tests {
));
assert_eq!(
strutils.apply("wykittens").unwrap(),
value::string("wyjotandrehuda")
UntaggedValue::string("wyjotandrehuda")
);
}
@ -590,7 +604,7 @@ mod tests {
..
}) => assert_eq!(
*o.get_data(&String::from("name")).borrow(),
value::string(String::from("JOTANDREHUDA")).into_untagged_value()
UntaggedValue::string(String::from("JOTANDREHUDA")).into_untagged_value()
),
_ => {}
}
@ -638,7 +652,7 @@ mod tests {
..
}) => assert_eq!(
*o.get_data(&String::from("name")).borrow(),
value::string(String::from("jotandrehuda")).into_untagged_value()
UntaggedValue::string(String::from("jotandrehuda")).into_untagged_value()
),
_ => {}
}
@ -686,7 +700,7 @@ mod tests {
..
}) => assert_eq!(
*o.get_data(&String::from("Nu_birthday")).borrow(),
value::int(10).into_untagged_value()
UntaggedValue::int(10).into_untagged_value()
),
_ => {}
}
@ -872,7 +886,7 @@ mod tests {
}) => assert_eq!(
*o.get_data(&String::from("rustconf")).borrow(),
Value {
value: value::string(String::from("22nd August 2019")),
value: UntaggedValue::string(String::from("22nd August 2019")),
tag: Tag::unknown()
}
),
@ -930,7 +944,7 @@ mod tests {
}) => assert_eq!(
*o.get_data(&String::from("staff")).borrow(),
Value {
value: value::string(String::from("wyjotandrehuda")),
value: UntaggedValue::string(String::from("wyjotandrehuda")),
tag: Tag::unknown()
}
),

View File

@ -1,4 +1,4 @@
use nu::{serve_plugin, value, Plugin};
use nu::{serve_plugin, Plugin};
use nu_errors::ShellError;
use nu_protocol::{
CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, UntaggedValue, Value,
@ -22,7 +22,7 @@ impl Sum {
tag,
}) => {
//TODO: handle overflow
self.total = Some(value::int(i + j).into_value(tag));
self.total = Some(UntaggedValue::int(i + j).into_value(tag));
Ok(())
}
None => {
@ -43,7 +43,7 @@ impl Sum {
tag,
}) => {
//TODO: handle overflow
self.total = Some(value::bytes(b + j).into_value(tag));
self.total = Some(UntaggedValue::bytes(b + j).into_value(tag));
Ok(())
}
None => {

View File

@ -1,340 +0,0 @@
use std::ffi::OsStr;
use futures::executor::block_on;
use futures::stream::StreamExt;
use heim::units::{frequency, information, thermodynamic_temperature, time};
use heim::{disk, host, memory, net, sensors};
use nu::{primitive, serve_plugin, value, Plugin, TaggedDictBuilder};
use nu_errors::ShellError;
use nu_protocol::{CallInfo, ReturnSuccess, ReturnValue, Signature, UntaggedValue, Value};
use nu_source::Tag;
struct Sys;
impl Sys {
fn new() -> Sys {
Sys
}
}
async fn cpu(tag: Tag) -> Option<Value> {
match futures::future::try_join(heim::cpu::logical_count(), heim::cpu::frequency()).await {
Ok((num_cpu, cpu_speed)) => {
let mut cpu_idx = TaggedDictBuilder::with_capacity(tag, 4);
cpu_idx.insert_untagged("cores", primitive::number(num_cpu));
let current_speed =
(cpu_speed.current().get::<frequency::hertz>() as f64 / 1_000_000_000.0 * 100.0)
.round()
/ 100.0;
cpu_idx.insert_untagged("current ghz", primitive::number(current_speed));
if let Some(min_speed) = cpu_speed.min() {
let min_speed =
(min_speed.get::<frequency::hertz>() as f64 / 1_000_000_000.0 * 100.0).round()
/ 100.0;
cpu_idx.insert_untagged("min ghz", primitive::number(min_speed));
}
if let Some(max_speed) = cpu_speed.max() {
let max_speed =
(max_speed.get::<frequency::hertz>() as f64 / 1_000_000_000.0 * 100.0).round()
/ 100.0;
cpu_idx.insert_untagged("max ghz", primitive::number(max_speed));
}
Some(cpu_idx.into_value())
}
Err(_) => None,
}
}
async fn mem(tag: Tag) -> Value {
let mut dict = TaggedDictBuilder::with_capacity(tag, 4);
let (memory_result, swap_result) =
futures::future::join(memory::memory(), memory::swap()).await;
if let Ok(memory) = memory_result {
dict.insert_untagged(
"total",
value::bytes(memory.total().get::<information::byte>()),
);
dict.insert_untagged(
"free",
value::bytes(memory.free().get::<information::byte>()),
);
}
if let Ok(swap) = swap_result {
dict.insert_untagged(
"swap total",
value::bytes(swap.total().get::<information::byte>()),
);
dict.insert_untagged(
"swap free",
value::bytes(swap.free().get::<information::byte>()),
);
}
dict.into_value()
}
async fn host(tag: Tag) -> Value {
let mut dict = TaggedDictBuilder::with_capacity(&tag, 6);
let (platform_result, uptime_result) =
futures::future::join(host::platform(), host::uptime()).await;
// OS
if let Ok(platform) = platform_result {
dict.insert_untagged("name", value::string(platform.system()));
dict.insert_untagged("release", value::string(platform.release()));
dict.insert_untagged("hostname", value::string(platform.hostname()));
dict.insert_untagged("arch", value::string(platform.architecture().as_str()));
}
// Uptime
if let Ok(uptime) = uptime_result {
let mut uptime_dict = TaggedDictBuilder::with_capacity(&tag, 4);
let uptime = uptime.get::<time::second>().round() as i64;
let days = uptime / (60 * 60 * 24);
let hours = (uptime - days * 60 * 60 * 24) / (60 * 60);
let minutes = (uptime - days * 60 * 60 * 24 - hours * 60 * 60) / 60;
let seconds = uptime % 60;
uptime_dict.insert_untagged("days", value::int(days));
uptime_dict.insert_untagged("hours", value::int(hours));
uptime_dict.insert_untagged("mins", value::int(minutes));
uptime_dict.insert_untagged("secs", value::int(seconds));
dict.insert_value("uptime", uptime_dict);
}
// Users
let mut users = host::users();
let mut user_vec = vec![];
while let Some(user) = users.next().await {
if let Ok(user) = user {
user_vec.push(Value {
value: value::string(user.username()),
tag: tag.clone(),
});
}
}
let user_list = UntaggedValue::Table(user_vec);
dict.insert_untagged("users", user_list);
dict.into_value()
}
async fn disks(tag: Tag) -> Option<UntaggedValue> {
let mut output = vec![];
let mut partitions = disk::partitions_physical();
while let Some(part) = partitions.next().await {
if let Ok(part) = part {
let mut dict = TaggedDictBuilder::with_capacity(&tag, 6);
dict.insert_untagged(
"device",
value::string(
part.device()
.unwrap_or_else(|| OsStr::new("N/A"))
.to_string_lossy(),
),
);
dict.insert_untagged("type", value::string(part.file_system().as_str()));
dict.insert_untagged("mount", value::string(part.mount_point().to_string_lossy()));
if let Ok(usage) = disk::usage(part.mount_point().to_path_buf()).await {
dict.insert_untagged(
"total",
value::bytes(usage.total().get::<information::byte>()),
);
dict.insert_untagged(
"used",
value::bytes(usage.used().get::<information::byte>()),
);
dict.insert_untagged(
"free",
value::bytes(usage.free().get::<information::byte>()),
);
}
output.push(dict.into_value());
}
}
if !output.is_empty() {
Some(UntaggedValue::Table(output))
} else {
None
}
}
async fn battery(tag: Tag) -> Option<UntaggedValue> {
let mut output = vec![];
if let Ok(manager) = battery::Manager::new() {
if let Ok(batteries) = manager.batteries() {
for battery in batteries {
if let Ok(battery) = battery {
let mut dict = TaggedDictBuilder::new(&tag);
if let Some(vendor) = battery.vendor() {
dict.insert_untagged("vendor", value::string(vendor));
}
if let Some(model) = battery.model() {
dict.insert_untagged("model", value::string(model));
}
if let Some(cycles) = battery.cycle_count() {
dict.insert_untagged("cycles", value::int(cycles));
}
if let Some(time_to_full) = battery.time_to_full() {
dict.insert_untagged(
"mins to full",
value::number(time_to_full.get::<battery::units::time::minute>()),
);
}
if let Some(time_to_empty) = battery.time_to_empty() {
dict.insert_untagged(
"mins to empty",
value::number(time_to_empty.get::<battery::units::time::minute>()),
);
}
output.push(dict.into_value());
}
}
}
}
if !output.is_empty() {
Some(UntaggedValue::Table(output))
} else {
None
}
}
async fn temp(tag: Tag) -> Option<UntaggedValue> {
let mut output = vec![];
let mut sensors = sensors::temperatures();
while let Some(sensor) = sensors.next().await {
if let Ok(sensor) = sensor {
let mut dict = TaggedDictBuilder::new(&tag);
dict.insert_untagged("unit", value::string(sensor.unit()));
if let Some(label) = sensor.label() {
dict.insert_untagged("label", value::string(label));
}
dict.insert_untagged(
"temp",
value::number(
sensor
.current()
.get::<thermodynamic_temperature::degree_celsius>(),
),
);
if let Some(high) = sensor.high() {
dict.insert_untagged(
"high",
value::number(high.get::<thermodynamic_temperature::degree_celsius>()),
);
}
if let Some(critical) = sensor.critical() {
dict.insert_untagged(
"critical",
value::number(critical.get::<thermodynamic_temperature::degree_celsius>()),
);
}
output.push(dict.into_value());
}
}
if !output.is_empty() {
Some(UntaggedValue::Table(output))
} else {
None
}
}
async fn net(tag: Tag) -> Option<UntaggedValue> {
let mut output = vec![];
let mut io_counters = net::io_counters();
while let Some(nic) = io_counters.next().await {
if let Ok(nic) = nic {
let mut network_idx = TaggedDictBuilder::with_capacity(&tag, 3);
network_idx.insert_untagged("name", value::string(nic.interface()));
network_idx.insert_untagged(
"sent",
value::bytes(nic.bytes_sent().get::<information::byte>()),
);
network_idx.insert_untagged(
"recv",
value::bytes(nic.bytes_recv().get::<information::byte>()),
);
output.push(network_idx.into_value());
}
}
if !output.is_empty() {
Some(UntaggedValue::Table(output))
} else {
None
}
}
async fn sysinfo(tag: Tag) -> Vec<Value> {
let mut sysinfo = TaggedDictBuilder::with_capacity(&tag, 7);
let (host, cpu, disks, memory, temp) = futures::future::join5(
host(tag.clone()),
cpu(tag.clone()),
disks(tag.clone()),
mem(tag.clone()),
temp(tag.clone()),
)
.await;
let (net, battery) = futures::future::join(net(tag.clone()), battery(tag.clone())).await;
sysinfo.insert_value("host", host);
if let Some(cpu) = cpu {
sysinfo.insert_value("cpu", cpu);
}
if let Some(disks) = disks {
sysinfo.insert_untagged("disks", disks);
}
sysinfo.insert_value("mem", memory);
if let Some(temp) = temp {
sysinfo.insert_untagged("temp", temp);
}
if let Some(net) = net {
sysinfo.insert_untagged("net", net);
}
if let Some(battery) = battery {
sysinfo.insert_untagged("battery", battery);
}
vec![sysinfo.into_value()]
}
impl Plugin for Sys {
fn config(&mut self) -> Result<Signature, ShellError> {
Ok(Signature::build("sys")
.desc("View information about the current system.")
.filter())
}
fn begin_filter(&mut self, callinfo: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
Ok(block_on(sysinfo(callinfo.name_tag))
.into_iter()
.map(ReturnSuccess::value)
.collect())
}
fn filter(&mut self, _: Value) -> Result<Vec<ReturnValue>, ShellError> {
Ok(vec![])
}
}
fn main() {
serve_plugin(&mut Sys::new());
}