hex_patch/app/files/
filesystem.rs1use std::{error::Error, path::Path};
2
3use crate::app::ssh::connection::Connection;
4
5use super::path;
6
7pub enum FileSystem {
8 Local {
9 path: String,
10 },
11 Remote {
12 path: String,
13 connection: Connection,
14 },
15}
16
17impl FileSystem {
18 pub fn new_local(path: &str) -> Result<Self, Box<dyn Error>> {
19 Ok(Self::Local {
20 path: Path::new(path)
21 .canonicalize()
22 .map(|path| path.to_string_lossy().to_string())?,
23 })
24 }
25
26 pub fn new_remote(
27 path: &str,
28 connection_str: &str,
29 password: Option<&str>,
30 ) -> Result<Self, Box<dyn Error>> {
31 let connection = Connection::new(connection_str, password)?;
32 Ok(Self::Remote {
33 path: connection.canonicalize(path)?,
34 connection,
35 })
36 }
37
38 pub fn separator(&self) -> char {
39 match self {
40 Self::Local { .. } => std::path::MAIN_SEPARATOR,
41 Self::Remote { connection, .. } => connection.separator(),
42 }
43 }
44
45 pub fn pwd(&self) -> &str {
46 match self {
47 Self::Local { path } | Self::Remote { path, .. } => path,
48 }
49 }
50
51 pub fn cd(&mut self, path: &str) {
52 match self {
53 Self::Local { path: current }
54 | Self::Remote {
55 path: current,
56 connection: _,
57 } => *current = path.into(),
58 }
59 }
60
61 pub fn ls(&self, path: &str) -> Result<Vec<String>, Box<dyn Error>> {
62 let mut ret = match self {
63 Self::Local { .. } => {
64 let dir = std::fs::read_dir(path)?;
65 let mut ret = Vec::new();
66 for f in dir {
67 let f = f?;
68 ret.push(f.path().to_string_lossy().to_string())
69 }
70 Ok(ret)
71 }
72 Self::Remote { connection, .. } => connection.ls(path),
73 }?;
74 if path::parent(path).is_some() {
75 ret.insert(0, path::join(path, "..", self.separator()));
76 }
77 Ok(ret)
78 }
79
80 pub fn read(&self, path: &str) -> Result<Vec<u8>, Box<dyn Error>> {
81 match self {
82 Self::Local { .. } => Ok(std::fs::read(path)?),
83 Self::Remote { connection, .. } => connection.read(path),
84 }
85 }
86
87 pub fn mkdirs(&self, path: &str) -> Result<(), Box<dyn Error>> {
88 match self {
89 Self::Local { .. } => std::fs::create_dir_all(path)?,
90 Self::Remote { connection, .. } => connection.mkdirs(path)?,
91 }
92 Ok(())
93 }
94
95 pub fn create(&self, path: &str) -> Result<(), Box<dyn Error>> {
96 match self {
97 Self::Local { .. } => {
98 std::fs::File::create(path)?;
99 }
100 Self::Remote { connection, .. } => {
101 connection.create(path)?;
102 }
103 }
104 Ok(())
105 }
106
107 pub fn write(&self, path: &str, data: &[u8]) -> Result<(), Box<dyn Error>> {
108 match self {
109 Self::Local { .. } => Ok(std::fs::write(path, data)?),
110 Self::Remote { connection, .. } => connection.write(path, data),
111 }
112 }
113
114 pub fn is_file(&self, path: &str) -> bool {
115 match self {
116 Self::Local { .. } => Path::new(path).is_file(),
117 Self::Remote { connection, .. } => connection.is_file(path),
118 }
119 }
120
121 pub fn is_dir(&self, path: &str) -> bool {
122 match self {
123 Self::Local { .. } => Path::new(path).is_dir(),
124 Self::Remote { connection, .. } => connection.is_dir(path),
125 }
126 }
127
128 pub fn canonicalize(&self, path: &str) -> Result<String, Box<dyn Error>> {
129 match self {
130 Self::Local { .. } => Ok(Path::new(path)
131 .canonicalize()
132 .map(|path| path.to_string_lossy().to_string())?),
133 Self::Remote { connection, .. } => connection.canonicalize(path),
134 }
135 }
136}
137
138impl Default for FileSystem {
139 fn default() -> Self {
140 Self::Local { path: "./".into() }
141 }
142}