WIP now load plugins automatically

This commit is contained in:
Jonathan Turner
2019-07-04 05:37:09 +12:00
parent 75ddfe9f5a
commit 0180769971
25 changed files with 348 additions and 329 deletions

View File

@ -1,30 +1,31 @@
use crate::commands::autoview;
use crate::commands::classified::SinkCommand;
use crate::commands::command::sink;
use crate::prelude::*;
use crate::commands::classified::{
ClassifiedCommand, ClassifiedInputStream, ClassifiedPipeline, ExternalCommand, InternalCommand,
StreamNext,
};
use crate::commands::command::sink;
use crate::commands::plugin::{JsonRpc, NuResult};
use crate::context::Context;
crate use crate::errors::ShellError;
use crate::evaluate::Scope;
use crate::parser::parse::span::Spanned;
use crate::parser::registry;
use crate::parser::{Pipeline, PipelineElement, TokenNode};
use crate::git::current_branch;
use crate::object::Value;
use crate::parser::parse::span::Spanned;
use crate::parser::registry;
use crate::parser::registry::CommandConfig;
use crate::parser::{Pipeline, PipelineElement, TokenNode};
use crate::prelude::*;
use log::{debug, trace};
use rustyline::error::ReadlineError;
use rustyline::{self, ColorMode, Config, Editor};
use std::env;
use std::error::Error;
use std::io::{BufRead, BufReader, Write};
use std::iter::Iterator;
use std::sync::atomic::{AtomicBool, Ordering};
use walkdir::WalkDir;
#[derive(Debug)]
pub enum MaybeOwned<'a, T> {
@ -41,6 +42,112 @@ impl<T> MaybeOwned<'a, T> {
}
}
fn load_plugin(fname: &str, context: &mut Context) -> Result<(), ShellError> {
use crate::commands::{command, plugin};
println!("fname: {}", fname);
let mut child = std::process::Command::new(fname)
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.spawn()
.expect("Failed to spawn child process");
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
let mut reader = BufReader::new(stdout);
println!("Sending out config request");
let request = JsonRpc::new("config", Vec::<Value>::new());
let request_raw = serde_json::to_string(&request).unwrap();
stdin.write(format!("{}\n", request_raw).as_bytes())?;
let mut input = String::new();
match reader.read_line(&mut input) {
Ok(_) => {
println!("Got a response!: {}", input);
let response =
serde_json::from_str::<JsonRpc<Result<CommandConfig, ShellError>>>(&input);
match response {
Ok(jrpc) => match jrpc.params {
Ok(params) => {
println!("Loaded: {}", params.name);
if params.is_filter {
let fname = fname.to_string();
context.add_commands(vec![command(
&params.name,
Box::new(move |x| plugin::filter_plugin(fname.clone(), x)),
)]);
Ok(())
} else if params.is_sink {
let fname = fname.to_string();
context.add_sinks(vec![sink(
&params.name,
Box::new(move |x| plugin::sink_plugin(fname.clone(), x)),
)]);
Ok(())
} else {
Ok(())
}
}
Err(e) => Err(e),
},
Err(e) => Err(ShellError::string(format!("Error: {:?}", e))),
}
}
Err(e) => Err(ShellError::string(format!("Error: {:?}", e))),
}
}
fn load_plugins(context: &mut Context) -> Result<(), ShellError> {
match env::var_os("PATH") {
Some(paths) => {
//println!("{:?}", paths);
for path in env::split_paths(&paths) {
match std::fs::read_dir(path) {
Ok(path) => {
for entry in path {
let entry = entry.unwrap();
let filename = entry.file_name();
let f_name = filename.to_string_lossy();
if f_name.starts_with("nu_plugin_") && !f_name.ends_with(".d") {
//println!("Found: {}", f_name);
load_plugin(&f_name, context)?;
}
}
}
_ => {}
}
}
}
None => println!("PATH is not defined in the environment."),
}
// Also use our debug output for now
let mut path = std::path::PathBuf::from(".");
path.push("target");
path.push("debug");
match std::fs::read_dir(path) {
Ok(path) => {
for entry in path {
let entry = entry.unwrap();
let filename = entry.file_name();
let f_name = filename.to_string_lossy();
println!("looking at: {}", f_name);
if f_name.starts_with("nu_plugin_") && !f_name.ends_with(".d") {
println!("Found: {}", f_name);
load_plugin(&entry.path().to_string_lossy(), context)?;
}
}
}
_ => {}
}
Ok(())
}
pub async fn cli() -> Result<(), Box<dyn Error>> {
let mut context = Context::basic()?;
@ -48,51 +155,55 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
use crate::commands::*;
context.add_commands(vec![
command("ps", ps::ps),
command("ls", ls::ls),
command("sysinfo", sysinfo::sysinfo),
command("cd", cd::cd),
command("view", view::view),
command("skip", skip::skip),
command("first", first::first),
command("size", size::size),
command("from-ini", from_ini::from_ini),
command("from-json", from_json::from_json),
command("from-toml", from_toml::from_toml),
command("from-xml", from_xml::from_xml),
command("from-yaml", from_yaml::from_yaml),
command("get", get::get),
command("enter", enter::enter),
command("exit", exit::exit),
command("lines", lines::lines),
command("pick", pick::pick),
command("split-column", split_column::split_column),
command("split-row", split_row::split_row),
command("lines", lines::lines),
command("reject", reject::reject),
command("trim", trim::trim),
command("to-array", to_array::to_array),
command("to-json", to_json::to_json),
command("to-toml", to_toml::to_toml),
command("sort-by", sort_by::sort_by),
command("ps", Box::new(ps::ps)),
command("ls", Box::new(ls::ls)),
command("sysinfo", Box::new(sysinfo::sysinfo)),
command("cd", Box::new(cd::cd)),
command("view", Box::new(view::view)),
command("skip", Box::new(skip::skip)),
command("first", Box::new(first::first)),
command("size", Box::new(size::size)),
command("from-ini", Box::new(from_ini::from_ini)),
command("from-json", Box::new(from_json::from_json)),
command("from-toml", Box::new(from_toml::from_toml)),
command("from-xml", Box::new(from_xml::from_xml)),
command("from-yaml", Box::new(from_yaml::from_yaml)),
command("get", Box::new(get::get)),
command("enter", Box::new(enter::enter)),
command("exit", Box::new(exit::exit)),
command("lines", Box::new(lines::lines)),
command("pick", Box::new(pick::pick)),
command("split-column", Box::new(split_column::split_column)),
command("split-row", Box::new(split_row::split_row)),
command("lines", Box::new(lines::lines)),
command("reject", Box::new(reject::reject)),
command("trim", Box::new(trim::trim)),
command("to-array", Box::new(to_array::to_array)),
command("to-json", Box::new(to_json::to_json)),
command("to-toml", Box::new(to_toml::to_toml)),
command("sort-by", Box::new(sort_by::sort_by)),
Arc::new(Open),
Arc::new(Where),
Arc::new(Config),
Arc::new(SkipWhile),
command("sort-by", sort_by::sort_by),
command("sort-by", Box::new(sort_by::sort_by)),
/*
command("inc", |x| plugin::filter_plugin("inc".into(), x)),
command("newskip", |x| plugin::filter_plugin("newskip".into(), x)),
*/
]);
context.add_sinks(vec![
sink("autoview", autoview::autoview),
sink("clip", clip::clip),
sink("save", save::save),
sink("table", table::table),
sink("tree", tree::tree),
sink("vtable", vtable::vtable),
sink("sum", |x| plugin::sink_plugin("sum".into(), x)),
sink("autoview", Box::new(autoview::autoview)),
sink("clip", Box::new(clip::clip)),
sink("save", Box::new(save::save)),
sink("table", Box::new(table::table)),
sink("tree", Box::new(tree::tree)),
sink("vtable", Box::new(vtable::vtable)),
//sink("sum", |x| plugin::sink_plugin("sum".into(), x)),
]);
}
load_plugins(&mut context);
let config = Config::builder().color_mode(ColorMode::Forced).build();
let h = crate::shell::Helper::new(context.clone_commands());
@ -250,7 +361,7 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
Some(ClassifiedCommand::Sink(_)) => {}
Some(ClassifiedCommand::External(_)) => {}
_ => pipeline.commands.push(ClassifiedCommand::Sink(SinkCommand {
command: sink("autoview", autoview::autoview),
command: sink("autoview", Box::new(autoview::autoview)),
name_span: None,
args: registry::Args {
positional: None,