summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rebar_prv_install_deps.erl2
-rw-r--r--src/rebar_prv_lock.erl2
-rw-r--r--src/rebar_prv_upgrade.erl48
-rw-r--r--src/rebar_state.erl8
4 files changed, 42 insertions, 18 deletions
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl
index 025d32a..49aa65c 100644
--- a/src/rebar_prv_install_deps.erl
+++ b/src/rebar_prv_install_deps.erl
@@ -287,7 +287,7 @@ update_src_deps(Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Update, Seen,
handle_update(AppInfo, UpdateName, UpdateLevel, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) ->
Name = rebar_app_info:name(AppInfo),
- {_, _, _, DepLevel} = lists:keyfind(Name, 1, Locks),
+ {_, _, DepLevel} = lists:keyfind(Name, 1, Locks),
case UpdateLevel < DepLevel
orelse Name =:= UpdateName of
true ->
diff --git a/src/rebar_prv_lock.erl b/src/rebar_prv_lock.erl
index 2f26a7f..8a69434 100644
--- a/src/rebar_prv_lock.erl
+++ b/src/rebar_prv_lock.erl
@@ -41,7 +41,7 @@ do(State) ->
,rebar_app_info:dep_level(Dep)}
end, AllDeps),
Dir = rebar_state:dir(State),
- file:write_file(filename:join(Dir, "rebar.lock"), io_lib:format("~p.~n", [Locks])),
+ file:write_file(filename:join(Dir, ?LOCK_FILE), io_lib:format("~p.~n", [Locks])),
{ok, State}.
-spec format_error(any()) -> iolist().
diff --git a/src/rebar_prv_upgrade.erl b/src/rebar_prv_upgrade.erl
index c0a56c3..4609f57 100644
--- a/src/rebar_prv_upgrade.erl
+++ b/src/rebar_prv_upgrade.erl
@@ -12,7 +12,10 @@
-include("rebar.hrl").
-define(PROVIDER, upgrade).
--define(DEPS, []).
+-define(DEPS, [lock]).
+%% Also only upgrade top-level (0) deps. Transitive deps shouldn't be
+%% upgradable -- if the user wants this, they should declare it at the
+%% top level and then upgrade.
%% ===================================================================
%% Public API
@@ -38,19 +41,36 @@ init(State) ->
do(State) ->
{Args, _} = rebar_state:command_parsed_args(State),
Name = ec_cnv:to_binary(proplists:get_value(package, Args)),
- Locks = rebar_state:get(State, locks, []),
- case lists:keyfind(Name, 1, Locks) of
- {_, _, _, Level} ->
- Deps = rebar_state:get(State, deps),
- case lists:keyfind(binary_to_atom(Name, utf8), 1, Deps) of
- false ->
- {error, io_lib:format("No such dependency ~s~n", [Name])};
- Dep ->
- rebar_prv_install_deps:handle_deps(State, [Dep], {true, Name, Level}),
- {ok, State}
- end;
- _ ->
- {error, io_lib:format("No such dependency ~s~n", [Name])}
+ Locks = rebar_state:lock(State),
+ %% TODO: optimize by running the find + unlock in one sweep
+ case find_app(Name, Locks) of
+ {AppInfo, 0} ->
+ %% Unlock the app and all those with a lock level higher than
+ %% it has
+ NewLocks = unlock_higher_than(0, Locks -- [AppInfo]),
+ {ok, rebar_state:lock(State, NewLocks)};
+ {_AppInfo, Level} when Level > 0 ->
+ {error, transitive_dependency};
+ false ->
+ {error, unknown_dependency}
+ end.
+
+find_app(_Name, []) -> false;
+find_app(Name, [App|Apps]) ->
+ case rebar_app_info:name(App) of
+ Name -> {App, rebar_app_info:dep_level(App)};
+ _ -> find_app(Name, Apps)
+ end.
+
+%% Because we operate on a lock list, removing the app from the list
+%% unlocks it.
+unlock_higher_than(_, []) -> [];
+unlock_higher_than(Level, [App | Apps]) ->
+ case rebar_app_info:dep_level(App) of
+ N when N > Level ->
+ unlock_higher_than(Level, Apps);
+ N when N =< Level ->
+ [App | unlock_higher_than(Level, Apps)]
end.
-spec format_error(any()) -> iolist().
diff --git a/src/rebar_state.erl b/src/rebar_state.erl
index 29b7c3f..70aba51 100644
--- a/src/rebar_state.erl
+++ b/src/rebar_state.erl
@@ -89,8 +89,10 @@ new(ParentState, Config, Dir) ->
Opts = ParentState#state_t.opts,
LocalOpts = case rebar_config:consult_file(filename:join(Dir, ?LOCK_FILE)) of
[D] ->
- LockedDeps = [X || X <- D, element(3, X) =:= 0],
- dict:from_list([{{locks, default}, LockedDeps}, {{deps, default}, D} | Config]);
+ %% We want the top level deps only from the lock file.
+ %% This ensures deterministic overrides for configs.
+ Deps = [X || X <- D, element(3, X) =:= 0],
+ dict:from_list([{{locks, default}, D}, {{deps, default}, Deps} | Config]);
_ ->
D = proplists:get_value(deps, Config, []),
dict:from_list([{{deps, default}, D} | Config])
@@ -133,6 +135,8 @@ current_profiles(#state_t{current_profiles=Profiles}) ->
lock(#state_t{lock=Lock}) ->
Lock.
+lock(State=#state_t{}, Apps) when is_list(Apps) ->
+ State#state_t{lock=Apps};
lock(State=#state_t{lock=Lock}, App) ->
State#state_t{lock=[App | Lock]}.