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 = "skip")]
23pub struct TransientEnvMap(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(#[bincode(with = "turbo_bincode::indexmap")] FxIndexMap<RcStr, RcStr>);
35
36#[turbo_tasks::value_impl]
37impl EnvMap {
38 #[turbo_tasks::function]
39 pub fn empty() -> Vc<Self> {
40 EnvMap(FxIndexMap::default()).cell()
41 }
42}
43
44#[turbo_tasks::value_impl]
45impl ProcessEnv for EnvMap {
46 #[turbo_tasks::function]
47 async fn read_all(self: Vc<Self>) -> Result<Vc<TransientEnvMap>> {
48 Ok(Vc::cell((*self.await?).clone()))
49 }
50
51 #[turbo_tasks::function]
52 fn read(self: Vc<Self>, name: RcStr) -> Vc<Option<RcStr>> {
53 case_insensitive_read(self.read_all(), name)
54 }
55}
56
57#[turbo_tasks::value_trait]
58pub trait ProcessEnv {
59 #[turbo_tasks::function]
61 fn read_all(self: Vc<Self>) -> Vc<TransientEnvMap>;
62
63 #[turbo_tasks::function]
65 fn read(self: Vc<Self>, name: RcStr) -> Vc<Option<RcStr>> {
66 case_insensitive_read(self.read_all(), name)
67 }
68}
69
70pub fn sorted_env_vars() -> FxIndexMap<RcStr, RcStr> {
71 let mut vars = env::vars()
72 .map(|(k, v)| (k.into(), v.into()))
73 .collect::<FxIndexMap<_, _>>();
74 vars.sort_keys();
75 vars
76}
77
78#[turbo_tasks::function]
79pub async fn case_insensitive_read(
80 map: Vc<TransientEnvMap>,
81 name: RcStr,
82) -> Result<Vc<Option<RcStr>>> {
83 Ok(Vc::cell(
84 to_uppercase_map(map)
85 .await?
86 .get(&RcStr::from(name.to_uppercase()))
87 .cloned(),
88 ))
89}
90
91#[turbo_tasks::function]
92async fn to_uppercase_map(map: Vc<TransientEnvMap>) -> Result<Vc<TransientEnvMap>> {
93 let map = &*map.await?;
94 let mut new = FxIndexMap::with_capacity_and_hasher(map.len(), Default::default());
95 for (k, v) in map {
96 new.insert(k.to_uppercase().into(), v.clone());
97 }
98 Ok(Vc::cell(new))
99}
100
101pub static GLOBAL_ENV_LOCK: Mutex<()> = Mutex::new(());