thiagowfx's avatar

¬ just serendipity 🍀 (not just serendipity)

Just

• 426 words • 2 min • updated

⚠️ This post is over one year old. It may no longer be up to date or relevant. Opinions may have changed.

Just is a command runner, a modern replacement for GNU Make.

It is written in Rust, has sensible defaults, and lots of syntactic sugar. A good analogy is fish versus bash when comparing just to make.

It’s very easy to learn from its README.md alone as it’s quite comprehensive. There’s also a gitbook.

Simon Willison prompted me to try it out.

As an exercise I decided to convert the Makefile used to manage this blog into a Justfile.

The original Makefile:

makefile
# Sitemap URL
SITEMAP = https://perrotta.dev/sitemap.xml

# Hugo port
PORT := 1313

# Abort if hugo is not installed.
ifeq (, $(shell which hugo))
  $(error "No hugo in $$PATH, install it first")
endif

all:
	hugo server --bind="0.0.0.0" --buildDrafts --port $(PORT) --watch

build:
	hugo --environment production --gc --minify

clean:
	$(RM) -r public/ resources/

ping:
	# Ping Google about changes in the sitemap
	curl -sS -o /dev/null "https://www.google.com/ping?sitemap=$(SITEMAP)"
	# Ping Bing (DuckDuckGo, etc) about changes in the sitemap
	curl -sS -o /dev/null "https://www.bing.com/ping?sitemap=$(SITEMAP)"

.PHONY: all build clean ping

Initially I asked ChatGPT to convert it to a Justfile but it was a disaster, even after a couple of iterations. Then I did it myself1. The Justfile:

justfile
set dotenv-load

watch:
	hugo server --buildDrafts --port ${PORT:-1313} --watch

build:
	hugo --environment production --gc --minify

# Create a new post. Usage: `just new "advent of code day 8"`
new post:
	hugo new content/posts/`date "+%Y-%m-%d"`-{{ kebabcase(post) }}.md

clean:
	rm -rf public/ resources/

# Ping Google and Bing about changes in the sitemap
ping sitemap="https://perrotta.dev/sitemap.xml":
	curl -sS -o /dev/null "https://www.google.com/ping?sitemap={{ sitemap }}"
	curl -sS -o /dev/null "https://www.bing.com/ping?sitemap={{ sitemap }}"

The main differences:

  • Environment variables: use {{ foo }} instead of $(FOO)
  • Exception: environment variables loaded from .env (via set dotenv-load) use $FOO or ${FOO} instead, like POSIX shell variables
  • Use rm -rf instead of $(RM) -r
  • Rules accept parameters. Look at new post as an example. Example usage: just new "advent of code day 8"
  • Run shell commands within rules with backticks. $(cmd) does not work.
  • Some handy out-of-the-box functions such as kebabcase(). No need to implement this kind of string manipulation in plain shell script!
  • Documentation comments above rules are recognized. They are displayed as help / usage text when running just -l. No need for hacky self-documented Makefile setups!
shell
% just -l
Available recipes:
    build
    clean
    new post # Create a new post. Usage: `just new "advent of code day 8"`
    ping sitemap="https://perrotta.dev/sitemap.xml" # Ping Google and Bing about changes in the sitemap
    watch

  1. With a bit of LLM prompting in lieu of Google or Stack Overflow searches. ↩︎