turbo_tasks_env/
dotenv.rs1use std::{env, sync::MutexGuard};
2
3use anyhow::{Context, Result};
4use turbo_rcstr::RcStr;
5use turbo_tasks::{FxIndexMap, ReadRef, ResolvedVc, Vc, turbofmt};
6use turbo_tasks_fs::{FileContent, FileSystemPath};
7
8use crate::{GLOBAL_ENV_LOCK, ProcessEnv, TransientEnvMap, sorted_env_vars};
9
10#[turbo_tasks::value]
14pub struct DotenvProcessEnv {
15 prior: Option<ResolvedVc<Box<dyn ProcessEnv>>>,
16 path: FileSystemPath,
17}
18
19#[turbo_tasks::value_impl]
20impl DotenvProcessEnv {
21 #[turbo_tasks::function]
22 pub fn new(prior: Option<ResolvedVc<Box<dyn ProcessEnv>>>, path: FileSystemPath) -> Vc<Self> {
23 DotenvProcessEnv { prior, path }.cell()
24 }
25
26 #[turbo_tasks::function]
27 pub fn read_prior(&self) -> Vc<TransientEnvMap> {
28 match self.prior {
29 None => TransientEnvMap::empty(),
30 Some(p) => p.read_all(),
31 }
32 }
33
34 #[turbo_tasks::function]
35 pub async fn read_all_with_prior(
36 &self,
37 prior: Vc<TransientEnvMap>,
38 ) -> Result<Vc<TransientEnvMap>> {
39 let prior = prior.await?;
40
41 let file = self.path.read().await?;
42 if let FileContent::Content(f) = &*file {
43 let res;
44 let vars;
45 {
46 let lock = GLOBAL_ENV_LOCK.lock().unwrap();
47
48 let initial = sorted_env_vars();
52
53 restore_env(&initial, &prior, &lock);
54
55 res = dotenv::from_read(f.read()).map(|e| e.load());
59
60 vars = sorted_env_vars();
61 restore_env(&vars, &initial, &lock);
62 }
63
64 if let Err(e) = res {
65 return Err(e)
67 .context(turbofmt!("unable to read {} for env vars", self.path).await?);
68 }
69
70 Ok(Vc::cell(vars))
71 } else {
72 Ok(ReadRef::cell(prior))
75 }
76 }
77}
78
79#[turbo_tasks::value_impl]
80impl ProcessEnv for DotenvProcessEnv {
81 #[turbo_tasks::function]
82 fn read_all(self: Vc<Self>) -> Vc<TransientEnvMap> {
83 let prior = self.read_prior();
84 self.read_all_with_prior(prior)
85 }
86}
87
88fn restore_env(
90 from: &FxIndexMap<RcStr, RcStr>,
91 to: &FxIndexMap<RcStr, RcStr>,
92 _lock: &MutexGuard<()>,
93) {
94 for key in from.keys() {
95 if !to.contains_key(key) {
96 unsafe { env::remove_var(key) };
97 }
98 }
99 for (key, value) in to {
100 match from.get(key) {
101 Some(v) if v == value => {}
102 _ => unsafe { env::set_var(key, value) },
103 }
104 }
105}