diff options
Diffstat (limited to 'src/rebar_core.erl')
-rw-r--r-- | src/rebar_core.erl | 144 |
1 files changed, 90 insertions, 54 deletions
diff --git a/src/rebar_core.erl b/src/rebar_core.erl index 9e3f9f0..3172d64 100644 --- a/src/rebar_core.erl +++ b/src/rebar_core.erl @@ -26,7 +26,7 @@ %% ------------------------------------------------------------------- -module(rebar_core). --export([process_commands/2]). +-export([process_commands/2, help/2]). -include("rebar.hrl"). @@ -34,6 +34,35 @@ %% Internal functions %% =================================================================== +help(ParentConfig, Commands) -> + %% get all core modules + {ok, AnyDirModules} = application:get_env(rebar, any_dir_modules), + {ok, RawCoreModules} = application:get_env(rebar, modules), + AppDirModules = proplists:get_value(app_dir, RawCoreModules), + RelDirModules = proplists:get_value(rel_dir, RawCoreModules), + CoreModules = AnyDirModules ++ AppDirModules ++ RelDirModules, + + %% get plugin modules + Predirs = [], + Dir = rebar_utils:get_cwd(), + PredirsAssoc = remember_cwd_predirs(Dir, Predirs), + Config = maybe_load_local_config(Dir, ParentConfig), + {ok, PluginModules} = plugin_modules(Config, PredirsAssoc), + + AllModules = CoreModules ++ PluginModules, + + lists:foreach( + fun(Cmd) -> + ?CONSOLE("==> help ~p~n~n", [Cmd]), + CmdModules = select_modules(AllModules, Cmd, []), + Modules = select_modules(CmdModules, info, []), + lists:foreach(fun(M) -> + ?CONSOLE("=== ~p:~p ===~n", [M, Cmd]), + M:info(help, Cmd), + ?CONSOLE("~n", []) + end, Modules) + end, Commands). + process_commands([], ParentConfig) -> AbortTrapped = rebar_config:get_xconf(ParentConfig, abort_trapped, false), case {get_operations(ParentConfig), AbortTrapped} of @@ -53,9 +82,10 @@ process_commands([Command | Rest], ParentConfig) -> ParentConfig4 = try - %% Convert the code path so that all the entries are absolute paths. - %% If not, code:set_path() may choke on invalid relative paths when trying - %% to restore the code path from inside a subdirectory. + %% Convert the code path so that all the entries are + %% absolute paths. If not, code:set_path() may choke on + %% invalid relative paths when trying to restore the code + %% path from inside a subdirectory. true = rebar_utils:expand_code_path(), {ParentConfig2, _DirSet} = process_dir(rebar_utils:get_cwd(), ParentConfig1, Command, @@ -68,8 +98,9 @@ process_commands([Command | Rest], ParentConfig) -> _ -> ok end, - %% TODO: reconsider after config inheritance removal/redesign - ParentConfig3 = rebar_config:clean_config(ParentConfig1, ParentConfig2), + %% TODO: reconsider after config inheritance removal/re-design + ParentConfig3 = rebar_config:clean_config(ParentConfig1, + ParentConfig2), %% Wipe out vsn cache to avoid invalid hits when %% dependencies are updated rebar_config:set_xconf(ParentConfig3, vsn_cache, dict:new()) @@ -107,41 +138,41 @@ process_dir(Dir, ParentConfig, Command, DirSet) -> %% to process this dir. {ok, AvailModuleSets} = application:get_env(rebar, modules), ModuleSet = choose_module_set(AvailModuleSets, Dir), - maybe_process_dir(ModuleSet, Config, CurrentCodePath, - Dir, Command, DirSet) + skip_or_process_dir(ModuleSet, Config, CurrentCodePath, + Dir, Command, DirSet) end. -maybe_process_dir({[], undefined}=ModuleSet, Config, CurrentCodePath, - Dir, Command, DirSet) -> - process_dir0(Dir, Command, DirSet, Config, CurrentCodePath, ModuleSet); -maybe_process_dir({_, ModuleSetFile}=ModuleSet, Config, CurrentCodePath, - Dir, Command, DirSet) -> +skip_or_process_dir({[], undefined}=ModuleSet, Config, CurrentCodePath, + Dir, Command, DirSet) -> + process_dir1(Dir, Command, DirSet, Config, CurrentCodePath, ModuleSet); +skip_or_process_dir({_, ModuleSetFile}=ModuleSet, Config, CurrentCodePath, + Dir, Command, DirSet) -> case lists:suffix(".app.src", ModuleSetFile) orelse lists:suffix(".app", ModuleSetFile) of true -> %% .app or .app.src file, check if is_skipped_app - maybe_process_dir0(ModuleSetFile, ModuleSet, - Config, CurrentCodePath, Dir, - Command, DirSet); + skip_or_process_dir1(ModuleSetFile, ModuleSet, + Config, CurrentCodePath, Dir, + Command, DirSet); false -> %% not an app dir, no need to consider apps=/skip_apps= - process_dir0(Dir, Command, DirSet, Config, + process_dir1(Dir, Command, DirSet, Config, CurrentCodePath, ModuleSet) end. -maybe_process_dir0(AppFile, ModuleSet, Config, CurrentCodePath, - Dir, Command, DirSet) -> +skip_or_process_dir1(AppFile, ModuleSet, Config, CurrentCodePath, + Dir, Command, DirSet) -> case rebar_app_utils:is_skipped_app(Config, AppFile) of {Config1, {true, SkippedApp}} -> ?DEBUG("Skipping app: ~p~n", [SkippedApp]), Config2 = increment_operations(Config1), {Config2, DirSet}; {Config1, false} -> - process_dir0(Dir, Command, DirSet, Config1, + process_dir1(Dir, Command, DirSet, Config1, CurrentCodePath, ModuleSet) end. -process_dir0(Dir, Command, DirSet, Config0, CurrentCodePath, +process_dir1(Dir, Command, DirSet, Config0, CurrentCodePath, {DirModules, ModuleSetFile}) -> %% Get the list of modules for "any dir". This is a catch-all list %% of modules that are processed in addition to modules associated @@ -156,11 +187,12 @@ process_dir0(Dir, Command, DirSet, Config0, CurrentCodePath, {Config1, Predirs} = acc_modules(Modules, preprocess, Config0, ModuleSetFile), - SubdirAssoc = remember_cwd_subdir(Dir, Predirs), + %% Remember associated pre-dirs (used for plugin lookup) + PredirsAssoc = remember_cwd_predirs(Dir, Predirs), %% Get the list of plug-in modules from rebar.config. These %% modules may participate in preprocess and postprocess. - {ok, PluginModules} = plugin_modules(Config1, SubdirAssoc), + {ok, PluginModules} = plugin_modules(Config1, PredirsAssoc), {Config2, PluginPredirs} = acc_modules(PluginModules, preprocess, Config1, ModuleSetFile), @@ -222,7 +254,7 @@ process_dir0(Dir, Command, DirSet, Config0, CurrentCodePath, %% Return the updated {config, dirset} as result Res. -remember_cwd_subdir(Cwd, Subdirs) -> +remember_cwd_predirs(Cwd, Predirs) -> Store = fun(Dir, Dict) -> case dict:find(Dir, Dict) of error -> @@ -233,11 +265,10 @@ remember_cwd_subdir(Cwd, Subdirs) -> ?ABORT("Internal consistency assertion failed.~n" "sub_dir ~s already associated with ~s.~n" "Duplicate sub_dirs or deps entries?", - [Dir, Existing]), - Dict + [Dir, Existing]) end end, - lists:foldl(Store, dict:new(), Subdirs). + lists:foldl(Store, dict:new(), Predirs). maybe_load_local_config(Dir, ParentConfig) -> %% We need to ensure we don't overwrite custom @@ -270,7 +301,6 @@ process_each([Dir | Rest], Command, Config, ModuleSetFile, DirSet) -> process_each(Rest, Command, Config3, ModuleSetFile, DirSet2) end. - %% %% Given a list of module sets from rebar.app and a directory, find %% the appropriate subset of modules for this directory @@ -458,9 +488,9 @@ acc_modules([Module | Rest], Command, Config, File, Acc) -> %% %% Return a flat list of rebar plugin modules. %% -plugin_modules(Config, SubdirAssoc) -> +plugin_modules(Config, PredirsAssoc) -> Modules = lists:flatten(rebar_config:get_all(Config, plugins)), - plugin_modules(Config, SubdirAssoc, ulist(Modules)). + plugin_modules(Config, PredirsAssoc, ulist(Modules)). ulist(L) -> ulist(L, []). @@ -475,16 +505,16 @@ ulist([H | T], Acc) -> ulist(T, [H | Acc]) end. -plugin_modules(_Config, _SubdirAssoc, []) -> +plugin_modules(_Config, _PredirsAssoc, []) -> {ok, []}; -plugin_modules(Config, SubdirAssoc, Modules) -> +plugin_modules(Config, PredirsAssoc, Modules) -> FoundModules = [M || M <- Modules, code:which(M) =/= non_existing], - plugin_modules(Config, SubdirAssoc, FoundModules, Modules -- FoundModules). + plugin_modules(Config, PredirsAssoc, FoundModules, Modules -- FoundModules). -plugin_modules(_Config, _SubdirAssoc, FoundModules, []) -> +plugin_modules(_Config, _PredirsAssoc, FoundModules, []) -> {ok, FoundModules}; -plugin_modules(Config, SubdirAssoc, FoundModules, MissingModules) -> - {Loaded, NotLoaded} = load_plugin_modules(Config, SubdirAssoc, +plugin_modules(Config, PredirsAssoc, FoundModules, MissingModules) -> + {Loaded, NotLoaded} = load_plugin_modules(Config, PredirsAssoc, MissingModules), AllViablePlugins = FoundModules ++ Loaded, case NotLoaded =/= [] of @@ -498,37 +528,43 @@ plugin_modules(Config, SubdirAssoc, FoundModules, MissingModules) -> end, {ok, AllViablePlugins}. -load_plugin_modules(Config, SubdirAssoc, Modules) -> +load_plugin_modules(Config, PredirsAssoc, Modules) -> Cwd = rebar_utils:get_cwd(), - PluginDir = case rebar_config:get_local(Config, plugin_dir, undefined) of - undefined -> - filename:join(Cwd, "plugins"); - Dir -> - Dir - end, + PluginDirs = case rebar_config:get_local(Config, plugin_dir, undefined) of + undefined -> + % Plugin can be in the project's "plugins" folder + [filename:join(Cwd, "plugins")]; + Dir -> + [Dir] + end ++ + % We also want to include this case: + % Plugin can be in "plugins" directory of the plugin base directory. For + % example, Cwd depends on Plugin, and deps/Plugin/plugins/Plugin.erl is the + % plugin. + [ + filename:join(Dir, "plugins") || + Dir <- get_plugin_base_dirs(Cwd, PredirsAssoc) + ], %% Find relevant sources in base_dir and plugin_dir Erls = string:join([atom_to_list(M)++"\\.erl" || M <- Modules], "|"), RE = "^" ++ Erls ++ "\$", - BaseDir = get_plugin_base_dir(Cwd, SubdirAssoc), %% If a plugin is found both in base_dir and plugin_dir, the clash %% will provoke an error and we'll abort. - Sources = rebar_utils:find_files(PluginDir, RE, false) - ++ rebar_utils:find_files(BaseDir, RE, false), + Sources = [rebar_utils:find_files(PD, RE, false) || PD <- PluginDirs], %% Compile and load plugins - Loaded = [load_plugin(Src) || Src <- Sources], + Loaded = [load_plugin(Src) || Src <- lists:append(Sources)], FilterMissing = is_missing_plugin(Loaded), NotLoaded = [V || V <- Modules, FilterMissing(V)], {Loaded, NotLoaded}. -get_plugin_base_dir(Cwd, SubdirAssoc) -> - case dict:find(Cwd, SubdirAssoc) of - {ok, BaseDir} -> - BaseDir; - error -> - Cwd - end. +%% @doc PredirsAssoc is a dictionary of plugindir -> 'parent' pairs +%% 'parent' in this case depends on plugin; therefore we have to give +%% all plugins that Cwd ('parent' in this case) depends on. +get_plugin_base_dirs(Cwd, PredirsAssoc) -> + [PluginDir || {PluginDir, Master} <- dict:to_list(PredirsAssoc), + Master =:= Cwd]. is_missing_plugin(Loaded) -> fun(Mod) -> not lists:member(Mod, Loaded) end. |