diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/rebar_prv_install_deps.erl | 2 | ||||
-rw-r--r-- | src/rebar_prv_lock.erl | 2 | ||||
-rw-r--r-- | src/rebar_prv_upgrade.erl | 48 | ||||
-rw-r--r-- | src/rebar_state.erl | 8 |
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]}. |