mad.erl 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. -module(mad).
  2. -export([deps/1]).
  3. -export([clone_deps/1]).
  4. -export([compile/1]).
  5. -export([compile_deps/1]).
  6. -export([update_path/1]).
  7. %% read rebar.config file and return the {deps, V}
  8. deps(RebarFile) ->
  9. case file:consult(RebarFile) of
  10. {ok, Conf} ->
  11. case lists:keyfind(deps, 1, Conf) of
  12. {deps, Deps} ->
  13. {ok, Deps};
  14. _ ->
  15. {ok, []}
  16. end;
  17. Else ->
  18. Else
  19. end.
  20. clone_deps(Deps) ->
  21. exec("mkdir", ["-p", deps_path()]),
  22. do_clone_deps(Deps).
  23. do_clone_deps([]) ->
  24. ok;
  25. do_clone_deps([{Name, _, Repo}|T]) ->
  26. Name1 = atom_to_list(Name),
  27. {Cmd, Url, Co} = Repo,
  28. %% branch/tag it should checkout to
  29. Co1 = case Co of
  30. {_, V} -> V;
  31. Else -> Else
  32. end,
  33. Name2 = make_dep_name(Name1, Co1),
  34. %% command options: clone url path/to/dep -b Branch/Tag
  35. Opts = ["clone", Url, get_path(Name2), "-b", Co1],
  36. io:format("dependency: ~s~n", [Name1]),
  37. %% run the command
  38. exec(Cmd, Opts),
  39. %% check dependencies of the dependency
  40. case deps(rebar_config_file(Name2)) of
  41. {ok, Deps} ->
  42. do_clone_deps(Deps);
  43. {error, _} ->
  44. ok
  45. end,
  46. do_clone_deps(T).
  47. %% compile dependencies and the app
  48. compile(Dir) ->
  49. RebarFile = filename:join([Dir, "rebar.config"]),
  50. case deps(RebarFile) of
  51. {ok, Deps} ->
  52. compile_deps(Deps);
  53. {error, _} ->
  54. ok
  55. end,
  56. compile_app(Dir).
  57. compile_deps([]) ->
  58. ok;
  59. compile_deps([{Name, _, Repo}|T]) ->
  60. Name1 = atom_to_list(Name),
  61. {_, _, Co} = Repo,
  62. %% branch/tag it should checkout to
  63. Co1 = case Co of
  64. {_, V} -> V;
  65. Else -> Else
  66. end,
  67. Name2 = make_dep_name(Name1, Co1),
  68. SrcDir = src(Name2),
  69. EbinDir = ebin(Name2),
  70. case file:list_dir(SrcDir) of
  71. {ok, Files} ->
  72. exec("mkdir", ["-p", EbinDir]),
  73. lists:foreach(compile_fun(SrcDir, EbinDir), Files);
  74. {error, _} -> ok
  75. end,
  76. %% check dependencies of the dependency
  77. case deps(rebar_config_file(Name2)) of
  78. {ok, Deps} ->
  79. compile_deps(Deps);
  80. {error, _} ->
  81. ok
  82. end,
  83. compile_deps(T).
  84. compile_app(Dir) ->
  85. SrcDir = filename:join([Dir, "src"]),
  86. case file:list_dir(SrcDir) of
  87. {ok, Files} ->
  88. EbinDir = filename:join([Dir, "ebin"]),
  89. lists:foreach(compile_fun(SrcDir, EbinDir), Files);
  90. {error, _} ->
  91. ok
  92. end.
  93. exec(Cmd, Opts) ->
  94. Opts1 = [concat([" ", X]) || X <- Opts],
  95. os:cmd(concat([Cmd, concat(Opts1)])).
  96. concat(L) ->
  97. lists:concat(L).
  98. make_dep_name(Name, Suffix) ->
  99. %% Name-Suffix
  100. concat([Name, "-", Suffix]).
  101. home() ->
  102. %% ~/
  103. {ok, [[H|_]]} = init:get_argument(home),
  104. H.
  105. deps_path() ->
  106. %% ~/.otp/deps
  107. filename:join([home(), ".otp", "deps"]).
  108. get_path(X) ->
  109. %% ~/.otp/deps/X
  110. filename:join([deps_path(), X]).
  111. rebar_config_file(X) ->
  112. %% ~/.otp/deps/X/rebar.config
  113. filename:join([get_path(X), "rebar.config"]).
  114. ebin(X) ->
  115. %% ~/.otp/deps/X/ebin
  116. filename:join([get_path(X), "ebin"]).
  117. src(X) ->
  118. %% ~/.otp/deps/X/src
  119. filename:join([get_path(X), "src"]).
  120. deps_path(Deps) ->
  121. deps_path(Deps, []).
  122. deps_path([], Acc) ->
  123. Acc;
  124. deps_path([{Name, _, Repo}|T], Acc) ->
  125. Name1 = atom_to_list(Name),
  126. {_, _, Co} = Repo,
  127. %% branch/tag it should checkout to
  128. Co1 = case Co of
  129. {_, V} -> V;
  130. Else -> Else
  131. end,
  132. Name2 = make_dep_name(Name1, Co1),
  133. Acc1 = case deps(rebar_config_file(Name2)) of
  134. {ok, Deps} ->
  135. deps_path(Deps, []);
  136. {error, _} ->
  137. []
  138. end,
  139. deps_path(T, [get_path(Name2)|Acc ++ Acc1]).
  140. deps_ebin(Deps) ->
  141. deps_ebin(deps_path(Deps), []).
  142. deps_ebin([], Acc) ->
  143. Acc;
  144. deps_ebin([H|T], Acc) ->
  145. deps_ebin(T, [filename:join([H, "ebin"])|Acc]).
  146. %% add application directory (its ebin) and its dependencies to the code path
  147. update_path(Dir) ->
  148. Ebin = filename:join([Dir, "ebin"]),
  149. code:add_path(Ebin),
  150. RebarFile = filename:join([Dir, "rebar.config"]),
  151. case deps(RebarFile) of
  152. {ok, Deps} ->
  153. code:add_paths(deps_ebin(Deps));
  154. {error, _} ->
  155. ok
  156. end.
  157. is_app_src(Filename) ->
  158. Filename =/= filename:rootname(Filename, ".app.src").
  159. app_src_to_app(Filename) ->
  160. filename:join([filename:basename(Filename, ".app.src") ++ ".app"]).
  161. compile_fun(SrcDir, EbinDir) ->
  162. fun(F) ->
  163. F1 = filename:join([SrcDir, F]),
  164. case is_app_src(F1) of
  165. false ->
  166. io:format("Compiling ~s~n", [F]),
  167. compile:file(F1, [{outdir, EbinDir}]);
  168. true ->
  169. AppF = app_src_to_app(F1),
  170. io:format("Writing ebin/~s~n", [AppF]),
  171. exec("cp", [F1, filename:join([EbinDir, AppF])])
  172. end
  173. end.