Skip to content

Commit 5e7d035

Browse files
Cleanup public source entry creation
1 parent b6ab98f commit 5e7d035

File tree

3 files changed

+146
-143
lines changed

3 files changed

+146
-143
lines changed

crates/oxide/src/glob.rs

Lines changed: 2 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use crate::PublicSourceEntry;
21
use fxhash::{FxHashMap, FxHashSet};
32
use std::path::PathBuf;
4-
use tracing::{event, Level};
3+
use tracing::event;
54

65
#[derive(Debug, Clone, PartialEq)]
76
pub struct GlobEntry {
@@ -12,105 +11,6 @@ pub struct GlobEntry {
1211
pub pattern: String,
1312
}
1413

15-
/// Optimize the PublicSourceEntry by trying to move all the static parts of the pattern to the
16-
/// base of the PublicSourceEntry.
17-
///
18-
/// ```diff
19-
/// - { base: '/', pattern: 'src/**/*.html'}
20-
/// + { base: '/src', pattern: '**/*.html'}
21-
/// ```
22-
///
23-
/// A file stays in the `pattern` part, because the `base` should only be a directory.
24-
///
25-
/// ```diff
26-
/// - { base: '/', pattern: 'src/examples/index.html'}
27-
/// + { base: '/src/examples', pattern: 'index.html'}
28-
/// ```
29-
///
30-
/// A folder will be moved to the `base` part, and the `pattern` will be set to `**/*`.
31-
///
32-
/// ```diff
33-
/// - { base: '/', pattern: 'src/examples'}
34-
/// + { base: '/src/examples', pattern: '**/*'}
35-
/// ```
36-
///
37-
/// In addition, we will canonicalize the base path so we always work with the correctly resolved
38-
/// path.
39-
pub fn optimize_public_source_entry(source: &mut PublicSourceEntry) {
40-
// Resolve base path immediately
41-
let Ok(base) = dunce::canonicalize(&source.base) else {
42-
event!(Level::ERROR, "Failed to resolve base: {:?}", source.base);
43-
return;
44-
};
45-
source.base = base.to_string_lossy().to_string();
46-
47-
// No dynamic part, figure out if we are dealing with a file or a directory.
48-
if !source.pattern.contains('*') {
49-
let combined_path = if source.pattern.starts_with("/") {
50-
PathBuf::from(&source.pattern)
51-
} else {
52-
PathBuf::from(&source.base).join(&source.pattern)
53-
};
54-
55-
match dunce::canonicalize(combined_path) {
56-
Ok(resolved_path) if resolved_path.is_dir() => {
57-
source.base = resolved_path.to_string_lossy().to_string();
58-
source.pattern = "**/*".to_owned();
59-
}
60-
Ok(resolved_path) if resolved_path.is_file() => {
61-
source.base = resolved_path
62-
.parent()
63-
.unwrap()
64-
.to_string_lossy()
65-
.to_string();
66-
// Ensure leading slash, otherwise it will match against all files in all folders/
67-
source.pattern = format!(
68-
"/{}",
69-
resolved_path
70-
.file_name()
71-
.unwrap()
72-
.to_string_lossy()
73-
.to_string()
74-
);
75-
}
76-
_ => {}
77-
}
78-
return;
79-
}
80-
81-
// Contains dynamic part
82-
let (static_part, dynamic_part) = split_pattern(&source.pattern);
83-
84-
let base: PathBuf = source.base.clone().into();
85-
let base = match static_part {
86-
Some(static_part) => base.join(static_part),
87-
None => base,
88-
};
89-
90-
// TODO: If the base does not exist on disk, try removing the last slash and try again.
91-
let base = match dunce::canonicalize(&base) {
92-
Ok(base) => base,
93-
Err(err) => {
94-
event!(tracing::Level::ERROR, "Failed to resolve glob: {:?}", err);
95-
return;
96-
}
97-
};
98-
99-
let pattern = match dynamic_part {
100-
Some(dynamic_part) => dynamic_part,
101-
None => {
102-
if base.is_dir() {
103-
"**/*".to_owned()
104-
} else {
105-
"".to_owned()
106-
}
107-
}
108-
};
109-
110-
source.base = base.to_string_lossy().to_string();
111-
source.pattern = pattern;
112-
}
113-
11414
pub fn hoist_static_glob_parts(entries: &Vec<GlobEntry>, emit_parent_glob: bool) -> Vec<GlobEntry> {
11515
let mut result = vec![];
11616

@@ -254,7 +154,7 @@ pub fn optimize_patterns(entries: &Vec<GlobEntry>) -> Vec<GlobEntry> {
254154
// Input: `../project-b/foo/bar.html`
255155
// Split results in: `("../project-b/foo", "bar.html")`
256156
//
257-
fn split_pattern(pattern: &str) -> (Option<String>, Option<String>) {
157+
pub fn split_pattern(pattern: &str) -> (Option<String>, Option<String>) {
258158
// No dynamic parts, so we can just return the input as-is.
259159
if !pattern.contains('*') {
260160
return (Some(pattern.to_owned()), None);

crates/oxide/src/scanner/sources.rs

Lines changed: 97 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use crate::glob::optimize_public_source_entry;
1+
use crate::glob::split_pattern;
22
use crate::GlobEntry;
33
use bexpand::Expression;
44
use std::path::PathBuf;
5+
use tracing::{event, Level};
56

67
use super::auto_source_detection::IGNORED_CONTENT_DIRS;
78

@@ -75,25 +76,103 @@ impl Sources {
7576
}
7677

7778
impl PublicSourceEntry {
78-
#[cfg(test)]
79-
pub fn from_pattern(dir: PathBuf, pattern: &str) -> Self {
80-
let mut parts = pattern.split_whitespace();
81-
let _ = parts.next().unwrap_or_default();
82-
let not_or_pattern = parts.next().unwrap_or_default();
83-
if not_or_pattern == "not" {
84-
let pattern = parts.next().unwrap_or_default();
85-
return Self {
86-
base: dir.to_string_lossy().into(),
87-
pattern: pattern[1..pattern.len() - 1].to_string(),
88-
negated: true,
79+
/// Optimize the PublicSourceEntry by trying to move all the static parts of the pattern to the
80+
/// base of the PublicSourceEntry.
81+
///
82+
/// ```diff
83+
/// - { base: '/', pattern: 'src/**/*.html'}
84+
/// + { base: '/src', pattern: '**/*.html'}
85+
/// ```
86+
///
87+
/// A file stays in the `pattern` part, because the `base` should only be a directory.
88+
///
89+
/// ```diff
90+
/// - { base: '/', pattern: 'src/examples/index.html'}
91+
/// + { base: '/src/examples', pattern: 'index.html'}
92+
/// ```
93+
///
94+
/// A folder will be moved to the `base` part, and the `pattern` will be set to `**/*`.
95+
///
96+
/// ```diff
97+
/// - { base: '/', pattern: 'src/examples'}
98+
/// + { base: '/src/examples', pattern: '**/*'}
99+
/// ```
100+
///
101+
/// In addition, we will canonicalize the base path so we always work with the correctly
102+
/// resolved path.
103+
pub fn optimize(&mut self) {
104+
// Resolve base path immediately
105+
let Ok(base) = dunce::canonicalize(&self.base) else {
106+
event!(Level::ERROR, "Failed to resolve base: {:?}", self.base);
107+
return;
108+
};
109+
self.base = base.to_string_lossy().to_string();
110+
111+
// No dynamic part, figure out if we are dealing with a file or a directory.
112+
if !self.pattern.contains('*') {
113+
let combined_path = if self.pattern.starts_with("/") {
114+
PathBuf::from(&self.pattern)
115+
} else {
116+
PathBuf::from(&self.base).join(&self.pattern)
89117
};
90-
}
91118

92-
Self {
93-
base: dir.to_string_lossy().into(),
94-
pattern: not_or_pattern[1..not_or_pattern.len() - 1].to_string(),
95-
negated: false,
119+
match dunce::canonicalize(combined_path) {
120+
Ok(resolved_path) if resolved_path.is_dir() => {
121+
self.base = resolved_path.to_string_lossy().to_string();
122+
self.pattern = "**/*".to_owned();
123+
}
124+
Ok(resolved_path) if resolved_path.is_file() => {
125+
self.base = resolved_path
126+
.parent()
127+
.unwrap()
128+
.to_string_lossy()
129+
.to_string();
130+
// Ensure leading slash, otherwise it will match against all files in all folders/
131+
self.pattern = format!(
132+
"/{}",
133+
resolved_path
134+
.file_name()
135+
.unwrap()
136+
.to_string_lossy()
137+
.to_string()
138+
);
139+
}
140+
_ => {}
141+
}
142+
return;
96143
}
144+
145+
// Contains dynamic part
146+
let (static_part, dynamic_part) = split_pattern(&self.pattern);
147+
148+
let base: PathBuf = self.base.clone().into();
149+
let base = match static_part {
150+
Some(static_part) => base.join(static_part),
151+
None => base,
152+
};
153+
154+
// TODO: If the base does not exist on disk, try removing the last slash and try again.
155+
let base = match dunce::canonicalize(&base) {
156+
Ok(base) => base,
157+
Err(err) => {
158+
event!(tracing::Level::ERROR, "Failed to resolve glob: {:?}", err);
159+
return;
160+
}
161+
};
162+
163+
let pattern = match dynamic_part {
164+
Some(dynamic_part) => dynamic_part,
165+
None => {
166+
if base.is_dir() {
167+
"**/*".to_owned()
168+
} else {
169+
"".to_owned()
170+
}
171+
}
172+
};
173+
174+
self.base = base.to_string_lossy().to_string();
175+
self.pattern = pattern;
97176
}
98177
}
99178

@@ -139,7 +218,7 @@ pub fn public_source_entries_to_private_source_entries(
139218
.collect::<Vec<_>>()
140219
})
141220
.map(|mut public_source| {
142-
optimize_public_source_entry(&mut public_source);
221+
public_source.optimize();
143222
public_source
144223
})
145224
.collect::<Vec<_>>();

0 commit comments

Comments
 (0)