use std::path::{Path, PathBuf};
use crate::resolver::ResolutionOverrides;
use crate::tool;
use crate::types::{ProjectContext, TaskSource};
pub(crate) fn select_task_entry<'a>(
ctx: &ProjectContext,
overrides: &ResolutionOverrides,
found: &[&'a crate::types::Task],
) -> &'a crate::types::Task {
found
.iter()
.min_by_key(|task| {
(
source_priority(overrides, task.source),
source_depth(ctx, task.source),
task.source.display_order(),
task.alias_of.is_some(),
)
})
.copied()
.expect("task selection should have at least one match")
}
pub(crate) fn source_priority(overrides: &ResolutionOverrides, source: TaskSource) -> u16 {
let default_tier: u16 = match source {
TaskSource::TurboJson => 0,
TaskSource::PackageJson => 1,
_ => 2,
};
if overrides.prefer_runners.is_empty() {
return default_tier;
}
if let Some(idx) = overrides
.prefer_runners
.iter()
.position(|r| r.task_source() == Some(source))
{
return u16::try_from(idx).unwrap_or(u16::MAX);
}
u16::try_from(overrides.prefer_runners.len()).unwrap_or(u16::MAX) + default_tier
}
pub(crate) fn source_depth(ctx: &ProjectContext, source: TaskSource) -> usize {
source_dir(source, &ctx.root)
.and_then(|dir| {
ctx.root
.ancestors()
.position(|ancestor| ancestor == dir.as_path())
.or_else(|| {
dir.starts_with(&ctx.root).then_some(0)
})
})
.unwrap_or(usize::MAX)
}
fn source_dir(source: TaskSource, root: &Path) -> Option<PathBuf> {
let path = match source {
TaskSource::PackageJson => tool::node::find_manifest_upwards(root),
TaskSource::DenoJson => tool::deno::find_config_upwards(root),
TaskSource::CargoAliases => tool::cargo_aliases::find_anchor(root),
TaskSource::GoPackage => tool::go_pm::find_file(root),
TaskSource::TurboJson => tool::files::find_first_upwards(root, tool::turbo::FILENAMES),
TaskSource::Makefile => tool::files::find_first_upwards(root, tool::make::FILENAMES),
TaskSource::Justfile => tool::just::find_file(root),
TaskSource::Taskfile => tool::files::find_first_upwards(root, tool::go_task::FILENAMES),
TaskSource::BaconToml => tool::files::find_first_upwards(root, tool::bacon::FILENAMES),
TaskSource::MiseToml => tool::files::find_first_upwards(root, tool::mise::FILENAMES),
};
path.and_then(|path| path.parent().map(Path::to_path_buf))
}