opfs_project/
lib.rs

1#![cfg(all(target_family = "wasm", target_os = "unknown"))]
2
3use std::{
4    io::Result,
5    path::{Path, PathBuf},
6    sync::Arc,
7};
8
9mod fuse;
10pub mod package_lock;
11pub mod package_manager;
12pub mod pack;
13pub mod tar_cache;
14mod util;
15
16pub use tokio_fs_ext::DirEntry;
17
18pub use package_manager::{install, InstallOptions, OmitType};
19
20/// Read file content with fuse.link support
21pub async fn read<P: AsRef<Path>>(path: P) -> Result<Arc<Vec<u8>>> {
22    let path_ref = path.as_ref();
23    let prepared_path = crate::util::prepare_path(path_ref);
24
25    // Try to read through node_modules fuse link logic first
26    if let Some(content) = fuse::try_read_through_fuse_link(&prepared_path).await? {
27        return Ok(content);
28    }
29
30    // Fallback to direct read
31    let content = tokio_fs_ext::read(&prepared_path).await?;
32    Ok(Arc::new(content))
33}
34
35/// Read directory contents with file type information and fuse.link support
36pub async fn read_dir<P: AsRef<Path>>(path: P) -> Result<Vec<tokio_fs_ext::DirEntry>> {
37    let path_ref = path.as_ref();
38    let prepared_path = crate::util::prepare_path(path_ref);
39
40    // Handle node_modules fuse.link logic
41    if let Some(entries) = fuse::try_read_dir_through_fuse_link(&prepared_path).await? {
42        return Ok(entries);
43    }
44
45    // Handle direct directory reading
46    let entries = crate::util::read_dir_direct(&prepared_path).await?;
47    Ok(entries)
48}
49
50pub async fn write(path: impl AsRef<Path>, content: impl AsRef<[u8]>) -> Result<()> {
51    // TODO: try fuse link first
52    tokio_fs_ext::write(path, content).await
53}
54
55pub async fn create_dir(path: impl AsRef<Path>) -> Result<()> {
56    // TODO: try fuse link first
57    tokio_fs_ext::create_dir(path).await
58}
59
60pub async fn create_dir_all(path: impl AsRef<Path>) -> Result<()> {
61    // TODO: try fuse link first
62    tokio_fs_ext::create_dir_all(path).await
63}
64
65pub async fn copy(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<u64> {
66    // TODO: try fuse link first
67    tokio_fs_ext::copy(from, to).await
68}
69
70pub async fn remove_file(path: impl AsRef<Path>) -> Result<()> {
71    // TODO: try fuse link first
72    tokio_fs_ext::remove_file(path).await
73}
74
75pub async fn remove_dir(path: impl AsRef<Path>) -> Result<()> {
76    // TODO: try fuse link first
77    tokio_fs_ext::remove_dir(path).await
78}
79
80pub async fn remove_dir_all(path: impl AsRef<Path>) -> Result<()> {
81    // TODO: try fuse link first
82    tokio_fs_ext::remove_dir_all(path).await
83}
84
85pub async fn metadata(path: impl AsRef<Path>) -> Result<tokio_fs_ext::Metadata> {
86    // TODO: try fuse link first
87    tokio_fs_ext::metadata(path).await
88}
89
90/// Set current working directory
91pub fn set_cwd(path: impl AsRef<Path>) {
92    tokio_fs_ext::set_current_dir(path).unwrap();
93}
94
95/// Read current working directory
96pub fn get_cwd() -> PathBuf {
97    tokio_fs_ext::current_dir().unwrap()
98}
99
100#[cfg(test)]
101pub mod test_utils {
102    use std::sync::Once;
103
104    static INIT: Once = Once::new();
105
106    /// Initialize tracing-web for tests
107    /// This should be called at the beginning of each test to enable web console logging
108    pub fn init_tracing() {
109        INIT.call_once(|| {
110            {
111                use tracing_subscriber::{
112                    fmt::{
113                        self,
114                        format::FmtSpan,
115                    },
116                    layer::SubscriberExt,
117                    registry,
118                    util::SubscriberInitExt,
119                };
120
121                use tracing_web::MakeWebConsoleWriter;
122
123                let fmt_layer = fmt::layer()
124                .without_time()
125                .with_span_events(FmtSpan::CLOSE)
126                .with_writer(MakeWebConsoleWriter::new());
127
128            registry().with(fmt_layer).init();
129            }
130        });
131    }
132}