kcl_lib/fs/
local.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//! Functions for interacting with a file system locally.

use anyhow::Result;

use crate::{
    errors::{KclError, KclErrorDetails},
    fs::FileSystem,
};

#[derive(Debug, Clone)]
pub struct FileManager {}

impl FileManager {
    pub fn new() -> FileManager {
        FileManager {}
    }
}

impl Default for FileManager {
    fn default() -> Self {
        FileManager::new()
    }
}

#[async_trait::async_trait]
impl FileSystem for FileManager {
    async fn read<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
        &self,
        path: P,
        source_range: crate::executor::SourceRange,
    ) -> Result<Vec<u8>, KclError> {
        tokio::fs::read(&path).await.map_err(|e| {
            KclError::Engine(KclErrorDetails {
                message: format!("Failed to read file `{}`: {}", path.as_ref().display(), e),
                source_ranges: vec![source_range],
            })
        })
    }

    async fn read_to_string<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
        &self,
        path: P,
        source_range: crate::executor::SourceRange,
    ) -> Result<String, KclError> {
        tokio::fs::read_to_string(&path).await.map_err(|e| {
            KclError::Engine(KclErrorDetails {
                message: format!("Failed to read file `{}`: {}", path.as_ref().display(), e),
                source_ranges: vec![source_range],
            })
        })
    }

    async fn exists<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
        &self,
        path: P,
        source_range: crate::executor::SourceRange,
    ) -> Result<bool, crate::errors::KclError> {
        tokio::fs::metadata(&path).await.map(|_| true).or_else(|e| {
            if e.kind() == std::io::ErrorKind::NotFound {
                Ok(false)
            } else {
                Err(KclError::Engine(KclErrorDetails {
                    message: format!("Failed to check if file `{}` exists: {}", path.as_ref().display(), e),
                    source_ranges: vec![source_range],
                }))
            }
        })
    }

    async fn get_all_files<P: AsRef<std::path::Path> + std::marker::Send + std::marker::Sync>(
        &self,
        path: P,
        source_range: crate::executor::SourceRange,
    ) -> Result<Vec<std::path::PathBuf>, crate::errors::KclError> {
        let mut files = vec![];
        let mut stack = vec![path.as_ref().to_path_buf()];

        while let Some(path) = stack.pop() {
            if !path.is_dir() {
                continue;
            }

            let mut read_dir = tokio::fs::read_dir(&path).await.map_err(|e| {
                KclError::Engine(KclErrorDetails {
                    message: format!("Failed to read directory `{}`: {}", path.display(), e),
                    source_ranges: vec![source_range],
                })
            })?;

            while let Ok(Some(entry)) = read_dir.next_entry().await {
                let path = entry.path();
                if path.is_dir() {
                    // Iterate over the directory.
                    stack.push(path);
                } else {
                    files.push(path);
                }
            }
        }

        Ok(files)
    }
}