Skip to content

Commit 9644c18

Browse files
committed
Use custom implementation of canonicalize for WASI
1 parent 85575a4 commit 9644c18

File tree

11 files changed

+74
-11
lines changed

11 files changed

+74
-11
lines changed

Cargo.lock

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

crates/fsops/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "fsops"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
name = "fsops"
8+
bench = false
9+
10+
[dependencies]
11+
dunce = "1.0.5"

crates/fsops/src/lib.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use std::io;
2+
use std::path::{Path, PathBuf};
3+
4+
/// https://github.com/oxc-project/oxc-resolver/blob/42a1e3eb50e9a1365c422c41d51f287fe5fb8244/src/file_system.rs#L93-L122
5+
pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
6+
#[cfg(not(target_os = "wasi"))]
7+
{
8+
dunce::canonicalize(path)
9+
}
10+
#[cfg(target_os = "wasi")]
11+
{
12+
canonicalize_wasi(path)
13+
}
14+
}
15+
16+
#[cfg(target_os = "wasi")]
17+
fn canonicalize_wasi<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
18+
use std::fs;
19+
let path = path.as_ref();
20+
let meta = fs::symlink_metadata(path)?;
21+
if meta.file_type().is_symlink() {
22+
let link = fs::read_link(path)?;
23+
let mut path_buf = path.to_path_buf();
24+
path_buf.pop();
25+
for segment in link.iter() {
26+
match segment.to_str() {
27+
Some("..") => {
28+
path_buf.pop();
29+
}
30+
Some(".") | None => {}
31+
Some(seg) => {
32+
// Need to trim the extra \0 introduces by rust std rust-lang/rust#123727
33+
path_buf.push(seg.trim_end_matches('\0'));
34+
}
35+
}
36+
}
37+
Ok(path_buf)
38+
} else {
39+
Ok(path.to_path_buf())
40+
}
41+
}

crates/ignore/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ memchr = "2.6.3"
2626
same-file = "1.0.6"
2727
walkdir = "2.4.0"
2828
dunce = "1.0.5"
29+
fsops = { path = "../fsops" }
2930

3031
[dependencies.regex-automata]
3132
version = "0.4.0"

crates/ignore/src/dir.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ impl Ignore {
176176
if !self.is_root() {
177177
panic!("Ignore::add_parents called on non-root matcher");
178178
}
179-
// CHANGED: Use `dunce::canonicalize` as we use it everywhere else.
180-
let absolute_base = match dunce::canonicalize(path.as_ref()) {
179+
// CHANGED: Use `fsops::canonicalize` as we use it everywhere else.
180+
let absolute_base = match fsops::canonicalize(path.as_ref()) {
181181
Ok(path) => Arc::new(path),
182182
Err(_) => {
183183
// There's not much we can do here, so just return our

crates/oxide/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ fast-glob = "0.4.3"
1919
classification-macros = { path = "../classification-macros" }
2020
ignore = { path = "../ignore" }
2121
regex = "1.11.1"
22+
fsops = { path = "../fsops" }
2223

2324
[dev-dependencies]
2425
tempfile = "3.13.0"

crates/oxide/src/glob.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub fn hoist_static_glob_parts(entries: &Vec<GlobEntry>, emit_parent_glob: bool)
2323
None => base,
2424
};
2525

26-
let base = match dunce::canonicalize(&base) {
26+
let base = match fsops::canonicalize(&base) {
2727
Ok(base) => base,
2828
Err(err) => {
2929
event!(tracing::Level::ERROR, "Failed to resolve glob: {:?}", err);
@@ -253,7 +253,7 @@ mod tests {
253253
let optimized_sources = optimize_patterns(&sources);
254254

255255
let parent_dir =
256-
format!("{}{}", dunce::canonicalize(base).unwrap().display(), "/").replace('\\', "/");
256+
format!("{}{}", fsops::canonicalize(base).unwrap().display(), "/").replace('\\', "/");
257257

258258
// Remove the temporary directory from the base
259259
optimized_sources

crates/oxide/src/paths.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,6 @@ impl Path {
6060
}
6161

6262
pub fn canonicalize(&self) -> io::Result<Self> {
63-
Ok(dunce::canonicalize(&self.inner)?.into())
63+
Ok(fsops::canonicalize(&self.inner)?.into())
6464
}
6565
}

crates/oxide/src/scanner/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ fn init_tracing() {
6363
.unwrap_or_else(|_| panic!("Failed to open {file_path}"));
6464

6565
let file_path = Path::new(&file_path);
66-
let absolute_file_path = dunce::canonicalize(file_path)
66+
let absolute_file_path = fsops::canonicalize(file_path)
6767
.unwrap_or_else(|_| panic!("Failed to canonicalize {file_path:?}"));
6868
eprintln!(
6969
"{} Writing debug info to: {}\n",
@@ -215,7 +215,7 @@ impl Scanner {
215215
.into_iter()
216216
.filter_map(|changed_content| match changed_content {
217217
ChangedContent::File(file, extension) => {
218-
let Ok(file) = dunce::canonicalize(file) else {
218+
let Ok(file) = fsops::canonicalize(file) else {
219219
return None;
220220
};
221221
Some(ChangedContent::File(file, extension))

crates/oxide/src/scanner/sources.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ impl PublicSourceEntry {
102102
/// resolved path.
103103
pub fn optimize(&mut self) {
104104
// Resolve base path immediately
105-
let Ok(base) = dunce::canonicalize(&self.base) else {
105+
let Ok(base) = fsops::canonicalize(&self.base) else {
106106
event!(Level::ERROR, "Failed to resolve base: {:?}", self.base);
107107
return;
108108
};
@@ -116,7 +116,7 @@ impl PublicSourceEntry {
116116
PathBuf::from(&self.base).join(&self.pattern)
117117
};
118118

119-
match dunce::canonicalize(combined_path) {
119+
match fsops::canonicalize(combined_path) {
120120
Ok(resolved_path) if resolved_path.is_dir() => {
121121
self.base = resolved_path.to_string_lossy().to_string();
122122
self.pattern = "**/*".to_owned();
@@ -144,7 +144,7 @@ impl PublicSourceEntry {
144144
Some(static_part) => {
145145
// TODO: If the base does not exist on disk, try removing the last slash and try
146146
// again.
147-
match dunce::canonicalize(base.join(static_part)) {
147+
match fsops::canonicalize(base.join(static_part)) {
148148
Ok(base) => base,
149149
Err(err) => {
150150
event!(tracing::Level::ERROR, "Failed to resolve glob: {:?}", err);

0 commit comments

Comments
 (0)