Skip to main content

rich_ext/diff/
transform.rs

1//! Transforms over a parsed git [`Patch`], for a
2//! [`Pipeline`](crate::transform::Pipeline).
3
4use super::git::Patch;
5use crate::env_inspect::name_matches;
6use crate::transform::{Transform, TransformError};
7
8/// Keeps the files whose old or new path matches any pattern: a
9/// case-insensitive substring, or a whole-path glob with `*` and `?`.
10#[derive(Clone, Debug)]
11pub struct KeepFiles(pub Vec<String>);
12
13impl Transform<Patch> for KeepFiles {
14    fn apply(&self, mut patch: Patch) -> Result<Patch, TransformError> {
15        patch.files.retain(|file| {
16            [&file.old_path, &file.new_path]
17                .into_iter()
18                .flatten()
19                .any(|path| self.0.iter().any(|pattern| name_matches(pattern, path)))
20        });
21        Ok(patch)
22    }
23}
24
25#[cfg(test)]
26mod tests {
27    use super::*;
28    use crate::diff::git::parse_unified;
29
30    #[test]
31    fn keeps_matching_files() {
32        let patch = parse_unified(
33            "diff --git a/src/a.rs b/src/a.rs\n--- a/src/a.rs\n+++ b/src/a.rs\n@@ -1 +1 @@\n-a\n+b\n\
34             diff --git a/README.md b/README.md\n--- a/README.md\n+++ b/README.md\n@@ -1 +1 @@\n-a\n+b\n",
35        )
36        .unwrap();
37        let kept = KeepFiles(vec!["*.rs".into()]).apply(patch.clone()).unwrap();
38        assert_eq!(kept.files.len(), 1);
39        assert_eq!(kept.files[0].path(), "src/a.rs");
40        assert_eq!(kept.stats(), (1, 1));
41        let readme = KeepFiles(vec!["readme".into()]).apply(patch).unwrap();
42        assert_eq!(readme.files[0].path(), "README.md");
43    }
44}