mcpField
J
justfile

justfile

github.com/iloveitaly開発0190 回インストール3 週間前に更新
リポジトリ

justfile について

`justfile`にrecipeとして定義したプロジェクト固有のコマンドを実行するコマンドランナーです。開発者はコマンドラインから依存関係を含むrecipeを呼び出し、引数や環境、作業ディレクトリを設定できます。

主な機能

  1. 01`justfile`でプロジェクトコマンドを定義
  2. 02recipeの引数と依存関係
  3. 03recipe一覧とエイリアス
  4. 04`.env`ファイルの読み込み
  5. 05シェルと作業ディレクトリの設定
  6. 06複数OSでのコマンド実行

活用シーン

  1. 01プロジェクトのテストやビルドの実行
  2. 02セットアップやリリースrecipeの連携
  3. 03利用可能なプロジェクトコマンドの確認
  4. 04異なるOS間での再利用可能なコマンド共有

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/iloveitaly/ai-skills --skill justfile

インストール後、Claude Code で/justfileを入力して読み込まれたか確認します。

詳細

Justfile の作成

以下の README は、https://github.com/casey/just/blob/master/README.md から取得しています。

Justfile の構文とシステムについて、すべて説明しています。


just

just は、プロジェクト固有のコマンドを保存して実行する便利な方法です。

この README は書籍としても公開されています。 書籍には最新リリースの内容が反映されます。一方、 GitHub 上の README には最新の master の内容が反映されます。

(中文文档在 这里, 快看过来!)

レシピと呼ばれるコマンドは、make に着想を得た構文を使い、justfile というファイルに保存されます。

screenshot

その後、just RECIPE で実行できます。

$ just test-all
cc *.c -o main
./test --all
Yay, all your tests passed!

just には便利な機能が数多くあり、make よりも多くの点で優れています。

  • just はビルドシステムではなくコマンドランナーなので、 make の複雑さや独特な挙動の多くを回避できます。 .PHONY レシピは不要です。
  • Linux、MacOS、Windows、その他の一般的な UNIX 系 OS を、追加の依存関係なしでサポートしています。(ただし、システムに sh がない場合は、別のシェルを選ぶ必要があります。)
  • エラーは具体的で分かりやすく、構文エラーは該当するソースの内容とともに報告されます。
  • レシピにはコマンドライン引数を渡せます。
  • 可能な限り、エラーは静的に解決されます。不明なレシピや循環依存関係は、実行開始前に報告されます。
  • just は.env ファイルを読み込むため、環境変数を簡単に設定できます。
  • レシピをコマンドラインから一覧表示できます。
  • 多くの一般的なシェルで、コマンドライン補完スクリプトを利用できます。
  • Python や NodeJS などの任意の言語でレシピを記述できます。
  • justfile があるディレクトリだけでなく、任意のサブディレクトリから just を実行できます。
  • ほかにもさまざまな機能があります。

just についてサポートが必要な場合は、気軽に issue を作成するか、Discord で連絡してください。機能のリクエストやバグ報告はいつでも歓迎です。

クイックスタート

just をコンピューターにインストールする方法については、インストールのセクションを参照してください。just --version を実行して、正しくインストールされたことを確認してください。

構文の概要については、このチートシートをご覧ください。

just をインストールして使える状態にしたら、プロジェクトのルートに justfile という名前のファイルを作成し、次の内容を記述します。

recipe-name:
  echo 'This is a recipe!'

# this is a comment
another-recipe:
  @echo 'This is another recipe.'

just を実行すると、現在のディレクトリとその上位のディレクトリで justfile を検索するため、プロジェクト内のどのサブディレクトリからでも実行できます。

justfile の検索では大文字と小文字が区別されないため、Justfile、JUSTFILE、JuStFiLe など、どのような表記でも動作します。また、justfile を隠したい場合に備えて、.justfile という名前のファイルも検索します。

引数なしで just を実行すると、justfile 内の最初のレシピが実行されます。

$ just
echo 'This is a recipe!'
This is a recipe!

1 つ以上の引数を指定すると、指定したレシピが実行されます。

$ just another-recipe
This is another recipe.

just は各コマンドを実行前に標準エラー出力へ表示するため、echo 'This is a recipe!' が表示されました。@ で始まる行ではこの表示が抑制されるため、echo 'This is another recipe.' は表示されませんでした。

コマンドが失敗すると、レシピの実行は停止します。ここでは、cargo test が成功した場合にのみ cargo publish が実行されます。

publish:
  cargo test
  # tests passed, time to publish!
  cargo publish

レシピは、ほかのレシピに依存できます。ここでは、test レシピが build レシピに依存しているため、test の前に build が実行されます。

build:
  cc main.c foo.c bar.c -o main

test: build
  ./test

sloc:
  @echo "`wc -l *.c` lines of code"
$ just test
cc main.c foo.c bar.c -o main
./test
testing… all tests passed!

依存関係のないレシピは、コマンドラインで指定した順に実行されます。

$ just build sloc
cc main.c foo.c bar.c -o main
1337 lines of code

依存先のレシピは、依存するレシピより後に指定されていても、必ず先に実行されます。

$ just test build
cc main.c foo.c bar.c -o main
./test
testing… all tests passed!

レシピはサブモジュール内のレシピに依存できます。

mod foo

baz: foo::bar

例

さまざまな justfile が、examples ディレクトリや GitHubで見つかります。

機能

デフォルトのレシピ

just をレシピを指定せずに実行すると、[default] 属性が付いたレシピが実行されます。[default] 属性が付いたレシピがない場合は、justfile の最初のレシピが実行されます。

このレシピには、テストの実行など、プロジェクトで最も頻繁に実行されるコマンドを指定できます。

test:
  cargo test

依存関係を使って、デフォルトで複数のレシピを実行することもできます。

default: lint build test

build:
  echo Building…

test:
  echo Testing…

lint:
  echo Linting…

デフォルトのレシピとして適切なものがない場合は、利用可能なレシピを一覧表示するレシピを justfile の先頭に追加できます。

default:
  just --list
利用可能なレシピの一覧表示

just --list を使うと、レシピをアルファベット順に一覧表示できます。

$ just --list
Available recipes:
    build
    test
    deploy
    lint

サブモジュール内のレシピは、just --list PATH で一覧表示できます。PATH は、スペースまたは :: で区切られたモジュールパスです。

$ cat justfile
mod foo
$ cat foo.just
mod bar
$ cat bar.just
baz:
$ just --list foo bar
Available recipes:
    baz
$ just --list foo::bar
Available recipes:
    baz

just --summary を使うと、より簡潔に表示できます。

$ just --summary
build test deploy lint

--unsorted を指定すると、justfile に記述された順序でレシピが表示されます。

test:
  echo 'Testing!'

build:
  echo 'Building!'
$ just --list --unsorted
Available recipes:
    test
    build
$ just --summary --unsorted
test build

just のデフォルトの動作を justfile のレシピ一覧表示にしたい場合は、次のようなデフォルトレシピを使えます。

default:
  @just --list

上記の行に --justfile {{justfile()}} を追加する必要がある場合があります。これを指定しない場合、just -f /some/distant/justfile -d . や just -f ./non-standard-justfile を実行したとき、レシピ内の just --list が指定したファイルを使うとは限りません。現在のパスから justfile を探すため、No justfile found エラーになることもあります。

--list-heading を使うと、見出しのテキストをカスタマイズできます。

$ just --list --list-heading $'Cool stuff…\n'
Cool stuff…
    test
    build

--list-prefix を使うと、インデントをカスタマイズできます。

$ just --list --list-prefix ····
Available recipes:
····test
····build

--list-heading の引数は、見出しとその後に続く改行の両方を置き換えます。そのため、空でない場合は改行を含めてください。この仕様により、空文字列を渡せば見出し行を完全に省略できます。

$ just --list --list-heading ''
    test
    build
複数のレシピの実行

コマンドラインで複数のレシピを一度に実行できます。

build:
  make web

serve:
  python3 -m http.server -d out 8000
$ just build serve
make web
python3 -m http.server -d out 8000

パラメーターを持つレシピは、ほかのレシピ名と一致する場合でも引数を取り込むことに注意してください。

build project:
  make {{project}}

serve:
  python3 -m http.server -d out 8000
