Skip to content
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
7 changes: 5 additions & 2 deletions docs/tasks/running-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <task>`, `mise run <task>`, `mise r <task>`, or just `mise <task>`—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
Expand Down
43 changes: 43 additions & 0 deletions e2e/env/test_env_template
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,46 @@ A = "a"
B = "{{ env.A }}"
EOF
assert "mise env -s bash | grep B" "export B=a"

cat <<EOF >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 <<EOF >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 <<EOF >mise.toml
[env]
FOO = "/foo"
_.source = { path = "env.sh", tools = true }
_.path = "{{ env.FOO }}"
EOF
cat <<EOF >env.sh
#!/usr/bin/env bash
export BAR="\$PATH"
EOF
assert_contains "mise env -s bash | grep BAR" "export BAR='/foo:"
2 changes: 1 addition & 1 deletion src/backend/asdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
8 changes: 5 additions & 3 deletions src/cli/generate/task_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand Down
45 changes: 8 additions & 37 deletions src/cli/run.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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};
Expand All @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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::<HashSet<_>>();
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)?;
}
}
Expand Down Expand Up @@ -505,18 +482,12 @@ impl Run {
}
}

fn exec_file(
&self,
file: &Path,
task: &Task,
env: &BTreeMap<String, String>,
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))?;
Expand Down
15 changes: 9 additions & 6 deletions src/cli/tasks/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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!(
Expand All @@ -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(", "))?;
Expand Down Expand Up @@ -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(", "),
Expand Down
17 changes: 10 additions & 7 deletions src/cli/tasks/ls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand All @@ -71,16 +73,16 @@ impl TasksLs {
.collect::<Vec<Task>>();

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<Task>) -> Result<()> {
fn display(&self, _ts: &Toolset, tasks: Vec<Task>) -> Result<()> {
let mut table = MiseTable::new(
self.no_header,
if self.extended {
Expand All @@ -95,10 +97,11 @@ impl TasksLs {
table.print()
}

fn display_usage(&self, tasks: Vec<Task>) -> Result<()> {
fn display_usage(&self, ts: &Toolset, tasks: Vec<Task>) -> 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);
}
Expand All @@ -111,7 +114,7 @@ impl TasksLs {
Ok(())
}

fn display_json(&self, tasks: Vec<Task>) -> Result<()> {
fn display_json(&self, _ts: &Toolset, tasks: Vec<Task>) -> Result<()> {
let array_items = tasks
.into_iter()
.filter(|t| self.hidden || !t.hide)
Expand Down
8 changes: 7 additions & 1 deletion src/config/env_directive/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand Down
19 changes: 5 additions & 14 deletions src/config/env_directive/path.rs
Original file line number Diff line number Diff line change
@@ -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<PathBuf> {
r.parse_template(ctx, tera, source, &input)
.map(PathBuf::from)
}
}

Expand Down
12 changes: 7 additions & 5 deletions src/config/env_directive/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ impl EnvResults {
) -> Result<IndexMap<PathBuf, IndexMap<String, String>>> {
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) => {
Expand Down
Loading
Loading