Skip to content

Commit

Permalink
Merge pull request #58 from ndtoan96/glob
Browse files Browse the repository at this point in the history
Add support for glob pattern
  • Loading branch information
dmerejkowsky committed Apr 1, 2021
2 parents 027d4da + 4eedffa commit 80d523b
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 7 deletions.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,24 @@ Patching src/foo.txt
++ spam_eggs, SpamEggs, and SPAM_EGGS!
```

## Filter files by type
## Filter files by type or glob patterns

Inspired by [ripgrep](https://github.com/BurntSushi/ripgrep), you can also select or ignore certain "file types":
Inspired by [ripgrep](https://github.com/BurntSushi/ripgrep), you can also select or ignore certain "file types" or glob patterns:

```
# Select only C++ files
$ ruplacer old new --type cpp
# Select only *.foo files
$ ruplacer old new --type *.foo
# Select only files that match foo*bar.c
$ ruplacer old new --type foo*bar.c
# Ignore all js files
$ ruplacer old new --type-ignore js
$ ruplacer old new --type-not js
# Ignore all *.bar files
$ ruplacer old new --type-not *.bar
# Ignore all files that match foo*bar.c
$ ruplacer old new --type-not foo*bar.c
```

Each "file type" is just a list of glob pattern. For instance: the `cpp` file type matches `*.C`, `*.H`, `*.cc`, `*.cpp` and so on ...
Expand Down
23 changes: 21 additions & 2 deletions src/directory_patcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,30 @@ impl DirectoryPatcher {
fn build_walker(&self) -> ignore::Walk {
let mut types_builder = ignore::types::TypesBuilder::new();
types_builder.add_defaults();
let mut cnt: u32 = 0;
for t in &self.settings.selected_file_types {
types_builder.select(t);
// Check if filter is file type or glob pattern
if t.contains("*") {
let new_type = format!("type{}", cnt);
// Note: .add(name, glob) only returns error with wrong name, hence unwrap()
types_builder.add(&new_type, t).unwrap();
types_builder.select(&new_type);
cnt += 1;
} else {
types_builder.select(t);
}
}
for t in &self.settings.ignored_file_types {
types_builder.negate(t);
// Check if filter is file type or glob pattern
if t.contains("*") {
let new_type = format!("type{}", cnt);
// Note: .add(name, glob) only returns error with wrong name, hence unwrap()
types_builder.add(&new_type, t).unwrap();
types_builder.negate(&new_type);
cnt += 1;
} else {
types_builder.negate(t);
}
}
let types_matcher = types_builder
.build()
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ struct Options {
#[structopt(
short = "t",
long = "type",
help = "Only search files matching <file_type>",
help = "Only search files matching <file_type> or glob pattern.",
multiple = true,
number_of_values = 1
)]
Expand All @@ -94,7 +94,7 @@ struct Options {
#[structopt(
short = "T",
long = "type-not",
help = "Ignore files matching <file_type>",
help = "Ignore files matching <file_type> or glob pattern.",
multiple = true,
number_of_values = 1
)]
Expand Down
91 changes: 91 additions & 0 deletions tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@ use ruplacer::Settings;

fn setup_test(tmp_dir: &TempDir) -> PathBuf {
let tmp_path = tmp_dir.path();
#[cfg(target_os="linux")]
let status = Command::new("cp")
.args(&["-R", "tests/data", &tmp_path.to_string_lossy()])
.status()
.expect("Failed to execute process");
#[cfg(target_os="windows")]
let status = Command::new("xcopy")
.args(&["/E", "/I", "tests\\data", &tmp_path.join("data").to_string_lossy()])
.status()
.expect("Failed to execute process");
assert!(status.success());
tmp_path.join("data")
}
Expand Down Expand Up @@ -159,6 +165,51 @@ fn test_select_file_types() {
assert_eq!(stats.matching_files, 1);
}

#[test]
fn test_select_file_types_by_glob_pattern_1() {
let tmp_dir = TempDir::new("test-ruplacer").expect("failed to create temp dir");
let data_path = setup_test(&tmp_dir);
add_python_file(&data_path);

let settings = Settings {
selected_file_types: vec!["*.py".to_string()],
..Default::default()
};
let patcher = run_ruplacer(&data_path, settings);

let stats = patcher.stats();
assert_eq!(stats.matching_files, 1);
}

#[test]
fn test_select_file_types_by_glob_pattern_2() {
let tmp_dir = TempDir::new("test-ruplacer").expect("failed to create temp dir");
let data_path = setup_test(&tmp_dir);
add_python_file(&data_path);

let settings = Settings {
selected_file_types: vec!["f*.py".to_string()],
..Default::default()
};
let patcher = run_ruplacer(&data_path, settings);

let stats = patcher.stats();
assert_eq!(stats.matching_files, 1);
}

#[test]
#[should_panic]
fn test_select_file_types_by_wrong_glob_pattern() {
let tmp_dir = TempDir::new("test-ruplacer").expect("failed to create temp dir");
let data_path = setup_test(&tmp_dir);

let settings = Settings {
selected_file_types: vec!["f**.py".to_string()],
..Default::default()
};
run_ruplacer(&data_path, settings);
}

#[test]
fn test_ignore_file_types() {
let tmp_dir = TempDir::new("test-ruplacer").expect("failed to create temp dir");
Expand All @@ -172,3 +223,43 @@ fn test_ignore_file_types() {

assert_not_replaced(&py_path);
}

#[test]
fn test_ignore_file_types_by_glob_pattern_1() {
let tmp_dir = TempDir::new("test-ruplacer").expect("failed to create temp dir");
let data_path = setup_test(&tmp_dir);
let py_path = add_python_file(&data_path);
let settings = Settings {
ignored_file_types: vec!["*.py".to_string()],
..Default::default()
};
run_ruplacer(&data_path, settings);

assert_not_replaced(&py_path);
}

#[test]
fn test_ignore_file_types_by_glob_pattern_2() {
let tmp_dir = TempDir::new("test-ruplacer").expect("failed to create temp dir");
let data_path = setup_test(&tmp_dir);
let py_path = add_python_file(&data_path);
let settings = Settings {
ignored_file_types: vec!["f*.py".to_string()],
..Default::default()
};
run_ruplacer(&data_path, settings);

assert_not_replaced(&py_path);
}

#[test]
#[should_panic]
fn test_ignore_file_types_by_wrong_glob_pattern() {
let tmp_dir = TempDir::new("test-ruplacer").expect("failed to create temp dir");
let data_path = setup_test(&tmp_dir);
let settings = Settings {
ignored_file_types: vec!["**.py".to_string()],
..Default::default()
};
run_ruplacer(&data_path, settings);
}

0 comments on commit 80d523b

Please sign in to comment.