ocy_core/
filesystem.rs

1use eyre::Context;
2use eyre::Result;
3
4use std::{
5    fs::{self, DirEntry},
6    path::Path,
7};
8
9use crate::models::FileInfo;
10use crate::models::SimpleFileKind;
11
12pub trait FileSystem {
13    fn current_directory(&self) -> Result<FileInfo>;
14
15    fn list_files(&self, file: &FileInfo) -> Result<Vec<FileInfo>>;
16
17    fn file_size(&self, file: &FileInfo) -> Result<u64>;
18}
19
20pub trait FileSystemClean {
21    fn remove_file(&self, file: &FileInfo) -> Result<()>;
22}
23pub struct RealFileSystem;
24
25impl FileSystem for RealFileSystem {
26    fn current_directory(&self) -> Result<FileInfo> {
27        let path_buf = std::env::current_dir()?;
28        Ok(FileInfo::new(
29            path_buf,
30            "".into(),
31            SimpleFileKind::Directory,
32        ))
33    }
34
35    fn list_files(&self, file: &FileInfo) -> Result<Vec<FileInfo>> {
36        fs::read_dir(&file.path)?
37            .map(|e| {
38                e.context("failed to read dir entry")
39                    .and_then(|entry| map_entry_to_simple_file(&entry))
40            })
41            .collect()
42    }
43
44    fn file_size(&self, file: &FileInfo) -> Result<u64> {
45        RealFileSystem::get_size(&file.path)
46    }
47}
48
49impl RealFileSystem {
50    pub fn get_size<P>(path: P) -> Result<u64>
51    where
52        P: AsRef<Path>,
53    {
54        let mut result = 0;
55
56        if path.as_ref().is_dir() {
57            for entry in fs::read_dir(&path)? {
58                let current_path = entry?.path();
59                if current_path.is_file() {
60                    result += current_path.metadata()?.len();
61                } else {
62                    result += RealFileSystem::get_size(current_path)?;
63                }
64            }
65        } else {
66            result = path.as_ref().metadata()?.len();
67        }
68        Ok(result)
69    }
70}
71
72fn map_entry_to_simple_file(entry: &DirEntry) -> Result<FileInfo> {
73    let path = entry.path();
74
75    let name = entry
76        .file_name()
77        .into_string()
78        .map_err(|_| eyre::eyre!("Cannot convert os string"))?;
79
80    let file_type = entry.file_type()?;
81
82    let kind = if file_type.is_dir() {
83        SimpleFileKind::Directory
84    } else {
85        SimpleFileKind::File
86    };
87
88    Ok(FileInfo::new(path, name, kind))
89}
90
91impl FileSystemClean for RealFileSystem {
92    fn remove_file(&self, file: &FileInfo) -> Result<()> {
93        if file.kind == SimpleFileKind::Directory {
94            std::fs::remove_dir_all(&file.path)?;
95        } else {
96            std::fs::remove_file(&file.path)?;
97        }
98        Ok(())
99    }
100}
101
102pub struct MockFileSystemClean;
103
104impl FileSystemClean for MockFileSystemClean {
105    fn remove_file(&self, _file: &FileInfo) -> Result<()> {
106        std::thread::sleep(std::time::Duration::from_secs(1));
107        Ok(())
108        //        Err(eyre::eyre!("Failed"))
109    }
110}