vrl/stdlib/
get_env_var.rs

1use crate::compiler::prelude::*;
2
3fn get_env_var(value: &Value) -> Resolved {
4    let name = value.try_bytes_utf8_lossy()?;
5    std::env::var(name.as_ref())
6        .map(Into::into)
7        .map_err(|e| e.to_string().into())
8}
9
10#[derive(Clone, Copy, Debug)]
11pub struct GetEnvVar;
12
13impl Function for GetEnvVar {
14    fn identifier(&self) -> &'static str {
15        "get_env_var"
16    }
17
18    fn usage(&self) -> &'static str {
19        "Returns the value of the environment variable specified by `name`."
20    }
21
22    fn category(&self) -> &'static str {
23        Category::System.as_ref()
24    }
25
26    fn internal_failure_reasons(&self) -> &'static [&'static str] {
27        &[
28            "Environment variable `name` does not exist.",
29            "The value of environment variable `name` is not valid Unicode",
30        ]
31    }
32
33    fn return_kind(&self) -> u16 {
34        kind::BYTES
35    }
36
37    fn parameters(&self) -> &'static [Parameter] {
38        const PARAMETERS: &[Parameter] = &[Parameter::required(
39            "name",
40            kind::BYTES,
41            "The name of the environment variable.",
42        )];
43        PARAMETERS
44    }
45
46    fn examples(&self) -> &'static [Example] {
47        &[example! {
48            title: "Get an environment variable",
49            source: r#"get_env_var!("HOME")"#,
50            result: Ok("/root"),
51            deterministic: false,
52        }]
53    }
54
55    fn compile(
56        &self,
57        _state: &state::TypeState,
58        _ctx: &mut FunctionCompileContext,
59        arguments: ArgumentList,
60    ) -> Compiled {
61        let name = arguments.required("name");
62
63        Ok(GetEnvVarFn { name }.as_expr())
64    }
65}
66
67#[derive(Debug, Clone)]
68struct GetEnvVarFn {
69    name: Box<dyn Expression>,
70}
71
72impl FunctionExpression for GetEnvVarFn {
73    fn resolve(&self, ctx: &mut Context) -> Resolved {
74        let value = self.name.resolve(ctx)?;
75        get_env_var(&value)
76    }
77
78    fn type_def(&self, _: &state::TypeState) -> TypeDef {
79        TypeDef::bytes().fallible()
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86    use crate::value;
87
88    test_function![
89        get_env_var => GetEnvVar;
90
91        before_each => {
92            // TODO: Audit that the environment access only happens in single-threaded code.
93            unsafe { std::env::set_var("VAR2", "var") };
94        }
95
96        doesnt_exist {
97            args: func_args![name: "VAR1"],
98            want: Err("environment variable not found"),
99            tdef: TypeDef::bytes().fallible(),
100        }
101
102        exists {
103            args: func_args![name: "VAR2"],
104            want: Ok(value!("var")),
105            tdef: TypeDef::bytes().fallible(),
106        }
107
108        invalid1 {
109            args: func_args![name: "="],
110            want: Err("environment variable not found"),
111            tdef: TypeDef::bytes().fallible(),
112        }
113
114        invalid2 {
115            args: func_args![name: ""],
116            want: Err("environment variable not found"),
117            tdef: TypeDef::bytes().fallible(),
118        }
119
120        invalid3 {
121            args: func_args![name: "a=b"],
122            want: Err("environment variable not found"),
123            tdef: TypeDef::bytes().fallible(),
124        }
125    ];
126}