Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modules stabilization tracking issue #929

Closed
5 tasks done
casey opened this issue Jul 29, 2021 · 45 comments
Closed
5 tasks done

Modules stabilization tracking issue #929

casey opened this issue Jul 29, 2021 · 45 comments

Comments

@casey
Copy link
Owner

casey commented Jul 29, 2021

This issue tracks stabilization of mod statements.

There are a bunch of features which aren't yet implemented, but I think they can all be implemented in a backwards compatible fashion:

  • Recipes defined in one module can be called from another
  • Variables defined in one module can be referenced from another
  • Allow inline modules that are declared and defined in a single file.
  • Allow submodules to opt-in to using parent module settings
  • Allow submodules to opt-in to loading .env files
  • Variables defined in a submodule should be overridable on the command line #2119
  • Make non-compilation errors refer to modules source file
  • Make just --show work with modules

I want the feature to be well used and well tested before stabilizing it.

@matthewtgilbride
Copy link

Hi @casey, curious if this project is inspired to any extent by mmake? For me, the most painful thing that traditional make lacks is support for remote includes.

For example, we have built out a set of common makefiles at my job for common projects (e.g. ExpressJS/Node apps, Spring Boot apps, AWS Lambda with SAM CLI, etc.). We also have a core makefile that exports handy commands to print messages in certain colors, require certain environment variables, etc.

The most annoying part of this setup is that we have to ask people to copy/paste files into their repos. We even have an update-makefiles command so that once they do so, they can consume updates without friction.

I just wanted to throw this out there. I know there is a lot of thought being put into a module system in general, but allowing for remote modules would be awesome.

Thanks for all the hard work on a really cool tool :)

@casey
Copy link
Owner Author

casey commented Oct 28, 2021

Hi @casey, curious if this project is inspired to any extent by mmake?

I didn't know about mmake but it seems to be in a similar vein, although just pre-dates it by a couple years. In fact, just also used to be a wrapper-script around make. I've been meaning to add a list of alternative command runners to the readme for a while, so I just opened #1008 which mentions mmake.

For me, the most painful thing that traditional make lacks is support for remote includes.

That's a super interesting feature. We don't have modules, but if we ever do, I wouldn't be opposed to adding something like that.

For example, we have built out a set of common makefiles at my job for common projects (e.g. ExpressJS/Node apps, Spring Boot apps, AWS Lambda with SAM CLI, etc.). We also have a core makefile that exports handy commands to print messages in certain colors, require certain environment variables, etc.

Interesting, that does seem very useful.

I just wanted to throw this out there. I know there is a lot of thought being put into a module system in general, but allowing for remote modules would be awesome.

Feel free to open an issue about remote modules, why they're cool, how you use them. It's something that won't get implemented for a long time, but having an issue for it would probably be good.

Thanks for all the hard work on a really cool tool :)

You are most welcome! It is good to be of service 🙌

@lorengordon
Copy link

Found this issue also hoping it was talking about remote includes. We currently use make, and rely heavily on a centralized makefile. It's distributed using an include line that uses a shell command to invoke curl:

