From b64177347347d007a723f47365f2e2558d57b7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Saparelli?= Date: Sat, 8 Apr 2023 19:47:56 +1200 Subject: [PATCH] Add log, stdout, stderr --- crates/cli/src/filterer.rs | 1 + crates/cli/src/filterer/proglib.rs | 124 +++++++++++++++++++++++++++++ crates/cli/src/filterer/progs.rs | 29 +------ 3 files changed, 129 insertions(+), 25 deletions(-) create mode 100644 crates/cli/src/filterer/proglib.rs diff --git a/crates/cli/src/filterer.rs b/crates/cli/src/filterer.rs index 28515457..1d3953e9 100644 --- a/crates/cli/src/filterer.rs +++ b/crates/cli/src/filterer.rs @@ -20,6 +20,7 @@ use watchexec_filterer_globset::GlobsetFilterer; use crate::args::{Args, FsEvent}; mod dirs; +mod proglib; mod progs; /// A custom filterer that combines the library's Globset filterer and a switch for --no-meta diff --git a/crates/cli/src/filterer/proglib.rs b/crates/cli/src/filterer/proglib.rs new file mode 100644 index 00000000..a86e95a3 --- /dev/null +++ b/crates/cli/src/filterer/proglib.rs @@ -0,0 +1,124 @@ +use std::iter::once; + +use jaq_core::{CustomFilter, Definitions, Error, Val}; +use miette::miette; +use tracing::{debug, error, info, trace, warn}; + +pub fn load_std_defs() -> miette::Result { + debug!("loading jaq core library"); + let mut defs = Definitions::core(); + + debug!("loading jaq standard library"); + let mut errs = Vec::new(); + jaq_std::std() + .into_iter() + .for_each(|def| defs.insert(def, &mut errs)); + + if !errs.is_empty() { + return Err(miette!("failed to load jaq standard library: {:?}", errs)); + } + Ok(defs) +} + +macro_rules! return_err { + ($err:expr) => { + return Box::new(once($err)) + }; +} + +#[inline] +fn custom_err(err: impl Into) -> Result { + Err(Error::Custom(err.into())) +} + +macro_rules! string_arg { + ($args:expr, $n:expr, $ctx:expr, $val:expr) => { + match $args[$n].run(($ctx.clone(), $val.clone())).next() { + Some(Ok(Val::Str(v))) => Ok(v.to_string()), + Some(Ok(val)) => custom_err(format!("expected string but got {val:?}")), + Some(Err(e)) => Err(e), + None => custom_err("value expected but none found"), + } + }; +} + +macro_rules! log_action { + ($level:expr, $val:expr) => { + match $level.to_ascii_lowercase().as_str() { + "trace" => trace!("jaq: {}", $val), + "debug" => debug!("jaq: {}", $val), + "info" => info!("jaq: {}", $val), + "warn" => warn!("jaq: {}", $val), + "error" => error!("jaq: {}", $val), + _ => return_err!(custom_err("invalid log level")), + } + }; +} + +pub fn load_watchexec_defs(defs: &mut Definitions) -> miette::Result<()> { + debug!("loading jaq watchexec library"); + + trace!("jaq: add log filter"); + defs.insert_custom( + "log", + CustomFilter::with_update( + 1, + |args, (ctx, val)| { + let level = match string_arg!(args, 0, ctx, val) { + Ok(v) => v, + Err(e) => return_err!(Err(e)), + }; + + log_action!(level, val); + + // passthrough + Box::new(once(Ok(val))) + }, + |args, (ctx, val), _| { + let level = match string_arg!(args, 0, ctx, val) { + Ok(v) => v, + Err(e) => return_err!(Err(e)), + }; + + log_action!(level, val); + + // passthrough + Box::new(once(Ok(val))) + }, + ), + ); + + trace!("jaq: add stdout filter"); + defs.insert_custom( + "stdout", + CustomFilter::with_update( + 0, + |_, (_, val)| { + println!("{}", val); + Box::new(once(Ok(val))) + }, + |_, (_, val), _| { + println!("{}", val); + Box::new(once(Ok(val))) + }, + ), + ); + + trace!("jaq: add stderr filter"); + defs.insert_custom( + "stderr", + CustomFilter::with_update( + 0, + |_, (_, val)| { + eprintln!("{}", val); + Box::new(once(Ok(val))) + }, + |_, (_, val), _| { + eprintln!("{}", val); + Box::new(once(Ok(val))) + }, + ), + ); + + Ok(()) +} diff --git a/crates/cli/src/filterer/progs.rs b/crates/cli/src/filterer/progs.rs index fba7c320..934a9b9b 100644 --- a/crates/cli/src/filterer/progs.rs +++ b/crates/cli/src/filterer/progs.rs @@ -1,4 +1,4 @@ -use std::{iter, marker::PhantomData}; +use std::{iter::once, marker::PhantomData}; use jaq_core::{ parse::{self, filter::Filter, Def}, @@ -72,8 +72,8 @@ impl FilterProgs { let (requester, mut receiver) = Requester::::new(BUFFER); let task = spawn_blocking(move || { - let mut defs = load_std_defs()?; - load_watchexec_defs(&mut defs)?; + let mut defs = super::proglib::load_std_defs()?; + super::proglib::load_watchexec_defs(&mut defs)?; load_user_progs(&mut defs, &progs)?; 'chan: while let Some((event, sender)) = receiver.blocking_recv() { @@ -97,7 +97,7 @@ impl FilterProgs { continue; } - let inputs = RcIter::new(iter::once(Ok(val.clone()))); + let inputs = RcIter::new(once(Ok(val.clone()))); let ctx = Ctx::new(Vec::new(), &inputs); let mut results = filter.run(ctx, val.clone()); if let Some(res) = results.next() { @@ -154,27 +154,6 @@ impl FilterProgs { } } -fn load_std_defs() -> miette::Result { - debug!("loading jaq core library"); - let mut defs = Definitions::core(); - - debug!("loading jaq standard library"); - let mut errs = Vec::new(); - jaq_std::std() - .into_iter() - .for_each(|def| defs.insert(def, &mut errs)); - - if !errs.is_empty() { - return Err(miette!("failed to load jaq standard library: {:?}", errs)); - } - Ok(defs) -} - -fn load_watchexec_defs(defs: &mut Definitions) -> miette::Result<()> { - debug!("loading jaq watchexec library"); - Ok(()) -} - fn load_user_progs(all_defs: &mut Definitions, progs: &[String]) -> miette::Result<()> { debug!("loading jaq programs"); for (n, prog) in progs.iter().enumerate() {