taplo_common/environment/
native.rs1use 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}