1use std::path::{Path, PathBuf};
2
3use crate::VirtualFileSystem;
4use dada_util::{Fallible, anyhow, bail};
5use url::Url;
6
7pub struct RealFs {
8 base_dir: Option<PathBuf>,
9}
10
11impl Default for RealFs {
12 fn default() -> Self {
13 Self::new()
14 }
15}
16
17impl RealFs {
18 pub fn new() -> Self {
19 Self {
20 base_dir: std::env::current_dir().ok(),
21 }
22 }
23
24 fn validate_scheme(url: &Url) -> Fallible<PathBuf> {
25 if url.scheme() != "file" {
26 bail!("unsupported scheme: {}", url.scheme());
27 }
28 url.to_file_path()
29 .map_err(|()| anyhow!("not a file path: {url}"))
30 }
31}
32
33impl VirtualFileSystem for RealFs {
34 fn contents(&self, url: &Url) -> Fallible<String> {
35 let path = Self::validate_scheme(url)?;
36 Ok(std::fs::read_to_string(&path)?)
37 }
38
39 fn exists(&self, url: &Url) -> bool {
40 match Self::validate_scheme(url) {
41 Ok(path) => path.exists(),
42 Err(_) => false,
43 }
44 }
45
46 fn path_url(&self, path: &Path) -> Fallible<Url> {
47 let path = if let Some(base_dir) = &self.base_dir {
48 base_dir.join(path)
49 } else {
50 path.to_path_buf()
51 };
52
53 Url::from_file_path(&path)
54 .map_err(|()| anyhow!("unable to construct URL from `{}`", path.display()))
55 }
56
57 fn url_display(&self, url: &Url) -> String {
58 match url.scheme() {
59 "file" => match url.to_file_path() {
60 Ok(path) => {
61 if let Some(base_dir) = &self.base_dir
62 && let Ok(suffix) = path.strip_prefix(base_dir)
63 {
64 return suffix.display().to_string();
65 }
66 path.display().to_string()
67 }
68
69 Err(()) => url.to_string(),
70 },
71
72 "libdada" => format!("[libdada] {}", url.path()),
73
74 _ => url.to_string(),
75 }
76 }
77}