Automating Tasks with Just
Throughout this book, we’ve been typing long cargo commands to run the logreader, extract
CopperLists, and more. Those commands are precise but tedious – especially when they
involve feature flags, binary names, and multiple path arguments.
The workspace template ships with a justfile that wraps common operations into short,
memorable commands. In this chapter, we’ll see what just is, what recipes come built-in,
and how to visualize the task graph.
What is Just?
Just is a command runner – think of it as a modern, simpler
alternative to make for project automation. You define recipes (named commands) in a
justfile, then run them with just <recipe>.
Installing Just
If you don’t have it already:
cargo install just
Or on most Linux distributions:
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | \
bash -s -- --to ~/bin
Verify with:
just --version
The workspace justfile
Here’s the justfile that comes with the cu_full workspace template:
# Render the execution DAG from the app config.
dag:
#!/usr/bin/env bash
set -euo pipefail
APP_DIR="${APP_DIR:-cu_example_app}"
cu29-rendercfg apps/"${APP_DIR}"/copperconfig.ron --open
# Compatibility alias for older docs.
rcfg: dag
# Extract the structured log via the log reader.
log:
#!/usr/bin/env bash
set -euo pipefail
APP_DIR="${APP_DIR:-cu_example_app}"
APP_NAME="${APP_NAME:-${APP_DIR}}"
RUST_BACKTRACE=1 cargo run -p "${APP_NAME}" --features=logreader \
--bin "${APP_NAME}-logreader" \
apps/"${APP_DIR}"/logs/"${APP_NAME}".copper \
extract-text-log target/debug/cu29_log_index
# Extract CopperLists from the log output.
cl:
#!/usr/bin/env bash
set -euo pipefail
APP_DIR="${APP_DIR:-cu_example_app}"
APP_NAME="${APP_NAME:-${APP_DIR}}"
RUST_BACKTRACE=1 cargo run -p "${APP_NAME}" --features=logreader \
--bin "${APP_NAME}-logreader" \
apps/"${APP_DIR}"/logs/"${APP_NAME}".copper extract-copperlists
Three recipes, each wrapping a command we’d otherwise have to type (or remember) by hand.
The recipes
just log – Extract text logs
Remember in Chapter 13 when we ran this?
cargo run --features logreader --bin my-project-logreader -- \
logs/my-project.copper extract-text-log target/debug/cu29_log_index
In the workspace, that becomes:
just log
It extracts the structured text logs (debug!(), info!(), etc.) from the .copper file
and reconstructs the human-readable output using the compile-time string index.
just cl – Extract CopperLists
Also from Chapter 13, extracting CopperList data (the message payloads from every cycle) was:
cargo run --features logreader --bin my-project-logreader -- \
logs/my-project.copper extract-copperlists
Now it’s just:
just cl
just dag – Render the task graph
This is the new one. Copper includes a tool called cu29-rendercfg that reads your
copperconfig.ron and generates a visual diagram of the task graph – an SVG showing
all tasks and their connections as a directed acyclic graph (DAG).
Let’s try it on our workspace.
Then, from the my_workspace/ directory:
just dag
This renders the DAG from apps/cu_example_app/copperconfig.ron and opens it in your
default browser. You’ll see a diagram like:
┌─────────┐ ┌─────────┐ ┌─────────┐
│ src │────▶│ t-0 │────▶│ sink │
└─────────┘ └─────────┘ └─────────┘
For our simple three-task pipeline, the diagram is straightforward. But as your robot grows to 10, 20, or 50 tasks with complex wiring, this visualization becomes invaluable for understanding the data flow at a glance.
Targeting a different app
All three recipes default to cu_example_app. If your workspace has multiple applications,
override the target with environment variables:
APP_DIR=my_other_app just log
APP_DIR=my_other_app just cl
APP_DIR=my_other_app just dag
The APP_DIR variable controls which app directory to look in, and APP_NAME (which
defaults to APP_DIR) controls the binary and package name passed to cargo.
just rcfg still works as a compatibility alias, but just dag is the current primary
name in the generated template.
Adding your own recipes
The justfile is yours to extend. Here are some recipes you might add as your project
evolves:
# Run the main application.
run:
cargo run -p cu_example_app
# Run with the console monitor enabled.
run-mon:
cargo run -p cu_example_app -- --monitor
# Build everything in release mode.
release:
cargo build --release
# Clean build artifacts and log files.
clean:
cargo clean
rm -f apps/*/logs/*.copper
Recipes are just shell commands with names. If you find yourself typing the same command twice, make it a recipe.
Why not make?
You could use make for all of this, and some people do. just has a few advantages for
this use case:
- No tabs-vs-spaces headaches –
justuses consistent indentation rules. - No implicit rules – every recipe is explicit. No “magic”
.PHONYtargets. - Variables and defaults –
justsupports environment variable defaults natively (the${APP_DIR:-cu_example_app}syntax). - Cross-platform – works the same on Linux, macOS, and Windows.
- No build system baggage –
justis purely a command runner, not a build system. Cargo is already your build system.