Skip to content

Commit

Permalink
Use ignore for better control over globbing
Browse files Browse the repository at this point in the history
resolves #13: Includes and excludes
resolves #24: Follows .gitgnore directives
  • Loading branch information
basile-henry committed Jan 28, 2021
1 parent e6e98b6 commit 58074d9
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 33 deletions.
101 changes: 101 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down
5 changes: 2 additions & 3 deletions examples/monorepo/prjfmt.toml
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -17,4 +16,4 @@ files = [ "*.rs" ]
includes = [ "rust/" ]
excludes = []
command = "cargo"
args = [ "fmt", "--" ]
args = [ "fmt", "--" ]
82 changes: 52 additions & 30 deletions src/formatters/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<Vec<String>>,
_excludes: &Option<Vec<String>>,
includes: &Option<Vec<String>>,
excludes: &Option<Vec<String>>,
) -> anyhow::Result<Vec<PathBuf>> {
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.clone().into_iter() {
overrides_builder.add(&format!("{}/**/{}", include, extension))?;
}
}
} else {
for extension in extensions.clone().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
Expand Down Expand Up @@ -246,6 +255,19 @@ pub enum FileExtensions {
MultipleFile(Vec<String>),
}

impl IntoIterator for FileExtensions {
type Item = String;
type IntoIter = either::Either<std::iter::Once<String>, std::vec::IntoIter<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.into_iter()),
}
}
}

#[derive(Debug, Deserialize, Serialize, Clone)]
/// Each context of the formatter config
pub struct CmdContext {
Expand Down

0 comments on commit 58074d9

Please sign in to comment.