Skip to content

Commit

Permalink
fix: add full tera context to tasks
Browse files Browse the repository at this point in the history
Fixes #3701
  • Loading branch information
jdx committed Dec 19, 2024
1 parent 7b57cf4 commit a562429
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 36 deletions.
14 changes: 14 additions & 0 deletions e2e/tasks/test_task_run_tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash

cat <<EOF >mise.toml
env.BAR = "bar"
tasks.a = "echo {{ env.BAR }}"
EOF
assert "mise run a" "bar"

cat <<EOF >mise.toml
env.BAR = "a"
tasks.a = "echo a"
tasks.b.depends = ["{{ env.BAR }}"]
EOF
assert "mise run b" "a"
2 changes: 1 addition & 1 deletion src/cli/direnv/envrc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl Envrc {
)?;
}
}
for path in ts.list_final_paths(config, env_results)?.into_iter().rev() {
for path in ts.list_final_paths(config, env_results)?.iter().rev() {
writeln!(file, "PATH_add {}", path.to_string_lossy())?;
}

Expand Down
2 changes: 1 addition & 1 deletion src/cli/doctor/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl Path {
env::split_paths(&path).collect()
} else {
let (_env, env_results) = ts.final_env(&config)?;
ts.list_final_paths(&config, env_results)?
ts.list_final_paths(&config, env_results)?.clone()
};
for path in paths {
println!("{}", path.display());
Expand Down
3 changes: 2 additions & 1 deletion src/cli/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ impl Env {
}

fn output_dotenv(&self, config: &Config, ts: Toolset) -> Result<()> {
for (k, v) in ts.final_env(config)?.0 {
let (env, _) = ts.final_env(config)?;
for (k, v) in env {
let k = k.to_string();
let v = v.to_string();
miseprint!("{}={}\n", k, v)?;
Expand Down
4 changes: 2 additions & 2 deletions src/cli/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl Exec {
});

let (program, mut args) = parse_command(&env::SHELL, &self.command, &self.c);
let env = measure!("env_with_path", { ts.env_with_path(&config)? });
let env = measure!("env_with_path", { ts.env_with_path(&config)?.clone() });

if program.rsplit('/').next() == Some("fish") {
let mut cmd = vec![];
Expand All @@ -94,7 +94,7 @@ impl Exec {
));
}
// TODO: env is being calculated twice with final_env and env_with_path
let env_results = ts.final_env(&config)?.1;
let (_, env_results) = ts.final_env(&config)?;
for p in ts.list_final_paths(&config, env_results)? {
cmd.push(format!(
"fish_add_path -gm {}",
Expand Down
2 changes: 1 addition & 1 deletion src/config/env_directive/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ impl Display for EnvDirective {
}
}

#[derive(Default)]
#[derive(Default, Clone)]
pub struct EnvResults {
pub env: IndexMap<String, (String, PathBuf)>,
pub env_remove: BTreeSet<String>,
Expand Down
4 changes: 2 additions & 2 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use eyre::{bail, eyre, Context, Result};
use indexmap::{IndexMap, IndexSet};
use itertools::Itertools;
use once_cell::sync::OnceCell;
use std::sync::LazyLock as Lazy;
use once_cell::sync::{OnceCell};
use rayon::prelude::*;
pub use settings::Settings;
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::fmt::{Debug, Formatter};
use std::iter::once;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::sync::LazyLock as Lazy;
use std::sync::{Arc, Mutex, OnceLock, RwLock};
use std::time::Duration;
use walkdir::WalkDir;
Expand Down
39 changes: 21 additions & 18 deletions src/task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::LazyLock as Lazy;
use std::{ffi, fmt, path};
use once_cell::sync::OnceCell;
use xx::regex;

mod deps;
Expand Down Expand Up @@ -97,6 +98,9 @@ pub struct Task {
// file type
#[serde(default)]
pub file: Option<PathBuf>,

#[serde(skip)]
pub tera_ctx: OnceCell<tera::Context>,
}

#[derive(Clone, PartialEq, Eq, Deserialize, Serialize)]
Expand Down Expand Up @@ -382,9 +386,8 @@ impl Task {
}) {
let config_root = self.config_root.clone().unwrap_or_default();
let mut tera = get_tera(Some(&config_root));
let mut tera_ctx = config.tera_ctx.clone();
tera_ctx.insert("config_root", &config_root);
let dir = tera.render_str(&dir, &tera_ctx)?;
let tera_ctx = self.tera_ctx()?;
let dir = tera.render_str(&dir, tera_ctx)?;
let dir = file::replace_path(&dir);
if dir.is_absolute() {
Ok(Some(dir.to_path_buf()))
Expand All @@ -398,6 +401,16 @@ impl Task {
}
}

pub fn tera_ctx(&self) -> Result<&tera::Context> {
self.tera_ctx.get_or_try_init(|| {
let config = Config::get();
let ts = config.get_toolset()?;
let mut tera_ctx = ts.tera_ctx()?.clone();
tera_ctx.insert("config_root", &self.config_root);
Ok(tera_ctx)
})
}

pub fn cf<'a>(&self, config: &'a Config) -> Option<&'a Box<dyn ConfigFile>> {
config.config_files.get(&self.config_source)
}
Expand All @@ -418,10 +431,8 @@ impl Task {
}

pub fn render(&mut self, config_root: &Path) -> Result<()> {
let config = Config::get();
let mut tera = get_tera(Some(config_root));
let mut tera_ctx = config.tera_ctx.clone();
tera_ctx.insert("config_root", &config_root);
let tera_ctx = self.tera_ctx()?.clone();
for a in &mut self.aliases {
*a = tera.render_str(a, &tera_ctx)?;
}
Expand All @@ -431,22 +442,13 @@ impl Task {
}
self.outputs.render(&mut tera, &tera_ctx)?;
for d in &mut self.depends {
d.task = tera.render_str(&d.task, &tera_ctx)?;
for a in &mut d.args {
*a = tera.render_str(a, &tera_ctx)?;
}
d.render(&mut tera, &tera_ctx)?;
}
for d in &mut self.depends_post {
d.task = tera.render_str(&d.task, &tera_ctx)?;
for a in &mut d.args {
*a = tera.render_str(a, &tera_ctx)?;
}
d.render(&mut tera, &tera_ctx)?;
}
for d in &mut self.wait_for {
d.task = tera.render_str(&d.task, &tera_ctx)?;
for a in &mut d.args {
*a = tera.render_str(a, &tera_ctx)?;
}
d.render(&mut tera, &tera_ctx)?;
}
for v in self.env.values_mut() {
if let EitherStringOrIntOrBool(Either::Left(s)) = v {
Expand Down Expand Up @@ -527,6 +529,7 @@ impl Default for Task {
file: None,
quiet: false,
tools: Default::default(),
tera_ctx: Default::default(),
}
}
}
Expand Down
27 changes: 20 additions & 7 deletions src/task/task_dep.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::config::config_file::toml::deserialize_arr;
use itertools::Itertools;
use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize};
use std::fmt;
Expand All @@ -12,6 +11,24 @@ pub struct TaskDep {
pub args: Vec<String>,
}

impl TaskDep {
pub fn render(&mut self, tera: &mut tera::Tera, tera_ctx: &tera::Context) -> crate::Result<&mut Self> {
self.task = tera.render_str(&self.task, tera_ctx)?;
for a in &mut self.args {
*a = tera.render_str(a, tera_ctx)?;
}
if self.args.is_empty() {
let s = self.task.clone();
let mut split = s.split_whitespace().map(|s| s.to_string());
if let Some(task) = split.next() {
self.task = task;
}
self.args = split.collect();
}
Ok(self)
}
}

impl Display for TaskDep {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.task)?;
Expand All @@ -32,13 +49,9 @@ impl FromStr for TaskDep {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts = s.split_whitespace().collect_vec();
if parts.is_empty() {
return Err("Task name is required".to_string());
}
Ok(Self {
task: parts[0].to_string(),
args: parts[1..].iter().map(|s| s.to_string()).collect(),
task: s.to_string(),
args: Default::default(),
})
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/task/task_script_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,9 @@ impl TaskScriptParser {
}
});
let config = Config::get();
let mut ctx = config.tera_ctx.clone();
// TODO: this won't have paths if they're added to the task directly
let ts = config.get_toolset()?;
let mut ctx = ts.tera_ctx()?.clone();
ctx.insert("config_root", config_root);
let scripts = scripts
.iter()
Expand Down
15 changes: 13 additions & 2 deletions src/toolset/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use console::truncate_str;
use eyre::{eyre, Result, WrapErr};
use indexmap::{IndexMap, IndexSet};
use itertools::Itertools;
use once_cell::sync::OnceCell;
pub use outdated_info::is_outdated_version;
use outdated_info::OutdatedInfo;
use rayon::prelude::*;
Expand Down Expand Up @@ -108,6 +109,7 @@ impl Default for InstallOptions {
pub struct Toolset {
pub versions: IndexMap<BackendArg, ToolVersionList>,
pub source: Option<ToolSource>,
tera_ctx: OnceCell<tera::Context>,
}

impl Toolset {
Expand Down Expand Up @@ -463,15 +465,15 @@ impl Toolset {
/// returns env_with_path but also with the existing env vars from the system
pub fn full_env(&self) -> Result<EnvMap> {
let mut env = env::PRISTINE_ENV.clone().into_iter().collect::<EnvMap>();
env.extend(self.env_with_path(&Config::get())?);
env.extend(self.env_with_path(&Config::get())?.clone());
Ok(env)
}
/// the full mise environment including all tool paths
pub fn env_with_path(&self, config: &Config) -> Result<EnvMap> {
let (mut env, env_results) = self.final_env(config)?;
let mut path_env = PathEnv::from_iter(env::PATH.clone());
for p in self.list_final_paths(config, env_results)? {
path_env.add(p);
path_env.add(p.clone());
}
env.insert(PATH_KEY.to_string(), path_env.to_string());
Ok(env)
Expand Down Expand Up @@ -585,6 +587,15 @@ impl Toolset {
let paths = env_results.env_paths.into_iter().chain(paths).collect();
Ok(paths)
}
pub fn tera_ctx(&self) -> Result<&tera::Context> {
self.tera_ctx.get_or_try_init(|| {
let config = Config::get();
let env = self.env_with_path(&config).unwrap();
let mut ctx = config.tera_ctx.clone();
ctx.insert("env", &env);
Ok(ctx)
})
}
pub fn which(&self, bin_name: &str) -> Option<(Arc<dyn Backend>, ToolVersion)> {
self.list_current_installed_versions()
.into_par_iter()
Expand Down

0 comments on commit a562429

Please sign in to comment.