mirror of
https://github.com/correl/rebar.git
synced 2024-11-15 03:00:18 +00:00
Add support for non-Erlang/OTP (raw) dependencies
Introduce a new 'raw' option for dependency specs in rebar.config file. For example: {deps, {dependency_name, "1.0.*", {git, "<...>", {branch, "master"}}, [raw] } ]}. When this option is specified, rebar does not require the dependency to have a standard Erlang/OTP layout which assumes presence of either "src/dependency_name.app.src" or "ebin/dependency_name.app" files. 'raw' dependencies can still contain 'rebar.config' and even can have the proper OTP directory layout, but they won't be compiled. Only a subset of rebar commands will be executed on the 'raw' subdirectories: get-deps, update-deps, check-deps, list-deps and delete-deps.
This commit is contained in:
parent
32e67ef55e
commit
0b833391ed
3 changed files with 62 additions and 15 deletions
|
@ -20,7 +20,7 @@ run(Dir) ->
|
||||||
{ok, Missing} =
|
{ok, Missing} =
|
||||||
retest:sh_expect(Ref,
|
retest:sh_expect(Ref,
|
||||||
"DEBUG: Missing deps : \\[\\{dep,bad_name,"
|
"DEBUG: Missing deps : \\[\\{dep,bad_name,"
|
||||||
"boo,\"\\.\",undefined\\}\\]",
|
"boo,\"\\.\",undefined,false\\}\\]",
|
||||||
[{capture, all, list}]),
|
[{capture, all, list}]),
|
||||||
retest_log:log(debug, "[CAPTURED]: ~s~n", [Captured]),
|
retest_log:log(debug, "[CAPTURED]: ~s~n", [Captured]),
|
||||||
retest_log:log(debug, "[Missing]: ~s~n", [Missing]),
|
retest_log:log(debug, "[Missing]: ~s~n", [Missing]),
|
||||||
|
|
|
@ -138,7 +138,20 @@
|
||||||
{deps, [application_name,
|
{deps, [application_name,
|
||||||
{application_name, "1.0.*"},
|
{application_name, "1.0.*"},
|
||||||
{application_name, "1.0.*",
|
{application_name, "1.0.*",
|
||||||
{git, "git://github.com/basho/rebar.git", {branch, "master"}}}]}.
|
{git, "git://github.com/basho/rebar.git", {branch, "master"}}},
|
||||||
|
|
||||||
|
%% Dependencies can be marked as 'raw'. Rebar does not require such dependencies
|
||||||
|
%% to have a standard Erlang/OTP layout which assumes the presence of either
|
||||||
|
%% "src/dependency_name.app.src" or "ebin/dependency_name.app" files.
|
||||||
|
%%
|
||||||
|
%% 'raw' dependencies can still contain 'rebar.config' and even can have the
|
||||||
|
%% proper OTP directory layout, but they won't be compiled.
|
||||||
|
%%
|
||||||
|
%% Only a subset of rebar commands will be executed on the 'raw' subdirectories:
|
||||||
|
%% get-deps, update-deps, check-deps, list-deps and delete-deps.
|
||||||
|
{application_name, "",
|
||||||
|
{git, "git://github.com/basho/rebar.git", {branch, "master"}},
|
||||||
|
[raw]}]}.
|
||||||
|
|
||||||
%% == Subdirectories ==
|
%% == Subdirectories ==
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,8 @@
|
||||||
-record(dep, { dir,
|
-record(dep, { dir,
|
||||||
app,
|
app,
|
||||||
vsn_regex,
|
vsn_regex,
|
||||||
source }).
|
source,
|
||||||
|
is_raw }). %% is_raw = true means non-Erlang/OTP dependency
|
||||||
|
|
||||||
%% ===================================================================
|
%% ===================================================================
|
||||||
%% Public API
|
%% Public API
|
||||||
|
@ -78,8 +79,12 @@ preprocess(Config, _) ->
|
||||||
Config3
|
Config3
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
%% Filtering out 'raw' dependencies so that no commands other than
|
||||||
|
%% deps-related can be executed on their directories.
|
||||||
|
NonRawAvailableDeps = [D || D <- AvailableDeps, not D#dep.is_raw],
|
||||||
|
|
||||||
%% Return all the available dep directories for process
|
%% Return all the available dep directories for process
|
||||||
{ok, NewConfig, dep_dirs(AvailableDeps)}.
|
{ok, NewConfig, dep_dirs(NonRawAvailableDeps)}.
|
||||||
|
|
||||||
postprocess(Config, _) ->
|
postprocess(Config, _) ->
|
||||||
case rebar_config:get_xconf(Config, ?MODULE, undefined) of
|
case rebar_config:get_xconf(Config, ?MODULE, undefined) of
|
||||||
|
@ -90,8 +95,9 @@ postprocess(Config, _) ->
|
||||||
{ok, NewConfig, Dirs}
|
{ok, NewConfig, Dirs}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
compile(Config, AppFile) ->
|
compile(Config, _) ->
|
||||||
'check-deps'(Config, AppFile).
|
{Config1, _AvailDeps} = do_check_deps(Config),
|
||||||
|
{ok, Config1}.
|
||||||
|
|
||||||
%% set REBAR_DEPS_DIR and ERL_LIBS environment variables
|
%% set REBAR_DEPS_DIR and ERL_LIBS environment variables
|
||||||
setup_env(Config) ->
|
setup_env(Config) ->
|
||||||
|
@ -111,13 +117,14 @@ setup_env(Config) ->
|
||||||
end,
|
end,
|
||||||
[{"REBAR_DEPS_DIR", DepsDir}, ERL_LIBS].
|
[{"REBAR_DEPS_DIR", DepsDir}, ERL_LIBS].
|
||||||
|
|
||||||
'check-deps'(Config, _) ->
|
%% common function used by 'check-deps' and 'compile'
|
||||||
|
do_check_deps(Config) ->
|
||||||
%% Get the list of immediate (i.e. non-transitive) deps that are missing
|
%% Get the list of immediate (i.e. non-transitive) deps that are missing
|
||||||
Deps = rebar_config:get_local(Config, deps, []),
|
Deps = rebar_config:get_local(Config, deps, []),
|
||||||
case find_deps(Config, find, Deps) of
|
case find_deps(Config, find, Deps) of
|
||||||
{Config1, {_, []}} ->
|
{Config1, {AvailDeps, []}} ->
|
||||||
%% No missing deps
|
%% No missing deps
|
||||||
{ok, Config1};
|
{Config1, AvailDeps};
|
||||||
{_Config1, {_, MissingDeps}} ->
|
{_Config1, {_, MissingDeps}} ->
|
||||||
lists:foreach(fun (#dep{app=App, vsn_regex=Vsn, source=Src}) ->
|
lists:foreach(fun (#dep{app=App, vsn_regex=Vsn, source=Src}) ->
|
||||||
?CONSOLE("Dependency not available: "
|
?CONSOLE("Dependency not available: "
|
||||||
|
@ -126,6 +133,10 @@ setup_env(Config) ->
|
||||||
?FAIL
|
?FAIL
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
'check-deps'(Config, _) ->
|
||||||
|
{Config1, AvailDeps} = do_check_deps(Config),
|
||||||
|
{ok, save_dep_dirs(Config1, AvailDeps)}.
|
||||||
|
|
||||||
'get-deps'(Config, _) ->
|
'get-deps'(Config, _) ->
|
||||||
%% Determine what deps are available and missing
|
%% Determine what deps are available and missing
|
||||||
Deps = rebar_config:get_local(Config, deps, []),
|
Deps = rebar_config:get_local(Config, deps, []),
|
||||||
|
@ -171,7 +182,7 @@ setup_env(Config) ->
|
||||||
case find_deps(Config, find, Deps) of
|
case find_deps(Config, find, Deps) of
|
||||||
{Config1, {AvailDeps, []}} ->
|
{Config1, {AvailDeps, []}} ->
|
||||||
lists:foreach(fun(Dep) -> print_source(Dep) end, AvailDeps),
|
lists:foreach(fun(Dep) -> print_source(Dep) end, AvailDeps),
|
||||||
{ok, Config1};
|
{ok, save_dep_dirs(Config1, AvailDeps)};
|
||||||
{_, MissingDeps} ->
|
{_, MissingDeps} ->
|
||||||
?ABORT("Missing dependencies: ~p\n", [MissingDeps])
|
?ABORT("Missing dependencies: ~p\n", [MissingDeps])
|
||||||
end.
|
end.
|
||||||
|
@ -221,7 +232,7 @@ update_deps_code_path(Config, []) ->
|
||||||
update_deps_code_path(Config, [Dep | Rest]) ->
|
update_deps_code_path(Config, [Dep | Rest]) ->
|
||||||
Config2 =
|
Config2 =
|
||||||
case is_app_available(Config, Dep#dep.app,
|
case is_app_available(Config, Dep#dep.app,
|
||||||
Dep#dep.vsn_regex, Dep#dep.dir) of
|
Dep#dep.vsn_regex, Dep#dep.dir, Dep#dep.is_raw) of
|
||||||
{Config1, {true, _}} ->
|
{Config1, {true, _}} ->
|
||||||
Dir = filename:join(Dep#dep.dir, "ebin"),
|
Dir = filename:join(Dep#dep.dir, "ebin"),
|
||||||
ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
|
ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
|
||||||
|
@ -247,9 +258,14 @@ find_deps(Config, Mode, [App | Rest], Acc) when is_atom(App) ->
|
||||||
find_deps(Config, Mode, [{App, VsnRegex} | Rest], Acc) when is_atom(App) ->
|
find_deps(Config, Mode, [{App, VsnRegex} | Rest], Acc) when is_atom(App) ->
|
||||||
find_deps(Config, Mode, [{App, VsnRegex, undefined} | Rest], Acc);
|
find_deps(Config, Mode, [{App, VsnRegex, undefined} | Rest], Acc);
|
||||||
find_deps(Config, Mode, [{App, VsnRegex, Source} | Rest], Acc) ->
|
find_deps(Config, Mode, [{App, VsnRegex, Source} | Rest], Acc) ->
|
||||||
|
find_deps(Config, Mode, [{App, VsnRegex, Source, []} | Rest], Acc);
|
||||||
|
find_deps(Config, Mode, [{App, VsnRegex, Source, Opts} | Rest], Acc) when is_list(Opts) ->
|
||||||
Dep = #dep { app = App,
|
Dep = #dep { app = App,
|
||||||
vsn_regex = VsnRegex,
|
vsn_regex = VsnRegex,
|
||||||
source = Source },
|
source = Source,
|
||||||
|
%% dependency is considered raw (i.e. non-Erlang/OTP) when
|
||||||
|
%% 'raw' option is present
|
||||||
|
is_raw = proplists:get_value(raw, Opts, false) },
|
||||||
{Config1, {Availability, FoundDir}} = find_dep(Config, Dep),
|
{Config1, {Availability, FoundDir}} = find_dep(Config, Dep),
|
||||||
find_deps(Config1, Mode, Rest,
|
find_deps(Config1, Mode, Rest,
|
||||||
acc_deps(Mode, Availability, Dep, FoundDir, Acc));
|
acc_deps(Mode, Availability, Dep, FoundDir, Acc));
|
||||||
|
@ -284,7 +300,8 @@ find_dep_in_dir(Config, _Dep, {false, Dir}) ->
|
||||||
find_dep_in_dir(Config, Dep, {true, Dir}) ->
|
find_dep_in_dir(Config, Dep, {true, Dir}) ->
|
||||||
App = Dep#dep.app,
|
App = Dep#dep.app,
|
||||||
VsnRegex = Dep#dep.vsn_regex,
|
VsnRegex = Dep#dep.vsn_regex,
|
||||||
case is_app_available(Config, App, VsnRegex, Dir) of
|
IsRaw = Dep#dep.is_raw,
|
||||||
|
case is_app_available(Config, App, VsnRegex, Dir, IsRaw) of
|
||||||
{Config1, {true, _AppFile}} -> {Config1, {avail, Dir}};
|
{Config1, {true, _AppFile}} -> {Config1, {avail, Dir}};
|
||||||
{Config1, {false, _}} -> {Config1, {missing, Dir}}
|
{Config1, {false, _}} -> {Config1, {missing, Dir}}
|
||||||
end.
|
end.
|
||||||
|
@ -309,7 +326,11 @@ require_source_engine(Source) ->
|
||||||
true = source_engine_avail(Source),
|
true = source_engine_avail(Source),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
is_app_available(Config, App, VsnRegex, Path) ->
|
%% IsRaw = false means regular Erlang/OTP dependency
|
||||||
|
%%
|
||||||
|
%% IsRaw = true means non-Erlang/OTP dependency, e.g. the one that does not
|
||||||
|
%% have a proper .app file
|
||||||
|
is_app_available(Config, App, VsnRegex, Path, _IsRaw = false) ->
|
||||||
?DEBUG("is_app_available, looking for App ~p with Path ~p~n", [App, Path]),
|
?DEBUG("is_app_available, looking for App ~p with Path ~p~n", [App, Path]),
|
||||||
case rebar_app_utils:is_app_dir(Path) of
|
case rebar_app_utils:is_app_dir(Path) of
|
||||||
{true, AppFile} ->
|
{true, AppFile} ->
|
||||||
|
@ -340,6 +361,19 @@ is_app_available(Config, App, VsnRegex, Path) ->
|
||||||
?WARN("Expected ~s to be an app dir (containing ebin/*.app), "
|
?WARN("Expected ~s to be an app dir (containing ebin/*.app), "
|
||||||
"but no .app found.\n", [Path]),
|
"but no .app found.\n", [Path]),
|
||||||
{Config, {false, {missing_app_file, Path}}}
|
{Config, {false, {missing_app_file, Path}}}
|
||||||
|
end;
|
||||||
|
is_app_available(Config, App, _VsnRegex, Path, _IsRaw = true) ->
|
||||||
|
?DEBUG("is_app_available, looking for Raw Depencency ~p with Path ~p~n", [App, Path]),
|
||||||
|
case filelib:is_dir(Path) of
|
||||||
|
true ->
|
||||||
|
%% TODO: look for version string in <Path>/VERSION file? Not clear
|
||||||
|
%% how to detect git/svn/hg/{cmd, ...} settings that can be passed
|
||||||
|
%% to rebar_utils:vcs_vsn/2 to obtain version dynamically
|
||||||
|
{Config, {true, Path}};
|
||||||
|
false ->
|
||||||
|
?WARN("Expected ~s to be a raw dependency directory, "
|
||||||
|
"but no directory found.\n", [Path]),
|
||||||
|
{Config, {false, {missing_raw_dependency_directory, Path}}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
use_source(Config, Dep) ->
|
use_source(Config, Dep) ->
|
||||||
|
@ -353,7 +387,7 @@ use_source(Config, Dep, Count) ->
|
||||||
true ->
|
true ->
|
||||||
%% Already downloaded -- verify the versioning matches the regex
|
%% Already downloaded -- verify the versioning matches the regex
|
||||||
case is_app_available(Config, Dep#dep.app,
|
case is_app_available(Config, Dep#dep.app,
|
||||||
Dep#dep.vsn_regex, Dep#dep.dir) of
|
Dep#dep.vsn_regex, Dep#dep.dir, Dep#dep.is_raw) of
|
||||||
{Config1, {true, _}} ->
|
{Config1, {true, _}} ->
|
||||||
Dir = filename:join(Dep#dep.dir, "ebin"),
|
Dir = filename:join(Dep#dep.dir, "ebin"),
|
||||||
ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
|
ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
|
||||||
|
|
Loading…
Reference in a new issue