summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--Makefile11
-rw-r--r--THANKS2
-rw-r--r--dialyzer_reference2
-rw-r--r--inttest/depplugins/depplugins_rt.erl50
-rw-r--r--inttest/depplugins/rebar.config1
-rw-r--r--inttest/depplugins/rebar_dependsonplugin.config2
-rw-r--r--inttest/depplugins/testplugin_mod.erl6
-rw-r--r--inttest/tdeps1/a.rebar.config2
-rw-r--r--inttest/tdeps1/b.rebar.config2
-rw-r--r--inttest/tdeps1/tdeps1_rt.erl19
-rw-r--r--inttest/tdeps2/a.rebar.config2
-rw-r--r--inttest/tdeps2/b.rebar.config2
-rw-r--r--inttest/tdeps2/tdeps2_rt.erl19
-rw-r--r--priv/shell-completion/bash/rebar59
-rw-r--r--priv/shell-completion/zsh/_rebar6
-rw-r--r--priv/templates/simpleapp_sup.erl1
-rw-r--r--priv/templates/simplenode.erl.script26
-rwxr-xr-x[-rw-r--r--]priv/templates/simplenode.nodetool58
-rw-r--r--priv/templates/simplenode.reltool.config8
-rwxr-xr-xpriv/templates/simplenode.runner117
-rw-r--r--priv/templates/simplenode.windows.runner.cmd9
-rw-r--r--rebar.config1
-rw-r--r--rebar.config.sample40
-rw-r--r--src/rebar.erl65
-rw-r--r--src/rebar_abnfc_compiler.erl17
-rw-r--r--src/rebar_appups.erl10
-rw-r--r--src/rebar_asn1_compiler.erl20
-rw-r--r--src/rebar_base_compiler.erl2
-rw-r--r--src/rebar_cleaner.erl17
-rw-r--r--src/rebar_core.erl144
-rw-r--r--src/rebar_ct.erl59
-rw-r--r--src/rebar_deps.erl36
-rw-r--r--src/rebar_dia_compiler.erl20
-rw-r--r--src/rebar_edoc.erl11
-rw-r--r--src/rebar_erlc_compiler.erl49
-rw-r--r--src/rebar_erlydtl_compiler.erl33
-rw-r--r--src/rebar_escripter.erl27
-rw-r--r--src/rebar_eunit.erl40
-rw-r--r--src/rebar_lfe_compiler.erl11
-rw-r--r--src/rebar_neotoma_compiler.erl18
-rw-r--r--src/rebar_otp_app.erl20
-rw-r--r--src/rebar_port_compiler.erl37
-rw-r--r--src/rebar_protobuffs_compiler.erl21
-rw-r--r--src/rebar_qc.erl22
-rw-r--r--src/rebar_reltool.erl55
-rw-r--r--src/rebar_require_vsn.erl32
-rw-r--r--src/rebar_templater.erl48
-rw-r--r--src/rebar_upgrade.erl10
-rw-r--r--src/rebar_utils.erl2
-rw-r--r--src/rebar_xref.erl19
-rwxr-xr-xtest/upgrade_project/rel/files/dummy187
-rwxr-xr-xtest/upgrade_project/rel/files/erl26
-rw-r--r--test/upgrade_project/rel/files/nodetool58
-rw-r--r--test/upgrade_project/rel/files/sys.config1
-rw-r--r--test/upgrade_project/rel/files/vm.args8
56 files changed, 1285 insertions, 288 deletions
diff --git a/.travis.yml b/.travis.yml
index f5e3d99..191d337 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,8 @@
language: erlang
otp_release:
+ - R16B
- R15B01
- R15B
- R14B04
- R14B03
-script: "make debug xref clean all deps test"
+script: "make travis"
diff --git a/Makefile b/Makefile
index 3f7b8ee..1144d5e 100644
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,10 @@ all:
./bootstrap
clean:
- @rm -rf rebar ebin/*.beam inttest/rt.work rt.work .test
+ @rm -rf rebar ebin/*.beam inttest/rt.work rt.work .eunit
+
+distclean: clean
+ @rm -rf deps
debug:
@./bootstrap debug
@@ -21,7 +24,7 @@ dialyzer: dialyzer_warnings
@diff -U0 dialyzer_reference dialyzer_warnings
dialyzer_warnings:
- -@dialyzer -q -n ebin -Wunmatched_returns -Werror_handling \
+ -@dialyzer -q -nn -n ebin -Wunmatched_returns -Werror_handling \
-Wrace_conditions > dialyzer_warnings
binary: VSN = $(shell ./rebar -V)
@@ -35,4 +38,6 @@ deps:
test:
@$(REBAR) eunit
- @$(RETEST) inttest
+ @$(RETEST) -v inttest
+
+travis: clean debug xref clean all deps test
diff --git a/THANKS b/THANKS
index 16b1f24..1be44e5 100644
--- a/THANKS
+++ b/THANKS
@@ -97,7 +97,7 @@ Eric B Merritt
Fred Hebert
Kresten Krab Thorup
David Aaberg
-DeadZen
+Pedram Nimreezi
Edwin Fine
Lev Walkin
Roberto Ostinelli
diff --git a/dialyzer_reference b/dialyzer_reference
index a50bb88..fccada2 100644
--- a/dialyzer_reference
+++ b/dialyzer_reference
@@ -1,3 +1,3 @@
-rebar_eunit.erl:351: Call to missing or unexported function eunit_test:function_wrapper/2
+rebar_eunit.erl:388: Call to missing or unexported function eunit_test:function_wrapper/2
rebar_utils.erl:162: Call to missing or unexported function escript:foldl/3
diff --git a/inttest/depplugins/depplugins_rt.erl b/inttest/depplugins/depplugins_rt.erl
new file mode 100644
index 0000000..7b106eb
--- /dev/null
+++ b/inttest/depplugins/depplugins_rt.erl
@@ -0,0 +1,50 @@
+%%% @doc Plugin handling test
+%%%
+%%% This test checks if plugins are loaded correctly.
+%%%
+%%% It has three applications:
+%%% <ol>
+%%% <li>fish. top-level module, has one dependency: `dependsonplugin'.</li>
+%%% <li>dependsonplugin. This depends on some pre-compile actions by the
+%%% plugin. In the test the plugin creates a file `pre.compile' in the
+%%% top-level folder of this application.</li>
+%%% <li>testplugin. This is a plugin application which creates the file.</li>
+%%% </ol>
+
+-module(depplugins_rt).
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [
+ {copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {create, "ebin/fish.app", app(fish, [])},
+
+ {create, "deps/dependsonplugin/ebin/dependsonplugin.app",
+ app(dependsonplugin, [])},
+ {copy, "rebar_dependsonplugin.config",
+ "deps/dependsonplugin/rebar.config"},
+ {copy, "testplugin_mod.erl",
+ "deps/testplugin/plugins/testplugin_mod.erl"},
+ {create, "deps/testplugin/ebin/testplugin.app",
+ app(testplugin, [])}
+ ].
+
+run(_Dir) ->
+ ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
+ ?assertEqual(true, filelib:is_regular("deps/dependsonplugin/pre.compile")),
+ ok.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff --git a/inttest/depplugins/rebar.config b/inttest/depplugins/rebar.config
new file mode 100644
index 0000000..3a2e34e
--- /dev/null
+++ b/inttest/depplugins/rebar.config
@@ -0,0 +1 @@
+{deps, [dependsonplugin]}.
diff --git a/inttest/depplugins/rebar_dependsonplugin.config b/inttest/depplugins/rebar_dependsonplugin.config
new file mode 100644
index 0000000..df36213
--- /dev/null
+++ b/inttest/depplugins/rebar_dependsonplugin.config
@@ -0,0 +1,2 @@
+{deps, [testplugin]}.
+{plugins, [testplugin_mod]}.
diff --git a/inttest/depplugins/testplugin_mod.erl b/inttest/depplugins/testplugin_mod.erl
new file mode 100644
index 0000000..055bbc7
--- /dev/null
+++ b/inttest/depplugins/testplugin_mod.erl
@@ -0,0 +1,6 @@
+-module(testplugin_mod).
+-compile(export_all).
+
+pre_compile(Config, _) ->
+ ok = file:write_file("pre.compile", <<"Yadda!">>),
+ rebar_log:log(info, "Wrote ~p/pre.compile~n", [rebar_utils:get_cwd()]).
diff --git a/inttest/tdeps1/a.rebar.config b/inttest/tdeps1/a.rebar.config
index 01609ee..991ea5a 100644
--- a/inttest/tdeps1/a.rebar.config
+++ b/inttest/tdeps1/a.rebar.config
@@ -1 +1 @@
-{deps, [{b, "1", {hg, "../repo/b", "tip"}}]}.
+{deps, [{b, "1", {git, "../repo/b"}}]}.
diff --git a/inttest/tdeps1/b.rebar.config b/inttest/tdeps1/b.rebar.config
index 59c8987..ffbd0db 100644
--- a/inttest/tdeps1/b.rebar.config
+++ b/inttest/tdeps1/b.rebar.config
@@ -1 +1 @@
-{deps, [{c, "1", {hg, "../repo/c", "tip"}}]}.
+{deps, [{c, "1", {git, "../repo/c"}}]}.
diff --git a/inttest/tdeps1/tdeps1_rt.erl b/inttest/tdeps1/tdeps1_rt.erl
index 43184c6..3de1a2b 100644
--- a/inttest/tdeps1/tdeps1_rt.erl
+++ b/inttest/tdeps1/tdeps1_rt.erl
@@ -23,12 +23,23 @@ files() ->
{copy, "c.hrl", "repo/c/include/c.hrl"}
].
+apply_cmds([], _Params) ->
+ ok;
+apply_cmds([Cmd | Rest], Params) ->
+ io:format("Running: ~s (~p)\n", [Cmd, Params]),
+ {ok, _} = retest_sh:run(Cmd, Params),
+ apply_cmds(Rest, Params).
+
run(_Dir) ->
- %% Initialize the b/c apps as mercurial repos so that dependencies pull
+ %% Initialize the b/c apps as git repos so that dependencies pull
%% properly
- HgCmd = "/bin/sh -c \"hg init && hg add && hg commit -m 'Initial commit'\"",
- {ok, _} = retest_sh:run(HgCmd, [{dir, "repo/b"}]),
- {ok, _} = retest_sh:run(HgCmd, [{dir, "repo/c"}]),
+ GitCmds = ["git init",
+ "git add -A",
+ "git config user.email 'tdeps@example.com'",
+ "git config user.name 'tdeps'",
+ "git commit -a -m 'Initial Commit'"],
+ apply_cmds(GitCmds, [{dir, "repo/b"}]),
+ apply_cmds(GitCmds, [{dir, "repo/c"}]),
{ok, _} = retest_sh:run("./rebar get-deps compile", []),
diff --git a/inttest/tdeps2/a.rebar.config b/inttest/tdeps2/a.rebar.config
index 01609ee..991ea5a 100644
--- a/inttest/tdeps2/a.rebar.config
+++ b/inttest/tdeps2/a.rebar.config
@@ -1 +1 @@
-{deps, [{b, "1", {hg, "../repo/b", "tip"}}]}.
+{deps, [{b, "1", {git, "../repo/b"}}]}.
diff --git a/inttest/tdeps2/b.rebar.config b/inttest/tdeps2/b.rebar.config
index 59c8987..ffbd0db 100644
--- a/inttest/tdeps2/b.rebar.config
+++ b/inttest/tdeps2/b.rebar.config
@@ -1 +1 @@
-{deps, [{c, "1", {hg, "../repo/c", "tip"}}]}.
+{deps, [{c, "1", {git, "../repo/c"}}]}.
diff --git a/inttest/tdeps2/tdeps2_rt.erl b/inttest/tdeps2/tdeps2_rt.erl
index bad546e..987567e 100644
--- a/inttest/tdeps2/tdeps2_rt.erl
+++ b/inttest/tdeps2/tdeps2_rt.erl
@@ -31,12 +31,23 @@ files() ->
{copy, "c.hrl", "repo/c/include/c.hrl"}
].
+apply_cmds([], _Params) ->
+ ok;
+apply_cmds([Cmd | Rest], Params) ->
+ io:format("Running: ~s (~p)\n", [Cmd, Params]),
+ {ok, _} = retest_sh:run(Cmd, Params),
+ apply_cmds(Rest, Params).
+
run(_Dir) ->
- %% Initialize the b/c apps as mercurial repos so that dependencies pull
+ %% Initialize the b/c apps as git repos so that dependencies pull
%% properly
- HgCmd = "/bin/sh -c \"hg init && hg add && hg commit -m 'Initial commit'\"",
- {ok, _} = retest_sh:run(HgCmd, [{dir, "repo/b"}]),
- {ok, _} = retest_sh:run(HgCmd, [{dir, "repo/c"}]),
+ GitCmds = ["git init",
+ "git add -A",
+ "git config user.email 'tdeps@example.com'",
+ "git config user.name 'tdeps'",
+ "git commit -a -m 'Initial Commit'"],
+ ok = apply_cmds(GitCmds, [{dir, "repo/b"}]),
+ ok = apply_cmds(GitCmds, [{dir, "repo/c"}]),
{ok, _} = retest_sh:run("./rebar -v get-deps compile", []),
ok.
diff --git a/priv/shell-completion/bash/rebar b/priv/shell-completion/bash/rebar
index d76e2ba..d4a42dc 100644
--- a/priv/shell-completion/bash/rebar
+++ b/priv/shell-completion/bash/rebar
@@ -6,14 +6,57 @@ _rebar()
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
- sopts="-h -c -v -V -f -j"
- lopts=" --help --commands --verbose --force --jobs= --version"
- cmdsnvars="check-deps clean compile create create-app create-node ct \
- doc delete-deps escriptize eunit get-deps generate generate-upgrade \
- help list-deps list-templates qc update-deps version xref overlay \
- apps= case= force=1 jobs= suites= verbose=1 appid= \
- previous_release= nodeid= root_dir= skip_deps=true skip_apps= \
- template= template_dir="
+ sopts="-h -c -v -V -f -D -j -C -p -k"
+ lopts="--help \
+ --commands \
+ --verbose \
+ --force \
+ --jobs \
+ --config \
+ --profile \
+ --keep-going \
+ --version"
+ cmdsnvars="check-deps \
+ clean \
+ compile \
+ create \
+ create-app \
+ create-node \
+ ct \
+ doc \
+ delete-deps \
+ escriptize \
+ eunit \
+ get-deps \
+ generate \
+ generate-appups \
+ generate-upgrade \
+ help \
+ list-deps \
+ list-templates \
+ qc \
+ update-deps \
+ version \
+ xref \
+ overlay \
+ apps= \
+ case= \
+ dump_spec=1 \
+ force=1 \
+ jobs= \
+ suites= \
+ verbose=1 \
+ appid= \
+ overlay_vars= \
+ previous_release= \
+ nodeid= \
+ root_dir= \
+ skip_deps=true \
+ skip_apps= \
+ target_dir= \
+ template= \
+ template_dir= \
+ tests="
if [[ ${cur} == --* ]] ; then
COMPREPLY=( $(compgen -W "${lopts}" -- ${cur}) )
diff --git a/priv/shell-completion/zsh/_rebar b/priv/shell-completion/zsh/_rebar
index 7ac5a51..3d04ba1 100644
--- a/priv/shell-completion/zsh/_rebar
+++ b/priv/shell-completion/zsh/_rebar
@@ -43,6 +43,7 @@ _rebar () {
'overlay[Run reltool overlays only]' \
'generate-appups[Generate appup files]' \
'generate-upgrade[Build an upgrade package]' \
+ 'escriptize[Create stand-alone escript executable]' \
'eunit[Run eunit tests]' \
'ct[Run common_test suites]' \
'qc[Test QuickCheck properties]' \
@@ -51,18 +52,21 @@ _rebar () {
'version[Show version information]' \
'apps[Application names to process]:' \
'case[Common Test case]:' \
- 'dump_spec[Dump reltool spec]:' \
+ 'dump_spec[Dump reltool spec]::flag:(1)' \
'jobs[Number of workers]::workers:(0 1 2 3 4 5 6 7 8 9)' \
'suites[Common Test suites]::suite name:_path_files -W "(src test)" -g "*.erl(:r)"' \
'verbose[Verbosity level]::verbosity level:(0 1 2 3)' \
'appid[Application id]:' \
+ 'overlay_vars[Overlay variables file]:' \
'previous_release[Previous release path]:' \
'nodeid[Node id]:' \
'root_dir[Reltool config root directory]::directory:_files -/' \
'skip_deps[Skip deps]::flag:(true false)' \
'skip_apps[Application names to not process]::flag:(true false)' \
+ 'target_dir[Target directory]:' \
'template[Template name]:' \
'template_dir[Template directory]::directory:_files -/' \
+ 'tests[Run eunit tests whose name starts with given string]:' \
&& ret=0
;;
esac
diff --git a/priv/templates/simpleapp_sup.erl b/priv/templates/simpleapp_sup.erl
index 931db75..477479f 100644
--- a/priv/templates/simpleapp_sup.erl
+++ b/priv/templates/simpleapp_sup.erl
@@ -1,4 +1,3 @@
-
-module({{appid}}_sup).
-behaviour(supervisor).
diff --git a/priv/templates/simplenode.erl.script b/priv/templates/simplenode.erl.script
index 6f65e3f..f4c63af 100644
--- a/priv/templates/simplenode.erl.script
+++ b/priv/templates/simplenode.erl.script
@@ -1,16 +1,26 @@
#!/bin/sh
-## This script replaces the default "erl" in erts-VSN/bin. This is necessary
-## as escript depends on erl and in turn, erl depends on having access to a
-## bootscript (start.boot). Note that this script is ONLY invoked as a side-effect
-## of running escript -- the embedded node bypasses erl and uses erlexec directly
-## (as it should).
+# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is.
+if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then
+ POSIX_SHELL="true"
+ export POSIX_SHELL
+ exec /usr/bin/ksh $0 "$@"
+fi
+
+# clear it so if we invoke other scripts, they run as ksh as well
+unset POSIX_SHELL
+
+## This script replaces the default "erl" in erts-VSN/bin. This is
+## necessary as escript depends on erl and in turn, erl depends on
+## having access to a bootscript (start.boot). Note that this script
+## is ONLY invoked as a side-effect of running escript -- the embedded
+## node bypasses erl and uses erlexec directly (as it should).
##
-## Note that this script makes the assumption that there is a start_clean.boot
-## file available in $ROOTDIR/release/VSN.
+## Note that this script makes the assumption that there is a
+## start_clean.boot file available in $ROOTDIR/release/VSN.
# Determine the abspath of where this script is executing from.
-ERTS_BIN_DIR=$(cd ${0%/*} && pwd)
+ERTS_BIN_DIR=$(cd ${0%/*} && pwd -P)
# Now determine the root directory -- this script runs from erts-VSN/bin,
# so we simply need to strip off two dirs from the end of the ERTS_BIN_DIR
diff --git a/priv/templates/simplenode.nodetool b/priv/templates/simplenode.nodetool
index eb08fa4..ce06c6a 100644..100755
--- a/priv/templates/simplenode.nodetool
+++ b/priv/templates/simplenode.nodetool
@@ -1,3 +1,4 @@
+#!/usr/bin/env escript
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ft=erlang ts=4 sw=4 et
%% -------------------------------------------------------------------
@@ -5,25 +6,51 @@
%% nodetool: Helper Script for interacting with live nodes
%%
%% -------------------------------------------------------------------
-
main(Args) ->
ok = start_epmd(),
%% Extract the args
{RestArgs, TargetNode} = process_args(Args, [], undefined),
+ %% any commands that don't need a running node
+ case RestArgs of
+ ["chkconfig", File] ->
+ case file:consult(File) of
+ {ok, _} ->
+ io:format("ok\n"),
+ halt(0);
+ {error, {Line, Mod, Term}} ->
+ io:format(standard_error, ["Error on line ",
+ file:format_error({Line, Mod, Term}), "\n"], []),
+ halt(1);
+ {error, R} ->
+ io:format(standard_error, ["Error reading config file: ",
+ file:format_error(R), "\n"], []),
+ halt(1)
+ end;
+ _ ->
+ ok
+ end,
+
%% See if the node is currently running -- if it's not, we'll bail
- case {net_kernel:hidden_connect_node(TargetNode), net_adm:ping(TargetNode)} of
+ case {net_kernel:hidden_connect_node(TargetNode),
+ net_adm:ping(TargetNode)} of
{true, pong} ->
ok;
+ {false,pong} ->
+ io:format("Failed to connect to node ~p .\n", [TargetNode]),
+ halt(1);
{_, pang} ->
io:format("Node ~p not responding to pings.\n", [TargetNode]),
halt(1)
end,
case RestArgs of
+ ["getpid"] ->
+ io:format("~p\n",
+ [list_to_integer(rpc:call(TargetNode, os, getpid, []))]);
["ping"] ->
- %% If we got this far, the node already responsed to a ping, so just dump
- %% a "pong"
+ %% If we got this far, the node already responsed to a
+ %% ping, so just dump a "pong"
io:format("pong\n");
["stop"] ->
io:format("~p\n", [rpc:call(TargetNode, init, stop, [], 60000)]);
@@ -32,7 +59,9 @@ main(Args) ->
["reboot"] ->
io:format("~p\n", [rpc:call(TargetNode, init, reboot, [], 60000)]);
["rpc", Module, Function | RpcArgs] ->
- case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
+ case rpc:call(TargetNode,
+ list_to_atom(Module),
+ list_to_atom(Function),
[RpcArgs], 60000) of
ok ->
ok;
@@ -42,8 +71,23 @@ main(Args) ->
_ ->
halt(1)
end;
+ ["rpc_infinity", Module, Function | RpcArgs] ->
+ case rpc:call(TargetNode,
+ list_to_atom(Module),
+ list_to_atom(Function),
+ [RpcArgs], infinity) of
+ ok ->
+ ok;
+ {badrpc, Reason} ->
+ io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
+ halt(1);
+ _ ->
+ halt(1)
+ end;
["rpcterms", Module, Function, ArgsAsString] ->
- case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
+ case rpc:call(TargetNode,
+ list_to_atom(Module),
+ list_to_atom(Function),
consult(ArgsAsString), 60000) of
{badrpc, Reason} ->
io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
@@ -53,7 +97,7 @@ main(Args) ->
end;
Other ->
io:format("Other: ~p\n", [Other]),
- io:format("Usage: nodetool {ping|stop|restart|reboot}\n")
+ io:format("Usage: nodetool {chkconfig|getpid|ping|stop|restart|reboot|rpc|rpc_infinity|rpcterms}\n")
end,
net_kernel:stop().
diff --git a/priv/templates/simplenode.reltool.config b/priv/templates/simplenode.reltool.config
index b580c2a..bac7270 100644
--- a/priv/templates/simplenode.reltool.config
+++ b/priv/templates/simplenode.reltool.config
@@ -1,3 +1,5 @@
+%% -*- mode: erlang -*-
+%% ex: ft=erlang
{sys, [
{lib_dirs, []},
{erts, [{mod_cond, derived}, {app_file, strip}]},
@@ -17,9 +19,9 @@
{boot_rel, "{{nodeid}}"},
{profile, embedded},
{incl_cond, derived},
- {mod_cond, derived},
{excl_archive_filters, [".*"]}, %% Do not archive built libs
- {excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)",
+ {excl_sys_filters, ["^bin/(?!start_clean.boot)",
+ "^erts.*/bin/(dialyzer|typer)",
"^erts.*/(doc|info|include|lib|man|src)"]},
{excl_app_filters, ["\.gitignore"]},
{app, {{nodeid}}, [{mod_cond, app}, {incl_cond, include}]}
@@ -31,6 +33,8 @@
{mkdir, "log/sasl"},
{copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
{copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"},
+ {copy, "{{nodeid}}/bin/start_clean.boot",
+ "\{\{erts_vsn\}\}/bin/start_clean.boot"},
{copy, "files/{{nodeid}}", "bin/{{nodeid}}"},
{copy, "files/{{nodeid}}.cmd", "bin/{{nodeid}}.cmd"},
{copy, "files/start_erl.cmd", "bin/start_erl.cmd"},
diff --git a/priv/templates/simplenode.runner b/priv/templates/simplenode.runner
index 43d90bc..c2ef258 100755
--- a/priv/templates/simplenode.runner
+++ b/priv/templates/simplenode.runner
@@ -2,7 +2,20 @@
# -*- tab-width:4;indent-tabs-mode:nil -*-
# ex: ts=4 sw=4 et
-RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd)
+# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is.
+if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then
+ POSIX_SHELL="true"
+ export POSIX_SHELL
+ # To support 'whoami' add /usr/ucb to path
+ PATH=/usr/ucb:$PATH
+ export PATH
+ exec /usr/bin/ksh $0 "$@"
+fi
+
+# clear it so if we invoke other scripts, they run as ksh
+unset POSIX_SHELL
+
+RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd -P)
CALLER_DIR=$PWD
@@ -11,10 +24,17 @@ RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc
# Note the trailing slash on $PIPE_DIR/
PIPE_DIR=/tmp/$RUNNER_BASE_DIR/
RUNNER_USER=
+WHOAMI=$(whoami)
# Make sure this script is running as the appropriate user
-if [ ! -z "$RUNNER_USER" ] && [ `whoami` != "$RUNNER_USER" ]; then
- exec sudo -u $RUNNER_USER -i $0 $@
+if ([ "$RUNNER_USER" ] && [ "x$WHOAMI" != "x$RUNNER_USER" ]); then
+ type sudo > /dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "sudo doesn't appear to be installed and your EUID isn't $RUNNER_USER" 1>&2
+ exit 1
+ fi
+ echo "Attempting to restart script through sudo -H -u $RUNNER_USER" >&2
+ exec sudo -H -u $RUNNER_USER -i $RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT $@
fi
# Identify the script name
@@ -25,7 +45,8 @@ START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data`
ERTS_VSN=${START_ERL% *}
APP_VSN=${START_ERL#* }
-# Use $CWD/vm.args if exists, otherwise releases/APP_VSN/vm.args, or else etc/vm.args
+# Use $CWD/vm.args if exists, otherwise releases/APP_VSN/vm.args, or
+# else etc/vm.args
if [ -e "$CALLER_DIR/vm.args" ]; then
VMARGS_PATH=$CALLER_DIR/vm.args
USE_DIR=$CALLER_DIR
@@ -54,7 +75,7 @@ else
fi
# Extract the target node name from node.args
-NAME_ARG=`egrep '^-s?name' $VMARGS_PATH`
+NAME_ARG=`egrep '^\-s?name' $VMARGS_PATH`
if [ -z "$NAME_ARG" ]; then
echo "vm.args needs to have either -name or -sname parameter."
exit 1
@@ -64,12 +85,13 @@ fi
REMSH_TYPE=`echo $NAME_ARG | awk '{print $1}'`
REMSH_NAME=`echo $NAME_ARG | awk '{print $2}'`
-# Note the `date +%s`, used to allow multiple remsh to the same node transparently
+# Note the `date +%s`, used to allow multiple remsh to the same node
+# transparently
REMSH_NAME_ARG="$REMSH_TYPE remsh`date +%s`@`echo $REMSH_NAME | awk -F@ '{print $2}'`"
REMSH_REMSH_ARG="-remsh $REMSH_NAME"
# Extract the target cookie
-COOKIE_ARG=`grep '^-setcookie' $VMARGS_PATH`
+COOKIE_ARG=`grep '^\-setcookie' $VMARGS_PATH`
if [ -z "$COOKIE_ARG" ]; then
echo "vm.args needs to have a -setcookie parameter."
exit 1
@@ -81,7 +103,6 @@ cd $USE_DIR
# Make sure log directory exists
mkdir -p $USE_DIR/log
-
# Add ERTS bin dir to our path
ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
@@ -91,11 +112,35 @@ NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG"
# Setup remote shell command to control node
REMSH="$ERTS_PATH/erl $REMSH_NAME_ARG $REMSH_REMSH_ARG $COOKIE_ARG"
+# Common functions
+
+# Ping node without allowing nodetool to take stdin
+ping_node() {
+ $NODETOOL ping < /dev/null
+}
+
+# Set the PID global variable, return 1 on error
+get_pid() {
+ PID=`$NODETOOL getpid < /dev/null`
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ echo "Node is not running!"
+ return 1
+ fi
+
+ # don't allow empty or init pid's
+ if [ -z $PID ] || [ "$PID" -le 1 ]; then
+ return 1
+ fi
+
+ return 0
+}
+
# Check the first argument for instructions
case "$1" in
start|start_boot)
# Make sure there is not already a node running
- RES=`$NODETOOL ping`
+ RES=`ping_node`
if [ "$RES" = "pong" ]; then
echo "Node is already running!"
exit 1
@@ -122,27 +167,28 @@ case "$1" in
stop)
# Wait for the node to completely stop...
case `uname -s` in
- Linux|Darwin|FreeBSD|DragonFly|NetBSD|OpenBSD)
- # PID COMMAND
- PID=`ps ax -o pid= -o command=|\
- grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'`
- ;;
- SunOS)
- # PID COMMAND
- PID=`ps -ef -o pid= -o args=|\
- grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'`
- ;;
- CYGWIN*)
- # UID PID PPID TTY STIME COMMAND
- PID=`ps -efW|grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $2}'`
- ;;
+ Darwin)
+ # Make sure we explicitly set this because iTerm.app doesn't for
+ # some reason.
+ COMMAND_MODE=unix2003
esac
+
+ # Get the PID from nodetool
+ get_pid
+ GPR=$?
+ if [ "$GPR" -ne 0 ] || [ -z $PID ]; then
+ exit $GPR
+ fi
+
+ # Tell nodetool to initiate a stop
$NODETOOL stop
ES=$?
if [ "$ES" -ne 0 ]; then
exit $ES
fi
- while `kill -0 $PID 2>/dev/null`;
+
+ # Wait for the node to completely stop...
+ while `kill -s 0 $PID 2>/dev/null`
do
sleep 1
done
@@ -168,7 +214,7 @@ case "$1" in
ping)
## See if the VM is alive
- $NODETOOL ping
+ ping_node
ES=$?
if [ "$ES" -ne 0 ]; then
exit $ES
@@ -176,8 +222,8 @@ case "$1" in
;;
attach)
- # Make sure a node IS running
- RES=`$NODETOOL ping`
+ # Make sure a node is running
+ ping_node
ES=$?
if [ "$ES" -ne 0 ]; then
echo "Node is not running!"
@@ -189,8 +235,8 @@ case "$1" in
;;
remote_console)
- # Make sure a node IS running
- RES=`$NODETOOL ping`
+ # Make sure a node is running
+ ping_node
ES=$?
if [ "$ES" -ne 0 ]; then
echo "Node is not running!"
@@ -210,7 +256,7 @@ case "$1" in
fi
# Make sure a node IS running
- RES=`$NODETOOL ping`
+ ping_node
ES=$?
if [ "$ES" -ne 0 ]; then
echo "Node is not running!"
@@ -283,8 +329,17 @@ case "$1" in
# Start the VM
exec $CMD -- ${1+"$@"}
;;
+ getpid)
+ # Get the PID from nodetool
+ get_pid
+ ES=$?
+ if [ "$ES" -ne 0 ] || [ -z $PID ]; then
+ exit $ES
+ fi
+ echo $PID
+ ;;
*)
- echo "Usage: $SCRIPT {start|start_boot <file>|foreground|stop|restart|reboot|ping|console|console_clean|console_boot <file>|attach|remote_console|upgrade}"
+ echo "Usage: $SCRIPT {start|start_boot <file>|foreground|stop|restart|reboot|ping|console|getpid|console_clean|console_boot <file>|attach|remote_console|upgrade}"
exit 1
;;
esac
diff --git a/priv/templates/simplenode.windows.runner.cmd b/priv/templates/simplenode.windows.runner.cmd
index 16da5b9..d45f438 100644
--- a/priv/templates/simplenode.windows.runner.cmd
+++ b/priv/templates/simplenode.windows.runner.cmd
@@ -30,6 +30,7 @@
@set epmd="%erts_bin%\epmd.exe"
@set escript="%erts_bin%\escript.exe"
@set werl="%erts_bin%\werl.exe"
+@set nodetool="%erts_bin%\nodetool"
@if "%1"=="usage" @goto usage
@if "%1"=="install" @goto install
@@ -38,13 +39,14 @@
@if "%1"=="stop" @goto stop
@if "%1"=="restart" @call :stop && @goto start
@if "%1"=="console" @goto console
+@if "%1"=="ping" @goto ping
@if "%1"=="query" @goto query
@if "%1"=="attach" @goto attach
@if "%1"=="upgrade" @goto upgrade
@echo Unknown command: "%1"
:usage
-@echo Usage: %~n0 [install^|uninstall^|start^|stop^|restart^|console^|query^|attach^|upgrade]
+@echo Usage: %~n0 [install^|uninstall^|start^|stop^|restart^|console^|ping^|query^|attach^|upgrade]
@goto :EOF
:install
@@ -71,6 +73,11 @@
@start "%node_name% console" %werl% -boot "%node_boot_script%" -config "%sys_config%" -args_file "%vm_args%" -sname %node_name%
@goto :EOF
+:ping
+@%escript% %nodetool% ping -sname "%node_name%" -setcookie "%erlang_cookie%"
+@exit %ERRORLEVEL%
+@goto :EOF
+
:query
@%erlsrv% list %service_name%
@exit %ERRORLEVEL%
diff --git a/rebar.config b/rebar.config
index b03f338..9028737 100644
--- a/rebar.config
+++ b/rebar.config
@@ -1,7 +1,6 @@
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 ft=erlang et
-{app_bin, ["priv/rebar"]}.
%% escript_incl_extra is for internal rebar-private use only.
%% Do not use outside rebar. Config interface is not stable.
{escript_incl_extra, [{"priv/templates/*", "."}]}.
diff --git a/rebar.config.sample b/rebar.config.sample
index 8e4b51e..d8d61fc 100644
--- a/rebar.config.sample
+++ b/rebar.config.sample
@@ -5,6 +5,11 @@
%% == Core ==
+%% Check required ERTS or OTP release version
+{require_erts_vsn, ".*"}.
+{require_otp_vsn, ".*"}.
+{require_min_otp_vsn, ".*"}.
+
%% Additional library directories to add to the code path
{lib_dirs, []}.
@@ -30,6 +35,18 @@
%% SNMP mibs to compile first?
{mib_first_files, []}.
+%% leex options
+{xrl_opts, []}.
+
+%% leex files to compile first
+{xrl_first_files, []}.
+
+%% yecc options
+{yrl_opts, []}.
+
+%% yecc files to compile first
+{yrl_first_files, []}.
+
%% == EDoc ==
%% EDoc options
@@ -50,6 +67,13 @@
{"linux", "priv/hello_linux", ["c_src/hello_linux.c"]},
{"linux", "priv/hello_linux", ["c_src/*.c"], [{env, []}]}]}.
+%% == escriptize ==
+{escript_name, "application"}.
+{escript_incl_apps, []}.
+{escript_shebang, "#!/usr/bin/env escript\n"}.
+{escript_comment, "%%\n"}.
+{escript_emu_args, "%%! -pa application/application/ebin\n"}.
+
%% == LFE Compiler ==
%% LFE files to compile before the rest
@@ -114,16 +138,8 @@
%% Which files to cleanup
{clean_files, ["file", "file2"]}.
-%% == Reltool ==
-
-%% Target directory for the release
-{target, "target"}.
-
%% == OTP Applications ==
-%% Binaries to link into the erlang path?
-{app_bin, []}.
-
%% Enable validation of the OTP app module list. Default is 'true'
{validate_app_modules, true}.
@@ -140,7 +156,7 @@
{deps, [application_name,
{application_name, "1.0.*"},
{application_name, "1.0.*",
- {git, "git://github.com/basho/rebar.git", {branch, "master"}}},
+ {git, "git://github.com/rebar/rebar.git", {branch, "master"}}},
%% Dependencies can be marked as 'raw'. Rebar does not require
%% such dependencies to have a standard Erlang/OTP layout
%% which assumes the presence of either
@@ -155,7 +171,7 @@
%% 'raw' subdirectories: get-deps, update-deps, check-deps,
%% list-deps and delete-deps.
{application_name, "",
- {git, "git://github.com/basho/rebar.git", {branch, "master"}},
+ {git, "git://github.com/rebar/rebar.git", {branch, "master"}},
[raw]}]}.
%% == Subdirectories ==
@@ -197,9 +213,9 @@
%% Optional custom xref queries (xref manual has details) specified as
%% {xref_queries, [{query_string(), expected_query_result()},...]}
-%% The following for example removes all references to ejabberd:*_msg/4
+%% The following for example removes all references to mod:*foo/4
%% functions from undefined external function calls as those are in a
%% generated module
{xref_queries,
[{"(XC - UC) || (XU - X - B"
- " - (\"ejabberd_logger\":\".*_msg\"/\"4\"))",[]}]}.
+ " - (\"mod\":\".*foo\"/\"4\"))",[]}]}.
diff --git a/src/rebar.erl b/src/rebar.erl
index c7c9d29..ded5ebe 100644
--- a/src/rebar.erl
+++ b/src/rebar.erl
@@ -76,8 +76,18 @@ run(BaseConfig, Commands) ->
%% Internal functions
%% ====================================================================
+run(["help"|RawCmds]) when RawCmds =/= [] ->
+ ok = load_rebar_app(),
+ Cmds = unabbreviate_command_names(RawCmds),
+ Args = parse_args(Cmds),
+ BaseConfig = init_config(Args),
+ {BaseConfig1, _} = save_options(BaseConfig, Args),
+ BaseConfig2 = init_config1(BaseConfig1),
+ rebar_core:help(BaseConfig2, [list_to_atom(C) || C <- Cmds]);
run(["help"]) ->
help();
+run(["info"|_]) ->
+ help();
run(["version"]) ->
ok = load_rebar_app(),
%% Display vsn and build time info
@@ -138,6 +148,16 @@ init_config({Options, _NonOptArgs}) ->
%% Initialize vsn cache
rebar_config:set_xconf(BaseConfig1, vsn_cache, dict:new()).
+init_config1(BaseConfig) ->
+ %% Determine the location of the rebar executable; important for pulling
+ %% resources out of the escript
+ ScriptName = filename:absname(escript:script_name()),
+ BaseConfig1 = rebar_config:set_xconf(BaseConfig, escript, ScriptName),
+ ?DEBUG("Rebar location: ~p\n", [ScriptName]),
+ %% Note the top-level directory for reference
+ AbsCwd = filename:absname(rebar_utils:get_cwd()),
+ rebar_config:set_xconf(BaseConfig1, base_dir, AbsCwd).
+
run_aux(BaseConfig, Commands) ->
%% Make sure crypto is running
case crypto:start() of
@@ -148,18 +168,10 @@ run_aux(BaseConfig, Commands) ->
%% Convert command strings to atoms
CommandAtoms = [list_to_atom(C) || C <- Commands],
- %% Determine the location of the rebar executable; important for pulling
- %% resources out of the escript
- ScriptName = filename:absname(escript:script_name()),
- BaseConfig1 = rebar_config:set_xconf(BaseConfig, escript, ScriptName),
- ?DEBUG("Rebar location: ~p\n", [ScriptName]),
-
- %% Note the top-level directory for reference
- AbsCwd = filename:absname(rebar_utils:get_cwd()),
- BaseConfig2 = rebar_config:set_xconf(BaseConfig1, base_dir, AbsCwd),
+ BaseConfig1 = init_config1(BaseConfig),
%% Process each command, resetting any state between each one
- rebar_core:process_commands(CommandAtoms, BaseConfig2).
+ rebar_core:process_commands(CommandAtoms, BaseConfig1).
%%
%% print help/usage string
@@ -169,7 +181,29 @@ help() ->
getopt:usage(OptSpecList, "rebar",
"[var=value,...] <command,...>",
[{"var=value", "rebar global variables (e.g. force=1)"},
- {"command", "Command to run (e.g. compile)"}]).
+ {"command", "Command to run (e.g. compile)"}]),
+ ?CONSOLE(
+ "Core rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n",
+ [
+ {lib_dirs, []},
+ {sub_dirs, ["dir1", "dir2"]},
+ {plugins, [plugin1, plugin2]},
+ {plugin_dir, "some_other_directory"},
+ {pre_hooks, [{clean, "./prepare_package_files.sh"},
+ {"linux", compile, "c_src/build_linux.sh"},
+ {compile, "escript generate_headers"},
+ {compile, "escript check_headers"}]},
+ {post_hooks, [{clean, "touch file1.out"},
+ {"freebsd", compile, "c_src/freebsd_tweaks.sh"},
+ {eunit, "touch file2.out"},
+ {compile, "touch postcompile.out"}]}
+ ]).
%%
%% Parse command line arguments using getopt and also filtering out any
@@ -283,6 +317,8 @@ commands() ->
clean Clean
compile Compile sources
+escriptize Generate escript archive
+
create template= [var=foo,...] Create skel based on template and vars
create-app [appid=myapp] Create simple app skel
create-node [nodeid=mynode] Create simple node skel
@@ -379,9 +415,10 @@ filter_flags(Config, [Item | Rest], Commands) ->
command_names() ->
["check-deps", "clean", "compile", "create", "create-app", "create-node",
- "ct", "delete-deps", "doc", "eunit", "generate", "generate-appups",
- "generate-upgrade", "get-deps", "help", "list-deps", "list-templates",
- "qc", "update-deps", "overlay", "shell", "version", "xref"].
+ "ct", "delete-deps", "doc", "eunit", "escriptize", "generate",
+ "generate-appups", "generate-upgrade", "get-deps", "help", "list-deps",
+ "list-templates", "qc", "update-deps", "overlay", "shell", "version",
+ "xref"].
unabbreviate_command_names([]) ->
[];
diff --git a/src/rebar_abnfc_compiler.erl b/src/rebar_abnfc_compiler.erl
index 0e6749a..37731b5 100644
--- a/src/rebar_abnfc_compiler.erl
+++ b/src/rebar_abnfc_compiler.erl
@@ -47,6 +47,9 @@
-export([compile/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -62,11 +65,23 @@ compile(Config, _AppFile) ->
option(module_ext, DtlOpts) ++ ".erl",
fun compile_abnfc/3).
-
%% ===================================================================
%% Internal functions
%% ===================================================================
+info(help, compile) ->
+ ?CONSOLE(
+ "Build ABNF (*.abnf) sources.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n",
+ [
+ {abnfc_opts, [{doc_root, "src"},
+ {out_dir, "src"},
+ {source_ext, ".abnfc"},
+ {module_ext, ""}]}
+ ]).
+
abnfc_opts(Config) ->
rebar_config:get(Config, abnfc_opts, []).
diff --git a/src/rebar_appups.erl b/src/rebar_appups.erl
index 0aeccb6..722f161 100644
--- a/src/rebar_appups.erl
+++ b/src/rebar_appups.erl
@@ -31,6 +31,9 @@
-export(['generate-appups'/2]).
+%% for internal use only
+-export([info/2]).
+
-define(APPUPFILEFORMAT, "%% appup generated for ~p by rebar (~p)~n"
"{~p, [{~p, ~p}], [{~p, []}]}.~n").
@@ -82,6 +85,13 @@
%% Internal functions
%% ===================================================================
+info(help, 'generate-appups') ->
+ ?CONSOLE("Generate appup files.~n"
+ "~n"
+ "Valid command line options:~n"
+ " previous_release=path~n",
+ []).
+
get_apps(Name, OldVerPath, NewVerPath) ->
OldApps = rebar_rel_utils:get_rel_apps(Name, OldVerPath),
?DEBUG("Old Version Apps: ~p~n", [OldApps]),
diff --git a/src/rebar_asn1_compiler.erl b/src/rebar_asn1_compiler.erl
index d93a2e8..25e3fd3 100644
--- a/src/rebar_asn1_compiler.erl
+++ b/src/rebar_asn1_compiler.erl
@@ -30,6 +30,9 @@
-export([compile/2,
clean/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -48,6 +51,23 @@ clean(_Config, _AppFile) ->
ok = rebar_file_utils:delete_each(GeneratedFiles),
ok.
+%% ===================================================================
+%% Internal functions
+%% ===================================================================
+
+info(help, compile) ->
+ info_help("Build ASN.1 (*.asn1) sources");
+info(help, clean) ->
+ info_help("Delete ASN.1 (*.asn1) results").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " {asn1_opts, []} (see asn1ct:compile/2 documentation)~n",
+ [Description]).
+
-spec compile_asn1(file:filename(), file:filename(),
rebar_config:config()) -> ok.
compile_asn1(Source, Target, Config) ->
diff --git a/src/rebar_base_compiler.erl b/src/rebar_base_compiler.erl
index 260cdaf..a0dec30 100644
--- a/src/rebar_base_compiler.erl
+++ b/src/rebar_base_compiler.erl
@@ -226,6 +226,8 @@ format_warnings(Config, Source, Warnings, Opts) ->
maybe_report([{error, {error, _Es, _Ws}=ErrorsAndWarnings}, {source, _}]) ->
maybe_report(ErrorsAndWarnings);
+maybe_report([{error, E}, {source, S}]) ->
+ report(["unexpected error compiling " ++ S, io_lib:fwrite("~n~p~n", [E])]);
maybe_report({error, Es, Ws}) ->
report(Es),
report(Ws);
diff --git a/src/rebar_cleaner.erl b/src/rebar_cleaner.erl
index 9ddeb8a..7a762f5 100644
--- a/src/rebar_cleaner.erl
+++ b/src/rebar_cleaner.erl
@@ -28,6 +28,9 @@
-export([clean/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -37,3 +40,17 @@ clean(Config, _AppFile) ->
%% Get a list of files to delete from config and remove them
FilesToClean = rebar_config:get(Config, clean_files, []),
lists:foreach(fun (F) -> rebar_file_utils:rm_rf(F) end, FilesToClean).
+
+%% ===================================================================
+%% Internal functions
+%% ===================================================================
+
+info(help, clean) ->
+ ?CONSOLE(
+ "Delete list of files.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n",
+ [
+ {clean_files, ["file", "file2"]}
+ ]).
diff --git a/src/rebar_core.erl b/src/rebar_core.erl
index 9e3f9f0..3172d64 100644
--- a/src/rebar_core.erl
+++ b/src/rebar_core.erl
@@ -26,7 +26,7 @@
%% -------------------------------------------------------------------
-module(rebar_core).
--export([process_commands/2]).
+-export([process_commands/2, help/2]).
-include("rebar.hrl").
@@ -34,6 +34,35 @@
%% Internal functions
%% ===================================================================
+help(ParentConfig, Commands) ->
+ %% get all core modules
+ {ok, AnyDirModules} = application:get_env(rebar, any_dir_modules),
+ {ok, RawCoreModules} = application:get_env(rebar, modules),
+ AppDirModules = proplists:get_value(app_dir, RawCoreModules),
+ RelDirModules = proplists:get_value(rel_dir, RawCoreModules),
+ CoreModules = AnyDirModules ++ AppDirModules ++ RelDirModules,
+
+ %% get plugin modules
+ Predirs = [],
+ Dir = rebar_utils:get_cwd(),
+ PredirsAssoc = remember_cwd_predirs(Dir, Predirs),
+ Config = maybe_load_local_config(Dir, ParentConfig),
+ {ok, PluginModules} = plugin_modules(Config, PredirsAssoc),
+
+ AllModules = CoreModules ++ PluginModules,
+
+ lists:foreach(
+ fun(Cmd) ->
+ ?CONSOLE("==> help ~p~n~n", [Cmd]),
+ CmdModules = select_modules(AllModules, Cmd, []),
+ Modules = select_modules(CmdModules, info, []),
+ lists:foreach(fun(M) ->
+ ?CONSOLE("=== ~p:~p ===~n", [M, Cmd]),
+ M:info(help, Cmd),
+ ?CONSOLE("~n", [])
+ end, Modules)
+ end, Commands).
+
process_commands([], ParentConfig) ->
AbortTrapped = rebar_config:get_xconf(ParentConfig, abort_trapped, false),
case {get_operations(ParentConfig), AbortTrapped} of
@@ -53,9 +82,10 @@ process_commands([Command | Rest], ParentConfig) ->
ParentConfig4 =
try
- %% Convert the code path so that all the entries are absolute paths.
- %% If not, code:set_path() may choke on invalid relative paths when trying
- %% to restore the code path from inside a subdirectory.
+ %% Convert the code path so that all the entries are
+ %% absolute paths. If not, code:set_path() may choke on
+ %% invalid relative paths when trying to restore the code
+ %% path from inside a subdirectory.
true = rebar_utils:expand_code_path(),
{ParentConfig2, _DirSet} = process_dir(rebar_utils:get_cwd(),
ParentConfig1, Command,
@@ -68,8 +98,9 @@ process_commands([Command | Rest], ParentConfig) ->
_ ->
ok
end,
- %% TODO: reconsider after config inheritance removal/redesign
- ParentConfig3 = rebar_config:clean_config(ParentConfig1, ParentConfig2),
+ %% TODO: reconsider after config inheritance removal/re-design
+ ParentConfig3 = rebar_config:clean_config(ParentConfig1,
+ ParentConfig2),
%% Wipe out vsn cache to avoid invalid hits when
%% dependencies are updated
rebar_config:set_xconf(ParentConfig3, vsn_cache, dict:new())
@@ -107,41 +138,41 @@ process_dir(Dir, ParentConfig, Command, DirSet) ->
%% to process this dir.
{ok, AvailModuleSets} = application:get_env(rebar, modules),
ModuleSet = choose_module_set(AvailModuleSets, Dir),
- maybe_process_dir(ModuleSet, Config, CurrentCodePath,
- Dir, Command, DirSet)
+ skip_or_process_dir(ModuleSet, Config, CurrentCodePath,
+ Dir, Command, DirSet)
end.
-maybe_process_dir({[], undefined}=ModuleSet, Config, CurrentCodePath,
- Dir, Command, DirSet) ->
- process_dir0(Dir, Command, DirSet, Config, CurrentCodePath, ModuleSet);
-maybe_process_dir({_, ModuleSetFile}=ModuleSet, Config, CurrentCodePath,
- Dir, Command, DirSet) ->
+skip_or_process_dir({[], undefined}=ModuleSet, Config, CurrentCodePath,
+ Dir, Command, DirSet) ->
+ process_dir1(Dir, Command, DirSet, Config, CurrentCodePath, ModuleSet);
+skip_or_process_dir({_, ModuleSetFile}=ModuleSet, Config, CurrentCodePath,
+ Dir, Command, DirSet) ->
case lists:suffix(".app.src", ModuleSetFile)
orelse lists:suffix(".app", ModuleSetFile) of
true ->
%% .app or .app.src file, check if is_skipped_app
- maybe_process_dir0(ModuleSetFile, ModuleSet,
- Config, CurrentCodePath, Dir,
- Command, DirSet);
+ skip_or_process_dir1(ModuleSetFile, ModuleSet,
+ Config, CurrentCodePath, Dir,
+ Command, DirSet);
false ->
%% not an app dir, no need to consider apps=/skip_apps=
- process_dir0(Dir, Command, DirSet, Config,
+ process_dir1(Dir, Command, DirSet, Config,
CurrentCodePath, ModuleSet)
end.
-maybe_process_dir0(AppFile, ModuleSet, Config, CurrentCodePath,
- Dir, Command, DirSet) ->
+skip_or_process_dir1(AppFile, ModuleSet, Config, CurrentCodePath,
+ Dir, Command, DirSet) ->
case rebar_app_utils:is_skipped_app(Config, AppFile) of
{Config1, {true, SkippedApp}} ->
?DEBUG("Skipping app: ~p~n", [SkippedApp]),
Config2 = increment_operations(Config1),
{Config2, DirSet};
{Config1, false} ->
- process_dir0(Dir, Command, DirSet, Config1,
+ process_dir1(Dir, Command, DirSet, Config1,
CurrentCodePath, ModuleSet)
end.
-process_dir0(Dir, Command, DirSet, Config0, CurrentCodePath,
+process_dir1(Dir, Command, DirSet, Config0, CurrentCodePath,
{DirModules, ModuleSetFile}) ->
%% Get the list of modules for "any dir". This is a catch-all list
%% of modules that are processed in addition to modules associated
@@ -156,11 +187,12 @@ process_dir0(Dir, Command, DirSet, Config0, CurrentCodePath,
{Config1, Predirs} = acc_modules(Modules, preprocess, Config0,
ModuleSetFile),
- SubdirAssoc = remember_cwd_subdir(Dir, Predirs),
+ %% Remember associated pre-dirs (used for plugin lookup)
+ PredirsAssoc = remember_cwd_predirs(Dir, Predirs),
%% Get the list of plug-in modules from rebar.config. These
%% modules may participate in preprocess and postprocess.
- {ok, PluginModules} = plugin_modules(Config1, SubdirAssoc),
+ {ok, PluginModules} = plugin_modules(Config1, PredirsAssoc),
{Config2, PluginPredirs} = acc_modules(PluginModules, preprocess,
Config1, ModuleSetFile),
@@ -222,7 +254,7 @@ process_dir0(Dir, Command, DirSet, Config0, CurrentCodePath,
%% Return the updated {config, dirset} as result
Res.
-remember_cwd_subdir(Cwd, Subdirs) ->
+remember_cwd_predirs(Cwd, Predirs) ->
Store = fun(Dir, Dict) ->
case dict:find(Dir, Dict) of
error ->
@@ -233,11 +265,10 @@ remember_cwd_subdir(Cwd, Subdirs) ->
?ABORT("Internal consistency assertion failed.~n"
"sub_dir ~s already associated with ~s.~n"
"Duplicate sub_dirs or deps entries?",
- [Dir, Existing]),
- Dict
+ [Dir, Existing])
end
end,
- lists:foldl(Store, dict:new(), Subdirs).
+ lists:foldl(Store, dict:new(), Predirs).
maybe_load_local_config(Dir, ParentConfig) ->
%% We need to ensure we don't overwrite custom
@@ -270,7 +301,6 @@ process_each([Dir | Rest], Command, Config, ModuleSetFile, DirSet) ->
process_each(Rest, Command, Config3, ModuleSetFile, DirSet2)
end.
-
%%
%% Given a list of module sets from rebar.app and a directory, find
%% the appropriate subset of modules for this directory
@@ -458,9 +488,9 @@ acc_modules([Module | Rest], Command, Config, File, Acc) ->
%%
%% Return a flat list of rebar plugin modules.
%%
-plugin_modules(Config, SubdirAssoc) ->
+plugin_modules(Config, PredirsAssoc) ->
Modules = lists:flatten(rebar_config:get_all(Config, plugins)),
- plugin_modules(Config, SubdirAssoc, ulist(Modules)).
+ plugin_modules(Config, PredirsAssoc, ulist(Modules)).
ulist(L) ->
ulist(L, []).
@@ -475,16 +505,16 @@ ulist([H | T], Acc) ->
ulist(T, [H | Acc])
end.
-plugin_modules(_Config, _SubdirAssoc, []) ->
+plugin_modules(_Config, _PredirsAssoc, []) ->
{ok, []};
-plugin_modules(Config, SubdirAssoc, Modules) ->
+plugin_modules(Config, PredirsAssoc, Modules) ->
FoundModules = [M || M <- Modules, code:which(M) =/= non_existing],
- plugin_modules(Config, SubdirAssoc, FoundModules, Modules -- FoundModules).
+ plugin_modules(Config, PredirsAssoc, FoundModules, Modules -- FoundModules).
-plugin_modules(_Config, _SubdirAssoc, FoundModules, []) ->
+plugin_modules(_Config, _PredirsAssoc, FoundModules, []) ->
{ok, FoundModules};
-plugin_modules(Config, SubdirAssoc, FoundModules, MissingModules) ->
- {Loaded, NotLoaded} = load_plugin_modules(Config, SubdirAssoc,
+plugin_modules(Config, PredirsAssoc, FoundModules, MissingModules) ->
+ {Loaded, NotLoaded} = load_plugin_modules(Config, PredirsAssoc,
MissingModules),
AllViablePlugins = FoundModules ++ Loaded,
case NotLoaded =/= [] of
@@ -498,37 +528,43 @@ plugin_modules(Config, SubdirAssoc, FoundModules, MissingModules) ->
end,
{ok, AllViablePlugins}.
-load_plugin_modules(Config, SubdirAssoc, Modules) ->
+load_plugin_modules(Config, PredirsAssoc, Modules) ->
Cwd = rebar_utils:get_cwd(),
- PluginDir = case rebar_config:get_local(Config, plugin_dir, undefined) of
- undefined ->
- filename:join(Cwd, "plugins");
- Dir ->
- Dir
- end,
+ PluginDirs = case rebar_config:get_local(Config, plugin_dir, undefined) of
+ undefined ->
+ % Plugin can be in the project's "plugins" folder
+ [filename:join(Cwd, "plugins")];
+ Dir ->
+ [Dir]
+ end ++
+ % We also want to include this case:
+ % Plugin can be in "plugins" directory of the plugin base directory. For
+ % example, Cwd depends on Plugin, and deps/Plugin/plugins/Plugin.erl is the
+ % plugin.
+ [
+ filename:join(Dir, "plugins") ||
+ Dir <- get_plugin_base_dirs(Cwd, PredirsAssoc)
+ ],
%% Find relevant sources in base_dir and plugin_dir
Erls = string:join([atom_to_list(M)++"\\.erl" || M <- Modules], "|"),
RE = "^" ++ Erls ++ "\$",
- BaseDir = get_plugin_base_dir(Cwd, SubdirAssoc),
%% If a plugin is found both in base_dir and plugin_dir, the clash
%% will provoke an error and we'll abort.
- Sources = rebar_utils:find_files(PluginDir, RE, false)
- ++ rebar_utils:find_files(BaseDir, RE, false),
+ Sources = [rebar_utils:find_files(PD, RE, false) || PD <- PluginDirs],
%% Compile and load plugins
- Loaded = [load_plugin(Src) || Src <- Sources],
+ Loaded = [load_plugin(Src) || Src <- lists:append(Sources)],
FilterMissing = is_missing_plugin(Loaded),
NotLoaded = [V || V <- Modules, FilterMissing(V)],
{Loaded, NotLoaded}.
-get_plugin_base_dir(Cwd, SubdirAssoc) ->
- case dict:find(Cwd, SubdirAssoc) of
- {ok, BaseDir} ->
- BaseDir;
- error ->
- Cwd
- end.
+%% @doc PredirsAssoc is a dictionary of plugindir -> 'parent' pairs
+%% 'parent' in this case depends on plugin; therefore we have to give
+%% all plugins that Cwd ('parent' in this case) depends on.
+get_plugin_base_dirs(Cwd, PredirsAssoc) ->
+ [PluginDir || {PluginDir, Master} <- dict:to_list(PredirsAssoc),
+ Master =:= Cwd].
is_missing_plugin(Loaded) ->
fun(Mod) -> not lists:member(Mod, Loaded) end.
diff --git a/src/rebar_ct.erl b/src/rebar_ct.erl
index e33c6c9..9951f8e 100644
--- a/src/rebar_ct.erl
+++ b/src/rebar_ct.erl
@@ -26,19 +26,22 @@
%% -------------------------------------------------------------------
%%
%% Targets:
-%% test - runs common test suites in ./test
-%% int_test - runs suites in ./int_test
-%% perf_test - runs suites inm ./perf_test
+%% test - run common test suites in ./test
+%% int_test - run suites in ./int_test
+%% perf_test - run suites inm ./perf_test
%%
%% Global options:
%% verbose=1 - show output from the common_test run as it goes
-%% suites="foo,bar" - runs <test>/foo_SUITE and <test>/bar_SUITE
-%% case="mycase" - runs individual test case foo_SUITE:mycase
+%% suites="foo,bar" - run <test>/foo_SUITE and <test>/bar_SUITE
+%% case="mycase" - run individual test case foo_SUITE:mycase
%% -------------------------------------------------------------------
-module(rebar_ct).
-export([ct/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -53,6 +56,26 @@ ct(Config, File) ->
%% ===================================================================
%% Internal functions
%% ===================================================================
+
+info(help, ct) ->
+ ?CONSOLE(
+ "Run common_test suites.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ "Valid command line options:~n"
+ " suites=foo,bar - run <test>/foo_SUITE and <test>/bar_SUITE~n"
+ " case=\"mycase\" - run individual test case foo_SUITE:mycase~n",
+ [
+ {ct_dir, "itest"},
+ {ct_log_dir, "test/logs"},
+ {ct_extra_params, "-boot start_sasl -s myapp"},
+ {ct_use_short_names, true}
+ ]).
+
run_test_if_present(TestDir, LogDir, Config, File) ->
case filelib:is_dir(TestDir) of
false ->
@@ -85,8 +108,16 @@ run_test(TestDir, LogDir, Config, _File) ->
" 2>&1 | tee -a " ++ RawLog
end,
- rebar_utils:sh(Cmd ++ Output, [{env,[{"TESTDIR", TestDir}]}]),
- check_log(Config, RawLog).
+ case rebar_utils:sh(Cmd ++ Output, [{env,[{"TESTDIR", TestDir}]}, return_on_error]) of
+ {ok,_} ->
+ %% in older versions of ct_run, this could have been a failure
+ %% that returned a non-0 code. Check for that!
+ check_success_log(Config, RawLog);
+ {error,Res} ->
+ %% In newer ct_run versions, this may be a sign of a good compile
+ %% that failed cases. In older version, it's a worse error.
+ check_fail_log(Config, RawLog, Cmd ++ Output, Res)
+ end.
clear_log(LogDir, RawLog) ->
case filelib:ensure_dir(filename:join(LogDir, "index.html")) of
@@ -101,7 +132,16 @@ clear_log(LogDir, RawLog) ->
%% calling ct with erl does not return non-zero on failure - have to check
%% log results
-check_log(Config, RawLog) ->
+check_success_log(Config, RawLog) ->
+ check_log(Config, RawLog, fun(Msg) -> ?CONSOLE("DONE.\n~s\n", [Msg]) end).
+
+check_fail_log(Config, RawLog, Command, {Rc, Output}) ->
+ check_log(Config, RawLog, fun(_Msg) ->
+ ?ABORT("~s failed with error: ~w and output:~n~s~n",
+ [Command, Rc, Output])
+ end).
+
+check_log(Config,RawLog,Fun) ->
{ok, Msg} =
rebar_utils:sh("grep -e 'TEST COMPLETE' -e '{error,make_failed}' "
++ RawLog, [{use_stdout, false}]),
@@ -119,9 +159,10 @@ check_log(Config, RawLog) ->
?FAIL;
true ->
- ?CONSOLE("DONE.\n~s\n", [Msg])
+ Fun(Msg)
end.
+
%% Show the log if it hasn't already been shown because verbose was on
show_log(Config, RawLog) ->
?CONSOLE("Showing log\n", []),
diff --git a/src/rebar_deps.erl b/src/rebar_deps.erl
index 074e929..313deaa 100644
--- a/src/rebar_deps.erl
+++ b/src/rebar_deps.erl
@@ -38,6 +38,8 @@
'delete-deps'/2,
'list-deps'/2]).
+%% for internal use only
+-export([info/2]).
-record(dep, { dir,
app,
@@ -203,6 +205,40 @@ do_check_deps(Config) ->
%% Internal functions
%% ===================================================================
+info(help, compile) ->
+ info_help("Display to be fetched dependencies");
+info(help, 'check-deps') ->
+ info_help("Display to be fetched dependencies");
+info(help, 'get-deps') ->
+ info_help("Fetch dependencies");
+info(help, 'update-deps') ->
+ info_help("Update fetched dependencies");
+info(help, 'delete-deps') ->
+ info_help("Delete fetched dependencies");
+info(help, 'list-deps') ->
+ info_help("List dependencies").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ "Valid command line options:~n"
+ " deps_dir=\"deps\" (override default or rebar.config deps_dir)~n",
+ [
+ Description,
+ {deps_dir, "deps"},
+ {deps, [application_name,
+ {application_name, "1.0.*"},
+ {application_name, "1.0.*",
+ {git, "git://github.com/rebar/rebar.git", {branch, "master"}}},
+ {application_name, "",
+ {git, "git://github.com/rebar/rebar.git", {branch, "master"}},
+ [raw]}]}
+ ]).
+
%% Added because of trans deps,
%% need all deps in same dir and should be the one set by the root rebar.config
%% Sets a default if root config has no deps_dir set
diff --git a/src/rebar_dia_compiler.erl b/src/rebar_dia_compiler.erl
index 51c075b..f81c734 100644
--- a/src/rebar_dia_compiler.erl
+++ b/src/rebar_dia_compiler.erl
@@ -28,6 +28,9 @@
-export([compile/2, clean/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -46,6 +49,23 @@ clean(_Config, _AppFile) ->
ok = rebar_file_utils:delete_each(GeneratedFiles),
ok.
+%% ===================================================================
+%% Internal functions
+%% ===================================================================
+
+info(help, compile) ->
+ info_help("Build Diameter (*.dia) sources");
+info(help, clean) ->
+ info_help("Delete generated Diameter files").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " {dia_opts, []} (see diameter_codegen:from_dict/4 documentation)~n",
+ [Description]).
+
-spec compile_dia(file:filename(), file:filename(),
rebar_config:config()) -> ok.
compile_dia(Source, Target, Config) ->
diff --git a/src/rebar_edoc.erl b/src/rebar_edoc.erl
index cf0239c..c828d27 100644
--- a/src/rebar_edoc.erl
+++ b/src/rebar_edoc.erl
@@ -39,6 +39,9 @@
-export([doc/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -71,6 +74,14 @@ doc(Config, File) ->
%% Internal functions
%% ===================================================================
+info(help, doc) ->
+ ?CONSOLE(
+ "Generate Erlang program documentation.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " {edoc_opts, []} (see edoc:application/3 documentation)~n",
+ []).
+
setup_code_path() ->
%% Setup code path prior to calling edoc so that edown, asciiedoc,
%% and the like can work properly when generating their own
diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl
index a63f9f4..caef0d2 100644
--- a/src/rebar_erlc_compiler.erl
+++ b/src/rebar_erlc_compiler.erl
@@ -29,8 +29,9 @@
-export([compile/2,
clean/2]).
-%% for internal use by only eunit and qc
--export([test_compile/3]).
+%% for internal use only
+-export([test_compile/3,
+ info/2]).
-include("rebar.hrl").
@@ -116,8 +117,6 @@ clean(_Config, _AppFile) ->
test_compile(Config, Cmd, OutDir) ->
%% Obtain all the test modules for inclusion in the compile stage.
- %% Notice: this could also be achieved with the following
- %% rebar.config option: {test_compile_opts, [{src_dirs, ["src", "test"]}]}
TestErls = rebar_utils:find_files("test", ".*\\.erl\$"),
%% Copy source files to eunit dir for cover in case they are not directly
@@ -165,6 +164,42 @@ test_compile(Config, Cmd, OutDir) ->
%% Internal functions
%% ===================================================================
+info(help, compile) ->
+ info_help("Build *.erl, *.yrl, *.xrl, and *.mib sources");
+info(help, clean) ->
+ info_help("Delete *.erl, *.yrl, *.xrl, and *.mib build results").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n",
+ [
+ Description,
+ {erl_opts, [no_debug_info,
+ {i, "myinclude"},
+ {src_dirs, ["src", "src2", "src3"]},
+ {platform_define,
+ "(linux|solaris|freebsd|darwin)", 'HAVE_SENDFILE'},
+ {platform_define, "(linux|freebsd)", 'BACKLOG', 128},
+ {platform_define, "R13", 'old_inets'}]},
+ {erl_first_files, ["mymib1", "mymib2"]},
+ {mib_opts, []},
+ {mib_first_files, []},
+ {xrl_opts, []},
+ {xrl_first_files, []},
+ {yrl_opts, []},
+ {yrl_first_files, []}
+ ]).
+
test_compile_config(Config, Cmd) ->
{Config1, TriqOpts} = triq_opts(Config),
{Config2, PropErOpts} = proper_opts(Config1),
@@ -265,11 +300,6 @@ doterl_compile(Config, OutDir, MoreSources) ->
true = code:set_path(CurrPath),
ok.
-
-%% ===================================================================
-%% Internal functions
-%% ===================================================================
-
-spec include_path(file:filename(),
rebar_config:config()) -> [file:filename(), ...].
include_path(Source, Config) ->
@@ -414,7 +444,6 @@ gather_src([], Srcs) ->
gather_src([Dir|Rest], Srcs) ->
gather_src(Rest, Srcs ++ rebar_utils:find_files(Dir, ".*\\.erl\$")).
-
-spec dirs(file:filename()) -> [file:filename()].
dirs(Dir) ->
[F || F <- filelib:wildcard(filename:join([Dir, "*"])), filelib:is_dir(F)].
diff --git a/src/rebar_erlydtl_compiler.erl b/src/rebar_erlydtl_compiler.erl
index b5fe899..4449be6 100644
--- a/src/rebar_erlydtl_compiler.erl
+++ b/src/rebar_erlydtl_compiler.erl
@@ -96,6 +96,9 @@
-export([compile/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -123,23 +126,39 @@ compile(Config, _AppFile) ->
true = code:set_path(OrigPath),
Result.
-
%% ===================================================================
%% Internal functions
%% ===================================================================
+info(help, compile) ->
+ ?CONSOLE(
+ "Build ErlyDtl (*.dtl) sources.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n",
+ [
+ {erlydtl_opts, [{doc_root, "templates"},
+ {out_dir, "ebin"},
+ {source_ext, ".dtl"},
+ {module_ext, "_dtl"},
+ {recursive, true}]}
+ ]).
+
erlydtl_opts(Config) ->
Opts = rebar_config:get(Config, erlydtl_opts, []),
Tuples = [{K,V} || {K,V} <- Opts],
case [L || L <- Opts, is_list(L), not io_lib:printable_list(L)] of
[] ->
- lists:keysort(1, Tuples);
+ [lists:keysort(1, Tuples)];
Lists ->
- lists:map(fun(L) ->
- lists:keysort(1, lists:foldl(fun({K,T}, Acc) ->
- lists:keystore(K, 1, Acc, {K, T})
- end, Tuples, L))
- end, Lists)
+ lists:map(
+ fun(L) ->
+ lists:keysort(1,
+ lists:foldl(
+ fun({K,T}, Acc) ->
+ lists:keystore(K, 1, Acc, {K, T})
+ end, Tuples, L))
+ end, Lists)
end.
option(Opt, DtlOpts) ->
diff --git a/src/rebar_escripter.erl b/src/rebar_escripter.erl
index 706cf7c..0cc43ef 100644
--- a/src/rebar_escripter.erl
+++ b/src/rebar_escripter.erl
@@ -29,6 +29,9 @@
-export([escriptize/2,
clean/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
-include_lib("kernel/include/file.hrl").
@@ -108,6 +111,30 @@ clean(Config0, AppFile) ->
%% Internal functions
%% ===================================================================
+info(help, escriptize) ->
+ info_help("Generate escript archive");
+info(help, clean) ->
+ info_help("Delete generated escript archive").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n",
+ [
+ Description,
+ {escript_name, "application"},
+ {escript_incl_apps, []},
+ {escript_shebang, "#!/usr/bin/env escript\n"},
+ {escript_comment, "%%\n"},
+ {escript_emu_args, "%%! -pa application/application/ebin\n"}
+ ]).
+
get_app_beams([], Acc) ->
Acc;
get_app_beams([App | Rest], Acc) ->
diff --git a/src/rebar_eunit.erl b/src/rebar_eunit.erl
index fd1a265..55e6a72 100644
--- a/src/rebar_eunit.erl
+++ b/src/rebar_eunit.erl
@@ -61,7 +61,7 @@
%% Additionally, for projects that have separate folders for the core
%% implementation, and for the unit tests, then the following
%% <code>rebar.config</code> option can be provided:
-%% <code>{test_compile_opts, [{src_dirs, ["dir"]}]}.</code>.
+%% <code>{eunit_compile_opts, [{src_dirs, ["src", "dir"]}]}.</code>.
%% @copyright 2009, 2010 Dave Smith
%% -------------------------------------------------------------------
-module(rebar_eunit).
@@ -69,6 +69,9 @@
-export([eunit/2,
clean/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
-define(EUNIT_DIR, ".eunit").
@@ -100,6 +103,40 @@ clean(_Config, _File) ->
%% Internal functions
%% ===================================================================
+info(help, eunit) ->
+ info_help("Run eunit tests");
+info(help, clean) ->
+ Description = ?FMT("Delete eunit test dir (~s)", [?EUNIT_DIR]),
+ info_help(Description).
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ "Valid command line options:~n"
+ " suites=\"foo,bar\" (Run tests in foo.erl, test/foo_tests.erl and~n"
+ " tests in bar.erl, test/bar_tests.erl)~n"
+ " tests=\"baz\" (For every existing suite, run the first test whose~n"
+ " name starts with bar and, if no such test exists,~n"
+ " run the test whose name starts with bar in the~n"
+ " suite's _tests module)~n",
+ [
+ Description,
+ {eunit_opts, []},
+ {eunit_compile_opts, []},
+ {eunit_first_files, []},
+ {cover_enabled, false},
+ {cover_print_enabled, false},
+ {cover_export_enabled, false}
+ ]).
+
run_eunit(Config, CodePath, SrcErls) ->
%% Build a list of all the .beams in ?EUNIT_DIR -- use this for
%% cover and eunit testing. Normally you can just tell cover
@@ -762,7 +799,6 @@ pause_until_net_kernel_stopped(0) ->
exit(net_kernel_stop_failed);
pause_until_net_kernel_stopped(N) ->
try
- _ = net_kernel:i(),
timer:sleep(100),
pause_until_net_kernel_stopped(N - 1)
catch
diff --git a/src/rebar_lfe_compiler.erl b/src/rebar_lfe_compiler.erl
index d288ca5..2a047d8 100644
--- a/src/rebar_lfe_compiler.erl
+++ b/src/rebar_lfe_compiler.erl
@@ -30,6 +30,9 @@
-export([compile/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -45,6 +48,14 @@ compile(Config, _AppFile) ->
%% Internal functions
%% ===================================================================
+info(help, compile) ->
+ ?CONSOLE(
+ "Build Lisp Flavoured Erlang (*.lfe) sources.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " erl_opts is reused.'~n",
+ []).
+
compile_lfe(Source, _Target, Config) ->
case code:which(lfe_comp) of
non_existing ->
diff --git a/src/rebar_neotoma_compiler.erl b/src/rebar_neotoma_compiler.erl
index 9bff892..5607aa4 100644
--- a/src/rebar_neotoma_compiler.erl
+++ b/src/rebar_neotoma_compiler.erl
@@ -42,6 +42,9 @@
-export([compile/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ============================================================================
@@ -57,9 +60,22 @@ compile(Config, _AppFile) ->
fun compile_neo/3, [{check_last_mod,false}]).
%% ============================================================================
-%% Public API
+%% Internal functions
%% ============================================================================
+info(help, compile) ->
+ ?CONSOLE(
+ "Build Neotoma (*.peg) sources.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n",
+ [
+ {neotom_opts, [{doc_root, "src"},
+ {out_dir, "src"},
+ {source_ext, ".peg"},
+ {module_ext, ""}]}
+ ]).
+
neotoma_opts(Config) ->
rebar_config:get(Config, neotoma_opts, []).
diff --git a/src/rebar_otp_app.erl b/src/rebar_otp_app.erl
index a62f584..6c52336 100644
--- a/src/rebar_otp_app.erl
+++ b/src/rebar_otp_app.erl
@@ -29,6 +29,9 @@
-export([compile/2,
clean/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -82,11 +85,26 @@ clean(_Config, File) ->
ok
end.
-
%% ===================================================================
%% Internal functions
%% ===================================================================
+info(help, compile) ->
+ info_help("Validate .app file");
+info(help, clean) ->
+ info_help("Delete .app file if generated from .app.src").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n",
+ [
+ Description,
+ {validate_app_modules, true}
+ ]).
+
preprocess(Config, AppSrcFile) ->
case rebar_app_utils:load_app_file(Config, AppSrcFile) of
{ok, Config1, AppName, AppData} ->
diff --git a/src/rebar_port_compiler.erl b/src/rebar_port_compiler.erl
index 70ee308..0abb044 100644
--- a/src/rebar_port_compiler.erl
+++ b/src/rebar_port_compiler.erl
@@ -27,8 +27,11 @@
-module(rebar_port_compiler).
-export([compile/2,
- clean/2,
- setup_env/1]).
+ clean/2]).
+
+%% for internal use only
+-export([setup_env/1,
+ info/2]).
-include("rebar.hrl").
@@ -97,7 +100,8 @@ compile(Config, AppFile) ->
[] ->
ok;
Specs ->
- SharedEnv = rebar_config:get_env(Config, ?MODULE),
+ SharedEnv = rebar_config:get_env(Config, rebar_deps) ++
+ rebar_config:get_env(Config, ?MODULE),
%% Compile each of the sources
NewBins = compile_sources(Config, Specs, SharedEnv),
@@ -149,6 +153,27 @@ setup_env(Config) ->
%% Internal functions
%% ===================================================================
+info(help, compile) ->
+ info_help("Build port sources");
+info(help, clean) ->
+ info_help("Delete port build results").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n"
+ " ~p~n",
+ [
+ Description,
+ {port_env, [{"CFLAGS", "$CFLAGS -Ifoo"},
+ {"freebsd", "LDFLAGS", "$LDFLAGS -lfoo"}]},
+ {port_specs, [{"priv/so_name.so", ["c_src/*.c"]},
+ {"linux", "priv/hello_linux", ["c_src/hello_linux.c"]},
+ {"linux", "priv/hello_linux", ["c_src/*.c"], [{env, []}]}]}
+ ]).
+
setup_env(Config, ExtraEnv) ->
%% Extract environment values from the config (if specified) and
%% merge with the default for this operating system. This enables
@@ -399,7 +424,7 @@ expand_vars_loop([], Recurse, Vars, Count) ->
expand_vars_loop(Recurse, [], Vars, Count-1);
expand_vars_loop([{K, V} | Rest], Recurse, Vars, Count) ->
%% Identify the variables that need expansion in this value
- ReOpts = [global, {capture, all_but_first, list}],
+ ReOpts = [global, {capture, all_but_first, list}, unicode],
case re:run(V, "\\\${?(\\w+)}?", ReOpts) of
{match, Matches} ->
%% Identify the unique variables that need to be expanded
@@ -472,8 +497,8 @@ erts_dir() ->
lists:concat([code:root_dir(), "/erts-", erlang:system_info(version)]).
os_env() ->
- Os = [list_to_tuple(re:split(S, "=", [{return, list}, {parts, 2}])) ||
- S <- os:getenv()],
+ ReOpts = [{return, list}, {parts, 2}, unicode],
+ Os = [list_to_tuple(re:split(S, "=", ReOpts)) || S <- os:getenv()],
%% Drop variables without a name (win32)
[T1 || {K, _V} = T1 <- Os, K =/= []].
diff --git a/src/rebar_protobuffs_compiler.erl b/src/rebar_protobuffs_compiler.erl
index 7ef58d6..579ecfb 100644
--- a/src/rebar_protobuffs_compiler.erl
+++ b/src/rebar_protobuffs_compiler.erl
@@ -29,6 +29,9 @@
-export([compile/2,
clean/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -57,7 +60,6 @@ compile(Config, _AppFile) ->
end
end.
-
clean(_Config, _AppFile) ->
%% Get a list of generated .beam and .hrl files and then delete them
Protos = rebar_utils:find_files("src", ".*\\.proto$"),
@@ -71,11 +73,24 @@ clean(_Config, _AppFile) ->
delete_each(Targets)
end.
-
%% ===================================================================
%% Internal functions
%% ===================================================================
+info(help, compile) ->
+ info_help("Build Protobuffs (*.proto) sources");
+info(help, clean) ->
+ info_help("Delete Protobuffs (*.proto) build results").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " erl_opts is passed as compile_flags to "
+ "protobuffs_compile:scan_file/2~n",
+ [Description]).
+
protobuffs_is_present() ->
code:which(protobuffs_compile) =/= non_existing.
@@ -115,7 +130,7 @@ compile_each(Config, [{Proto, Beam, Hrl} | Rest]) ->
ok = rebar_file_utils:mv(Hrl, "include"),
ok;
Other ->
- ?ERROR("Protobuff compile of ~s failed: ~p\n",
+ ?ERROR("Protobuffs compile of ~s failed: ~p\n",
[Proto, Other]),
?FAIL
end;
diff --git a/src/rebar_qc.erl b/src/rebar_qc.erl
index 5784f7d..53a6f52 100644
--- a/src/rebar_qc.erl
+++ b/src/rebar_qc.erl
@@ -26,7 +26,10 @@
%% -------------------------------------------------------------------
-module(rebar_qc).
--export([qc/2, triq/2, eqc/2]).
+-export([qc/2, triq/2, eqc/2, clean/2]).
+
+%% for internal use only
+-export([info/2]).
-include("rebar.hrl").
@@ -50,10 +53,26 @@ eqc(Config, _AppFile) ->
ok = load_qc_mod(eqc),
run_qc(Config, qc_opts(Config), eqc).
+clean(_Config, _File) ->
+ rebar_file_utils:rm_rf(?QC_DIR).
+
%% ===================================================================
%% Internal functions
%% ===================================================================
+info(help, qc) ->
+ ?CONSOLE(
+ "Test QuickCheck properties.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " {qc_opts, [{qc_mod, module()}, Options]}~n"
+ " ~p~n"
+ " ~p~n",
+ [
+ {qc_compile_opts, []},
+ {qc_first_files, []}
+ ]).
+
-define(TRIQ_MOD, triq).
-define(EQC_MOD, eqc).
@@ -156,6 +175,7 @@ qc_module(QC=triq, _QCOpts, M) ->
Failed ->
[Failed]
end;
+qc_module(QC=eqc, [], M) -> QC:module(M);
qc_module(QC=eqc, QCOpts, M) -> QC:module(QCOpts, M).
find_prop_mods() ->
diff --git a/src/rebar_reltool.erl b/src/rebar_reltool.erl
index 3c9b728..9f9488e 100644
--- a/src/rebar_reltool.erl
+++ b/src/rebar_reltool.erl
@@ -30,6 +30,9 @@
overlay/2,
clean/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
-include_lib("kernel/include/file.hrl").
@@ -80,6 +83,32 @@ clean(Config, ReltoolFile) ->
%% Internal functions
%% ===================================================================
+info(help, generate) ->
+ info_help("Build release with reltool");
+info(help, clean) ->
+ info_help("Delete release");
+info(help, overlay) ->
+ info_help("Run reltool overlays only").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~n"
+ "Valid reltool.config options:~n"
+ " {sys, []}~n"
+ " {target_dir, \"target\"}~n"
+ " {overlay_vars, \"overlay\"}~n"
+ " {overlay, []}~n"
+ "Valid command line options:~n"
+ " target_dir=target~n"
+ " overlay_vars=VarsFile~n"
+ " dump_spec=1 (write reltool target spec to reltool.spec)~n",
+ [
+ Description
+ ]).
+
check_vsn() ->
%% TODO: use application:load and application:get_key once we require
%% R14A or newer. There's no reltool.app before R14A.
@@ -137,22 +166,32 @@ process_overlay(Config, ReltoolConfig) ->
%% providing an additional file on the command-line.
%%
overlay_vars(Config, Vars0, ReltoolConfig) ->
- BaseVars = load_vars_file(proplists:get_value(overlay_vars, ReltoolConfig)),
- OverrideVars = load_vars_file(rebar_config:get_global(Config,
- overlay_vars,
- undefined)),
- M = fun(_Key, _Base, Override) -> Override end,
+ BaseVars = load_vars_file([proplists:get_value(overlay_vars, ReltoolConfig)]),
+ OverlayVars = rebar_config:get_global(Config, overlay_vars, []),
+ OverrideVars = load_vars_file(string:tokens(OverlayVars, ",")),
+ M = fun merge_overlay_var/3,
dict:merge(M, dict:merge(M, Vars0, BaseVars), OverrideVars).
+merge_overlay_var(_Key, _Base, Override) -> Override.
+
%%
%% If a filename is provided, construct a dict of terms
%%
-load_vars_file(undefined) ->
+load_vars_file([undefined]) ->
dict:new();
-load_vars_file(File) ->
+load_vars_file([]) ->
+ dict:new();
+load_vars_file(Files) ->
+ load_vars_file(Files, dict:new()).
+
+load_vars_file([], Dict) ->
+ Dict;
+load_vars_file([File | Files], BaseVars) ->
case rebar_config:consult_file(File) of
{ok, Terms} ->
- dict:from_list(Terms);
+ OverrideVars = dict:from_list(Terms),
+ M = fun merge_overlay_var/3,
+ load_vars_file(Files, dict:merge(M, BaseVars, OverrideVars));
{error, Reason} ->
?ABORT("Unable to load overlay_vars from ~p: ~p\n", [File, Reason])
end.
diff --git a/src/rebar_require_vsn.erl b/src/rebar_require_vsn.erl
index 83cb79d..385f55c 100644
--- a/src/rebar_require_vsn.erl
+++ b/src/rebar_require_vsn.erl
@@ -33,6 +33,9 @@
-export([compile/2,
eunit/2]).
+%% for internal use only
+-export([info/2]).
+
%% ===================================================================
%% Public API
%% ===================================================================
@@ -47,6 +50,25 @@ eunit(Config, _) ->
%% Internal functions
%% ====================================================================
+info(help, compile) ->
+ info_help();
+info(help, eunit) ->
+ info_help().
+
+info_help() ->
+ ?CONSOLE(
+ "Check required ERTS or OTP release version.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n",
+ [
+ {require_erts_vsn, ".*"},
+ {require_otp_vsn, ".*"},
+ {require_min_otp_vsn, ".*"}
+ ]).
+
check_versions(Config) ->
ErtsRegex = rebar_config:get(Config, require_erts_vsn, ".*"),
ReOpts = [{capture, none}],
@@ -77,18 +99,18 @@ check_versions(Config) ->
"OTP Release"),
case {OtpMaj, OtpMin} >= {MinMaj, MinMin} of
true ->
- ?DEBUG("~s satisfies the requirement for vsn ~s~n",
- [erlang:system_info(otp_release),
+ ?DEBUG("~s satisfies the requirement for vsn ~s~n",
+ [erlang:system_info(otp_release),
MinOtpVsn]);
- false ->
+ false ->
?ABORT("OTP release ~s or later is required, you have: ~s~n",
[MinOtpVsn,
erlang:system_info(otp_release)])
- end
+ end
end.
version_tuple(OtpRelease, Type) ->
- case re:run(OtpRelease, "R(\\d+)B?-?(\\d+)?", [{capture, all, list}]) of
+ case re:run(OtpRelease, "R(\\d+)B?-?(\\d+)?", [{capture, all, list}]) of
{match, [_Full, Maj, Min]} ->
{list_to_integer(Maj), list_to_integer(Min)};
{match, [_Full, Maj]} ->
diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl
index 0e1eef1..e997975 100644
--- a/src/rebar_templater.erl
+++ b/src/rebar_templater.erl
@@ -35,6 +35,9 @@
-export([resolve_variables/2,
render/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
-define(TEMPLATE_RE, ".*\\.template\$").
@@ -81,6 +84,9 @@ resolve_variables([], Dict) ->
resolve_variables([{Key, Value0} | Rest], Dict) when is_list(Value0) ->
Value = render(list_to_binary(Value0), Dict),
resolve_variables(Rest, dict:store(Key, Value, Dict));
+resolve_variables([{Key, {list, Dicts}} | Rest], Dict) when is_list(Dicts) ->
+ %% just un-tag it so mustache can use it
+ resolve_variables(Rest, dict:store(Key, Dicts, Dict));
resolve_variables([_Pair | Rest], Dict) ->
resolve_variables(Rest, Dict).
@@ -98,6 +104,27 @@ render(Bin, Context) ->
%% Internal functions
%% ===================================================================
+info(help, create) ->
+ ?CONSOLE(
+ "Create skel based on template and vars.~n"
+ "~n"
+ "Valid command line options:~n"
+ " template= [var=foo,...]~n", []);
+info(help, 'create-app') ->
+ ?CONSOLE(
+ "Create simple app skel.~n"
+ "~n"
+ "Valid command line options:~n"
+ " [appid=myapp]~n", []);
+info(help, 'create-node') ->
+ ?CONSOLE(
+ "Create simple node skel.~n"
+ "~n"
+ "Valid command line options:~n"
+ " [nodeid=mynode]~n", []);
+info(help, 'list-templates') ->
+ ?CONSOLE("List available templates.~n", []).
+
create1(Config, TemplateId) ->
{AvailTemplates, Files} = find_templates(Config),
?DEBUG("Available templates: ~p\n", [AvailTemplates]),
@@ -134,14 +161,14 @@ create1(Config, TemplateId) ->
undefined ->
Context0;
File ->
- case file:consult(File) of
- {ok, Terms} ->
- %% TODO: Cleanup/merge with similar code in rebar_reltool
- M = fun(_Key, _Base, Override) -> Override end,
- dict:merge(M, Context0, dict:from_list(Terms));
+ case consult(load_file([], file, File)) of
{error, Reason} ->
?ABORT("Unable to load template_vars from ~s: ~p\n",
- [File, Reason])
+ [File, Reason]);
+ Terms ->
+ %% TODO: Cleanup/merge with similar code in rebar_reltool
+ M = fun(_Key, _Base, Override) -> Override end,
+ dict:merge(M, Context0, dict:from_list(Terms))
end
end,
@@ -275,7 +302,7 @@ consult(Cont, Str, Acc) ->
case Result of
{ok, Tokens, _} ->
{ok, Term} = erl_parse:parse_term(Tokens),
- consult([], Remaining, [Term | Acc]);
+ consult([], Remaining, [maybe_dict(Term) | Acc]);
{eof, _Other} ->
lists:reverse(Acc);
{error, Info, _} ->
@@ -286,6 +313,13 @@ consult(Cont, Str, Acc) ->
end.
+maybe_dict({Key, {list, Dicts}}) ->
+ %% this is a 'list' element; a list of lists representing dicts
+ {Key, {list, [dict:from_list(D) || D <- Dicts]}};
+maybe_dict(Term) ->
+ Term.
+
+
write_file(Output, Data, Force) ->
%% determine if the target file already exists
FileExists = filelib:is_regular(Output),
diff --git a/src/rebar_upgrade.erl b/src/rebar_upgrade.erl
index 14ea758..d18603c 100644
--- a/src/rebar_upgrade.erl
+++ b/src/rebar_upgrade.erl
@@ -32,6 +32,9 @@
-export(['generate-upgrade'/2]).
+%% for internal use only
+-export([info/2]).
+
-define(TMP, "_tmp").
%% ====================================================================
@@ -80,6 +83,13 @@
%% Internal functions
%% ==================================================================
+info(help, 'generate-upgrade') ->
+ ?CONSOLE("Build an upgrade package.~n"
+ "~n"
+ "Valid command line options:~n"
+ " previous_release=path~n",
+ []).
+
run_checks(Config, OldVerPath, ReltoolConfig) ->
true = rebar_utils:prop_check(filelib:is_dir(OldVerPath),
"Release directory doesn't exist (~p)~n",
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index bb58460..fd93f98 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -195,7 +195,7 @@ expand_env_variable(InStr, VarName, RawVarValue) ->
%% Use a regex to match/replace:
%% Given variable "FOO": match $FOO\s | $FOOeol | ${FOO}
RegEx = io_lib:format("\\\$(~s(\\s|$)|{~s})", [VarName, VarName]),
- ReOpts = [global, {return, list}],
+ ReOpts = [global, {return, list}, unicode],
re:replace(InStr, RegEx, [VarValue, "\\2"], ReOpts)
end.
diff --git a/src/rebar_xref.erl b/src/rebar_xref.erl
index a55d71d..8c0a872 100644
--- a/src/rebar_xref.erl
+++ b/src/rebar_xref.erl
@@ -37,6 +37,9 @@
-export([xref/2]).
+%% for internal use only
+-export([info/2]).
+
%% ===================================================================
%% Public API
%% ===================================================================
@@ -100,6 +103,22 @@ xref(Config, _) ->
%% Internal functions
%% ===================================================================
+info(help, xref) ->
+ ?CONSOLE(
+ "Run cross reference analysis.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n",
+ [
+ {xref_warnings, false},
+ {xref_checks, [exports_not_used, undefined_function_calls]},
+ {xref_queries,
+ [{"(xc - uc) || (xu - x - b"
+ " - (\"mod\":\".*foo\"/\"4\"))",[]}]}
+ ]).
+
check_exports_not_used() ->
{ok, UnusedExports0} = xref:analyze(xref, exports_not_used),
UnusedExports = filter_away_ignored(UnusedExports0),
diff --git a/test/upgrade_project/rel/files/dummy b/test/upgrade_project/rel/files/dummy
index cfbfd4f..c2ef258 100755
--- a/test/upgrade_project/rel/files/dummy
+++ b/test/upgrade_project/rel/files/dummy
@@ -2,25 +2,41 @@
# -*- tab-width:4;indent-tabs-mode:nil -*-
# ex: ts=4 sw=4 et
-RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd)
+# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is.
+if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then
+ POSIX_SHELL="true"
+ export POSIX_SHELL
+ # To support 'whoami' add /usr/ucb to path
+ PATH=/usr/ucb:$PATH
+ export PATH
+ exec /usr/bin/ksh $0 "$@"
+fi
+
+# clear it so if we invoke other scripts, they run as ksh
+unset POSIX_SHELL
+
+RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd -P)
+
+CALLER_DIR=$PWD
RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*}
RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc
-RUNNER_LOG_DIR=$RUNNER_BASE_DIR/log
# Note the trailing slash on $PIPE_DIR/
PIPE_DIR=/tmp/$RUNNER_BASE_DIR/
RUNNER_USER=
+WHOAMI=$(whoami)
# Make sure this script is running as the appropriate user
-if [ ! -z "$RUNNER_USER" ] && [ `whoami` != "$RUNNER_USER" ]; then
- exec sudo -u $RUNNER_USER -i $0 $@
+if ([ "$RUNNER_USER" ] && [ "x$WHOAMI" != "x$RUNNER_USER" ]); then
+ type sudo > /dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "sudo doesn't appear to be installed and your EUID isn't $RUNNER_USER" 1>&2
+ exit 1
+ fi
+ echo "Attempting to restart script through sudo -H -u $RUNNER_USER" >&2
+ exec sudo -H -u $RUNNER_USER -i $RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT $@
fi
-# Make sure CWD is set to runner base dir
-cd $RUNNER_BASE_DIR
-
-# Make sure log directory exists
-mkdir -p $RUNNER_LOG_DIR
# Identify the script name
SCRIPT=`basename $0`
@@ -29,22 +45,37 @@ START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data`
ERTS_VSN=${START_ERL% *}
APP_VSN=${START_ERL#* }
-# Use releases/VSN/vm.args if it exists otherwise use etc/vm.args
-if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" ]; then
- VMARGS_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args"
+# Use $CWD/vm.args if exists, otherwise releases/APP_VSN/vm.args, or
+# else etc/vm.args
+if [ -e "$CALLER_DIR/vm.args" ]; then
+ VMARGS_PATH=$CALLER_DIR/vm.args
+ USE_DIR=$CALLER_DIR
else
- VMARGS_PATH="$RUNNER_ETC_DIR/vm.args"
+ USE_DIR=$RUNNER_BASE_DIR
+ if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" ]; then
+ VMARGS_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args"
+ else
+ VMARGS_PATH="$RUNNER_ETC_DIR/vm.args"
+ fi
fi
+RUNNER_LOG_DIR=$USE_DIR/log
+# Make sure log directory exists
+mkdir -p $RUNNER_LOG_DIR
+
# Use releases/VSN/sys.config if it exists otherwise use etc/app.config
-if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" ]; then
- CONFIG_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config"
+if [ -e "$USE_DIR/sys.config" ]; then
+ CONFIG_PATH="$USE_DIR/sys.config"
else
- CONFIG_PATH="$RUNNER_ETC_DIR/app.config"
+ if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" ]; then
+ CONFIG_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config"
+ else
+ CONFIG_PATH="$RUNNER_ETC_DIR/app.config"
+ fi
fi
# Extract the target node name from node.args
-NAME_ARG=`egrep '^-s?name' $VMARGS_PATH`
+NAME_ARG=`egrep '^\-s?name' $VMARGS_PATH`
if [ -z "$NAME_ARG" ]; then
echo "vm.args needs to have either -name or -sname parameter."
exit 1
@@ -54,17 +85,24 @@ fi
REMSH_TYPE=`echo $NAME_ARG | awk '{print $1}'`
REMSH_NAME=`echo $NAME_ARG | awk '{print $2}'`
-# Note the `date +%s`, used to allow multiple remsh to the same node transparently
-REMSH_NAME_ARG="$REMSH_TYPE attach`date +%s`@`echo $REMSH_NAME | awk -F@ '{print $2}'`"
+# Note the `date +%s`, used to allow multiple remsh to the same node
+# transparently
+REMSH_NAME_ARG="$REMSH_TYPE remsh`date +%s`@`echo $REMSH_NAME | awk -F@ '{print $2}'`"
REMSH_REMSH_ARG="-remsh $REMSH_NAME"
# Extract the target cookie
-COOKIE_ARG=`grep '^-setcookie' $VMARGS_PATH`
+COOKIE_ARG=`grep '^\-setcookie' $VMARGS_PATH`
if [ -z "$COOKIE_ARG" ]; then
echo "vm.args needs to have a -setcookie parameter."
exit 1
fi
+# Make sure CWD is set to the right dir
+cd $USE_DIR
+
+# Make sure log directory exists
+mkdir -p $USE_DIR/log
+
# Add ERTS bin dir to our path
ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
@@ -74,47 +112,83 @@ NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG"
# Setup remote shell command to control node
REMSH="$ERTS_PATH/erl $REMSH_NAME_ARG $REMSH_REMSH_ARG $COOKIE_ARG"
+# Common functions
+
+# Ping node without allowing nodetool to take stdin
+ping_node() {
+ $NODETOOL ping < /dev/null
+}
+
+# Set the PID global variable, return 1 on error
+get_pid() {
+ PID=`$NODETOOL getpid < /dev/null`
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ echo "Node is not running!"
+ return 1
+ fi
+
+ # don't allow empty or init pid's
+ if [ -z $PID ] || [ "$PID" -le 1 ]; then
+ return 1
+ fi
+
+ return 0
+}
+
# Check the first argument for instructions
case "$1" in
- start)
+ start|start_boot)
# Make sure there is not already a node running
- RES=`$NODETOOL ping`
+ RES=`ping_node`
if [ "$RES" = "pong" ]; then
echo "Node is already running!"
exit 1
fi
- shift # remove $1
+ case "$1" in
+ start)
+ shift
+ START_OPTION="console"
+ HEART_OPTION="start"
+ ;;
+ start_boot)
+ shift
+ START_OPTION="console_boot"
+ HEART_OPTION="start_boot"
+ ;;
+ esac
RUN_PARAM=$(printf "\'%s\' " "$@")
- HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT start $RUN_PARAM"
+ HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT $HEART_OPTION $RUN_PARAM"
export HEART_COMMAND
mkdir -p $PIPE_DIR
- $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT console $RUN_PARAM" 2>&1
+ $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT $START_OPTION $RUN_PARAM" 2>&1
;;
stop)
# Wait for the node to completely stop...
case `uname -s` in
- Linux|Darwin|FreeBSD|DragonFly|NetBSD|OpenBSD)
- # PID COMMAND
- PID=`ps ax -o pid= -o command=|\
- grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'`
- ;;
- SunOS)
- # PID COMMAND
- PID=`ps -ef -o pid= -o args=|\
- grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'`
- ;;
- CYGWIN*)
- # UID PID PPID TTY STIME COMMAND
- PID=`ps -efW|grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $2}'`
- ;;
+ Darwin)
+ # Make sure we explicitly set this because iTerm.app doesn't for
+ # some reason.
+ COMMAND_MODE=unix2003
esac
+
+ # Get the PID from nodetool
+ get_pid
+ GPR=$?
+ if [ "$GPR" -ne 0 ] || [ -z $PID ]; then
+ exit $GPR
+ fi
+
+ # Tell nodetool to initiate a stop
$NODETOOL stop
ES=$?
if [ "$ES" -ne 0 ]; then
exit $ES
fi
- while `kill -0 $PID 2>/dev/null`;
+
+ # Wait for the node to completely stop...
+ while `kill -s 0 $PID 2>/dev/null`
do
sleep 1
done
@@ -140,7 +214,7 @@ case "$1" in
ping)
## See if the VM is alive
- $NODETOOL ping
+ ping_node
ES=$?
if [ "$ES" -ne 0 ]; then
exit $ES
@@ -148,8 +222,8 @@ case "$1" in
;;
attach)
- # Make sure a node IS running
- RES=`$NODETOOL ping`
+ # Make sure a node is running
+ ping_node
ES=$?
if [ "$ES" -ne 0 ]; then
echo "Node is not running!"
@@ -161,8 +235,8 @@ case "$1" in
;;
remote_console)
- # Make sure a node IS running
- RES=`$NODETOOL ping`
+ # Make sure a node is running
+ ping_node
ES=$?
if [ "$ES" -ne 0 ]; then
echo "Node is not running!"
@@ -182,7 +256,7 @@ case "$1" in
fi
# Make sure a node IS running
- RES=`$NODETOOL ping`
+ ping_node
ES=$?
if [ "$ES" -ne 0 ]; then
echo "Node is not running!"
@@ -195,12 +269,18 @@ case "$1" in
$ERTS_PATH/escript $RUNNER_BASE_DIR/bin/install_upgrade.escript $node_name $erlang_cookie $2
;;
- console|console_clean)
+ console|console_clean|console_boot)
# .boot file typically just $SCRIPT (ie, the app name)
- # however, for debugging, sometimes start_clean.boot is useful:
+ # however, for debugging, sometimes start_clean.boot is useful.
+ # For e.g. 'setup', one may even want to name another boot script.
case "$1" in
console) BOOTFILE=$SCRIPT ;;
console_clean) BOOTFILE=start_clean ;;
+ console_boot)
+ shift
+ BOOTFILE="$1"
+ shift
+ ;;
esac
# Setup beam-required vars
ROOTDIR=$RUNNER_BASE_DIR
@@ -249,8 +329,17 @@ case "$1" in
# Start the VM
exec $CMD -- ${1+"$@"}
;;
+ getpid)
+ # Get the PID from nodetool
+ get_pid
+ ES=$?
+ if [ "$ES" -ne 0 ] || [ -z $PID ]; then
+ exit $ES
+ fi
+ echo $PID
+ ;;
*)
- echo "Usage: $SCRIPT {start|foreground|stop|restart|reboot|ping|console|console_clean|attach|remote_console|upgrade}"
+ echo "Usage: $SCRIPT {start|start_boot <file>|foreground|stop|restart|reboot|ping|console|getpid|console_clean|console_boot <file>|attach|remote_console|upgrade}"
exit 1
;;
esac
diff --git a/test/upgrade_project/rel/files/erl b/test/upgrade_project/rel/files/erl
index 6f65e3f..f4c63af 100755
--- a/test/upgrade_project/rel/files/erl
+++ b/test/upgrade_project/rel/files/erl
@@ -1,16 +1,26 @@
#!/bin/sh
-## This script replaces the default "erl" in erts-VSN/bin. This is necessary
-## as escript depends on erl and in turn, erl depends on having access to a
-## bootscript (start.boot). Note that this script is ONLY invoked as a side-effect
-## of running escript -- the embedded node bypasses erl and uses erlexec directly
-## (as it should).
+# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is.
+if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then
+ POSIX_SHELL="true"
+ export POSIX_SHELL
+ exec /usr/bin/ksh $0 "$@"
+fi
+
+# clear it so if we invoke other scripts, they run as ksh as well
+unset POSIX_SHELL
+
+## This script replaces the default "erl" in erts-VSN/bin. This is
+## necessary as escript depends on erl and in turn, erl depends on
+## having access to a bootscript (start.boot). Note that this script
+## is ONLY invoked as a side-effect of running escript -- the embedded
+## node bypasses erl and uses erlexec directly (as it should).
##
-## Note that this script makes the assumption that there is a start_clean.boot
-## file available in $ROOTDIR/release/VSN.
+## Note that this script makes the assumption that there is a
+## start_clean.boot file available in $ROOTDIR/release/VSN.
# Determine the abspath of where this script is executing from.
-ERTS_BIN_DIR=$(cd ${0%/*} && pwd)
+ERTS_BIN_DIR=$(cd ${0%/*} && pwd -P)
# Now determine the root directory -- this script runs from erts-VSN/bin,
# so we simply need to strip off two dirs from the end of the ERTS_BIN_DIR
diff --git a/test/upgrade_project/rel/files/nodetool b/test/upgrade_project/rel/files/nodetool
index eb08fa4..ce06c6a 100644
--- a/test/upgrade_project/rel/files/nodetool
+++ b/test/upgrade_project/rel/files/nodetool
@@ -1,3 +1,4 @@
+#!/usr/bin/env escript
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ft=erlang ts=4 sw=4 et
%% -------------------------------------------------------------------
@@ -5,25 +6,51 @@
%% nodetool: Helper Script for interacting with live nodes
%%
%% -------------------------------------------------------------------
-
main(Args) ->
ok = start_epmd(),
%% Extract the args
{RestArgs, TargetNode} = process_args(Args, [], undefined),
+ %% any commands that don't need a running node
+ case RestArgs of
+ ["chkconfig", File] ->
+ case file:consult(File) of
+ {ok, _} ->
+ io:format("ok\n"),
+ halt(0);
+ {error, {Line, Mod, Term}} ->
+ io:format(standard_error, ["Error on line ",
+ file:format_error({Line, Mod, Term}), "\n"], []),
+ halt(1);
+ {error, R} ->
+ io:format(standard_error, ["Error reading config file: ",
+ file:format_error(R), "\n"], []),
+ halt(1)
+ end;
+ _ ->
+ ok
+ end,
+
%% See if the node is currently running -- if it's not, we'll bail
- case {net_kernel:hidden_connect_node(TargetNode), net_adm:ping(TargetNode)} of
+ case {net_kernel:hidden_connect_node(TargetNode),
+ net_adm:ping(TargetNode)} of
{true, pong} ->
ok;
+ {false,pong} ->
+ io:format("Failed to connect to node ~p .\n", [TargetNode]),
+ halt(1);
{_, pang} ->
io:format("Node ~p not responding to pings.\n", [TargetNode]),
halt(1)
end,
case RestArgs of
+ ["getpid"] ->
+ io:format("~p\n",
+ [list_to_integer(rpc:call(TargetNode, os, getpid, []))]);
["ping"] ->
- %% If we got this far, the node already responsed to a ping, so just dump
- %% a "pong"
+ %% If we got this far, the node already responsed to a
+ %% ping, so just dump a "pong"
io:format("pong\n");
["stop"] ->
io:format("~p\n", [rpc:call(TargetNode, init, stop, [], 60000)]);
@@ -32,7 +59,9 @@ main(Args) ->
["reboot"] ->
io:format("~p\n", [rpc:call(TargetNode, init, reboot, [], 60000)]);
["rpc", Module, Function | RpcArgs] ->
- case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
+ case rpc:call(TargetNode,
+ list_to_atom(Module),
+ list_to_atom(Function),
[RpcArgs], 60000) of
ok ->
ok;
@@ -42,8 +71,23 @@ main(Args) ->
_ ->
halt(1)
end;
+ ["rpc_infinity", Module, Function | RpcArgs] ->
+ case rpc:call(TargetNode,
+ list_to_atom(Module),
+ list_to_atom(Function),
+ [RpcArgs], infinity) of
+ ok ->
+ ok;
+ {badrpc, Reason} ->
+ io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
+ halt(1);
+ _ ->
+ halt(1)
+ end;
["rpcterms", Module, Function, ArgsAsString] ->
- case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
+ case rpc:call(TargetNode,
+ list_to_atom(Module),
+ list_to_atom(Function),
consult(ArgsAsString), 60000) of
{badrpc, Reason} ->
io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
@@ -53,7 +97,7 @@ main(Args) ->
end;
Other ->
io:format("Other: ~p\n", [Other]),
- io:format("Usage: nodetool {ping|stop|restart|reboot}\n")
+ io:format("Usage: nodetool {chkconfig|getpid|ping|stop|restart|reboot|rpc|rpc_infinity|rpcterms}\n")
end,
net_kernel:stop().
diff --git a/test/upgrade_project/rel/files/sys.config b/test/upgrade_project/rel/files/sys.config
index d7677e7..3b7f6bd 100644
--- a/test/upgrade_project/rel/files/sys.config
+++ b/test/upgrade_project/rel/files/sys.config
@@ -8,3 +8,4 @@
{error_logger_mf_maxfiles, 5} % 5 files max
]}
].
+
diff --git a/test/upgrade_project/rel/files/vm.args b/test/upgrade_project/rel/files/vm.args
index 2d64e25..a9aeb64 100644
--- a/test/upgrade_project/rel/files/vm.args
+++ b/test/upgrade_project/rel/files/vm.args
@@ -9,11 +9,11 @@
##-heart
## Enable kernel poll and a few async threads
-+K true
-+A 5
+##+K true
+##+A 5
## Increase number of concurrent ports/sockets
--env ERL_MAX_PORTS 4096
+##-env ERL_MAX_PORTS 4096
## Tweak GC to run more often
--env ERL_FULLSWEEP_AFTER 10
+##-env ERL_FULLSWEEP_AFTER 10