diff options
author | Tim Watson <watson.timothy@gmail.com> | 2011-05-03 00:15:19 +0100 |
---|---|---|
committer | Tuncer Ayaz <tuncer.ayaz@gmail.com> | 2011-08-29 17:27:45 +0200 |
commit | 3b58935b8621a876afad2f649bbd00a12f7ab03f (patch) | |
tree | e7d90f6d318e8d52f9db40635c4bd22f40b1e9a5 /src | |
parent | 7a1c88228be2129ad517d5b4eda9c4c9232115bf (diff) |
Load plugins dynamically from source
This patch updates rebar_core to look for missing plugins (i.e. those
that aren't found on the code path at runtime) in a configurable
plugin directory, and dynamically compile and load them at runtime.
By default, the directory "plugins" is searched, although this can be
overriden by setting the plugin_dir in your rebar.config.
Diffstat (limited to 'src')
-rw-r--r-- | src/rebar_core.erl | 54 |
1 files changed, 49 insertions, 5 deletions
diff --git a/src/rebar_core.erl b/src/rebar_core.erl index 75569b4..f30eb35 100644 --- a/src/rebar_core.erl +++ b/src/rebar_core.erl @@ -380,13 +380,57 @@ ulist([H | T], Acc) -> plugin_modules(_Config, []) -> {ok, []}; -plugin_modules(_Config, Modules) -> +plugin_modules(Config, Modules) -> FoundModules = [M || M <- Modules, code:which(M) =/= non_existing], - case (Modules =:= FoundModules) of + plugin_modules(Config, FoundModules, Modules -- FoundModules). + +plugin_modules(_Config, FoundModules, []) -> + {ok, FoundModules}; +plugin_modules(Config, FoundModules, MissingModules) -> + {Loaded, NotLoaded} = load_plugin_modules(Config, MissingModules), + AllViablePlugins = FoundModules ++ Loaded, + case length(NotLoaded) > 0 of true -> - ok; + %% NB: we continue to ignore this situation, as did the original code + ?WARN("Missing plugins: ~p\n", NotLoaded); false -> - ?WARN("Missing plugins: ~p\n", [Modules -- FoundModules]), + ?DEBUG("Loaded plugins: ~p~n", [AllViablePlugins]), ok end, - {ok, FoundModules}. + {ok, AllViablePlugins}. + +load_plugin_modules(Config, Modules) -> + PluginDir = case rebar_config:get_local(Config, plugin_dir, undefined) of + undefined -> + filename:join(rebar_utils:get_cwd(), "plugins"); + Dir -> + Dir + end, + Sources = rebar_utils:find_files(PluginDir, ".*\.erl\$"), + Loaded = [load_plugin(Src) || Src <- Sources], + FilterMissing = is_missing_plugin(Loaded), + NotLoaded = [V || V <- Modules, FilterMissing(V)], + {Loaded, NotLoaded}. + +is_missing_plugin(Loaded) -> + fun(Mod) -> not lists:member(Mod, Loaded) end. + +load_plugin(Src) -> + case compile:file(Src, [binary, return_errors]) of + {ok, Mod, Bin} -> + load_plugin_module(Mod, Bin, Src); + {error, Errors, _Warnings} -> + ?ABORT("Plugin ~s contains compilation errors: ~p~n", + [Src, Errors]) + end. + +load_plugin_module(Mod, Bin, Src) -> + case code:is_loaded(Mod) of + {file, Loaded} -> + ?ABORT("Plugin ~p clashes with previously loaded module ~p~n", + [Mod, Loaded]); + false -> + ?INFO("Loading plugin ~p from ~s~n", [Mod, Src]), + {module, Mod} = code:load_binary(Mod, Src, Bin), + Mod + end. |