taplo_common/environment/
native.rs

1use std::path::Path;
2
3use crate::config::CONFIG_FILE_NAMES;
4
5use super::Environment;
6use async_trait::async_trait;
7use time::OffsetDateTime;
8
9#[derive(Clone)]
10pub struct NativeEnvironment {
11    handle: tokio::runtime::Handle,
12}
13
14impl NativeEnvironment {
15    #[must_use]
16    pub fn new() -> Self {
17        Self {
18            handle: tokio::runtime::Handle::current(),
19        }
20    }
21}
22
23impl Default for NativeEnvironment {
24    fn default() -> Self {
25        Self::new()
26    }
27}
28
29#[async_trait(?Send)]
30impl Environment for NativeEnvironment {
31    type Stdin = tokio::io::Stdin;
32    type Stdout = tokio::io::Stdout;
33    type Stderr = tokio::io::Stderr;
34
35    fn now(&self) -> time::OffsetDateTime {
36        OffsetDateTime::now_utc()
37    }
38
39    fn spawn<F>(&self, fut: F)
40    where
41        F: futures::Future + Send + 'static,
42        F::Output: Send,
43    {
44        self.handle.spawn(fut);
45    }
46
47    fn spawn_local<F>(&self, fut: F)
48    where
49        F: futures::Future + 'static,
50    {
51        tokio::task::spawn_local(fut);
52    }
53
54    fn env_var(&self, name: &str) -> Option<String> {
55        std::env::var(name).ok()
56    }
57
58    fn env_vars(&self) -> Vec<(String, String)> {
59        std::env::vars().collect()
60    }
61
62    fn atty_stderr(&self) -> bool {
63        use std::io::IsTerminal;
64        std::io::stderr().is_terminal()
65    }
66
67    fn stdin(&self) -> Self::Stdin {
68        tokio::io::stdin()
69    }
70
71    fn stdout(&self) -> Self::Stdout {
72        tokio::io::stdout()
73    }
74
75    fn stderr(&self) -> Self::Stderr {
76        tokio::io::stderr()
77    }
78
79    fn glob_files(&self, pattern: &str) -> Result<Vec<std::path::PathBuf>, anyhow::Error> {
80        let paths = glob::glob_with(
81            pattern,
82            glob::MatchOptions {
83                case_sensitive: true,
84                ..Default::default()
85            },
86        )?;
87        Ok(paths.filter_map(Result::ok).collect())
88    }
89
90    async fn read_file(&self, path: &Path) -> Result<Vec<u8>, anyhow::Error> {
91        Ok(tokio::fs::read(path).await?)
92    }
93
94    async fn write_file(&self, path: &std::path::Path, bytes: &[u8]) -> Result<(), anyhow::Error> {
95        Ok(tokio::fs::write(path, bytes).await?)
96    }
97
98    fn to_file_path(&self, url: &url::Url) -> Option<std::path::PathBuf> {
99        url.to_file_path().ok()
100    }
101
102    fn is_absolute(&self, base: &std::path::Path) -> bool {
103        base.is_absolute()
104    }
105
106    fn cwd(&self) -> Option<std::path::PathBuf> {
107        std::env::current_dir().ok()
108    }
109
110    async fn find_config_file(&self, from: &Path) -> Option<std::path::PathBuf> {
111        let mut p = from;
112
113        loop {
114            if let Ok(mut dir) = tokio::fs::read_dir(p).await {
115                while let Ok(Some(entry)) = dir.next_entry().await {
116                    for name in CONFIG_FILE_NAMES {
117                        if entry.file_name() == *name {
118                            let path = entry.path();
119                            return Some(path);
120                        }
121                    }
122                }
123            }
124
125            match p.parent() {
126                Some(parent) => p = parent,
127                None => {
128                    return None;
129                }
130            }
131        }
132    }
133}