Skip to content

Commit aa894ed

Browse files
committed
crossbeam
1 parent a21ecb4 commit aa894ed

File tree

3 files changed

+42
-35
lines changed

3 files changed

+42
-35
lines changed

Cargo.lock

Lines changed: 12 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ serde_yaml = "0.9.34"
2929
tempfile = "3.13.0"
3030
tracing = "0.1.40"
3131
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
32+
crossbeam-channel = "0.5.15"
3233

3334
[dev-dependencies]
3435
assert_cmd = "2.0.16"

src/project_builder.rs

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::{
66

77
use error_stack::{Report, Result, ResultExt};
88
use fast_glob::glob_match;
9-
use ignore::{WalkBuilder, WalkParallel, WalkState};
9+
use ignore::{DirEntry, WalkBuilder, WalkParallel, WalkState};
1010
use rayon::iter::{IntoParallelIterator, ParallelIterator};
1111
use tracing::{instrument, warn};
1212

@@ -53,25 +53,36 @@ impl<'a> ProjectBuilder<'a> {
5353
pub fn build(&mut self) -> Result<Project, Error> {
5454
let mut builder = WalkBuilder::new(&self.base_path);
5555
builder.hidden(false);
56+
builder.follow_links(false);
57+
// Prune traversal early: skip heavy and irrelevant directories
58+
let skip_dirs = ["node_modules", ".git", ".hg", ".svn", "target", ".idea", ".vscode", "tmp"];
59+
builder.filter_entry(move |entry: &DirEntry| {
60+
let _path = entry.path();
61+
let file_name = entry.file_name().to_str().unwrap_or("");
62+
if let Some(ft) = entry.file_type() {
63+
if ft.is_dir() && skip_dirs.iter().any(|d| *d == file_name) {
64+
return false;
65+
}
66+
}
67+
true
68+
});
69+
5670
let walk_parallel: WalkParallel = builder.build_parallel();
5771

58-
let collected_entry_types = Arc::new(Mutex::new(Vec::with_capacity(INITIAL_VECTOR_CAPACITY)));
59-
let collected_for_threads = Arc::clone(&collected_entry_types);
72+
let (tx, rx) = crossbeam_channel::unbounded::<EntryType>();
6073
let error_holder: Arc<Mutex<Option<Report<Error>>>> = Arc::new(Mutex::new(None));
6174
let error_holder_for_threads = Arc::clone(&error_holder);
6275

6376
let this: &ProjectBuilder<'a> = self;
6477

6578
walk_parallel.run(move || {
66-
let collected = Arc::clone(&collected_for_threads);
6779
let error_holder = Arc::clone(&error_holder_for_threads);
80+
let tx = tx.clone();
6881
Box::new(move |res| {
6982
if let Ok(entry) = res {
7083
match this.build_entry_type(entry) {
7184
Ok(entry_type) => {
72-
if let Ok(mut v) = collected.lock() {
73-
v.push(entry_type);
74-
}
85+
let _ = tx.send(entry_type);
7586
}
7687
Err(report) => {
7788
if let Ok(mut slot) = error_holder.lock() {
@@ -87,19 +98,7 @@ impl<'a> ProjectBuilder<'a> {
8798
});
8899

89100
// Take ownership of the collected entry types
90-
let entry_types = match Arc::try_unwrap(collected_entry_types) {
91-
Ok(mutex) => match mutex.into_inner() {
92-
Ok(entries) => entries,
93-
Err(poisoned) => poisoned.into_inner(),
94-
},
95-
Err(arc) => match arc.lock() {
96-
Ok(mut guard) => std::mem::take(&mut *guard),
97-
Err(poisoned) => {
98-
let mut guard = poisoned.into_inner();
99-
std::mem::take(&mut *guard)
100-
}
101-
},
102-
};
101+
let entry_types: Vec<EntryType> = rx.iter().collect();
103102

104103
// If any error occurred while building entry types, return it
105104
let maybe_error = match Arc::try_unwrap(error_holder) {
@@ -179,16 +178,16 @@ impl<'a> ProjectBuilder<'a> {
179178
project_files.push(project_file);
180179
}
181180
EntryType::Directory(absolute_path, relative_path) => {
182-
if relative_path.parent() == Some(Path::new(&self.config.vendored_gems_path)) {
183-
if let Some(file_name) = relative_path.file_name() {
184-
gems.push(VendoredGem {
185-
path: absolute_path,
186-
name: file_name.to_string_lossy().to_string(),
187-
});
188-
} else {
189-
warn!("Vendored gem path without file name: {:?}", relative_path);
190-
}
191-
}
181+
if relative_path.parent() == Some(Path::new(&self.config.vendored_gems_path)) {
182+
if let Some(file_name) = relative_path.file_name() {
183+
gems.push(VendoredGem {
184+
path: absolute_path,
185+
name: file_name.to_string_lossy().to_string(),
186+
});
187+
} else {
188+
warn!("Vendored gem path without file name: {:?}", relative_path);
189+
}
190+
}
192191
}
193192
EntryType::RubyPackage(absolute_path, relative_path) => {
194193
match ruby_package_owner(&absolute_path) {

0 commit comments

Comments
 (0)