Skip to content

Commit

Permalink
perform hot code realod in deploy scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin Rehfeld committed Nov 21, 2012
1 parent 1b2b954 commit a3fa012
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 2 deletions.
4 changes: 3 additions & 1 deletion bin/deploy-v1.sh
@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/bash -e

RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd)
RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*}
Expand All @@ -8,3 +8,5 @@ cp ./src/hcr_config.erl.v1 ./src/hcr_config.erl
cp ./src/hcr_model.erl.v1 ./src/hcr_model.erl

./rebar compile skip_deps=true
echo "Reloading code in node:"
exec erl_call -a "hcr_deploy reload_app []" -n hot_code_reload
4 changes: 3 additions & 1 deletion bin/deploy-v2.sh
@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/bash -e

RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd)
RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*}
Expand All @@ -8,3 +8,5 @@ cp ./src/hcr_config.erl.v2 ./src/hcr_config.erl
cp ./src/hcr_model.erl.v2 ./src/hcr_model.erl

./rebar compile skip_deps=true
echo "Reloading code in node:"
exec erl_call -a "hcr_deploy reload_app []" -n hot_code_reload
121 changes: 121 additions & 0 deletions src/hcr_deploy.erl
@@ -0,0 +1,121 @@
-module(hcr_deploy).

-export([reload_app/0,
modules_for_app/1,
reload_module/1,
reload_module/2,
add_paths/1,
modified_deps/0,
is_latest_version/1,
module_modified/1,
find_module_file/1]).


reload_app() ->
ModifiedModules = lists:filter(fun module_modified/1, modules_for_app(hot_code_reload)),
[] = [M || M <- ModifiedModules, code:soft_purge(M) =:= false],
ok = add_paths("deps"),
[code:load_file(M) || M <- ModifiedModules].


modules_for_app(App) when App =:= hot_code_reload ->
case code:where_is_file(atom_to_list(App) ++ ".app") of
{error, enoent} ->
{error, no_app_file};
Path ->
case file:consult(Path) of
{ok, [{application, App, Props}]} ->
proplists:get_value(modules, Props, []);
{error, Error} ->
{error, Error}
end
end.


reload_module(M) ->
code:soft_purge(M) andalso code:load_file(M).

reload_module(M, force) ->
code:purge(M),
code:load_file(M).


add_paths(BaseDir) ->
case file:list_dir(BaseDir) of
{ok, Filenames} ->
lists:foreach(fun (Dep) ->
true == code:add_path(
filename:join([BaseDir, Dep, "ebin"]))
end, Filenames),
ok;
{error, Reason} ->
{error, Reason}
end.

%% @doc: List loaded modules from deps/ that have changed on disk,
%% will not notice new beams that have not yet been loaded.
modified_deps() ->
{DepModules, _} = lists:unzip(lists:filter(
fun ({_, Beam}) ->
is_list(Beam) andalso
lists:prefix(filename:absname("deps"), Beam)
end,
code:all_loaded())),
lists:filter(fun (Module) -> not is_latest_version(Module) end, DepModules).

%% @doc: Check loaded vsn versus vsn on disk, do this since compile times changes
%% frequently for our deps even if source has not (because of delete-deps).
is_latest_version(Module) ->
case code:get_object_code(Module) of
{Module, _ObjectCode, Beam} ->
{ok, {Module, VsnDisk}} = beam_lib:version(Beam),
%% Can't use object code since it is read from disk
VsnLoaded = proplists:get_value(vsn, Module:module_info(attributes)),
VsnLoaded =:= VsnDisk;
error ->
%% Module not loaded
false
end.


%%
%% Snipped from Wings3d

module_modified(Module) ->
case code:is_loaded(Module) of
{file, preloaded} ->
false;
{file, Path} ->
CompileOpts = proplists:get_value(compile, Module:module_info()),
CompileTime = proplists:get_value(time, CompileOpts),
Src = proplists:get_value(source, CompileOpts),
module_modified(Path, CompileTime, Src);
_ ->
true %% consider new modules to be modified so they get loaded
end.

module_modified(Path, PrevCompileTime, PrevSrc) ->
case find_module_file(Path) of
false ->
false;
ModPath ->
{ok, {_, [{_, CB}]}} = beam_lib:chunks(ModPath, ["CInf"]),
CompileOpts = binary_to_term(CB),
CompileTime = proplists:get_value(time, CompileOpts),
Src = proplists:get_value(source, CompileOpts),
not ((CompileTime == PrevCompileTime) and (Src == PrevSrc))
end.

find_module_file(Path) ->
case file:read_file_info(Path) of
{ok, _} ->
Path;
_ ->
%% may be the path was changed?
case code:where_is_file(filename:basename(Path)) of
non_existing ->
false;
NewPath ->
NewPath
end
end.

0 comments on commit a3fa012

Please sign in to comment.