include $(shell test -f .common.mk || curl -sSL -o .common.mk http://url/to/common.mk; echo .common.mk)

Works pretty well, but some of the frustrations around make have us always looking for alternatives. Which is how I found just, and now I am evaluating whether it will work for us...

@dionjwa
Copy link

dionjwa commented Mar 16, 2022

I would also jump in with support for remote modules.

One of the hardest things about working with cloud infrastructure and deploying applications is the need for sharing and reusing.

Wanting to reuse all these great just commands I've written in one repository are not easily transferred to another repository.

I feel like deno has solved this problem (URL imports, versioned, immutable repos), and aim to write all my future cloud related coordination and scripting.

But it doesn't get around not being able to re-use just commands where I really want them.

I think this tool really appeals to those who pipeline software.

@stereobutter
Copy link

stereobutter commented Apr 20, 2022

I'd love to have something analogous to url imports in dhall for importing modules in just. A simple solution without caching or checksums would be enough for my needs. I'd likely use commit hashs/tags for versioning and whether or not a 50ms http request is cached or not doesn't matter to me.

Fetching from private repos is probably a more important feature and requires some though in the general case, for github nothing special is required as one can just put the personal access token in the url.

Importing from public repo:

keybase := import https://raw.githubusercontent.com/casey/just/v0.9.4/examples/keybase.just 

Importing from private repo

foo := import https://{{TOKEN}}@raw.githubusercontent.com/some_org/some_private_repo/v0.1/foo.just 

where TOKEN is either supplied via the command line or via environment variable.

@Splines
Copy link

Splines commented Dec 28, 2023

Thanks a lot for the new module system in v1.19.0 🔥

It'd be amazing to have the following feature (you already envisioned) in subsequent releases:

Allow specifying the path to the module source file, so a module justfile can be anywhere.

This is since I'd like to have one commands/ folder where I put in all my submodule .justfiles, e.g. docker.justfile, test.justfile etc. and have one project root .justfile. Having to create a new folder for every of them only clutters the workspace. I feel like how you have your project structured in folders does not necessarily correlate to how you want your commands to be modularized.

Here is the way I achieved this behavior so far.

@casey
Copy link
Owner Author

casey commented Dec 28, 2023

@Splines It is done! Added in #1786. You can now give a path by putting a string after the module name:

mod docker 'commands/docker.justfile'

It should make it into the next release.

@Splines
Copy link

Splines commented Dec 28, 2023

@casey Wow, that was quick! Very greateful ❤

@MadBomber
Copy link

Thank you @casey for hanging in there on the import and module features!

@laniakea64
Copy link
Contributor

Nice, this looks like it could be an elegant replacement for justfile recipes such as

[no-exit-message]
foo +args:
  {{quote(just_executable())}} -f some_repo/foo/justfile {{args}}

the purpose of which is to run just foo recipe to run a repository's just recipes with some local custom environment settings.

But in testing out replacing this recipe with mod foo 'some_repo/foo/justfile', came across a couple points that block this usage:

  1. The main place I have such recipe is in a justfile that manages temporary clones of a couple repos. So the repo that contains the justfile I would use as module does not always exist. Currently this state causes error: Failed to read justfile that prevents running any recipes. Could there please be a way for "module only if specified file exists", i.e. if the module file is not found at the specified path, the justfile doesn't error out but the module/subcommands simply doesn't work?

  2. The documentation of this feature says -

justfile() and justfile_directory() always return the path to the root
justfile and the directory that contains it, even when called from submodule
recipes.

This behavior means that justfiles with recipes that do just -f {{justfile()}} cannot be both usable standalone and usable as modules. Is there a way to get the full path of a justfile regardless of whether it's invoked directly or used as a module?

@WladyX
Copy link

WladyX commented Dec 29, 2023

Hey @casey, thank you so much for just and for this update, quick question, do you plan, or maybe it's already possible and i've missed it to include modules from git repos, like @stereobutter initially mentioned, i would love that.

@casey
Copy link
Owner Author

casey commented Dec 29, 2023

@WladyX Do you mean including modules from a local git repo, or a remote git repo?

@WladyX
Copy link

WladyX commented Dec 29, 2023

Yes, exactly.

@casey
Copy link
Owner Author

casey commented Dec 29, 2023

@WladyX Sorry, to be clear, do you want to load modules from a file in a local git repo, e.g., one that's on the same computer that just is running on, or a remote repo, like one on GitHub?

@WladyX
Copy link

WladyX commented Dec 29, 2023

no worries Casey!
I would like to be able to import a module from a private gitlab instance.
My master plan is to a have repo with just modules and import the modules i want to any repo/folder i need.
eg:

  • repo1 (aka just-modules) with modules foo1, foo2
  • repo2 (aka myrepo) with bar that imports foo1 from repo1.mydomain.com

ideally i want to be able to make templates and by using variables to adapt them to each repo.
so when i update a template(module) i update it for every repo using it.

does that make sense?

@casey
Copy link
Owner Author

casey commented Dec 29, 2023

I created #1799 to discuss remote imports.

@BCNelson
Copy link

BCNelson commented Feb 13, 2024

I'm finding it to be off putting that the functions justfile() and justfile_directory() change behavior when in a modules file. I would expect that they always return the current file. Is this what module() and module_directory() are going to be used for?

Edit: I missed #929 (comment) already talking about this but just wanted to echo that is it causing me some grief as well.

@crdx
Copy link
Contributor

crdx commented May 26, 2024

@casey

From #1202 (comment):

I want to give a final call for testing and feedback for the modules feature. All bugs I know of have been fixed

Would you consider #1866 to be a bug related to modules?

@casey
Copy link
Owner Author

casey commented May 26, 2024

@crdx It's definitely a bug related to modules, although it can be fixed in a backwards-compatible way, so it isn't a stabilization blocker.

@gl-yziquel
Copy link
Contributor

gl-yziquel commented May 26, 2024

On my end, while impressed with the subcommand features implemented with modules and submodules, I am not really satisfied with the listing of the subcommands in modules and submodules.

I find it too verbose and too nested.

What I would expect, as it fits my taste, would be short lines for commands, and not showing the subcommands. So, I'd suggest, as an additional feature, a directive [no-unfold] or [fold-listing] (perhaps with a max nested level) that would only give the command giving access to subcommands, but not the nested subcommands themselves.

This way, I have the freedom to implement a help command in toplevel that would allow to invoke the listing of subcommands of a command and only that. Like just help my_command would get the listing of subcommands of my_command.

Working in small tmuxed fractions of screen over ssh, having a long, nested, list of commands, subcommands of commands, subcommands of subcommands of commands... not that good an idea.

@valscion
Copy link

valscion commented May 27, 2024

I concur @gl-yziquel — here's a side-by-side comparison of the old behavior and one of the old-style way we have done since 2019 #208 (comment) and have since made way bigger:

image image image

And now I can't list the admin tasks with just --unstable admin -l or any such combination — I don't know if I'm doing something wrong or is it impossible with modules to first only show the top-level modules and then dive deeper like before.

The way we've made our just scripts discoverable and how we've taught that here is that we've told developers to first run just — then take a guess which "namespace" the thing you probably want belongs to, e.g. "start", and then run just start — and then pick the command which one thinks is correct. Here's an example of how one could figure out how to start a device simulator of any kind:

  1. just
  2. Oh, it might be "devices" — let's try it: just devices
  3. Ok cool, I'm interested in IE11 testing — just devices ie11
  4. Ok now I know what to call
image

Again, I don't know if this behavior is reproducible with modules or not. But this is a crucial aspect for us to keep the scripts both maintainable and discoverable at the same time.''

The way we've made e.g. just devices work is that by convention, all of our Justfiles have their first script be help that only lists the available recipes in there:

image

I'd go as far as suggest the help behavior as in my example above should be the default and that showing the scripts inside modules should be an opt-in feature rather than having to supply something like [no-unfold] or [fold-listing] directives everywhere.

@valscion
Copy link

Also, spotted that using just --list --list-prefix "some prefix" with the modules prints out the "some prefix" list prefix double for modules. That looks like a bug — but I've never tested out list-prefix earlier. (I'm using just version 1.27.0 in all my screenshots here)

