1use std::{
2 io::{self, ErrorKind},
3 path::Path,
4};
5
6use anyhow::{Context, Result, anyhow};
7use turbo_tasks::Vc;
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
22#[cfg(not(target_os = "windows"))]
23pub async fn uri_from_file(root: FileSystemPath, path: Option<&str>) -> Result<String> {
24 use turbo_unix_path::sys_to_unix;
25
26 let root_fs = root.fs();
27 let root_fs = &*Vc::try_resolve_downcast_type::<DiskFileSystem>(root_fs)
28 .await?
29 .context("Expected root to have a DiskFileSystem")?
30 .await?;
31
32 Ok(format!(
33 "file://{}",
34 &sys_to_unix(
35 &root_fs
36 .to_sys_path(match path {
37 Some(path) => root.join(path)?,
38 None => root,
39 })?
40 .to_string_lossy()
41 )
42 .split('/')
43 .map(|s| urlencoding::encode(s))
44 .collect::<Vec<_>>()
45 .join("/")
46 ))
47}
48
49#[cfg(target_os = "windows")]
50pub async fn uri_from_file(root: FileSystemPath, path: Option<&str>) -> Result<String> {
51 let root_fs = root.fs();
52 let root_fs = &*Vc::try_resolve_downcast_type::<DiskFileSystem>(root_fs)
53 .await?
54 .context("Expected root to have a DiskFileSystem")?
55 .await?;
56
57 let sys_path = root_fs.to_sys_path(match path {
58 Some(path) => root.join(path.into())?,
59 None => root,
60 })?;
61
62 let raw_path = sys_path.to_string_lossy().to_string();
63 let normalized_path = raw_path.replace('\\', "/");
64
65 let mut segments = normalized_path.split('/');
66
67 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()))
70 .collect::<Vec<_>>()
71 .join("/");
72
73 let uri = format!("file:///{}", encoded_path);
74
75 Ok(uri)
76}