用 rebar 來構建、編譯、測試、發佈 Erlang 應用程序

rebar 是一個遵循 Erlang/OTP 原則的 Erlang 項目構建工具,使用它能夠減小構建標準 Erlang/OTP 項目架構配置的工做量,而且能夠很容易的編譯、測試、發佈 Erlang 應用程序。更強大的是,rebar 提供一種依賴管理機制,它可使開發者很方便地經過 GitHg 等方式重用常見的第三方 Erlang 模塊或庫。html

安裝 rebarnode

你能夠從 https://github.com/rebar/rebar/wiki/rebar 下載編譯好的版本,也能夠本身下載 rebar 的源代碼,本身編譯一個:git

1github

2shell

3bootstrap

git clone git://github.com/rebar/rebar.gitbash

cdrebar架構

./bootstrapapp

上面編譯好以後,在當前目錄下就會生成一個名爲 "rebar" 獨立的 erlang 腳本(escript),把它放在你想建立標準 Erlang/OTP 項目的目錄路徑下便可使用,或者把 rebar 放在系統目錄的 Path 下,方便在終端使用:框架

1

sudomvrebar /usr/local/bin

在終端輸入 "rebar -c" 將列出全部可執行的 rebar 命令。或者輸入 "rebar -h" 查看更多的 rebar 參數信息。

用 rebar 構建項目

建立一個名爲 rebarapp 的文件夾

1

2

mkdirrebarapp

cdrebarapp

建立名爲 rebarapp 項目:

1

rebar create-app appid=rebarapp

rebar 會根據默認模板(template)在當前目錄下生成一個 src 文件夾,裏面包含下面3個文件:

  • rebarapp.app.src 應用的資源描述文件,影響後面編譯生成的 rebarapp.app 裏的內容

  • rebarapp_app.erl 應用的 Application Behaviour 代碼文件

  • rebarapp_sup.erl 應用的 Supervisor Behaviour 代碼文件

rebar 還內置了 gen_servergen_fsmapplication 等 Erlang/OTP 行爲模式的模板,能夠自動生成這些行爲模式的框架代碼。這裏以 gen_server 爲例,給應用添加一個名爲 rebarapp_server 的 gen_server 行爲模式。在應用根目錄執行如下命令:

1

rebar create template=simplesrv srvid=rebarapp_server

執行完後自動會在 src 文件夾裏生成一個 rebarapp_server.erl 的 gen_server 框架格式的文件,simplesrv 是 gen_server 模板的名稱(gen_fsm、application對應的是simplefsm、simpleapp),srvid 則是該 gen_server 模板的ID(gen_fsm、application對應的是fsmid、appid)。

爲了測試,這裏對 rebarapp_server.erl 進行修改,export 一個 hello 方法,並添加一個 cast 的消息輸出,修改後的 rebarapp_server.erl 文件內容以下:

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

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

-module(rebarapp_server).

-behaviour(gen_server).

-define(SERVER, ?MODULE).

 

%% ------------------------------------------------------------------

%% API Function Exports

%% ------------------------------------------------------------------

 

-export([start_link/0, hello/0]).

 

%% ------------------------------------------------------------------

%% gen_server Function Exports

%% ------------------------------------------------------------------

 

-export([init/1, handle_call/3, handle_cast/2, handle_info/2,

         terminate/2, code_change/3]).

 

%% ------------------------------------------------------------------

%% API Function Definitions

%% ------------------------------------------------------------------

 

start_link() ->

    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

 

%% @doc  just a test

hello() ->

    gen_server:cast(?SERVER, 'HELLO').

 

%% ------------------------------------------------------------------

%% gen_server Function Definitions

%% ------------------------------------------------------------------

 

init(Args) ->

    {ok, Args}.

 

handle_call(_Request, _From, State) ->

    {reply, ok, State}.

 

handle_cast('HELLO', State) ->

    io:format("Hello World!~n"),

    {noreply, State};

 

handle_cast(_Msg, State) ->

    {noreply, State}.

 

handle_info(_Info, State) ->

    {noreply, State}.

 

terminate(_Reason, _State) ->

    ok.

 

code_change(_OldVsn, State, _Extra) ->

    {ok, State}.

 

%% ------------------------------------------------------------------

%% Internal Function Definitions

%% ------------------------------------------------------------------

修改 rebarapp_sup.erl 的 init 函數,把 rebarapp_server 做爲應用管理者 rebarapp_sup 的工做進程啓動,修改以下:

1

2

3

init([]) ->

    RebarappServer= ?CHILD(rebarapp_server, worker),

    {ok, { {one_for_one, 5, 10}, [RebarappServer]} }.

編譯應用

1

rebar compile

編譯完後,會在根目錄下生成一個 ebin 的文件夾,裏面存放的是該應用的資源文件 rebarapp.app 和應用的 beam 文件,也能夠執行如下命令對編譯生成的應用文件進行清理:

1

rebar clean

使用 Edoc 生成應用文檔

1

rebar doc

命令執行完後,會在根目錄生成一個 doc 的文件夾,打開裏面的 index.html 就能夠很直觀地看到該應用的模塊 API 概覽。

eunit 測試

rebar 會根據一個名爲 rebar.config 的文件裏的 eunit 配置選項來對應用進行測試,rebar.config 詳細地配置選項信息能夠查看官方上的 rebar.config.sample。在應用的根目錄下建立一個 rebar.config,填入如下內容:

