From 12bfee0bec5024b0633755d9dd18d9396cbe9783 Mon Sep 17 00:00:00 2001 From: sharkdp Date: Fri, 12 May 2017 11:50:03 +0200 Subject: [PATCH] Re-write in rust --- .gitignore | 8 +-- CMakeLists.txt | 18 ------- Cargo.lock | 143 +++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 9 ++++ README.md | 30 +++++------ src/fnd.cpp | 63 ---------------------- src/main.rs | 78 +++++++++++++++++++++++++++ 7 files changed, 244 insertions(+), 105 deletions(-) delete mode 100644 CMakeLists.txt create mode 100644 Cargo.lock create mode 100644 Cargo.toml delete mode 100644 src/fnd.cpp create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore index 915bef4..324c57f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,2 @@ -CMakeCache.txt -CMakeFiles -Makefile -cmake_install.cmake -build -fnd +target/ +**/*.rs.bk diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index e26586d..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -cmake_minimum_required(VERSION 3.1.0) - -project(fnd CXX) - -find_package(Boost 1.60 REQUIRED COMPONENTS system filesystem) -include_directories( ${Boost_INCLUDE_DIR} ) - -file(GLOB SOURCES "src/*.cpp") - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic") - -add_executable(fnd ${SOURCES}) - -target_compile_features(fnd PRIVATE cxx_range_for) - -target_link_libraries(fnd ${Boost_LIBRARIES}) - -install(TARGETS fnd DESTINATION bin) diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6013483 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,143 @@ +[root] +name = "fd" +version = "0.1.0" +dependencies = [ + "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "aho-corasick" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getopts" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "same-file" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread-id" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unreachable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "utf8-ranges" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "walkdir" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" +"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)" = "babb8281da88cba992fa1f4ddec7d63ed96280a1a53ec9b919fd37b53d71e502" +"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" +"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" +"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" +"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" +"checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a" +"checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7" +"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" +"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0eab6db --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "fd" +version = "0.1.0" +authors = ["David Peter "] + +[dependencies] +getopts = "0.2" +regex = "0.2" +walkdir = "1" diff --git a/README.md b/README.md index 05162de..639fe1b 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,30 @@ -# fnd +# fd A modern, convenient and fast replacement for `find`. **Features:** -* Easy syntax. `fnd PATTERN` instead of `find -iname '*PATTERN*'`. +* Easy syntax: `fd PATTERN` instead of `find -iname '*PATTERN*'`. * Colored output. * Regular expressions. -* The command name is *25%* shorter than `find` :-). +* The command name is *50%* shorter than `find` :-). ## Examples ``` bash -> fnd +> fd +README.md src -src/fnd.cpp -README.md +src/main.rs +Cargo.toml LICENSE -CMakeLists.txt +Cargo.lock -> fnd cpp -src/fnd.cpp +> fd rs +src/main.rs -> fnd '[A-Z].*' -README.md +> fd '^[A-Z]+$' LICENSE -CMakeLists.txt ``` -## Dependencies -* g++ `>=4.9` -* boost `>=1.60` - ## Build ```bash -cmake . -make +cargo build ``` diff --git a/src/fnd.cpp b/src/fnd.cpp deleted file mode 100644 index 91c026d..0000000 --- a/src/fnd.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include -#include - -namespace fs = boost::filesystem; - -static const std::string ANSI_PURPLE = "\x1b[35;06m"; -static const std::string ANSI_CYAN = "\x1b[36;01m"; -static const std::string ANSI_RESET = "\x1b[0m"; - -void printPath(const fs::path& path) { - if (fs::is_symlink(path)) { - std::cout << ANSI_PURPLE; - } else if (fs::is_directory(path)) { - std::cout << ANSI_CYAN; - } - - std::cout << path.string(); - - std::cout << ANSI_RESET << std::endl; -} - -void findFiles(const std::regex& pattern) { - const fs::path& currentPath = fs::current_path(); - - for (auto& entry: fs::recursive_directory_iterator(currentPath)) { - const fs::path& path = entry.path().lexically_relative(currentPath); - - if (std::regex_search(path.string(), pattern)) { - printPath(path); - } - } -} - -int main(int argc, char* argv[]) { - std::string argument; - - if (argc == 1) { - argument = ""; - } else if (argc == 2) { - argument = argv[1]; - } - - if (argc > 2 || argument == "-h" || argument == "--help") { - std::cerr << "Usage: fnd [PATTERN]" << std::endl; - return 1; - } - - // try to parse the argument as a regex - try { - std::regex::flag_type flags = std::regex_constants::ECMAScript - | std::regex_constants::icase; - std::regex re(argument, flags); - - findFiles(re); - } - catch (const std::regex_error& e) { - std::cerr << "Regex error: " << e.what() << std::endl; - return 1; - } - - return 0; -} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..795b52d --- /dev/null +++ b/src/main.rs @@ -0,0 +1,78 @@ +extern crate walkdir; +extern crate regex; +extern crate getopts; + +use std::env; +use std::path::Path; +use std::io::Write; +use std::process; +use std::error::Error; + +use walkdir::{WalkDir, DirEntry, WalkDirIterator}; +use regex::Regex; +use getopts::Options; + +fn is_hidden(entry: &DirEntry) -> bool { + entry.file_name() + .to_str() + .map(|s| s.starts_with(".")) + .unwrap_or(false) +} + +fn scan(root: &Path, pattern: &Regex) { + let walker = WalkDir::new(root).into_iter(); + for entry in walker.filter_entry(|e| !is_hidden(e)) + .filter_map(|e| e.ok()) { + if entry.path() == root { + continue; + } + + let path_relative = entry.path().strip_prefix(root).unwrap(); + let path_str = match path_relative.to_str() { + Some(s) => s, + None => continue + }; + match pattern.find(path_str) { + Some(_) => + println!("{}", path_str), + None => + continue + } + } +} + +fn error(err: &T) -> ! { + writeln!(&mut std::io::stderr(), "{}", err.description()) + .expect("Failed writing to stderr"); + process::exit(1); +} + +fn main() { + let args: Vec = env::args().collect(); + + let mut opts = Options::new(); + opts.optflag("h", "help", "print this help message"); + let matches = match opts.parse(&args[1..]) { + Ok(m) => { m } + Err(f) => { error(&f) } + }; + + if matches.opt_present("h") { + let brief = "Usage: fd [PATTERN]"; + print!("{}", opts.usage(&brief)); + process::exit(1); + } + + let empty = String::new(); + let pattern = matches.free.get(0).unwrap_or(&empty); + + let current_dir_buf = env::current_dir() + .expect("Could not get current directory!"); + let current_dir = current_dir_buf.as_path(); + + match Regex::new(pattern) { + Ok(re) => + scan(current_dir, &re), + Err(err) => error(&err) + } +}