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.

140 lines
6.2 KiB

10 years ago
10 years ago
10 years ago
10 years ago
  1. %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% ex: ts=4 sw=4 et
  3. %% -------------------------------------------------------------------
  4. %%
  5. %% rebar: Erlang Build Tools
  6. %%
  7. %% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com)
  8. %%
  9. %% Permission is hereby granted, free of charge, to any person obtaining a copy
  10. %% of this software and associated documentation files (the "Software"), to deal
  11. %% in the Software without restriction, including without limitation the rights
  12. %% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. %% copies of the Software, and to permit persons to whom the Software is
  14. %% furnished to do so, subject to the following conditions:
  15. %%
  16. %% The above copyright notice and this permission notice shall be included in
  17. %% all copies or substantial portions of the Software.
  18. %%
  19. %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. %% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. %% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. %% THE SOFTWARE.
  26. %% -------------------------------------------------------------------
  27. -module(rebar_core).
  28. -export([process_command/2
  29. ,update_code_path/1]).
  30. -include("rebar.hrl").
  31. -spec process_command(rebar_state:t(), atom()) -> {ok, rebar_state:t()} | {error, string()}.
  32. process_command(State, Command) ->
  33. %% ? rebar_prv_install_deps:setup_env(State),
  34. Providers = rebar_state:providers(State),
  35. Namespace = rebar_state:namespace(State),
  36. {TargetProviders, CommandProvider} =
  37. case Namespace of
  38. undefined ->
  39. %% undefined namespace means 'default', but on the first run;
  40. %% it is used as an implicit counter for the first vs. subsequent
  41. %% runs.
  42. {providers:get_target_providers(Command, Providers, default),
  43. providers:get_provider(Command, Providers, default)};
  44. _ ->
  45. {providers:get_target_providers(Command, Providers, Namespace),
  46. providers:get_provider(Command, Providers, Namespace)}
  47. end,
  48. case CommandProvider of
  49. not_found ->
  50. case Namespace of
  51. undefined ->
  52. %% On the first run (Namespace = undefined), we use the
  53. %% unfound command name to be a namespace.
  54. case providers:get_providers_by_namespace(Command, Providers) of
  55. [] ->
  56. {error, io_lib:format("Command ~p not found", [Command])};
  57. _ ->
  58. do([{default, do} | TargetProviders],
  59. rebar_state:namespace(State, Command))
  60. end;
  61. default ->
  62. {error, io_lib:format("Command ~p not found", [Command])};
  63. _ ->
  64. {error, io_lib:format("Command ~p not found in namespace ~p",
  65. [Command, Namespace])}
  66. end;
  67. CommandProvider ->
  68. case Command of
  69. Command when Command =:= do, Namespace =:= undefined ->
  70. %% We're definitely in the default namespace. 'do' doesn't
  71. %% properly exist for non-default namespaces outside of
  72. %% dynamic dispatch calls for namespaces.
  73. do(TargetProviders, rebar_state:namespace(State, default));
  74. Command when Command =:= do; Command =:= as ->
  75. do(TargetProviders, State);
  76. _ ->
  77. Profile = providers:profile(CommandProvider),
  78. State1 = rebar_state:apply_profiles(State, [Profile]),
  79. Opts = providers:opts(CommandProvider)++rebar3:global_option_spec_list(),
  80. case getopt:parse(Opts, rebar_state:command_args(State1)) of
  81. {ok, Args} ->
  82. State2 = rebar_state:command_parsed_args(State1, Args),
  83. do(TargetProviders, State2);
  84. {error, {invalid_option, Option}} ->
  85. {error, io_lib:format("Invalid option ~s on task ~p", [Option, Command])}
  86. end
  87. end
  88. end.
  89. -spec do([{atom(), atom()}], rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
  90. do([], State) ->
  91. {ok, State};
  92. do([ProviderName | Rest], State) ->
  93. Provider = providers:get_provider(ProviderName
  94. ,rebar_state:providers(State)),
  95. case providers:do(Provider, State) of
  96. {ok, State1} ->
  97. do(Rest, State1);
  98. {error, Error} ->
  99. {error, Error}
  100. end.
  101. update_code_path(State) ->
  102. true = rebar_utils:expand_code_path(),
  103. LibDirs = rebar_dir:lib_dirs(State),
  104. DepsDir = rebar_dir:deps_dir(State),
  105. PluginsDir = rebar_dir:plugins_dir(State),
  106. _UpdatedCodePaths = update_code_path_(lists:usort([DepsDir, PluginsDir | LibDirs])).
  107. %% ===================================================================
  108. %% Internal functions
  109. %% ===================================================================
  110. update_code_path_(Paths) ->
  111. LibPaths = expand_lib_dirs(Paths, rebar_dir:get_cwd(), []),
  112. ok = code:add_pathsa(LibPaths),
  113. %% track just the paths we added, so we can remove them without
  114. %% removing other paths added by this dep
  115. {added, LibPaths}.
  116. expand_lib_dirs([], _Root, Acc) ->
  117. Acc;
  118. expand_lib_dirs([Dir | Rest], Root, Acc) ->
  119. %% The current dir should only have an ebin dir.
  120. %% Other lib dirs contain app directories, so need the wildcard
  121. Apps = case Dir of
  122. "." ->
  123. [filename:join(Dir, "ebin")];
  124. _ ->
  125. filelib:wildcard(filename:join([Dir, "*", "ebin"]))
  126. end,
  127. FqApps = case filename:pathtype(Dir) of
  128. absolute -> Apps;
  129. _ -> [filename:join([Root, A]) || A <- Apps]
  130. end,
  131. expand_lib_dirs(Rest, Root, Acc ++ FqApps).