| extern crate docopt; |
| extern crate serde; |
| #[macro_use] |
| extern crate serde_derive; |
| extern crate walkdir; |
| |
| use std::io::{self, Write}; |
| |
| use docopt::Docopt; |
| use walkdir::WalkDir; |
| |
| const USAGE: &'static str = " |
| Usage: |
| walkdir [options] [<dir> ...] |
| |
| Options: |
| -h, --help |
| -L, --follow-links Follow symlinks. |
| --min-depth NUM Minimum depth. |
| --max-depth NUM Maximum depth. |
| -n, --fd-max NUM Maximum open file descriptors. [default: 32] |
| --tree Show output as a tree. |
| --sort Sort the output. |
| -q, --ignore-errors Ignore errors. |
| -d, --depth Show directory's contents before the directory itself. |
| -x, --same-file-system Stay on the same file system. |
| "; |
| |
| #[derive(Debug, Deserialize)] |
| #[allow(dead_code)] |
| struct Args { |
| arg_dir: Option<Vec<String>>, |
| flag_follow_links: bool, |
| flag_min_depth: Option<usize>, |
| flag_max_depth: Option<usize>, |
| flag_fd_max: usize, |
| flag_tree: bool, |
| flag_ignore_errors: bool, |
| flag_sort: bool, |
| flag_depth: bool, |
| flag_same_file_system: bool, |
| } |
| |
| macro_rules! wout { ($($tt:tt)*) => { {writeln!($($tt)*)}.unwrap() } } |
| |
| fn main() { |
| let args: Args = Docopt::new(USAGE) |
| .and_then(|d| d.deserialize()) |
| .unwrap_or_else(|e| e.exit()); |
| let mind = args.flag_min_depth.unwrap_or(0); |
| let maxd = args.flag_max_depth.unwrap_or(::std::usize::MAX); |
| for dir in args.arg_dir.unwrap_or(vec![".".to_string()]) { |
| let mut walkdir = WalkDir::new(dir) |
| .max_open(args.flag_fd_max) |
| .follow_links(args.flag_follow_links) |
| .min_depth(mind) |
| .max_depth(maxd) |
| .same_file_system(args.flag_same_file_system); |
| if args.flag_sort { |
| walkdir = walkdir.sort_by(|a,b| a.file_name().cmp(b.file_name())); |
| } |
| if args.flag_depth { |
| walkdir = walkdir.contents_first(true) |
| } |
| let it = walkdir.into_iter(); |
| let mut out = io::BufWriter::new(io::stdout()); |
| let mut eout = io::stderr(); |
| if args.flag_tree { |
| for dent in it { |
| match dent { |
| Err(err) => { |
| out.flush().unwrap(); |
| wout!(eout, "ERROR: {}", err); |
| } |
| Ok(dent) => { |
| let name = dent.file_name().to_string_lossy(); |
| wout!(out, "{}{}", indent(dent.depth()), name); |
| } |
| } |
| } |
| } else if args.flag_ignore_errors { |
| for dent in it.filter_map(|e| e.ok()) { |
| wout!(out, "{}", dent.path().display()); |
| } |
| } else { |
| for dent in it { |
| match dent { |
| Err(err) => { |
| out.flush().unwrap(); |
| wout!(eout, "ERROR: {}", err); |
| } |
| Ok(dent) => { |
| wout!(out, "{}", dent.path().display()); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| fn indent(depth: usize) -> String { |
| ::std::iter::repeat(' ').take(2 * depth).collect() |
| } |