use std::future::Future;
use clawless_core::cancellation::Cancellation;
use clawless_core::context::Context;
use clawless_core::event::event_channel;
use clawless_core::output::Output;
use clawless_core::signal::wait_for_shutdown;
use crate::error::CommandResult;
use crate::output::OutputFlags;
use crate::presenter::{Presenter, TerminalPresenter};
#[derive(Debug)]
pub struct CommandRunner;
impl CommandRunner {
pub fn run<E, F>(matches: clap::ArgMatches, exec: E) -> Result<(), Box<dyn std::error::Error>>
where
E: FnOnce(clap::ArgMatches, Context) -> F,
F: Future<Output = CommandResult> + Send + 'static,
{
let cancellation = Cancellation::new();
let output_flags = OutputFlags::from_arg_matches(&matches);
let (sender, receiver) = event_channel();
let output = Output::new(sender);
let context = Context::builder()
.cancellation(cancellation.clone())
.output(output)
.build()?;
let presenter = TerminalPresenter::builder()
.receiver(receiver)
.verbosity(output_flags.verbosity())
.mode(output_flags.mode())
.build();
let rt = tokio::runtime::Runtime::new()?;
rt.block_on(async {
tokio::spawn(wait_for_shutdown(cancellation));
presenter.present(Box::pin(exec(matches, context))).await
})?;
Ok(())
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::missing_panics_doc)]
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use super::*;
#[test]
fn run_with_a_closure_that_owns_state_executes_the_leaf() {
let matches =
OutputFlags::augment_command(clap::Command::new("test")).get_matches_from(["test"]);
let executed = Arc::new(AtomicBool::new(false));
let owned = Arc::clone(&executed);
CommandRunner::run(matches, move |_matches, _context| async move {
owned.store(true, Ordering::SeqCst);
Ok(())
})
.expect("the runner runs the leaf to completion");
assert!(executed.load(Ordering::SeqCst));
}
#[test]
fn trait_send() {
fn assert_send<T: Send>() {}
assert_send::<CommandRunner>();
}
#[test]
fn trait_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<CommandRunner>();
}
#[test]
fn trait_unpin() {
fn assert_unpin<T: Unpin>() {}
assert_unpin::<CommandRunner>();
}
}