2017-06-11 14:15:25 +02:00
|
|
|
#[macro_use]
|
|
|
|
extern crate clap;
|
2017-05-12 13:02:20 +02:00
|
|
|
extern crate ansi_term;
|
2017-06-10 17:30:48 +02:00
|
|
|
extern crate atty;
|
2017-05-12 22:50:52 +02:00
|
|
|
extern crate regex;
|
2017-05-15 22:38:34 +02:00
|
|
|
extern crate ignore;
|
2017-09-09 16:08:46 +02:00
|
|
|
extern crate num_cpus;
|
2017-06-05 11:56:39 +02:00
|
|
|
|
|
|
|
pub mod lscolors;
|
2017-06-05 16:25:13 +02:00
|
|
|
pub mod fshelper;
|
2017-10-04 14:31:08 +02:00
|
|
|
mod app;
|
2017-10-10 08:01:17 +02:00
|
|
|
mod internal;
|
|
|
|
mod output;
|
|
|
|
mod walk;
|
2017-05-12 11:50:03 +02:00
|
|
|
|
|
|
|
use std::env;
|
2017-05-12 19:34:31 +02:00
|
|
|
use std::error::Error;
|
2017-10-10 08:01:17 +02:00
|
|
|
use std::path::Path;
|
2017-06-11 22:43:30 +02:00
|
|
|
use std::sync::Arc;
|
2017-06-16 10:37:40 +02:00
|
|
|
use std::time;
|
2017-05-12 11:50:03 +02:00
|
|
|
|
2017-06-10 17:30:48 +02:00
|
|
|
use atty::Stream;
|
2017-10-10 08:01:17 +02:00
|
|
|
use regex::RegexBuilder;
|
2017-05-12 13:02:20 +02:00
|
|
|
|
2017-10-10 08:01:17 +02:00
|
|
|
use internal::{error, FdOptions, PathDisplay, ROOT_DIR};
|
2017-06-05 11:56:39 +02:00
|
|
|
use lscolors::LsColors;
|
2017-10-10 08:01:17 +02:00
|
|
|
use walk::FileType;
|
2017-05-12 11:50:03 +02:00
|
|
|
|
|
|
|
fn main() {
|
2017-10-04 14:31:08 +02:00
|
|
|
let matches = app::build_app().get_matches();
|
2017-05-12 11:50:03 +02:00
|
|
|
|
2017-06-05 16:25:13 +02:00
|
|
|
// Get the search pattern
|
|
|
|
let empty_pattern = String::new();
|
2017-06-11 14:15:25 +02:00
|
|
|
let pattern = matches.value_of("pattern").unwrap_or(&empty_pattern);
|
2017-05-12 11:50:03 +02:00
|
|
|
|
2017-06-05 16:25:13 +02:00
|
|
|
// Get the current working directory
|
2017-05-12 12:39:13 +02:00
|
|
|
let current_dir_buf = match env::current_dir() {
|
|
|
|
Ok(cd) => cd,
|
2017-06-11 20:55:01 +02:00
|
|
|
Err(_) => error("Error: could not get current directory.")
|
2017-05-12 12:39:13 +02:00
|
|
|
};
|
2017-05-12 11:50:03 +02:00
|
|
|
let current_dir = current_dir_buf.as_path();
|
|
|
|
|
2017-06-05 16:25:13 +02:00
|
|
|
// Get the root directory for the search
|
2017-06-11 20:55:01 +02:00
|
|
|
let mut root_dir_is_absolute = false;
|
2017-06-11 20:41:32 +02:00
|
|
|
let root_dir_buf = if let Some(rd) = matches.value_of("path") {
|
2017-06-11 20:55:01 +02:00
|
|
|
let path = Path::new(rd);
|
|
|
|
|
|
|
|
root_dir_is_absolute = path.is_absolute();
|
|
|
|
|
2017-10-07 09:40:44 +02:00
|
|
|
fshelper::absolute_path(path).unwrap_or_else(
|
2017-06-11 20:55:01 +02:00
|
|
|
|_| error(&format!("Error: could not find directory '{}'.", rd))
|
2017-06-11 20:41:32 +02:00
|
|
|
)
|
|
|
|
} else {
|
|
|
|
current_dir_buf.clone()
|
|
|
|
};
|
|
|
|
|
|
|
|
if !root_dir_buf.is_dir() {
|
2017-06-11 20:55:01 +02:00
|
|
|
error(&format!("Error: '{}' is not a directory.", root_dir_buf.to_string_lossy()));
|
2017-06-11 20:41:32 +02:00
|
|
|
}
|
|
|
|
|
2017-06-05 16:25:13 +02:00
|
|
|
let root_dir = root_dir_buf.as_path();
|
|
|
|
|
2017-06-05 14:14:01 +02:00
|
|
|
// The search will be case-sensitive if the command line flag is set or
|
|
|
|
// if the pattern has an uppercase character (smart case).
|
2017-06-11 14:15:25 +02:00
|
|
|
let case_sensitive = matches.is_present("case-sensitive") ||
|
2017-06-05 14:14:01 +02:00
|
|
|
pattern.chars().any(char::is_uppercase);
|
|
|
|
|
2017-09-30 23:02:57 +02:00
|
|
|
let colored_output = match matches.value_of("color") {
|
|
|
|
Some("always") => true,
|
|
|
|
Some("never") => false,
|
|
|
|
_ => atty::is(Stream::Stdout)
|
|
|
|
};
|
2017-05-15 21:41:31 +02:00
|
|
|
|
2017-06-01 22:46:15 +02:00
|
|
|
let ls_colors =
|
2017-06-05 14:14:01 +02:00
|
|
|
if colored_output {
|
|
|
|
Some(
|
|
|
|
env::var("LS_COLORS")
|
|
|
|
.ok()
|
|
|
|
.map(|val| LsColors::from_string(&val))
|
|
|
|
.unwrap_or_default()
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2017-05-12 15:44:09 +02:00
|
|
|
|
|
|
|
let config = FdOptions {
|
2017-06-05 14:14:01 +02:00
|
|
|
case_sensitive: case_sensitive,
|
2017-06-11 14:15:25 +02:00
|
|
|
search_full_path: matches.is_present("full-path"),
|
|
|
|
ignore_hidden: !matches.is_present("hidden"),
|
|
|
|
read_ignore: !matches.is_present("no-ignore"),
|
|
|
|
follow_links: matches.is_present("follow"),
|
2017-08-01 22:36:38 +02:00
|
|
|
null_separator: matches.is_present("null_separator"),
|
2017-06-11 14:15:25 +02:00
|
|
|
max_depth: matches.value_of("depth")
|
2017-06-16 10:37:40 +02:00
|
|
|
.and_then(|n| usize::from_str_radix(n, 10).ok()),
|
2017-09-09 16:08:46 +02:00
|
|
|
threads: std::cmp::max(
|
|
|
|
matches.value_of("threads")
|
|
|
|
.and_then(|n| usize::from_str_radix(n, 10).ok())
|
2017-09-15 21:03:47 +02:00
|
|
|
.unwrap_or_else(num_cpus::get),
|
2017-09-09 16:08:46 +02:00
|
|
|
1
|
|
|
|
),
|
2017-06-16 10:37:40 +02:00
|
|
|
max_buffer_time: matches.value_of("max-buffer-time")
|
|
|
|
.and_then(|n| u64::from_str_radix(n, 10).ok())
|
|
|
|
.map(time::Duration::from_millis),
|
2017-06-11 20:55:01 +02:00
|
|
|
path_display: if matches.is_present("absolute-path") || root_dir_is_absolute {
|
2017-06-05 21:18:27 +02:00
|
|
|
PathDisplay::Absolute
|
|
|
|
} else {
|
|
|
|
PathDisplay::Relative
|
|
|
|
},
|
2017-09-17 02:36:07 +02:00
|
|
|
ls_colors: ls_colors,
|
2017-09-17 09:37:39 +02:00
|
|
|
file_type: match matches.value_of("file-type") {
|
|
|
|
Some("f") | Some("file") => FileType::RegularFile,
|
|
|
|
Some("d") | Some("directory") => FileType::Directory,
|
2017-10-09 21:25:30 +02:00
|
|
|
Some("l") | Some("symlink") => FileType::SymLink,
|
2017-09-17 09:37:39 +02:00
|
|
|
_ => FileType::Any,
|
|
|
|
},
|
2017-09-29 22:33:33 +02:00
|
|
|
extension: matches.value_of("extension")
|
|
|
|
.map(|e| e.trim_left_matches('.').to_lowercase()),
|
2017-05-12 15:44:09 +02:00
|
|
|
};
|
2017-05-12 13:32:30 +02:00
|
|
|
|
2017-06-05 21:18:27 +02:00
|
|
|
let root = Path::new(ROOT_DIR);
|
|
|
|
let base = match config.path_display {
|
|
|
|
PathDisplay::Relative => current_dir,
|
|
|
|
PathDisplay::Absolute => root
|
|
|
|
};
|
|
|
|
|
2017-05-12 12:39:13 +02:00
|
|
|
match RegexBuilder::new(pattern)
|
2017-05-12 15:44:09 +02:00
|
|
|
.case_insensitive(!config.case_sensitive)
|
2017-05-12 12:39:13 +02:00
|
|
|
.build() {
|
2017-10-10 08:01:17 +02:00
|
|
|
Ok(re) => walk::scan(root_dir, Arc::new(re), base, Arc::new(config)),
|
2017-05-12 12:39:13 +02:00
|
|
|
Err(err) => error(err.description())
|
2017-05-12 11:50:03 +02:00
|
|
|
}
|
|
|
|
}
|