From 5db64236f7289bd6cda09e1aa47bef21296dcdd9 Mon Sep 17 00:00:00 2001 From: Avril Date: Mon, 10 Aug 2020 22:55:54 +0100 Subject: [PATCH] noprogress works. colour~ --- Cargo.lock | 28 +++++++++++- Cargo.toml | 6 ++- src/arg.rs | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 8 +++- src/work.rs | 107 +++++++++++++++++++++++++++++++++------------- 5 files changed, 233 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8517392..7864ff4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,17 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.9", +] + [[package]] name = "bitflags" version = "1.2.1" @@ -182,6 +193,7 @@ dependencies = [ "cfg-if", "futures", "lazy_static", + "recolored", "rustc_version", "termprogress", "tokio", @@ -361,6 +373,17 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "recolored" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1584c92dd8a87686229f766bb3a62d263a90c47c81e45a49f1a6d684a1b7968d" +dependencies = [ + "atty", + "lazy_static", + "winapi 0.3.9", +] + [[package]] name = "redox_syscall" version = "0.1.57" @@ -442,10 +465,11 @@ dependencies = [ [[package]] name = "termprogress" -version = "0.2.4" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdac4acf3a5e8889b18583692fcae227f0dacc42c6714696cf6b424ecac51aa6" +checksum = "6611ecf7fedefdb0f74d6194da1918f15c00ef97ae4bbd1f60a9c7ca2ae0eb14" dependencies = [ + "rustc_version", "terminal_size", ] diff --git a/Cargo.toml b/Cargo.toml index f43c468..ed6f203 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,18 +8,20 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["splash", "progress"] +default = ["splash", "progress", "colour"] progress = ["termprogress"] threads = ["tokio/rt-threaded"] splash = [] +colour = ["recolored"] [dependencies] lazy_static = "1.4" tokio = {version = "0.2", features= ["rt-core", "rt-util", "macros", "fs", "io-driver", "io-util", "io-std", "process", "sync", "stream"]} futures = "0.3" -termprogress = {version="0.2", optional=true} +termprogress = {version="0.3", optional=true} cfg-if = "0.1.10" +recolored = { version = "1.9.3", optional = true } [build-dependencies] rustc_version = "0.2" diff --git a/src/arg.rs b/src/arg.rs index c1ed730..e3161ae 100644 --- a/src/arg.rs +++ b/src/arg.rs @@ -19,19 +19,109 @@ use lazy_static::lazy_static; &PROG[..] } +fn extra_args() -> &'static str +{ + lazy_static! { + static ref EXTRA: &'static str = { + let work = || -> Result { + use std::fmt::Write as _; + let mut output = String::new(); + #[cfg(feature="progress")] writeln!(output, " --no-progress Do not display progress bar")?; + Ok(output) + }; + match work() { + Ok(output) => Box::leak(output.into_boxed_str()), + Err(err) => { + eprintln!("Failed to write usage message: {}", err); + "" + }, + } + }; + } + &EXTRA[..] +} + +mod feature +{ + use cfg_if::cfg_if; + #[macro_export] macro_rules! check { + (on $name:literal) => { + if cfg!(feature = $name) { + feature::on($name, true); + } else { + feature::off($name, false); + } + }; + (off $name:literal) => { + if cfg!(feature = $name) { + feature::on($name, false); + } else { + feature::off($name, true); + } + } + } + pub fn on(name: impl AsRef, default: bool) + { + cfg_if! { + if #[cfg(feature="colour")] { + use recolored::Colorize; + if default { + println!(" {}", format!("+{}", name.as_ref()).red()); + } else { + println!(" {}", format!("+{}", name.as_ref()).bright_red()); + } + } else { + println!(" +{}", name.as_ref()) + } + } + } + + pub fn off(name: impl AsRef, default: bool) + { + cfg_if! { + if #[cfg(feature="colour")] { + use recolored::Colorize; + if default { + println!(" {}", format!("-{}", name.as_ref()).blue()); + } else { + println!(" {}", format!("-{}", name.as_ref()).bright_blue()); + + } + } else { + println!(" -{}", name.as_ref()) + } + } + } +} + +fn comp_flags() +{ + check!(on "splash"); + check!(on "colour"); + check!(on "progress"); + check!(off "threads"); +} + pub fn usage() -> ! { #[cfg(feature="splash")] splash::print(); - println!(r"Usage: {prog} [--max-children ] [-] + println!(r"Usage: {prog} [OPTIONS] [-] Usage: {prog} --help OPTIONS: --max-children Max subprocesses allowed to live at once. Infinite by default. + --recursive Recurse up to `` times. Must be at least `1`. Default is off. + -r Resurse infinitely. +{extra} + - Stop parsing args here. ENVIRONMENT VARS: - LEANIFY= Path to leanify executable, defaults to looking in `PATH' if set.", prog = program_name()); + LEANIFY= Path to leanify executable, defaults to looking in `PATH' if set. +", prog = program_name(), extra = &extra_args()[..extra_args().len()-1]); + println!("Compiled with:"); + comp_flags(); std::process::exit(1) } @@ -82,12 +172,33 @@ impl From for Error } +/// Any extra options +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Flags +{ + /// Display the progress bar + #[cfg(feature="progress")] pub progress: bool, +} + +impl Default for Flags +{ + #[inline] + fn default() -> Self + { + Self { + #[cfg(feature="progress")] progress: true, + } + } +} + + #[derive(Debug, Clone, PartialEq, Eq)] pub struct Config { pub max_children: Option, pub files: Vec, pub recursive: Option, + pub flags: Flags } impl Default for Config @@ -99,6 +210,7 @@ impl Default for Config max_children: None, files: Vec::new(), recursive: Some(unsafe{NonZeroUsize::new_unchecked(1)}), + flags: Flags::default(), } } } @@ -148,6 +260,11 @@ where I: IntoIterator, continue; } }, + #[cfg(feature="progress")] + "--no-progress" => { + cfg.flags.progress = false; + continue; + }, "-r" => { cfg.recursive = None; }, diff --git a/src/main.rs b/src/main.rs index 6b1187a..fe9377a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,13 @@ #![cfg_attr(nightly, feature(int_error_matching))] #![cfg_attr(nightly, feature(linked_list_remove))] -#![cfg_attr(nightly, feature(const_fn))] +#![cfg_attr(nightly, feature(const_fn))] +#![cfg_attr(nightly, feature(never_type))] + #![allow(dead_code)] +use cfg_if::cfg_if; + mod defer; mod ext; pub use ext::JoinStrsExt as _; @@ -31,7 +35,7 @@ async fn work() -> Result<(), Box> let args = arg::parse_args().await.with_prefix("failed to parse args")?; let leanify = leanify::find_binary().with_prefix("Couldn't find leanify binary")?; - work::work(leanify, args.files, args.max_children).await + work::work(&args.flags, leanify, args.files, args.max_children).await } diff --git a/src/work.rs b/src/work.rs index d989199..984de24 100644 --- a/src/work.rs +++ b/src/work.rs @@ -36,24 +36,37 @@ where T: Future } } -async fn do_work(process: impl AsRef, file: impl AsRef, mut prog: progress::ProgressSender) -> Result, process::Error> +#[cfg(feature="progress")] +type ProgressSender = progress::ProgressSender; +#[cfg(not(feature="progress"))] +type ProgressSender = (); + +#[allow(unused_mut)] +#[allow(unused_variables)] +async fn do_work(process: impl AsRef, file: impl AsRef, mut prog: ProgressSender) -> Result, process::Error> { let process = process.as_ref(); let file = file.as_ref(); let (tx, mut rx) = mpsc::channel::<(bool, String)>(16); - let _opt_await: OptionFuture<_> = prog.println(format!("[p]: Processing {:?}", file)).await.ok().into(); + #[cfg(feature="progress")] let _opt_await: OptionFuture<_> = prog.println(format!("[p]: Processing {:?}", file)).await.ok().into(); + #[cfg(not(feature="progress"))] let _opt_await = println!("[p]: Processing {:?}", file); let collector = { - let mut prog = prog.clone(); let file = file.to_owned(); tokio::spawn(async move { let mut stack = fixed_stack::FixedStack::new(100); while let Some((err, value)) = rx.recv().await { if err { - let value = format!("[!] {:?}: {}", file, value); - if let Err(_) = prog.eprintln(&value[..]).await { - eprintln!("\n{}", value); + cfg_if!{ + if #[cfg(feature="progress")] { + let value = format!("[!] {:?}: {}", file, value); + if let Err(_) = prog.eprintln(&value[..]).await { + eprintln!("\n{}", value); + } + } else { + eprintln!("[!] {:?}: {}", file, value); + } } } else { stack.push(value); @@ -70,7 +83,7 @@ async fn do_work(process: impl AsRef, file: impl AsRef, mut prog: p } } -pub async fn work(process: U, files: I, children: Option) -> Result<(), Box> +pub async fn work(flags: &arg::Flags, process: U, files: I, children: Option) -> Result<(), Box> where I: IntoIterator, ::IntoIter: ExactSizeIterator, T: AsRef + Send + Sync + 'static + Clone, @@ -82,21 +95,35 @@ where I: IntoIterator, let files = files.into_iter(); - #[cfg(feature="progress")] let (mut progress, prog_handle) = progress::create_progress::(files.len(), iter::empty()); - + #[cfg(feature="progress")] let (mut progress, prog_handle) = { + if flags.progress { + progress::create_progress::(files.len(), iter::empty()) + } else { + progress::create_progress::(files.len(), iter::empty()) + } + }; let display = { - let mut progress = progress.clone(); + #[cfg(feature="progress")] let mut progress = progress.clone(); tokio::spawn(async move { //let mut last: OptionFuture<_> = None.into(); while let Some((file, values, i)) = rx.recv().await { - let mut builder =progress.builder(); - for line in values.into_iter() - { - let line = format!(" -> ({}) {:?}: {}", i, file.as_ref(), line); - builder.println(line); + cfg_if!{ + if #[cfg(feature="progress")] { + let mut builder =progress.builder(); + for line in values.into_iter() + { + let line = format!(" -> ({}) {:?}: {}", i, file.as_ref(), line); + builder.println(line); + } + let _ = builder.send().await; + } else { + for line in values.into_iter() + { + println!(" -> ({}) {:?}: {}", i, file.as_ref(), line); + } + } } - let _ = builder.send().await; } }) }; @@ -106,24 +133,45 @@ where I: IntoIterator, let semaphore = semaphore.clone(); let process = Arc::clone(&process); let mut tx = tx.clone(); - let mut progress = progress.clone(); + + #[cfg(feature="progress")] let mut progress = progress.clone(); (tokio::spawn(async move { - let task_id: OptionFuture<_> = { + #[cfg(feature="progress")] type Opt = OptionFuture; + #[cfg(not(feature="progress"))] type Opt = std::marker::PhantomData; + let _task_id: Opt<_> = { let _lock = maybe_await(semaphore.map(|x| x.acquire_owned())).await; - let worker = do_work(process.as_ref(), &filename, progress.clone()); - let task = progress.add_task(format!("{:?}", filename.as_ref())); - let worker = future::join(task, worker).await; + + // (task_id, worker_result) + let worker = { + cfg_if!{ + if #[cfg(feature="progress")] { + let worker = do_work(process.as_ref(), &filename, progress.clone()); + let task = progress.add_task(format!("{:?}", filename.as_ref())); + future::join(task, worker).await + } else { + (Option::::None, do_work(process.as_ref(), &filename, ()).await) + } + } + }; + match worker.1 { Ok(strings) => tx.send((filename, strings, i)).await.map_err(|_| "Child panic").unwrap(), Err(error) => { - //eprintln!("[!] {:?}: {}", filename.as_ref(), error) - let _ = progress.eprintln(format!("[!] ({}) {:?}: {}", i, filename.as_ref(), error)).await.or_else(|e| {eprintln!("\n{}",e); Err(e)}); + #[cfg(not(feature="progress"))] eprintln!("[!] {:?}: {}", filename.as_ref(), error); + #[cfg(feature="progress")] let _ = progress.eprintln(format!("[!] ({}) {:?}: {}", i, filename.as_ref(), error)).await.or_else(|e| {eprintln!("\n{}",e); Err(e)}); }, } - worker.0.ok().into() + cfg_if!{ + if #[cfg(feature="progress")] { + worker.0.ok().into() + } else { + std::marker::PhantomData:: + } + } }; - if let Some(Ok(id)) = task_id.await { + #[cfg(feature="progress")] + if let Some(Ok(id)) = _task_id.await { let mut builder = progress.builder(); builder.bump_min(1); builder.remove_task(id); @@ -135,15 +183,16 @@ where I: IntoIterator, })).await .into_iter() .filter_map(|x| x.err()); - - progress.shutdown().await?; + + #[cfg(feature="progress")] progress.shutdown().await?; for failed in results { - progress.eprintln(format!("[e] Child panic {:?}", failed)).await?.await?; + #[cfg(feature="progress")] progress.eprintln(format!("[e] Child panic {:?}", failed)).await?.await?; + #[cfg(not(feature="progress"))] eprintln!("[e] Child panic {:?}", failed); } drop(tx); display.await?; - prog_handle.await.expect("Child panic")?; + #[cfg(feature="progress")] prog_handle.await.expect("Child panic")?; Ok(()) }