summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTim Watson <watson.timothy@gmail.com>2011-05-03 00:15:19 +0100
committerTuncer Ayaz <tuncer.ayaz@gmail.com>2011-08-29 17:27:45 +0200
commit3b58935b8621a876afad2f649bbd00a12f7ab03f (patch)
treee7d90f6d318e8d52f9db40635c4bd22f40b1e9a5 /src
parent7a1c88228be2129ad517d5b4eda9c4c9232115bf (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.erl54
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.