|
|
|
@ -8,6 +8,8 @@ use std::{
|
|
|
|
|
},
|
|
|
|
|
path::{Path,PathBuf,},
|
|
|
|
|
ffi::OsStr,
|
|
|
|
|
borrow::BorrowMut,
|
|
|
|
|
iter,
|
|
|
|
|
};
|
|
|
|
|
use tokio::{
|
|
|
|
|
prelude::*,
|
|
|
|
@ -18,8 +20,10 @@ use tokio::{
|
|
|
|
|
io,
|
|
|
|
|
};
|
|
|
|
|
use futures::future::{
|
|
|
|
|
self,
|
|
|
|
|
join_all,
|
|
|
|
|
Future,
|
|
|
|
|
OptionFuture,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
async fn maybe_await<T>(from: Option<T>) -> Option<<T as Future>::Output>
|
|
|
|
@ -32,21 +36,34 @@ where T: Future
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn do_work(process: impl AsRef<Path>, file: impl AsRef<OsStr>) -> Result<fixed_stack::IntoIter<String>, process::Error>
|
|
|
|
|
async fn do_work(process: impl AsRef<Path>, file: impl AsRef<OsStr>, mut prog: progress::ProgressSender) -> Result<fixed_stack::IntoIter<String>, process::Error>
|
|
|
|
|
{
|
|
|
|
|
let process = process.as_ref();
|
|
|
|
|
let file = file.as_ref();
|
|
|
|
|
|
|
|
|
|
let (tx, mut rx) = mpsc::channel(16);
|
|
|
|
|
println!("[p]: Processing {:?}", file);
|
|
|
|
|
let collector = tokio::spawn(async move {
|
|
|
|
|
let (tx, mut rx) = mpsc::channel::<(bool, String)>(16);
|
|
|
|
|
|
|
|
|
|
let _opt_await: OptionFuture<_> = prog.println(format!("[p]: Processing {:?}", file)).await.ok().into();
|
|
|
|
|
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(value) = rx.recv().await {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
stack.push(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
stack
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
};
|
|
|
|
|
tokio::task::yield_now().await;
|
|
|
|
|
//let _ = opt_await.await;
|
|
|
|
|
match process::contained_spawn(process, std::iter::once(file), tx).await {
|
|
|
|
|
Ok(_) => Ok(collector.await.expect("Child panic").into_iter()),
|
|
|
|
|
Err(error) => Err(error),
|
|
|
|
@ -55,44 +72,78 @@ async fn do_work(process: impl AsRef<Path>, file: impl AsRef<OsStr>) -> Result<f
|
|
|
|
|
|
|
|
|
|
pub async fn work<I,T,U>(process: U, files: I, children: Option<NonZeroUsize>) -> Result<(), Box<dyn std::error::Error>>
|
|
|
|
|
where I: IntoIterator<Item=T>,
|
|
|
|
|
T: AsRef<OsStr> + Send + Sync + 'static,
|
|
|
|
|
<I as IntoIterator>::IntoIter: ExactSizeIterator,
|
|
|
|
|
T: AsRef<OsStr> + Send + Sync + 'static + Clone,
|
|
|
|
|
U: Into<PathBuf>
|
|
|
|
|
{
|
|
|
|
|
let (tx,mut rx) = mpsc::channel::<(T, fixed_stack::IntoIter<String>)>(children.as_ref().map(|&x| usize::from(x)).unwrap_or(16));
|
|
|
|
|
let (tx,mut rx) = mpsc::channel::<(T, fixed_stack::IntoIter<String>, usize)>(children.as_ref().map(|&x| usize::from(x)).unwrap_or(16));
|
|
|
|
|
let semaphore = children.map(|children| Arc::new(Semaphore::new(children.into())));
|
|
|
|
|
let process = Arc::new(process.into());
|
|
|
|
|
|
|
|
|
|
let display = tokio::spawn(async move {
|
|
|
|
|
let mut stdout = io::stdout();
|
|
|
|
|
while let Some((file, values)) = rx.recv().await {
|
|
|
|
|
|
|
|
|
|
let files = files.into_iter();
|
|
|
|
|
#[cfg(feature="progress")] let (mut progress, prog_handle) = progress::create_progress::<termprogress::progress::Bar,_>(files.len(), iter::empty());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let display = {
|
|
|
|
|
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] {:?}: {}\n", file.as_ref(), line);
|
|
|
|
|
let _ = stdout.write_all(line.as_bytes()).await;
|
|
|
|
|
|
|
|
|
|
let line = format!(" -> ({}) {:?}: {}", i, file.as_ref(), line);
|
|
|
|
|
builder.println(line);
|
|
|
|
|
}
|
|
|
|
|
let _ = builder.send().await;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for failed in join_all(files.into_iter()
|
|
|
|
|
})
|
|
|
|
|
};
|
|
|
|
|
let mut i=0usize;
|
|
|
|
|
let results = join_all(files
|
|
|
|
|
.map(|filename| {
|
|
|
|
|
let semaphore = semaphore.clone();
|
|
|
|
|
let process = Arc::clone(&process);
|
|
|
|
|
let mut tx = tx.clone();
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
let mut progress = progress.clone();
|
|
|
|
|
|
|
|
|
|
(tokio::spawn(async move {
|
|
|
|
|
let task_id: OptionFuture<_> = {
|
|
|
|
|
let _lock = maybe_await(semaphore.map(|x| x.acquire_owned())).await;
|
|
|
|
|
match do_work(process.as_ref(), &filename).await {
|
|
|
|
|
Ok(strings) => tx.send((filename, strings)).await.map_err(|_| "Child panic").unwrap(),
|
|
|
|
|
Err(error) => eprintln!("[!] {:?}: {}", filename.as_ref(), error),
|
|
|
|
|
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;
|
|
|
|
|
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)});
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
worker.0.ok().into()
|
|
|
|
|
};
|
|
|
|
|
if let Some(Ok(id)) = task_id.await {
|
|
|
|
|
let mut builder = progress.builder();
|
|
|
|
|
builder.bump_min(1);
|
|
|
|
|
builder.remove_task(id);
|
|
|
|
|
let _ = builder.send().await;
|
|
|
|
|
} else {
|
|
|
|
|
let _ = progress.bump_min(1).await;
|
|
|
|
|
}
|
|
|
|
|
}),i+=1).0
|
|
|
|
|
})).await
|
|
|
|
|
.into_iter()
|
|
|
|
|
.filter_map(|x| x.err())
|
|
|
|
|
.filter_map(|x| x.err());
|
|
|
|
|
|
|
|
|
|
progress.shutdown().await?;
|
|
|
|
|
for failed in results
|
|
|
|
|
{
|
|
|
|
|
eprintln!("Child panic: {}", failed);
|
|
|
|
|
progress.eprintln(format!("[e] Child panic {:?}", failed)).await?.await?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
drop(tx);
|
|
|
|
|
display.await?;
|
|
|
|
|
prog_handle.await.expect("Child panic")?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|