$ just build serve
make: *** No rule to make target `serve'.  Stop.

--one フラグを使うと、コマンドラインで実行できるレシピを1つに制限できます。

$ just --one build serve
error: Expected 1 command-line recipe invocation but found 2.
作業ディレクトリ

デフォルトでは、レシピは justfile を含むディレクトリを作業ディレクトリとして実行されます。

[no-cd] 属性を使うと、just を実行したディレクトリを作業ディレクトリとしてレシピを実行できます。

@foo:
  pwd

[no-cd]
@bar:
  pwd
$ cd subdir
$ just foo
/
$ just bar
/subdir

set working-directory := '…' を使うと、すべてのレシピの作業ディレクトリを上書きできます。

set working-directory := 'bar'

@foo:
  pwd
$ pwd
/home/bob
$ just foo
/home/bob/bar

working-directory 属性1.38.0を使うと、特定のレシピの作業ディレクトリを上書きできます。

[working-directory: 'bar']
@foo:
  pwd
$ pwd
/home/bob
$ just foo
/home/bob/bar

working-directory 設定または working-directory 属性の引数には、絶対パスまたは相対パスを指定できます。相対パスの場合は、デフォルトの作業ディレクトリを基準に解釈されます。

エイリアス

エイリアスを使うと、別の名前でコマンドラインからレシピを実行できます。

alias b := build

build:
  echo 'Building!'
$ just b
echo 'Building!'
Building!

エイリアスの対象には、サブモジュール内のレシピも指定できます。

mod foo

alias baz := foo::bar
設定

設定は、解釈と実行を制御します。各設定は、justfile 内の場所を問わず、1回だけ指定できます。

例:

set shell := ["zsh", "-cu"]

foo:
  # this line will be run as `zsh -cu 'ls **/*.txt'`
  ls **/*.txt
設定一覧
名前値デフォルト説明
allow-duplicate-recipesbooleanfalsejustfile の後方に記述されたレシピが、同じ名前を持つ前方のレシピを上書きできるようにします。
allow-duplicate-variablesbooleanfalsejustfile の後方に記述された変数が、同じ名前を持つ前方の変数を上書きできるようにします。
dotenv-filenamestring-存在する場合、任意の名前の .env ファイルを読み込みます。
dotenv-loadbooleanfalse存在する場合、.env ファイルを読み込みます。
dotenv-overridebooleanfalse.env ファイルの値で既存の環境変数を上書きします。
dotenv-pathstring-任意のパスから .env ファイルを読み込み、ファイルが存在しない場合はエラーにします。dotenv-filename より優先されます。
dotenv-requiredbooleanfalse.env ファイルが見つからない場合はエラーにします。
exportbooleanfalseすべての変数を環境変数としてエクスポートします。
fallbackbooleanfalseコマンドラインで最初に指定されたレシピが見つからない場合、親ディレクトリの justfile を検索します。
ignore-commentsbooleanfalse# で始まるレシピ行を無視します。
positional-argumentsbooleanfalse位置引数を渡します。
quietbooleanfalse実行前にレシピ行を表示しないようにします。
script-interpreter1.33.0[COMMAND, ARGS…]['sh', '-eu']空の [script] 属性を持つレシピの呼び出しに使用するコマンドを設定します。
shell[COMMAND, ARGS…]-レシピの呼び出しとバッククォートの評価に使用するコマンドを設定します。
tempdirstring-システムのデフォルトの一時ディレクトリではなく、tempdir に一時ディレクトリを作成します。
unstable1.31.0booleanfalse不安定な機能を有効にします。
windows-powershellbooleanfalseWindows で PowerShell をデフォルトのシェルとして使用します。(非推奨です。代わりに windows-shell を使用してください。
windows-shell[COMMAND, ARGS…]-レシピの呼び出しとバッククォートの評価に使用するコマンドを設定します。
working-directory1.33.0string-デフォルトの作業ディレクトリからの相対パスで、レシピとバッククォートの作業ディレクトリを設定します。

ブール型の設定は、次のように記述できます。

set NAME

これは次と同等です。

set NAME := true

ブール型以外の設定には、文字列と式の両方を設定できます。1.46.0

ただし、設定はバッククォートや多くの関数の動作に影響するため、式にバッククォートや関数呼び出しを直接含めることはできません。参照を介して間接的に含めることもできません。

重複するレシピを許可する

allow-duplicate-recipes が true に設定されている場合、同じ名前のレシピを複数定義してもエラーにならず、最後の定義が使用されます。デフォルトは false です。

set allow-duplicate-recipes

@foo:
  echo foo

@foo:
  echo bar
$ just foo
bar
重複する変数を許可する

allow-duplicate-variables が true に設定されている場合、同じ名前の変数を複数定義してもエラーにならず、最後の定義が使用されます。デフォルトは false です。

set allow-duplicate-variables

a := "foo"
a := "bar"

@foo:
  echo {{a}}
$ just foo
bar
Dotenv 設定

dotenv-load、dotenv-filename、dotenv-override、dotenv-path、 dotenv-required のいずれかが設定されている場合、just はファイルから 環境変数を読み込もうとします。

dotenv-path が設定されている場合、just は指定されたパスにあるファイルを探します。 パスは絶対パスでも、作業ディレクトリからの相対パスでもかまいません。

コマンドラインオプション --dotenv-path(短縮形 -E)を使うと、実行時に dotenv-path を設定または上書きできます。

dotenv-filename が設定されている場合、just は作業ディレクトリとその各親ディレクトリを 基準に、指定されたパスにあるファイルを探します。

dotenv-filename が設定されておらず、dotenv-load または dotenv-required が 設定されている場合、just は作業ディレクトリとその各親ディレクトリを基準に、 .env という名前のファイルを探します。

dotenv-filename と dotenv-path は似ていますが、dotenv-path は作業ディレクトリを 基準にのみ確認されるのに対し、dotenv-filename は作業ディレクトリとその各親ディレクトリを 基準に確認されます。

dotenv-required が設定されていない限り、環境ファイルが見つからなくてもエラーにはなりません。

読み込まれた変数は just 変数ではなく環境変数です。そのため、レシピやバッククォートでは $VARIABLE_NAME を使ってアクセスする必要があります。

dotenv-override が設定されている場合、環境ファイルの変数は既存の環境変数を上書きします。

たとえば、.env ファイルに次の内容が含まれているとします。

# a comment, will be ignored
DATABASE_ADDRESS=localhost:6379
SERVER_PORT=1337

そして、justfile に次の内容が含まれているとします。

set dotenv-load

serve:
  @echo "Starting server with database $DATABASE_ADDRESS on port $SERVER_PORT…"
  ./server --database $DATABASE_ADDRESS --port $SERVER_PORT

この場合、just serve は次のように出力します。

$ just serve
Starting server with database localhost:6379 on port 1337…
./server --database $DATABASE_ADDRESS --port $SERVER_PORT
エクスポート

export 設定を有効にすると、すべての just 変数が環境変数としてエクスポートされます。 デフォルトは false です。

set export

a := "hello"

@foo b:
  echo $a
  echo $b
$ just foo goodbye
hello
goodbye
位置引数

positional-arguments が true の場合、レシピの引数はコマンドに位置引数として渡されます。 行単位のレシピでは、引数 $0 はレシピ名になります。

たとえば、次のレシピを実行すると、

set positional-arguments

@foo bar:
  echo $0
  echo $1

次のように出力されます。

$ just foo hello
foo
hello

bash や zsh などの sh 互換シェルでは、$@ はレシピに渡された位置引数を 1 番目から順に展開します。"$@" のように二重引用符内で使用すると、空白を含む引数も 二重引用符で囲まれた場合と同様に渡されます。つまり、"$@" は "$1" "$2"… と同等です。 位置パラメーターがない場合、"$@" と $@ は何もない状態に展開されます (つまり、削除されます)。

このレシピの例では、引数を1つずつ別々の行に出力します。

set positional-arguments

@test *args='':
  bash -c 'while (( "$#" )); do echo - $1; shift; done' -- "$@"

引数を 2 つ 指定して実行すると、

$ just test foo "bar baz"
- foo
- bar baz

位置引数は、[positional-arguments] 属性1.29.0を使って レシピごとに有効にすることもできます。

[positional-arguments]
@foo bar:
  echo $0
  echo $1

PowerShell は位置引数を他のシェルと同じ方法では処理しないため、位置引数を有効にすると PowerShell を使うレシピが動作しなくなる可能性があります。

PowerShell 7.4 以降を使用している場合、-CommandWithArgs フラグを使うと 位置引数が期待どおりに動作します。

set shell := ['pwsh.exe', '-CommandWithArgs']
set positional-arguments

print-args a b c:
  Write-Output @($args[1..($args.Count - 1)])
シェル

shell 設定は、レシピの行とバッククォートを実行するコマンドを制御します。 シバン付きレシピには影響しません。デフォルトのシェルは sh -cu です。

# use python3 to execute recipe lines and backticks
set shell := ["python3", "-c"]

# use print to capture result of evaluation
foos := `print("foo" * 4)`

foo:
  print("Snake snake snake snake.")
  print("{{foos}}")

just は実行するコマンドを引数として渡します。多くのシェルでは、最初の引数を評価させるために、 多くの場合 -c などの追加フラグが必要です。

Windows シェル

just は Windows ではデフォルトで sh を使用します。Windows で別のシェルを使うには、 windows-shell を使用します。

set windows-shell := ["powershell.exe", "-NoLogo", "-Command"]

hello:
  Write-Host "Hello, world!"

すべてのプラットフォームで PowerShell を使用する justfile については、 powershell.just を参照してください。

Windows PowerShell

set windows-powershell は従来の powershell.exe バイナリを使用するため、現在は推奨されていません。 Windows で使用するシェルをより柔軟に制御するには、上記の windows-shell 設定を参照してください。

just は Windows ではデフォルトで sh を使用します。代わりに powershell.exe を使用するには、 windows-powershell を true に設定します。

set windows-powershell := true

hello:
  Write-Host "Hello, world!"
Python 3
set shell := ["python3", "-c"]
Bash
set shell := ["bash", "-uc"]
Z Shell
set shell := ["zsh", "-uc"]
Fish
set shell := ["fish", "-c"]
Nushell
set shell := ["nu", "-c"]

デフォルトのテーブルモードを light に変更する場合:

set shell := ['nu', '-m', 'light', '-c']

Nushell は Rust で記述されており、Windows/macOS/Linux をクロスプラットフォームでサポートしています。

ドキュメントコメント

レシピの直前にあるコメントは、just --list に表示されます。

# build stuff
build:
  ./bin/build

# test stuff
test:
  ./bin/test
$ just --list
Available recipes:
    build # build stuff
    test # test stuff

[doc] 属性を使うと、レシピのドキュメントコメントを設定または非表示にできます。

# This comment won't appear
[doc('Build stuff')]
build:
  ./bin/build

# This one won't either
[doc]
test:
  ./bin/test
$ just --list
Available recipes:
    build # Build stuff
    test
式と置換

式では、さまざまな演算子や関数呼び出しを使用できます。これらは、代入、レシピ引数のデフォルト値、レシピ本体の {{…}} 置換内で使用できます。

tmpdir  := `mktemp -d`
version := "0.2.7"
tardir  := tmpdir / "awesomesauce-" + version
tarball := tardir + ".tar.gz"
config  := quote(config_dir() / ".project-config")

publish:
  rm -f {{tarball}}
  mkdir {{tardir}}
  cp README.md *.c {{ config }} {{tardir}}
  tar zcvf {{tarball}} {{tardir}}
  scp {{tarball}} [email protected]:release/
  rm -rf {{tarball}} {{tardir}}
連結

+ 演算子は、左辺の引数と右辺の引数を連結した値を返します。

foobar := 'foo' + 'bar'
論理演算子

論理演算子 && と || は、Python の and や or と同様に、文字列の値を合成するために使用できます1.37.0。これらの演算子では、空文字列 '' は偽、それ以外のすべての文字列は真として扱われます。

これらの演算子は現在、不安定です。

&& 演算子は、左辺の引数が空文字列の場合は空文字列を返し、それ以外の場合は右辺の引数を返します。

foo := '' && 'goodbye'      # ''
bar := 'hello' && 'goodbye' # 'goodbye'

|| 演算子は、左辺の引数が空でない場合はその値を返し、空の場合は右辺の引数を返します。

foo := '' || 'goodbye'      # 'goodbye'
bar := 'hello' || 'goodbye' # 'hello'
パスの結合

/ 演算子を使うと、2 つの文字列をスラッシュで結合できます。

foo := "a" / "b"
$ just --evaluate foo
a/b

すでに / が含まれている場合でも、/ が追加されることに注意してください。

foo := "a/"
bar := foo / "b"
$ just --evaluate bar
a//b

絶対パスを作成することもできます1.5.0。

foo := / "b"
$ just --evaluate foo
/b

/ 演算子は、Windows 上でも / 文字を使用します。そのため、/ 演算子は、ユニバーサル命名規則(UNC)を使用するパス、つまり \? で始まるパスには使用しないでください。UNC パスではスラッシュがサポートされていないためです。

{{ のエスケープ

{{ を含むレシピを記述するには、{{{{ を使用します。

braces:
  echo 'I {{{{LOVE}} curly braces!'

(対応する }} がない場合は無視されるため、エスケープする必要はありません。)

別の方法として、エスケープしたいテキスト全体を補間の中に入れることもできます。

braces:
  echo '{{'I {{LOVE}} curly braces!'}}'

さらに、{{ "{{" }} を使用する方法もあります。

braces:
  echo 'I {{ "{{" }}LOVE}} curly braces!'
文字列

'single'、"double"、'''triple''' で囲んだ文字列リテラルを使用できます。レシピ本体とは異なり、文字列内では {{…}} の補間はサポートされていません。

二重引用符で囲んだ文字列では、エスケープシーケンスを使用できます。

carriage-return   := "\r"
double-quote      := "\""
newline           := "\n"
no-newline        := "\
"
slash             := "\\"
tab               := "\t"
unicode-codepoint := "\u{1F916}"
$ just --evaluate
"arriage-return   := "
double-quote      := """
newline           := "
"
no-newline        := ""
slash             := "\"
tab               := "     "
unicode-codepoint := "🤖"

Unicode 文字のエスケープシーケンス \u{…}1.36.0 では、最大 6 桁の 16 進数を指定できます。

文字列には改行を含めることができます。

single := '
hello
'

double := "
goodbye
"

単一引用符で囲んだ文字列では、エスケープシーケンスは認識されません。

escapes := '\t\n\r\"\\'
$ just --evaluate
escapes := "\t\n\r\"\\"

単一引用符または二重引用符を 3 つずつ使って囲むことで、インデント付きの単一引用符および二重引用符文字列を使用できます。インデント付き文字列では、先頭の改行と、空白でないすべての行に共通する先頭の空白が取り除かれます。

# this string will evaluate to `foo\nbar\n`
x := '''
  foo
  bar
'''

# this string will evaluate to `abc\n  wuv\nxyz\n`
y := """
  abc
    wuv
  xyz
"""

インデントなしの文字列と同様に、インデント付きの二重引用符文字列ではエスケープシーケンスが処理され、インデント付きの単一引用符文字列ではエスケープシーケンスが無視されます。エスケープシーケンスの処理は、インデントの削除後に行われます。インデントの削除アルゴリズムでは、エスケープシーケンスによって生成された空白や改行は考慮されません。

シェル展開文字列

x を接頭辞に付けた文字列は、シェル展開されます1.27.0。

foobar := x'~/$FOO/${BAR}'
値置換後
$VAR環境変数 VAR の値
${VAR}環境変数 VAR の値
${VAR:-DEFAULT}環境変数 VAR の値。VAR が設定されていない場合は DEFAULT
先頭の ~現在のユーザーのホームディレクトリのパス
先頭の ~USERUSER のホームディレクトリのパス

この展開はコンパイル時に行われるため、.env ファイルの変数やエクスポートされた just 変数は使用できません。ただし、この仕組みにより、just 変数や .env ファイルに依存できない設定やインポートパスなどの場所で、シェル展開文字列を使用できます。

フォーマット文字列

f が前に付いた文字列はフォーマット文字列です1.44.0:

name := "world"
message := f'Hello, {{name}}!'

フォーマット文字列には、式を含む {{…}} で区切られた補間を含めることができます。フォーマット文字列は、文字列の断片と評価された式を連結した文字列に評価されます。

フォーマット文字列にリテラルの {{ を含めるには、{{{{ を使用します:

foo := f'I {{{{LOVE} curly braces!'
エラーの無視

通常、コマンドがゼロ以外の終了ステータスを返すと、実行は停止します。コマンドが失敗した場合でも、その後の実行を続けるには、コマンドの前に - を付けます:

foo:
  -cat foo
  echo 'Done!'
$ just foo
cat foo
cat: foo: No such file or directory
echo 'Done!'
Done!
関数

just には、式で使用できる多くの組み込み関数があります。レシピ本文での {{…}} 置換、代入、デフォルトのパラメーター値などで使用できます。

_directory で終わる関数は、すべて _dir に省略できます。そのため、home_directory() は home_dir() とも記述できます。また、invocation_directory_native() は invocation_dir_native() に省略できます。

システム情報
  • arch() — 命令セットアーキテクチャです。指定可能な値は "aarch64"、"arm"、"asmjs"、"hexagon"、"mips"、"msp430"、"powerpc"、"powerpc64"、"s390x"、"sparc"、"wasm32"、"x86"、"x86_64"、"xcore" です。
  • num_cpus()1.15.0 - 論理 CPU の数です。
  • os() — オペレーティングシステムです。指定可能な値は "android"、"bitrig"、"dragonfly"、"emscripten"、"freebsd"、"haiku"、"ios"、"linux"、"macos"、"netbsd"、"openbsd"、"solaris"、"windows" です。
  • os_family() — オペレーティングシステムのファミリーです。指定可能な値は "unix" と "windows" です。

例:

system-info:
  @echo "This is an {{arch()}} machine".
$ just system-info
This is an x86_64 machine

os_family() 関数を使うと、さまざまなオペレーティングシステムで動作するクロスプラットフォームの justfile を作成できます。例については、cross-platform.just ファイルを参照してください。

外部コマンド
  • shell(command, args...)1.27.0 は、シェルスクリプトの command を、0 個以上の位置引数 args とともに実行した際の標準出力を返します。command の解釈に使用されるシェルは、レシピ行の評価に使用されるものと同じで、set shell := […] で変更できます。

    command は最初の引数として渡されます。そのため、コマンドが 'echo $@' で、デフォルトのシェルコマンド sh -cu と args の 'foo'、'bar' を使用する場合、コマンドライン全体は次のようになります:

    'sh' '-cu' 'echo $@' 'echo $@' 'foo' 'bar'
    

    これにより、$@ が期待どおりに機能し、$1 が最初の引数を参照します。$@ には最初の位置引数は含まれません。この引数は、実行するプログラムの名前として扱われるためです。

# arguments can be variables or expressions
file := '/sys/class/power_supply/BAT0/status'
bat0stat := shell('cat $1', file)

# commands can be variables or expressions
command := 'wc -l'
output := shell(command + ' "$1"', 'main.c')

# arguments referenced by the shell command must be used
empty := shell('echo', 'foo')
full := shell('echo $1', 'foo')
error := shell('echo $1')
# Using python as the shell. Since `python -c` sets `sys.argv[0]` to `'-c'`,
# the first "real" positional argument will be `sys.argv[2]`.
set shell := ["python3", "-c"]
olleh := shell('import sys; print(sys.argv[2][::-1])', 'hello')
環境変数
  • env(key)1.15.0 — 名前が key の環境変数を取得します。変数が存在しない場合は中断します。
home_dir := env('HOME')

test:
  echo "{{home_dir}}"
$ just
/home/user1
  • env(key, default)1.15.0 — 名前が key の環境変数を取得します。変数が存在しない場合は default を返します。
  • env_var(key) — env(key) の非推奨の別名です。
  • env_var_or_default(key, default) — env(key, default) の非推奨の別名です。

現在は不安定な || 演算子を使うと、値が空の環境変数にデフォルト値を代入できます:

set unstable

foo := env('FOO', '') || 'DEFAULT_VALUE'
実行可能ファイル
  • require(name)1.39.0 — 環境変数 PATH に含まれるディレクトリを検索し、実行可能ファイル name のフルパスを返します。該当する実行可能ファイルが存在しない場合は、エラーで停止します。

    bash := require("bash")
    
    @test:
        echo "bash: '{{bash}}'"
    
    $ just
    bash: '/bin/bash'
    
  • which(name)1.39.0 — 環境変数 PATH に含まれるディレクトリを検索し、実行可能ファイル name のフルパスを返します。該当する実行可能ファイルが存在しない場合は、空の文字列を返します。現在は不安定です。

    set unstable
    
    bosh := which("bosh")
    
    @test:
        echo "bosh: '{{bosh}}'"
    
    $ just
    bosh: ''
    
呼び出し情報
  • is_dependency() - 現在のレシピが直接実行されているのではなく、別のレシピの依存関係として実行されている場合は文字列 true を返し、それ以外の場合は文字列 false を返します。
呼び出しディレクトリ
  • invocation_directory() - just がコマンドを実行する前にディレクトリを変更(chdir)する前の、just が呼び出された時点のカレントディレクトリの絶対パスを取得します。Windows では、invocation_directory() は cygpath を使用して、呼び出しディレクトリを Cygwin 互換の / 区切りパスに変換します。すべてのプラットフォームで呼び出しディレクトリをそのまま返すには、invocation_directory_native() を使用してください。

たとえば、ユーザー(呼び出し元)の視点で「カレントディレクトリ」にあるファイルだけを対象に rustfmt を実行するには、次のルールを使用します。

rustfmt:
  find {{invocation_directory()}} -name \*.rs -exec rustfmt {} \;

別の方法として、コマンドをカレントディレクトリから実行する必要がある場合は、たとえば次のようにします。

build:
  cd {{invocation_directory()}}; ./some_script_that_needs_to_be_run_from_here
  • invocation_directory_native() - just がコマンドを実行する前にディレクトリを変更(chdir)する前の、just が呼び出された時点のカレントディレクトリの絶対パスを取得します。
Justfile と Justfile ディレクトリ
  • justfile() - 現在の justfile のパスを取得します。
  • justfile_directory() - 現在の justfile の親ディレクトリのパスを取得します。

たとえば、現在の justfile の場所を基準にコマンドを実行するには、次のようにします。

script:
  {{justfile_directory()}}/scripts/some_script
ソースとソースディレクトリ
  • source_file()1.27.0 - 現在のソースファイルのパスを取得します。
  • source_directory()1.27.0 - 現在のソースファイルの親ディレクトリのパスを取得します。

ルートの justfile では、source_file() と source_directory() は justfile() と justfile_directory() と同じように動作します。ただし、インポートまたはサブモジュール内から呼び出した場合は、それぞれ現在の import または mod のソースファイルのパスとディレクトリを返します。

Just 実行ファイル
  • just_executable() - just 実行ファイルの絶対パスです。

たとえば、次のようにします。

executable:
  @echo The executable is at: {{just_executable()}}
$ just
The executable is at: /bin/just
Just プロセス ID
  • just_pid() - just 実行ファイルのプロセス ID です。

たとえば、次のようにします。

pid:
  @echo The process ID is: {{ just_pid() }}
$ just
The process ID is: 420
文字列操作
  • append(suffix, s)1.27.0 s 内の空白区切り文字列に suffix を追加します。append('/src', 'foo bar baz') → 'foo/src bar/src baz/src'
  • prepend(prefix, s)1.27.0 s 内の空白区切り文字列の先頭に prefix を追加します。prepend('src/', 'foo bar baz') → 'src/foo src/bar src/baz'
  • encode_uri_component(s)1.27.0 - [A-Za-z0-9_.!~*'()-] を除く s 内の文字をパーセントエンコードします。JavaScript の encodeURIComponent 関数と同じ動作です。
  • quote(s) - すべてのシングルクォートを '\'' に置き換え、s の前後にシングルクォートを追加します。これは、多くのシェル(Bourne shell の派生シェルの大半を含む)で特殊文字をエスケープするのに十分です。
  • replace(s, from, to) - s 内のすべての from を to に置き換えます。
  • replace_regex(s, regex, replacement) - s 内の regex に一致する部分をすべて replacement に置き換えます。正規表現には Rust の regex クレートを使用します。使用例については、構文ドキュメントを参照してください。キャプチャグループをサポートしています。replacement 文字列には置換文字列の構文を使用します。
  • trim(s) - s の先頭と末尾の空白を削除します。
  • trim_end(s) - s の末尾の空白を削除します。
  • trim_end_match(s, substring) - substring に一致する s の末尾部分を削除します。
  • trim_end_matches(s, substring) - substring に一致する s の末尾部分を繰り返し削除します。
  • trim_start(s) - s の先頭の空白を削除します。
  • trim_start_match(s, substring) - substring に一致する s の先頭部分を削除します。
  • trim_start_matches(s, substring) - substring に一致する s の先頭部分を繰り返し削除します。
大文字・小文字の変換
  • capitalize(s)1.7.0 - s の先頭文字を大文字にし、 残りを小文字に変換します。
  • kebabcase(s)1.7.0 - s を kebab-case に変換します。
  • lowercamelcase(s)1.7.0 - s を lowerCamelCase に変換します。
  • lowercase(s) - s を小文字に変換します。
  • shoutykebabcase(s)1.7.0 - s を SHOUTY-KEBAB-CASE に変換します。
  • shoutysnakecase(s)1.7.0 - s を SHOUTY_SNAKE_CASE に変換します。
  • snakecase(s)1.7.0 - s を snake_case に変換します。
  • titlecase(s)1.7.0 - s を Title Case に変換します。
  • uppercamelcase(s)1.7.0 - s を UpperCamelCase に変換します。
  • uppercase(s) - s を大文字に変換します。
パス操作
失敗する可能性がある関数
  • absolute_path(path) - 作業ディレクトリ内の相対パス path に対する絶対パスです。 ディレクトリ /foo での absolute_path("./bar.txt") は /foo/bar.txt です。
  • canonicalize(path)1.24.0 - シンボリックリンクを解決し、可能な場合は ., .. および余分な / を取り除いて、path を正規化します。
  • extension(path) - path の拡張子です。extension("/foo/bar.txt") は txt です。
  • file_name(path) - 先頭のディレクトリ部分をすべて取り除いた path のファイル名です。 file_name("/foo/bar.txt") は bar.txt です。
  • file_stem(path) - 拡張子を除いた path のファイル名です。 file_stem("/foo/bar.txt") は bar です。
  • parent_directory(path) - path の親ディレクトリです。 parent_directory("/foo/bar.txt") は /foo です。
  • without_extension(path) - 拡張子を除いた path です。 without_extension("/foo/bar.txt") は /foo/bar です。

たとえば、パスに拡張子がない場合など、これらの関数は失敗することがあり、 その場合は実行が停止します。

失敗しない関数
  • clean(path) - 余分なパス区切り文字、中間の . 要素、および可能な場合は .. を取り除いて path を簡潔にします。clean("foo//bar") は foo/bar、clean("foo/..") は .、clean("foo/./bar") は foo/bar です。
  • join(a, b…) - この関数は Unix では /、Windows では \ を使うため、 望ましくない動作につながる場合があります。特に Windows で \ が必要な場合を除き、 常に / を使う / 演算子(例:a / b)を代わりに使うことを検討してください。 パス a と パス b を結合します。join("foo/bar", "baz") は foo/bar/baz です。2 つ以上の引数を受け取ります。
ファイルシステムへのアクセス
  • path_exists(path) - パスが既存のエンティティを指している場合は true、そうでない場合は false を返します。 シンボリックリンクをたどり、パスにアクセスできない場合や、リンク先のないシンボリックリンクを指している場合は false を返します。
  • read(path)1.39.0 - path にあるファイルの内容を文字列として返します。
エラー報告
  • error(message) - 実行を中止し、エラー message をユーザーに報告します。
UUID とハッシュの生成
  • blake3(string)1.25.0 - string の BLAKE3 ハッシュを16進数文字列として返します。
  • blake3_file(path)1.25.0 - path にあるファイルの BLAKE3 ハッシュを16進数 文字列として返します。
  • sha256(string) - string の SHA-256 ハッシュを16進数文字列として返します。
  • sha256_file(path) - path にあるファイルの SHA-256 ハッシュを16進数 文字列として返します。
  • uuid() - バージョン 4 のランダムな UUID を生成します。
ランダム
  • choose(n, alphabet)1.27.0 - alphabet からランダムに選んだ文字を n 個並べた文字列を生成します。 alphabet に同じ文字を複数含めることはできません。たとえば、choose('64', HEX) は 64 文字のランダムな小文字の16進数文字列を生成します。
日時
  • datetime(format)1.30.0 - format に従った現地時刻を返します。
  • datetime_utc(format)1.30.0 - format に従った UTC 時刻を返します。

datetime と datetime_utc の引数は、strftime 形式のフォーマット文字列です。 詳細については、 chrono ライブラリのドキュメント を参照してください。

セマンティックバージョン
  • semver_matches(version, requirement)1.16.0 - セマンティック version(例:"0.1.0")が requirement(例:">=0.1.0")に一致するか確認し、一致する場合は "true"、それ以外の場合は"false"を返します。
スタイル
  • style(name)1.37.0 - justで使用される、名前付きのターミナル表示属性 エスケープシーケンスを返します。標準的な色やスタイルを含むターミナル表示属性の エスケープシーケンス定数とは異なり、style(name)はjust自体が使用する エスケープシーケンスを返し、レシピの出力をjust独自の出力に合わせるために 使用できます。

    nameに指定できる値は、エコーされるレシピ行を表す'command'、error、 warningです。

    たとえば、エラーメッセージにスタイルを適用するには、次のようにします。

    scary:
      @echo '{{ style("error") }}OH NO{{ NORMAL }}'
    
ユーザーディレクトリ1.23.0

これらの関数は、設定、データ、キャッシュ、実行ファイル、ユーザーのホーム ディレクトリなどの、ユーザー固有のディレクトリへのパスを返します。

Unixでは、これらの関数は XDG Base Directory Specificationに 従います。

MacOSとWindowsでは、これらの関数はシステムで指定されたユーザー固有の ディレクトリを返します。たとえば、cache_directory()はMacOSでは ~/Library/Cachesを、Windowsでは{FOLDERID_LocalAppData}を返します。

詳しくは、dirsクレートを ご覧ください。

  • cache_directory() - ユーザー固有のキャッシュディレクトリ。
  • config_directory() - ユーザー固有の設定ディレクトリ。
  • config_local_directory() - ローカルのユーザー固有の設定ディレクトリ。
  • data_directory() - ユーザー固有のデータディレクトリ。
  • data_local_directory() - ローカルのユーザー固有のデータディレクトリ。
  • executable_directory() - ユーザー固有の実行ファイルディレクトリ。
  • home_directory() - ユーザーのホームディレクトリ。

すべてのプラットフォームでXDGベースディレクトリを使用したい場合は、適切な 環境変数とフォールバックを指定してenv(…)関数を使用できます。ただし、XDG 仕様では絶対パスでないパスを無視する必要があるため、仕様に準拠した アプリケーションとの完全な互換性を確保するには、次のようにする必要があります。

xdg_config_dir := if env('XDG_CONFIG_HOME', '') =~ '^/' {
  env('XDG_CONFIG_HOME')
} else {
  home_directory() / '.config'
}
定数

いくつかの定数があらかじめ定義されています。

名前値Windows での値
HEX1.27.0"0123456789abcdef"
HEXLOWER1.27.0"0123456789abcdef"
HEXUPPER1.27.0"0123456789ABCDEF"
PATH_SEP1.41.0"/""\"
PATH_VAR_SEP1.41.0":"";"
CLEAR1.37.0"\ec"
NORMAL1.37.0"\e[0m"
BOLD1.37.0"\e[1m"
ITALIC1.37.0"\e[3m"
UNDERLINE1.37.0"\e[4m"
INVERT1.37.0"\e[7m"
HIDE1.37.0"\e[8m"
STRIKETHROUGH1.37.0"\e[9m"
BLACK1.37.0"\e[30m"
RED1.37.0"\e[31m"
GREEN1.37.0"\e[32m"
YELLOW1.37.0"\e[33m"
BLUE1.37.0"\e[34m"
MAGENTA1.37.0"\e[35m"
CYAN1.37.0"\e[36m"
WHITE1.37.0"\e[37m"
BG_BLACK1.37.0"\e[40m"
BG_RED1.37.0"\e[41m"
BG_GREEN1.37.0"\e[42m"
BG_YELLOW1.37.0"\e[43m"
BG_BLUE1.37.0"\e[44m"
BG_MAGENTA1.37.0"\e[45m"
BG_CYAN1.37.0"\e[46m"
BG_WHITE1.37.0"\e[47m"
@foo:
  echo {{HEX}}
$ just foo
0123456789abcdef

\eで始まる定数は、 ANSI エスケープシーケンスです。

CLEARは、clearコマンドと同様に画面をクリアします。それ以外は \e[Nmの形式で、Nは整数であり、端末の表示属性を設定します。

端末の表示属性を指定するエスケープシーケンスは組み合わせて使用できます。たとえば、文字の太さをBOLD、文字のスタイルをSTRIKETHROUGH、前景色をCYAN、背景色をBG_BLUEに設定できます。端末の表示を通常の状態に戻すには、その後にNORMALを指定してください。

エスケープシーケンスは引用符で囲んでください。一部のシェルでは[が特殊文字として扱われるためです。

@foo:
  echo '{{BOLD + STRIKETHROUGH + CYAN + BG_BLUE}}Hi!{{NORMAL}}'
属性

レシピ、mod 文、エイリアスには、その動作を変更する属性を注釈として付けられます。

名前型説明
[arg(ARG, help="HELP")]1.46.0recipe使用方法のメッセージで、ARG のヘルプ文字列 HELP を表示します。
[arg(ARG, long="LONG")]1.46.0recipe引数 ARG の値を --LONG オプションとして渡すことを必須にします。
[arg(ARG, short="S")]1.46.0recipe引数 ARG の値を短縮形の -S オプションとして渡すことを必須にします。
[arg(ARG, value="VALUE")]1.46.0recipeオプション ARG を、値を取らないフラグにします。
[arg(ARG, pattern="PATTERN")]1.45.0recipe引数 ARG の値が正規表現 PATTERN に一致することを必須にします。
[confirm]1.17.0recipeレシピを実行する前に確認を必須にします。
[confirm(PROMPT)]1.23.0recipeカスタムプロンプトを使い、レシピを実行する前に確認を必須にします。
[default]1.43.0recipeレシピをモジュールのデフォルトレシピとして使用します。
[doc(DOC)]1.27.0module, recipeレシピまたはモジュールのドキュメントコメントをDOCに設定します。
[extension(EXT)]1.32.0recipeシバン付きレシピスクリプトのファイル拡張子をEXTに設定します。ピリオドを付ける場合はEXTに含めてください。
[group(NAME)]1.27.0module, recipeレシピまたはモジュールをグループ NAME に配置します。
[linux]1.8.0recipeLinux でレシピを有効にします。
[macos]1.8.0recipeMacOS でレシピを有効にします。
[metadata(METADATA)]1.42.0recipeMETADATA をレシピに付与します。
[no-cd]1.9.0recipeレシピを実行する前にディレクトリを変更しません。
[no-exit-message]1.7.0recipeレシピが失敗してもエラーメッセージを表示しません。
[no-quiet]1.23.0recipeグローバルに静かなレシピの設定を上書きし、レシピを常に表示します。
[openbsd]1.38.0recipeOpenBSD でレシピを有効にします。
[parallel]1.42.0recipeこのレシピの依存関係を並列実行します。
[positional-arguments]1.29.0recipeこのレシピで位置引数を有効にします。
[private]1.10.0alias, recipeレシピ、エイリアス、または変数を非公開にします。非公開レシピを参照してください。
[script]1.33.0recipeレシピをスクリプトとして実行します。詳しくはスクリプトレシピを参照してください。
[script(COMMAND)]1.32.0recipeCOMMAND で解釈されるスクリプトとしてレシピを実行します。詳しくはスクリプトレシピを参照してください。
[unix]1.8.0recipeUnix 系 OS でレシピを有効にします。(MacOS を含みます。)
[windows]1.8.0recipeWindows でレシピを有効にします。
[working-directory(PATH)]1.38.0recipeレシピの作業ディレクトリを設定します。PATH は相対パスまたは絶対パスを指定できます。相対パスの場合は、デフォルトの作業ディレクトリを基準に解釈されます。

レシピには、複数行にわたって複数の属性を指定できます。

[no-cd]
[private]
foo:
    echo "foo"

または、1 行にカンマ区切りで指定できます1.14.0。

[no-cd, private]
foo:
    echo "foo"

引数が 1 つの属性は、コロンを使って記述できます。

[group: 'bar']
foo:
レシピの有効化と無効化1.8.0

[linux]、[macos]、[unix]、[windows] 属性は、構成属性です。デフォルトでは、レシピは常に有効です。構成属性が 1 つ以上付いたレシピは、その構成のいずれかが有効な場合にのみ有効になります。

これを使うと、実行するオペレーティングシステムに応じて動作が異なるjustfileを記述できます。このjustfileのrunレシピは、オペレーティングシステムに応じて異なる C コンパイラを使い、そのコンパイラに適した出力バイナリ名でmain.cをコンパイルして実行します。

[unix]
run:
  cc main.c
  ./a.out

[windows]
run:
  cl main.c
  main.exe
ディレクトリの変更を無効にする1.9.0

just は通常、justfile があるディレクトリをカレントディレクトリに設定してレシピを実行します。[no-cd] 属性を使うと、この動作を無効にできます。これにより、呼び出し元のディレクトリからの相対パスを使うレシピや、カレントディレクトリを操作するレシピを作成できます。

たとえば、次の commit レシピは、

[no-cd]
commit file:
  git add {{file}}
  git commit

[no-cd] によって commit の実行時に just がカレントディレクトリを変更しないため、カレントディレクトリからの相対パスを使用できます。

レシピの実行に確認を求める1.17.0

just は通常、エラーが発生しない限り、すべてのレシピを実行します。[confirm] 属性を使うと、実行前にターミナルで確認を求めるレシピを指定できます。just に --yes を渡すと、この設定を上書きでき、属性が指定されたすべてのレシピが自動的に確認済みになります。

確認を求めるレシピに依存するレシピは、依存先のレシピが確認されなかった場合、実行されません。また、確認を求めるレシピの後に渡されたレシピも実行されません。

[confirm]
delete-all:
  rm -rf *
確認プロンプトをカスタマイズする1.23.0

デフォルトの確認プロンプトは、[confirm(PROMPT)] で上書きできます。

[confirm("Are you sure you want to delete everything?")]
delete-everything:
  rm -rf *
グループ

レシピとモジュールには、1つ以上のグループ名を指定できます。

[group('lint')]
js-lint:
    echo 'Running JS linter…'

[group('rust recipes')]
[group('lint')]
rust-lint:
    echo 'Running Rust linter…'

[group('lint')]
cpp-lint:
  echo 'Running C++ linter…'

# not in any group
email-everyone:
    echo 'Sending mass email…'

レシピはグループごとに一覧表示されます。

$ just --list
Available recipes:
    email-everyone # not in any group

    [lint]
    cpp-lint
    js-lint
    rust-lint

    [rust recipes]
    rust-lint

just --list --unsorted を実行すると、各グループ内で justfile に記述された順序でレシピが表示されます。

$ just --list --unsorted
Available recipes:
    (no group)
    email-everyone # not in any group

    [lint]
    js-lint
    rust-lint
    cpp-lint

    [rust recipes]
    rust-lint

--groups を使うと、グループを一覧表示できます。

$ just --groups
Recipe groups:
  lint
  rust recipes

just --groups --unsorted を使うと、justfile に記述された順序でグループが表示されます。

バッククォートを使ったコマンドの評価

バッククォートを使うと、コマンドの結果を保存できます。

localhost := `dumpinterfaces | cut -d: -f2 | sed 's/\/.*//' | sed 's/ //g'`

serve:
  ./serve {{localhost}} 8080

3つのバッククォートで区切られたインデント付きのバッククォートは、インデント付き文字列と同じ方法でインデントが除去されます。

# This backtick evaluates the command `echo foo\necho bar\n`, which produces the value `foo\nbar\n`.
stuff := ```
    echo foo
    echo bar

