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(
|
fn evaluate_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
expression: &Expression<'a>,
|
expression: &Expression<'a>,
|
||||||
arguments: &Map<&str, Cow<str>>
|
arguments: &Map<&str, Cow<str>>
|
||||||
) -> RunResult<'a, String> {
|
) -> RunResult<'a, String> {
|
||||||
match *expression {
|
match *expression {
|
||||||
Expression::Variable{name, ..} => {
|
Expression::Variable{name, ..} => {
|
||||||
@ -106,7 +106,10 @@ impl<'a, 'b> AssignmentEvaluator<'a, 'b> {
|
|||||||
let call_arguments = call_arguments.iter().map(|argument| {
|
let call_arguments = call_arguments.iter().map(|argument| {
|
||||||
self.evaluate_expression(argument, arguments)
|
self.evaluate_expression(argument, arguments)
|
||||||
}).collect::<Result<Vec<String>, RuntimeError>>()?;
|
}).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::String{ref cooked_string} => Ok(cooked_string.cooked.clone()),
|
||||||
Expression::Backtick{raw, ref token} => {
|
Expression::Backtick{raw, ref token} => {
|
||||||
|
@ -76,7 +76,7 @@ impl<'a: 'b, 'b> AssignmentResolver<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Call{ref token, ref arguments, ..} => {
|
Expression::Call{ref token, ref arguments, ..} => {
|
||||||
::functions::resolve_function(token, arguments.len())?
|
resolve_function(token, arguments.len())?
|
||||||
}
|
}
|
||||||
Expression::Concatination{ref lhs, ref rhs} => {
|
Expression::Concatination{ref lhs, ref rhs} => {
|
||||||
self.resolve_expression(lhs)?;
|
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 {
|
enum Function {
|
||||||
Nullary(fn( ) -> Result<String, String>),
|
Nullary(fn(&FunctionContext, ) -> Result<String, String>),
|
||||||
Unary (fn(&str ) -> Result<String, String>),
|
Unary (fn(&FunctionContext, &str ) -> Result<String, String>),
|
||||||
Binary (fn(&str, &str) -> Result<String, String>),
|
Binary (fn(&FunctionContext, &str, &str) -> Result<String, String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
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, ()> {
|
pub fn resolve_function<'a>(token: &Token<'a>, argc: usize) -> CompilationResult<'a, ()> {
|
||||||
let name = token.lexeme;
|
let name = token.lexeme;
|
||||||
if let Some(function) = FUNCTIONS.get(&name) {
|
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>(
|
pub fn evaluate_function<'a>(
|
||||||
token: &Token<'a>,
|
token: &Token<'a>,
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
|
context: &FunctionContext,
|
||||||
arguments: &[String]
|
arguments: &[String]
|
||||||
) -> RunResult<'a, String> {
|
) -> RunResult<'a, String> {
|
||||||
if let Some(function) = FUNCTIONS.get(name) {
|
if let Some(function) = FUNCTIONS.get(name) {
|
||||||
use self::Function::*;
|
use self::Function::*;
|
||||||
let argc = arguments.len();
|
let argc = arguments.len();
|
||||||
match (function, argc) {
|
match (function, argc) {
|
||||||
(&Nullary(f), 0) => f()
|
(&Nullary(f), 0) => f(context)
|
||||||
.map_err(|message| RuntimeError::FunctionCall{token: token.clone(), message}),
|
.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}),
|
.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}),
|
.map_err(|message| RuntimeError::FunctionCall{token: token.clone(), message}),
|
||||||
_ => {
|
_ => {
|
||||||
Err(RuntimeError::Internal {
|
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())
|
Ok(target::arch().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn os() -> Result<String, String> {
|
pub fn os(_context: &FunctionContext) -> Result<String, String> {
|
||||||
Ok(target::os().to_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())
|
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::*;
|
use std::env::VarError::*;
|
||||||
|
|
||||||
|
if let Some(value) = context.dotenv.get(key) {
|
||||||
|
return Ok(value.clone());
|
||||||
|
}
|
||||||
|
|
||||||
match env::var(key) {
|
match env::var(key) {
|
||||||
Err(NotPresent) => Err(format!("environment variable `{}` not present", key)),
|
Err(NotPresent) => Err(format!("environment variable `{}` not present", key)),
|
||||||
Err(NotUnicode(os_string)) =>
|
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::*;
|
use std::env::VarError::*;
|
||||||
match env::var(key) {
|
match env::var(key) {
|
||||||
Err(NotPresent) => Ok(default.to_string()),
|
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 assignment_resolver;
|
||||||
mod color;
|
mod color;
|
||||||
mod command_ext;
|
mod command_ext;
|
||||||
|
mod common;
|
||||||
mod compilation_error;
|
mod compilation_error;
|
||||||
mod configuration;
|
mod configuration;
|
||||||
mod cooked_string;
|
mod cooked_string;
|
||||||
mod load_dotenv;
|
|
||||||
mod expression;
|
mod expression;
|
||||||
mod fragment;
|
mod fragment;
|
||||||
mod functions;
|
mod function;
|
||||||
mod justfile;
|
mod justfile;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
|
mod load_dotenv;
|
||||||
mod misc;
|
mod misc;
|
||||||
mod parameter;
|
mod parameter;
|
||||||
mod parser;
|
mod parser;
|
||||||
@ -41,43 +42,6 @@ mod runtime_error;
|
|||||||
mod shebang;
|
mod shebang;
|
||||||
mod token;
|
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::*;
|
use common::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -42,7 +42,7 @@ impl<'a, 'b> RecipeResolver<'a, 'b> {
|
|||||||
for fragment in line {
|
for fragment in line {
|
||||||
if let Fragment::Expression{ref expression, ..} = *fragment {
|
if let Fragment::Expression{ref expression, ..} = *fragment {
|
||||||
for (function, argc) in expression.functions() {
|
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 {
|
return Err(CompilationError {
|
||||||
index: error.index,
|
index: error.index,
|
||||||
line: error.line,
|
line: error.line,
|
||||||
|
@ -1771,3 +1771,32 @@ echo:
|
|||||||
stderr: "echo dotenv-value\n",
|
stderr: "echo dotenv-value\n",
|
||||||
status: EXIT_SUCCESS,
|
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