You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
2.1 KiB
95 lines
2.1 KiB
//! Arg parsing
|
|
use super::*;
|
|
use std::{
|
|
ffi::OsStr,
|
|
path::{
|
|
Path, PathBuf,
|
|
},
|
|
borrow::Cow,
|
|
};
|
|
use tokio::{
|
|
sync::{
|
|
mpsc,
|
|
},
|
|
};
|
|
use futures::{
|
|
stream::{self, Stream, BoxStream, StreamExt,},
|
|
};
|
|
|
|
/// Parsed command-line args
|
|
#[derive(Debug)]
|
|
pub struct Args
|
|
{
|
|
paths: Option<Vec<PathBuf>>,
|
|
}
|
|
|
|
impl Args
|
|
{
|
|
/// Paths as an async stream
|
|
///
|
|
/// # Non-immediate
|
|
/// When input paths come from `stdin`, the output stream will be non-immediate.
|
|
pub fn paths(&self) -> BoxStream<'_, Cow<'_, Path>>
|
|
{
|
|
if let Some(paths) = self.paths.as_ref() {
|
|
stream::iter(paths.iter().map(|x| Cow::Borrowed(Path::new(x)))).boxed()
|
|
} else {
|
|
let (tx, rx) = mpsc::channel(128);
|
|
tokio::spawn(async move {
|
|
use tokio::io::{
|
|
self,
|
|
AsyncReadExt, AsyncBufReadExt
|
|
};
|
|
let mut stdin = {
|
|
tokio::io::BufReader::new(io::stdin())
|
|
};
|
|
let mut buf = Vec::with_capacity(1024);
|
|
loop
|
|
{
|
|
buf.clear();
|
|
use std::os::unix::prelude::*;
|
|
let n = match stdin.read_until(b'\n', &mut buf).await {
|
|
Ok(n) => n,
|
|
Err(e) => {
|
|
error!("paths: Failed to read input line: {}", e);
|
|
break;
|
|
},
|
|
};
|
|
trace!("paths: buffer: {:?}", &buf[..]);
|
|
if n == 0 {
|
|
trace!("paths: Stdin exhausted. Exiting.");
|
|
break;
|
|
}
|
|
let path_bytes = &buf[..n];
|
|
let path_bytes = if path_bytes.len() == 1 {
|
|
trace!("paths: Ignoring empty line. Yielding then continuing.");
|
|
tokio::task::yield_now().await;
|
|
continue;
|
|
} else {
|
|
&path_bytes[.. (path_bytes.len()-1)]
|
|
};
|
|
let path = Path::new(OsStr::from_bytes(path_bytes));
|
|
trace!("Read path {:?}", path);
|
|
if path.exists() {
|
|
if tx.send(path.to_owned()).await.is_err() {
|
|
trace!("paths: Stream dropped, cancelling stdin read.");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
tokio_stream::wrappers::ReceiverStream::new(rx).map(|x| Cow::Owned(x)).boxed()
|
|
}
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub fn parse_args() -> eyre::Result<Args>
|
|
{
|
|
//return Ok(Args { paths: None });
|
|
todo!("parse(std::env::args().skip(1))")
|
|
}
|
|
|
|
//TODO: fn parse(args: impl IntoIterator<Item=String>) -> eyre::Result<Args>
|
|
|