See the [Strings](#strings) section for details on unindenting.

Backticks may not start with `#!`. This syntax is reserved for a future
upgrade.

The [`shell(…)` function](#external-commands) provides a more general mechanism
to invoke external commands, including the ability to execute the contents of a
variable as a command, and to pass arguments to a command.

### Conditional Expressions

`if`/`else` expressions evaluate different branches depending on if two
expressions evaluate to the same value:

```just
foo := if "2" == "2" { "Good!" } else { "1984" }

bar:
  @echo "{{foo}}"
$ just bar
Good!

不等しいかどうかを判定することもできます。

foo := if "hello" != "goodbye" { "xyz" } else { "abc" }

bar:
  @echo {{foo}}
$ just bar
xyz

また、正規表現に一致するかどうかも判定できます。

foo := if "hello" =~ 'hel+o' { "match" } else { "mismatch" }

bar:
  @echo {{foo}}
$ just bar
match

正規表現には regex クレートが使われており、構文は docs.rsに記載されています。正規表現では バックスラッシュのエスケープシーケンスをよく使うため、スラッシュがそのまま正規表現パーサーに渡される単一引用符の文字列リテラルの使用を検討してください。

条件式は短絡評価されるため、いずれか一方の分岐だけが評価されます。この性質を利用すると、実行すべきでない場合にバッククォート式が実行されないようにできます。

foo := if env_var("RELEASE") == "true" { `get-something-from-release-database` } else { "dummy-value" }

条件式はレシピ内でも使用できます。

bar foo:
  echo {{ if foo == "bar" { "hello" } else { "goodbye" } }}

複数の条件式を連結できます。

foo := if "hello" == "goodbye" {
  "xyz"
} else if "a" == "a" {
  "abc"
} else {
  "123"
}

bar:
  @echo {{foo}}
$ just bar
abc
エラーによる実行の停止

error 関数を使うと、実行を停止できます。たとえば、次のようにします。

foo := if "hello" == "goodbye" {
  "xyz"
} else if "a" == "b" {
  "abc"
} else {
  error("123")
}

実行すると、次のエラーが出力されます。

error: Call to function `error` failed: 123
   |
16 |   error("123")
コマンドラインからの変数設定

コマンドラインから変数を上書きできます。

os := "linux"

test: build
  ./test --test {{os}}

build:
  ./build {{os}}
$ just
./build linux
./test --test linux

レシピの前に、NAME=VALUE の形式の引数をいくつでも渡せます。

$ just os=plan9
./build plan9
./test --test plan9

または、--set フラグを使うこともできます。

$ just --set os bsd
./build bsd
./test --test bsd
環境変数の取得と設定
just 変数のエクスポート

export キーワードを前に付けた代入は、環境変数としてレシピにエクスポートされます。

export RUST_BACKTRACE := "1"

test:
  # will print a stack trace if it crashes
  cargo test

$ を前に付けたパラメーターは、環境変数としてエクスポートされます。

test $RUST_BACKTRACE="1":
  # will print a stack trace if it crashes
  cargo test

エクスポートされた変数とパラメーターは、同じスコープ内のバッククォートにはエクスポートされません。

export WORLD := "world"
# This backtick will fail with "WORLD: unbound variable"
BAR := `echo hello $WORLD`
# Running `just a foo` will fail with "A: unbound variable"
a $A $B=`echo $A`:
  echo $A $B

export が設定されている場合、すべての just 変数が環境変数としてエクスポートされます。

環境変数のエクスポートを解除する1.29.0

環境変数は unexport キーワードを使ってエクスポートを解除できます。

unexport FOO

@foo:
  echo $FOO
$ export FOO=bar
$ just foo
sh: FOO: unbound variable
環境から環境変数を取得する

環境にある環境変数は、自動的にレシピに渡されます。

print_home_folder:
  echo "HOME is: '${HOME}'"
$ just
HOME is '/home/myuser'
環境変数から just 変数を設定する

env() 関数を使うと、環境変数を just 変数に渡すことができます。 環境変数を参照してください。

レシピのパラメーター

レシピにはパラメーターを設定できます。ここでは、レシピ build に target というパラメーターを設定しています。

build target:
  @echo 'Building {{target}}…'
  cd {{target}} && make

コマンドラインから引数を渡すには、レシピ名の後に指定します。

$ just build my-awesome-project
Building my-awesome-project…
cd my-awesome-project && make

依存関係に引数を渡すには、引数とともに依存関係をかっこで囲みます。

default: (build "main")

build target:
  @echo 'Building {{target}}…'
  cd {{target}} && make

依存関係には、変数を引数として渡すこともできます。

target := "main"

_build version:
  @echo 'Building {{version}}…'
  cd {{version}} && make

build: (_build target)

コマンドの引数を依存関係に渡すには、引数とともに依存関係をかっこで囲みます。

build target:
  @echo "Building {{target}}…"

push target: (build target)
  @echo 'Pushing {{target}}…'

パラメーターにはデフォルト値を指定できます。

default := 'all'

test target tests=default:
  @echo 'Testing {{target}}:{{tests}}…'
  ./test --tests {{tests}} {{target}}

デフォルト値が指定されているパラメーターは省略できます。

$ just test server
Testing server:all…
./test --tests all server

または、値を指定できます。

$ just test server unit
Testing server:unit…
./test --tests unit server

デフォルト値には任意の式を指定できますが、+、&&、||、または / 演算子を含む式はかっこで囲む必要があります。

arch := "wasm"

test triple=(arch + "-unknown-unknown") input=(arch / "input.dat"):
  ./test {{triple}}

レシピの最後のパラメーターには可変長パラメーターを指定できます。引数名の前に + または * を付けて示します。

backup +FILES:
  scp {{FILES}} [email protected]:

+ を付けた可変長パラメーターは、1 個以上の引数を受け取り、スペースで区切った引数を含む文字列に展開されます。

$ just backup FAQ.md GRAMMAR.md
scp FAQ.md GRAMMAR.md [email protected]:
FAQ.md                  100% 1831     1.8KB/s   00:00
GRAMMAR.md              100% 1666     1.6KB/s   00:00

* を付けた可変長パラメーターは、0 個以上の引数を受け取り、スペースで区切った引数を含む文字列に展開されます。引数がない場合は空の文字列になります。

commit MESSAGE *FLAGS:
  git commit {{FLAGS}} -m "{{MESSAGE}}"

可変長パラメーターにもデフォルト値を指定できます。コマンドラインから渡された引数は、デフォルト値より優先されます。

test +FLAGS='-q':
  cargo test {{FLAGS}}

{{…}} の置換結果にスペースが含まれる場合は、引用符で囲む必要があります。たとえば、次のレシピがあるとします。

search QUERY:
  lynx https://www.google.com/?q={{QUERY}}

次のように入力すると、

$ just search "cat toupee"

just はコマンド lynx https://www.google.com/?q=cat toupee を実行します。これは sh によって lynx、https://www.google.com/?q=cat、toupee として解析されますが、意図した lynx と https://www.google.com/?q=cat toupee にはなりません。

引用符を追加すれば解決できます。

search QUERY:
  lynx 'https://www.google.com/?q={{QUERY}}'

$ を付けたパラメーターは、環境変数としてエクスポートされます。

foo $bar:
  echo $bar

[arg("name", pattern="pattern")] 属性を使うと、パラメーターが正規表現パターンに一致するよう制約できます1.45.0。

[arg('n', pattern='\d+')]
double n:
  echo $(({{n}} * 2))

パターンの先頭には ^、末尾には $ が追加されるため、引数の値全体が一致する必要があります。

| 演算子を使うと、複数の選択肢にパターンを制約できます。

[arg('flag', pattern='--help|--version')]
info flag:
  just {{flag}}

正規表現には Rust の regex クレートが使われます。使用例については 構文のドキュメントを参照してください。

--usage サブコマンドを使うと、レシピの使用方法を表示できます1.46.0。

$ just --usage foo
Usage: just foo [OPTIONS] bar

Arguments:
  bar

[arg(ARG, help=HELP)] 属性を使うと、引数にヘルプ文字列を追加できます。

[arg("bar", help="hello")]
foo bar:
$ just --usage foo
Usage: just foo bar

Arguments:
  bar hello
レシピのフラグとオプション

レシピのパラメーターは、デフォルトでは位置引数です。

この justfile では:

@foo bar:
  echo bar={{bar}}

パラメーター bar は位置引数です:

$ just foo hello
bar=hello

[arg(ARG, long=OPTION)]1.46.0 属性を使用すると、パラメーターをロングオプションにできます。

この justfile では:

[arg("bar", long="bar")]
foo bar:

パラメーター bar は --bar オプションで指定します:

$ just foo --bar hello
bar=hello

オプションは --name=value 構文でも渡せます:

$ just foo --bar=hello
bar=hello

long の値は省略できます。省略した場合、オプションはパラメーター名をデフォルトとして使用します:

[arg("bar", long)]
foo bar:

[arg(ARG, short=OPTION)]1.46.0 属性を使用すると、パラメーターをショートオプションにできます。

この justfile では:

[arg("bar", short="b")]
foo bar:

パラメーター bar は -b オプションで指定します:

$ just foo -b hello
bar=hello

パラメーターにロングオプションとショートオプションの両方がある場合、どちらを使っても指定できます。

可変長の + および ? パラメーターはオプションにできません。

[arg(ARG, value=VALUE, …)]1.46.0 属性は、long または short と併用すると、値を取らないフラグにパラメーターをできます。

この justfile では:

[arg("bar", long="bar", value="hello")]
foo bar:

パラメーター bar は --bar オプションで指定しますが、値は取らず、代わりに [arg] 属性で指定された値を使用します:

$ just foo --bar
bar=hello

これは、危険なコマンドで --force のようなフラグを常に必須にしたい場合に便利です。

パラメーターにデフォルト値がある場合、フラグは省略可能です:

[arg("bar", long="bar", value="hello")]
foo bar="goodbye":

呼び出し時に渡されなかった場合は、デフォルト値が設定されます:

$ just foo
bar=goodbye
依存関係

依存関係は、それに依存するレシピより先に実行されます:

a: b
  @echo A

b:
  @echo B
$ just a
B
A

just の同じ呼び出し内では、同じ引数を持つレシピは、コマンドラインで何回指定されているか、または依存関係として何回指定されているかにかかわらず、一度だけ実行されます:

a:
  @echo A

b: a
  @echo B

c: a
  @echo C
$ just a a a a a
A
$ just b c
A
B
C

何らかのセットアップを行うレシピに複数のレシピが依存している場合、それらのレシピを実行すると、セットアップは一度だけ実行されます:

build:
  cc main.c

test-foo: build
  ./a.out --test foo

test-bar: build
  ./a.out --test bar
$ just test-foo test-bar
cc main.c
./a.out --test foo
./a.out --test bar

同じ実行内でレシピがスキップされるのは、同じ引数を受け取る場合に限られます:

build:
  cc main.c

test TEST: build
  ./a.out --test {{TEST}}
$ just test foo test bar
cc main.c
./a.out --test foo
./a.out --test bar
レシピの最後にレシピを実行する

通常の依存関係は、レシピの開始前に必ず実行されます。つまり、依存先は常に依存元より先に実行されます。これらの依存関係は「先行依存関係」と呼ばれます。

レシピには後続依存関係を指定することもでき、これはレシピの直後に実行され、&& で指定します:

a:
  echo 'A!'

b: a && c d
  echo 'B!'

c:
  echo 'C!'

d:
  echo 'D!'

b を実行すると、次のように表示されます:

$ just b
echo 'A!'
A!
echo 'B!'
B!
echo 'C!'
C!
echo 'D!'
D!
レシピの途中でレシピを実行する

just は別のレシピの途中でレシピを実行する機能をサポートしていませんが、レシピの途中で just を再帰的に呼び出すことはできます。次の justfile の場合:

a:
  echo 'A!'

b: a
  echo 'B start!'
  just c
  echo 'B end!'

c:
  echo 'C!'

b を実行すると、次のように表示されます:

$ just b
echo 'A!'
A!
echo 'B start!'
B start!
echo 'C!'
C!
echo 'B end!'
B end!

レシピ c はまったく新しい just の呼び出しで実行されるため、いくつかの制限があります。代入は再計算され、依存関係が二度実行される可能性があり、コマンドライン引数は子の just プロセスに引き継がれません。

Shebang レシピ

#! で始まるレシピは shebang レシピと呼ばれ、レシピ本文をファイルに保存して実行されます。これにより、さまざまな言語でレシピを記述できます。

polyglot: python js perl sh ruby nu

python:
  #!/usr/bin/env python3
  print('Hello from python!')

js:
  #!/usr/bin/env node
  console.log('Greetings from JavaScript!')

perl:
  #!/usr/bin/env perl
  print "Larry Wall says Hi!\n";

sh:
  #!/usr/bin/env sh
  hello='Yo'
  echo "$hello from a shell script!"

nu:
  #!/usr/bin/env nu
  let hello = 'Hola'
  echo $"($hello) from a nushell script!"

ruby:
  #!/usr/bin/env ruby
  puts "Hello from ruby!"
$ just polyglot
Hello from python!
Greetings from JavaScript!
Larry Wall says Hi!
Yo from a shell script!
Hola from a nushell script!
Hello from ruby!

Linux や MacOS などの Unix 系オペレーティングシステムでは、shebang レシピはレシピ本文を一時ディレクトリ内のファイルに保存し、そのファイルに実行権限を付与して実行されます。次に OS は shebang 行をコマンドラインに解析し、ファイルのパスを含めて実行します。たとえば、レシピが #!/usr/bin/env bash で始まる場合、OS が実行する最終的なコマンドは /usr/bin/env bash /tmp/PATH_TO_SAVED_RECIPE_BODY のようになります。

shebang 行の分割方法はオペレーティングシステムによって異なります。引数付きのコマンドを渡す場合、-S フラグを使って env に明示的な分割を指示する必要がある場合があります。

run:
  #!/usr/bin/env -S bash -x
  ls

Windows は shebang 行をサポートしていません。Windows では、just が shebang 行をコマンドと引数に分割し、レシピ本文をファイルに保存して、分割したコマンドと引数を呼び出します。その際、保存したレシピ本文のパスを最後の引数として追加します。たとえば Windows で、レシピが #! py で始まる場合、OS が実行する最終的なコマンドは py C:\Temp\PATH_TO_SAVED_RECIPE_BODY のようになります。

スクリプトレシピ

[script(COMMAND)]1.32.0 属性を持つレシピは、COMMAND によって解釈されるスクリプトとして実行されます。これにより、Windows で cygpath を使う必要があること、/usr/bin/env を使う必要があること、Unix 系 OS 間で shebang 行の分割方法に一貫性がないこと、ファイルを実行できる一時ディレクトリが必要になることなど、shebang レシピに関するいくつかの問題を回避できます。

空の [script] 属性を持つレシピは、set shell の値ではなく、set script-interpreter := […]1.33.0 の値(デフォルトは sh -eu)を使って実行されます。

レシピ本文は評価され、一時ディレクトリ内のディスクに書き込まれ、そのパスを引数として COMMAND に渡すことで実行されます。

スクリプトレシピと Shebang レシピの一時ファイル

スクリプトレシピと shebang レシピはどちらも、実行のためにレシピ本文を一時ファイルに書き込みます。スクリプトレシピはファイルをコマンドに渡して実行しますが、shebang レシピはファイルを直接実行します。一時ファイルを含むファイルシステムが noexec でマウントされている場合、またはその他の理由で実行できない場合、shebang レシピの実行は失敗します。

just が一時ファイルを書き込むディレクトリは、優先順位の高い順に、次の方法で設定できます。

  • --tempdir コマンドラインオプションまたは JUST_TEMPDIR 環境変数を使って、グローバルに設定します1.41.0。
  • tempdir 設定を使って、モジュールごとに設定します。
  • XDG_RUNTIME_DIR 環境変数を使って、Linux 上でグローバルに設定します。
  • 上記のいずれも指定されていない場合は、std::env::temp_dir が返すディレクトリを使います。
uv を使った Python レシピ

uv は、Rust で書かれた優れたクロスプラットフォームの Python プロジェクトマネージャーです。

[script] 属性と script-interpreter 設定を使うと、just を簡単に設定して uv で Python レシピを実行できます。

set unstable

set script-interpreter := ['uv', 'run', '--script']

[script]
hello:
  print("Hello from Python!")

[script]
goodbye:
  # /// script
  # requires-python = ">=3.11"
  # dependencies=["sh"]
  # ///
  import sh
  print(sh.echo("Goodbye from Python!"), end='')

もちろん、shebang も使えます。

hello:
  #!/usr/bin/env -S uv run --script
  print("Hello from Python!")
より安全な Bash Shebang レシピ

bash の shebang レシピを記述する場合は、set -euxo pipefail を追加することを検討してください。

foo:
  #!/usr/bin/env bash
  set -euxo pipefail
  hello='Yo'
  echo "$hello from Bash!"

必須ではありませんが、set -euxo pipefail を設定すると、いくつかの便利な機能が有効になり、bash の shebang レシピが通常の行単位の just レシピに近い動作をするようになります。

  • set -e を指定すると、コマンドが失敗したときに bash が終了します。
  • set -u を指定すると、変数が未定義のときに bash が終了します。
  • set -x を指定すると、bash が各スクリプト行の実行前にその行を出力します。
  • set -o pipefail を指定すると、パイプライン内のコマンドが失敗したときに bash が終了します。これは bash 固有の機能のため、通常の行単位の just レシピでは有効になりません。

これらを組み合わせることで、シェルスクリプトでよくある落とし穴を多数回避できます。

Windows での Shebang レシピの実行

Windows では、/ を含む shebang のインタープリターのパスは、 Cygwin に付属するユーティリティ cygpath を使って、 Unix 形式のパスから Windows 形式のパスに変換されます。

たとえば、Windows でこのレシピを実行するには、次のようにします。

echo:
  #!/bin/sh
  echo "Hello!"

インタープリターのパス /bin/sh は、実行前に cygpath を使って Windows 形式のパスに変換されます。

インタープリターのパスに / が含まれていない場合は、変換せずに実行されます。 この方法は、cygpath が利用できない場合や、Windows 形式のパスをインタープリターに 渡したい場合に便利です。

レシピでの変数の設定

レシピの各行は just ではなくシェルによって解釈されるため、レシピの途中で just の変数を設定することはできません。

foo:
  x := "hello" # This doesn't work!
  echo {{x}}

シェル変数は使用できますが、別の問題があります。レシピの各行は新しいシェル インスタンスで実行されるため、ある行で設定した変数は次の行には引き継がれません。

foo:
  x=hello && echo $x # This works!
  y=bye
  echo $y            # This doesn't, `y` is undefined here!

この問題を回避するには、shebang レシピを使用するのが最善です。shebang レシピの 本文はスクリプトとして取り出されて実行されるため、一つのシェルインスタンスで 全体が実行されます。

foo:
  #!/usr/bin/env bash
  set -euxo pipefail
  x=hello
  echo $x
レシピ間での環境変数の共有

レシピの各行は新しいシェルで実行されるため、レシピ間で環境変数を共有することは できません。

Python 仮想環境の使用

Python の venv のようなツールは、 動作するために環境変数の読み込みが必要なことがあり、just での使用が難しい 場合があります。回避策として、仮想環境のバイナリを直接実行できます。

venv:
  [ -d foo ] || python3 -m venv foo

run: venv
  ./foo/bin/python3 main.py
レシピでの作業ディレクトリの変更

レシピの各行は新しいシェルで実行されるため、ある行で作業ディレクトリを変更しても、 後続の行には影響しません。

foo:
  pwd    # This `pwd` will print the same directory…
  cd bar
  pwd    # …as this `pwd`!

これを回避する方法はいくつかあります。一つは、実行したいコマンドと同じ行で cd を呼び出す方法です。

foo:
  cd bar && pwd

もう一つは、shebang レシピを使用する方法です。shebang レシピの本文はスクリプトとして 取り出されて実行されるため、一つのシェルインスタンスで全体が実行されます。そのため、 シェルスクリプトと同様に、ある行での cd が後続の行に影響します。

foo:
  #!/usr/bin/env bash
  set -euxo pipefail
  cd bar
  pwd
インデント

レシピの行はスペースまたはタブでインデントできますが、両者を混在させることは できません。レシピ内のすべての行で同じ種類のインデントを使用する必要がありますが、 同じ justfile 内の別々のレシピでは異なる種類のインデントを使用できます。

各レシピは recipe-name より少なくとも一段階インデントする必要がありますが、 それよりさらに深くインデントすることもできます。

以下は、スペースを ·、タブを → で表した、スペースとタブでインデントされた レシピを含む justfile です。

set windows-shell := ["pwsh", "-NoLogo", "-NoProfileLoadTime", "-Command"]

set ignore-comments

list-space directory:
··#!pwsh
··foreach ($item in $(Get-ChildItem {{directory}} )) {
····echo $item.Name
··}
··echo ""

# indentation nesting works even when newlines are escaped
list-tab directory:
→ @foreach ($item in $(Get-ChildItem {{directory}} )) { \
→ → echo $item.Name \
→ }
→ @echo ""
PS > just list-space ~
Desktop
Documents
Downloads

PS > just list-tab ~
Desktop
Documents
Downloads
複数行の構文

先頭に shebang のないレシピは行ごとに評価されて実行されるため、複数行の構文は 意図したとおりに動作しないことがあります。

たとえば、次の justfile では、

conditional:
  if true; then
    echo 'True!'
  fi

conditional レシピの2行目の先頭に余分な空白があると、構文解析エラーになります。

$ just conditional
error: Recipe line has extra leading whitespace
  |
3 |         echo 'True!'
  |     ^^^^^^^^^^^^^^^^

回避するには、条件文を一行に記述するか、スラッシュで改行をエスケープするか、 レシピに shebang を追加します。参考として、複数行の構文の例をいくつか示します。

if 文
conditional:
  if true; then echo 'True!'; fi
conditional:
  if true; then \
    echo 'True!'; \
  fi
conditional:
  #!/usr/bin/env sh
  if true; then
    echo 'True!'
  fi
for ループ
for:
  for file in `ls .`; do echo $file; done
for:
  for file in `ls .`; do \
    echo $file; \
  done
for:
  #!/usr/bin/env sh
  for file in `ls .`; do
    echo $file
  done
while ループ
while:
  while `server-is-dead`; do ping -c 1 server; done
while:
  while `server-is-dead`; do \
    ping -c 1 server; \
  done
while:
  #!/usr/bin/env sh
  while `server-is-dead`; do
    ping -c 1 server
  done
レシピ本文の外側

括弧で囲まれた式は複数行にまたがることができます。

abc := ('a' +
        'b'
         + 'c')

abc2 := (
  'a' +
  'b' +
  'c'
)

foo param=('foo'
      + 'bar'
    ):
  echo {{param}}

bar: (foo
        'Foo'
     )
  echo 'Bar!'

バックスラッシュで終わる行は、空白で結合されたかのように次の行へ続きます 1.15.0。

a := 'foo' + \
     'bar'

foo param1 \
  param2='foo' \
  *varparam='': dep1 \
                (dep2 'foo')
  echo {{param1}} {{param2}} {{varparam}}

dep1: \
    # this comment is not part of the recipe body
  echo 'dep1'

dep2 \
  param:
    echo 'Dependency with parameter {{param}}'

バックスラッシュによる行継続は、補間内でも使用できます。バックスラッシュの次の行は インデントする必要があります。

recipe:
  echo '{{ \
  "This interpolation " + \
    "has a lot of text." \
  }}'
  echo 'back to recipe body'
コマンドラインオプション

just は、レシピや変数の一覧表示、ダンプ、デバッグに役立つさまざまな コマンドラインオプションをサポートしています。

$ just --list
Available recipes:
  js
  perl
  polyglot
  python
  ruby
$ just --show perl
perl:
  #!/usr/bin/env perl
  print "Larry Wall says Hi!\n";
$ just --show polyglot
polyglot: python js perl sh ruby
環境変数によるコマンドラインオプションの設定

一部のコマンドラインオプションは、環境変数で設定できます。

たとえば、不安定な機能は --unstable フラグで有効にできます。

$ just --unstable

または、JUST_UNSTABLE 環境変数を設定することでも有効にできます。

$ export JUST_UNSTABLE=1
$ just

環境変数は子プロセスに継承されるため、環境変数で設定したコマンドライン オプションは just の再帰的な呼び出しにも継承されます。一方、 引数で設定したコマンドラインオプションは継承されません。

環境変数で設定できるオプションについては、just --help を参照してください。

プライベートレシピ

名前が _ で始まるレシピとエイリアスは、just --list で省略されます。

test: _test-helper
  ./bin/test

_test-helper:
  ./bin/super-secret-test-helper-stuff
$ just --list
Available recipes:
    test

また、just --summary でも省略されます。

$ just --summary
test

[private] 属性1.10.0を使うと、名前を変更せずにレシピや エイリアスを非表示にすることもできます。

[private]
foo:

[private]
alias b := bar

bar:
$ just --list
Available recipes:
    bar

これは、ほかのレシピの依存関係としてのみ使用するヘルパーレシピに便利です。

静かなレシピ

レシピ名の前に @ を付けると、各行の前にある @ の意味が反転します。

@quiet:
  echo hello
  echo goodbye
  @# all done!

これで、@ で始まる行だけが表示されます。

$ just quiet
hello
goodbye
# all done!

Justfile 内のすべてのレシピを静かにするには、set quiet を設定します。

set quiet

foo:
  echo "This is quiet"

@foo2:
  echo "This is also quiet"

[no-quiet] 属性はこの設定を上書きします。

set quiet

foo:
  echo "This is quiet"

[no-quiet]
foo2:
  echo "This is not quiet"

シバンレシピはデフォルトで静かです。

foo:
  #!/usr/bin/env bash
  echo 'Foo!'
$ just foo
Foo!

シバンレシピ名に @ を付けると、実行前に just がレシピを表示します。

@bar:
  #!/usr/bin/env bash
  echo 'Bar!'
$ just bar
#!/usr/bin/env bash
echo 'Bar!'
Bar!

通常、レシピの行が失敗すると、just はエラーメッセージを表示します。このエラーメッセージは、[no-exit-message]1.7.0 属性を使って抑制できます。ツールをラップするレシピで特に便利です。

git *args:
    @git {{args}}
$ just git status
fatal: not a git repository (or any of the parent directories): .git
error: Recipe `git` failed on line 2 with exit code 128

ツールがゼロ以外のコードで終了したときに終了エラーメッセージを抑制するには、この属性を追加します。

[no-exit-message]
git *args:
    @git {{args}}
$ just git status
fatal: not a git repository (or any of the parent directories): .git
インタラクティブな選択ツールで実行するレシピを選択する

--choose サブコマンドを使うと、just が選択ツールを呼び出し、実行するレシピを選択できます。選択ツールは、標準入力からレシピ名を含む行を読み取り、そのうち1つ以上の名前をスペース区切りで標準出力に出力する必要があります。

現在、--choose では引数が必要なレシピを実行する方法がないため、そのようなレシピは選択ツールに渡されません。プライベートレシピとエイリアスもスキップされます。

選択ツールは --chooser フラグで指定できます。--chooser が指定されていない場合、just はまず $JUST_CHOOSER が設定されているか確認します。設定されていない場合は、人気のあるあいまい検索ツールである fzf がデフォルトになります。

fzf --exact のように、選択ツールに引数を含めることができます。

選択ツールはレシピの行と同じ方法で呼び出されます。たとえば、選択ツールが fzf の場合は sh -cu 'fzf' で呼び出されます。また、シェルまたはシェルの引数が上書きされている場合、選択ツールの呼び出しにもその設定が適用されます。

just で選択ツールによるレシピ選択をデフォルトにしたい場合は、次のようにデフォルトレシピを設定できます。

default:
  @just --choose
別のディレクトリにある justfile の呼び出し

just に渡す最初の引数に / が含まれている場合、次の処理が行われます。

  1. 引数は最後の / で分割されます。
  2. 最後の / より前の部分はディレクトリとして扱われます。just は現在のディレクトリではなく、そのディレクトリから justfile の検索を開始します。
  3. 最後のスラッシュより後の部分は通常の引数として扱われます。空の場合は無視されます。

少し奇妙に思えるかもしれませんが、サブディレクトリにある justfile のコマンドを実行したい場合に便利です。

たとえば、foo というサブディレクトリを含むディレクトリにいて、そのサブディレクトリに build レシピを含む justfile があり、build がデフォルトレシピでもある場合、次のコマンドはすべて同じ結果になります。

$ (cd foo && just build)
$ just foo/build
$ just foo/

最初のレシピの後に指定された追加のレシピは、同じ justfile から検索されます。たとえば、次のコマンドはどちらも同じ結果になります。

$ just foo/a b
$ (cd foo && just a b)

どちらも foo/justfile のレシピ a と b を呼び出します。

インポート

import 文を使うと、ある justfile に別のファイルの内容を取り込めます。

次の justfile があるとします。

import 'foo/bar.just'

a: b
  @echo A

そして、foo/bar.just に次の内容があるとします。

b:
  @echo B

foo/bar.just は justfile に取り込まれ、レシピ b が定義されます。

$ just b
B
$ just a
B
A

import のパスには、絶対パスまたはそのパスを含む justfile の場所からの相対パスを指定できます。インポートパスの先頭にある ~/ は、現在のユーザーのホームディレクトリに置き換えられます。

justfile では定義の順序は関係ないため、インクルードされたファイルから、import 文の後に定義された変数やレシピを参照できます。

インポートされたファイルに import を含めることもでき、その場合は再帰的に処理されます。

allow-duplicate-recipes と allow-duplicate-variables を指定すると、重複するレシピと変数がそれぞれ互いを上書きできるようになり、エラーは発生しません。

モジュール内では、後の定義が前の定義を上書きします。

set allow-duplicate-recipes

foo:

foo:
  echo 'yes'

import が関わる場合は、残念ながら仕組みがかなり複雑になり、説明も困難です。

浅い階層の定義は常に深い階層の定義を上書きします。そのため、最上位のレシピはインポート内のレシピを上書きし、インポート内のレシピは、そのレシピをインポートするインポート内のレシピを上書きします。

重複する定義がインポートされ、同じ深さにある場合は、後のインポートではなく、先のインポートに含まれる定義が上書きします。

これは、just がインポートの処理にスタックを使い、ソース内の順序でインポートをスタックに積み、常にスタックの先頭を次に処理するためです。その結果、先のインポートがコンパイラーによって実際には後から処理されます。

これは明らかにバグですが、just は非常に強力な後方互換性を保証しており、誰の justfile も壊さないよう細心の注意を払っています。そのため、実際に修正できるかどうかを議論するため、issue #2540 を作成しました。

import キーワードの後に ? を付けると、インポートを任意にできます。

import? 'foo/bar.just'

同じソースファイルを複数回インポートしてもエラーにはなりません1.37.0。これにより、たとえば foo.just と bar.just という複数の justfile が、共通のレシピを含む 3 つ目の justfile(たとえば baz.just)をそれぞれインポートできます。この場合、baz.just の重複インポートはエラーになりません。

# justfile
import 'foo.just'
import 'bar.just'
# foo.just
import 'baz.just'
foo: baz
# bar.just
import 'baz.just'
bar: baz
# baz
baz:
モジュール1.19.0

justfile では、mod 文を使ってモジュールを宣言できます。

mod 文は just1.31.0 で安定化されました。それ以前のバージョンで使うには、--unstable フラグ、set unstable、または JUST_UNSTABLE 環境変数を設定する必要があります。

次の justfile があるとします。

mod bar

a:
  @echo A

そして、bar.just に次の内容があるとします。

b:
  @echo B

bar.just は justfile にサブモジュールとして読み込まれます。あるサブモジュールで定義されたレシピ、エイリアス、変数は、別のサブモジュールでは使用できません。また、各モジュールは独自の設定を使用します。

サブモジュール内のレシピは、サブコマンドとして実行できます。

$ just bar b
B

または、パス構文を使って実行できます。

$ just bar::b
B

モジュール名が foo の場合、just は foo.just、foo/mod.just、foo/justfile、foo/.justfile の順にモジュールファイルを検索します。後者 2 つの場合、モジュールファイルの大文字・小文字は問いません。

モジュール文は、次の形式にもできます。

mod foo 'PATH'

この形式では、通常の場所ではなく、PATH からモジュールのソースファイルを読み込みます。PATH の先頭にある ~/ は、現在のユーザーのホームディレクトリに置き換えられます。PATH はモジュールのソースファイル自体を指すことも、mod.just、justfile、.justfile という名前のモジュールソースファイルを含むディレクトリを指すこともできます。後者 2 つの場合、モジュールファイルの大文字・小文字は問いません。

環境ファイルが読み込まれるのはルートの justfile のみで、読み込まれた環境変数はサブモジュールでも使用できます。環境ファイルの読み込みに影響するサブモジュールの設定は無視されます。

[no-cd] 属性のないサブモジュール内のレシピは、サブモジュールのソースファイルがあるディレクトリを作業ディレクトリとして実行されます。

justfile() と justfile_directory() は、サブモジュール内のレシピから呼び出された場合でも、常にルートの justfile のパスと、そのファイルを含むディレクトリを返します。

mod キーワードの後に ? を付けると、モジュールをオプションにできます。

mod? foo

オプションモジュールのソースファイルが見つからなくても、エラーにはなりません。

ソースファイルのないオプションモジュール同士は競合しないため、ソースファイルのパスが異なり、存在するソースファイルが最大 1 つであれば、同じ名前の mod 文を複数記述できます。

mod? foo 'bar.just'
mod? foo 'baz.just'

モジュールにはドキュメントコメントを付けることができ、--list の出力に表示されます1.30.0。

# foo is a great module!
mod foo
$ just --list
Available recipes:
    foo ... # foo is a great module!

モジュールにはまだ多くの機能が不足しています。たとえば、別のモジュールの変数を参照する機能などです。詳細については、モジュール改善の追跡イシューを参照してください。

justfile を非表示にする

just は justfile と .justfile という名前の justfile を検索します。これを利用すると、justfile を非表示にできます。

Just スクリプト

justfile の先頭に shebang 行を追加し、実行可能にすると、just をスクリプトのインタープリターとして使用できます。

$ cat > script <<EOF
#!/usr/bin/env just --justfile

foo:
  echo foo
EOF
$ chmod +x script
$ ./script foo
echo foo
foo

shebang 付きのスクリプトを実行すると、システムはスクリプトのパスを shebang 内のコマンドに引数として渡します。そのため、shebang が #!/usr/bin/env just --justfile の場合、コマンドは /usr/bin/env just --justfile PATH_TO_SCRIPT になります。

上記の shebang を使うと、just は作業ディレクトリをスクリプトのある場所に変更します。作業ディレクトリを変更しないようにするには、#!/usr/bin/env just --working-directory . --justfile を使います。

注:shebang 行の分割方法は、オペレーティングシステムによって一貫していません。上記の例は macOS でのみテストされています。Linux では、env に -S フラグを渡す必要がある場合があります。

#!/usr/bin/env -S just --justfile

default:
  echo foo
justfile のフォーマットとダンプ

各 justfile には、空白と改行に関する標準的なフォーマットがあります。

現在は不安定な --fmt フラグを使用すると、現在の justfile を標準フォーマットのバージョンで上書きできます。

$ cat justfile
# A lot of blank lines





some-recipe:
  echo "foo"
$ just --fmt --unstable
$ cat justfile
# A lot of blank lines

some-recipe:
    echo "foo"

just --fmt --check --unstable を実行すると、--fmt をチェックモードで実行します。justfile を上書きする代わりに、正しくフォーマットされていれば just は終了コード 0 で終了し、正しくない場合は終了コード 1 で終了して差分を出力します。

--dump コマンドを使用すると、フォーマット済みの justfile を標準出力に出力できます。

$ just --dump > formatted-justfile

--dump コマンドは --dump-format json と併用して、justfile の JSON 表現を出力できます。

親の justfile へのフォールバック

レシピが justfile で見つからず、fallback 設定が有効になっている場合、just は親ディレクトリからルートディレクトリに到達するまで、上位のディレクトリにある justfile を探します。fallback 設定が false または未設定の justfile に到達すると、just は検索を停止します。

たとえば、現在のディレクトリに次の justfile があるとします。

set fallback
foo:
  echo foo

そして、親ディレクトリには次の justfile があるとします。

bar:
  echo bar
$ just bar
Trying ../justfile
echo bar
bar
引数の分割を防ぐ

次の justfile があるとします。

foo argument:
  touch {{argument}}

次のコマンドを実行すると、some と argument.txt の 2 つのファイルが作成されます。

$ just foo "some argument.txt"

ユーザーのシェルは "some argument.txt" を単一の引数として解析しますが、just が touch {{argument}} を touch some argument.txt に置き換える際に、引用符は保持されないため、touch には 2 つの引数が渡されます。

これを防ぐ方法はいくつかあります。引用符、位置引数、エクスポートされた引数です。

引用符

{{argument}} の展開を引用符で囲むことができます。

foo argument:
  touch '{{argument}}'

これにより、たとえば {{argument}} と書いた場合など、実行前に変数名のタイプミスを検出する just の機能が保たれます。ただし、argument の値にシングルクォートが含まれている場合は、期待どおりに動作しません。

位置引数

positional-arguments 設定を有効にすると、すべての引数が位置引数として渡され、$1、$2、…、$@ でアクセスできるようになります。これらを二重引用符で囲むことで、シェルによるさらなる分割を防げます。

set positional-arguments

foo argument:
  touch "$1"

たとえば $1 ではなく $2 と入力した場合など、タイプミスを検出する just の機能は失われますが、二重引用符を含む値も含め、argument のあらゆる値で動作します。

エクスポートされた引数

export 設定を有効にすると、すべての引数がエクスポートされます。

set export

foo argument:
  touch "$argument"

または、個々の引数の前に $ を付けてエクスポートすることもできます。

foo $argument:
  touch "$argument"

たとえば $argument と入力した場合など、タイプミスを検出する just の機能は失われますが、二重引用符を含む値も含め、argument のあらゆる値で動作します。

シェルの設定

レシピが #! シバンで始まらない場合のデフォルトである、行単位のレシピに使用するシェルは、いくつかの方法で設定できます。優先順位は高い順に次のとおりです。

  1. --shell および --shell-arg コマンドラインオプション。いずれかを指定すると、just は現在の justfile 内の設定を無視します。
  2. set windows-shell := [...]
  3. set windows-powershell(非推奨)
  4. set shell := [...]

set windows-shell は set shell より優先順位が高いため、Windows では set windows-shell でシェルを選び、それ以外のすべてのプラットフォームでは set shell でシェルを選べます。

タイムスタンプ

just は各レシピコマンドの前にタイムスタンプを出力できます。

recipe:
  echo one
  sleep 2
  echo two
$ just --timestamp recipe
[07:28:46] echo one
one
[07:28:46] sleep 2
[07:28:48] echo two
two

デフォルトでは、タイムスタンプは HH:MM:SS の形式で出力されます。--timestamp-format で形式を変更できます。

$ just --timestamp recipe --timestamp-format '%H:%M:%S%.3f %Z'
[07:32:11:.349 UTC] echo one
one
[07:32:11:.350 UTC] sleep 2
[07:32:13:.352 UTC] echo two
two

--timestamp-format の引数は strftime 形式のフォーマット文字列です。詳しくは chrono library docs を参照してください。

シグナル処理

シグナルは、特定の動作を引き起こすために実行中のプログラムへ送られるメッセージです。たとえば、CTRL-Cが押されると、端末のフォアグラウンドプロセスグループに属するすべてのプロセスにSIGINTが送られます。

justはシグナルを受け取ると終了しようとしますが、実行中の子プロセスを残さないようにもします。この2つの目標は、ある程度相反します。

justが子プロセスを残して終了すると、ユーザーは子プロセスをps aux | grepで探し、手動でkillするしかありません。これは面倒な作業です。

致命的なシグナル

ユーザーが端末を閉じる、ctrl-cを入力する、またはctrl-\を入力すると、それぞれSIGHUP、SIGINT、SIGQUITが生成され、フォアグラウンドプロセスグループに属するすべてのプロセスに送られます。

SIGTERMはkillコマンドが送るデフォルトのシグナルで、対象のプロセスのみに配信されます。

子プロセスが実行されていない場合、justは上記のいずれかのシグナルを受け取ると、ただちに終了します。

子プロセスが実行中の場合、justは子プロセスを残さないよう、その子プロセスが終了するまで待機します。

さらに、SIGTERMを受け取ると、justは実行中の子プロセスにもSIGTERMを転送します1.41.0</sup。他の致命的なシグナルとは異なり、SIGTERMはjustだけに送られた可能性が高いためです。

justが致命的なシグナルを受け取った後に子プロセスが正常終了するかどうかにかかわらず、justは実行を停止します。

SIGINFO

ユーザーが BSD系の オペレーティングシステム(MacOSなど。ただしLinuxを除く)でctrl-tを入力すると、フォアグラウンドプロセスグループに属するすべてのプロセスにSIGINFOが送られます。

justは、すべての子プロセスのIDとコマンドの一覧を出力して応答します1.41.0</sup。

Windows

Windowsでは、ユーザーがctrl-cを入力すると、justはSIGINTを受け取った場合と同じように動作します。他のシグナルはサポートされていません。

コメント