Rebar3 Shell

这篇文章我花了好长时间来写。关于rebar3 shell的其中一件事就是它会怎么做你期望它处理不论大或小的项目:它装载代码路径,启动应用(如果指定的话),允许一个分布式节点运行,让你定义定制的脚本来设置它的状态,并且让你在它里面运行rebar3的任务,同时好好地更新状态使得工作正常运行。

它有很多好的特性,不过在我的观点来看,这些是一个Erlang shell工具最少要支持的。因此,尝试展示这些特性听起来好像是吹嘘你该做的本分事情一样;多说无益,下面就进入正题。

不过,一些Erlang的东西的可用性一直很糟糕,我们(贡献者)已经在rebar3上做了很多工作来尝试解决这些糟糕的体验。我不得不说,很多社区已经有大量的非常好的工具,但是它们都是独立的,如何用好它们必须要读者自己去逐个尝试。这个时候,rebar3横空出世了。

当使用rebar3 shell命令的时候首先吸引人的是,它会自动编译项目(如果项目还没有被编译)并且将编译后的项目加入你的代码搜索路径:

1
2
3
4
5
6
7
8
9
10
11
rebar3 shell
===> Verifying dependencies...
===> Compiling vegur
Erlang/OTP 18 [erts-7.1] [source] [64-bit] [smp:8:4] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V7.1 (abort with ^G)
1> vegur:module_info().
[{module,vegur},
{exports,[{start_http,3},
{start_proxy,3},
...

这个功能作用于所有项目。这至少摆脱很多需要你自己手写默认设置的许多烦恼。现在这些都由rebar3 shell来做。

对于一个编程语言来说,一个好的shell环境就是关于它的互动性。期望能够快速地重编译代码或者运行测试,并且重新装载代码而不需要任何中断或丢失状态。rebar3 shell有一个代理,隐藏在r3模块背后,它准备着所有需要重新编译代码或者运行任务的状态的管理。所以,例如任何存在的项目,我可以要求重新编译或者任何其他任务运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2> r3:do(compile).
===> This feature is experimental and may be modified or removed at any time.
Verifying dependencies...
Compiling vegur
ok
3> r3:do(ct).
Verifying dependencies...
Fetching websocket_client ({git,"git@github.com:jeremyong/websocket_client.git",
{tag,"v0.7"}})
Linking _build/default/lib/cowboyku to _build/test/lib/cowboyku
Linking _build/default/lib/cowlib to _build/test/lib/cowlib
Linking _build/default/lib/erequest_id to _build/test/lib/erequest_id
...
Running Common Test suites...
%%% vegur_bytepipe_SUITE ==> pipe_proc: OK
%%% vegur_bytepipe_SUITE ==> pipe_proc_callback: OK
%%% vegur_bytepipe_SUITE ==> pipe_proc_timeout: OK
...
All 140 tests passed.
ok
3> r3:do(dialyzer).
Verifying dependencies...
...
Analyzing 19 files with "/home/ferd/code/self/vegur/_build/default/rebar3_18.1.5_plt"...
ok

如上述例子等等。所有这些任务都会用你的最新版本的rebar.config文件来运行它的任务和切换路径重装载模块等等。

rebar3的代理还有一个名字使得可以在外部调用它。你可以用一个名字来启动一个shell(rebar3 shell –name my_shell 或 rebar3 shell –sname my_shell)然后远程向它发送消息或者直接RPC调用当作指令。

1
2
rebar3 shell --sname=my_shell
erl -sname remote -eval 'rpc:call(my_shell@localhost, r3, do, [ct]), halt(0).' -noshell

当作人们的工具的目的应该是可以被用来从你的IDE或编辑器里增加钩子到Erlang shell里。

被写出来的和rebar3代理一起工作的插件也是一种选择。例如,通过监控硬盘,rebar3_atuo 能够被用来自动重新编译修改过的文件,这样也省了这个的功能要和IDE或编辑器合成的需求。

这提供了一个非常好的改进,例如,在运行调试周期,在测试,代码分析和交互式调试都可以在同一个环境进行。

为了使得开发周期更加与你的项目成长无缝对接,rebar3 shell将在构建工具里自动侦测release配置,并且以你的release遵循的的应用配置【1】启动你的系统。

这意味着只要你的代码库配置成装配为一个可执行版本,你可以在它里面访问shell的代码重装载特性,使用的是同样的工具,而这些工具你可能以别的方式使用。

如果你不使用release呢?应用可以在你的rebar.config文件里被指定为{shell, [{apps, [myapp]}]} 或者在命令行里的参数里指定(–apps app1,app2)。

1
2
3
4
5
6
7
8
9
rebar3 shell --apps vegur
===> Verifying dependencies...
===> Compiling vegur
...
===> Booted midjan
===> Booted quickrand
===> Booted uuid
===> Booted erequest_id
===> Booted vegur

万一你的开发环境和生产环境不匹配,任意的代码可以被运行来设置shell并且通过escript来设置它。这些设置指定的动态环境变量或启动外部依赖的模拟模块是特别有用的。为了进一步解释,下面的例子将展示我们如何不让shell启动,除非所有需要设置的环境变量都设置好了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env escript
main(_) ->
OSVars = ["USER", "PASS"],
[check_is_set(Var) || Var <- OSVars].
check_is_set(Var) ->
case os:getenv(Var) of
false ->
rebar_api:error("Missing var ~s", [Var]),
halt(1);
_ ->
ok
end.

这个escript文件可以通过增加{shell, [{script_file, “path/to/file”}]}到你的rebar.config文件配置成总是执行,或者通过在命令行被直接调用:

1
2
3
4
5
6
7
rebar3 shell --script_file test/check_env.escript
===> Verifying dependencies...
===> Compiling vegur
Erlang/OTP 18 [erts-7.1] [source] [64-bit] [smp:8:4] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V7.1 (abort with ^G)
1> ===> Missing var PASS

希望这些工具比那些开箱即用的更可以让Erlang开发者的生活轻松些。

【1】这里有些警告:因为rebar3 shell是一个开发工具,诸如Erlang虚拟机配置的选项(例如,调度器的数量)已经在运行时里有了而且不能被修改。它不能复制所有release的配置,因此,你应该在生产环境保持使用release。

原文链接: http://ferd.ca/rebar3-shell.html