Make .env vars available in env_var functions (#310)
This commit is contained in:
parent
70e96d52eb
commit
68b343bc17
@ -83,7 +83,7 @@ impl<'a, 'b> AssignmentEvaluator<'a, 'b> {
|
||||
fn evaluate_expression(
|
||||
&mut self,
|
||||
expression: &Expression<'a>,
|
||||
arguments: &Map<&str, Cow<str>>
|
||||
arguments: &Map<&str, Cow<str>>
|
||||
) -> RunResult<'a, String> {
|
||||
match *expression {
|
||||
Expression::Variable{name, ..} => {
|
||||
@ -106,7 +106,10 @@ impl<'a, 'b> AssignmentEvaluator<'a, 'b> {
|
||||
let call_arguments = call_arguments.iter().map(|argument| {
|
||||
self.evaluate_expression(argument, arguments)
|
||||
}).collect::<Result<Vec<String>, RuntimeError>>()?;
|
||||
::functions::evaluate_function(token, name, &call_arguments)
|
||||
let context = FunctionContext {
|
||||
dotenv: self.dotenv,
|
||||
};
|
||||
evaluate_function(token, name, &context, &call_arguments)
|
||||
}
|
||||
Expression::String{ref cooked_string} => Ok(cooked_string.cooked.clone()),
|
||||
Expression::Backtick{raw, ref token} => {
|
||||
|
@ -76,7 +76,7 @@ impl<'a: 'b, 'b> AssignmentResolver<'a, 'b> {
|
||||
}
|
||||
}
|
||||
Expression::Call{ref token, ref arguments, ..} => {
|
||||
::functions::resolve_function(token, arguments.len())?
|
||||
resolve_function(token, arguments.len())?
|
||||
}
|
||||
Expression::Concatination{ref lhs, ref rhs} => {
|
||||
self.resolve_expression(lhs)?;
|
||||
|
35
src/common.rs
Normal file
35
src/common.rs
Normal file
@ -0,0 +1,35 @@
|
||||
pub use std::borrow::Cow;
|
||||
pub use std::collections::{BTreeMap as Map, BTreeSet as Set};
|
||||
pub use std::fmt::Display;
|
||||
pub use std::io::prelude::*;
|
||||
pub use std::ops::Range;
|
||||
pub use std::path::{Path, PathBuf};
|
||||
pub use std::process::Command;
|
||||
pub use std::{cmp, env, fs, fmt, io, iter, process, vec, usize};
|
||||
|
||||
pub use color::Color;
|
||||
pub use libc::{EXIT_FAILURE, EXIT_SUCCESS};
|
||||
pub use regex::Regex;
|
||||
pub use tempdir::TempDir;
|
||||
|
||||
pub use assignment_evaluator::AssignmentEvaluator;
|
||||
pub use assignment_resolver::AssignmentResolver;
|
||||
pub use command_ext::CommandExt;
|
||||
pub use compilation_error::{CompilationError, CompilationErrorKind, CompilationResult};
|
||||
pub use configuration::Configuration;
|
||||
pub use cooked_string::CookedString;
|
||||
pub use expression::Expression;
|
||||
pub use fragment::Fragment;
|
||||
pub use function::{evaluate_function, resolve_function, FunctionContext};
|
||||
pub use justfile::Justfile;
|
||||
pub use lexer::Lexer;
|
||||
pub use load_dotenv::load_dotenv;
|
||||
pub use misc::{default, empty};
|
||||
pub use parameter::Parameter;
|
||||
pub use parser::Parser;
|
||||
pub use range_ext::RangeExt;
|
||||
pub use recipe::Recipe;
|
||||
pub use recipe_resolver::RecipeResolver;
|
||||
pub use runtime_error::{RuntimeError, RunResult};
|
||||
pub use shebang::Shebang;
|
||||
pub use token::{Token, TokenKind};
|
@ -12,9 +12,9 @@ lazy_static! {
|
||||
}
|
||||
|
||||
enum Function {
|
||||
Nullary(fn( ) -> Result<String, String>),
|
||||
Unary (fn(&str ) -> Result<String, String>),
|
||||
Binary (fn(&str, &str) -> Result<String, String>),
|
||||
Nullary(fn(&FunctionContext, ) -> Result<String, String>),
|
||||
Unary (fn(&FunctionContext, &str ) -> Result<String, String>),
|
||||
Binary (fn(&FunctionContext, &str, &str) -> Result<String, String>),
|
||||
}
|
||||
|
||||
impl Function {
|
||||
@ -28,6 +28,10 @@ impl Function {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FunctionContext<'a> {
|
||||
pub dotenv: &'a Map<String, String>,
|
||||
}
|
||||
|
||||
pub fn resolve_function<'a>(token: &Token<'a>, argc: usize) -> CompilationResult<'a, ()> {
|
||||
let name = token.lexeme;
|
||||
if let Some(function) = FUNCTIONS.get(&name) {
|
||||
@ -48,19 +52,20 @@ pub fn resolve_function<'a>(token: &Token<'a>, argc: usize) -> CompilationResult
|
||||
}
|
||||
|
||||
pub fn evaluate_function<'a>(
|
||||
token: &Token<'a>,
|
||||
name: &'a str,
|
||||
token: &Token<'a>,
|
||||
name: &'a str,
|
||||
context: &FunctionContext,
|
||||
arguments: &[String]
|
||||
) -> RunResult<'a, String> {
|
||||
if let Some(function) = FUNCTIONS.get(name) {
|
||||
use self::Function::*;
|
||||
let argc = arguments.len();
|
||||
match (function, argc) {
|
||||
(&Nullary(f), 0) => f()
|
||||
(&Nullary(f), 0) => f(context)
|
||||
.map_err(|message| RuntimeError::FunctionCall{token: token.clone(), message}),
|
||||
(&Unary(f), 1) => f(&arguments[0])
|
||||
(&Unary(f), 1) => f(context, &arguments[0])
|
||||
.map_err(|message| RuntimeError::FunctionCall{token: token.clone(), message}),
|
||||
(&Binary(f), 2) => f(&arguments[0], &arguments[1])
|
||||
(&Binary(f), 2) => f(context, &arguments[0], &arguments[1])
|
||||
.map_err(|message| RuntimeError::FunctionCall{token: token.clone(), message}),
|
||||
_ => {
|
||||
Err(RuntimeError::Internal {
|
||||
@ -75,20 +80,25 @@ pub fn evaluate_function<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arch() -> Result<String, String> {
|
||||
pub fn arch(_context: &FunctionContext) -> Result<String, String> {
|
||||
Ok(target::arch().to_string())
|
||||
}
|
||||
|
||||
pub fn os() -> Result<String, String> {
|
||||
pub fn os(_context: &FunctionContext) -> Result<String, String> {
|
||||
Ok(target::os().to_string())
|
||||
}
|
||||
|
||||
pub fn os_family() -> Result<String, String> {
|
||||
pub fn os_family(_context: &FunctionContext) -> Result<String, String> {
|
||||
Ok(target::os_family().to_string())
|
||||
}
|
||||
|
||||
pub fn env_var(key: &str) -> Result<String, String> {
|
||||
pub fn env_var(context: &FunctionContext, key: &str) -> Result<String, String> {
|
||||
use std::env::VarError::*;
|
||||
|
||||
if let Some(value) = context.dotenv.get(key) {
|
||||
return Ok(value.clone());
|
||||
}
|
||||
|
||||
match env::var(key) {
|
||||
Err(NotPresent) => Err(format!("environment variable `{}` not present", key)),
|
||||
Err(NotUnicode(os_string)) =>
|
||||
@ -97,7 +107,15 @@ pub fn env_var(key: &str) -> Result<String, String> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn env_var_or_default(key: &str, default: &str) -> Result<String, String> {
|
||||
pub fn env_var_or_default(
|
||||
context: &FunctionContext,
|
||||
key: &str,
|
||||
default: &str,
|
||||
) -> Result<String, String> {
|
||||
if let Some(value) = context.dotenv.get(key) {
|
||||
return Ok(value.clone());
|
||||
}
|
||||
|
||||
use std::env::VarError::*;
|
||||
match env::var(key) {
|
||||
Err(NotPresent) => Ok(default.to_string()),
|
42
src/main.rs
42
src/main.rs
@ -20,15 +20,16 @@ mod assignment_evaluator;
|
||||
mod assignment_resolver;
|
||||
mod color;
|
||||
mod command_ext;
|
||||
mod common;
|
||||
mod compilation_error;
|
||||
mod configuration;
|
||||
mod cooked_string;
|
||||
mod load_dotenv;
|
||||
mod expression;
|
||||
mod fragment;
|
||||
mod functions;
|
||||
mod function;
|
||||
mod justfile;
|
||||
mod lexer;
|
||||
mod load_dotenv;
|
||||
mod misc;
|
||||
mod parameter;
|
||||
mod parser;
|
||||
@ -41,43 +42,6 @@ mod runtime_error;
|
||||
mod shebang;
|
||||
mod token;
|
||||
|
||||
mod common {
|
||||
pub use std::borrow::Cow;
|
||||
pub use std::collections::{BTreeMap as Map, BTreeSet as Set};
|
||||
pub use std::fmt::Display;
|
||||
pub use std::io::prelude::*;
|
||||
pub use std::ops::Range;
|
||||
pub use std::path::{Path, PathBuf};
|
||||
pub use std::process::Command;
|
||||
pub use std::{cmp, env, fs, fmt, io, iter, process, vec, usize};
|
||||
|
||||
pub use color::Color;
|
||||
pub use libc::{EXIT_FAILURE, EXIT_SUCCESS};
|
||||
pub use regex::Regex;
|
||||
pub use tempdir::TempDir;
|
||||
|
||||
pub use assignment_evaluator::AssignmentEvaluator;
|
||||
pub use assignment_resolver::AssignmentResolver;
|
||||
pub use command_ext::CommandExt;
|
||||
pub use compilation_error::{CompilationError, CompilationErrorKind, CompilationResult};
|
||||
pub use configuration::Configuration;
|
||||
pub use cooked_string::CookedString;
|
||||
pub use expression::Expression;
|
||||
pub use fragment::Fragment;
|
||||
pub use justfile::Justfile;
|
||||
pub use lexer::Lexer;
|
||||
pub use load_dotenv::load_dotenv;
|
||||
pub use misc::{default, empty};
|
||||
pub use parameter::Parameter;
|
||||
pub use parser::Parser;
|
||||
pub use range_ext::RangeExt;
|
||||
pub use recipe::Recipe;
|
||||
pub use recipe_resolver::RecipeResolver;
|
||||
pub use runtime_error::{RuntimeError, RunResult};
|
||||
pub use shebang::Shebang;
|
||||
pub use token::{Token, TokenKind};
|
||||
}
|
||||
|
||||
use common::*;
|
||||
|
||||
fn main() {
|
||||
|
@ -42,7 +42,7 @@ impl<'a, 'b> RecipeResolver<'a, 'b> {
|
||||
for fragment in line {
|
||||
if let Fragment::Expression{ref expression, ..} = *fragment {
|
||||
for (function, argc) in expression.functions() {
|
||||
if let Err(error) = ::functions::resolve_function(function, argc) {
|
||||
if let Err(error) = resolve_function(function, argc) {
|
||||
return Err(CompilationError {
|
||||
index: error.index,
|
||||
line: error.line,
|
||||
|
@ -1771,3 +1771,32 @@ echo:
|
||||
stderr: "echo dotenv-value\n",
|
||||
status: EXIT_SUCCESS,
|
||||
}
|
||||
integration_test! {
|
||||
name: dotenv_variable_in_function_in_recipe,
|
||||
justfile: "
|
||||
#
|
||||
echo:
|
||||
echo {{env_var_or_default('DOTENV_KEY', 'foo')}}
|
||||
echo {{env_var('DOTENV_KEY')}}
|
||||
",
|
||||
args: (),
|
||||
stdout: "dotenv-value\ndotenv-value\n",
|
||||
stderr: "echo dotenv-value\necho dotenv-value\n",
|
||||
status: EXIT_SUCCESS,
|
||||
}
|
||||
|
||||
integration_test! {
|
||||
name: dotenv_variable_in_function_in_backtick,
|
||||
justfile: "
|
||||
#
|
||||
X=env_var_or_default('DOTENV_KEY', 'foo')
|
||||
Y=env_var('DOTENV_KEY')
|
||||
echo:
|
||||
echo {{X}}
|
||||
echo {{Y}}
|
||||
",
|
||||
args: (),
|
||||
stdout: "dotenv-value\ndotenv-value\n",
|
||||
stderr: "echo dotenv-value\necho dotenv-value\n",
|
||||
status: EXIT_SUCCESS,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user