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#[turbo_tasks::value(transparent)]
21pub struct EnvMap(
22    #[turbo_tasks(trace_ignore)]
23    #[bincode(with = "turbo_bincode::indexmap")]
24    FxIndexMap<RcStr, RcStr>,
25);
26
27#[turbo_tasks::value_impl]
28impl EnvMap {
29    #[turbo_tasks::function]
30    pub fn empty() -> Vc<Self> {
31        EnvMap(FxIndexMap::default()).cell()
32    }
33}
34
35#[turbo_tasks::value_impl]
36impl ProcessEnv for EnvMap {
37    #[turbo_tasks::function]
38    fn read_all(self: Vc<Self>) -> Vc<EnvMap> {
39        self
40    }
41
42    #[turbo_tasks::function]
43    fn read(self: Vc<Self>, name: RcStr) -> Vc<Option<RcStr>> {
44        case_insensitive_read(self, name)
45    }
46}
47
48#[turbo_tasks::value_trait]
49pub trait ProcessEnv {
50    // TODO SECURITY: From security perspective it's not good that we read *all* env
51    // vars into the cache. This might store secrects into the filesystem cache
52    // which we want to avoid.
53    // Instead we should use only `read_prefix` to read all env vars with a specific
54    // prefix.
55    /// Reads all env variables into a Map
56    #[turbo_tasks::function]
57    fn read_all(self: Vc<Self>) -> Vc<EnvMap>;
58
59    /// Reads a single env variable. Ignores casing.
60    #[turbo_tasks::function]
61    fn read(self: Vc<Self>, name: RcStr) -> Vc<Option<RcStr>> {
62        case_insensitive_read(self.read_all(), name)
63    }
64}
65
66pub fn sorted_env_vars() -> FxIndexMap<RcStr, RcStr> {
67    let mut vars = env::vars()
68        .map(|(k, v)| (k.into(), v.into()))
69        .collect::<FxIndexMap<_, _>>();
70    vars.sort_keys();
71    vars
72}
73
74#[turbo_tasks::function]
75pub async fn case_insensitive_read(map: Vc<EnvMap>, name: RcStr) -> Result<Vc<Option<RcStr>>> {
76    Ok(Vc::cell(
77        to_uppercase_map(map)
78            .await?
79            .get(&RcStr::from(name.to_uppercase()))
80            .cloned(),
81    ))
82}
83
84#[turbo_tasks::function]
85async fn to_uppercase_map(map: Vc<EnvMap>) -> Result<Vc<EnvMap>> {
86    let map = &*map.await?;
87    let mut new = FxIndexMap::with_capacity_and_hasher(map.len(), Default::default());
88    for (k, v) in map {
89        new.insert(k.to_uppercase().into(), v.clone());
90    }
91    Ok(Vc::cell(new))
92}
93
94pub static GLOBAL_ENV_LOCK: Mutex<()> = Mutex::new(());