Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add full tera context to tasks #3708

Merged
merged 1 commit into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
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
2 changes: 1 addition & 1 deletion src/cli/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ snapshot_kind: text
Toolset {
versions: {},
source: None,
tera_ctx: OnceCell(Uninit),
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ Toolset {
"/tmp/.mise.toml",
),
),
tera_ctx: OnceCell(Uninit),
}
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
33 changes: 14 additions & 19 deletions src/task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,7 @@ impl Task {
spec.cmd.name = self.name.clone();
(spec, vec![])
} else {
let (scripts, spec) =
TaskScriptParser::new(cwd).parse_run_scripts(&self.config_root, self.run())?;
let (scripts, spec) = TaskScriptParser::new(cwd).parse_run_scripts(self, self.run())?;
(spec, scripts)
};
spec.name = self.name.clone();
Expand Down Expand Up @@ -382,8 +381,7 @@ 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 tera_ctx = self.tera_ctx()?;
let dir = tera.render_str(&dir, &tera_ctx)?;
let dir = file::replace_path(&dir);
if dir.is_absolute() {
Expand All @@ -398,6 +396,14 @@ impl Task {
}
}

pub fn tera_ctx(&self) -> Result<tera::Context> {
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 +424,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()?;
for a in &mut self.aliases {
*a = tera.render_str(a, &tera_ctx)?;
}
Expand All @@ -431,22 +435,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
38 changes: 28 additions & 10 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,28 @@ 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 +53,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 Expand Up @@ -85,9 +102,10 @@ mod tests {
assert_eq!(td.task, "task");
assert!(td.args.is_empty());

let td: TaskDep = "task arg1 arg2".parse().unwrap();
assert_eq!(td.task, "task");
assert_eq!(td.args, vec!["arg1", "arg2"]);
// TODO: td.render()
// let td: TaskDep = "task arg1 arg2".parse().unwrap();
// assert_eq!(td.task, "task");
// assert_eq!(td.args, vec!["arg1", "arg2"]);
}

#[test]
Expand Down
18 changes: 8 additions & 10 deletions src/task/task_script_parser.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::config::{Config, SETTINGS};
use crate::config::SETTINGS;
use crate::exit::exit;
use crate::shell::ShellType;
use crate::task::Task;
Expand Down Expand Up @@ -27,7 +27,7 @@ impl TaskScriptParser {

pub fn parse_run_scripts(
&self,
config_root: &Option<PathBuf>,
task: &Task,
scripts: &[String],
) -> Result<(Vec<String>, usage::Spec)> {
let mut tera = self.get_tera();
Expand Down Expand Up @@ -272,9 +272,7 @@ impl TaskScriptParser {
}
}
});
let config = Config::get();
let mut ctx = config.tera_ctx.clone();
ctx.insert("config_root", config_root);
let ctx = task.tera_ctx()?;
let scripts = scripts
.iter()
.map(|s| tera.render_str(s.trim(), &ctx).unwrap())
Expand Down Expand Up @@ -384,7 +382,7 @@ mod tests {
let task = Task::default();
let parser = TaskScriptParser::new(None);
let scripts = vec!["echo {{ arg(i=0, name='foo') }}".to_string()];
let (scripts, spec) = parser.parse_run_scripts(&None, &scripts).unwrap();
let (scripts, spec) = parser.parse_run_scripts(&task, &scripts).unwrap();
assert_eq!(scripts, vec!["echo MISE_TASK_ARG:foo:MISE_TASK_ARG"]);
let arg0 = spec.cmd.args.first().unwrap();
assert_eq!(arg0.name, "foo");
Expand All @@ -403,7 +401,7 @@ mod tests {
"echo {{ arg(name='foo') }}; echo {{ arg(name='bar') }}; echo {{ arg(name='foo') }}"
.to_string(),
];
let (scripts, spec) = parser.parse_run_scripts(&None, &scripts).unwrap();
let (scripts, spec) = parser.parse_run_scripts(&task, &scripts).unwrap();
assert_eq!(scripts, vec!["echo MISE_TASK_ARG:foo:MISE_TASK_ARG; echo MISE_TASK_ARG:bar:MISE_TASK_ARG; echo MISE_TASK_ARG:foo:MISE_TASK_ARG"]);
let arg0 = spec.cmd.args.first().unwrap();
let arg1 = spec.cmd.args.get(1).unwrap();
Expand All @@ -426,7 +424,7 @@ mod tests {
let task = Task::default();
let parser = TaskScriptParser::new(None);
let scripts = vec!["echo {{ arg(var=true) }}".to_string()];
let (scripts, spec) = parser.parse_run_scripts(&None, &scripts).unwrap();
let (scripts, spec) = parser.parse_run_scripts(&task, &scripts).unwrap();
assert_eq!(scripts, vec!["echo MISE_TASK_ARG:0:MISE_TASK_ARG"]);
let arg0 = spec.cmd.args.first().unwrap();
assert_eq!(arg0.name, "0");
Expand All @@ -446,7 +444,7 @@ mod tests {
let task = Task::default();
let parser = TaskScriptParser::new(None);
let scripts = vec!["echo {{ flag(name='foo') }}".to_string()];
let (scripts, spec) = parser.parse_run_scripts(&None, &scripts).unwrap();
let (scripts, spec) = parser.parse_run_scripts(&task, &scripts).unwrap();
assert_eq!(scripts, vec!["echo MISE_TASK_ARG:foo:MISE_TASK_ARG"]);
let flag = spec.cmd.flags.iter().find(|f| &f.name == "foo").unwrap();
assert_eq!(&flag.name, "foo");
Expand All @@ -462,7 +460,7 @@ mod tests {
let task = Task::default();
let parser = TaskScriptParser::new(None);
let scripts = vec!["echo {{ option(name='foo') }}".to_string()];
let (scripts, spec) = parser.parse_run_scripts(&None, &scripts).unwrap();
let (scripts, spec) = parser.parse_run_scripts(&task, &scripts).unwrap();
assert_eq!(scripts, vec!["echo MISE_TASK_ARG:foo:MISE_TASK_ARG"]);
let option = spec.cmd.flags.iter().find(|f| &f.name == "foo").unwrap();
assert_eq!(&option.name, "foo");
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)?;
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
12 changes: 8 additions & 4 deletions src/toolset/tool_request_set.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use std::collections::{BTreeMap, BTreeSet, HashSet};
use std::fmt::{Debug, Display};

use indexmap::IndexMap;
use itertools::Itertools;

use crate::backend::backend_type::BackendType;
use crate::cli::args::{BackendArg, ToolArg};
use crate::config::{Config, Settings};
use crate::env;
use crate::registry::REGISTRY;
use crate::toolset::{ToolRequest, ToolSource, Toolset};
use indexmap::IndexMap;
use itertools::Itertools;

#[derive(Debug, Default, Clone)]
pub struct ToolRequestSet {
Expand Down Expand Up @@ -168,7 +168,11 @@ impl ToolRequestSetBuilder {
}

fn is_disabled(&self, ba: &BackendArg) -> bool {
!ba.is_os_supported() || self.disable_tools.contains(ba)
let backend_type = ba.backend_type();
backend_type == BackendType::Unknown
|| (cfg!(windows) && backend_type == BackendType::Asdf)
|| !ba.is_os_supported()
|| self.disable_tools.contains(ba)
}

fn load_config_files(&self, trs: &mut ToolRequestSet) -> eyre::Result<()> {
Expand Down
Loading