49 KiB
↖️ 目录
just
just
为您提供一种保存和运行项目特有命令的便捷方式。
本指南同时也可以以 书 的形式在线阅读;
命令,在此也称为配方,存储在一个名为 justfile
的文件中,其语法受 make
启发:
然后你可以用 just RECIPE
运行它们:
$ just test-all
cc *.c -o main
./test --all
Yay, all your tests passed!
just
有很多很棒的特性,而且相比 make
有很多改进:
-
just
是一个命令运行器,而不是一个构建系统,所以它避免了许多make
的复杂性和特异性。不需要.PHONY
配方! -
支持 Linux、MacOS 和 Windows,而且无需额外的依赖。(尽管如果你的系统没有
sh
,你需要 选择一个不同的 Shell)。 -
错误具体且富有参考价值,语法错误将会与产生它们的上下文一起被报告。
-
配方可以接受 命令行参数。
-
错误会尽可能被静态地解决。未知的配方和循环依赖关系会在运行之前被报告。
-
just
可以 加载.env
文件,简化环境变量注入。 -
配方可以在 命令行中列出。
-
命令行自动补全脚本 支持大多数流行的 Shell。
-
配方可以用 任意语言 编写,如 Python 或 NodeJS。
-
just
可以从任何子目录中调用,而不仅仅是包含justfile
的目录。 -
不仅如此,还有 更多!
如果你在使用 just
方面需要帮助,请随时创建一个 Issue 或在Discord上与我联系。我们随时欢迎功能请求和错误报告!
安装
预备知识
just
应该可以在任何有合适的 sh
的系统上运行,包括Linux、MacOS 和 BSD。
在 Windows 上,just
可以使用 Git for Windows、GitHub Desktop 或 Cygwin 所提供的 sh
。
如果你不愿意安装 sh
,也可以使用 shell
设置来指定你要使用的 Shell。
比如 PowerShell:
# 使用 PowerShell 替代 sh:
set shell := ["powershell.exe", "-c"]
hello:
Write-Host "Hello, world!"
…或者 cmd.exe
:
# 使用 cmd.exe 替代 sh:
set shell := ["cmd.exe", "/c"]
list:
dir
你也可以使用命令行参数来设置 Shell。例如,若要使用PowerShell 也可以用 --shell powershell.exe --shell-arg -c
启动just
。
(PowerShell 默认安装在 Windows 7 SP1 和 Windows Server 2008 R2 S1 及更高版本上,而 cmd.exe
相当麻烦,所以PowerShell 被推荐给大多数 Windows 用户)
安装包
操作系统 | 包管理器 | 安装包 | 命令 |
---|---|---|---|
Various | Cargo | just | cargo install just |
Microsoft Windows | Scoop | just | scoop install just |
Various | Homebrew | just | brew install just |
macOS | MacPorts | just | port install just |
Arch Linux | pacman | just | pacman -S just |
Various | Nix | just | nix-env -iA nixpkgs.just |
NixOS | Nix | just | nix-env -iA nixos.just |
Solus | eopkg | just | eopkg install just |
Void Linux | XBPS | just | xbps-install -S just |
FreeBSD | pkg | just | pkg install just |
Alpine Linux | apk-tools | just | apk add just |
Fedora Linux | DNF | just | dnf install just |
Gentoo Linux | Portage | dm9pZCAq overlay: sys-devel/just | eselect repository enable dm9pZCAq && emerge --sync dm9pZCAq && emerge sys-devel/just |
Various | Conda | just | conda install -c conda-forge just |
Microsoft Windows | Chocolatey | just | choco install just |
预制二进制文件
Linux、MacOS 和 Windows 的预制二进制文件可以在 发布页 上找到。
你也可以在 Linux、MacOS 或 Windows 上使用下面的命令来下载最新的版本,只需将 DEST
替换为你想存储 just
的目录:
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to DEST
例如,安装 just
到 ~/bin
目录:
# 创建 ~/bin
mkdir -p ~/bin
# 下载并解压 just 到 ~/bin/just
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to ~/bin
# 在 Shell 搜索可执行文件的路径中添加`~/bin`
# 这一行应该被添加到你的 Shell 初始化文件中,e.g. `~/.bashrc` 或者 `~/.zshrc`:
export PATH="$PATH:$HOME/bin"
# 现在 just 应该就可以执行了
just --help
GitHub Actions
extractions/setup-just 可以用来在 GitHub Actions 的工作流程中安装 just
。
使用举例:
- uses: extractions/setup-just@v1
with:
just-version: 0.8 # optional semver specification, otherwise latest
发布 RSS 订阅
向后兼容性
随着1.0版本的发布,just
突出对向后兼容性和稳定性的强烈承诺。
未来的版本将不会引入向后不兼容的变化,不会使现有的 justfile
停止工作,或破坏命令行界面的正常调用。
然而,这并不排除修复全面的错误,即使这样做可能会破坏依赖其行为的 justfiles
。
永远不会有一个 just
2.0。任何理想的向后兼容的变化都是在每个 justfile
的基础上选择性加入的,所以用户可以在他们的闲暇时间进行迁移。
还没有准备好稳定化的功能将在 --unstable
标志后被选择性启用。由--unstable
启用的功能可能会在任何时候以不兼容的方式发生变化。
编辑器支持
justfile
的语法与 make
非常接近,你可以让你的编辑器对 just
使用 make
语法高亮。
Vim 和 Neovim
vim-just
vim-just 插件可以为 vim 提供 justfile
语法高亮显示。
你可以用你喜欢的软件包管理器安装它,如 Plug:
call plug#begin()
Plug 'NoahTheDuke/vim-just'
call plug#end()
或者使用 Vim 的内置包支持:
mkdir -p ~/.vim/pack/vendor/start
cd ~/.vim/pack/vendor/start
git clone https://github.com/NoahTheDuke/vim-just.git
vim-just
也可以从 vim-polyglot 获得,这是一个多语言的 Vim 插件。
tree-sitter-just
tree-sitter-just 是一个针对 Neovim 的 Nvim Treesitter 插件。
Makefile 语法高亮
Vim 内置的 makefile 语法高亮对 justfile
来说并不完美,但总比没有好。你可以把以下内容放在 ~/.vim/filetype.vim
中:
if exists("did_load_filetypes")
finish
endif
augroup filetypedetect
au BufNewFile,BufRead justfile setf make
augroup END
或者在单个 justfile
中添加以下内容,以在每个文件的基础上启用 make
模式:
# vim: set ft=make :
Emacs
just-mode 可以为 justfile
提供语法高亮和自动缩进。它可以在 MELPA 上通过 just-mode 获得。
justl 提供了执行和列出配方的命令。
你可以在一个单独的 justfile
中添加以下内容,以便对每个文件启用 make
模式:
# Local Variables:
# mode: makefile
# End:
Visual Studio Code
由 skellock 为 VS Code 提供的扩展 可在此获得(仓库)。
你可以通过运行以下命令来安装它:
code --install-extension skellock.just
Kakoune
Kakoune 已经内置支持 justfile
语法高亮,这要感谢 TeddyDD。
Sublime Text
由 TonioGela 编写的 Sublime Text 的语法高亮文件在 extras/just.sublim-syntax 中提供。
其它编辑器
欢迎给我发送必要的命令,以便在你选择的编辑器中实现语法高亮,这样我就可以把它们放在这里。
快速开始
参见 安装部分 了解如何在你的电脑上安装 just
。试着运行 just --version
以确保它被正确安装。
关于语法的概述,请查看这个 速查表。
一旦 just
安装完毕并开始工作,在你的项目根目录创建一个名为 justfile
的文件,内容如下:
recipe-name:
echo 'This is a recipe!'
# 这是一行注释
another-recipe:
@echo 'This is another recipe.'
当你调用 just
时,它会在当前目录和父目录寻找文件 justfile
,所以你可以从你项目的任何子目录中调用它。
搜索 justfile
是不分大小写的,所以任何大小写,如 Justfile
、JUSTFILE
或 JuStFiLe
都可以工作。just
也会寻找名字为 .justfile
的文件,以便你打算隐藏一个 justfile
。
运行 just
时未传参数,则运行 justfile
中的第一个配方:
$ just
echo 'This is a recipe!'
This is a recipe!
通过一个或多个参数指定要运行的配方:
$ just another-recipe
This is another recipe.
just
在运行每条命令前都会将其打印到标准错误中,这就是为什么 echo 'This is a recipe!'
被打印出来。对于以 @
开头的行,这将被抑制,这就是为什么 echo 'This is another recipe.'
没有被打印。
如果一个命令失败,配方就会停止运行。这里 cargo publish
只有在 cargo test
成功后才会运行:
publish:
cargo test
# 前面的测试通过才会执行 publish!
cargo publish
配方可以依赖其他配方。在这里,test
配方依赖于 build
配方,所以 build
将在 test
之前运行:
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!
示例
在 Examples 目录 中可以找到各种 justfile
的例子。
特性介绍
默认配方
当 just
被调用而没有传入任何配方时,它会运行 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 --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
标题文本可以用 --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
别名
别名允许你用其他名称来调用配方:
alias b := build
build:
echo 'Building!'
$ just b
build
echo 'Building!'
Building!
设置
设置控制解释和执行。每个设置最多可以指定一次,可以出现在 justfile
的任何地方。
例如:
set shell := ["zsh", "-cu"]
foo:
# this line will be run as `zsh -cu 'ls **/*.txt'`
ls **/*.txt
设置一览表
名称 | 值 | 描述 |
---|---|---|
allow-duplicate-recipes |
boolean | 允许在 justfile 后面出现的配方覆盖之前的同名配方 |
dotenv-load |
boolean | 加载 .env 环境变量文件, 如果有的话 |
export |
boolean | 将所有变量导出为环境变量 |
positional-arguments |
boolean | 传递位置参数 |
shell |
[COMMAND, ARGS…] |
设置用于调用配方和评估反引号内包裹内容的命令 |
windows-powershell |
boolean | 在 Windows 上使用 PowerShell 作为默认 Shell |
Bool 类型设置可以写成:
set NAME
这就相当于:
set NAME := true
允许重复的配方
如果 allow-duplicate-recipes
被设置为 true
,那么定义多个同名的配方就不会出错,而会使用最后的定义。默认为 false
。
set allow-duplicate-recipes
@foo:
echo foo
@foo:
echo bar
$ just foo
bar
环境变量加载
如果将 dotenv-load
设置为 true
,并且存在 .env
文件,则该环境配置文件将被加载。默认为 false
。
导出
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
当使用 sh
兼容的 Shell,如 bash
或 zsh
时,$@
会展开为传给配方的位置参数,从1开始。当在双引号内使用 "$@"
时,包括空白的参数将被传递,就像它们是双引号一样。也就是说,"$@"
相当于 "$1" "$2"
......当没有位置参数时,"$@"
和 $@
将展开为空(即,它们被删除)。
这个例子的配方将逐行打印参数:
set positional-arguments
@test *args='':
bash -c 'while (( "$#" )); do echo - $1; shift; done' -- "$@"
用 两个 参数运行:
$ just test foo "bar baz"
- foo
- bar baz
Shell
shell
设置控制用于调用执行配方代码行和反引号内指令的命令。Shebang 配方不受影响。
# 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
把要执行的命令作为一个参数进行传递。许多 Shell 需要一个额外的标志,通常是 -c
,以使它们评估执行第一个参数。
Windows PowerShell
just
在Windows上默认使用 sh
。要使用 PowerShell,请将 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"]
文档注释
紧接着配方前面的注释将出现在 just --list
中:
# build stuff
build:
./bin/build
# test stuff
test:
./bin/test
$ just --list
Available recipes:
build # build stuff
test # test stuff
.env
集成
如果 dotenv-load
被设置,just
将从一个名为 .env
的文件中加载环境变量。这个文件可以和你的 justfile
位于同一目录下,或者位于其父目录下。这些变量是环境变量,而不是 just
的变量,因此必须使用 $VARIABLE_NAME
在配方和反引号中访问。
例如,假如你的 .env
文件包含:
# 注释,将被忽略
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
变量和替换
支持在变量、字符串、拼接和替换中使用 {{…}}
:
version := "0.2.7"
tardir := "awesomesauce-" + version
tarball := tardir + ".tar.gz"
publish:
rm -f {{tarball}}
mkdir {{tardir}}
cp README.md *.c {{tardir}}
tar zcvf {{tarball}} {{tardir}}
scp {{tarball}} me@server.com:release/
rm -rf {{tarball}} {{tardir}}
转义 {{
想要写一个包含 {{
的配方,可以使用 {{{{
:
braces:
echo 'I {{{{LOVE}} curly braces!'
(未匹配的 }}
会被忽略,所以不需要转义)
另一个选择是把所有你想转义的文本都放在插值里面:
braces:
echo '{{'I {{LOVE}} curly braces!'}}'
然而,另一个选择是使用 {{ "{{" }}
:
braces:
echo 'I {{ "{{" }}LOVE}} curly braces!'
字符串
双引号字符串支持转义序列:
string-with-tab := "\t"
string-with-newline := "\n"
string-with-carriage-return := "\r"
string-with-double-quote := "\""
string-with-slash := "\\"
string-with-no-newline := "\
"
$ just --evaluate
"tring-with-carriage-return := "
string-with-double-quote := """
string-with-newline := "
"
string-with-no-newline := ""
string-with-slash := "\"
string-with-tab := " "
字符串可以包含换行符:
single := '
hello
'
double := "
goodbye
"
单引号字符串不支持转义序列:
escapes := '\t\n\r\"\\'
$ just --evaluate
escapes := "\t\n\r\"\\"
支持单引号和双引号字符串的缩进版本,以三个单引号或三个双引号为界。缩进的字符串行被删除了所有非空行所共有的前导空白:
# 这个字符串执行结果为 `foo\nbar\n`
x := '''
foo
bar
'''
# 这个字符串执行结果为 `abc\n wuv\nbar\n`
y := """
abc
wuv
xyz
"""
与未缩进的字符串类似,缩进的双引号字符串处理转义序列,而缩进的单引号字符串则忽略转义序列。转义序列的处理是在取消缩进后进行的。取消缩进的算法不考虑转义序列产生的空白或换行。
错误忽略
通常情况下,如果一个命令返回一个非零的退出状态,将停止执行。要想在一个命令之后继续执行,即使它失败了,需要在命令前加上 -
:
foo:
-cat foo
echo 'Done!'
$ just foo
cat foo
cat: foo: No such file or directory
echo 'Done!'
Done!
函数
just
提供了一些内置函数,在编写配方时可能很有用。
系统信息
-
arch()
— 指令集结构。可能的值是:"aarch64"
,"arm"
,"asmjs"
,"hexagon"
,"mips"
,"msp430"
,"powerpc"
,"powerpc64"
,"s390x"
,"sparc"
,"wasm32"
,"x86"
,"x86_64"
, 和"xcore"
。 -
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 文件。
环境变量
env_var(key)
— 获取名称为key
的环境变量,如果不存在则终止。
home_dir := env_var('HOME')
test:
echo "{{home_dir}}"
$ just
/home/user1
env_var_or_default(key, default)
— 获取名称为key
的环境变量,如果不存在则返回default
。
调用目录
invocation_directory()
- 获取just
被调用时当前目录所对应的绝对路径,在just
改变路径并执行相应命令前。
例如,要对 "当前目录" 下的文件调用 rustfmt
(从用户/调用者的角度看),使用以下规则:
rustfmt:
find {{invocation_directory()}} -name \*.rs -exec rustfmt {} \;
另外,如果你的命令需要从当前目录运行,你可以使用如下方式:
build:
cd {{invocation_directory()}}; ./some_script_that_needs_to_be_run_from_here
Justfile 和 Justfile 目录
-
justfile()
- 取得当前justfile
的路径。 -
justfile_directory()
- 取得当前justfile
文件父目录的路径。
例如,运行一个相对于当前 justfile
位置的命令:
script:
./{{justfile_directory()}}/scripts/some_script
Just 可执行程序
just_executable()
-just
可执行文件的绝对路径。
例如:
executable:
@echo The executable is at: {{just_executable()}}
$ just
The executable is at: /bin/just
字符串处理
-
lowercase(s)
- 将s
转换为小写形式。 -
quote(s)
- 用'\''
替换所有的单引号,并在s
的首尾添加单引号。这足以为许多 Shell 转义特殊字符,包括大多数 Bourne Shell 的后代。 -
replace(s, from, to)
- 将s
中的所有from
替换为to
。 -
trim(s)
- 去掉s
的首尾空格。 -
trim_end(s)
- 去掉s
的尾部空格。 -
trim_end_match(s, pat)
- 删除与pat
匹配的s
的后缀。 -
trim_end_matches(s, pat)
- 反复删除与pat
匹配的s
的后缀。 -
trim_start(s)
- 去掉s
的首部空格。 -
trim_start_match(s, pat)
- 删除与pat
匹配的s
的前缀。 -
trim_start_matches(s, pat)
- 反复删除与pat
匹配的s
的前缀。 -
uppercase(s)
- 将s
转换为大写形式。
路径操作
非可靠的
-
absolute_path(path)
- 将当前工作目录中到相对路径path
的路径转换为绝对路径。在/foo
目录通过absolute_path("./bar.txt")
可以得到/foo/bar.txt
。 -
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
。
这些函数可能会失败,例如,如果一个路径没有扩展名,则将停止执行。
可靠的
-
join(a, b…)
- 将路径a
与路径b
连接。join("foo/bar", "baz")
结果为foo/bar/baz
。接受两个或多个参数。 -
clean(path)
- 通过删除多余的路径分隔符、中间的.
和..
来简化path
。clean("foo//bar")
结果为foo/bar
,clean("foo/..")
为.
,clean("foo/./bar")
结果为foo/bar
。
文件系统访问
path_exists(path)
- 如果路径指向一个存在的文件或目录,则返回true
,否则返回false
。也会遍历符号链接,如果路径无法访问或指向一个无效的符号链接,则返回false
。
错误报告
error(message)
- 终止执行并向用户报告错误message
。
UUID 和哈希值生成
sha256(string)
- 以十六进制字符串形式返回string
的 SHA-256 哈希值。sha256_file(path)
- 以十六进制字符串形式返回path
处的文件的 SHA-256 哈希值。uuid()
- 返回一个随机生成的 UUID。
使用反引号的命令求值
反引号可以用来存储命令的求值结果:
localhost := `dumpinterfaces | cut -d: -f2 | sed 's/\/.*//' | sed 's/ //g'`
serve:
./serve {{localhost}} 8080
缩进的反引号,以三个反引号为界,与字符串缩进的方式一样,会被去掉缩进:
# This backtick evaluates the command `echo foo\necho bar\n`, which produces the value `foo\nbar\n`.
stuff := ```
echo foo
echo bar
```
参见Strings部分,了解去除缩进的细节。
反引号内不能以 #!
开头。这种语法是为将来的升级而保留的。
条件表达式
if
/ else
表达式评估不同的分支,取决于两个表达式是否评估为相同的值:
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:
# 如果它崩溃了,将打印一个堆栈追踪
cargo test
以 $
为前缀的参数将被作为环境变量导出:
test $RUST_BACKTRACE="1":
# 如果它崩溃了,将打印一个堆栈追踪
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
变量都将作为环境变量被导出。
从环境中获取环境变量
来自环境的环境变量会自动传递给配方:
print_home_folder:
echo "HOME is: '${HOME}'"
$ just
HOME is '/home/myuser'
从 .env
文件加载环境变量
如果 dotenv-load 被设置,just
将从 .env
文件中加载环境变量。该文件中的变量将作为环境变量提供给配方。参见 dotenv-integration 以获得更多信息。
从环境变量中设置 just
变量
环境变量可以通过函数 env_var()
和 env_var_or_default()
传入到 just
变量。
参见 environment-variables。
配方参数
配方可以有参数。这里的配方 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
参数可以有默认值:
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"):
./test {{triple}}
配方的最后一个参数可以是变长的,在参数名称前用 +
或 *
表示:
backup +FILES:
scp {{FILES}} me@server.com:
以 +
为前缀的变长参数接受 一个或多个 参数,并展开为一个包含这些参数的字符串,以空格分隔:
$ just backup FAQ.md GRAMMAR.md
scp FAQ.md GRAMMAR.md me@server.com:
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
在配方的末尾运行配方
一个配方的正常依赖总是在配方开始之前运行。也就是说,被依赖方总是在依赖方之前运行。这些依赖被称为 "前期依赖"。
一个配方也可以有后续的依赖,它们在配方之后运行,用 &&
表示:
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
进程。
用其他语言书写配方
以 #!
开头的配方将作为脚本执行,因此你可以用其他语言编写配方:
polyglot: python js perl sh ruby
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!"
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!
Hello from ruby!
更加安全的 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
配方中没有开启。
这些措施共同避免了很多 Shell 脚本的问题。
在 Windows 上执行 Shebang 配方
在 Windows 上,包含 /
的 Shebang 解释器路径通过 cygpath
从 Unix 风格的路径转换为 Windows 风格的路径,该工具随 Cygwin 一起提供。
例如,要在 Windows 上执行这个配方:
echo:
#!/bin/sh
echo "Hello!"
解释器路径 /bin/sh
在执行前将被 cygpath
翻译成 Windows 风格的路径。
如果解释器路径不包含 /
,它将被执行而不被翻译。这主要用于 cygpath
不可用或者你希望向解释器传递一个 Windows 风格的路径的情况下。
在配方中设置变量
配方代码行是由 Shell 解释的,而不是 just
,所以不可能在配方中设置 just
变量:
foo:
x := "hello" # This doesn't work!
echo {{x}}
使用 Shell 变量是可能的,但还有一个问题:每一行配方都由一个新的 Shell 实例运行,所以在一行中设置的变量不会在下一行中生效:
foo:
x=hello && echo $x # 这个没问题!
y=bye
echo $y # 这个是有问题的, `y` 在此处未定义!
解决这个问题的最好方法是使用 Shebang 配方。Shebang 配方体被提取出来并作为脚本运行,所以一个 Shell 实例就可以运行整个配方体:
foo:
#!/usr/bin/env bash
set -euxo pipefail
x=hello
echo $x
改变配方中的工作目录
每一行配方都由一个新的 Shell 执行,所以如果你在某一行改变了工作目录,对后面的行不会有影响:
foo:
pwd # This `pwd` will print the same directory…
cd bar
pwd # …as this `pwd`!
有几个方法可以解决这个问题。一个是在你想运行的命令的同一行调用 cd
:
foo:
cd bar && pwd
另一种方法是使用 Shebang 配方。Shebang 配方体被提取并作为脚本运行,因此一个 Shell 实例将运行整个配方体,所以一行的 pwd
改变将影响后面的行,就像一个 Shell 脚本:
foo:
#!/usr/bin/env bash
set -euxo pipefail
cd bar
pwd
缩进
配方代码行可以用空格或制表符缩进,但不能两者混合使用。一个配方的所有行必须有相同的缩进,但同一 justfile
中的不同配方可以使用不同的缩进。
多行结构
没有初始 Shebang 的配方会被逐行评估和运行,这意味着多行结构可能不会像你预期的那样工作。
例如对于下面的 justfile
:
conditional:
if true; then
echo 'True!'
fi
在 conditional
配方的第二行前有额外的前导空格,会产生一个解析错误:
$ 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
命令行选项
just
提供了一些有用的命令行选项,用于列出、Dump 和调试配方以及变量:
$ 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
可以通过 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
这对那些只作为其他配方的依赖使用的辅助配方很有用。
安静配方
配方名称可在前面加上 @
,可以在每行反转行首 @
的含义:
@quiet:
echo hello
echo goodbye
@# all done!
现在只有以 @
开头的行才会被回显:
$ j quiet
hello
goodbye
# all done!
Shebang 配方默认是安静的:
foo:
#!/usr/bin/env bash
echo 'Foo!'
$ just foo
Foo!
在 Shebang 配方名称前面添加 @
,使 just
在执行配方前打印该配方:
@bar:
#!/usr/bin/env bash
echo 'Bar!'
$ just bar
#!/usr/bin/env bash
echo 'Bar!'
Bar!
通过交互式选择器选择要运行的配方
--choose
子命令可以使 just
唤起一个选择器来让您选择要运行的配方。选择器应该从标准输入中读取包含配方名称的行,并将其中一个或多个用空格分隔的名称打印到标准输出。
因为目前没有办法通过 --choose
运行一个需要传入参数的配方,所以这样的配方将不会在选择器中列出。另外,私有配方和别名也会被忽略。
选择器可以用 --chooser
标志来覆写。如果 --chooser
没有给出,那么 just
首先检查 $JUST_CHOOSER
是否被设置。如果没有,那么将使用默认选择器 fzf
,这是一个流行的模糊查找器。
参数可以包含在选择器中,例如:fzf --exact
。
选择器的调用方式与配方行的调用方式相同。例如,如果选择器是 fzf
,它将被通过 sh -cu 'fzf'
调用,如果 Shell 或 Shell 参数被覆写,选择器的调用将尊重这些覆写。
如果你希望 just
默认用选择器来选择配方,你可以用这个作为你的默认配方:
default:
@just --choose
在其他目录下调用 justfile
如果传递给 just
的第一个参数包含 /
,那么就会发生以下情况:
-
参数在最后的
/
处被分割; -
最后一个
/
之前的部分将被视为一个目录。just
将从这里开始搜索justfile
,而不是在当前目录下; -
最后一个斜线之后的部分被视为正常参数,如果是空的,则被忽略;
这可能看起来有点奇怪,但如果你想在一个子目录下的 justfile
中运行一个命令,这很有用。
例如,如果你在一个目录中,该目录包含一个名为 foo
的子目录,该目录包含一个 justfile
,其配方为 build
,也是默认的配方,以下都是等同的:
$ (cd foo && just build)
$ just foo/build
$ just foo/
隐藏 justfile
just
会寻找名为 justfile
和 .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
。
对于上面的命令,just
会把它的工作目录改为脚本的位置。如果你想让工作目录保持不变,可以使用 #!/usr/bin/env just --working-directory . --justfile
。
注意:Shebang 的行分隔在不同的操作系统中并不一致。前面的例子只在 macOS 上进行了测试。在 Linux 上,你可能需要向 env
传递 -S
标志:
#!/usr/bin/env -S just --justfile
default:
echo foo
将 justfile
转为JSON文件
--dump
命令可以和 --dump-format json
一起使用,以打印一个 justfile
的JSON表示。JSON格式目前还不稳定,所以需要添加 --unstable
标志。
回退到父 justfile
如果没有找到配方,just
将在父目录和递归地在其上级目录里寻找 justfile
,直到到达根目录。
这个功能目前是不稳定的,所以必须用 --unstable
标志启用。
举个例子,假设当前目录包含这个 justfile
:
foo:
echo foo
而父目录包含这个 justfile
:
bar:
echo bar
$ just --unstable bar
Trying ../justfile
echo bar
bar