DEV Community

George Shuklin
George Shuklin

Posted on

Good practices for Just: no '../' in paths.

If you don't know, Just is https://just.systems/, the beautiful well-thought replacement for make as 'small scale executor'. It does not replace make as a build tool (handling creation dates for files, etc), but it does so for every .phony stuff from a Makefile.

As for most tools, the usage starts small, but starts to spiral into chaos as line count grows. My current project I work on has about 300 lines in Justfiles. Very dense lines, with average recipe about 3–5 lines, and the magic living between recipes (one recipe is calling other or dependent on other recipes).

The chaos must be resisted with order and rules. A good rule is the best practice.

I don't have 100% assurance in things I write now, but I feel, I can call them at least 'good practices'. There are few now, but they start to accumulate as I correct my previous design mistakes and see arising problems.

Rule 1: No ..

We start with cwd (current working directory) been set to the path where used Justfile is placed.

├── Justfile
├── somedir
Enter fullscreen mode Exit fullscreen mode

We go into somedir, type just myrecipe and our working directory is the dirictory where Justfile is, not 'somedir'.

This is nice and we can use it for relative pathes. There is nothing bad in writing something like that:

deploy:
  ansible-playbook playbooks/deploy.yaml -i inventory/
Enter fullscreen mode Exit fullscreen mode

Even if we are calling just deploy in the playbooks directory it will work as expected, we will go 'up' to run this command and all pathes will point to the expected files.

There are also [no-cd] and [cd dir] attributes.

But... Sometimes we need to change directory.

deploy:
   cd ansible && ansible-playbook playbooks/deploy.yaml -i ../inventory/
Enter fullscreen mode Exit fullscreen mode

We changed the structure. Now there is ansible/playbooks/ and /inventory and we need to cd to ansible before running Ansible (because there is ansible.cfg there and all other stuff).

But inventory is outside of ansible (for whatever reasons). And we need it.

Simple solution is '..'. Which quickly become:

cd production/deploy/ansible && ANSIBLE_INVENTORY=$(realpath inventory/),$(realpath ../environments/{{ environment }}/ansible/inventory) -e @../../../sources/data {{ args }}
Enter fullscreen mode Exit fullscreen mode

Can you see the problem? Too many ...

If you decide to move stuff around during refactoring, you will have to recalculate those '..', and it's hard, because you need to reason on state machine jumping between directories.

Solution? Use {{ justfile_directory() }}.

  1. It is the absolute path. Except when you need relative path for external reasons, it's always pointing to the proper place, even if you pass it as an argument to the utility which run from a different directory.
  2. It is the relative path in sense, than clonning a repo into a different directory or moving stuff around keeps relative links unbroken.

Best of both worlds.

Let's look to the good practice of using {{ justfile_directory() }}.

cd production/deploy/ansible && ANSIBLE_INVENTORY={{ justfile_directory() }}/production/deploy/ansible/inventory,{{ justfile_directory() }}/production/environments/{{ environment }}/ansible/inventory) -e @{{ justfile_directory }}/sources/data {{ args }}
Enter fullscreen mode Exit fullscreen mode

(I may made some relative mistakes while writing it, it hurts my brain to think about original paths).

Result is much more readable (although, longer). We always can see where file is relative to the justfile, and there is no 'relativity' of (working directory after cd, relative paths for Ansible, etc, etc).

For every utility it is absolute path, no thinking required.

For developer it's all relative paths, relative to a single location - the placement of the Justfile.

If we decide to remove 'production' from the path, we don't need to think which ../.. to reduce and which to keep. It all stays intact.

I will post more good practices as I find the specific cases.

Top comments (0)