2014年7月28日

erlang - rebar

本文接續上一篇對 rebar 的簡介,說明有關取得相依套件, 建構 release package 以及程式不關機直接升級的問題。

Templates

如果要使用自己的 template,就把 mytemplate.template 放到 templates 目錄中,並執行以下指令

rebar create template=mytemplate

rebar 提供了幾個內建的 templates

Template Variables Command Alias Command
simplesrv srvid rebar create template=simplesrv X
simplenode nodeid rebar create template=simplenode rebar create-node
simplemod modid rebar create template=simplemod X
simplelib libid rebar create template=simplelib rebar create-lib
simplefsm fsmid rebar create template=simplefsm X
simpleapp appid rebar create template=simpleapp rebar create-app
ctsuite testmod rebar create template=ctsuite X
basicnif module rebar create template=basicnif X

管理發行版本

rebar 利用 reltool.config 建立執行的節點。

如果一個專案中,包含了多個 OTP applicaitons,我們可以建立一個 app 目錄,並把 otp application 移到 app 目錄中。

mkdir apps
cd apps

mkdir myapp
cd myapp

rebar create-app appid=myapp

cd ../../

編輯檔案 rebar.config

{sub_dirs, ["apps/myapp", "rel"]}.

然後就可以編譯專案

rebar compile

建立 release 目錄與檔案

mkdir rel
cd rel
rebar create-node

修改 reltool.config

line 4
        {lib_dirs, ["../apps"]},

line 12 mynode 改為 myapp
        [
         kernel,
         stdlib,
         sasl,
         myapp
        ]},

line 27 改為
        {app, myapp, [{mod_cond, app}, {incl_cond, include}, {lib_dir, ".."}]}

產生 build release

cd ..
rebar -v generate

使用 rel/mynode/bin/mynode 啟動與停止節點

> rel/mynode/bin/mynode
Usage: mynode {start|start_boot <file>|foreground|stop|restart|reboot|ping|console|getpid|console_clean|console_boot <file>|attach|remote_console|upgrade}

啟動 app 後,進入 console 互動
> rel/mynode/bin/mynode console
(mynode@127.0.0.1)1> application:which_applications().
[{sasl,"SASL  CXC 138 11","2.3.4"},
 {myapp,[],"1"},
 {stdlib,"ERTS  CXC 138 10","1.19.4"},
 {kernel,"ERTS  CXC 138 10","2.16.4"}]


在背景啟動或停止 app
> rel/mynode/bin/mynode start
> rel/mynode/bin/mynode stop

增加 deps

專案通常會使用一些第三方的專業套件,我們必須要先修改 rebar.config。
必須增加 deps tuple 如下
{deps, [Dependency1, dependency2, ...]}

每一個 Dependency1 內容如下
{App, VsnRegex, Source}

Source 指定該 library 的來源,有以下幾種選擇。

  1. {hg, Url, Rev}
    mercury repository
  2. {git, Url}
  3. {git, Url, {branch, Branch}}
  4. {git, Url, ""} 等同於 {git, Url, {branch, "HEAD"}}
  5. {git, Url, {tag, Tag}}
  6. {git, Url, Rev}
  7. {bzr, Url, Rev}
    bazaar repository

以下這個例子,使用了 cowboy。

{deps, [
    {cowboy, "",
        {git, "git://github.com/extend/cowboy.git",{branch, "master"}}}
        ]}.
{sub_dirs, ["apps/myapp", "rel"]}.

我們可以在 command line 用以下指令,從 git 取得 cowboy 相關的 libraries,包含了 cowlib, ranch與cowboy,程式碼都會 clone 到 deps。

rebar get-deps
rebar update-deps

如果專案 app 裡的程式碼使用了 cowboy,編譯時,也必須把 deps 相關的 libs 包含進去。

修改 reltool.config

line 4 增加 ../deps
        {lib_dirs, ["../apps", "../deps"]},

line 12 mynode 改為 myapp
        [
         kernel,
         stdlib,
         sasl,
         myapp
        ]},

line 27
        {app, mynode, [{incl_cond, include}]},
        {app, cowboy, [{incl_cond, include}]}

Makefile

可以做個簡單的 Makefile,簡化重複輸入指令的麻煩。

all: compile

deps:
    rebar get-deps
    rebar update-deps

compile:
    rebar compile

clean:
    rebar clean

test: compile
    rebar eunit skip_deps=true

release: compile
    rebar -v generate
    mkdir -p ./rel/mynode/priv
    cp -r ./apps/myapp/priv/ ./rel/mynode/priv/

.PHONY: all deps compile

Upgrades

把 apps/myapp/src/myapp.app.src and rel/reltool.conf 兩個檔案的版本號碼 vsn 都從 1 改為 2

在 rebar 有個測試的 dummy project 可用來驗證 OTP 程式線上直接升級的程序。

在取得 dummy project source code 時,一開始是設定為 0.1 版,所以先編譯然後就啟動 dummy server。

rebar compile
rebar generate
mv rel/dummy rel/dummy_0.1
rebar clean

啟動 dummy server

cd rel/dummy_0.1
bin/dummy console

(dummy@127.0.0.1)1> dummy_server:get_state().
0
(dummy@127.0.0.1)2> dummy_server:set_state(123).
{ok,123}
(dummy@127.0.0.1)3> dummy_server:get_state().
123

在另一個 terminal,進行 0.2 版的編譯

先將版本號碼從 0.1 版改為 0.2

vi apps/dummy/src/dummy.app.src
vi rel/reltool.config

編譯並封裝 0.2 版

rebar compile
rebar generate

rebar generate-appups previous_release=dummy_0.1
rebar generate-upgrade previous_release=dummy_0.1

這一行是一個測試 dummy_0.2.tar.gz 的壓縮檔
tar -zvtf rel/dummy_0.2.tar.gz

將 0.1 版 升級到 0.2 版

mv rel/dummy_0.2.tar.gz rel/dummy_0.1/releases/

回到剛剛 0.1 版的 console
(dummy@127.0.0.1)6> release_handler:unpack_release("dummy_0.2").
{ok,"0.2"}
(dummy@127.0.0.1)7> release_handler:install_release("0.2").
{ok,"0.1",[]}
(dummy@127.0.0.1)8> release_handler:make_permanent("0.2").
ok
(dummy@127.0.0.1)9> release_handler:which_releases().
[{"dummy","0.2",
  ["kernel-2.16.4","stdlib-1.19.4","sasl-2.3.4","dummy-0.2",
   "asn1-2.0.4","compiler-4.9.4","crypto-3.2","et-1.4.4.5",
   "gs-1.5.15.2","inets-5.9.8","mnesia-4.11",
   "observer-1.3.1.2","public_key-0.21","runtime_tools-1.8.13",
   "ssl-5.3.3","tools-2.6.13","webtool-0.8.9.2","wx-1.1.2"],
  permanent},
 {"dummy","0.1",
  ["kernel-2.16.4","stdlib-1.19.4","sasl-2.3.4","dummy-0.1",
   "asn1-2.0.4","compiler-4.9.4","crypto-3.2","et-1.4.4.5",
   "gs-1.5.15.2","inets-5.9.8","mnesia-4.11",
   "observer-1.3.1.2","public_key-0.21","runtime_tools-1.8.13",
   "ssl-5.3.3","tools-2.6.13","webtool-0.8.9.2","wx-1.1.2"],
  old}]
(dummy@127.0.0.1)10> dummy_server:get_state().
123

References

[How To]使用rebar構建erlang 項目
Rebar:Erlang構建工具