image

@casey
Copy link
Owner Author

casey commented May 29, 2024

@BCNelson There are a bunch of new functions for getting paths. justfile() and justfile_directory() always return the path to the root justfile. source_file() and source_directory() return the path to the current file, regardless of whether it's a module or a import. module_file() and module_directory() will return the path to the current module. So inside an import, source_file() will return the path to the import file, and module_file() will return the path to the module that contains it. Note that module_file() and module_directory() are still unreleased.

@casey
Copy link
Owner Author

casey commented May 29, 2024

@stuartellis and @foresterre Referring to parent and submodule recipes in aliases and dependencies is planned, but not for initial stabilization, since it can be added in a backwards-compatible way.

@casey
Copy link
Owner Author

casey commented May 29, 2024

@gl-yziquel and @valscion Thanks so much for the feedback! I'm not a heavy user of modules (in fact, I don't think I've ever actually used one in my own justfiles 😅) so feedback is very helpful.

To sum up:

  1. the default display of submodule recipes is too verbose and nested
  2. just --list should accept a submodule path, so you can do just --list SUBMODULE and it should behave as if you were doing just --justfile SUBMODULE --list
  3. it should be possible to iteratively descend into a tree of modules with --list, so you can do just --list, see stuff, then do just --list SUBMODULE to see things in that submodule, etc

--list-prefix is working as intended. --list-prefix, by default, is four spaces, and you can use --list-prefix to change indentation.

--list output is human readable, not machine readable, so it isn't subject to backwards compatible guarantees, i.e., we can stabilize modules, but still change --list output in the future. That being said, I'd like to get it into a reasonable state before stabilizing modules.

@casey
Copy link
Owner Author

casey commented May 29, 2024

I opened #2107 to track improving --list output with modules.

@foresterre
Copy link