1

2

3

4

5

6

7

8

9

10

%%-*- mode: erlang -*-

 

%% Erlang compiler options

{erl_opts, [debug_info,

            {i, "test"},

            {src_dirs, ["src"]}]}.

 

{eunit_opts, [verbose, {report, {eunit_surefire, [{dir, "."}]}}]}.

 

{cover_enabled, true}.

上面的配置將會加載根目錄下的 test 文件夾裏的文件,因此須要在根目錄下建立一個 test 文件夾:

1

mkdir-p test

這裏 test 文件夾將存放 eunit 的測試用例,在 test 文件夾裏新建一個名爲 rebarapp_test.hrl 的測試用例文件,內容以下:

1

2

3

4

5

6

7

8

9

-include_lib("eunit/include/eunit.hrl").

 

 

my_test() ->

    ?assert(1 + 2 =:= 3).

 

simple_test() ->

    ok = application:start(rebarapp),

    ?assertNot(undefined =:= whereis(rebarapp_sup)).

而後在 rebarapp_server.erl 的文件末尾加上如下測試代碼:

1

2

3

-ifdef(TEST).

-include("rebarapp_test.hrl").

-endif.

固然,若是有必要的話也能夠在每一個模塊文件上加上面測試代碼。執行如下命令進行 eunit 測試:

1

rebar compile eunit

若是應用文件沒什麼變化修改,也能夠直接運行 "rebar eunit"。這時終端出現如下相似顯示,則 eunit 測試完成:

1

2

3

4

5

6

7

8

9

10

11

==> rebarapp (eunit)

======================== EUnit ========================

module 'rebarapp_app'

module 'rebarapp_server'

  rebarapp_server: my_test...ok

  rebarapp_server: simple_test...[0.014 s] ok

  [done in 0.019 s]

module 'rebarapp_sup'

=======================================================

  All 2 tests passed.

Cover analysis: /Users/dengjoe/erlang/rebarapp/.eunit/index.html

能夠打開根目錄下的.eunit/index.html 查看測試報告。

發佈應用

在應用根目錄下建立一個名爲 rel 的文件夾,用來做爲應用發佈的文件夾:

1

2

mkdir-p rel

cdrel

在當前 rel 文件夾裏建立一個名爲 rebarapp 的獨立的 Erlang VM 節點:

1

rebar create-node nodeid=rebarapp

修改 rel/reltool.config 裏的 lib_dirs 的值,默認是一個空列表 "[]",改成應用所在的目錄路徑 '["../../"]',否則到後面編譯發佈時會報 "Missing application directory" 的錯誤出來,修改後的 reltool.config 配置內容以下所示:

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

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

{sys, [

       {lib_dirs, ["../../"]},

       {erts, [{mod_cond, derived}, {app_file, strip}]},

       {app_file, strip},

       {rel, "rebarapp", "1",

        [

         kernel,

         stdlib,

         sasl,

         rebarapp

        ]},

       {rel, "start_clean", "",

        [

         kernel,

         stdlib

        ]},

       {boot_rel, "rebarapp"},

       {profile, embedded},

       {incl_cond, derived},

       {mod_cond, derived},

       {excl_archive_filters, [".*"]}, %% Do not archive built libs

       {excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)",

                           "^erts.*/(doc|info|include|lib|man|src)"]},

       {excl_app_filters, ["\.gitignore"]},

       {app, rebarapp, [{mod_cond, app}, {incl_cond, include}]}

      ]}.

 

{target_dir, "rebarapp"}.

 

{overlay, [

           {mkdir, "log/sasl"},

           {copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},

           {copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"},

           {copy, "files/rebarapp", "bin/rebarapp"},

           {copy, "files/rebarapp.cmd", "bin/rebarapp.cmd"},

           {copy, "files/start_erl.cmd", "bin/start_erl.cmd"},

           {copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"},

           {copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"},

           {copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"}

          ]}.

返回應用的根目錄,在 rebar.config 加上如下一行,把新建的 rel 文件夾放入到 rebar 可訪問的子文件夾裏,做爲應用內容發佈文件夾: 

1

{sub_dirs, ["rel"]}.

再從新編譯下應用 rebarapp

1

rebar compile

若是報什麼錯,應用 rebarapp 就能夠發佈了:

1

rebar generate

在終端上看到 "==> rel (generate)" 且沒報什麼錯,應用 rebarapp 發佈成功,並在 rel/rebarapp/bin 目錄下生成一個用來啓動應用或中止應用等操控動做的 shell 文件 rebarapp。

操控文件 rel/rebarapp/bin/rebarapp 用法:

1

rebarapp {start|start_boot |foreground|stop|restart|reboot|ping|console|console_clean|console_boot |attach|remote_console|upgrade}

例如:

啓動應用 rebarapp

1

rel/rebarapp/bin/rebarapp start

中止應用 rebarapp

1

rel/rebarapp/bin/rebarapp stop

或者啓動應用 rebarapp 後返回一個 erlang shell 的控制檯

1

rel/rebarapp/bin/rebarapp console

OK,在 erlang shell 的控制檯上調用 rebarapp_server:hello() 輸出一個 "Hello World!" 吧。

相關文章
相關標籤/搜索