Skip to content

Commit 2971302

Browse files
committed
wip: override builder optimization
1 parent 2b7ee14 commit 2971302

File tree

4 files changed

+81
-32
lines changed

4 files changed

+81
-32
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ custom_config.toml
77
example-repo
88
.codeowners.cache
99
perf.*
10+
example-repo
11+
CODEOWNERS

src/core/cache.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use super::parse::parse_repo;
1010
use super::tag_resolver::find_tags_for_file;
1111
use super::types::{CacheEncoding, CodeownersCache, CodeownersEntry, FileEntry};
1212
use crate::core::resolver::find_owners_and_tags_for_file;
13+
use crate::core::types::{CodeownersEntryMatcher, codeowners_entry_to_matcher};
1314
use crate::utils::error::{Error, Result};
1415

1516
/// Create a cache from parsed CODEOWNERS entries and files
@@ -21,17 +22,22 @@ pub fn build_cache(
2122

2223
println!("start building cache");
2324

25+
let matched_entries: Vec<CodeownersEntryMatcher> = entries
26+
.iter()
27+
.map(|entry| codeowners_entry_to_matcher(entry))
28+
.collect();
29+
2430
// Process each file to find owners and tags
2531
let file_entries: Vec<FileEntry> = files
26-
.par_chunks(10)
32+
.par_chunks(100)
2733
.flat_map(|chunk| {
2834
chunk
2935
.iter()
3036
.map(|file_path| {
3137
println!("Processing file: {}", file_path.display());
3238

3339
let (owners, tags) =
34-
find_owners_and_tags_for_file(file_path, &entries).unwrap();
40+
find_owners_and_tags_for_file(file_path, &matched_entries).unwrap();
3541

3642
// Build file entry
3743
FileEntry {

src/core/resolver.rs

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
1-
use super::types::Tag;
1+
use super::{
2+
smart_iter::SmartIter,
3+
types::{CodeownersEntryMatcher, Tag},
4+
};
25
use crate::utils::error::{Error, Result};
36
use ignore::overrides::{Override, OverrideBuilder};
47

5-
use std::path::Path;
8+
use std::{path::Path, time::Instant};
69

710
use super::types::{CodeownersEntry, Owner};
811

912
/// Find both owners and tags for a specific file based on all parsed CODEOWNERS entries
1013
pub fn find_owners_and_tags_for_file(
11-
file_path: &Path, entries: &[CodeownersEntry],
14+
file_path: &Path, entries: &[CodeownersEntryMatcher],
1215
) -> Result<(Vec<Owner>, Vec<Tag>)> {
1316
// Early return if no entries
1417
if entries.is_empty() {
1518
return Ok((Vec::new(), Vec::new()));
1619
}
17-
let target_dir = file_path.parent().ok_or_else(|| {
18-
std::io::Error::new(
19-
std::io::ErrorKind::InvalidInput,
20-
"file path has no parent directory",
21-
)
22-
})?;
20+
21+
let target_dir = file_path
22+
.parent()
23+
.ok_or_else(|| Error::new("file path has no parent directory"))?;
2324

2425
let mut candidates: Vec<_> = entries
2526
.iter()
@@ -45,31 +46,15 @@ pub fn find_owners_and_tags_for_file(
4546
Ok(p) => p,
4647
Err(_) => return None, // Should not happen due to starts_with check
4748
};
49+
4850
let depth = rel_path.components().count();
4951

5052
// Check if the pattern matches the target file
5153
let matches = {
52-
let mut builder = OverrideBuilder::new(codeowners_dir);
53-
if let Err(e) = builder.add(&entry.pattern) {
54-
eprintln!(
55-
"Invalid pattern '{}' in {}: {}",
56-
entry.pattern,
57-
entry.source_file.display(),
58-
e
59-
);
60-
return None;
61-
}
62-
let over: Override = match builder.build() {
63-
Ok(o) => o,
64-
Err(e) => {
65-
eprintln!(
66-
"Failed to build override for pattern '{}': {}",
67-
entry.pattern, e
68-
);
69-
return None;
70-
}
71-
};
72-
over.matched(file_path, false).is_whitelist()
54+
entry
55+
.override_matcher
56+
.matched(file_path, false)
57+
.is_whitelist()
7358
};
7459

7560
if matches { Some((entry, depth)) } else { None }

src/core/types.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::path::PathBuf;
22

3+
use ignore::overrides::Override;
34
use serde::{Deserialize, Serialize};
45

56
/// CODEOWNERS entry with source tracking
@@ -12,6 +13,61 @@ pub struct CodeownersEntry {
1213
pub tags: Vec<Tag>,
1314
}
1415

16+
/// CODEOWNERS entry with Override matcher
17+
#[derive(Debug)]
18+
pub struct CodeownersEntryMatcher {
19+
pub source_file: PathBuf,
20+
pub line_number: usize,
21+
pub pattern: String,
22+
pub owners: Vec<Owner>,
23+
pub tags: Vec<Tag>,
24+
pub override_matcher: Override,
25+
}
26+
27+
pub fn codeowners_entry_to_matcher(entry: &CodeownersEntry) -> CodeownersEntryMatcher {
28+
let codeowners_dir = match entry.source_file.parent() {
29+
Some(dir) => dir,
30+
None => {
31+
eprintln!(
32+
"CODEOWNERS entry has no parent directory: {}",
33+
entry.source_file.display()
34+
);
35+
panic!("Invalid CODEOWNERS entry without parent directory");
36+
}
37+
};
38+
39+
let mut builder = ignore::overrides::OverrideBuilder::new(codeowners_dir);
40+
41+
if let Err(e) = builder.add(&entry.pattern) {
42+
eprintln!(
43+
"Invalid pattern '{}' in {}: {}",
44+
entry.pattern,
45+
entry.source_file.display(),
46+
e
47+
);
48+
panic!("Invalid CODEOWNERS entry pattern");
49+
}
50+
let override_matcher: Override = match builder.build() {
51+
Ok(o) => o,
52+
Err(e) => {
53+
eprintln!(
54+
"Failed to build override for pattern '{}': {}",
55+
entry.pattern, e
56+
);
57+
panic!("Failed to build CODEOWNERS entry matcher");
58+
}
59+
};
60+
61+
CodeownersEntryMatcher {
62+
source_file: entry.source_file.clone(),
63+
line_number: entry.line_number,
64+
pattern: entry.pattern.clone(),
65+
owners: entry.owners.clone(),
66+
tags: entry.tags.clone(),
67+
override_matcher,
68+
}
69+
}
70+
1571
/// Detailed owner representation
1672
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
1773
pub struct Owner {

0 commit comments

Comments
 (0)