From 5ac98c020df2cea79a1f41e6b22ad9a24d41cf90 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Sat, 8 Jun 2024 18:17:55 -0700 Subject: [PATCH] Add `is_dependency()` function (#2139) --- README.md | 6 ++++++ src/evaluator.rs | 9 +++++++-- src/function.rs | 5 +++++ src/justfile.rs | 12 +++++++----- src/recipe.rs | 3 ++- tests/functions.rs | 23 +++++++++++++++++++++++ 6 files changed, 50 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9efa80a..040639f 100644 --- a/README.md +++ b/README.md @@ -1426,6 +1426,12 @@ $ just - `env(key)`1.15.0 — Alias for `env_var(key)`. - `env(key, default)`1.15.0 — Alias for `env_var_or_default(key, default)`. +#### Invocation Information + +- `is_dependency()` - Returns the string `true` if the current recipe is being + run as a dependency of another recipe, rather than being run directly, + otherwise returns the string `false`. + #### Invocation Directory - `invocation_directory()` - Retrieves the absolute path to the current diff --git a/src/evaluator.rs b/src/evaluator.rs index ba33677..82260b8 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -3,6 +3,7 @@ use super::*; pub(crate) struct Evaluator<'src: 'run, 'run> { pub(crate) assignments: Option<&'run Table<'src, Assignment<'src>>>, pub(crate) context: ExecutionContext<'src, 'run>, + pub(crate) is_dependency: bool, pub(crate) scope: Scope<'src, 'run>, } @@ -49,6 +50,7 @@ impl<'src, 'run> Evaluator<'src, 'run> { context, assignments: Some(&module.assignments), scope, + is_dependency: false, }; for assignment in module.assignments.values() { @@ -280,10 +282,11 @@ impl<'src, 'run> Evaluator<'src, 'run> { pub(crate) fn evaluate_parameters( context: &ExecutionContext<'src, 'run>, + is_dependency: bool, arguments: &[String], parameters: &[Parameter<'src>], ) -> RunResult<'src, (Scope<'src, 'run>, Vec)> { - let mut evaluator = Self::new(context, context.scope); + let mut evaluator = Self::new(context, is_dependency, context.scope); let mut positional = Vec::new(); @@ -324,11 +327,13 @@ impl<'src, 'run> Evaluator<'src, 'run> { pub(crate) fn new( context: &ExecutionContext<'src, 'run>, + is_dependency: bool, scope: &'run Scope<'src, 'run>, ) -> Self { Self { - context: *context, assignments: None, + context: *context, + is_dependency, scope: scope.child(), } } diff --git a/src/function.rs b/src/function.rs index d44bbb5..206faf8 100644 --- a/src/function.rs +++ b/src/function.rs @@ -59,6 +59,7 @@ pub(crate) fn get(name: &str) -> Option { "home_directory" => Nullary(|_| dir("home", dirs::home_dir)), "invocation_directory" => Nullary(invocation_directory), "invocation_directory_native" => Nullary(invocation_directory_native), + "is_dependency" => Nullary(is_dependency), "join" => BinaryPlus(join), "just_executable" => Nullary(just_executable), "just_pid" => Nullary(just_pid), @@ -341,6 +342,10 @@ fn invocation_directory_native(context: Context) -> Result { }) } +fn is_dependency(context: Context) -> Result { + Ok(context.evaluator.is_dependency.to_string()) +} + fn prepend(_context: Context, prefix: &str, s: &str) -> Result { Ok( s.split_whitespace() diff --git a/src/justfile.rs b/src/justfile.rs index be5d5f8..5b3f0bf 100644 --- a/src/justfile.rs +++ b/src/justfile.rs @@ -257,6 +257,7 @@ impl<'src> Justfile<'src> { &context, &mut ran, invocation.recipe, + false, )?; } @@ -385,6 +386,7 @@ impl<'src> Justfile<'src> { context: &ExecutionContext<'src, '_>, ran: &mut Ran<'src>, recipe: &Recipe<'src>, + is_dependency: bool, ) -> RunResult<'src> { if ran.has_run(&recipe.namepath, arguments) { return Ok(()); @@ -397,11 +399,11 @@ impl<'src> Justfile<'src> { } let (outer, positional) = - Evaluator::evaluate_parameters(context, arguments, &recipe.parameters)?; + Evaluator::evaluate_parameters(context, is_dependency, arguments, &recipe.parameters)?; let scope = outer.child(); - let mut evaluator = Evaluator::new(context, &scope); + let mut evaluator = Evaluator::new(context, true, &scope); if !context.config.no_dependencies { for Dependency { recipe, arguments } in recipe.dependencies.iter().take(recipe.priors) { @@ -410,11 +412,11 @@ impl<'src> Justfile<'src> { .map(|argument| evaluator.evaluate_expression(argument)) .collect::>>()?; - Self::run_recipe(&arguments, context, ran, recipe)?; + Self::run_recipe(&arguments, context, ran, recipe, true)?; } } - recipe.run(context, &scope, &positional)?; + recipe.run(context, &scope, &positional, is_dependency)?; if !context.config.no_dependencies { let mut ran = Ran::default(); @@ -426,7 +428,7 @@ impl<'src> Justfile<'src> { evaluated.push(evaluator.evaluate_expression(argument)?); } - Self::run_recipe(&evaluated, context, &mut ran, recipe)?; + Self::run_recipe(&evaluated, context, &mut ran, recipe, true)?; } } diff --git a/src/recipe.rs b/src/recipe.rs index ac06839..13b3bb9 100644 --- a/src/recipe.rs +++ b/src/recipe.rs @@ -149,6 +149,7 @@ impl<'src, D> Recipe<'src, D> { context: &ExecutionContext<'src, 'run>, scope: &Scope<'src, 'run>, positional: &[String], + is_dependency: bool, ) -> RunResult<'src, ()> { let config = &context.config; @@ -162,7 +163,7 @@ impl<'src, D> Recipe<'src, D> { ); } - let evaluator = Evaluator::new(context, scope); + let evaluator = Evaluator::new(context, is_dependency, scope); if self.shebang { self.run_shebang(context, scope, positional, config, evaluator) diff --git a/tests/functions.rs b/tests/functions.rs index caf772c..bfb05f2 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -1027,3 +1027,26 @@ import ) .run(); } + +#[test] +fn is_dependency() { + let justfile = " + alpha: beta + @echo 'alpha {{is_dependency()}}' + beta: && gamma + @echo 'beta {{is_dependency()}}' + gamma: + @echo 'gamma {{is_dependency()}}' + "; + Test::new() + .args(["alpha"]) + .justfile(justfile) + .stdout("beta true\ngamma true\nalpha false\n") + .run(); + + Test::new() + .args(["beta"]) + .justfile(justfile) + .stdout("beta false\ngamma true\n") + .run(); +}