1%% @author {{author}}
2%% @copyright {{year}} {{author}}
3
4%% @doc Ensure that the relatively-installed dependencies are on the code
5%%      loading path, and locate resources relative
6%%      to this application's path.
7
8-module({{appid}}_deps).
9-author("{{author}}").
10
11-export([ensure/0, ensure/1]).
12-export([get_base_dir/0, get_base_dir/1]).
13-export([local_path/1, local_path/2]).
14-export([deps_on_path/0, new_siblings/1]).
15
16%% @spec deps_on_path() -> [ProjNameAndVers]
17%% @doc List of project dependencies on the path.
18deps_on_path() ->
19    F = fun (X, Acc) ->
20                ProjDir = filename:dirname(X),
21                case {filename:basename(X),
22                      filename:basename(filename:dirname(ProjDir))} of
23                    {"ebin", "deps"} ->
24                        [filename:basename(ProjDir) | Acc];
25                    _ ->
26                        Acc
27                end
28        end,
29    ordsets:from_list(lists:foldl(F, [], code:get_path())).
30
31%% @spec new_siblings(Module) -> [Dir]
32%% @doc Find new siblings paths relative to Module that aren't already on the
33%%      code path.
34new_siblings(Module) ->
35    Existing = deps_on_path(),
36    SiblingEbin = filelib:wildcard(local_path(["deps", "*", "ebin"], Module)),
37    Siblings = [filename:dirname(X) || X <- SiblingEbin,
38                           ordsets:is_element(
39                             filename:basename(filename:dirname(X)),
40                             Existing) =:= false],
41    lists:filter(fun filelib:is_dir/1,
42                 lists:append([[filename:join([X, "ebin"]),
43                                filename:join([X, "include"])] ||
44                                  X <- Siblings])).
45
46
47%% @spec ensure(Module) -> ok
48%% @doc Ensure that all ebin and include paths for dependencies
49%%      of the application for Module are on the code path.
50ensure(Module) ->
51    code:add_paths(new_siblings(Module)),
52    code:clash(),
53    ok.
54
55%% @spec ensure() -> ok
56%% @doc Ensure that the ebin and include paths for dependencies of
57%%      this application are on the code path. Equivalent to
58%%      ensure(?Module).
59ensure() ->
60    ensure(?MODULE).
61
62%% @spec get_base_dir(Module) -> string()
63%% @doc Return the application directory for Module. It assumes Module is in
64%%      a standard OTP layout application in the ebin or src directory.
65get_base_dir(Module) ->
66    {file, Here} = code:is_loaded(Module),
67    filename:dirname(filename:dirname(Here)).
68
69%% @spec get_base_dir() -> string()
70%% @doc Return the application directory for this application. Equivalent to
71%%      get_base_dir(?MODULE).
72get_base_dir() ->
73    get_base_dir(?MODULE).
74
75%% @spec local_path([string()], Module) -> string()
76%% @doc Return an application-relative directory from Module's application.
77local_path(Components, Module) ->
78    filename:join([get_base_dir(Module) | Components]).
79
80%% @spec local_path(Components) -> string()
81%% @doc Return an application-relative directory for this application.
82%%      Equivalent to local_path(Components, ?MODULE).
83local_path(Components) ->
84    local_path(Components, ?MODULE).
85