Merge remote-tracking branch 'canonical/next'
[sinan.git] / src / sin_hooks.erl
blobf7130d9fda48b9f106cd81037fb91999f1647fe8
1 %% -*- mode: Erlang; fill-column: 80; comment-column: 75; -*-
2 %%%-------------------------------------------------------------------
3 %%% @author Eric Merritt <ericbmerritt@gmail.com>
4 %%% @copyright (C) 2009-2011 Eric Merritt
5 %%% @doc
6 %%% Provides a means of correctly creating eta pre/post task hooks
7 %%% and executing those hooks that exist.
8 %%% @end
9 %%%-------------------------------------------------------------------
10 -module(sin_hooks).
12 -include_lib("sinan/include/sinan.hrl").
14 -define(NEWLINE, 10).
15 -define(CARRIAGE_RETURN, 13).
17 %% API
18 -export([get_hooks_function/2,
19 format_exception/1]).
21 %%%===================================================================
22 %%% API
23 %%%===================================================================
25 %% @doc Creats a function that can be used to run build hooks in the system.
26 -spec get_hooks_function(sin_state:state(),
27 ProjectRoot::string()) -> function().
28 get_hooks_function(State, ProjectRoot) ->
29 HooksDir = filename:join([ProjectRoot, "_hooks"]),
30 case sin_utils:file_exists(State, HooksDir) of
31 false ->
32 no_hooks;
33 true ->
34 gen_build_hooks_function(HooksDir)
35 end.
37 %% @doc Format an exception thrown by this module
38 -spec format_exception(sin_exceptions:exception()) ->
39 string().
40 format_exception(Exception) ->
41 sin_exceptions:format_exception(Exception).
43 %%%===================================================================
44 %%% Internal functions
45 %%%===================================================================
47 %% @doc Generate a function that can be run pre and post task
48 -spec gen_build_hooks_function(HooksDir::string()) -> function().
49 gen_build_hooks_function(HooksDir) ->
50 fun(Type, Task, Config, State) ->
51 do_hook(Config, State, Type, Task, HooksDir)
52 end.
54 %% @doc Setup to run the hook and run it if it exists.
55 -spec do_hook(sin_config:config(), sin_state:state(),
56 Type::atom(), Task::atom(),
57 HooksDir::string()) -> ok.
58 do_hook(Config, State, Type, Task, HooksDir) when is_atom(Task) ->
59 HookName = atom_to_list(Type) ++ "_" ++ atom_to_list(Task),
60 HookPath = filename:join(HooksDir, HookName),
61 case sin_utils:file_exists(State, HookPath) of
62 true ->
63 sin_log:verbose(Config, "hook: ~s", [HookName]),
64 run_hook(Config, State, HookPath, list_to_atom(HookName));
65 _ ->
66 State
67 end.
69 %% @doc Setup the execution environment and run the hook.
70 -spec run_hook(sin_config:config(), sin_state:state(),
71 HookPath::list(), HookName::atom()) -> ok.
72 run_hook(Config, State, HookPath, HookName) ->
73 command(Config, State, HookPath, create_env(State), HookName).
75 %% @doc create a minimal env for the hook from the state.
76 -spec create_env(sin_state:state()) -> Env::[{string(), string()}].
77 create_env(State) ->
78 Env =
79 [{"SIN_RELEASE",
80 erlang:atom_to_list(sin_state:get_value(release, State))},
81 {"SIN_RELEASE_VSN", sin_state:get_value(release_vsn, State)},
82 {"SIN_BUILD_ROOT", sin_state:get_value(build_root, State)},
83 {"SIN_BUILD_DIR", sin_state:get_value(build_dir, State)},
84 {"SIN_APPS_DIR", sin_state:get_value(apps_dir, State)},
85 {"SIN_RELEASE_DIR", sin_state:get_value(release_dir, State)},
86 {"SIN_HOME_DIR", sin_state:get_value(home_dir, State)},
87 {"SIN_PROJECT_DIR", sin_state:get_value(project_dir, State)}] ++
88 [[{"SIN_" ++ erlang:atom_to_list(Name) ++
89 "_VSN", Vsn},
90 {"SIN_" ++ erlang:atom_to_list(Name) ++
91 "_DIR", AppDir}] ||
92 #app{name=Name, vsn=Vsn, path=AppDir}
93 <- sin_state:get_value(project_apps, [], State)],
94 lists:flatten(Env).
96 %% @doc Given a command an an environment run that command with the environment
97 -spec command(sin_config:config(), sin_state:state(), Command::list(), Env::list(),
98 HookName::atom()) -> list().
99 command(Config, State, Cmd, Env, HookName) ->
100 Opt = [{env, Env}],
101 case sin_sh:sh(Config, Cmd, Opt) of
102 {ok, _} ->
103 State;
104 {error, Reason} ->
105 ?SIN_RAISE(State, {error_running_hook, HookName, Reason})
106 end.