Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for non-Erlang/OTP (raw) dependencies #217

Merged
merged 1 commit into from
Oct 21, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion inttest/t_custom_config/t_custom_config_rt.erl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ run(Dir) ->
{ok, Missing} =
retest:sh_expect(Ref,
"DEBUG: Missing deps : \\[\\{dep,bad_name,"
"boo,\"\\.\",undefined\\}\\]",
"boo,\"\\.\",undefined,false\\}\\]",
[{capture, all, list}]),
retest_log:log(debug, "[CAPTURED]: ~s~n", [Captured]),
retest_log:log(debug, "[Missing]: ~s~n", [Missing]),
Expand Down
15 changes: 14 additions & 1 deletion rebar.config.sample
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,20 @@
{deps, [application_name,
{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 ==

Expand Down
60 changes: 47 additions & 13 deletions src/rebar_deps.erl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
-record(dep, { dir,
app,
vsn_regex,
source }).
source,
is_raw }). %% is_raw = true means non-Erlang/OTP dependency

%% ===================================================================
%% Public API
Expand Down Expand Up @@ -78,8 +79,12 @@ preprocess(Config, _) ->
Config3
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
{ok, NewConfig, dep_dirs(AvailableDeps)}.
{ok, NewConfig, dep_dirs(NonRawAvailableDeps)}.

postprocess(Config, _) ->
case rebar_config:get_xconf(Config, ?MODULE, undefined) of
Expand All @@ -90,8 +95,9 @@ postprocess(Config, _) ->
{ok, NewConfig, Dirs}
end.

compile(Config, AppFile) ->
'check-deps'(Config, AppFile).
compile(Config, _) ->
{Config1, _AvailDeps} = do_check_deps(Config),
{ok, Config1}.

%% set REBAR_DEPS_DIR and ERL_LIBS environment variables
setup_env(Config) ->
Expand All @@ -111,13 +117,14 @@ setup_env(Config) ->
end,
[{"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
Deps = rebar_config:get_local(Config, deps, []),
case find_deps(Config, find, Deps) of
{Config1, {_, []}} ->
{Config1, {AvailDeps, []}} ->
%% No missing deps
{ok, Config1};
{Config1, AvailDeps};
{_Config1, {_, MissingDeps}} ->
lists:foreach(fun (#dep{app=App, vsn_regex=Vsn, source=Src}) ->
?CONSOLE("Dependency not available: "
Expand All @@ -126,6 +133,10 @@ setup_env(Config) ->
?FAIL
end.

'check-deps'(Config, _) ->
{Config1, AvailDeps} = do_check_deps(Config),
{ok, save_dep_dirs(Config1, AvailDeps)}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the only difference between check-deps and compile is that check_deps invokes save_dep_dirs/2? Why?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dizzyd Regrading compile, I just followed the original behavior where it was calling check-deps. check-deps was changed to call save_deps_dirs/2, because, unlike compile, it should work recursively on raw deps as well. The full list of deps will be returned later by postprocess/2 and raw deps will be processed recursively from there. The same applies to get-deps. I relied on the existing mechanism in rebar_core.erl to avoid (post-)processing non-raw deps twice.


'get-deps'(Config, _) ->
%% Determine what deps are available and missing
Deps = rebar_config:get_local(Config, deps, []),
Expand Down Expand Up @@ -171,7 +182,7 @@ setup_env(Config) ->
case find_deps(Config, find, Deps) of
{Config1, {AvailDeps, []}} ->
lists:foreach(fun(Dep) -> print_source(Dep) end, AvailDeps),
{ok, Config1};
{ok, save_dep_dirs(Config1, AvailDeps)};
{_, MissingDeps} ->
?ABORT("Missing dependencies: ~p\n", [MissingDeps])
end.
Expand Down Expand Up @@ -221,7 +232,7 @@ update_deps_code_path(Config, []) ->
update_deps_code_path(Config, [Dep | Rest]) ->
Config2 =
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, _}} ->
Dir = filename:join(Dep#dep.dir, "ebin"),
ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
Expand All @@ -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, 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, Opts} | Rest], Acc) when is_list(Opts) ->
Dep = #dep { app = App,
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),
find_deps(Config1, Mode, Rest,
acc_deps(Mode, Availability, Dep, FoundDir, Acc));
Expand Down Expand Up @@ -284,7 +300,8 @@ find_dep_in_dir(Config, _Dep, {false, Dir}) ->
find_dep_in_dir(Config, Dep, {true, Dir}) ->
App = Dep#dep.app,
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, {false, _}} -> {Config1, {missing, Dir}}
end.
Expand All @@ -309,7 +326,11 @@ require_source_engine(Source) ->
true = source_engine_avail(Source),
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]),
case rebar_app_utils:is_app_dir(Path) of
{true, AppFile} ->
Expand Down Expand Up @@ -340,6 +361,19 @@ is_app_available(Config, App, VsnRegex, Path) ->
?WARN("Expected ~s to be an app dir (containing ebin/*.app), "
"but no .app found.\n", [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.

use_source(Config, Dep) ->
Expand All @@ -353,7 +387,7 @@ use_source(Config, Dep, Count) ->
true ->
%% Already downloaded -- verify the versioning matches the regex
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, _}} ->
Dir = filename:join(Dep#dep.dir, "ebin"),
ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
Expand Down