|
1 | 1 | use std::{ |
2 | | - fs::File, |
3 | | - path::{Path, PathBuf}, |
| 2 | + env, fs::File, path::{Path, PathBuf} |
4 | 3 | }; |
5 | 4 |
|
6 | 5 | use error_stack::{Result, ResultExt}; |
7 | 6 | use fast_glob::glob_match; |
8 | 7 | use ignore::WalkBuilder; |
| 8 | +use jwalk::WalkDir; |
9 | 9 | use rayon::iter::{IntoParallelIterator, ParallelIterator}; |
10 | 10 | use tracing::instrument; |
11 | 11 |
|
@@ -50,22 +50,46 @@ impl<'a> ProjectBuilder<'a> { |
50 | 50 |
|
51 | 51 | #[instrument(level = "debug", skip_all)] |
52 | 52 | pub fn build(&mut self) -> Result<Project, Error> { |
| 53 | + match env::var("jwalk") { |
| 54 | + Ok(_) => self.build_with_jwalk(), |
| 55 | + Err(_) => self.build_with_walkdir(), |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + fn build_with_jwalk(&mut self) -> Result<Project, Error> { |
| 60 | + dbg!("building with jwalk"); |
| 61 | + let mut entry_types = Vec::with_capacity(INITIAL_VECTOR_CAPACITY); |
| 62 | + |
| 63 | + for entry in WalkDir::new(&self.base_path).follow_links(true).skip_hidden(false).into_iter() { |
| 64 | + let entry = match entry.change_context(Error::Io) { |
| 65 | + Ok(entry) => entry, |
| 66 | + Err(_) => continue, |
| 67 | + }; |
| 68 | + let absolute_path = entry.path(); |
| 69 | + let is_dir = entry.file_type().is_dir(); |
| 70 | + entry_types.push(self.build_entry_type(&absolute_path, is_dir)?); |
| 71 | + } |
| 72 | + self.build_project_from_entry_types(entry_types) |
| 73 | + } |
| 74 | + |
| 75 | + fn build_with_walkdir(&mut self) -> Result<Project, Error> { |
| 76 | + dbg!("building with walkdir"); |
53 | 77 | let mut entry_types = Vec::with_capacity(INITIAL_VECTOR_CAPACITY); |
54 | 78 | let mut builder = WalkBuilder::new(&self.base_path); |
55 | 79 | builder.hidden(false); |
56 | 80 | let walkdir = builder.build(); |
57 | 81 |
|
58 | 82 | for entry in walkdir { |
59 | 83 | let entry = entry.change_context(Error::Io)?; |
60 | | - entry_types.push(self.build_entry_type(entry)?); |
| 84 | + let absolute_path = entry.path(); |
| 85 | + let is_dir = entry.file_type().ok_or(Error::Io).change_context(Error::Io)?.is_dir(); |
| 86 | + |
| 87 | + entry_types.push(self.build_entry_type(absolute_path, is_dir)?); |
61 | 88 | } |
62 | 89 | self.build_project_from_entry_types(entry_types) |
63 | 90 | } |
64 | 91 |
|
65 | | - fn build_entry_type(&mut self, entry: ignore::DirEntry) -> Result<EntryType, Error> { |
66 | | - let absolute_path = entry.path(); |
67 | | - |
68 | | - let is_dir = entry.file_type().ok_or(Error::Io).change_context(Error::Io)?.is_dir(); |
| 92 | + fn build_entry_type(&mut self, absolute_path: &Path, is_dir: bool) -> Result<EntryType, Error> { |
69 | 93 | let relative_path = absolute_path.strip_prefix(&self.base_path).change_context(Error::Io)?.to_owned(); |
70 | 94 |
|
71 | 95 | if is_dir { |
@@ -97,6 +121,88 @@ impl<'a> ProjectBuilder<'a> { |
97 | 121 | } |
98 | 122 |
|
99 | 123 | fn build_project_from_entry_types(&mut self, entry_types: Vec<EntryType>) -> Result<Project, Error> { |
| 124 | + match env::var("entryrayon") { |
| 125 | + Ok(_) => self.build_project_from_entry_types_rayon(entry_types), |
| 126 | + Err(_) => self.build_project_from_entry_types_serial(entry_types), |
| 127 | + } |
| 128 | + } |
| 129 | + |
| 130 | + fn build_project_from_entry_types_serial(&mut self, entry_types: Vec<EntryType>) -> Result<Project, Error> { |
| 131 | + dbg!("building with serial"); |
| 132 | + let mut project_files = Vec::<ProjectFile>::with_capacity(INITIAL_VECTOR_CAPACITY); |
| 133 | + let mut vendored_gems = Vec::<VendoredGem>::new(); |
| 134 | + let mut packages = Vec::<Package>::new(); |
| 135 | + let mut directory_codeowner_files = Vec::<DirectoryCodeownersFile>::new(); |
| 136 | + let mut teams = Vec::<Team>::new(); |
| 137 | + |
| 138 | + for entry_type in entry_types { |
| 139 | + match entry_type { |
| 140 | + EntryType::OwnedFile(project_file) => { |
| 141 | + project_files.push(project_file); |
| 142 | + } |
| 143 | + EntryType::Directory(absolute_path, relative_path) => { |
| 144 | + if relative_path.parent() == Some(Path::new(&self.config.vendored_gems_path)) { |
| 145 | + let file_name = relative_path.file_name().expect("expected a file_name"); |
| 146 | + vendored_gems.push(VendoredGem { |
| 147 | + path: absolute_path, |
| 148 | + name: file_name.to_string_lossy().to_string(), |
| 149 | + }); |
| 150 | + } |
| 151 | + } |
| 152 | + EntryType::RubyPackage(absolute_path, relative_path) => { |
| 153 | + if let Some(owner) = ruby_package_owner(&absolute_path).unwrap() { |
| 154 | + packages.push(Package { |
| 155 | + path: relative_path.clone(), |
| 156 | + owner, |
| 157 | + package_type: PackageType::Ruby, |
| 158 | + }); |
| 159 | + } |
| 160 | + } |
| 161 | + EntryType::JavascriptPackage(absolute_path, relative_path) => { |
| 162 | + if let Some(owner) = javascript_package_owner(&absolute_path).unwrap() { |
| 163 | + packages.push(Package { |
| 164 | + path: relative_path.clone(), |
| 165 | + owner, |
| 166 | + package_type: PackageType::Javascript, |
| 167 | + }); |
| 168 | + } |
| 169 | + } |
| 170 | + EntryType::CodeownerFile(absolute_path, relative_path) => { |
| 171 | + let owner = std::fs::read_to_string(absolute_path).unwrap(); |
| 172 | + let owner = owner.trim().to_owned(); |
| 173 | + directory_codeowner_files.push(DirectoryCodeownersFile { |
| 174 | + path: relative_path.clone(), |
| 175 | + owner, |
| 176 | + }); |
| 177 | + } |
| 178 | + EntryType::TeamFile(absolute_path, _relative_path) => { |
| 179 | + let file = File::open(&absolute_path).unwrap(); |
| 180 | + let deserializer: deserializers::Team = serde_yaml::from_reader(file).unwrap(); |
| 181 | + teams.push(Team { |
| 182 | + path: absolute_path.to_owned(), |
| 183 | + name: deserializer.name, |
| 184 | + github_team: deserializer.github.team, |
| 185 | + owned_globs: deserializer.owned_globs, |
| 186 | + owned_gems: deserializer.ruby.map(|ruby| ruby.owned_gems).unwrap_or_default(), |
| 187 | + avoid_ownership: deserializer.github.do_not_add_to_codeowners_file, |
| 188 | + }); |
| 189 | + } |
| 190 | + EntryType::NullEntry() => {} |
| 191 | + } |
| 192 | + } |
| 193 | + Ok(Project { |
| 194 | + base_path: self.base_path.to_owned(), |
| 195 | + files: project_files, |
| 196 | + vendored_gems, |
| 197 | + teams, |
| 198 | + packages, |
| 199 | + codeowners_file_path: self.codeowners_file_path.to_path_buf(), |
| 200 | + directory_codeowner_files, |
| 201 | + }) |
| 202 | + } |
| 203 | + |
| 204 | + fn build_project_from_entry_types_rayon(&mut self, entry_types: Vec<EntryType>) -> Result<Project, Error> { |
| 205 | + dbg!("building entry types with rayon"); |
100 | 206 | let (project_files, packages, vendored_gems, directory_codeowners, teams): (Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>) = entry_types |
101 | 207 | .into_par_iter() |
102 | 208 | .fold( |
|
0 commit comments