diff --git a/docs/tasks/running-tasks.md b/docs/tasks/running-tasks.md index aa3381038d..f2f56d83a4 100644 --- a/docs/tasks/running-tasks.md +++ b/docs/tasks/running-tasks.md @@ -4,8 +4,11 @@ See available tasks with `mise tasks`. To show tasks hidden with property `hide= List dependencies of tasks with `mise task deps [tasks]...`. -Run a task with `mise task run`, `mise run`, or just `mise r`. -You might even want to make a shell alias like `alias mr='mise run --'` since this is likely a common command. +Run a task with `mise task run `, `mise run `, `mise r `, or just `mise `—however +that last one you should never put into scripts or documentation because if mise ever adds a command with that name in a +future mise version, the task will be shadowed and must be run with one of the other forms. + +Most mise users will have an alias for `mise run` like `alias mr='mise run'`. By default, tasks will execute with a maximum of 4 parallel jobs. Customize this with the `--jobs` option, `jobs` setting or `MISE_JOBS` environment variable. The output normally will be by line, prefixed with the task diff --git a/e2e/env/test_env_template b/e2e/env/test_env_template index 64ff1df355..43107b9ad9 100644 --- a/e2e/env/test_env_template +++ b/e2e/env/test_env_template @@ -18,3 +18,46 @@ A = "a" B = "{{ env.A }}" EOF assert "mise env -s bash | grep B" "export B=a" + +cat <mise.toml +[env] +FOO = "foo" + +[tasks.foo] +env.BAR = "bar" + +run = """ +printf '\$FOO: %s\n' \$FOO +printf '\$BAR: %s\n' \$BAR +echo "{% raw %}{{ env.FOO }}{% endraw %}: {{ env.FOO }}" +echo "{% raw %}{{ env.BAR }}{% endraw %}: {{ env.BAR }}" +""" +EOF +assert "mise run --trace foo" "\$FOO: foo +\$BAR: bar +{{ env.FOO }}: foo +{{ env.BAR }}: bar" + +cat <mise.toml +[env] +FOO = "foo" + +[tasks.foo] +env.BAR = "{{ env.FOO }}" +env.BAZ = "{{ env.BAR }}" + +run = "printf '\$BAZ: %s\n' \$BAZ" +EOF +assert "mise run --trace foo" "\$BAZ: foo" + +cat <mise.toml +[env] +FOO = "/foo" +_.source = { path = "env.sh", tools = true } +_.path = "{{ env.FOO }}" +EOF +cat <env.sh +#!/usr/bin/env bash +export BAR="\$PATH" +EOF +assert_contains "mise env -s bash | grep BAR" "export BAR='/foo:" diff --git a/src/backend/asdf.rs b/src/backend/asdf.rs index 7aefbc4b73..807cb27274 100644 --- a/src/backend/asdf.rs +++ b/src/backend/asdf.rs @@ -143,7 +143,7 @@ impl AsdfBackend { } let script = sm.get_script_path(&ExecEnv); let dir = dirs::CWD.clone().unwrap_or_default(); - let ed = EnvDiff::from_bash_script(&script, &dir, &sm.env, Default::default())?; + let ed = EnvDiff::from_bash_script(&script, &dir, &sm.env, &Default::default())?; let env = ed .to_patches() .into_iter() diff --git a/src/cli/generate/task_docs.rs b/src/cli/generate/task_docs.rs index a14d226f7d..ef26254b51 100644 --- a/src/cli/generate/task_docs.rs +++ b/src/cli/generate/task_docs.rs @@ -40,18 +40,20 @@ enum TaskDocsStyle { impl TaskDocs { pub fn run(self) -> eyre::Result<()> { + let config = Config::get(); + let ts = config.get_toolset()?; let dir = dirs::CWD.as_ref().unwrap(); - let tasks = Config::get().load_tasks_in_dir(dir)?; + let tasks = config.load_tasks_in_dir(dir)?; let mut out = vec![]; for task in tasks.iter().filter(|t| !t.hide) { - out.push(task.render_markdown(dir)?); + out.push(task.render_markdown(ts, dir)?); } if let Some(output) = &self.output { if self.multi { if output.is_dir() { for (i, task) in tasks.iter().filter(|t| !t.hide).enumerate() { let path = output.join(format!("{}.md", i)); - file::write(&path, &task.render_markdown(dir)?)?; + file::write(&path, &task.render_markdown(ts, dir)?)?; } } else { return Err(eyre::eyre!( diff --git a/src/cli/run.rs b/src/cli/run.rs index 29d0fa30ec..0720fee8ba 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, HashSet}; +use std::collections::BTreeMap; use std::io::Write; use std::iter::once; use std::ops::Deref; @@ -16,7 +16,7 @@ use crate::env_diff::EnvMap; use crate::errors::Error; use crate::file::display_path; use crate::http::HTTP; -use crate::task::{Deps, EitherIntOrBool, GetMatchingExt, Task}; +use crate::task::{Deps, GetMatchingExt, Task}; use crate::toolset::{InstallOptions, ToolsetBuilder}; use crate::ui::{ctrlc, prompt, style, time}; use crate::{dirs, env, exit, file, ui}; @@ -25,7 +25,6 @@ use console::Term; use crossbeam_channel::{select, unbounded}; use demand::{DemandOption, Select}; use duct::IntoExecutablePath; -use either::Either; use eyre::{bail, ensure, eyre, Result}; use glob::glob; use itertools::Itertools; @@ -338,7 +337,7 @@ impl Run { tools.push(format!("{}@{}", k, v).parse()?); } let ts = ToolsetBuilder::new().with_args(&tools).build(&config)?; - let mut env = ts.env_with_path(&config)?; + let mut env = task.render_env(&ts)?; let output = self.output(Some(task)); env.insert("MISE_TASK_OUTPUT".into(), output.to_string()); if output == TaskOutput::Prefix { @@ -366,36 +365,14 @@ impl Run { if let Some(config_root) = &task.config_root { env.insert("MISE_CONFIG_ROOT".into(), config_root.display().to_string()); } - let string_env: Vec<(String, String)> = task - .env - .iter() - .filter_map(|(k, v)| match &v.0 { - Either::Left(v) => Some((k.to_string(), v.to_string())), - Either::Right(EitherIntOrBool(Either::Left(v))) => { - Some((k.to_string(), v.to_string())) - } - _ => None, - }) - .collect_vec(); - let rm_env = task - .env - .iter() - .filter(|(_, v)| v.0 == Either::Right(EitherIntOrBool(Either::Right(false)))) - .map(|(k, _)| k) - .collect::>(); - let env: EnvMap = env - .iter() - .map(|(k, v)| (k.to_string(), v.to_string())) - .chain(string_env) - .filter(|(k, _)| !rm_env.contains(k)) - .collect(); - let timer = std::time::Instant::now(); if let Some(file) = &task.file { self.exec_file(file, task, &env, &prefix)?; } else { - for (script, args) in task.render_run_scripts_with_args(self.cd.clone(), &task.args)? { + for (script, args) in + task.render_run_scripts_with_args(self.cd.clone(), &task.args, &env)? + { self.exec_script(&script, &args, task, &env, &prefix)?; } } @@ -505,18 +482,12 @@ impl Run { } } - fn exec_file( - &self, - file: &Path, - task: &Task, - env: &BTreeMap, - prefix: &str, - ) -> Result<()> { + fn exec_file(&self, file: &Path, task: &Task, env: &EnvMap, prefix: &str) -> Result<()> { let config = Config::get(); let mut env = env.clone(); let command = file.to_string_lossy().to_string(); let args = task.args.iter().cloned().collect_vec(); - let (spec, _) = task.parse_usage_spec(self.cd.clone())?; + let (spec, _) = task.parse_usage_spec(self.cd.clone(), &env)?; if !spec.cmd.args.is_empty() || !spec.cmd.flags.is_empty() { let args = once(command.clone()).chain(args.clone()).collect_vec(); let po = usage::parse(&spec, &args).map_err(|err| eyre!(err))?; diff --git a/src/cli/tasks/info.rs b/src/cli/tasks/info.rs index 6fc94ca979..f4a760fab6 100644 --- a/src/cli/tasks/info.rs +++ b/src/cli/tasks/info.rs @@ -3,6 +3,7 @@ use itertools::Itertools; use serde_json::json; use crate::config::Config; +use crate::env_diff::EnvMap; use crate::file::display_path; use crate::task::Task; use crate::ui::info; @@ -25,10 +26,12 @@ impl TasksInfo { let task = config.tasks()?.get(&self.task); if let Some(task) = task { + let ts = config.get_toolset()?; + let env = task.render_env(ts)?; if self.json { - self.display_json(task)?; + self.display_json(task, &env)?; } else { - self.display(task)?; + self.display(task, &env)?; } } else { bail!( @@ -40,7 +43,7 @@ impl TasksInfo { Ok(()) } - fn display(&self, task: &Task) -> Result<()> { + fn display(&self, task: &Task, env: &EnvMap) -> Result<()> { info::inline_section("Task", &task.name)?; if !task.aliases.is_empty() { info::inline_section("Aliases", task.aliases.join(", "))?; @@ -82,15 +85,15 @@ impl TasksInfo { if !task.env.is_empty() { info::section("Environment Variables", toml::to_string_pretty(&task.env)?)?; } - let (spec, _) = task.parse_usage_spec(None)?; + let (spec, _) = task.parse_usage_spec(None, env)?; if !spec.is_empty() { info::section("Usage Spec", &spec)?; } Ok(()) } - fn display_json(&self, task: &Task) -> Result<()> { - let (spec, _) = task.parse_usage_spec(None)?; + fn display_json(&self, task: &Task, env: &EnvMap) -> Result<()> { + let (spec, _) = task.parse_usage_spec(None, env)?; let o = json!({ "name": task.name.to_string(), "aliases": task.aliases.join(", "), diff --git a/src/cli/tasks/ls.rs b/src/cli/tasks/ls.rs index 06b6c74dc2..5d5551bc00 100644 --- a/src/cli/tasks/ls.rs +++ b/src/cli/tasks/ls.rs @@ -5,6 +5,7 @@ use itertools::Itertools; use crate::config::Config; use crate::file::{display_path, display_rel_path}; use crate::task::Task; +use crate::toolset::Toolset; use crate::ui::table::MiseTable; /// List available tasks to execute @@ -62,6 +63,7 @@ pub enum SortOrder { impl TasksLs { pub fn run(self) -> Result<()> { let config = Config::try_get()?; + let ts = config.get_toolset()?; let tasks = config .tasks()? .values() @@ -71,16 +73,16 @@ impl TasksLs { .collect::>(); if self.usage { - self.display_usage(tasks)?; + self.display_usage(ts, tasks)?; } else if self.json { - self.display_json(tasks)?; + self.display_json(ts, tasks)?; } else { - self.display(tasks)?; + self.display(ts, tasks)?; } Ok(()) } - fn display(&self, tasks: Vec) -> Result<()> { + fn display(&self, _ts: &Toolset, tasks: Vec) -> Result<()> { let mut table = MiseTable::new( self.no_header, if self.extended { @@ -95,10 +97,11 @@ impl TasksLs { table.print() } - fn display_usage(&self, tasks: Vec) -> Result<()> { + fn display_usage(&self, ts: &Toolset, tasks: Vec) -> Result<()> { let mut usage = usage::Spec::default(); for task in tasks { - let (mut task_spec, _) = task.parse_usage_spec(None)?; + let env = task.render_env(ts)?; + let (mut task_spec, _) = task.parse_usage_spec(None, &env)?; for (name, complete) in task_spec.complete { task_spec.cmd.complete.insert(name, complete); } @@ -111,7 +114,7 @@ impl TasksLs { Ok(()) } - fn display_json(&self, tasks: Vec) -> Result<()> { + fn display_json(&self, _ts: &Toolset, tasks: Vec) -> Result<()> { let array_items = tasks .into_iter() .filter(|t| self.hidden || !t.hide) diff --git a/src/config/env_directive/mod.rs b/src/config/env_directive/mod.rs index 7c7c278f93..adc98efa53 100644 --- a/src/config/env_directive/mod.rs +++ b/src/config/env_directive/mod.rs @@ -3,6 +3,7 @@ use crate::dirs; use crate::env; use crate::env_diff::EnvMap; use crate::file::display_path; +use crate::path_env::PathEnv; use crate::tera::{get_tera, tera_exec}; use eyre::{eyre, Context}; use indexmap::IndexMap; @@ -224,7 +225,12 @@ impl EnvResults { r.env_remove.insert(k); } EnvDirective::Path(input_str, _opts) => { - Self::path(&mut ctx, &mut tera, &mut r, &mut paths, source, input_str)?; + let path = Self::path(&mut ctx, &mut tera, &mut r, &source, input_str)?; + paths.push((path.clone(), source.clone())); + let env_path = env.get(&*env::PATH_KEY).cloned().unwrap_or_default().0; + let mut env_path: PathEnv = env_path.parse()?; + env_path.add(path); + env.insert(env::PATH_KEY.to_string(), (env_path.to_string(), None)); } EnvDirective::File(input, _opts) => { let files = Self::file( diff --git a/src/config/env_directive/path.rs b/src/config/env_directive/path.rs index 8fb3fd1d7a..fc734afe7b 100644 --- a/src/config/env_directive/path.rs +++ b/src/config/env_directive/path.rs @@ -1,26 +1,17 @@ use crate::config::env_directive::EnvResults; use crate::result; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; impl EnvResults { pub fn path( ctx: &mut tera::Context, tera: &mut tera::Tera, r: &mut EnvResults, - paths: &mut Vec<(PathBuf, PathBuf)>, - source: PathBuf, + source: &Path, input: String, - ) -> result::Result<()> { - // trace!("resolve: input_str: {:#?}", input_str); - // trace!( - // "resolve: normal: input: {:?}, input.to_string(): {:?}", - // &input, - // input.to_string_lossy().as_ref() - // ); - let s = r.parse_template(ctx, tera, &source, &input)?; - // trace!("resolve: s: {:?}", &s); - paths.push((s.into(), source)); - Ok(()) + ) -> result::Result { + r.parse_template(ctx, tera, source, &input) + .map(PathBuf::from) } } diff --git a/src/config/env_directive/source.rs b/src/config/env_directive/source.rs index 9a5d63631d..b812ad2717 100644 --- a/src/config/env_directive/source.rs +++ b/src/config/env_directive/source.rs @@ -20,14 +20,16 @@ impl EnvResults { ) -> Result>> { let mut out = IndexMap::new(); let s = r.parse_template(ctx, tera, source, &input)?; + let orig_path = env_vars.get(&*env::PATH_KEY).cloned().unwrap_or_default(); + let mut env_diff_opts = EnvDiffOptions::default(); + env_diff_opts.ignore_keys.shift_remove(&*env::PATH_KEY); // allow modifying PATH for p in xx::file::glob(normalize_path(config_root, s.into())).unwrap_or_default() { + if !p.exists() { + continue; + } let env = out.entry(p.clone()).or_insert_with(IndexMap::new); - let orig_path = env_vars.get(&*env::PATH_KEY).cloned().unwrap_or_default(); - let mut env_diff_opts = EnvDiffOptions::default(); - env_diff_opts.ignore_keys.shift_remove(&*env::PATH_KEY); // allow modifying PATH let env_diff = - EnvDiff::from_bash_script(&p, config_root, env_vars.clone(), env_diff_opts) - .unwrap_or_default(); + EnvDiff::from_bash_script(&p, config_root, env_vars.clone(), &env_diff_opts)?; for p in env_diff.to_patches() { match p { EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => { diff --git a/src/env_diff.rs b/src/env_diff.rs index ece50b3b6f..9744440e0d 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -66,7 +66,7 @@ impl EnvDiff { script: &Path, dir: &Path, env: T, - opts: EnvDiffOptions, + opts: &EnvDiffOptions, ) -> Result where T: IntoIterator, @@ -99,7 +99,7 @@ impl EnvDiff { match line.strip_prefix("declare -x ") { Some(line) => { let (k, v) = line.split_once('=').unwrap_or_default(); - if invalid_key(k, &opts) { + if invalid_key(k, opts) { continue; } cur_key = Some(k.to_string()); @@ -387,7 +387,8 @@ mod tests { .map(|(k, v)| (k.into(), v.into())) .collect::>(); let cwd = dirs::CWD.clone().unwrap(); - let ed = EnvDiff::from_bash_script(path.as_path(), &cwd, orig, Default::default()).unwrap(); + let ed = + EnvDiff::from_bash_script(path.as_path(), &cwd, orig, &Default::default()).unwrap(); assert_debug_snapshot!(ed); } diff --git a/src/path_env.rs b/src/path_env.rs index 248ad41e85..ec2f934837 100644 --- a/src/path_env.rs +++ b/src/path_env.rs @@ -1,11 +1,11 @@ +use crate::config::Settings; +use crate::dirs; use std::env::{join_paths, split_paths}; use std::ffi::OsString; use std::fmt; use std::fmt::{Display, Formatter}; use std::path::PathBuf; - -use crate::config::Settings; -use crate::dirs; +use std::str::FromStr; pub struct PathEnv { pre: Vec, @@ -74,6 +74,14 @@ impl FromIterator for PathEnv { } } +impl FromStr for PathEnv { + type Err = eyre::Error; + + fn from_str(s: &str) -> Result { + Ok(Self::from_iter(split_paths(s))) + } +} + #[cfg(unix)] #[cfg(test)] mod tests { diff --git a/src/task/mod.rs b/src/task/mod.rs index f2c2fe821a..9ec9798cb2 100644 --- a/src/task/mod.rs +++ b/src/task/mod.rs @@ -31,7 +31,9 @@ mod task_script_parser; pub mod task_sources; use crate::config::config_file::ConfigFile; +use crate::env_diff::EnvMap; use crate::file::display_path; +use crate::toolset::Toolset; use crate::ui::style; pub use deps::Deps; use task_dep::TaskDep; @@ -284,7 +286,11 @@ impl Task { Ok((depends, depends_post)) } - pub fn parse_usage_spec(&self, cwd: Option) -> Result<(usage::Spec, Vec)> { + pub fn parse_usage_spec( + &self, + cwd: Option, + env: &EnvMap, + ) -> Result<(usage::Spec, Vec)> { let (mut spec, scripts) = if let Some(file) = &self.file { let mut spec = usage::Spec::parse_script(file) .inspect_err(|e| debug!("failed to parse task file with usage: {e}")) @@ -292,7 +298,8 @@ impl Task { spec.cmd.name = self.name.clone(); (spec, vec![]) } else { - let (scripts, spec) = TaskScriptParser::new(cwd).parse_run_scripts(self, self.run())?; + let (scripts, spec) = + TaskScriptParser::new(cwd).parse_run_scripts(self, self.run(), env)?; (spec, scripts) }; spec.name = self.name.clone(); @@ -317,8 +324,9 @@ impl Task { &self, cwd: Option, args: &[String], + env: &EnvMap, ) -> Result)>> { - let (spec, scripts) = self.parse_usage_spec(cwd)?; + let (spec, scripts) = self.parse_usage_spec(cwd, env)?; if has_any_args_defined(&spec) { Ok( replace_template_placeholders_with_args(self, &spec, &scripts, args)? @@ -341,8 +349,9 @@ impl Task { } } - pub fn render_markdown(&self, dir: &Path) -> Result { - let (spec, _) = self.parse_usage_spec(Some(dir.to_path_buf()))?; + pub fn render_markdown(&self, ts: &Toolset, dir: &Path) -> Result { + let env = self.render_env(ts)?; + let (spec, _) = self.parse_usage_spec(Some(dir.to_path_buf()), &env)?; let ctx = usage::docs::markdown::MarkdownRenderer::new(spec) .with_replace_pre_with_code_fences(true) .with_header_level(2); @@ -443,16 +452,47 @@ impl Task { for d in &mut self.wait_for { d.render(&mut tera, &tera_ctx)?; } - for v in self.env.values_mut() { - if let EitherStringOrIntOrBool(Either::Left(s)) = v { - *s = tera.render_str(s, &tera_ctx)?; - } - } if let Some(dir) = &mut self.dir { *dir = tera.render_str(dir, &tera_ctx)?; } Ok(()) } + + pub fn render_env(&self, ts: &Toolset) -> Result { + let config = Config::get(); + let mut tera = get_tera(self.config_root.as_deref()); + let mut tera_ctx = ts.tera_ctx()?.clone(); + let mut env = ts.full_env(&config)?; + if let Some(root) = &config.project_root { + tera_ctx.insert("config_root", &root); + } + let task_env: Vec<(String, String)> = self + .env + .iter() + .filter_map(|(k, v)| match &v.0 { + Either::Left(v) => Some((k.to_string(), v.to_string())), + Either::Right(EitherIntOrBool(Either::Left(v))) => { + Some((k.to_string(), v.to_string())) + } + _ => None, + }) + .collect_vec(); + for (k, v) in task_env { + tera_ctx.insert("env", &env); + env.insert(k, tera.render_str(&v, &tera_ctx)?); + } + let rm_env = self + .env + .iter() + .filter(|(_, v)| v.0 == Either::Right(EitherIntOrBool(Either::Right(false)))) + .map(|(k, _)| k) + .collect::>(); + + Ok(env + .into_iter() + .filter(|(k, _)| !rm_env.contains(k)) + .collect()) + } } fn name_from_path(prefix: impl AsRef, path: impl AsRef) -> Result { diff --git a/src/task/task_script_parser.rs b/src/task/task_script_parser.rs index 3f26070640..426f809775 100644 --- a/src/task/task_script_parser.rs +++ b/src/task/task_script_parser.rs @@ -1,4 +1,5 @@ use crate::config::SETTINGS; +use crate::env_diff::EnvMap; use crate::exit::exit; use crate::shell::ShellType; use crate::task::Task; @@ -29,6 +30,7 @@ impl TaskScriptParser { &self, task: &Task, scripts: &[String], + env: &EnvMap, ) -> Result<(Vec, usage::Spec)> { let mut tera = self.get_tera(); let arg_order = Arc::new(Mutex::new(HashMap::new())); @@ -272,10 +274,11 @@ impl TaskScriptParser { } } }); - let ctx = task.tera_ctx()?; + let mut tera_ctx = task.tera_ctx()?; + tera_ctx.insert("env", &env); let scripts = scripts .iter() - .map(|s| tera.render_str(s.trim(), &ctx).unwrap()) + .map(|s| tera.render_str(s.trim(), &tera_ctx).unwrap()) .collect(); let mut cmd = usage::SpecCommand::default(); // TODO: ensure no gaps in args, e.g.: 1,2,3,4,5 @@ -382,7 +385,9 @@ 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(&task, &scripts).unwrap(); + let (scripts, spec) = parser + .parse_run_scripts(&task, &scripts, &Default::default()) + .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"); @@ -401,7 +406,9 @@ mod tests { "echo {{ arg(name='foo') }}; echo {{ arg(name='bar') }}; echo {{ arg(name='foo') }}" .to_string(), ]; - let (scripts, spec) = parser.parse_run_scripts(&task, &scripts).unwrap(); + let (scripts, spec) = parser + .parse_run_scripts(&task, &scripts, &Default::default()) + .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(); @@ -424,7 +431,9 @@ 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(&task, &scripts).unwrap(); + let (scripts, spec) = parser + .parse_run_scripts(&task, &scripts, &Default::default()) + .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"); @@ -444,7 +453,9 @@ 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(&task, &scripts).unwrap(); + let (scripts, spec) = parser + .parse_run_scripts(&task, &scripts, &Default::default()) + .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"); @@ -460,7 +471,9 @@ 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(&task, &scripts).unwrap(); + let (scripts, spec) = parser + .parse_run_scripts(&task, &scripts, &Default::default()) + .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"); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 4bf9309cb6..326b18b9fd 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -532,7 +532,10 @@ impl Toolset { let mut tera_env = env::PRISTINE_ENV.clone().into_iter().collect::(); tera_env.extend(env.clone()); let mut path_env = PathEnv::from_iter(env::PATH.clone()); - for p in self.list_paths().into_iter() { + for p in self.list_paths() { + path_env.add(p); + } + for p in config.path_dirs()?.clone() { path_env.add(p); } tera_env.insert(PATH_KEY.to_string(), path_env.to_string());