1pub mod clone;
7pub mod composite;
8pub mod local;
9pub mod store;
10
11pub use composite::{CompositeProvider, Mount};
12pub use local::LocalProvider;
13pub use store::StoreProvider;
14
15use synwire_core::BoxFuture;
16use synwire_core::vfs::types::{CpOptions, LsOptions, RmOptions};
17use synwire_core::vfs::{Vfs, VfsError};
18
19pub fn bash_command<'a>(
24 vfs: &'a dyn Vfs,
25 cmd: &'a str,
26 args: &'a [&'a str],
27) -> BoxFuture<'a, Result<String, VfsError>> {
28 Box::pin(async move {
29 match cmd {
30 "ls" => {
31 let path = args.first().copied().unwrap_or(".");
32 let entries = vfs.ls(path, LsOptions::default()).await?;
33 let names: Vec<String> = entries.iter().map(|e| e.name.clone()).collect();
34 Ok(names.join("\n"))
35 }
36 "cat" => {
37 let path = args
38 .first()
39 .ok_or_else(|| VfsError::Unsupported("cat requires a path argument".into()))?;
40 let content = vfs.read(path).await?;
41 String::from_utf8(content.content)
42 .map_err(|_| VfsError::Unsupported("binary file".into()))
43 }
44 "rm" => {
45 let path = args
46 .first()
47 .ok_or_else(|| VfsError::Unsupported("rm requires a path argument".into()))?;
48 vfs.rm(path, RmOptions::default()).await?;
49 Ok(String::new())
50 }
51 "cp" => {
52 if args.len() < 2 {
53 return Err(VfsError::Unsupported("cp requires src and dst".into()));
54 }
55 let result = vfs.cp(args[0], args[1], CpOptions::default()).await?;
56 Ok(format!(
57 "copied {} bytes to {}",
58 result.bytes_transferred, result.path
59 ))
60 }
61 "mv" => {
62 if args.len() < 2 {
63 return Err(VfsError::Unsupported("mv requires src and dst".into()));
64 }
65 let result = vfs.mv_file(args[0], args[1]).await?;
66 Ok(format!("moved to {}", result.path))
67 }
68 "pwd" => vfs.pwd().await,
69 "cd" => {
70 let path = args
71 .first()
72 .ok_or_else(|| VfsError::Unsupported("cd requires a path argument".into()))?;
73 vfs.cd(path).await?;
74 Ok(String::new())
75 }
76 other => Err(VfsError::Unsupported(format!("unknown command: {other}"))),
77 }
78 })
79}