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(#[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    // TODO SECURITY: From security perspective it's not good that we read *all* env
47    // vars into the cache. This might store secrects into the persistent cache
48    // which we want to avoid.
49    // Instead we should use only `read_prefix` to read all env vars with a specific
50    // prefix.
51    /// Reads all env variables into a Map
52    fn read_all(self: Vc<Self>) -> Vc<EnvMap>;
53
54    /// Reads a single env variable. Ignores casing.
55    fn read(self: Vc<Self>, name: RcStr) -> Vc<Option<RcStr>> {
56        case_insensitive_read(self.read_all(), name)
57    }
58}
59
60pub fn sorted_env_vars() -> FxIndexMap<RcStr, RcStr> {
61    let mut vars = env::vars()
62        .map(|(k, v)| (k.into(), v.into()))
63        .collect::<FxIndexMap<_, _>>();
64    vars.sort_keys();
65    vars
66}
67
68#[turbo_tasks::function]
69pub async fn case_insensitive_read(map: Vc<EnvMap>, name: RcStr) -> Result<Vc<Option<RcStr>>> {
70    Ok(Vc::cell(
71        to_uppercase_map(map)
72            .await?
73            .get(&RcStr::from(name.to_uppercase()))
74            .cloned(),
75    ))
76}
77
78#[turbo_tasks::function]
79async fn to_uppercase_map(map: Vc<EnvMap>) -> Result<Vc<EnvMap>> {
80    let map = &*map.await?;
81    let mut new = FxIndexMap::with_capacity_and_hasher(map.len(), Default::default());
82    for (k, v) in map {
83        new.insert(k.to_uppercase().into(), v.clone());
84    }
85    Ok(Vc::cell(new))
86}
87
88pub static GLOBAL_ENV_LOCK: Mutex<()> = Mutex::new(());
89
90pub fn register() {
91    turbo_tasks::register();
92    include!(concat!(env!("OUT_DIR"), "/register.rs"));
93}