aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/relx.erl2
-rw-r--r--src/rlx_prv_assembler.erl45
-rw-r--r--src/rlx_prv_config.erl3
-rw-r--r--src/rlx_state.erl14
-rw-r--r--test/rlx_release_SUITE.erl46
5 files changed, 100 insertions, 10 deletions
diff --git a/src/relx.erl b/src/relx.erl
index 6306559..d61f426 100644
--- a/src/relx.erl
+++ b/src/relx.erl
@@ -197,6 +197,8 @@ opt_spec_list() ->
"Whether to use the default system added lib dirs (means you must add them all manually). Default is true"},
{log_level, $V, "verbose", {integer, 2},
"Verbosity level, maybe between 0 and 3"},
+ {dev_mode, $d, "dev-mode", {boolean, false},
+ "Symlink the applications and configuration into the release instead of copying"},
{override_app, $a, "override_app", string,
"Provide an app name and a directory to override in the form <appname>:<app directory>"},
{config, $c, "config", {string, ""}, "The path to a config file"},
diff --git a/src/rlx_prv_assembler.erl b/src/rlx_prv_assembler.erl
index 9e3a6f7..8a60f52 100644
--- a/src/rlx_prv_assembler.erl
+++ b/src/rlx_prv_assembler.erl
@@ -41,6 +41,7 @@ init(State) ->
%% looking for OTP Applications
-spec do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error().
do(State) ->
+ print_dev_mode(State),
{RelName, RelVsn} = rlx_state:default_configured_release(State),
Release = rlx_state:get_realized_release(State, RelName, RelVsn),
OutputDir = rlx_state:output_dir(State),
@@ -139,6 +140,15 @@ format_error({tar_generation_error, Module, Errors}) ->
%%%===================================================================
%%% Internal Functions
%%%===================================================================
+print_dev_mode(State) ->
+ case rlx_state:dev_mode(State) of
+ true ->
+ ec_cmd_log:info(rlx_state:log(State),
+ "Dev mode enabled, release will be symlinked");
+ false ->
+ ok
+ end.
+
-spec create_output_dir(file:name()) ->
ok | {error, Reason::term()}.
create_output_dir(OutputDir) ->
@@ -157,7 +167,7 @@ create_output_dir(OutputDir) ->
copy_app_directories_to_output(State, Release, OutputDir) ->
LibDir = filename:join([OutputDir, "lib"]),
ok = ec_file:mkdir_p(LibDir),
- Apps = rlx_release:application_details(Release),
+ Apps = prepare_applications(State, rlx_release:application_details(Release)),
Result = lists:filter(fun({error, _}) ->
true;
(_) ->
@@ -173,6 +183,14 @@ copy_app_directories_to_output(State, Release, OutputDir) ->
create_release_info(State, Release, OutputDir)
end.
+prepare_applications(State, Apps) ->
+ case rlx_state:dev_mode(State) of
+ true ->
+ [rlx_app_info:link(App, true) || App <- Apps];
+ false ->
+ Apps
+ end.
+
copy_app(LibDir, App) ->
AppName = erlang:atom_to_list(rlx_app_info:name(App)),
AppVsn = rlx_app_info:vsn_as_string(App),
@@ -323,13 +341,29 @@ copy_or_generate_sys_config_file(State, Release, OutputDir, RelDir) ->
false ->
?RLX_ERROR({config_does_not_exist, ConfigPath});
true ->
- ok = ec_file:copy(ConfigPath, RelSysConfPath),
- include_erts(State, Release, OutputDir, RelDir)
+ copy_or_symlink_sys_config_file(State, Release, OutputDir, RelDir,
+ ConfigPath, RelSysConfPath)
end
end.
+%% @doc copy config/sys.config or generate one to releases/VSN/sys.config
+-spec copy_or_symlink_sys_config_file(rlx_state:t(), rlx_release:t(),
+ file:name(), file:name(),
+ file:name(), file:name()) ->
+ {ok, rlx_state:t()} | relx:error().
+copy_or_symlink_sys_config_file(State, Release, OutputDir, RelDir,
+ ConfigPath, RelSysConfPath) ->
+ case rlx_state:dev_mode(State) of
+ true ->
+ ok = file:make_symlink(ConfigPath, RelSysConfPath);
+ _ ->
+ ok = ec_file:copy(ConfigPath, RelSysConfPath)
+ end,
+ include_erts(State, Release, OutputDir, RelDir).
+
%% @doc Optionally add erts directory to release, if defined.
--spec include_erts(rlx_state:t(), rlx_release:t(), file:name(), file:name()) -> {ok, rlx_state:t()} | relx:error().
+-spec include_erts(rlx_state:t(), rlx_release:t(), file:name(), file:name()) ->
+ {ok, rlx_state:t()} | relx:error().
include_erts(State, Release, OutputDir, RelDir) ->
case rlx_state:get(State, include_erts, true) of
true ->
@@ -383,7 +417,7 @@ make_boot_script(State, Release, OutputDir, RelDir) ->
end) of
ok ->
ec_cmd_log:error(rlx_state:log(State),
- "release successfully created!"),
+ "release successfully created!"),
create_RELEASES(OutputDir, ReleaseFile),
{ok, State};
error ->
@@ -1171,7 +1205,6 @@ append_node_suffix(Name, Suffix) ->
list_to_atom(lists:concat([Node, Suffix, os:getpid()]))
end.
-
%%
%% Given a string or binary, parse it into a list of terms, ala file:consult/0
%%
diff --git a/src/rlx_prv_config.erl b/src/rlx_prv_config.erl
index 71a2dc9..b223bce 100644
--- a/src/rlx_prv_config.erl
+++ b/src/rlx_prv_config.erl
@@ -105,7 +105,6 @@ parent_dir([_H], Acc) ->
parent_dir([H | T], Acc) ->
parent_dir(T, [H | Acc]).
-
-spec load_config(file:filename(), rlx_state:t()) ->
{ok, rlx_state:t()} | relx:error().
load_config(ConfigFile, State) ->
@@ -153,6 +152,8 @@ load_terms({skip_apps, SkipApps0}, {ok, State0}) ->
{ok, rlx_state:skip_apps(State0, SkipApps0)};
load_terms({overrides, Overrides0}, {ok, State0}) ->
{ok, rlx_state:overrides(State0, Overrides0)};
+load_terms({dev_mode, DevMode}, {ok, State0}) ->
+ {ok, rlx_state:dev_mode(State0, DevMode)};
load_terms({release, {RelName, Vsn}, Applications}, {ok, State0}) ->
Release0 = rlx_release:new(RelName, Vsn),
case rlx_release:goals(Release0, Applications) of
diff --git a/src/rlx_state.erl b/src/rlx_state.erl
index b196e8d..81f9fca 100644
--- a/src/rlx_state.erl
+++ b/src/rlx_state.erl
@@ -61,6 +61,8 @@
put/3,
caller/1,
caller/2,
+ dev_mode/1,
+ dev_mode/2,
upfrom/1,
format/1,
format/2]).
@@ -88,6 +90,7 @@
skip_apps=[] :: [AppName::atom()],
configured_releases :: releases(),
realized_releases :: releases(),
+ dev_mode=false :: boolean(),
upfrom :: string() | binary() | undefined,
config_values :: ec_dictionary:dictionary(Key::atom(),
Value::term())}).
@@ -209,7 +212,7 @@ vm_args(#state_t{vm_args=VmArgs}) ->
-spec vm_args(t(), file:filename()) -> t().
vm_args(State, VmArgs) ->
- State#state_t{vm_args=VmArgs}.
+ State#state_t{vm_args=VmArgs}.
-spec sys_config(t()) -> file:filename() | undefined.
sys_config(#state_t{sys_config=SysConfig}) ->
@@ -317,6 +320,15 @@ caller(#state_t{caller=Caller}) ->
caller(S, Caller) ->
S#state_t{caller=Caller}.
+-spec dev_mode(t()) -> boolean().
+dev_mode(#state_t{dev_mode=DevMode}) ->
+ DevMode.
+
+-spec dev_mode(t(), boolean()) -> t().
+dev_mode(S, DevMode) ->
+ S#state_t{dev_mode=DevMode}.
+
+
-spec upfrom(t()) -> string() | binary() | undefined.
upfrom(#state_t{upfrom=UpFrom}) ->
UpFrom.
diff --git a/test/rlx_release_SUITE.erl b/test/rlx_release_SUITE.erl
index 821a4d1..184f444 100644
--- a/test/rlx_release_SUITE.erl
+++ b/test/rlx_release_SUITE.erl
@@ -38,7 +38,8 @@
make_invalid_config_release/1,
make_relup_release/1,
make_relup_release2/1,
- make_one_app_top_level_release/1]).
+ make_one_app_top_level_release/1,
+ make_dev_mode_release/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -69,7 +70,7 @@ all() ->
make_implicit_config_release, make_rerun_overridden_release,
overlay_release, make_goalless_release, make_depfree_release,
make_invalid_config_release, make_relup_release, make_relup_release2,
- make_one_app_top_level_release].
+ make_one_app_top_level_release, make_dev_mode_release].
make_release(Config) ->
LibDir1 = proplists:get_value(lib1, Config),
@@ -832,6 +833,46 @@ make_one_app_top_level_release(Config) ->
?assert(lists:keymember(kernel, 1, AppSpecs)),
?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)).
+make_dev_mode_release(Config) ->
+ LibDir1 = proplists:get_value(lib1, Config),
+ [(fun({Name, Vsn}) ->
+ create_app(LibDir1, Name, Vsn, [kernel, stdlib], [])
+ end)(App)
+ ||
+ App <-
+ [{create_random_name("lib_app1_"), create_random_vsn()}
+ || _ <- lists:seq(1, 100)]],
+
+ create_app(LibDir1, "goal_app_1", "0.0.1", [stdlib,kernel,non_goal_1], []),
+ create_app(LibDir1, "lib_dep_1", "0.0.1", [stdlib,kernel], []),
+ create_app(LibDir1, "goal_app_2", "0.0.1", [stdlib,kernel,goal_app_1,non_goal_2], []),
+ create_app(LibDir1, "non_goal_1", "0.0.1", [stdlib,kernel], [lib_dep_1]),
+ create_app(LibDir1, "non_goal_2", "0.0.1", [stdlib,kernel], []),
+
+ SysConfig = filename:join([LibDir1, "config", "sys.config"]),
+ write_config(SysConfig, [{this_is_a_test, "yup it is"}]),
+
+ ConfigFile = filename:join([LibDir1, "relx.config"]),
+ write_config(ConfigFile,
+ [{dev_mode, true},
+ {sys_config, SysConfig},
+ {release, {foo, "0.0.1"},
+ [goal_app_1,
+ goal_app_2]}]),
+ OutputDir = filename:join([proplists:get_value(data_dir, Config),
+ create_random_name("relx-output")]),
+ {ok, State} = relx:do(undefined, undefined, [], [LibDir1], 3,
+ OutputDir, ConfigFile),
+ [{{foo, "0.0.1"}, _Release}] = ec_dictionary:to_list(rlx_state:realized_releases(State)),
+
+ ?assert(ec_file:is_symlink(filename:join([OutputDir, "lib", "non_goal_1-0.0.1"]))),
+ ?assert(ec_file:is_symlink(filename:join([OutputDir, "lib", "non_goal_2-0.0.1"]))),
+ ?assert(ec_file:is_symlink(filename:join([OutputDir, "lib", "goal_app_1-0.0.1"]))),
+ ?assert(ec_file:is_symlink(filename:join([OutputDir, "lib", "goal_app_2-0.0.1"]))),
+ ?assert(ec_file:is_symlink(filename:join([OutputDir, "lib", "lib_dep_1-0.0.1"]))),
+ ?assert(ec_file:is_symlink(filename:join([OutputDir, "releases", "0.0.1",
+ "sys.config"]))).
+
%%%===================================================================
%%% Helper Functions
@@ -888,6 +929,7 @@ create_random_vsn() ->
".", erlang:integer_to_list(random:uniform(100))]).
write_config(Filename, Values) ->
+ ok = filelib:ensure_dir(Filename),
ok = ec_file:write(Filename,
[io_lib:format("~p.\n", [Val]) || Val <- Values]).