You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 rivejä
7.8 KiB

10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
  1. -module(rebar_app_discover).
  2. -export([do/2,
  3. format_error/1,
  4. find_unbuilt_apps/1,
  5. find_apps/1,
  6. find_apps/2,
  7. find_app/2,
  8. validate_application_info/1,
  9. validate_application_info/2]).
  10. -include_lib("providers/include/providers.hrl").
  11. do(State, LibDirs) ->
  12. BaseDir = rebar_state:dir(State),
  13. Dirs = [filename:join(BaseDir, LibDir) || LibDir <- LibDirs],
  14. Apps = find_apps(Dirs, all),
  15. ProjectDeps = rebar_state:deps_names(State),
  16. %% Sort apps so we get the same merged deps config everytime
  17. SortedApps = rebar_utils:sort_deps(Apps),
  18. lists:foldl(fun(AppInfo, StateAcc) ->
  19. StateAcc1 = merge_deps(AppInfo, StateAcc),
  20. ProjectDeps1 = lists:delete(rebar_app_info:name(AppInfo), ProjectDeps),
  21. rebar_state:project_apps(StateAcc1
  22. ,rebar_app_info:deps(AppInfo, ProjectDeps1))
  23. end, State, SortedApps).
  24. format_error({module_list, File}) ->
  25. io_lib:format("Error reading module list from ~p~n", [File]);
  26. format_error({missing_module, Module}) ->
  27. io_lib:format("Module defined in app file missing: ~p~n", [Module]).
  28. merge_deps(AppInfo, State) ->
  29. Profiles = rebar_state:current_profiles(State),
  30. Name = rebar_app_info:name(AppInfo),
  31. C = rebar_config:consult(rebar_app_info:dir(AppInfo)),
  32. AppState = rebar_state:apply_overrides(
  33. rebar_state:apply_profiles(
  34. rebar_state:new(State, C, rebar_app_info:dir(AppInfo)), Profiles), Name),
  35. lists:foldl(fun(Profile, StateAcc) ->
  36. AppProfDeps = rebar_state:get(AppState, {deps, Profile}, []),
  37. TopLevelProfDeps = rebar_state:get(StateAcc, {deps, Profile}, []),
  38. ProfDeps2 = lists:keymerge(1, TopLevelProfDeps, AppProfDeps),
  39. rebar_state:set(StateAcc, {deps, Profile}, ProfDeps2)
  40. end, State, lists:reverse(Profiles)).
  41. -spec all_app_dirs(list(file:name())) -> list(file:name()).
  42. all_app_dirs(LibDirs) ->
  43. lists:flatmap(fun(LibDir) ->
  44. app_dirs(LibDir)
  45. end, LibDirs).
  46. app_dirs(LibDir) ->
  47. Path1 = filename:join([LibDir,
  48. "*",
  49. "src",
  50. "*.app.src"]),
  51. Path2 = filename:join([LibDir,
  52. "src",
  53. "*.app.src"]),
  54. Path3 = filename:join([LibDir,
  55. "*",
  56. "ebin",
  57. "*.app"]),
  58. Path4 = filename:join([LibDir,
  59. "ebin",
  60. "*.app"]),
  61. lists:usort(lists:foldl(fun(Path, Acc) ->
  62. Files = filelib:wildcard(ec_cnv:to_list(Path)),
  63. [app_dir(File) || File <- Files] ++ Acc
  64. end, [], [Path1, Path2, Path3, Path4])).
  65. find_unbuilt_apps(LibDirs) ->
  66. find_apps(LibDirs, invalid).
  67. -spec find_apps([file:filename_all()]) -> [rebar_app_info:t()].
  68. find_apps(LibDirs) ->
  69. find_apps(LibDirs, valid).
  70. -spec find_apps([file:filename_all()], valid | invalid | all) -> [rebar_app_info:t()].
  71. find_apps(LibDirs, Validate) ->
  72. rebar_utils:filtermap(fun(AppDir) ->
  73. find_app(AppDir, Validate)
  74. end, all_app_dirs(LibDirs)).
  75. -spec find_app(file:filename_all(), valid | invalid | all) -> {true, rebar_app_info:t()} | false.
  76. find_app(AppDir, Validate) ->
  77. AppFile = filelib:wildcard(filename:join([AppDir, "ebin", "*.app"])),
  78. AppSrcFile = filelib:wildcard(filename:join([AppDir, "src", "*.app.src"])),
  79. case AppFile of
  80. [File] ->
  81. AppInfo = create_app_info(AppDir, File),
  82. AppInfo1 = rebar_app_info:app_file(AppInfo, File),
  83. AppInfo2 = case AppSrcFile of
  84. [F] ->
  85. rebar_app_info:app_file_src(AppInfo1, F);
  86. [] ->
  87. AppInfo1;
  88. Other when is_list(Other) ->
  89. throw({error, {multiple_app_files, Other}})
  90. end,
  91. case Validate of
  92. valid ->
  93. case validate_application_info(AppInfo2) of
  94. true ->
  95. {true, AppInfo2};
  96. _ ->
  97. false
  98. end;
  99. invalid ->
  100. case validate_application_info(AppInfo2) of
  101. true ->
  102. false;
  103. _ ->
  104. {true, AppInfo2}
  105. end;
  106. all ->
  107. {true, AppInfo2}
  108. end;
  109. [] ->
  110. case AppSrcFile of
  111. [File] ->
  112. case Validate of
  113. V when V =:= invalid ; V =:= all ->
  114. AppInfo = create_app_info(AppDir, File),
  115. {true, rebar_app_info:app_file_src(AppInfo, File)};
  116. valid ->
  117. false
  118. end;
  119. [] ->
  120. false;
  121. Other when is_list(Other) ->
  122. throw({error, {multiple_app_files, Other}})
  123. end;
  124. Other when is_list(Other) ->
  125. throw({error, {multiple_app_files, Other}})
  126. end.
  127. app_dir(AppFile) ->
  128. filename:join(rebar_utils:droplast(filename:split(filename:dirname(AppFile)))).
  129. -spec create_app_info(file:name(), file:name()) -> rebar_app_info:t() | error.
  130. create_app_info(AppDir, AppFile) ->
  131. case file:consult(AppFile) of
  132. {ok, [{application, AppName, AppDetails}]} ->
  133. AppVsn = proplists:get_value(vsn, AppDetails),
  134. Applications = proplists:get_value(applications, AppDetails, []),
  135. IncludedApplications = proplists:get_value(included_applications, AppDetails, []),
  136. {ok, AppInfo} = rebar_app_info:new(AppName, AppVsn, AppDir, []),
  137. AppInfo1 = rebar_app_info:applications(
  138. rebar_app_info:app_details(AppInfo, AppDetails),
  139. IncludedApplications++Applications),
  140. rebar_app_info:dir(AppInfo1, AppDir);
  141. _ ->
  142. error
  143. end.
  144. -spec validate_application_info(rebar_app_info:t()) -> boolean().
  145. validate_application_info(AppInfo) ->
  146. validate_application_info(AppInfo, rebar_app_info:app_details(AppInfo)).
  147. validate_application_info(AppInfo, AppDetail) ->
  148. EbinDir = rebar_app_info:ebin_dir(AppInfo),
  149. case rebar_app_info:app_file(AppInfo) of
  150. undefined ->
  151. false;
  152. AppFile ->
  153. case get_modules_list(AppFile, AppDetail) of
  154. {ok, List} ->
  155. has_all_beams(EbinDir, List);
  156. _Error ->
  157. ?PRV_ERROR({module_list, AppFile})
  158. end
  159. end.
  160. -spec get_modules_list(file:filename_all(), proplists:proplist()) ->
  161. {ok, list()} |
  162. {warning, Reason::term()} |
  163. {error, Reason::term()}.
  164. get_modules_list(AppFile, AppDetail) ->
  165. case proplists:get_value(modules, AppDetail) of
  166. undefined ->
  167. {warning, {invalid_app_file, AppFile}};
  168. ModulesList ->
  169. {ok, ModulesList}
  170. end.
  171. -spec has_all_beams(file:filename_all(), list()) -> true | providers:error().
  172. has_all_beams(EbinDir, [Module | ModuleList]) ->
  173. BeamFile = filename:join([EbinDir,
  174. ec_cnv:to_list(Module) ++ ".beam"]),
  175. case filelib:is_file(BeamFile) of
  176. true ->
  177. has_all_beams(EbinDir, ModuleList);
  178. false ->
  179. ?PRV_ERROR({missing_module, Module})
  180. end;
  181. has_all_beams(_, []) ->
  182. true.