diff options
-rw-r--r-- | src/relx.erl | 2 | ||||
-rw-r--r-- | src/rlx_prv_assembler.erl | 45 | ||||
-rw-r--r-- | src/rlx_prv_config.erl | 3 | ||||
-rw-r--r-- | src/rlx_state.erl | 14 | ||||
-rw-r--r-- | test/rlx_release_SUITE.erl | 46 |
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]). |