1#![feature(arbitrary_self_types)]
2#![feature(arbitrary_self_types_pointers)]
3
4mod command_line;
5mod custom;
6mod dotenv;
7mod filter;
8
9use std::{env, sync::Mutex};
10
11use anyhow::Result;
12use turbo_rcstr::RcStr;
13use turbo_tasks::{FxIndexMap, Vc};
14
15pub use self::{
16 command_line::CommandLineProcessEnv, custom::CustomProcessEnv, dotenv::DotenvProcessEnv,
17 filter::FilterProcessEnv,
18};
19
20#[turbo_tasks::value(transparent, serialization = "none")]
23pub struct TransientEnvMap(#[turbo_tasks(trace_ignore)] FxIndexMap<RcStr, RcStr>);
24
25#[turbo_tasks::value_impl]
26impl TransientEnvMap {
27 #[turbo_tasks::function]
28 pub fn empty() -> Vc<Self> {
29 TransientEnvMap(FxIndexMap::default()).cell()
30 }
31}
32
33#[turbo_tasks::value(transparent)]
34pub struct EnvMap(
35 #[turbo_tasks(trace_ignore)]
36 #[bincode(with = "turbo_bincode::indexmap")]
37 FxIndexMap<RcStr, RcStr>,
38);
39
40#[turbo_tasks::value_impl]
41impl EnvMap {
42 #[turbo_tasks::function]
43 pub fn empty() -> Vc<Self> {
44 EnvMap(FxIndexMap::default()).cell()
45 }
46}
47
48#[turbo_tasks::value_impl]
49impl ProcessEnv for EnvMap {
50 #[turbo_tasks::function]
51 async fn read_all(self: Vc<Self>) -> Result<Vc<TransientEnvMap>> {
52 Ok(Vc::cell((*self.await?).clone()))
53 }
54
55 #[turbo_tasks::function]
56 fn read(self: Vc<Self>, name: RcStr) -> Vc<Option<RcStr>> {
57 case_insensitive_read(self.read_all(), name)
58 }
59}
60
61#[turbo_tasks::value_trait]
62pub trait ProcessEnv {
63 #[turbo_tasks::function]
65 fn read_all(self: Vc<Self>) -> Vc<TransientEnvMap>;
66
67 #[turbo_tasks::function]
69 fn read(self: Vc<Self>, name: RcStr) -> Vc<Option<RcStr>> {
70 case_insensitive_read(self.read_all(), name)
71 }
72}
73
74pub fn sorted_env_vars() -> FxIndexMap<RcStr, RcStr> {
75 let mut vars = env::vars()
76 .map(|(k, v)| (k.into(), v.into()))
77 .collect::<FxIndexMap<_, _>>();
78 vars.sort_keys();
79 vars
80}
81
82#[turbo_tasks::function]
83pub async fn case_insensitive_read(
84 map: Vc<TransientEnvMap>,
85 name: RcStr,
86) -> Result<Vc<Option<RcStr>>> {
87 Ok(Vc::cell(
88 to_uppercase_map(map)
89 .await?
90 .get(&RcStr::from(name.to_uppercase()))
91 .cloned(),
92 ))
93}
94
95#[turbo_tasks::function]
96async fn to_uppercase_map(map: Vc<TransientEnvMap>) -> Result<Vc<TransientEnvMap>> {
97 let map = &*map.await?;
98 let mut new = FxIndexMap::with_capacity_and_hasher(map.len(), Default::default());
99 for (k, v) in map {
100 new.insert(k.to_uppercase().into(), v.clone());
101 }
102 Ok(Vc::cell(new))
103}
104
105pub static GLOBAL_ENV_LOCK: Mutex<()> = Mutex::new(());