aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric <[email protected]>2013-10-15 10:28:20 -0700
committerEric <[email protected]>2013-10-15 13:22:24 -0700
commit51b7508737fd7668d000781c6502361e132cbbc4 (patch)
tree395c66c9be2e2b2c0f092ad4e445133a0c3897d2
parenta54bb2bd0c8f540a7bed3b3aa7e6732b131d7bb4 (diff)
downloadrelx-51b7508737fd7668d000781c6502361e132cbbc4.tar.gz
relx-51b7508737fd7668d000781c6502361e132cbbc4.tar.bz2
relx-51b7508737fd7668d000781c6502361e132cbbc4.zip
add a dev mode that symlinks the release instead of copying it
This should only ever be used for development, however it makes it very, very nice to be able to simple recompile a project without recopying it to try new things.
-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]).