bsdkrun_sdk/
filesystem.rs1use std::path::Path;
7
8use crate::error::{Error, Result};
9use crate::process::{run, run_binary};
10
11pub struct FileSystem {
25 id: String,
26}
27
28impl FileSystem {
29 pub(crate) fn new(id: impl Into<String>) -> Self {
30 FileSystem { id: id.into() }
31 }
32
33 pub fn write_file(&self, path: &str, data: &[u8]) -> Result<()> {
35 let args = vec![
36 "cp".to_string(),
37 "-".to_string(),
38 format!("{}:{}", self.id, path),
39 ];
40 let res = run_binary(args, Some(data))?;
41 if res.exit_code != 0 {
42 return Err(transfer_error(&res.stderr, path));
43 }
44 Ok(())
45 }
46
47 pub fn read_file(&self, path: &str) -> Result<Vec<u8>> {
49 let args = vec![
50 "cp".to_string(),
51 format!("{}:{}", self.id, path),
52 "-".to_string(),
53 ];
54 let res = run_binary(args, None)?;
55 if res.exit_code != 0 {
56 return Err(transfer_error(&res.stderr, path));
57 }
58 Ok(res.stdout)
59 }
60
61 pub fn read_to_string(&self, path: &str) -> Result<String> {
63 Ok(String::from_utf8_lossy(&self.read_file(path)?).into_owned())
64 }
65
66 pub fn upload(&self, local_path: impl AsRef<Path>, remote_path: &str) -> Result<()> {
73 let local = local_path.as_ref();
74 let meta = std::fs::metadata(local).map_err(|e| Error::FileTransfer {
75 path: local.display().to_string(),
76 message: format!("cannot upload {}: {e}", local.display()),
77 })?;
78 let mut args = vec!["cp".to_string()];
79 if meta.is_dir() {
80 args.push("-r".to_string());
81 }
82 args.push(local.display().to_string());
83 args.push(format!("{}:{}", self.id, remote_path));
84 let res = run(args)?;
85 if res.exit_code != 0 {
86 return Err(transfer_error(&res.stderr, &local.display().to_string()));
87 }
88 Ok(())
89 }
90
91 pub fn download(
96 &self,
97 remote_path: &str,
98 local_path: impl AsRef<Path>,
99 recursive: bool,
100 ) -> Result<()> {
101 let mut args = vec!["cp".to_string()];
102 if recursive {
103 args.push("-r".to_string());
104 }
105 args.push(format!("{}:{}", self.id, remote_path));
106 args.push(local_path.as_ref().display().to_string());
107 let res = run(args)?;
108 if res.exit_code != 0 {
109 return Err(transfer_error(&res.stderr, remote_path));
110 }
111 Ok(())
112 }
113}
114
115fn transfer_error(stderr: &str, path: &str) -> Error {
117 let text = stderr.trim().trim_start_matches("Error: ").trim();
118 Error::FileTransfer {
119 path: path.to_string(),
120 message: if text.is_empty() {
121 format!("file transfer failed for {path}")
122 } else {
123 text.to_string()
124 },
125 }
126}