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 = "skip"` to avoid storing
21/// environment variables (which may contain secrets) in the persistent cache.
22#[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    /// Reads all env variables into a Map
60    #[turbo_tasks::function]
61    fn read_all(self: Vc<Self>) -> Vc<TransientEnvMap>;
62
63    /// Reads a single env variable. Ignores casing.
64    #[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(());