summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/rebar_app_utils.erl1
-rw-r--r--src/rebar_prv_deps.erl141
-rw-r--r--test/rebar_deps_SUITE.erl35
3 files changed, 137 insertions, 40 deletions
diff --git a/src/rebar_app_utils.erl b/src/rebar_app_utils.erl
index 5fe5ba6..0ea6ad8 100644
--- a/src/rebar_app_utils.erl
+++ b/src/rebar_app_utils.erl
@@ -34,6 +34,7 @@
validate_application_info/2,
parse_deps/5,
parse_deps/6,
+ parse_dep/6,
expand_deps_sources/2,
dep_to_app/7,
format_error/1]).
diff --git a/src/rebar_prv_deps.erl b/src/rebar_prv_deps.erl
index d8f22d9..5443ab5 100644
--- a/src/rebar_prv_deps.erl
+++ b/src/rebar_prv_deps.erl
@@ -9,7 +9,7 @@
-include("rebar.hrl").
-define(PROVIDER, deps).
--define(DEPS, [app_discovery]).
+-define(DEPS, [install_deps]).
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
@@ -22,54 +22,127 @@ init(State) ->
{deps, ?DEPS},
{example, "rebar3 deps"},
{short_desc, "List dependencies"},
- {desc, "List dependencies. Those not matching lock files "
- "are followed by an asterisk (*)."},
+ {desc, "List dependencies. Those not matching "
+ "the config file are followed by "
+ "an asterisk (*)."},
{opts, []}])),
{ok, State1}.
+
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
Profiles = rebar_state:current_profiles(State),
- [display(State, Profile, rebar_state:get(State, {parsed_deps, Profile}, []))
- || Profile <- Profiles],
+ [display(State, Profile) || Profile <- Profiles],
{ok, State}.
+
-spec format_error(any()) -> iolist().
format_error(Reason) ->
io_lib:format("~p", [Reason]).
-display(State, default, Deps) ->
- display_deps(State, Deps),
+
+display(State, Profile = default) ->
+ display_profile_deps(State, Profile),
?CONSOLE("", []);
-display(State, Profile, Deps) ->
+display(State, Profile) ->
?CONSOLE("-- ~p --", [Profile]),
- display(State, default, Deps).
-
-display_deps(State, Deps) ->
- lists:foreach(fun(Dep) -> display_dep(State, Dep) end, Deps).
-
-display_dep(State, Dep) ->
- DepWithSource = rebar_app_utils:expand_deps_sources(Dep, State),
-
- Name = rebar_utils:to_binary(rebar_app_info:name(DepWithSource)),
- NeedsUpdateSuffix = case rebar_fetch:needs_update(DepWithSource, State) of
- true -> "*";
- false -> ""
- end,
- IsLockedPrefix = case rebar_app_info:is_lock(DepWithSource) of
- true -> "locked ";
- _ -> ""
- end,
- CommonConsoleArgs = [Name, NeedsUpdateSuffix, IsLockedPrefix],
-
- Source = rebar_app_info:source(DepWithSource),
- case Source of
- {pkg, _Name, Vsn, _Hash, _RepoConfig} ->
- VsnBinary = rebar_utils:to_binary(Vsn),
- ?CONSOLE("~ts~ts (~tspackage ~ts)", CommonConsoleArgs ++ [VsnBinary]);
+ display_profile_deps(State, Profile),
+ ?CONSOLE("", []).
+
+
+display_profile_deps(State, Profile) ->
+ DepsDir = rebar_prv_install_deps:profile_dep_dir(State, Profile),
+
+ ProfileDeps = rebar_state:get(State, {deps, Profile}, []),
+ % ProfileDeps include those deps from rebar.lock that have been
+ % removed from rebar.config
+ ConfiguredDeps = [parse_dep_without_locks(DepsDir, Dep, State)
+ || Dep <- ProfileDeps],
+ LockedDepsMap = locked_deps_map(State, Profile),
+ [display_dep(State, Dep, LockedDepsMap) || Dep <- ConfiguredDeps].
+
+
+parse_dep_without_locks(DepsDir, Dep, State) ->
+ ParsedDep = rebar_app_utils:parse_dep(Dep, root, DepsDir, State, [], 0),
+ case Dep of
+ {_Name, Src, Level} when is_tuple(Src), is_integer(Level) ->
+ % This Dep is not in rebar.config but in rebar.lock
+ rebar_app_info:source(ParsedDep, undefined);
_ ->
- ?CONSOLE("~ts~ts (~ts~ts source)", CommonConsoleArgs ++ [type(Source)])
+ rebar_app_utils:expand_deps_sources(ParsedDep, State)
end.
-type(Source) when is_tuple(Source) -> element(1, Source).
+
+locked_deps_map(State, Profile) ->
+ ParsedDeps = rebar_state:get(State, {parsed_deps, Profile}, []),
+ lists:foldl(fun(Dep, DepsIn) ->
+ case rebar_app_info:is_lock(Dep) of
+ true ->
+ DepName = rebar_app_info:name(Dep),
+ DepsIn#{rebar_utils:to_binary(DepName) => Dep};
+ _ ->
+ DepsIn
+ end
+ end, #{}, ParsedDeps).
+
+
+display_dep(State, Dep, LockedDeps) ->
+ Name = rebar_utils:to_binary(rebar_app_info:name(Dep)),
+ NeedsUpdate = rebar_fetch:needs_update(Dep, State),
+ Source = rebar_app_info:source(Dep),
+ LockedSource = case maps:get(Name, LockedDeps, undefined) of
+ undefined -> undefined;
+ LockedDep -> rebar_app_info:source(LockedDep)
+ end,
+
+ display_dep_line(Name, NeedsUpdate, source_text(LockedSource), source_text(Source)).
+
+
+% Dep is a checkout
+display_dep_line(Name, _NeedsUpdate, _LockedSource, Source = checkout) ->
+ ?CONSOLE("~ts* (~ts)", [Name, Source]);
+
+% Dep exists only in lock file
+display_dep_line(Name, _NeedsUpdate, LockedSource, _Source = undefined) ->
+ ?CONSOLE("~ts* (locked ~ts <> none)", [Name, LockedSource]);
+
+% Dep not locked, report whether the disk copy matches the Source
+display_dep_line(Name, true, undefined, Source) ->
+ ?CONSOLE("~ts* (~ts)", [Name, Source]);
+display_dep_line(Name, _, undefined, Source) ->
+ ?CONSOLE("~ts (~ts)", [Name, Source]);
+
+% Dep locked, install_deps provider should have had updated the disk copy with
+% the locked version
+display_dep_line(Name, false, _LockedSource, Source) ->
+ % dep locked and no need to update (LockedSource and Source might not match
+ % because of one using {ref, X} and the other {tag, Y})
+ ?CONSOLE("~ts (locked ~ts)", [Name, Source]);
+display_dep_line(Name, _NeedsUpdate, LockedSource, Source) ->
+ % dep locked with mismatching lock and config files
+ ?CONSOLE("~ts* (locked ~ts <> ~ts)", [Name, LockedSource, Source]).
+
+
+source_text(Source) when is_list(Source); is_atom(Source) ->
+ Source;
+source_text({pkg, _Name, Vsn, _Hash, _RepoConfig}) ->
+ source_text({pkg, _Name, Vsn, _Hash});
+source_text({pkg, _Name, Vsn, _Hash}) ->
+ [<<"package">>, " ", rebar_utils:to_binary(Vsn)];
+source_text(Source) when is_tuple(Source), tuple_size(Source) < 3 ->
+ element(1, Source);
+source_text(Source) when is_tuple(Source) ->
+ Type = element(1, Source),
+ case element(3, Source) of
+ {ref , Ref} ->
+ SmallRef = case rebar_utils:to_binary(Ref) of
+ <<R:7/binary, _/binary>> -> <<R/binary, "...">>;
+ R -> R
+ end,
+ [atom_to_binary(Type, unicode), " source ", SmallRef];
+ {_ , Vsn} ->
+ [atom_to_binary(Type, unicode), " source ", rebar_utils:to_binary(Vsn)];
+ _ ->
+ [atom_to_binary(Type, unicode), " source"]
+ end.
diff --git a/test/rebar_deps_SUITE.erl b/test/rebar_deps_SUITE.erl
index f0dd28c..f9be2a3 100644
--- a/test/rebar_deps_SUITE.erl
+++ b/test/rebar_deps_SUITE.erl
@@ -256,6 +256,7 @@ mock_warnings() ->
mock_rebar_fetch() ->
meck:new(rebar_fetch, [no_link, passthrough]).
+
%%% TESTS %%%
flat(Config) -> run(Config).
pick_highest_left(Config) -> run(Config).
@@ -508,21 +509,43 @@ deps_cmd_needs_update_called(Config) ->
{ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps}])),
rebar_test_utils:run_and_check(Config, RebarConfig, ["deps"], {ok, []}),
+ [<<"b">>] = rebar_fetch_needs_update_calls_sorted(),
+
%% Add c to top level
TopDeps2 = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"c", "2.0.0", []}
,{"b", "1.0.0", []}])),
{ok, RebarConfig2} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps2}])),
rebar_test_utils:run_and_check(Config, RebarConfig2, ["deps"], {ok, []}),
- % Only top level deps are checked for updates
- UpdateCheckDeps = rebar_fetch_needs_update_calls(),
- UpdateCheckDepsNames = [rebar_app_info:name(Dep) || Dep <- UpdateCheckDeps],
- [<<"b">>, <<"b">>, <<"c">>] = lists:sort(UpdateCheckDepsNames).
+ %% Only top level deps are checked for updates
+ [<<"b">>, <<"b">>, <<"c">>] = rebar_fetch_needs_update_calls_sorted(),
+
+ %% Lock deps
+ rebar_test_utils:run_and_check(Config, RebarConfig2, ["lock"], {ok, []}),
+ NeedsUpdate1 = rebar_fetch_needs_update_calls_sorted(),
+
+ %% Switch c for a as top level deps
+ TopDeps3 = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
+ ,{"b", "1.0.0", []}])),
+
+ {ok, RebarConfig3} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps3}])),
+ LockFile = filename:join(AppDir, "rebar.lock"),
+ RebarConfig4 = rebar_config:merge_locks(RebarConfig3,
+ rebar_config:consult_lock_file(LockFile)),
+
+ rebar_test_utils:run_and_check(Config, RebarConfig4, ["deps"], {ok, []}),
+
+ NeedsUpdate2 = lists:subtract(rebar_fetch_needs_update_calls_sorted(), NeedsUpdate1),
+
+ %% B and C from lock file + install_deps and A, B and C from 'deps'
+ [<<"a">>, <<"b">>, <<"b">>, <<"c">>, <<"c">>] = NeedsUpdate2.
-rebar_fetch_needs_update_calls() ->
+rebar_fetch_needs_update_calls_sorted() ->
History = meck:history(rebar_fetch),
- [Dep || {_, {rebar_fetch, needs_update, [Dep, _]}, _} <- History].
+ DepsNames = [rebar_app_info:name(Dep)
+ || {_, {rebar_fetch, needs_update, [Dep, _]}, _} <- History],
+ lists:sort(DepsNames).
warning_calls() ->
History = meck:history(rebar_log),