Skip to main content

agent_line/tools/
file.rs

1use crate::agent::StepError;
2use std::fs::OpenOptions;
3use std::io::Write;
4
5/// Read an entire file into a string.
6pub fn read_file(path: &str) -> Result<String, StepError> {
7    Ok(std::fs::read_to_string(path)?)
8}
9/// Write content to a file, creating parent directories if needed.
10pub fn write_file(path: &str, content: &str) -> Result<(), StepError> {
11    if let Some(parent) = std::path::Path::new(path).parent() {
12        std::fs::create_dir_all(parent)?;
13    }
14    Ok(std::fs::write(path, content)?)
15}
16
17/// List entries in a directory.
18pub fn list_dir(path: &str) -> Result<Vec<String>, StepError> {
19    let mut entries = Vec::new();
20    for entry in std::fs::read_dir(path)? {
21        let entry = entry?;
22        entries.push(entry.path().display().to_string());
23    }
24    Ok(entries)
25}
26/// Recursively find files matching a suffix pattern (e.g. `"*.rs"`).
27pub fn find_files(path: &str, pattern: &str) -> Result<Vec<String>, StepError> {
28    let mut results = Vec::new();
29    find_files_recursive(path, pattern, &mut results)?;
30    Ok(results)
31}
32
33fn find_files_recursive(
34    dir: &str,
35    pattern: &str,
36    results: &mut Vec<String>,
37) -> Result<(), StepError> {
38    for entry in std::fs::read_dir(dir)? {
39        let entry = entry?;
40        let path = entry.path();
41
42        if path.is_dir() {
43            find_files_recursive(&path.display().to_string(), pattern, results)?;
44        } else if let Some(name) = path.file_name().and_then(|n| n.to_str())
45            && name.ends_with(pattern.trim_start_matches('*'))
46        {
47            results.push(path.display().to_string());
48        }
49    }
50    Ok(())
51}
52
53/// Append content to a file, creating it if it doesn't exist.
54pub fn append_file(file_path: &str, content: &str) -> Result<(), StepError> {
55    let mut file = OpenOptions::new()
56        .append(true)
57        .create(true)
58        .open(file_path)?;
59
60    file.write_all(content.as_bytes())?;
61    Ok(())
62}
63
64/// Check if a file exists.
65pub fn file_exists(file_path: &str) -> bool {
66    std::path::Path::new(file_path).exists()
67}
68
69/// Delete a file.
70pub fn delete_file(file_path: &str) -> Result<(), StepError> {
71    std::fs::remove_file(file_path)?;
72    Ok(())
73}
74
75/// Create a directory and all parent directories.
76pub fn create_dir(name: &str) -> Result<(), StepError> {
77    std::fs::create_dir_all(name)?;
78    Ok(())
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn test_append_to_existing_file() {
87        let path = "/tmp/agent_line_test_append.txt";
88        let _ = std::fs::remove_file(path);
89        write_file(path, "hello").unwrap();
90        append_file(path, " world").unwrap();
91        assert_eq!(read_file(path).unwrap(), "hello world");
92        std::fs::remove_file(path).unwrap();
93    }
94
95    #[test]
96    fn test_append_creates_file_if_missing() {
97        let path = "/tmp/agent_line_test_append_new.txt";
98        let _ = std::fs::remove_file(path);
99        append_file(path, "new content").unwrap();
100        assert_eq!(read_file(path).unwrap(), "new content");
101        std::fs::remove_file(path).unwrap();
102    }
103
104    #[test]
105    fn test_file_exists_true() {
106        let path = "/tmp/agent_line_test_exists.txt";
107        write_file(path, "data").unwrap();
108        assert!(file_exists(path));
109        std::fs::remove_file(path).unwrap();
110    }
111
112    #[test]
113    fn test_file_exists_false() {
114        assert!(!file_exists("/tmp/agent_line_nonexistent_xyz.txt"));
115    }
116
117    #[test]
118    fn test_delete_file_removes_it() {
119        let path = "/tmp/agent_line_test_delete.txt";
120        write_file(path, "data").unwrap();
121        delete_file(path).unwrap();
122        assert!(!file_exists(path));
123    }
124
125    #[test]
126    fn test_delete_file_not_found_is_error() {
127        let result = delete_file("/tmp/agent_line_no_such_file_xyz.txt");
128        assert!(result.is_err());
129    }
130
131    #[test]
132    fn test_create_dir_simple() {
133        let path = "/tmp/agent_line_test_dir";
134        let _ = std::fs::remove_dir_all(path);
135        create_dir(path).unwrap();
136        assert!(std::path::Path::new(path).is_dir());
137        std::fs::remove_dir_all(path).unwrap();
138    }
139
140    #[test]
141    fn test_create_dir_nested() {
142        let path = "/tmp/agent_line_test_dir_nested/a/b/c";
143        let _ = std::fs::remove_dir_all("/tmp/agent_line_test_dir_nested");
144        create_dir(path).unwrap();
145        assert!(std::path::Path::new(path).is_dir());
146        std::fs::remove_dir_all("/tmp/agent_line_test_dir_nested").unwrap();
147    }
148}