1use std::{
2 io::{self, ErrorKind},
3 path::{Path, PathBuf},
4};
5
6use anyhow::{Context, Result, anyhow};
7use turbo_tasks::ResolvedVc;
8
9use crate::{DiskFileSystem, FileSystemPath};
10
11pub fn extract_disk_access<T>(value: io::Result<T>, path: &Path) -> Result<Option<T>> {
15 match value {
16 Ok(v) => Ok(Some(v)),
17 Err(e) if matches!(e.kind(), ErrorKind::NotFound | ErrorKind::InvalidFilename) => Ok(None),
18 Err(e) => Err(anyhow!(e).context(format!("reading file {}", path.display()))),
19 }
20}
21
22pub async fn uri_from_file(root: FileSystemPath, path: Option<&str>) -> Result<String> {
23 let root_fs = root.fs;
24 let root_fs = &*ResolvedVc::try_downcast_type::<DiskFileSystem>(root_fs)
25 .context("Expected root to have a DiskFileSystem")?
26 .await?;
27
28 let path = match path {
29 Some(path) => root.join(path)?,
30 None => root,
31 };
32
33 Ok(uri_from_path_buf(root_fs.to_sys_path(&path)))
34}
35
36#[cfg(not(target_os = "windows"))]
37pub fn uri_from_path_buf(sys_path: PathBuf) -> String {
38 use turbo_unix_path::sys_to_unix;
39 let sys_path = sys_path.to_string_lossy();
40
41 format!(
42 "file://{}",
43 sys_to_unix(&sys_path)
44 .split('/')
45 .map(|s| urlencoding::encode(s))
46 .collect::<Vec<_>>()
47 .join("/")
48 )
49}
50
51#[cfg(target_os = "windows")]
52pub fn uri_from_path_buf(sys_path: PathBuf) -> String {
53 let raw_path = sys_path.to_string_lossy().to_string();
54 let normalized_path = raw_path.replace('\\', "/");
55
56 let mut segments = normalized_path.split('/');
57
58 let first = segments.next().unwrap_or_default(); let encoded_path = std::iter::once(first.to_string()) .chain(segments.map(|s| urlencoding::encode(s).into_owned()))
61 .collect::<Vec<_>>()
62 .join("/");
63
64 format!("file:///{}", encoded_path)
65}