aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuis Rascão <[email protected]>2017-10-19 05:23:47 +0100
committerTristan Sloughter <[email protected]>2017-10-18 21:23:47 -0700
commit9855022433c9e3e08850c13b925b94f3b87df6c3 (patch)
treec51a6e321b7ba730d04cca06139b71fb9625bdd8
parent5050dd81853923e904080de1da56e049f24459e3 (diff)
downloadrelx-9855022433c9e3e08850c13b925b94f3b87df6c3.tar.gz
relx-9855022433c9e3e08850c13b925b94f3b87df6c3.tar.bz2
relx-9855022433c9e3e08850c13b925b94f3b87df6c3.zip
Start script extensions (#613)
* Extended start script command extensions Provide a mechanism that allows for the application to extend the list of commands available to be invoked from the start script. An application may be able to define a 'foo' extension that is associated with a 'foo_script' written and maintained by the applicationr, (this association is kept in rebar.config), upon invocation of bin/<release_name> foo the 'foo_script' will then be invoked. * Add test coverage for extension script * Ensure extended script usage argument
-rwxr-xr-xpriv/templates/extended_bin55
-rw-r--r--src/rlx_prv_assembler.erl26
-rw-r--r--test/rlx_extended_bin_SUITE.erl46
3 files changed, 120 insertions, 7 deletions
diff --git a/priv/templates/extended_bin b/priv/templates/extended_bin
index 0abf38b..6742cf7 100755
--- a/priv/templates/extended_bin
+++ b/priv/templates/extended_bin
@@ -47,6 +47,7 @@ POST_STOP_HOOKS="{{{ post_stop_hooks }}}"
PRE_INSTALL_UPGRADE_HOOKS="{{{ pre_install_upgrade_hooks }}}"
POST_INSTALL_UPGRADE_HOOKS="{{{ post_install_upgrade_hooks }}}"
STATUS_HOOK="{{{ status_hook }}}"
+EXTENSIONS="{{{ extensions }}}"
relx_usage() {
command="$1"
@@ -107,7 +108,15 @@ relx_usage() {
echo "Obtains node status information."
;;
*)
- echo "Usage: $REL_NAME {start|start_boot <file>|foreground|stop|restart|reboot|pid|ping|console|console_clean|console_boot <file>|attach|remote_console|upgrade|downgrade|install|uninstall|versions|escript|rpc|rpcterms|eval|status}"
+ # check for extension
+ IS_EXTENSION=$(relx_is_extension $command)
+ if [ "$IS_EXTENSION" = "1" ]; then
+ EXTENSION_SCRIPT=$(relx_get_extension_script $command)
+ relx_run_extension $EXTENSION_SCRIPT help
+ else
+ EXTENSIONS=`echo $EXTENSIONS | sed -e 's/|undefined//g'`
+ echo "Usage: $REL_NAME {start|start_boot <file>|foreground|stop|restart|reboot|pid|ping|console|console_clean|console_boot <file>|attach|remote_console|upgrade|downgrade|install|uninstall|versions|escript|rpc|rpcterms|eval|status|$EXTENSIONS}"
+ fi
;;
esac
}
@@ -285,6 +294,40 @@ relx_run_hooks() {
done
}
+relx_is_extension() {
+ EXTENSION=$1
+ case "$EXTENSION" in
+ {{{ extensions }}})
+ echo "1"
+ ;;
+ *)
+ echo "0"
+ ;;
+ esac
+}
+
+relx_get_extension_script() {
+ EXTENSION=$1
+ # below are the extensions declarations
+ # of the form:
+ # foo_extension="path/to/foo_script";bar_extension="path/to/bar_script"
+ {{{extension_declarations}}}
+ # get the command extension (eg. foo) and
+ # obtain the actual script filename that it
+ # refers to (eg. "path/to/foo_script"
+ eval echo "$"${EXTENSION}_extension""
+}
+
+relx_run_extension() {
+ # drop the first argument which is the name of the
+ # extension script
+ EXTENSION_SCRIPT=$1
+ shift
+ # all extension script locations are expected to be
+ # relative to the start script location
+ [ "$SCRIPT_DIR/$EXTENSION_SCRIPT" ] && . "$SCRIPT_DIR/$EXTENSION_SCRIPT" $@
+}
+
find_erts_dir
export ROOTDIR="$RELEASE_ROOT_DIR"
export BINDIR="$ERTS_DIR/bin"
@@ -671,7 +714,15 @@ case "$1" in
relx_usage $TOPIC
;;
*)
- relx_usage
+ # check for extension
+ IS_EXTENSION=$(relx_is_extension $1)
+ if [ "$IS_EXTENSION" = "1" ]; then
+ EXTENSION_SCRIPT=$(relx_get_extension_script $1)
+ shift
+ relx_run_extension $EXTENSION_SCRIPT $@
+ else
+ relx_usage $1
+ fi
exit 1
;;
esac
diff --git a/src/rlx_prv_assembler.erl b/src/rlx_prv_assembler.erl
index 2088de6..a6bf5f8 100644
--- a/src/rlx_prv_assembler.erl
+++ b/src/rlx_prv_assembler.erl
@@ -401,9 +401,12 @@ write_bin_file(State, Release, OutputDir, RelDir) ->
extended_start_script_hooks,
[]),
State),
+ Extensions = rlx_state:get(State,
+ extended_start_script_extensions,
+ []),
extended_bin_file_contents(OsFamily, RelName, RelVsn,
rlx_release:erts(Release), ErlOpts,
- Hooks)
+ Hooks, Extensions)
end,
%% We generate the start script by default, unless the user
%% tells us not too
@@ -787,7 +790,7 @@ bin_file_contents(OsFamily, RelName, RelVsn, ErtsVsn, ErlOpts) ->
render(Template, [{rel_name, RelName}, {rel_vsn, RelVsn},
{erts_vsn, ErtsVsn}, {erl_opts, ErlOpts}]).
-extended_bin_file_contents(OsFamily, RelName, RelVsn, ErtsVsn, ErlOpts, Hooks) ->
+extended_bin_file_contents(OsFamily, RelName, RelVsn, ErtsVsn, ErlOpts, Hooks, Extensions) ->
Template = case OsFamily of
unix -> extended_bin;
win32 -> extended_bin_windows
@@ -802,6 +805,21 @@ extended_bin_file_contents(OsFamily, RelName, RelVsn, ErtsVsn, ErlOpts, Hooks) -
PostInstallUpgradeHooks = string:join(proplists:get_value(post_install_upgrade,
Hooks, []), " "),
StatusHook = string:join(proplists:get_value(status, Hooks, []), " "),
+ {ExtensionsList1, ExtensionDeclarations1} =
+ lists:foldl(fun({Name, Script},
+ {ExtensionsList0, ExtensionDeclarations0}) ->
+ ExtensionDeclaration = atom_to_list(Name) ++
+ "_extension=\"" ++
+ Script ++ "\"",
+ {ExtensionsList0 ++ [atom_to_list(Name)],
+ ExtensionDeclarations0 ++ [ExtensionDeclaration]}
+ end, {[], []}, Extensions),
+ % pipe separated string of extensions, to show on the start script usage
+ % (eg. foo|bar)
+ ExtensionsList = string:join(ExtensionsList1 ++ ["undefined"], "|"),
+ % command separated string of extension script declarations
+ % (eg. foo_extension="path/to/foo_script")
+ ExtensionDeclarations = string:join(ExtensionDeclarations1, ";"),
render(Template, [{rel_name, RelName}, {rel_vsn, RelVsn},
{erts_vsn, ErtsVsn}, {erl_opts, ErlOpts},
{pre_start_hooks, PreStartHooks},
@@ -810,7 +828,9 @@ extended_bin_file_contents(OsFamily, RelName, RelVsn, ErtsVsn, ErlOpts, Hooks) -
{post_stop_hooks, PostStopHooks},
{pre_install_upgrade_hooks, PreInstallUpgradeHooks},
{post_install_upgrade_hooks, PostInstallUpgradeHooks},
- {status_hook, StatusHook}]).
+ {status_hook, StatusHook},
+ {extensions, ExtensionsList},
+ {extension_declarations, ExtensionDeclarations}]).
erl_ini(OutputDir, ErtsVsn) ->
ErtsDirName = string:concat("erts-", ErtsVsn),
diff --git a/test/rlx_extended_bin_SUITE.erl b/test/rlx_extended_bin_SUITE.erl
index c2e6bc2..4407cfc 100644
--- a/test/rlx_extended_bin_SUITE.erl
+++ b/test/rlx_extended_bin_SUITE.erl
@@ -49,7 +49,8 @@
builtin_pid_start_script_hook/1,
builtin_wait_for_process_start_script_hook/1,
mixed_custom_and_builtin_start_script_hooks/1,
- builtin_status_script/1, custom_status_script/1]).
+ builtin_status_script/1, custom_status_script/1,
+ extension_script/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -82,7 +83,7 @@ all() ->
replace_os_vars_custom_location, replace_os_vars_dev_mode, replace_os_vars_twice, custom_start_script_hooks,
builtin_wait_for_vm_start_script_hook, builtin_pid_start_script_hook,
builtin_wait_for_process_start_script_hook, mixed_custom_and_builtin_start_script_hooks,
- builtin_status_script, custom_status_script].
+ builtin_status_script, custom_status_script, extension_script].
ping(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
@@ -1492,6 +1493,47 @@ start_fail_when_circular_argsfiles(Config) ->
ec_file:write(VmArgs3, "-args_file " ++ VmArgs2 ++ "\n"),
start_fail_with_vmargs(Config, VmArgs, 5).
+extension_script(Config) ->
+ LibDir1 = proplists:get_value(lib1, Config),
+
+ rlx_test_utils:create_full_app(LibDir1, "goal_app", "0.0.1",
+ [stdlib,kernel], []),
+
+ OutputDir = filename:join([proplists:get_value(priv_dir, Config),
+ rlx_test_utils:create_random_name("relx-output")]),
+
+ ConfigFile = filename:join([LibDir1, "relx.config"]),
+ rlx_test_utils:write_config(ConfigFile,
+ [{release, {foo, "0.0.1"},
+ [goal_app]},
+ {lib_dirs, [filename:join(LibDir1, "*")]},
+ {generate_start_script, true},
+ {extended_start_script, true},
+ {extended_start_script_extensions, [
+ {bar, "extensions/bar"}
+ ]},
+ {overlay, [
+ {copy, "./bar", "bin/extensions/bar"}]}
+ ]),
+
+ %% write the extension script
+ ok = file:write_file(filename:join([LibDir1, "./bar"]),
+ "#!/bin/bash\n"
+ "echo \\{bar, $REL_NAME, \\'$NAME\\', $COOKIE\\}.\n"
+ "exit 0"),
+
+ {ok, _State} = relx:do(foo, undefined, [], [LibDir1], 3,
+ OutputDir, ConfigFile),
+ os:cmd(filename:join([OutputDir, "foo", "bin", "foo start"])),
+ timer:sleep(2000),
+ {ok, "pong"} = sh(filename:join([OutputDir, "foo", "bin", "foo ping"])),
+ %% write the extension script output to a file
+ {ok, Str} = sh(filename:join([OutputDir, "foo", "bin", "foo bar"])),
+ ec_file:write(filename:join([OutputDir, "bar.txt"]), Str),
+ os:cmd(filename:join([OutputDir, "foo", "bin", "foo stop"])),
+ {ok, [Term]} = file:consult(filename:join([OutputDir, "bar.txt"])),
+ {ok, {bar, foo, _, foo} = Term}.
+
%%-------------------------------------------------------------------
%% Helper Function for start_fail_when_* tests
%%-------------------------------------------------------------------