Skip to main content

turbo_tasks_env/
lib.rs

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/// Like [`EnvMap`], but with `serialization = "none"` to avoid storing
21/// environment variables (which may contain secrets) in the persistent cache.
22#[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    /// Reads all env variables into a Map
64    #[turbo_tasks::function]
65    fn read_all(self: Vc<Self>) -> Vc<TransientEnvMap>;
66
67    /// Reads a single env variable. Ignores casing.
68    #[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(());