Skip to content

Instantly share code, notes, and snippets.

@sheepla
Last active February 9, 2025 06:52
Show Gist options
  • Save sheepla/3d82140c1a64ad19142520e4d549ac7d to your computer and use it in GitHub Desktop.
Save sheepla/3d82140c1a64ad19142520e4d549ac7d to your computer and use it in GitHub Desktop.
Iterate files with optional globbing
use clap::{Parser, ValueEnum};
use glob::{glob, GlobError, PatternError};
use std::path::PathBuf;
use thiserror::Error;
#[derive(Debug, clap::Parser)]
struct Args {
#[arg(help = "Target files path")]
files: Vec<String>,
}
fn main() -> Result<(), Box<AppError>> {
let args = Args::parse();
for result in list_files(args.files.as_slice(), !args.no_glob) {
let path = result?;
println!("{}", path.to_string_lossy());
}
Ok(())
}
fn list_files<'a>(
patterns: &'a [String],
expand_glob: bool,
) -> impl Iterator<Item = Result<PathBuf, AppError>> + 'a {
patterns.iter().flat_map(move |pattern| {
let paths = if expand_glob {
match glob(pattern) {
Ok(paths) => paths,
Err(err) => {
return Box::new(std::iter::once(Err(AppError::PatternError(err))))
as Box<dyn Iterator<Item = Result<PathBuf, AppError>> + 'a>
}
}
} else {
let path = PathBuf::from(pattern);
if path.is_file() {
return Box::new(std::iter::once(Ok(path)))
as Box<dyn Iterator<Item = Result<PathBuf, AppError>> + 'a>;
} else {
return Box::new(std::iter::empty::<Result<PathBuf, AppError>>())
as Box<dyn Iterator<Item = Result<PathBuf, AppError>> + 'a>;
}
};
Box::new(paths.filter_map(|p| p.ok().filter(|path| path.is_file()).map(Ok)))
as Box<dyn Iterator<Item = Result<PathBuf, AppError>> + 'a>
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment