just icon indicating copy to clipboard operation
just copied to clipboard

Sharing `just` arguments between invocations

Open poliorcetics opened this issue 1 year ago • 11 comments

In a previous version --command-color was added to allow coloring the command that is run in the stdout output. This works well but it not transferred to inner calls to just:

inner arg:
    just something {{ arg }}

something arg:
    echo {{ arg }}
just --color-command red inner "I am a teapot"
just something "I am a teapot" # <--- colored red
echo "I am a teapot"           # <--- not colored red
I am a teapot

Looking at the manual, this is not something that is easily done right now. It can also cause problems with --yes: top level recipes will be automatically confirmed but not inner ones

I see at leastfour possible solutions:

  1. Allow configuring just through individual env vars: e.g, JUST_CONFIRM="yes" or JUST_COMMAND_COLOR="red" which would be automatically read
  2. Allow configuring just through a single env vars: JUST_EXTRA_ARGS="--yes --command-color red" which would be automatically read
  3. Add a function to inherit args in inner commands: just just_args() something ... in the recipe above
  4. Add a setting to inherit args in inner commands: set inherit-just-args := true

I'm unsure which is the best. The env vars solutions will make it easy to share arguments, for example in CI scripts but could be surprising (maybe a log at the start, saying "using ... from env" ?). It's already something done by lots of programs though, so I don't think that's too bad.

Solutions 3 and 4 have the issue that they need to be set in each Justfile to work, which will be frustrating when adding a new one in a subdirectory for example. Solution 3 especially needs to be set on each invocation, which is quite invasive but offers lots of control.

poliorcetics avatar Jan 09 '24 08:01 poliorcetics

  1. Allow configuring just through individual env vars: e.g, JUST_CONFIRM="yes" or JUST_COMMAND_COLOR="red" which would be automatically read

+1 to this approach and it'd be consistent with existing behavior.

In the case of --command-color, if it would also set the hypothetical JUST_COMMAND_COLOR env var, this would solve https://github.com/casey/just/issues/1702 as a side effect. Given the rationale why --command-color was added, it anyway seems wise to have --command-color inherited by default.

laniakea64 avatar Jan 09 '24 14:01 laniakea64

Oh I didn't know about JUST_UNSTABLE, that is certainly a good point for solution 1, thanks!

poliorcetics avatar Jan 09 '24 15:01 poliorcetics

I think that some combination of environment variables, and a setting, might be a good approach here. Automatically exporting and inheriting arguments would break backwards compatibility, so a setting would be necessary so that users can opt-in on a per-justfile basis. For example, if users used just --yes on the parent invocation, changing child invocations to behave as if --yes was set would be a change in behavior.

So, if something like set inherit were used, just would automatically export some subset of environment variables, and then child just processes would read them. The setting could be in parent justfiles, with something like set export-args, or in children, with something like set inherit-args.

This setting can be initially made unstable, so that we can tweak which settings are exported. I suspect that there might be some tricky edge cases.

I think that something like --yes or --quiet would be good to start with. The environment variable names should match the argument names, so for --yes, the environment variable would be called JUST_YES, and any value other than the empty string would be interpreted as true.

casey avatar Jan 09 '24 18:01 casey

I labeled this as a good first issue, in case anyone wants to take a crack at it.

casey avatar Jan 09 '24 18:01 casey

I'm starting to take a look at this and I have a question: should the setting be "global" set export-args-as-env := true or precise set-export-args-as-env := ["JUST_YES", "JUST_COLOR"] ? Or both maybe ?

poliorcetics avatar Feb 01 '24 23:02 poliorcetics

or precise set-export-args-as-env := ["JUST_YES", "JUST_COLOR"] ?

:+1: Nice idea. +1 for the precise proposal. This syntax is intrinsically backwards-compatible with future additions to exported/exportable arguments, and it provides more functionality for justfile authors.

I think naming the setting export-args as casey proposed above would be equally clear while also being more concise.

laniakea64 avatar Feb 04 '24 01:02 laniakea64

I like the idea of explicitly specifying what you want to export. There's already a set export, so another name is probably better. And there are things other than args, like settings, which we want to export, so export-args isn't great.

casey avatar Feb 11 '24 20:02 casey

An idea that might dovetail with this:

Add a function just() which is sugar for (just_executable() + ' --justfile ' + justfile() + ' ' + just_options() + ' -- ')

where just_options() returns the options passed in to the current invocation.

Then I can recurse with

recurse:
    {{ just() }} recurse

while ensuring that

  • No PATH change in the shell stopped me from invoking the binary, or invoked a different version
  • An override of the working directory is preserved
  • Any other non-recipe args are preserved, including --set overrides.

Having written this out, I realize it sounds a lot like $(MAKE) and $(MAKEFLAGS), with the confusion that entails. But it may be an alternative to forwarding options through the environment.

starthal avatar Feb 16 '24 21:02 starthal

That's another option but it has a problem: in a CI environment, it's easier to export JUST_YES=1; export JUST_COLOR=always and all present and future just calls will work on the first try as expected, whereas the {{ just() }} option means each new just call in the CI needs the arguments copied, which I don't think is nice to use

It's the same for local use too, I would like to be able to set JUST_COLOR and never have to worry about it again for normal use

poliorcetics avatar Feb 17 '24 18:02 poliorcetics

An idea that might dovetail with this:

Add a function just() which is sugar for (just_executable() + ' --justfile ' + justfile() + ' ' + just_options() + ' -- ')

where just_options() returns the options passed in to the current invocation.

Although that could be useful, it is not a good "alternative" to environment variables. In addition to what @poliorcetics said, it would be harder for recipes to use the options for something other than passing to recursive just invocations. Also, with the way just currently works, this function might be problematic where justfile() or just_executable() contain whitespace.

laniakea64 avatar Feb 21 '24 17:02 laniakea64

Another possible approach:

Export all variables to a single JUST_VARIABLES in some structural format (maybe JSON, it can be serialized or deserialized almost anywhere).

Provide a function var(<name>, <default>), which behaves like env(...), except that it reads from JUST_VARIABLES.

In justfile, when set inherit (or perhaps set export-variables):

  1. If JUST_VARIABLES is not set, export all variables to JUST_VARIABLES;
  2. Otherwise, update them.

Edit: We can also export each variable to different variables, like JUST_VARIABLE_foo, this should be more convenient to check or override. But this can create a lot of env variables.

loichyan avatar Jul 30 '24 10:07 loichyan