noprogress works. colour~

master
Avril 4 years ago
parent 1cc0e38987
commit 5db64236f7
Signed by: flanchan
GPG Key ID: 284488987C31F630

28
Cargo.lock generated

@ -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",
]

@ -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"

@ -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<String, std::fmt::Error> {
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<str>, 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<str>, 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 <number>] [-] <files...>
println!(r"Usage: {prog} [OPTIONS] [-] <files...>
Usage: {prog} --help
OPTIONS:
--max-children <number> Max subprocesses allowed to live at once. Infinite by default.
--recursive <number> Recurse up to `<number>` times. Must be at least `1`. Default is off.
-r Resurse infinitely.
{extra}
- Stop parsing args here.
ENVIRONMENT VARS:
LEANIFY=<process name> Path to leanify executable, defaults to looking in `PATH' if set.", prog = program_name());
LEANIFY=<process name> 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<ParseIntError> 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<NonZeroUsize>,
pub files: Vec<PathBuf>,
pub recursive: Option<NonZeroUsize>,
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<Item=T>,
continue;
}
},
#[cfg(feature="progress")]
"--no-progress" => {
cfg.flags.progress = false;
continue;
},
"-r" => {
cfg.recursive = None;
},

@ -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<dyn std::error::Error>>
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
}

@ -36,24 +36,37 @@ where T: Future
}
}
async fn do_work(process: impl AsRef<Path>, file: impl AsRef<OsStr>, mut prog: progress::ProgressSender) -> Result<fixed_stack::IntoIter<String>, 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<Path>, file: impl AsRef<OsStr>, mut prog: ProgressSender) -> Result<fixed_stack::IntoIter<String>, 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<Path>, file: impl AsRef<OsStr>, mut prog: p
}
}
pub async fn work<I,T,U>(process: U, files: I, children: Option<NonZeroUsize>) -> Result<(), Box<dyn std::error::Error>>
pub async fn work<I,T,U>(flags: &arg::Flags, process: U, files: I, children: Option<NonZeroUsize>) -> Result<(), Box<dyn std::error::Error>>
where I: IntoIterator<Item=T>,
<I as IntoIterator>::IntoIter: ExactSizeIterator,
T: AsRef<OsStr> + Send + Sync + 'static + Clone,
@ -82,21 +95,35 @@ where I: IntoIterator<Item=T>,
let files = files.into_iter();
#[cfg(feature="progress")] let (mut progress, prog_handle) = progress::create_progress::<termprogress::progress::Bar,_>(files.len(), iter::empty());
#[cfg(feature="progress")] let (mut progress, prog_handle) = {
if flags.progress {
progress::create_progress::<termprogress::progress::Bar,_>(files.len(), iter::empty())
} else {
progress::create_progress::<termprogress::silent::Silent,_>(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<Item=T>,
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<T> = OptionFuture<T>;
#[cfg(not(feature="progress"))] type Opt<T> = std::marker::PhantomData<T>;
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<Item=T>,
})).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(())
}

Loading…
Cancel
Save