ruplacer/
directory_patcher.rs1use anyhow::{Context, Result};
2use std::path::Path;
3
4use crate::console::Console;
5use crate::file_patcher::FilePatcher;
6use crate::query::Query;
7use crate::settings::Settings;
8use crate::stats::Stats;
9
10#[derive(Debug)]
11pub struct DirectoryPatcher<'a> {
32 path: &'a Path,
33 settings: &'a Settings,
34 console: &'a Console,
35 stats: Stats,
36}
37
38impl<'a> DirectoryPatcher<'a> {
39 pub fn new(
40 console: &'a Console,
41 path: &'a Path,
42 settings: &'a Settings,
43 ) -> DirectoryPatcher<'a> {
44 let stats = Stats::default();
45 DirectoryPatcher {
46 console,
47 path,
48 settings,
49 stats,
50 }
51 }
52
53 pub fn run(&mut self, query: &Query) -> Result<()> {
55 let walker = self.build_walker()?;
56 for entry in walker {
57 let entry = entry.with_context(|| "Could not read directory entry")?;
58 if let Some(file_type) = entry.file_type() {
59 if file_type.is_file() {
60 self.patch_file(entry.path(), query)?;
61 }
62 }
63 }
64 Ok(())
65 }
66
67 pub fn stats(self) -> Stats {
68 self.stats
69 }
70
71 pub(crate) fn patch_file(&mut self, entry: &Path, query: &Query) -> Result<()> {
72 let file_patcher = FilePatcher::new(self.console, entry, query)?;
73 let file_patcher = match file_patcher {
74 None => return Ok(()),
75 Some(f) => f,
76 };
77 let num_replacements = file_patcher.num_replacements();
78 if num_replacements != 0 {
79 self.console.print_message("\n");
80 }
81 let num_lines = file_patcher.num_lines();
82 self.stats.update(num_lines, num_replacements);
83 if self.settings.dry_run {
84 return Ok(());
85 }
86 file_patcher.run()?;
87 Ok(())
88 }
89
90 fn build_walker(&self) -> Result<ignore::Walk> {
91 let mut types_builder = ignore::types::TypesBuilder::new();
92 types_builder.add_defaults();
93 let mut count: u32 = 0;
94 for t in &self.settings.selected_file_types {
95 if t.contains('*') {
97 let new_type = format!("type{}", count);
98 types_builder.add(&new_type, t).unwrap();
100 types_builder.select(&new_type);
101 count += 1;
102 } else {
103 types_builder.select(t);
104 }
105 }
106 for t in &self.settings.ignored_file_types {
107 if t.contains('*') {
109 let new_type = format!("type{}", count);
110 types_builder.add(&new_type, t).unwrap();
112 types_builder.negate(&new_type);
113 count += 1;
114 } else {
115 types_builder.negate(t);
116 }
117 }
118 let types_matcher = types_builder.build()?;
119 let mut walk_builder = ignore::WalkBuilder::new(self.path);
120 walk_builder.types(types_matcher);
121 if self.settings.ignored {
124 walk_builder.ignore(false);
125 }
126 if self.settings.hidden {
127 walk_builder.hidden(false);
128 }
129 Ok(walk_builder.build())
130 }
131}