1use std::fs;
2use std::path::{Path, PathBuf};
3use teaql_tool_core::{Result, TeaQLToolError};
4
5pub struct FileTool;
7
8impl FileTool {
9 pub fn read_string<P: AsRef<Path>>(&self, path: P) -> Result<String> {
11 fs::read_to_string(path.as_ref())
12 .map_err(|e| TeaQLToolError::ExecutionError(format!("Failed to read file: {}", e)))
13 }
14
15 pub fn read_bytes<P: AsRef<Path>>(&self, path: P) -> Result<Vec<u8>> {
17 fs::read(path.as_ref())
18 .map_err(|e| TeaQLToolError::ExecutionError(format!("Failed to read bytes: {}", e)))
19 }
20
21 pub fn write_string<P: AsRef<Path>, C: AsRef<[u8]>>(&self, path: P, content: C) -> Result<()> {
23 fs::write(path.as_ref(), content)
24 .map_err(|e| TeaQLToolError::ExecutionError(format!("Failed to write file: {}", e)))
25 }
26
27 pub fn exists<P: AsRef<Path>>(&self, path: P) -> bool {
29 path.as_ref().exists()
30 }
31
32 pub fn is_file<P: AsRef<Path>>(&self, path: P) -> bool {
34 path.as_ref().is_file()
35 }
36
37 pub fn is_dir<P: AsRef<Path>>(&self, path: P) -> bool {
39 path.as_ref().is_dir()
40 }
41
42 pub fn mkdir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
44 fs::create_dir(path.as_ref())
45 .map_err(|e| TeaQLToolError::ExecutionError(format!("Failed to create directory: {}", e)))
46 }
47
48 pub fn mkdir_all<P: AsRef<Path>>(&self, path: P) -> Result<()> {
50 fs::create_dir_all(path.as_ref())
51 .map_err(|e| TeaQLToolError::ExecutionError(format!("Failed to create directories recursively: {}", e)))
52 }
53
54 pub fn delete_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
56 fs::remove_file(path.as_ref())
57 .map_err(|e| TeaQLToolError::ExecutionError(format!("Failed to delete file: {}", e)))
58 }
59
60 pub fn delete_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
62 fs::remove_dir(path.as_ref())
63 .map_err(|e| TeaQLToolError::ExecutionError(format!("Failed to delete directory: {}", e)))
64 }
65
66 pub fn delete_recursive<P: AsRef<Path>>(&self, path: P) -> Result<()> {
68 fs::remove_dir_all(path.as_ref())
69 .map_err(|e| TeaQLToolError::ExecutionError(format!("Failed to recursively delete directory: {}", e)))
70 }
71
72 pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(&self, from: P, to: Q) -> Result<u64> {
74 fs::copy(from.as_ref(), to.as_ref())
75 .map_err(|e| TeaQLToolError::ExecutionError(format!("Failed to copy file: {}", e)))
76 }
77
78 pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(&self, from: P, to: Q) -> Result<()> {
80 fs::rename(from.as_ref(), to.as_ref())
81 .map_err(|e| TeaQLToolError::ExecutionError(format!("Failed to rename/move: {}", e)))
82 }
83
84 pub fn list_files<P: AsRef<Path>>(&self, dir: P) -> Result<Vec<PathBuf>> {
86 self.list_entries(dir, true, false)
87 }
88
89 pub fn list_dirs<P: AsRef<Path>>(&self, dir: P) -> Result<Vec<PathBuf>> {
91 self.list_entries(dir, false, true)
92 }
93
94 fn list_entries<P: AsRef<Path>>(&self, dir: P, include_files: bool, include_dirs: bool) -> Result<Vec<PathBuf>> {
96 let mut result = Vec::new();
97 let entries = fs::read_dir(dir.as_ref())
98 .map_err(|e| TeaQLToolError::ExecutionError(format!("Failed to read directory: {}", e)))?;
99
100 for entry in entries {
101 let entry = entry.map_err(|e| TeaQLToolError::ExecutionError(format!("Error reading directory entry: {}", e)))?;
102 let path = entry.path();
103 if path.is_file() && include_files {
104 result.push(path);
105 } else if path.is_dir() && include_dirs {
106 result.push(path);
107 }
108 }
109 Ok(result)
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use std::env;
117
118 #[test]
119 fn test_file_operations() {
120 let tool = FileTool;
121 let mut tmp_path = env::temp_dir();
122 tmp_path.push("teaql_test_file.txt");
123
124 tool.write_string(&tmp_path, "hello teaql").unwrap();
126 assert!(tool.exists(&tmp_path));
127 assert!(tool.is_file(&tmp_path));
128
129 let content = tool.read_string(&tmp_path).unwrap();
131 assert_eq!(content, "hello teaql");
132
133 tool.delete_file(&tmp_path).unwrap();
135 assert!(!tool.exists(&tmp_path));
136 }
137}