Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add hidden flag to traverse hidden files #250

Merged
merged 1 commit into from
Oct 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clippy.toml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
too-many-arguments-threshold = 9
too-many-arguments-threshold = 10
8 changes: 8 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ treefmt [FLAGS] [OPTIONS] [--] [paths]...

> Only apply selected formatters. Defaults to all formatters.

`-H, --hidden`

> Also traverse hidden files (files that start with a .). This behaviour can be overridden with the `--no-hidden` flag.

`--no-hidden`

> Override the `--hidden` flag. Don't traverse hidden files.

`--tree-root <tree-root>`

> Set the path to the tree root directory where treefmt will look for the files to format. Defaults to the folder holding the `treefmt.toml` file. It’s mostly useful in combination with `--config-file` to specify the project root which won’t coincide with the directory holding `treefmt.toml`.
Expand Down
2 changes: 2 additions & 0 deletions src/command/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub fn format_cmd(
work_dir: &Path,
config_file: &Path,
paths: &[PathBuf],
hidden: bool,
no_cache: bool,
clear_cache: bool,
fail_on_change: bool,
Expand Down Expand Up @@ -55,6 +56,7 @@ pub fn format_cmd(
&cache_dir,
config_file,
&paths,
hidden,
no_cache,
clear_cache,
fail_on_change,
Expand Down
14 changes: 12 additions & 2 deletions src/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use std::{
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
/// Create a new treefmt.toml
/// Create a new treefmt.toml.
#[arg(short, long, default_value_t = false)]
pub init: bool,

Expand All @@ -39,6 +39,15 @@ pub struct Cli {
#[arg(short, long, default_value_t = false)]
pub clear_cache: bool,

#[arg(long = "hidden", short = 'H')]
/// Include hidden files while traversing the tree.
/// Override with the --no-hidden flag.
pub hidden: bool,
/// Overrides the --hidden flag.
/// Don't include hidden files while traversing the tree.
#[arg(long, overrides_with = "hidden", hide = true)]
no_hidden: bool,

/// Exit with error if any changes were made. Useful for CI.
#[arg(
long,
Expand All @@ -52,7 +61,7 @@ pub struct Cli {
#[arg(long, default_value_t = false)]
pub allow_missing_formatter: bool,

/// Log verbosity is based off the number of v used
/// Log verbosity is based off the number of v used.
#[clap(flatten)]
pub verbose: Verbosity<InfoLevel>,

Expand Down Expand Up @@ -158,6 +167,7 @@ pub fn run_cli(cli: &Cli) -> anyhow::Result<()> {
&cli.work_dir,
config_file,
&cli.paths,
cli.hidden,
cli.no_cache,
cli.clear_cache,
cli.fail_on_change,
Expand Down
147 changes: 136 additions & 11 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub fn run_treefmt(
cache_dir: &Path,
treefmt_toml: &Path,
paths: &[PathBuf],
hidden: bool,
no_cache: bool,
clear_cache: bool,
fail_on_change: bool,
Expand Down Expand Up @@ -89,7 +90,7 @@ pub fn run_treefmt(
cache.update_formatters(formatters.clone());
}

let walker = build_walker(paths);
let walker = build_walker(paths, hidden);

let matches = collect_matches_from_walker(walker, &formatters, &mut stats);
stats.timed_debug("tree walk");
Expand Down Expand Up @@ -322,14 +323,15 @@ fn collect_matches_from_walker(
}

/// Configure and build the tree walker
fn build_walker(paths: Vec<PathBuf>) -> Walk {
fn build_walker(paths: Vec<PathBuf>, hidden: bool) -> Walk {
// For some reason the WalkBuilder must start with one path, but can add more paths later.
// unwrap: we checked before that there is at least one path in the vector
let mut builder = WalkBuilder::new(paths.first().unwrap());
// Add the other paths
for path in paths[1..].iter() {
builder.add(path);
}
builder.hidden(!hidden);
// TODO: builder has a lot of interesting options.
// TODO: use build_parallel with a Visitor.
// See https://docs.rs/ignore/0.4.17/ignore/struct.WalkParallel.html#method.visit
Expand Down Expand Up @@ -981,7 +983,7 @@ mod tests {

let formatters = load_formatters(root, tree_root, false, &None, &mut stats).unwrap();

let walker = build_walker(vec![tree_root.to_path_buf()]);
let walker = build_walker(vec![tree_root.to_path_buf()], false);
let _matches = collect_matches_from_walker(walker, &formatters, &mut stats);

assert_eq!(stats.traversed_files, 3);
Expand Down Expand Up @@ -1030,13 +1032,62 @@ mod tests {

let formatters = load_formatters(root, tree_root, false, &None, &mut stats).unwrap();

let walker = build_walker(vec![tree_root.to_path_buf()]);
let walker = build_walker(vec![tree_root.to_path_buf()], false);
let _matches = collect_matches_from_walker(walker, &formatters, &mut stats);

assert_eq!(stats.traversed_files, 15);
assert_eq!(stats.matched_files, 9);
}
#[test]
fn test_walker_some_matches_walk_hidden() {
let tmpdir = utils::tmp_mkdir();

let black = tmpdir.path().join("black");
let nixpkgs_fmt = tmpdir.path().join("nixpkgs-fmt");
let elm_fmt = tmpdir.path().join("elm-fmt");
utils::write_binary_file(&black, " ");
utils::write_binary_file(&nixpkgs_fmt, " ");
utils::write_binary_file(&elm_fmt, " ");
let tree_root = tmpdir.path();

let files = vec!["test", "test1", "test3", ".test4"];

for file in files {
utils::write_file(tree_root.join(format!("{file}.py")), " ");
utils::write_file(tree_root.join(format!("{file}.nix")), " ");
utils::write_file(tree_root.join(format!("{file}.elm")), " ");
utils::write_file(tree_root.join(file), " ");
}

let config = format!(
"
[formatter.python]
command = {black:?}
includes = [\"*.py\"]

[formatter.nix]
command = {nixpkgs_fmt:?}
includes = [\"*.nix\"]

[formatter.elm]
command = {elm_fmt:?}
options = [\"--yes\"]
includes = [\"*.elm\"]
"
);

let root = from_string(&config).unwrap();
let mut stats = Statistics::init();

let formatters = load_formatters(root, tree_root, false, &None, &mut stats).unwrap();

let walker = build_walker(vec![tree_root.to_path_buf()], true);
let _matches = collect_matches_from_walker(walker, &formatters, &mut stats);

assert_eq!(stats.traversed_files, 19);
assert_eq!(stats.matched_files, 12);
}
#[test]
fn test_walker_some_matches_specific_include() {
let tmpdir = utils::tmp_mkdir();

Expand Down Expand Up @@ -1080,7 +1131,7 @@ mod tests {

let formatters = load_formatters(root, tree_root, false, &None, &mut stats).unwrap();

let walker = build_walker(vec![tree_root.to_path_buf()]);
let walker = build_walker(vec![tree_root.to_path_buf()], false);
let _matches = collect_matches_from_walker(walker, &formatters, &mut stats);

assert_eq!(stats.traversed_files, 15);
Expand Down Expand Up @@ -1130,7 +1181,7 @@ mod tests {

let formatters = load_formatters(root, tree_root, false, &None, &mut stats).unwrap();

let walker = build_walker(vec![tree_root.to_path_buf()]);
let walker = build_walker(vec![tree_root.to_path_buf()], false);
let matches = collect_matches_from_walker(walker, &formatters, &mut stats);

assert_eq!(stats.traversed_files, 12);
Expand Down Expand Up @@ -1213,7 +1264,7 @@ mod tests {

let formatters = load_formatters(root, tree_root, false, &None, &mut stats).unwrap();

let walker = build_walker(vec![tree_root.to_path_buf()]);
let walker = build_walker(vec![tree_root.to_path_buf()], false);
let matches = collect_matches_from_walker(walker, &formatters, &mut stats);

assert_eq!(stats.traversed_files, 18);
Expand Down Expand Up @@ -1285,7 +1336,7 @@ mod tests {

let formatters = load_formatters(root, tree_root, false, &None, &mut stats).unwrap();

let walker = build_walker(vec![tree_root.to_path_buf()]);
let walker = build_walker(vec![tree_root.to_path_buf()], false);
let matches = collect_matches_from_walker(walker, &formatters, &mut stats);

assert_eq!(stats.traversed_files, 7);
Expand Down Expand Up @@ -1347,7 +1398,7 @@ mod tests {

let formatters = load_formatters(root, tree_root, false, &None, &mut stats).unwrap();

let walker = build_walker(vec![tree_root.to_path_buf()]);
let walker = build_walker(vec![tree_root.to_path_buf()], false);
let matches = collect_matches_from_walker(walker, &formatters, &mut stats);

assert_eq!(stats.traversed_files, 7);
Expand Down Expand Up @@ -1417,7 +1468,7 @@ mod tests {

let formatters = load_formatters(root, tree_root, false, &None, &mut stats).unwrap();

let walker = build_walker(vec![tree_root.to_path_buf()]);
let walker = build_walker(vec![tree_root.to_path_buf()], false);
let matches = collect_matches_from_walker(walker, &formatters, &mut stats);

assert_eq!(stats.traversed_files, 8);
Expand Down Expand Up @@ -1486,7 +1537,7 @@ mod tests {

let formatters = load_formatters(root, tree_root, false, &None, &mut stats).unwrap();

let walker = build_walker(vec![tree_root.to_path_buf()]);
let walker = build_walker(vec![tree_root.to_path_buf()], false);
let matches = collect_matches_from_walker(walker, &formatters, &mut stats);

assert_eq!(stats.traversed_files, 7);
Expand All @@ -1505,4 +1556,78 @@ mod tests {
assert_eq!(python_matches, expected_python_matches);
assert!(nix_matches);
}
#[test]
fn test_walker_some_matches_exclude_gitignore_hidden() {
let tmpdir = utils::tmp_mkdir();

let black = tmpdir.path().join("black");
let nixpkgs_fmt = tmpdir.path().join("nixpkgs-fmt");
utils::write_binary_file(&black, " ");
utils::write_binary_file(&nixpkgs_fmt, " ");
let tree_root = tmpdir.path();
let git_dir = tree_root.join(".git");

utils::Git::new(tmpdir.path().to_path_buf())
.git_ignore("test1.nix\n.git/*.nix")
.exclude("result\n.direnv")
.create();

let files = vec!["test", "test1", ".test4"];

for file in files {
utils::write_file(tree_root.join(format!("{file}.py")), " ");
utils::write_file(tree_root.join(format!("{file}.nix")), " ");
utils::write_file(tree_root.join(format!("{file}.py")), " ");
utils::write_file(tree_root.join(format!("{file}.nix")), " ");
utils::write_file(git_dir.join(file), " ");
utils::write_file(tree_root.join(file), " ");
}
utils::write_file(tree_root.join("result"), " ");
utils::write_file(tree_root.join(".direnv"), " ");

let config = format!(
"
[formatter.python]
command = {black:?}
includes = [\"*.py\", \"test\"]
excludes = [\"test.py\" ]

[formatter.nix]
command = {nixpkgs_fmt:?}
includes = [\"*.nix\"]
excludes = [\"test.nix\"]
"
);

let root = from_string(&config).unwrap();
let mut stats = Statistics::init();

let formatters = load_formatters(root, tree_root, false, &None, &mut stats).unwrap();

let walker = build_walker(vec![tree_root.to_path_buf()], true);
let matches = collect_matches_from_walker(walker, &formatters, &mut stats);

assert_eq!(stats.traversed_files, 15);
assert_eq!(stats.matched_files, 5);
let python_matches: Vec<PathBuf> = matches
.get(&FormatterName::new("python"))
.unwrap()
.keys()
.cloned()
.collect();
let nix_matches: Vec<PathBuf> = matches
.get(&FormatterName::new("nix"))
.unwrap()
.keys()
.cloned()
.collect();
let expected_nix_matches: Vec<PathBuf> =
[".test4.nix"].iter().map(|p| tree_root.join(p)).collect();
let expected_python_matches: Vec<PathBuf> = [".git/test", ".test4.py", "test", "test1.py"]
.iter()
.map(|p| tree_root.join(p))
.collect();
assert_eq!(python_matches, expected_python_matches);
assert_eq!(nix_matches, expected_nix_matches);
}
}
Loading