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)]
21pub struct EnvMap(#[turbo_tasks(trace_ignore)] FxIndexMap<RcStr, RcStr>);
22
23#[turbo_tasks::value_impl]
24impl EnvMap {
25 #[turbo_tasks::function]
26 pub fn empty() -> Vc<Self> {
27 EnvMap(FxIndexMap::default()).cell()
28 }
29}
30
31#[turbo_tasks::value_impl]
32impl ProcessEnv for EnvMap {
33 #[turbo_tasks::function]
34 fn read_all(self: Vc<Self>) -> Vc<EnvMap> {
35 self
36 }
37
38 #[turbo_tasks::function]
39 fn read(self: Vc<Self>, name: RcStr) -> Vc<Option<RcStr>> {
40 case_insensitive_read(self, name)
41 }
42}
43
44#[turbo_tasks::value_trait]
45pub trait ProcessEnv {
46 #[turbo_tasks::function]
53 fn read_all(self: Vc<Self>) -> Vc<EnvMap>;
54
55 #[turbo_tasks::function]
57 fn read(self: Vc<Self>, name: RcStr) -> Vc<Option<RcStr>> {
58 case_insensitive_read(self.read_all(), name)
59 }
60}
61
62pub fn sorted_env_vars() -> FxIndexMap<RcStr, RcStr> {
63 let mut vars = env::vars()
64 .map(|(k, v)| (k.into(), v.into()))
65 .collect::<FxIndexMap<_, _>>();
66 vars.sort_keys();
67 vars
68}
69
70#[turbo_tasks::function]
71pub async fn case_insensitive_read(map: Vc<EnvMap>, name: RcStr) -> Result<Vc<Option<RcStr>>> {
72 Ok(Vc::cell(
73 to_uppercase_map(map)
74 .await?
75 .get(&RcStr::from(name.to_uppercase()))
76 .cloned(),
77 ))
78}
79
80#[turbo_tasks::function]
81async fn to_uppercase_map(map: Vc<EnvMap>) -> Result<Vc<EnvMap>> {
82 let map = &*map.await?;
83 let mut new = FxIndexMap::with_capacity_and_hasher(map.len(), Default::default());
84 for (k, v) in map {
85 new.insert(k.to_uppercase().into(), v.clone());
86 }
87 Ok(Vc::cell(new))
88}
89
90pub static GLOBAL_ENV_LOCK: Mutex<()> = Mutex::new(());
91
92pub fn register() {
93 turbo_tasks::register();
94 include!(concat!(env!("OUT_DIR"), "/register.rs"));
95}