foresterre commented May 29, 2024

Something else I noticed, is that using the interactive chooser, e.g. @just --choose --unstable doesn't list anything from the modules (I expected it to).

output of @just --choose --unstable

I figured, if supplied with the module name like @just --choose --unstable dav1d it would show a list from the module, similar to how running just --unstable dav1d would execute the default script in the module dav1d.

output of @just --choose --unstable dav1d

a 'just' script which calls some just modules

@casey
Copy link
Owner Author

casey commented May 29, 2024

@foresterre I wasn't actually able to reproduce this, but I opened #2110 to track it. If you could provide a repro there that would be great.

@casey
Copy link
Owner Author

casey commented May 30, 2024

I just merged #2107, so --list no longer displays recipes in submodules, but instead displays MODULE ....

As far as I know, there are no current blockers to stabilization. There are a lot of features that I want to add later, but they can be added in a backwards compatible way, so they don't block stabilization.

My current plan is to stabilize modules on July 1st, so testing and feedback are much appreciated!

@valscion
Copy link

valscion commented Jun 27, 2024

TL:DR;

  • I found no blockers
  • Code changes are fairly trivial when converting to submodules
    • ...but some "old style" of using submodules might be missed when doing first pass of converting "old style" to built-in modules
  • Error messages for errors coming from a submodule don't explain that the problem is in the submodule's Justfile instead of root Justfile
  • just --show submodule did not work (but maybe that's OK? A bit surprising, though)

I've tested out the different ways we use submodules and couldn't come up with an example where the submodules wouldn't have worked.

I really like how the end result in #2113 felt like!

We do have to do a few changes to how we have our modules created but the changes are quite straightforward — the biggest one being that we have to change how our default help modules are defined as they no longer need to remember what "submodule" they're under — and it's a good thing!

For some cases where we've called to recipes defined in other submodules, I think we'll use --justfile pointing to the root Justfile so we can call the other submodules like we would've been calling them from the get-go.

Here's a few of the changes we'd need to do, with one invocation of just deps now needed to be changed to show that as an example:

git diff details

diff --git a/Justfile b/Justfile
--- a/Justfile
+++ b/Justfile
@@ -7,34 +7,21 @@ help:
 
-admin +args='help':
-  #!/usr/bin/env bash
-  just --working-directory `pwd` --justfile tasks/admin/Justfile $(cat <<EOF;
-  {{args}}
-  EOF)
+mod admin 'tasks/admin/Justfile'
 
-assets +args='help':
-  @just --working-directory `pwd` --justfile tasks/assets/Justfile {{ args }}
+mod assets 'tasks/assets/Justfile'
 
-aws +args='help':
-  @just --working-directory `pwd` --justfile tasks/aws/Justfile {{ args }}
+mod aws 'tasks/aws/Justfile'
 
-clean +args='help':
-  @just --working-directory `pwd` --justfile tasks/clean/Justfile {{ args }}
+mod clean 'tasks/clean/Justfile'
 
-csv +args='help':
-  @just --working-directory `pwd` --justfile tasks/csv/Justfile {{ args }}
+mod csv 'tasks/csv/Justfile'
 
-deps +args='help':
-  @just --working-directory `pwd` --justfile tasks/deps/Justfile {{ args }}
+mod deps 'tasks/deps/Justfile'
 
-devices +args='help':
-  @just --working-directory `pwd` --justfile tasks/devices/Justfile {{ args }}
+mod devices 'tasks/devices/Justfile'
 
-docker +args='help':
-  @just --working-directory `pwd` --justfile tasks/docker/Justfile {{ args }}
+mod docker 'tasks/docker/Justfile'
 
-docs +args='help':
-  @just --working-directory `pwd` --justfile tasks/docs/Justfile {{ args }}
+mod docs 'tasks/docs/Justfile'
 
-elasticsearch +args='help':
-  @just --working-directory `pwd` --justfile tasks/elasticsearch/Justfile {{ args }}
+mod elasticsearch 'tasks/elasticsearch/Justfile'
 
@@ -44,16 +31,11 @@ elasticsearch +args='help':
 
-mixpanel +args='help':
-  @just --working-directory `pwd` --justfile tasks/mixpanel/Justfile {{ args }}
+mod mixpanel 'tasks/mixpanel/Justfile'
 
-start +args='help':
-  @just --working-directory `pwd` --justfile tasks/start/Justfile {{ args }}
+mod start 'tasks/start/Justfile'
 
-stripo +args='help':
-  @just --working-directory `pwd` --justfile tasks/stripo/Justfile {{ args }}
+mod stripo 'tasks/stripo/Justfile'
 
-tests +args='help':
-  @just --working-directory `pwd` --justfile tasks/tests/Justfile {{ args }}
+mod tests 'tasks/tests/Justfile'
 
-translations +args='help':
-  @just --working-directory `pwd` --justfile tasks/translations/Justfile {{ args }}
+mod translations 'tasks/translations/Justfile'
 
diff --git a/tasks/admin/Justfile b/tasks/admin/Justfile
--- a/tasks/admin/Justfile
+++ b/tasks/admin/Justfile
@@ -8,3 +8,3 @@ set dotenv-load := true
 help:
-  @just admin -l
+  @just -l
 
diff --git a/tasks/assets/Justfile b/tasks/assets/Justfile
--- a/tasks/assets/Justfile
+++ b/tasks/assets/Justfile
@@ -5,3 +5,3 @@ set dotenv-load := true
 help:
-  @just assets -l
+  @just -l
 
diff --git a/tasks/aws/Justfile b/tasks/aws/Justfile
--- a/tasks/aws/Justfile
+++ b/tasks/aws/Justfile
@@ -5,3 +5,3 @@ set dotenv-load := true
 help:
-  @just aws -l
+  @just -l
 
diff --git a/tasks/clean/Justfile b/tasks/clean/Justfile
--- a/tasks/clean/Justfile
+++ b/tasks/clean/Justfile
@@ -5,3 +5,3 @@ set dotenv-load := true
 help:
-  @just clean -l
+  @just -l
 
diff --git a/tasks/csv/Justfile b/tasks/csv/Justfile
--- a/tasks/csv/Justfile
+++ b/tasks/csv/Justfile
@@ -5,3 +5,3 @@ set dotenv-load := true
 help:
-  @just csv -l
+  @just -l
 
diff --git a/tasks/deps/Justfile b/tasks/deps/Justfile
--- a/tasks/deps/Justfile
+++ b/tasks/deps/Justfile
@@ -5,3 +5,3 @@ set dotenv-load := true
 help:
-  @just deps -l
+  @just -l
 
diff --git a/tasks/devices/Justfile b/tasks/devices/Justfile
--- a/tasks/devices/Justfile
+++ b/tasks/devices/Justfile
@@ -5,14 +5,6 @@ set dotenv-load := true
 help:
-  @just devices -l
+  @just -l
 
-# Example: just devices android start
-android +args='help':
-  @just --working-directory `pwd` --justfile tasks/devices/android/Justfile {{ args }}
-
-# Example: just devices ie11 start
-ie11 +args='help':
-  @just --working-directory `pwd` --justfile tasks/devices/ie11/Justfile {{ args }}
-
-# Example: just devices ios start
-ios +args='help':
-  @just --working-directory `pwd` --justfile tasks/devices/ios/Justfile {{ args }}
+mod android './android/Justfile'
+mod ie11 './ie11/Justfile'
+mod ios './ios/Justfile'
diff --git a/tasks/devices/android/Justfile b/tasks/devices/android/Justfile
--- a/tasks/devices/android/Justfile
+++ b/tasks/devices/android/Justfile
@@ -4,3 +4,3 @@ set dotenv-load := false
 help:
-  @just devices android -l
+  @just -l
 
@@ -66,3 +66,3 @@ list:
   export ANDROID_AVD_HOME={{justfile_directory()}}/avd
-  just deps require-brew-program avdmanager android-commandlinetools
+  just --justfile ../../../Justfile deps require-brew-program avdmanager android-commandlinetools
   avdmanager list avd
diff --git a/tasks/devices/ie11/Justfile b/tasks/devices/ie11/Justfile
--- a/tasks/devices/ie11/Justfile
+++ b/tasks/devices/ie11/Justfile
@@ -11,3 +11,3 @@ ie11_win7_virtualbox_dir := 'tasks/devices/virtualbox/ie11_win7'
 help:
-  @just devices ie11 -l
+  @just -l
 
diff --git a/tasks/devices/ios/Justfile b/tasks/devices/ios/Justfile
--- a/tasks/devices/ios/Justfile
+++ b/tasks/devices/ios/Justfile
@@ -5,3 +5,3 @@ set dotenv-load := true
 help:
-  @just devices ios -l
+  @just -l
 
diff --git a/tasks/docker/Justfile b/tasks/docker/Justfile
--- a/tasks/docker/Justfile
+++ b/tasks/docker/Justfile
@@ -5,3 +5,3 @@ set dotenv-load := true
 help:
-  @just docker -l
+  @just -l
 
diff --git a/tasks/docs/Justfile b/tasks/docs/Justfile
--- a/tasks/docs/Justfile
+++ b/tasks/docs/Justfile
@@ -4,3 +4,3 @@ set dotenv-load := false
 help:
-  @just docs -l
+  @just -l
 
diff --git a/tasks/elasticsearch/Justfile b/tasks/elasticsearch/Justfile
--- a/tasks/elasticsearch/Justfile
+++ b/tasks/elasticsearch/Justfile
@@ -5,3 +5,3 @@ set dotenv-load := true
 help:
-  @just elasticsearch -l
+  @just -l
 
diff --git a/tasks/mixpanel/Justfile b/tasks/mixpanel/Justfile
--- a/tasks/mixpanel/Justfile
+++ b/tasks/mixpanel/Justfile
@@ -5,3 +5,3 @@ set dotenv-load := true
 help:
-  @just mixpanel -l
+  @just -l
 
diff --git a/tasks/start/Justfile b/tasks/start/Justfile
--- a/tasks/start/Justfile
+++ b/tasks/start/Justfile
@@ -5,3 +5,3 @@ set dotenv-load := true
 help:
-  @just start -l
+  @just -l
 
diff --git a/tasks/stripo/Justfile b/tasks/stripo/Justfile
--- a/tasks/stripo/Justfile
+++ b/tasks/stripo/Justfile
@@ -5,3 +5,3 @@ set dotenv-load := true
 help:
-  @just stripo -l
+  @just -l
 
diff --git a/tasks/tests/Justfile b/tasks/tests/Justfile
--- a/tasks/tests/Justfile
+++ b/tasks/tests/Justfile
@@ -5,3 +5,3 @@ set dotenv-load := true
 help:
-  @just tests -l
+  @just -l
 
diff --git a/tasks/translations/Justfile b/tasks/translations/Justfile
--- a/tasks/translations/Justfile
+++ b/tasks/translations/Justfile
@@ -5,3 +5,3 @@ set dotenv-load := true
 help:
-  @just translations -l
+  @just -l

There will most likely be some cases where these "calls to submodules" will need to be fixed later and ones we'll forget to update when going all-in to Just modules. Most of the calls should still be for just deps as that's the most common one we have and for recipes defined in the same Justfile as the submodule itself.

One thing that I found was confusing is the error when a submodule is calling out to a recipe that is missing. For example:

$ just admin fix-venue-location
error: Justfile does not contain recipe `admin`.
error: Recipe `fix-venue-location` failed with exit code 1

And I had these:

# <root>/Justfile
mod admin 'tasks/admin/Justfile'

# <root>/tasks/admin/Justfile
fix-venue-location env='development' +ARGS='--usage':
    #!/usr/bin/env bash
    just admin _run-ruby-script-using-confirmation {{ env }} fix_venue_location $(cat <<EOF;
    {{ ARGS }}
    EOF)

It was also nice that I could still do just --show admin fix-venue-location while previously I was doing just admin --show fix-venue-location — but now I can no longer do just --show admin as admin is a submodule.

Current file structure we have without modules looked like this for that case:

# <root>/Justfile
admin +args='help':
    #!/usr/bin/env bash
    just --working-directory `pwd` --justfile tasks/admin/Justfile $(cat <<EOF;
    {{ args }}
    EOF)

# <root>/tasks/admin/Justfile
    #!/usr/bin/env bash
    just admin _run-ruby-script-using-confirmation {{ env }} fix_venue_location $(cat <<EOF;
    {{ ARGS }}
    EOF)

If I had an error with the old way of calling, for example if I had just not-correct-admin in there, the error message would've been like this:

$ just admin fix-venue-location
error: Justfile does not contain recipe `not-correct-admin`.
error: Recipe `fix-venue-location` failed with exit code 1
error: Recipe `admin` failed with exit code 1

So the error message did refer to "Recipe `admin` failed with exit code 1" that at least somehow pointed to the problem being inside the admin "submodule".

@bukowa
Copy link
Contributor

bukowa commented Jul 2, 2024

Maybe related #2215

@casey
Copy link
Owner Author

casey commented Jul 4, 2024

@valscion Thanks for the detailed write up! I'm really glad to hear that modules are mostly working for your use-case, especially since it was your comment way back in 2019 which got me thinking about modules in the first place.

just --show should definitely work with modules, since there's really no reason not to. Compilation errors currently contain a path to the module in which they occurred, but non-complation errors do not. This is only because compilation errors always contain a token, which contains a path to the source file in which the error occurs, which makes printing a path to the source file easy. Non-compilation errors should definitely have a path to the justfile, since otherwise you're right it pretty confusing.

I added both of these to the list of future changes to make in the top comment, since both of them can be implemented in a backwards compatible fashion. When modules are stabilized and this issue is closed, I'll make dedicated issues for all of them.

@bukowa
Copy link
Contributor

bukowa commented Jul 7, 2024

Is there any reason why / is not allowed in a mod name? I'm looking for a way to distinguish a mod so that I can quickly know it's coming from a specific directory. Using - or _ is not a solution imho.

mod 'dir1/dir2/dir3' './dir1/dir2/dir3/justfile'

build:
    dir1/dir2/dir3::build

@casey
Copy link
Owner Author

casey commented Jul 7, 2024

Module names are identifiers, which are of the form [a-zA-Z_][a-zA-Z9-9-]*. This is intentionally restrictive. For example, if / were allowed in identifiers, then a/b couldn't be used as the path joining operator, since it would be parsed as an identifier.

@gl-yziquel
Copy link
Contributor

gl-yziquel commented Jul 7, 2024

@bukowa @casey Perhaps a "mod mymod from myfile" syntax would be nice. I kind of stumbled in the same situation as I'd like some of my module where deployed in some /usr/share/just hierarchy.

@casey
Copy link
Owner Author

casey commented Jul 7, 2024

@gl-yziquel. Can you do mod mymod "/usr/share/just/some/module.just"?

@gl-yziquel
Copy link
Contributor

@gl-yziquel. Can you do mod mymod "/usr/share/just/some/module.just"?

I'll keep that in mind...

@bukowa
Copy link
Contributor

bukowa commented Jul 7, 2024

@bukowa @casey Perhaps a "mod mymod from myfile" syntax would be nice. I kind of stumbled in the same situation as I'd like some of my module where deployed in some /usr/share/just hierarchy.

One thing I came across is importing a module with a circular dependency, where examples uses main, and main uses examples. My solution is to split this module into two files, for example:

root/build.just:

build: deps
    ...

deps:
    ...

root/justfile

import './build.just'
mod examples './examples/justfile'

test: build
    just examples::run

root/examples/justfile:

mod root '../build.just'

deps:
    just root::build
    
run: deps
    ...

@bukowa
Copy link
Contributor

bukowa commented Jul 8, 2024

Trying to figure out how to reexport var from other module I wonder if is there a better way?

X:

export INTERNAL_VAR := "..."

INTERNAL_VAR:
    echo "{{INTERNAL_VAR}}"

Y:

mod X '../X/justfile'

export SOME_ENV := `just --justfile ../X/justfile INTERNAL_VAR`

Attribute could be a solution here to not repeat recipe hmm

[echo]
export INTERNAL_VAR := "..."

EDIT: This wont work well with circular dependencies as ../X cannot correctly resolve in some cases.
EDIT2: Just use separate file for vars (vars.just) and reimport ^^ imports gonna save us ! :D

@casey
Copy link
Owner Author

casey commented Jul 14, 2024

As of just 1.31.0, just released, modules have been stabilized!

There aren't any major changes to modules 1.31, the only minor one is that a mod statement with a path may now point to a directory:

mod foo 'some/directory'

In which case some/directory is searched for a file called justfile, .justfile, or mod.just, so you don't need to write the filename explicitly.

There are still a lot of things missing, but they can be added in a backwards compatible fashion. I'm going to create issues for all the items in the top post here, and make a module improvements tracking issue.

Thanks to everyone for bearing with me, thanks to the contributors and commenters, and thanks to @neunenak who did the initial work with !include that got things going.

@casey casey closed this as completed Jul 14, 2024
@casey
Copy link
Owner Author

casey commented Jul 14, 2024

The module stabilization tracking issue is dead, long live the module improvement tracking issue!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests