diff --git a/Cargo.lock b/Cargo.lock index 8e1cbe5a..949da429 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,14 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + [[package]] name = "ansi_term" version = "0.11.0" @@ -47,6 +56,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bstr" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473fc6b38233f9af7baa94fb5852dca389e3d95b8e21c8e3719301462c5d9faf" +dependencies = [ + "memchr", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -184,6 +202,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "generic-array" version = "0.14.4" @@ -200,6 +224,19 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +[[package]] +name = "globset" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + [[package]] name = "heck" version = "0.3.2" @@ -224,6 +261,24 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" +[[package]] +name = "ignore" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b287fb45c60bb826a0dc68ff08742b9d88a2fea13d6e0c286b3172065aaf878c" +dependencies = [ + "crossbeam-utils", + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + [[package]] name = "itoa" version = "0.4.7" @@ -251,6 +306,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + [[package]] name = "memoffset" version = "0.6.1" @@ -270,6 +331,12 @@ dependencies = [ "libc", ] +[[package]] +name = "once_cell" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" + [[package]] name = "opaque-debug" version = "0.3.0" @@ -282,10 +349,12 @@ version = "0.1.0" dependencies = [ "anyhow", "console", + "either", "env_logger", "filetime", "glob", "hex", + "ignore", "log", "rayon", "serde", @@ -378,7 +447,10 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" dependencies = [ + "aho-corasick", + "memchr", "regex-syntax", + "thread_local", ] [[package]] @@ -393,6 +465,15 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -503,6 +584,15 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "thread_local" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8208a331e1cb318dd5bd76951d2b8fc48ca38a69f5f4e4af1b6a9f8c6236915" +dependencies = [ + "once_cell", +] + [[package]] name = "toml" version = "0.5.8" @@ -548,6 +638,17 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +[[package]] +name = "walkdir" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index f34043ab..112d95b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,10 +9,12 @@ edition = "2018" [dependencies] anyhow = "1.0" console = "0.13" +either = "1.6.1" env_logger = { version = "0.8", default-features = false } filetime = "0.2" glob = "0.3" hex = "0.4" +ignore = "0.4.17" log = "0.4" rayon = "1.5.0" serde = { version = "1.0", features = ["derive"] } diff --git a/examples/monorepo/prjfmt.toml b/examples/monorepo/prjfmt.toml index 07ee21be..b202db90 100644 --- a/examples/monorepo/prjfmt.toml +++ b/examples/monorepo/prjfmt.toml @@ -1,8 +1,7 @@ # fmt is the universal code formatter - https://github.com/numtide/fmt [formatters.ormolu] files = "*.hs" # / "*.hs" / "Makefile" mandatory -#includes = [ "haskell/" ] # "haskell-frontend/*.hs" treat it like whitelist, and haskell-frontend will be ignored. only if `includes` exists. -#excludes = [] # blacklisted folder/files. +excludes = [ "haskell/" ] # blacklisted folder/files. command = "ormolu" args = [ "--ghc-opt", "-XBangPatterns", @@ -17,4 +16,4 @@ files = [ "*.rs" ] includes = [ "rust/" ] excludes = [] command = "cargo" -args = [ "fmt", "--" ] \ No newline at end of file +args = [ "fmt", "--" ] diff --git a/overlay.nix b/overlay.nix index f547c197..09bdb3c1 100644 --- a/overlay.nix +++ b/overlay.nix @@ -5,7 +5,7 @@ final: prev: pname = "prjfmt"; version = "0.0.1"; src = ./.; - cargoSha256 = "sha256-98M9OPWil9bKknam8ys4dNP6/iZObW0RrAC7PxiHxYI="; + cargoSha256 = "sha256:0bsxwl5bhjg8d4mdyk2mx7g5744b790nhdlyg393vwjmnbnyy1k2"; doCheck = false; nativeBuildInputs = [ ]; buildInputs = [ ]; diff --git a/src/formatters/tool.rs b/src/formatters/tool.rs index e1ba0550..7119a3e5 100644 --- a/src/formatters/tool.rs +++ b/src/formatters/tool.rs @@ -4,13 +4,12 @@ use crate::formatters::manifest::{read_prjfmt_manifest, RootManifest}; use crate::{emoji, CLOG}; use anyhow::{anyhow, Error, Result}; use filetime::FileTime; -use glob; use rayon::prelude::*; use serde::{Deserialize, Serialize}; use std::cmp::Ordering; use std::collections::{BTreeMap, BTreeSet}; use std::fs::{metadata, read_to_string}; -use std::iter::Iterator; +use std::iter::{IntoIterator, Iterator}; use std::path::PathBuf; use xshell::cmd; @@ -113,38 +112,48 @@ pub fn run_prjfmt(cwd: PathBuf, cache_dir: PathBuf) -> anyhow::Result<()> { pub fn glob_to_path( cwd: &PathBuf, extensions: &FileExtensions, - _includes: &Option>, - _excludes: &Option>, + includes: &Option>, + excludes: &Option>, ) -> anyhow::Result> { - let dir = cwd.to_str().unwrap_or(""); - - let glob_ext = |extension| -> anyhow::Result<_> { - let pat = format!("{}/**/{}", dir, extension); - let globs = glob::glob(&pat).map_err(|err| { - anyhow::anyhow!( - "{} Error at position: {} due to {}", - emoji::ERROR, - err.pos, - err.msg - ) - })?; - - Ok(globs.map(|glob_res| Ok(glob_res?))) - }; + use ignore::{overrides::OverrideBuilder, WalkBuilder}; - match extensions { - FileExtensions::SingleFile(sfile) => glob_ext(sfile)?.collect(), - FileExtensions::MultipleFile(strs) => { - strs.iter() - .map(glob_ext) - .try_fold(Vec::new(), |mut v, globs| { - for glob in globs? { - v.push(glob?) - } - Ok(v) - }) + let mut overrides_builder = OverrideBuilder::new(cwd); + + if let Some(includes) = includes { + for include in includes { + // Remove trailing `/` as we add one explicitly in the override + let include = include.trim_end_matches('/'); + for extension in extensions.into_iter() { + overrides_builder.add(&format!("{}/**/{}", include, extension))?; + } + } + } else { + for extension in extensions.into_iter() { + overrides_builder.add(&extension)?; } } + + if let Some(excludes) = excludes { + for exclude in excludes { + overrides_builder.add(&format!("!{}", exclude))?; + } + } + + let overrides = overrides_builder.build()?; + + Ok(WalkBuilder::new(cwd) + .overrides(overrides) + .build() + .filter_map(|e| { + e.ok().and_then(|e| { + match e.file_type() { + // Skip directory entries + Some(t) if t.is_dir() => None, + _ => Some(e.into_path()), + } + }) + }) + .collect()) } /// Convert each PathBuf into FileMeta @@ -246,6 +255,18 @@ pub enum FileExtensions { MultipleFile(Vec), } +impl<'a> IntoIterator for &'a FileExtensions { + type Item = &'a String; + type IntoIter = either::Either, std::slice::Iter<'a, String>>; + + fn into_iter(self) -> Self::IntoIter { + match self { + FileExtensions::SingleFile(glob) => either::Either::Left(std::iter::once(glob)), + FileExtensions::MultipleFile(globs) => either::Either::Right(globs.iter()), + } + } +} + #[derive(Debug, Deserialize, Serialize, Clone)] /// Each context of the formatter config pub struct CmdContext { diff --git a/src/main.rs b/src/main.rs index 64e729e8..096a4b27 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,5 @@ #![allow(clippy::redundant_closure, clippy::redundant_pattern_matching)] -extern crate anyhow; -extern crate env_logger; -extern crate log; -extern crate prjfmt; -extern crate structopt; - use prjfmt::{run_cli, Cli, CLOG}; use structopt::StructOpt;