Move sys, ps, fetch, post to internal commands (#3983)

* Move sys, ps, fetch, post to internal commands

* Remove old plugins

* clippy

Co-authored-by: JT <jonatha.d.turner@gmail.com>
This commit is contained in:
JT 2021-09-01 14:29:09 +12:00 committed by GitHub
parent 66cedf0b3a
commit 08014c6a98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 549 additions and 779 deletions

97
Cargo.lock generated
View File

@ -1397,12 +1397,6 @@ version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2"
[[package]]
name = "futures-timer"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
[[package]]
name = "futures-util"
version = "0.3.16"
@ -2444,18 +2438,14 @@ dependencies = [
"nu-value-ext",
"nu_plugin_binaryview",
"nu_plugin_chart",
"nu_plugin_fetch",
"nu_plugin_from_bson",
"nu_plugin_from_sqlite",
"nu_plugin_inc",
"nu_plugin_match",
"nu_plugin_post",
"nu_plugin_ps",
"nu_plugin_query_json",
"nu_plugin_s3",
"nu_plugin_selector",
"nu_plugin_start",
"nu_plugin_sys",
"nu_plugin_textview",
"nu_plugin_to_bson",
"nu_plugin_to_sqlite",
@ -2542,6 +2532,7 @@ dependencies = [
"log",
"md-5",
"meval",
"mime",
"minus",
"nu-ansi-term",
"nu-data",
@ -2572,6 +2563,7 @@ dependencies = [
"rand 0.8.4",
"rayon",
"regex",
"reqwest",
"roxmltree",
"rusqlite",
"rust-embed",
@ -2587,12 +2579,14 @@ dependencies = [
"strip-ansi-escapes",
"sxd-document",
"sxd-xpath",
"sysinfo",
"tempfile",
"term 0.7.0",
"term_size",
"termcolor",
"thiserror",
"titlecase",
"tokio",
"toml",
"trash",
"umask",
@ -2927,22 +2921,6 @@ dependencies = [
"tui",
]
[[package]]
name = "nu_plugin_fetch"
version = "0.36.1"
dependencies = [
"base64",
"futures 0.3.16",
"mime",
"nu-errors",
"nu-plugin",
"nu-protocol",
"nu-source",
"reqwest",
"tokio",
"url",
]
[[package]]
name = "nu_plugin_from_bson"
version = "0.36.1"
@ -3008,38 +2986,6 @@ dependencies = [
"regex",
]
[[package]]
name = "nu_plugin_post"
version = "0.36.1"
dependencies = [
"base64",
"futures 0.3.16",
"mime",
"nu-errors",
"nu-plugin",
"nu-protocol",
"nu-source",
"num-traits",
"reqwest",
"serde_json",
"tokio",
"url",
]
[[package]]
name = "nu_plugin_ps"
version = "0.36.1"
dependencies = [
"futures 0.3.16",
"futures-timer",
"nu-errors",
"nu-plugin",
"nu-protocol",
"nu-source",
"num-bigint 0.3.2",
"sysinfo 0.16.5",
]
[[package]]
name = "nu_plugin_query_json"
version = "0.36.1"
@ -3090,20 +3036,6 @@ dependencies = [
"webbrowser",
]
[[package]]
name = "nu_plugin_sys"
version = "0.36.1"
dependencies = [
"futures 0.3.16",
"futures-util",
"nu-errors",
"nu-plugin",
"nu-protocol",
"nu-source",
"num-bigint 0.3.2",
"sysinfo 0.18.2",
]
[[package]]
name = "nu_plugin_textview"
version = "0.36.1"
@ -4948,29 +4880,12 @@ dependencies = [
[[package]]
name = "sysinfo"
version = "0.16.5"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567e910ef0207be81a4e1bb0491e9a8d9866cf45b20fe1a52c03d347da9ea51b"
checksum = "42ef9905d4f98c059046037078f070e66de0f5ac69e5bb63f6bf805b570b3b51"
dependencies = [
"cfg-if 1.0.0",
"core-foundation-sys",
"doc-comment",
"libc",
"ntapi",
"once_cell",
"rayon",
"winapi 0.3.9",
]
[[package]]
name = "sysinfo"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d404aefa651a24a7f2a1190fec9fb6380ba84ac511a6fefad79eb0e63d39a97d"
dependencies = [
"cfg-if 1.0.0",
"core-foundation-sys",
"doc-comment",
"libc",
"ntapi",
"once_cell",

View File

@ -33,18 +33,14 @@ nu-value-ext = { version = "0.36.1", path="./crates/nu-value-ext" }
nu_plugin_binaryview = { version = "0.36.1", path="./crates/nu_plugin_binaryview", optional=true }
nu_plugin_chart = { version = "0.36.1", path="./crates/nu_plugin_chart", optional=true }
nu_plugin_fetch = { version = "0.36.1", path="./crates/nu_plugin_fetch", optional=true }
nu_plugin_from_bson = { version = "0.36.1", path="./crates/nu_plugin_from_bson", optional=true }
nu_plugin_from_sqlite = { version = "0.36.1", path="./crates/nu_plugin_from_sqlite", optional=true }
nu_plugin_inc = { version = "0.36.1", path="./crates/nu_plugin_inc", optional=true }
nu_plugin_match = { version = "0.36.1", path="./crates/nu_plugin_match", optional=true }
nu_plugin_post = { version = "0.36.1", path="./crates/nu_plugin_post", optional=true }
nu_plugin_ps = { version = "0.36.1", path="./crates/nu_plugin_ps", optional=true }
nu_plugin_query_json = { version = "0.36.1", path="./crates/nu_plugin_query_json", optional=true }
nu_plugin_s3 = { version = "0.36.1", path="./crates/nu_plugin_s3", optional=true }
nu_plugin_selector = { version = "0.36.1", path="./crates/nu_plugin_selector", optional=true }
nu_plugin_start = { version = "0.36.1", path="./crates/nu_plugin_start", optional=true }
nu_plugin_sys = { version = "0.36.1", path="./crates/nu_plugin_sys", optional=true }
nu_plugin_textview = { version = "0.36.1", path="./crates/nu_plugin_textview", optional=true }
nu_plugin_to_bson = { version = "0.36.1", path="./crates/nu_plugin_to_bson", optional=true }
nu_plugin_to_sqlite = { version = "0.36.1", path="./crates/nu_plugin_to_sqlite", optional=true }
@ -65,6 +61,8 @@ rstest = "0.10.0"
[build-dependencies]
[features]
fetch-support = ["nu-command/fetch", "nu-command/post"]
sys-support = ["nu-command/sys", "nu-command/ps"]
ctrlc-support = ["nu-cli/ctrlc", "nu-command/ctrlc"]
rustyline-support = ["nu-cli/rustyline-support", "nu-command/rustyline-support"]
term-support = ["nu-command/term"]
@ -73,15 +71,13 @@ which-support = ["nu-command/which", "nu-engine/which"]
default = [
"nu-cli/shadow-rs",
"sys",
"ps",
"sys-support",
"ctrlc-support",
"which-support",
"term-support",
"rustyline-support",
"match",
"post",
"fetch",
"fetch-support",
"zip-support",
"dataframe",
]
@ -109,12 +105,8 @@ extra = [
wasi = ["inc", "match", "match", "tree", "rustyline-support"]
# Stable (Default)
fetch = ["nu_plugin_fetch"]
inc = ["nu_plugin_inc"]
match = ["nu_plugin_match"]
post = ["nu_plugin_post"]
ps = ["nu_plugin_ps"]
sys = ["nu_plugin_sys"]
textview = ["nu_plugin_textview"]
# Extra
@ -145,7 +137,6 @@ dataframe = [
"nu-command/dataframe",
"nu-value-ext/dataframe",
"nu-data/dataframe",
"nu_plugin_post/dataframe",
"nu_plugin_to_bson/dataframe",
]
@ -165,31 +156,11 @@ name = "nu_plugin_core_inc"
path = "src/plugins/nu_plugin_core_inc.rs"
required-features = ["inc"]
[[bin]]
name = "nu_plugin_core_ps"
path = "src/plugins/nu_plugin_core_ps.rs"
required-features = ["ps"]
[[bin]]
name = "nu_plugin_core_sys"
path = "src/plugins/nu_plugin_core_sys.rs"
required-features = ["sys"]
[[bin]]
name = "nu_plugin_core_fetch"
path = "src/plugins/nu_plugin_core_fetch.rs"
required-features = ["fetch"]
[[bin]]
name = "nu_plugin_core_match"
path = "src/plugins/nu_plugin_core_match.rs"
required-features = ["match"]
[[bin]]
name = "nu_plugin_core_post"
path = "src/plugins/nu_plugin_core_post.rs"
required-features = ["post"]
# Extra plugins
[[bin]]

View File

@ -28,6 +28,8 @@ nu-value-ext = { version = "0.36.1", path="../nu-value-ext" }
nu-ansi-term = { version = "0.36.1", path="../nu-ansi-term" }
nu-pretty-hex = { version = "0.36.1", path="../nu-pretty-hex" }
url = "2.2.1"
mime = "0.3.16"
Inflector = "0.11"
arboard = { version="1.1.0", optional=true }
base64 = "0.13.0"
@ -71,6 +73,7 @@ quick-xml = "0.22"
rand = "0.8"
rayon = "1.5.0"
regex = "1.4.3"
reqwest = {version = "0.11", optional = true }
roxmltree = "0.14.0"
rust-embed = "5.9.0"
rustyline = { version="9.0.0", optional=true }
@ -84,16 +87,17 @@ sha2 = "0.9.3"
strip-ansi-escapes = "0.1.0"
sxd-document = "0.3.2"
sxd-xpath = "0.4.2"
sysinfo = { version = "0.20.2", optional = true }
thiserror = "1.0.26"
tempfile = "3.2.0"
term = { version="0.7.0", optional=true }
term_size = "0.3.2"
termcolor = "1.1.2"
titlecase = "1.1.0"
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
toml = "0.5.8"
trash = { version="1.3.0", optional=true }
unicode-segmentation = "1.8"
url = "2.2.0"
uuid_crate = { package="uuid", version="0.8.2", features=["v4"], optional=true }
which = { version="4.1.0", optional=true }
zip = { version="0.5.9", optional=true }
@ -134,3 +138,7 @@ stable = []
trash-support = ["trash"]
table-pager = ["minus", "crossterm"]
dataframe = ["nu-protocol/dataframe", "polars"]
fetch = ["reqwest", "tokio"]
post = ["reqwest", "tokio"]
sys = ["sysinfo"]
ps = ["sysinfo"]

View File

@ -17,6 +17,7 @@ mod platform;
mod random;
mod shells;
mod strings;
mod system;
mod viewers;
pub use charting::*;
@ -55,6 +56,7 @@ pub use platform::*;
pub use random::*;
pub use shells::*;
pub use strings::*;
pub use system::*;
pub use viewers::*;
#[cfg(test)]

View File

@ -1,10 +1,92 @@
use crate::prelude::*;
use base64::encode;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{CallInfo, CommandAction, ReturnSuccess, ReturnValue, UntaggedValue, Value};
use nu_protocol::{CommandAction, ReturnSuccess, ReturnValue, Value};
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
use nu_source::{AnchorLocation, Span, Tag};
use std::path::PathBuf;
use std::str::FromStr;
pub struct Command;
impl WholeStreamCommand for Command {
fn name(&self) -> &str {
"fetch"
}
fn signature(&self) -> Signature {
Signature::build("fetch")
.desc("Load from a URL into a cell, convert to table if possible (avoid by appending '--raw').")
.required(
"URL",
SyntaxShape::String,
"the URL to fetch the contents from",
)
.named(
"user",
SyntaxShape::Any,
"the username when authenticating",
Some('u'),
)
.named(
"password",
SyntaxShape::Any,
"the password when authenticating",
Some('p'),
)
.switch("raw", "fetch contents as text rather than a table", Some('r'))
.filter()
}
fn usage(&self) -> &str {
"Fetch the contents from a URL (HTTP GET operation)."
}
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
run_fetch(args)
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Fetch content from url.com",
example: "fetch url.com",
result: None,
},
Example {
description: "Fetch content from url.com, with username and password",
example: "fetch -u myuser -p mypass url.com",
result: None,
},
]
}
}
fn run_fetch(args: CommandArgs) -> Result<ActionStream, ShellError> {
let mut fetch_helper = Fetch::new();
fetch_helper.setup(args)?;
let runtime = tokio::runtime::Runtime::new()?;
Ok(vec![runtime.block_on(fetch(
&fetch_helper.path.clone().ok_or_else(|| {
ShellError::labeled_error(
"internal error: path not set",
"path not set",
&fetch_helper.tag,
)
})?,
fetch_helper.has_raw,
fetch_helper.user.clone(),
fetch_helper.password,
))]
.into_iter()
.into_action_stream())
//fetch.setup(callinfo)?;
}
#[derive(Default)]
pub struct Fetch {
pub path: Option<Value>,
@ -25,32 +107,25 @@ impl Fetch {
}
}
pub fn setup(&mut self, call_info: CallInfo) -> ReturnValue {
pub fn setup(&mut self, args: CommandArgs) -> Result<(), ShellError> {
self.path = Some({
let file = call_info.args.nth(0).ok_or_else(|| {
args.req(0).map_err(|_| {
ShellError::labeled_error(
"No file or directory specified",
"for command",
&call_info.name_tag,
&args.name_tag(),
)
})?;
file.clone()
})?
});
self.tag = call_info.name_tag.clone();
self.tag = args.name_tag();
self.has_raw = call_info.args.has("raw");
self.has_raw = args.has_flag("raw");
self.user = match call_info.args.get("user") {
Some(user) => Some(user.as_string()?),
None => None,
};
self.user = args.get_flag("user")?;
self.password = match call_info.args.get("password") {
Some(password) => Some(password.as_string()?),
None => None,
};
self.password = args.get_flag("password")?;
ReturnSuccess::value(UntaggedValue::nothing().into_untagged_value())
Ok(())
}
}

View File

@ -1,3 +1,12 @@
mod url_;
#[cfg(feature = "fetch")]
mod fetch;
#[cfg(feature = "fetch")]
pub use fetch::Command as Fetch;
#[cfg(feature = "post")]
mod post;
#[cfg(feature = "post")]
pub use post::Command as Post;
mod url_;
pub use url_::*;

View File

@ -1,15 +1,109 @@
use crate::prelude::*;
use base64::encode;
use mime::Mime;
use nu_engine::WholeStreamCommand;
use nu_errors::{CoerceInto, ShellError};
use nu_protocol::{
CallInfo, CommandAction, Primitive, ReturnSuccess, ReturnValue, UnspannedPathMember,
UntaggedValue, Value,
CommandAction, Primitive, ReturnSuccess, ReturnValue, UnspannedPathMember, UntaggedValue, Value,
};
use nu_protocol::{Signature, SyntaxShape};
use nu_source::{AnchorLocation, Tag, TaggedItem};
use num_traits::cast::ToPrimitive;
use std::path::PathBuf;
use std::str::FromStr;
pub struct Command;
impl WholeStreamCommand for Command {
fn name(&self) -> &str {
"post"
}
fn signature(&self) -> Signature {
Signature::build("post")
.desc("Post content to a URL and retrieve data as a table if possible.")
.required("path", SyntaxShape::Any, "the URL to post to")
.required("body", SyntaxShape::Any, "the contents of the post body")
.named(
"user",
SyntaxShape::Any,
"the username when authenticating",
Some('u'),
)
.named(
"password",
SyntaxShape::Any,
"the password when authenticating",
Some('p'),
)
.named(
"content-type",
SyntaxShape::Any,
"the MIME type of content to post",
Some('t'),
)
.named(
"content-length",
SyntaxShape::Any,
"the length of the content being posted",
Some('l'),
)
.switch(
"raw",
"return values as a string instead of a table",
Some('r'),
)
.filter()
}
fn usage(&self) -> &str {
"Post a body to a URL (HTTP POST operation)."
}
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
run_post(args)
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Post content to url.com",
example: "post url.com 'body'",
result: None,
},
Example {
description: "Post content to url.com, with username and password",
example: "post -u myuser -p mypass url.com 'body'",
result: None,
},
]
}
}
fn run_post(args: CommandArgs) -> Result<ActionStream, ShellError> {
let mut helper = Post::new();
helper.setup(args)?;
let runtime = tokio::runtime::Runtime::new()?;
Ok(vec![runtime.block_on(post_helper(
&helper.path.clone().ok_or_else(|| {
ShellError::labeled_error("expected a 'path'", "expected a 'path'", &helper.tag)
})?,
helper.has_raw,
&helper.body.clone().ok_or_else(|| {
ShellError::labeled_error("expected a 'body'", "expected a 'body'", &helper.tag)
})?,
helper.user.clone(),
helper.password.clone(),
&helper.headers,
))]
.into_iter()
.into_action_stream())
//fetch.setup(callinfo)?;
}
#[derive(Clone)]
pub enum HeaderKind {
ContentType(String),
@ -40,42 +134,35 @@ impl Post {
}
}
pub fn setup(&mut self, call_info: CallInfo) -> ReturnValue {
pub fn setup(&mut self, args: CommandArgs) -> Result<(), ShellError> {
self.path = Some({
let file = call_info.args.nth(0).ok_or_else(|| {
args.req(0).map_err(|_| {
ShellError::labeled_error(
"No file or directory specified",
"for command",
&call_info.name_tag,
&args.name_tag(),
)
})?;
file.clone()
})?
});
self.has_raw = call_info.args.has("raw");
self.body = {
let file = call_info.args.nth(1).ok_or_else(|| {
ShellError::labeled_error("No body specified", "for command", &call_info.name_tag)
let file = args.req(1).map_err(|_| {
ShellError::labeled_error("No body specified", "for command", &args.name_tag())
})?;
Some(file.clone())
Some(file)
};
self.user = match call_info.args.get("user") {
Some(user) => Some(user.as_string()?),
None => None,
};
self.tag = args.name_tag();
self.password = match call_info.args.get("password") {
Some(password) => Some(password.as_string()?),
None => None,
};
self.has_raw = args.has_flag("raw");
self.headers = get_headers(&call_info)?;
self.user = args.get_flag("user")?;
self.tag = call_info.name_tag;
self.password = args.get_flag("password")?;
ReturnSuccess::value(UntaggedValue::nothing().into_untagged_value())
self.headers = get_headers(&args)?;
Ok(())
}
}
@ -465,10 +552,10 @@ fn json_list(input: &[Value]) -> Result<Vec<serde_json::Value>, ShellError> {
Ok(out)
}
fn get_headers(call_info: &CallInfo) -> Result<Vec<HeaderKind>, ShellError> {
fn get_headers(args: &CommandArgs) -> Result<Vec<HeaderKind>, ShellError> {
let mut headers = vec![];
match extract_header_value(call_info, "content-type") {
match extract_header_value(args, "content-type") {
Ok(h) => {
if let Some(ct) = h {
headers.push(HeaderKind::ContentType(ct))
@ -479,7 +566,7 @@ fn get_headers(call_info: &CallInfo) -> Result<Vec<HeaderKind>, ShellError> {
}
};
match extract_header_value(call_info, "content-length") {
match extract_header_value(args, "content-length") {
Ok(h) => {
if let Some(cl) = h {
headers.push(HeaderKind::ContentLength(cl))
@ -493,14 +580,14 @@ fn get_headers(call_info: &CallInfo) -> Result<Vec<HeaderKind>, ShellError> {
Ok(headers)
}
fn extract_header_value(call_info: &CallInfo, key: &str) -> Result<Option<String>, ShellError> {
if call_info.args.has(key) {
let tagged = call_info.args.get(key);
fn extract_header_value(args: &CommandArgs, key: &str) -> Result<Option<String>, ShellError> {
if args.has_flag(key) {
let tagged = args.get_flag(key)?;
let val = match tagged {
Some(Value {
value: UntaggedValue::Primitive(Primitive::String(s)),
..
}) => s.clone(),
}) => s,
Some(Value { tag, .. }) => {
return Err(ShellError::labeled_error(
format!("{} not in expected format. Expected string.", key),

View File

@ -0,0 +1,9 @@
#[cfg(feature = "ps")]
mod ps;
#[cfg(feature = "ps")]
pub use ps::Command as Ps;
#[cfg(feature = "sys")]
mod sys;
#[cfg(feature = "sys")]
pub use sys::Command as Sys;

View File

@ -1,28 +1,55 @@
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{TaggedDictBuilder, UntaggedValue, Value};
use nu_source::Tag;
use nu_protocol::{Signature, TaggedDictBuilder, UntaggedValue};
use sysinfo::{ProcessExt, System, SystemExt};
#[derive(Default)]
pub struct Ps;
pub struct Command;
impl Ps {
pub fn new() -> Ps {
Ps
impl WholeStreamCommand for Command {
fn name(&self) -> &str {
"ps"
}
fn signature(&self) -> Signature {
Signature::build("ps")
.desc("View information about system processes.")
.switch(
"long",
"list all available columns for each entry",
Some('l'),
)
.filter()
}
fn usage(&self) -> &str {
"View information about system processes."
}
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
run_ps(args)
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "List the system processes",
example: "ps",
result: None,
}]
}
}
pub async fn ps(tag: Tag, long: bool) -> Result<Vec<Value>, ShellError> {
fn run_ps(args: CommandArgs) -> Result<OutputStream, ShellError> {
let long = args.has_flag("long");
let mut sys = System::new_all();
sys.refresh_all();
let mut output = vec![];
let result: Vec<_> = sys.get_processes().iter().map(|x| *x.0).collect();
let result: Vec<_> = sys.processes().iter().map(|x| *x.0).collect();
for pid in result.into_iter() {
if let Some(result) = sys.get_process(pid) {
let mut dict = TaggedDictBuilder::new(&tag);
if let Some(result) = sys.process(pid) {
let mut dict = TaggedDictBuilder::new(args.name_tag());
dict.insert_untagged("pid", UntaggedValue::int(pid as i64));
dict.insert_untagged("name", UntaggedValue::string(result.name()));
dict.insert_untagged(
@ -31,7 +58,7 @@ pub async fn ps(tag: Tag, long: bool) -> Result<Vec<Value>, ShellError> {
);
dict.insert_untagged(
"cpu",
UntaggedValue::decimal_from_float(result.cpu_usage() as f64, tag.span),
UntaggedValue::decimal_from_float(result.cpu_usage() as f64, args.name_tag().span),
);
dict.insert_untagged("mem", UntaggedValue::filesize(result.memory() * 1000));
dict.insert_untagged(
@ -53,5 +80,5 @@ pub async fn ps(tag: Tag, long: bool) -> Result<Vec<Value>, ShellError> {
}
}
Ok(output)
Ok(output.into_iter().into_output_stream())
}

View File

@ -1,204 +1,40 @@
use nu_protocol::{TaggedDictBuilder, UntaggedValue, Value};
use nu_source::Tag;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{Signature, TaggedDictBuilder, UntaggedValue};
use sysinfo::{ComponentExt, DiskExt, NetworkExt, ProcessorExt, System, SystemExt, UserExt};
#[derive(Default)]
pub struct Sys;
pub struct Command;
impl Sys {
pub fn new() -> Sys {
Sys
impl WholeStreamCommand for Command {
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, args: CommandArgs) -> Result<OutputStream, ShellError> {
run_sys(args)
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Show info about the system",
example: "sys",
result: None,
}]
}
}
pub fn disks(sys: &mut System, tag: Tag) -> Option<UntaggedValue> {
sys.refresh_disks();
sys.refresh_disks_list();
let mut output = vec![];
for disk in sys.get_disks() {
let mut dict = TaggedDictBuilder::new(&tag);
dict.insert_untagged(
"device",
UntaggedValue::string(trim_cstyle_null(
disk.get_name().to_string_lossy().to_string(),
)),
);
dict.insert_untagged(
"type",
UntaggedValue::string(trim_cstyle_null(
String::from_utf8_lossy(disk.get_file_system()).to_string(),
)),
);
dict.insert_untagged("mount", UntaggedValue::filepath(disk.get_mount_point()));
dict.insert_untagged("total", UntaggedValue::filesize(disk.get_total_space()));
dict.insert_untagged("free", UntaggedValue::filesize(disk.get_available_space()));
output.push(dict.into_value());
}
if !output.is_empty() {
Some(UntaggedValue::Table(output))
} else {
None
}
}
pub fn net(sys: &mut System, tag: Tag) -> Option<UntaggedValue> {
sys.refresh_networks();
sys.refresh_networks_list();
let mut output = vec![];
for (iface, data) in sys.get_networks() {
let mut dict = TaggedDictBuilder::new(&tag);
dict.insert_untagged(
"name",
UntaggedValue::string(trim_cstyle_null(iface.to_string())),
);
dict.insert_untagged(
"sent",
UntaggedValue::filesize(data.get_total_transmitted()),
);
dict.insert_untagged("recv", UntaggedValue::filesize(data.get_total_received()));
output.push(dict.into_value());
}
if !output.is_empty() {
Some(UntaggedValue::Table(output))
} else {
None
}
}
pub fn cpu(sys: &mut System, tag: Tag) -> Option<UntaggedValue> {
sys.refresh_cpu();
let mut output = vec![];
for cpu in sys.get_processors() {
let mut dict = TaggedDictBuilder::new(&tag);
dict.insert_untagged(
"name",
UntaggedValue::string(trim_cstyle_null(cpu.get_name().to_string())),
);
dict.insert_untagged(
"brand",
UntaggedValue::string(trim_cstyle_null(cpu.get_brand().to_string())),
);
dict.insert_untagged("freq", UntaggedValue::int(cpu.get_frequency() as i64));
output.push(dict.into_value());
}
if !output.is_empty() {
Some(UntaggedValue::Table(output))
} else {
None
}
}
pub fn mem(sys: &mut System, tag: Tag) -> Option<UntaggedValue> {
sys.refresh_memory();
let mut dict = TaggedDictBuilder::new(tag);
let total_mem = sys.get_total_memory();
let free_mem = sys.get_free_memory();
let total_swap = sys.get_total_swap();
let free_swap = sys.get_free_swap();
dict.insert_untagged("total", UntaggedValue::filesize(total_mem * 1000));
dict.insert_untagged("free", UntaggedValue::filesize(free_mem * 1000));
dict.insert_untagged("swap total", UntaggedValue::filesize(total_swap * 1000));
dict.insert_untagged("swap free", UntaggedValue::filesize(free_swap * 1000));
Some(dict.into_untagged_value())
}
pub fn host(sys: &mut System, tag: Tag) -> Option<UntaggedValue> {
sys.refresh_users_list();
let mut dict = TaggedDictBuilder::new(&tag);
if let Some(name) = sys.get_name() {
dict.insert_untagged("name", UntaggedValue::string(trim_cstyle_null(name)));
}
if let Some(version) = sys.get_os_version() {
dict.insert_untagged(
"os version",
UntaggedValue::string(trim_cstyle_null(version)),
);
}
if let Some(version) = sys.get_kernel_version() {
dict.insert_untagged(
"kernel version",
UntaggedValue::string(trim_cstyle_null(version)),
);
}
if let Some(hostname) = sys.get_host_name() {
dict.insert_untagged(
"hostname",
UntaggedValue::string(trim_cstyle_null(hostname)),
);
}
dict.insert_untagged(
"uptime",
UntaggedValue::duration(1000000000 * sys.get_uptime() as i64),
);
let mut users = vec![];
for user in sys.get_users() {
let mut user_dict = TaggedDictBuilder::new(&tag);
user_dict.insert_untagged(
"name",
UntaggedValue::string(trim_cstyle_null(user.get_name().to_string())),
);
let mut groups = vec![];
for group in user.get_groups() {
groups
.push(UntaggedValue::string(trim_cstyle_null(group.to_string())).into_value(&tag));
}
user_dict.insert_untagged("groups", UntaggedValue::Table(groups));
users.push(user_dict.into_value());
}
if !users.is_empty() {
dict.insert_untagged("sessions", UntaggedValue::Table(users));
}
Some(dict.into_untagged_value())
}
pub fn temp(sys: &mut System, tag: Tag) -> Option<UntaggedValue> {
sys.refresh_components();
sys.refresh_components_list();
let mut output = vec![];
for component in sys.get_components() {
let mut dict = TaggedDictBuilder::new(&tag);
dict.insert_untagged("unit", UntaggedValue::string(component.get_label()));
dict.insert_untagged(
"temp",
UntaggedValue::decimal_from_float(component.get_temperature() as f64, tag.span),
);
dict.insert_untagged(
"high",
UntaggedValue::decimal_from_float(component.get_max() as f64, tag.span),
);
if let Some(critical) = component.get_critical() {
dict.insert_untagged(
"critical",
UntaggedValue::decimal_from_float(critical as f64, tag.span),
);
}
output.push(dict.into_value());
}
if !output.is_empty() {
Some(UntaggedValue::Table(output))
} else {
None
}
}
pub async fn sysinfo(tag: Tag) -> Vec<Value> {
fn run_sys(args: CommandArgs) -> Result<OutputStream, ShellError> {
let tag = args.name_tag();
let mut sys = System::new();
let mut sysinfo = TaggedDictBuilder::with_capacity(&tag, 6);
@ -222,9 +58,191 @@ pub async fn sysinfo(tag: Tag) -> Vec<Value> {
sysinfo.insert_value("net", net);
}
vec![sysinfo.into_value()]
Ok(vec![sysinfo.into_value()].into_iter().into_output_stream())
}
pub fn trim_cstyle_null(s: String) -> String {
s.trim_matches(char::from(0)).to_string()
}
pub fn disks(sys: &mut System, tag: Tag) -> Option<UntaggedValue> {
sys.refresh_disks();
sys.refresh_disks_list();
let mut output = vec![];
for disk in sys.disks() {
let mut dict = TaggedDictBuilder::new(&tag);
dict.insert_untagged(
"device",
UntaggedValue::string(trim_cstyle_null(disk.name().to_string_lossy().to_string())),
);
dict.insert_untagged(
"type",
UntaggedValue::string(trim_cstyle_null(
String::from_utf8_lossy(disk.file_system()).to_string(),
)),
);
dict.insert_untagged("mount", UntaggedValue::filepath(disk.mount_point()));
dict.insert_untagged("total", UntaggedValue::filesize(disk.total_space()));
dict.insert_untagged("free", UntaggedValue::filesize(disk.available_space()));
output.push(dict.into_value());
}
if !output.is_empty() {
Some(UntaggedValue::Table(output))
} else {
None
}
}
pub fn net(sys: &mut System, tag: Tag) -> Option<UntaggedValue> {
sys.refresh_networks();
sys.refresh_networks_list();
let mut output = vec![];
for (iface, data) in sys.networks() {
let mut dict = TaggedDictBuilder::new(&tag);
dict.insert_untagged(
"name",
UntaggedValue::string(trim_cstyle_null(iface.to_string())),
);
dict.insert_untagged("sent", UntaggedValue::filesize(data.total_transmitted()));
dict.insert_untagged("recv", UntaggedValue::filesize(data.total_received()));
output.push(dict.into_value());
}
if !output.is_empty() {
Some(UntaggedValue::Table(output))
} else {
None
}
}
pub fn cpu(sys: &mut System, tag: Tag) -> Option<UntaggedValue> {
sys.refresh_cpu();
let mut output = vec![];
for cpu in sys.processors() {
let mut dict = TaggedDictBuilder::new(&tag);
dict.insert_untagged(
"name",
UntaggedValue::string(trim_cstyle_null(cpu.name().to_string())),
);
dict.insert_untagged(
"brand",
UntaggedValue::string(trim_cstyle_null(cpu.brand().to_string())),
);
dict.insert_untagged("freq", UntaggedValue::int(cpu.frequency() as i64));
output.push(dict.into_value());
}
if !output.is_empty() {
Some(UntaggedValue::Table(output))
} else {
None
}
}
pub fn mem(sys: &mut System, tag: Tag) -> Option<UntaggedValue> {
sys.refresh_memory();
let mut dict = TaggedDictBuilder::new(tag);
let total_mem = sys.total_memory();
let free_mem = sys.free_memory();
let total_swap = sys.total_swap();
let free_swap = sys.free_swap();
dict.insert_untagged("total", UntaggedValue::filesize(total_mem * 1000));
dict.insert_untagged("free", UntaggedValue::filesize(free_mem * 1000));
dict.insert_untagged("swap total", UntaggedValue::filesize(total_swap * 1000));
dict.insert_untagged("swap free", UntaggedValue::filesize(free_swap * 1000));
Some(dict.into_untagged_value())
}
pub fn host(sys: &mut System, tag: Tag) -> Option<UntaggedValue> {
sys.refresh_users_list();
let mut dict = TaggedDictBuilder::new(&tag);
if let Some(name) = sys.name() {
dict.insert_untagged("name", UntaggedValue::string(trim_cstyle_null(name)));
}
if let Some(version) = sys.os_version() {
dict.insert_untagged(
"os version",
UntaggedValue::string(trim_cstyle_null(version)),
);
}
if let Some(version) = sys.kernel_version() {
dict.insert_untagged(
"kernel version",
UntaggedValue::string(trim_cstyle_null(version)),
);
}
if let Some(hostname) = sys.host_name() {
dict.insert_untagged(
"hostname",
UntaggedValue::string(trim_cstyle_null(hostname)),
);
}
dict.insert_untagged(
"uptime",
UntaggedValue::duration(1000000000 * sys.uptime() as i64),
);
let mut users = vec![];
for user in sys.users() {
let mut user_dict = TaggedDictBuilder::new(&tag);
user_dict.insert_untagged(
"name",
UntaggedValue::string(trim_cstyle_null(user.name().to_string())),
);
let mut groups = vec![];
for group in user.groups() {
groups
.push(UntaggedValue::string(trim_cstyle_null(group.to_string())).into_value(&tag));
}
user_dict.insert_untagged("groups", UntaggedValue::Table(groups));
users.push(user_dict.into_value());
}
if !users.is_empty() {
dict.insert_untagged("sessions", UntaggedValue::Table(users));
}
Some(dict.into_untagged_value())
}
pub fn temp(sys: &mut System, tag: Tag) -> Option<UntaggedValue> {
sys.refresh_components();
sys.refresh_components_list();
let mut output = vec![];
for component in sys.components() {
let mut dict = TaggedDictBuilder::new(&tag);
dict.insert_untagged("unit", UntaggedValue::string(component.label()));
dict.insert_untagged(
"temp",
UntaggedValue::decimal_from_float(component.temperature() as f64, tag.span),
);
dict.insert_untagged(
"high",
UntaggedValue::decimal_from_float(component.max() as f64, tag.span),
);
if let Some(critical) = component.critical() {
dict.insert_untagged(
"critical",
UntaggedValue::decimal_from_float(critical as f64, tag.span),
);
}
output.push(dict.into_value());
}
if !output.is_empty() {
Some(UntaggedValue::Table(output))
} else {
None
}
}

View File

@ -269,6 +269,16 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
whole_stream_command(Seq),
whole_stream_command(SeqDates),
whole_stream_command(TermSize),
// Network
#[cfg(feature = "fetch")]
whole_stream_command(Fetch),
#[cfg(feature = "post")]
whole_stream_command(Post),
// System
#[cfg(feature = "ps")]
whole_stream_command(Ps),
#[cfg(feature = "sys")]
whole_stream_command(Sys),
]);
//Dataframe commands

View File

@ -1,24 +0,0 @@
[package]
authors = ["The Nu Project Contributors"]
description = "A URL fetch plugin for Nushell"
edition = "2018"
license = "MIT"
name = "nu_plugin_fetch"
version = "0.36.1"
[lib]
doctest = false
[dependencies]
base64 = "0.13.0"
futures = { version="0.3.12", features=["compat", "io-compat"] }
nu-errors = { path="../nu-errors", version = "0.36.1" }
nu-plugin = { path="../nu-plugin", version = "0.36.1" }
nu-protocol = { path="../nu-protocol", version = "0.36.1" }
nu-source = { path="../nu-source", version = "0.36.1" }
reqwest = "0.11"
tokio = { version = "1", features = ["rt-multi-thread"] }
url = "2.2.1"
mime = "0.3.16"
[build-dependencies]

View File

@ -1,4 +0,0 @@
mod fetch;
mod nu;
pub use fetch::Fetch;

View File

@ -1,6 +0,0 @@
use nu_plugin::serve_plugin;
use nu_plugin_fetch::Fetch;
fn main() {
serve_plugin(&mut Fetch::new())
}

View File

@ -1,45 +0,0 @@
use nu_errors::ShellError;
use nu_plugin::Plugin;
use nu_protocol::{CallInfo, ReturnValue, Signature, SyntaxShape};
use crate::fetch::fetch;
use crate::Fetch;
impl Plugin for Fetch {
fn config(&mut self) -> Result<Signature, ShellError> {
Ok(Signature::build("fetch")
.desc("Load from a URL into a cell, convert to table if possible (avoid by appending '--raw').")
.required(
"URL",
SyntaxShape::String,
"the URL to fetch the contents from",
)
.named(
"user",
SyntaxShape::Any,
"the username when authenticating",
Some('u'),
)
.named(
"password",
SyntaxShape::Any,
"the password when authenticating",
Some('p'),
)
.switch("raw", "fetch contents as text rather than a table", Some('r'))
.filter())
}
fn begin_filter(&mut self, callinfo: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
self.setup(callinfo)?;
let runtime = tokio::runtime::Runtime::new()?;
Ok(vec![runtime.block_on(fetch(
&self.path.clone().ok_or_else(|| {
ShellError::labeled_error("internal error: path not set", "path not set", &self.tag)
})?,
self.has_raw,
self.user.clone(),
self.password.clone(),
))])
}
}

View File

@ -1,30 +0,0 @@
[package]
authors = ["The Nu Project Contributors"]
description = "An HTTP post plugin for Nushell"
edition = "2018"
license = "MIT"
name = "nu_plugin_post"
version = "0.36.1"
[lib]
doctest = false
[dependencies]
base64 = "0.13.0"
futures = { version="0.3.5", features=["compat", "io-compat"] }
mime = "0.3.16"
nu-errors = { path="../nu-errors", version = "0.36.1" }
nu-plugin = { path="../nu-plugin", version = "0.36.1" }
nu-protocol = { path="../nu-protocol", version = "0.36.1" }
nu-source = { path="../nu-source", version = "0.36.1" }
num-traits = "0.2.12"
serde_json = "1.0.57"
reqwest = "0.11"
tokio = { version = "1", features = ["rt-multi-thread"] }
url = "2.1.1"
[features]
dataframe = ["nu-protocol/dataframe"]
[build-dependencies]

View File

@ -1,4 +0,0 @@
mod nu;
mod post;
pub use post::Post;

View File

@ -1,6 +0,0 @@
use nu_plugin::serve_plugin;
use nu_plugin_post::Post;
fn main() {
serve_plugin(&mut Post::new());
}

View File

@ -1,62 +0,0 @@
use nu_errors::ShellError;
use nu_plugin::Plugin;
use nu_protocol::{CallInfo, ReturnValue, Signature, SyntaxShape};
use crate::post::post_helper;
use crate::Post;
impl Plugin for Post {
fn config(&mut self) -> Result<Signature, ShellError> {
Ok(Signature::build("post")
.desc("Post content to a URL and retrieve data as a table if possible.")
.required("path", SyntaxShape::Any, "the URL to post to")
.required("body", SyntaxShape::Any, "the contents of the post body")
.named(
"user",
SyntaxShape::Any,
"the username when authenticating",
Some('u'),
)
.named(
"password",
SyntaxShape::Any,
"the password when authenticating",
Some('p'),
)
.named(
"content-type",
SyntaxShape::Any,
"the MIME type of content to post",
Some('t'),
)
.named(
"content-length",
SyntaxShape::Any,
"the length of the content being posted",
Some('l'),
)
.switch(
"raw",
"return values as a string instead of a table",
Some('r'),
)
.filter())
}
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
self.setup(call_info)?;
let runtime = tokio::runtime::Runtime::new()?;
Ok(vec![runtime.block_on(post_helper(
&self.path.clone().ok_or_else(|| {
ShellError::labeled_error("expected a 'path'", "expected a 'path'", &self.tag)
})?,
self.has_raw,
&self.body.clone().ok_or_else(|| {
ShellError::labeled_error("expected a 'body'", "expected a 'body'", &self.tag)
})?,
self.user.clone(),
self.password.clone(),
&self.headers.clone(),
))])
}
}

View File

@ -1,24 +0,0 @@
[package]
authors = ["The Nu Project Contributors"]
description = "A process list plugin for Nushell"
edition = "2018"
license = "MIT"
name = "nu_plugin_ps"
version = "0.36.1"
[lib]
doctest = false
[dependencies]
nu-errors = { path="../nu-errors", version = "0.36.1" }
nu-plugin = { path="../nu-plugin", version = "0.36.1" }
nu-protocol = { path="../nu-protocol", version = "0.36.1" }
nu-source = { path="../nu-source", version = "0.36.1" }
num-bigint = "0.3.1"
futures = { version="0.3.12", features=["compat", "io-compat"] }
futures-timer = "3.0.2"
sysinfo = "0.16.5"
[build-dependencies]

View File

@ -1,4 +0,0 @@
mod nu;
mod ps;
pub use ps::Ps;

View File

@ -1,6 +0,0 @@
use nu_plugin::serve_plugin;
use nu_plugin_ps::Ps;
fn main() {
serve_plugin(&mut Ps::new())
}

View File

@ -1,30 +0,0 @@
use crate::ps::{ps, Ps};
use nu_errors::ShellError;
use nu_plugin::Plugin;
use nu_protocol::{CallInfo, ReturnSuccess, ReturnValue, Signature, Value};
use futures::executor::block_on;
impl Plugin for Ps {
fn config(&mut self) -> Result<Signature, ShellError> {
Ok(Signature::build("ps")
.desc("View information about system processes.")
.switch(
"long",
"list all available columns for each entry",
Some('l'),
)
.filter())
}
fn begin_filter(&mut self, callinfo: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
Ok(block_on(ps(callinfo.name_tag, callinfo.args.has("long")))?
.into_iter()
.map(ReturnSuccess::value)
.collect())
}
fn filter(&mut self, _: Value) -> Result<Vec<ReturnValue>, ShellError> {
Ok(vec![])
}
}

View File

@ -1,23 +0,0 @@
[package]
authors = ["The Nu Project Contributors"]
description = "A system info plugin for Nushell"
edition = "2018"
license = "MIT"
name = "nu_plugin_sys"
version = "0.36.1"
[lib]
doctest = false
[dependencies]
nu-errors = { path="../nu-errors", version = "0.36.1" }
nu-plugin = { path="../nu-plugin", version = "0.36.1" }
nu-protocol = { path="../nu-protocol", version = "0.36.1" }
nu-source = { path="../nu-source", version = "0.36.1" }
futures = { version="0.3.5", features=["compat", "io-compat"] }
futures-util = "0.3.12"
num-bigint = "0.3.1"
sysinfo = "0.18.2"
[build-dependencies]

View File

@ -1,6 +0,0 @@
#![type_length_limit = "2474736"]
mod nu;
mod sys;
pub use sys::Sys;

View File

@ -1,6 +0,0 @@
use nu_plugin::serve_plugin;
use nu_plugin_sys::Sys;
fn main() {
serve_plugin(&mut Sys::new());
}

View File

@ -1,25 +0,0 @@
use crate::sys::{sysinfo, Sys};
use nu_errors::ShellError;
use nu_plugin::Plugin;
use nu_protocol::{CallInfo, ReturnSuccess, ReturnValue, Signature, Value};
use futures::executor::block_on;
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![])
}
}

View File

@ -1,6 +0,0 @@
use nu_plugin::serve_plugin;
use nu_plugin_fetch::Fetch;
fn main() {
serve_plugin(&mut Fetch::new());
}

View File

@ -1,6 +0,0 @@
use nu_plugin::serve_plugin;
use nu_plugin_post::Post;
fn main() {
serve_plugin(&mut Post::new());
}

View File

@ -1,6 +0,0 @@
use nu_plugin::serve_plugin;
use nu_plugin_ps::Ps;
fn main() {
serve_plugin(&mut Ps::new());
}

View File

@ -1,6 +0,0 @@
use nu_plugin::serve_plugin;
use nu_plugin_sys::Sys;
fn main() {
serve_plugin(&mut Sys::new());
}

View File

@ -106,183 +106,151 @@
<Component Id='binary2' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe2'
Name='nu_plugin_fetch.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_fetch.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary3' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe3'
Name='nu_plugin_inc.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_inc.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary4' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary3' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe4'
Name='nu_plugin_post.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_post.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary5' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe5'
Name='nu_plugin_ps.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_ps.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary6' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe6'
Id='exe3'
Name='nu_plugin_start.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_start.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary7' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary4' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe7'
Name='nu_plugin_sys.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_sys.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary8' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe8'
Id='exe4'
Name='nu_plugin_textview.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_textview.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary9' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary5' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe9'
Id='exe5'
Name='nu_plugin_tree.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_tree.exe'
KeyPath='yes'/>
</Component>
<!-- Downloaded from here https://github.com/jftuga/less-Windows/releases/download/less-v562.0/less.exe -->
<Component Id='binary10' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary6' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe10'
Id='exe6'
Name='less.exe'
DiskId='1'
Source='output\less.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary11' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary7' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe11'
Id='exe7'
Name='nu_plugin_match.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_match.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary12' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary8' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe12'
Id='exe8'
Name='README.txt'
DiskId='1'
Source='output\README.txt'
KeyPath='yes'/>
</Component>
<Component Id='binary13' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary9' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe13'
Id='exe9'
Name='LICENSE'
DiskId='1'
Source='output\LICENSE'
KeyPath='yes'/>
</Component>
<Component Id='binary14' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary10' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe14'
Id='exe10'
Name='LICENSE-for-less.txt'
DiskId='1'
Source='output\LICENSE-for-less.txt'
KeyPath='yes'/>
</Component>
<Component Id='binary15' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary11' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe15'
Id='exe11'
Name='nu_plugin_s3.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_s3.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary16' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary12' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe16'
Id='exe12'
Name='nu_plugin_chart_bar.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_chart_bar.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary17' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary13' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe17'
Id='exe13'
Name='nu_plugin_chart_line.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_chart_line.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary18' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary14' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe18'
Id='exe14'
Name='nu_plugin_xpath.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_xpath.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary19' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary15' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe19'
Id='exe15'
Name='nu_plugin_from_bson.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_from_bson.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary20' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary16' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe20'
Id='exe16'
Name='nu_plugin_to_bson.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_to_bson.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary21' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary17' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe21'
Id='exe17'
Name='nu_plugin_from_sqlite.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_from_sqlite.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary22' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary18' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe22'
Id='exe18'
Name='nu_plugin_to_sqlite.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_to_sqlite.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary23' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary19' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe23'
Id='exe19'
Name='nu_plugin_selector.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_selector.exe'
KeyPath='yes'/>
</Component>
<Component Id='binary24' Guid='*' Win64='$(var.Win64)'>
<Component Id='binary20' Guid='*' Win64='$(var.Win64)'>
<File
Id='exe24'
Id='exe20'
Name='nu_plugin_query_json.exe'
DiskId='1'
Source='target\$(var.Profile)\nu_plugin_query_json.exe'