summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--priv/shell-completion/bash/rebar31
-rw-r--r--priv/shell-completion/zsh/_rebar312
-rw-r--r--src/rebar_app_info.erl41
-rw-r--r--src/rebar_prv_deps.erl2
-rw-r--r--src/rebar_prv_install_deps.erl95
-rw-r--r--test/rebar_test_utils.erl24
-rw-r--r--test/rebar_upgrade_SUITE.erl84
8 files changed, 188 insertions, 73 deletions
diff --git a/README.md b/README.md
index 659ceff..ed5d5c8 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ rebar
rebar [3.0](#30) is an Erlang build tool that makes it easy to compile and test Erlang
applications, port drivers and releases.
-[![Build Status](https://travis-ci.org/rebar/rebar3.svg?branch=master)](https://travis-ci.org/rebar/rebar3)
+[![Build Status](https://travis-ci.org/rebar/rebar3.svg?branch=master)](https://travis-ci.org/rebar/rebar3) [![Windows build status](https://ci.appveyor.com/api/projects/status/yx4oitd9pvd2kab3?svg=true)](https://ci.appveyor.com/project/TristanSloughter/rebar3)
rebar is a self-contained Erlang script, so it's easy to distribute or even
embed directly in a project. Where possible, rebar uses standard Erlang/OTP
diff --git a/priv/shell-completion/bash/rebar3 b/priv/shell-completion/bash/rebar3
index cb6f69d..b6d3de2 100644
--- a/priv/shell-completion/bash/rebar3
+++ b/priv/shell-completion/bash/rebar3
@@ -27,6 +27,7 @@ _rebar3()
report \
shell \
tar \
+ unlock \
update \
upgrade \
version \
diff --git a/priv/shell-completion/zsh/_rebar3 b/priv/shell-completion/zsh/_rebar3
index 6950688..5fcdd91 100644
--- a/priv/shell-completion/zsh/_rebar3
+++ b/priv/shell-completion/zsh/_rebar3
@@ -72,6 +72,9 @@ _rebar3 () {
'(-v --verbose)'{-v,--verbose}'[Print coverage analysis]' \
&& ret=0
;;
+ (deps)
+ _message 'no more arguments' && ret=0
+ ;;
(dialyzer)
_arguments \
'(-u --update-plt)'{-u, --update-plt}'[Enable updating the PLT.]' \
@@ -100,7 +103,7 @@ _rebar3 () {
;;
(new)
_arguments \
- '1:type:(app lib release plugin)' \
+ '1:type:(app cmake escript lib plugin release)' \
'2:name:' \
'(-f --force)'{-f,--force}'[ overwrite existing files]' \
&& ret=0
@@ -160,6 +163,11 @@ _rebar3 () {
'(-r --root)'{-r,--root}'[The project root directory]:system libs:_files -/' \
&& ret=0
;;
+ (unlock)
+ _arguments \
+ '*: :_rebar3_list_deps' \
+ && ret=0
+ ;;
(update)
_message 'rebar update' && ret=0
;;
@@ -185,6 +193,7 @@ _rebar3_tasks() {
'compile:Compile apps .app.src and .erl files.'
'cover:Perform coverage analysis.'
'ct:Run Common Tests.'
+ 'deps:List dependencies.'
'dialyzer:Run the Dialyzer analyzer on the project.'
'do:Higher order provider for running multiple tasks in a sequence.'
'edoc:Generate documentation using edoc.'
@@ -197,6 +206,7 @@ _rebar3_tasks() {
'report:Provide a crash report to be sent to the rebar3 issues page.'
'shell:Run shell with project apps and deps in path.'
'tar:Tar archive of release built of project.'
+ 'unlock:Unlock dependencies..'
'update:Update package index.'
'upgrade:Upgrade dependencies.'
'version:Print version for rebar and current Erlang.'
diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl
index 91640f2..247e5f4 100644
--- a/src/rebar_app_info.erl
+++ b/src/rebar_app_info.erl
@@ -34,6 +34,8 @@
source/2,
state/1,
state/2,
+ is_lock/1,
+ is_lock/2,
is_checkout/1,
is_checkout/2,
valid/1,
@@ -41,22 +43,23 @@
-export_type([t/0]).
--record(app_info_t, {name :: binary(),
- app_file_src :: file:filename_all() | undefined,
- app_file :: file:filename_all() | undefined,
- config :: rebar_state:t() | undefined,
- original_vsn :: binary() | string() | undefined,
- app_details=[] :: list(),
- applications=[] :: list(),
- deps=[] :: list(),
+-record(app_info_t, {name :: binary(),
+ app_file_src :: file:filename_all() | undefined,
+ app_file :: file:filename_all() | undefined,
+ config :: rebar_state:t() | undefined,
+ original_vsn :: binary() | string() | undefined,
+ app_details=[] :: list(),
+ applications=[] :: list(),
+ deps=[] :: list(),
profiles=[default] :: [atom()],
- dep_level=0 :: integer(),
- dir :: file:name(),
- out_dir :: file:name(),
- source :: string() | tuple() | undefined,
- state :: rebar_state:t() | undefined,
- is_checkout=false :: boolean(),
- valid :: boolean()}).
+ dep_level=0 :: integer(),
+ dir :: file:name(),
+ out_dir :: file:name(),
+ source :: string() | tuple() | undefined,
+ state :: rebar_state:t() | undefined,
+ is_lock=false :: boolean(),
+ is_checkout=false :: boolean(),
+ valid :: boolean()}).
%%============================================================================
%% types
@@ -254,6 +257,14 @@ state(AppInfo=#app_info_t{}, State) ->
state(#app_info_t{state=State}) ->
State.
+-spec is_lock(t(), boolean()) -> t().
+is_lock(AppInfo=#app_info_t{}, IsLock) ->
+ AppInfo#app_info_t{is_lock=IsLock}.
+
+-spec is_lock(t()) -> boolean().
+is_lock(#app_info_t{is_lock=IsLock}) ->
+ IsLock.
+
-spec is_checkout(t(), boolean()) -> t().
is_checkout(AppInfo=#app_info_t{}, IsCheckout) ->
AppInfo#app_info_t{is_checkout=IsCheckout}.
diff --git a/src/rebar_prv_deps.erl b/src/rebar_prv_deps.erl
index be81c31..5e3b1c5 100644
--- a/src/rebar_prv_deps.erl
+++ b/src/rebar_prv_deps.erl
@@ -18,7 +18,7 @@ init(State) ->
providers:create([
{name, ?PROVIDER},
{module, ?MODULE},
- {bare, true},
+ {bare, false},
{deps, ?DEPS},
{example, "rebar3 deps"},
{short_desc, "List dependencies"},
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl
index 2d69aa9..cdc008c 100644
--- a/src/rebar_prv_install_deps.erl
+++ b/src/rebar_prv_install_deps.erl
@@ -202,20 +202,25 @@ update_pkg_deps(Profile, Packages, PkgDeps, Graph, Upgrade, Seen, State, Locks)
update_pkg_deps(Profile, S, Packages, Upgrade, Seen, State, Locks)
end.
+pkg_locked({Name, _, _}, Locks) ->
+ pkg_locked(Name, Locks);
pkg_locked({Name, _}, Locks) ->
+ pkg_locked(Name, Locks);
+pkg_locked(Name, Locks) ->
false =/= lists:keyfind(Name, 1, Locks).
-update_pkg_deps(Profile, Pkgs, Packages, Upgrade, Seen, State, _Locks) ->
+update_pkg_deps(Profile, Pkgs, Packages, Upgrade, Seen, State, Locks) ->
%% Create app_info record for each pkg dep
DepsDir = profile_dep_dir(State, Profile),
{Solved, _, State1}
= lists:foldl(fun(Pkg, {Acc, SeenAcc, StateAcc}) ->
- handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Acc, SeenAcc, StateAcc)
+ handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Acc, SeenAcc, Locks, StateAcc)
end, {[], Seen, State}, Pkgs),
{Solved, State1}.
-handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Fetched, Seen, State) ->
- AppInfo = package_to_app(DepsDir, Packages, Pkg, State),
+handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Fetched, Seen, Locks, State) ->
+ IsLock = pkg_locked(Pkg, Locks),
+ AppInfo = package_to_app(DepsDir, Packages, Pkg, IsLock, State),
Level = rebar_app_info:dep_level(AppInfo),
{NewSeen, NewState} = maybe_lock(Profile, AppInfo, Seen, State, Level),
{_, AppInfo1} = maybe_fetch(AppInfo, Profile, Upgrade, Seen, NewState),
@@ -247,7 +252,7 @@ maybe_lock(Profile, AppInfo, Seen, State, Level) ->
{Seen, State}
end.
-package_to_app(DepsDir, Packages, {Name, Vsn, Level}, State) ->
+package_to_app(DepsDir, Packages, {Name, Vsn, Level}, IsLock, State) ->
case dict:find({Name, Vsn}, Packages) of
error ->
case rebar_packages:check_registry(Name, Vsn, State) of
@@ -263,7 +268,8 @@ package_to_app(DepsDir, Packages, {Name, Vsn, Level}, State) ->
AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps),
AppInfo2 = rebar_app_info:dir(AppInfo1, filename:join([DepsDir, Name])),
AppInfo3 = rebar_app_info:dep_level(AppInfo2, Level),
- rebar_app_info:source(AppInfo3, {pkg, Name, Vsn})
+ AppInfo4 = rebar_app_info:is_lock(AppInfo3, IsLock),
+ rebar_app_info:source(AppInfo4, {pkg, Name, Vsn})
end.
-spec update_src_deps(atom(), non_neg_integer(), list(), list(), list(), rebar_state:t(), boolean(), sets:set(binary()), list()) -> {rebar_state:t(), list(), list(), sets:set(binary())}.
@@ -385,10 +391,10 @@ handle_dep(State, DepsDir, AppInfo, Locks, Level) ->
NewLocks = [{DepName, Source, LockLevel+Level} ||
{DepName, Source, LockLevel} <- rebar_state:get(S3, {locks, default}, [])],
AppInfo2 = rebar_app_info:deps(AppInfo1, rebar_state:deps_names(Deps)),
- {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, S3, Locks, Level),
+ {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, S3, Locks, Level+1),
{AppInfo2, SrcDeps, PkgDeps, Locks++NewLocks, State1}.
--spec maybe_fetch(rebar_app_info:t(), atom(), boolean() | {true, binary(), integer()},
+-spec maybe_fetch(rebar_app_info:t(), atom(), boolean(),
sets:set(binary()), rebar_state:t()) -> {boolean(), rebar_app_info:t()}.
maybe_fetch(AppInfo, Profile, Upgrade, Seen, State) ->
AppDir = ec_cnv:to_list(rebar_app_info:dir(AppInfo)),
@@ -476,69 +482,69 @@ parse_deps(DepsDir, Deps, State, Locks, Level) ->
end,
case lists:keyfind(ec_cnv:to_binary(Name), 1, Locks) of
false ->
- parse_dep(Dep, Acc, DepsDir, State);
+ parse_dep(Dep, Acc, DepsDir, false, State);
LockedDep ->
LockedLevel = element(3, LockedDep),
case LockedLevel > Level of
true ->
- parse_dep(Dep, Acc, DepsDir, State);
+ parse_dep(Dep, Acc, DepsDir, false, State);
false ->
- parse_dep(LockedDep, Acc, DepsDir, State)
+ parse_dep(LockedDep, Acc, DepsDir, true, State)
end
end
end, {[], []}, Deps).
-parse_dep({Name, Vsn}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_list(Vsn) ->
+parse_dep({Name, Vsn}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_list(Vsn) ->
CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
case rebar_app_info:discover(CheckoutsDir) of
{ok, _App} ->
- Dep = new_dep(DepsDir, Name, [], [], State),
+ Dep = new_dep(DepsDir, Name, [], [], IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
not_found ->
{SrcDepsAcc, [parse_goal(ec_cnv:to_binary(Name)
,ec_cnv:to_binary(Vsn)) | PkgDepsAcc]}
end;
-parse_dep(Name, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_atom(Name) ->
+parse_dep(Name, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_atom(Name) ->
{PkgName, PkgVsn} = get_package(ec_cnv:to_binary(Name), State),
CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
case rebar_app_info:discover(CheckoutsDir) of
{ok, _App} ->
- Dep = new_dep(DepsDir, Name, [], [], State),
+ Dep = new_dep(DepsDir, Name, [], [], IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
not_found ->
{SrcDepsAcc, [{PkgName, PkgVsn} | PkgDepsAcc]}
end;
-parse_dep({Name, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) ->
- Dep = new_dep(DepsDir, Name, [], Source, State),
+parse_dep({Name, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_tuple(Source) ->
+ Dep = new_dep(DepsDir, Name, [], Source, IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
-parse_dep({Name, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) ->
- Dep = new_dep(DepsDir, Name, [], Source, State),
+parse_dep({Name, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_tuple(Source) ->
+ Dep = new_dep(DepsDir, Name, [], Source, IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
-parse_dep({Name, _Vsn, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) ->
- Dep = new_dep(DepsDir, Name, [], Source, State),
+parse_dep({Name, _Vsn, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_tuple(Source) ->
+ Dep = new_dep(DepsDir, Name, [], Source, IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
-parse_dep({Name, _Vsn, Source, Opts}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) ->
+parse_dep({Name, _Vsn, Source, Opts}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_tuple(Source) ->
?WARN("Dependency option list ~p in ~p is not supported and will be ignored", [Opts, Name]),
- Dep = new_dep(DepsDir, Name, [], Source, State),
+ Dep = new_dep(DepsDir, Name, [], Source, IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
-parse_dep({_Name, {pkg, Name, Vsn}, Level}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_integer(Level) ->
+parse_dep({_Name, {pkg, Name, Vsn}, Level}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_integer(Level) ->
CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
case rebar_app_info:discover(CheckoutsDir) of
{ok, _App} ->
- Dep = new_dep(DepsDir, Name, [], [], State),
+ Dep = new_dep(DepsDir, Name, [], [], IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
not_found ->
{SrcDepsAcc, [{Name, Vsn} | PkgDepsAcc]}
end;
-parse_dep({Name, Source, Level}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source)
+parse_dep({Name, Source, Level}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_tuple(Source)
, is_integer(Level) ->
- Dep = new_dep(DepsDir, Name, [], Source, State),
+ Dep = new_dep(DepsDir, Name, [], Source, IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
-parse_dep(Dep, _, _, _) ->
+parse_dep(Dep, _, _, _, _) ->
throw(?PRV_ERROR({parse_dep, Dep})).
-new_dep(DepsDir, Name, Vsn, Source, State) ->
+new_dep(DepsDir, Name, Vsn, Source, IsLock, State) ->
CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
{ok, Dep} = case rebar_app_info:discover(CheckoutsDir) of
{ok, App} ->
@@ -559,7 +565,7 @@ new_dep(DepsDir, Name, Vsn, Source, State) ->
ParentOverrides = rebar_state:overrides(State),
Dep1 = rebar_app_info:state(Dep,
rebar_state:overrides(S, ParentOverrides++Overrides)),
- rebar_app_info:source(Dep1, Source).
+ rebar_app_info:is_lock(rebar_app_info:source(Dep1, Source), IsLock).
fetch_app(AppInfo, AppDir, State) ->
?INFO("Fetching ~s (~p)", [rebar_app_info:name(AppInfo), rebar_app_info:source(AppInfo)]),
@@ -580,22 +586,29 @@ update_app_info(AppInfo) ->
IncludedApplications++Applications),
rebar_app_info:valid(AppInfo1, false).
-maybe_upgrade(AppInfo, AppDir, false, State) ->
+maybe_upgrade(AppInfo, AppDir, Upgrade, State) ->
Source = rebar_app_info:source(AppInfo),
- rebar_fetch:needs_update(AppDir, Source, State);
-maybe_upgrade(AppInfo, AppDir, true, State) ->
- Source = rebar_app_info:source(AppInfo),
- case rebar_fetch:needs_update(AppDir, Source, State) of
+ case Upgrade orelse rebar_app_info:is_lock(AppInfo) of
true ->
- ?INFO("Upgrading ~s", [rebar_app_info:name(AppInfo)]),
- case rebar_fetch:download_source(AppDir, Source, State) of
+ case rebar_fetch:needs_update(AppDir, Source, State) of
true ->
- true;
- Error ->
- throw(Error)
+ ?INFO("Upgrading ~s", [rebar_app_info:name(AppInfo)]),
+ case rebar_fetch:download_source(AppDir, Source, State) of
+ true ->
+ true;
+ Error ->
+ throw(Error)
+ end;
+ false ->
+ case Upgrade of
+ true ->
+ ?INFO("No upgrade needed for ~s", [rebar_app_info:name(AppInfo)]),
+ false;
+ false ->
+ false
+ end
end;
false ->
- ?INFO("No upgrade needed for ~s", [rebar_app_info:name(AppInfo)]),
false
end.
diff --git a/test/rebar_test_utils.erl b/test/rebar_test_utils.erl
index c4dc663..68e0603 100644
--- a/test/rebar_test_utils.erl
+++ b/test/rebar_test_utils.erl
@@ -182,7 +182,7 @@ check_results(AppDir, Expected) ->
lists:foreach(
fun({app, Name}) ->
- ct:pal("Name: ~p", [Name]),
+ ct:pal("App Name: ~p", [Name]),
case lists:keyfind(Name, 1, DepsNames) of
false ->
error({app_not_found, Name});
@@ -190,7 +190,7 @@ check_results(AppDir, Expected) ->
ok
end
; ({app, Name, invalid}) ->
- ct:pal("Name: ~p", [Name]),
+ ct:pal("Invalid Name: ~p", [Name]),
case lists:keyfind(Name, 1, InvalidDepsNames) of
false ->
error({app_not_found, Name});
@@ -198,7 +198,7 @@ check_results(AppDir, Expected) ->
ok
end
; ({app, Name, valid}) ->
- ct:pal("Name: ~p", [Name]),
+ ct:pal("Valid Name: ~p", [Name]),
case lists:keyfind(Name, 1, ValidDepsNames) of
false ->
error({app_not_found, Name});
@@ -206,13 +206,13 @@ check_results(AppDir, Expected) ->
ok
end
; ({checkout, Name}) ->
- ct:pal("Name: ~p", [Name]),
+ ct:pal("Checkout Name: ~p", [Name]),
?assertNotEqual(false, lists:keyfind(Name, 1, CheckoutsNames))
; ({dep, Name}) ->
- ct:pal("Name: ~p", [Name]),
+ ct:pal("Dep Name: ~p", [Name]),
?assertNotEqual(false, lists:keyfind(Name, 1, DepsNames))
; ({dep, Name, Vsn}) ->
- ct:pal("Name: ~p, Vsn: ~p", [Name, Vsn]),
+ ct:pal("Dep Name: ~p, Vsn: ~p", [Name, Vsn]),
case lists:keyfind(Name, 1, DepsNames) of
false ->
error({dep_not_found, Name});
@@ -221,10 +221,10 @@ check_results(AppDir, Expected) ->
iolist_to_binary(rebar_app_info:original_vsn(App)))
end
; ({plugin, Name}) ->
- ct:pal("Name: ~p", [Name]),
+ ct:pal("Plugin Name: ~p", [Name]),
?assertNotEqual(false, lists:keyfind(Name, 1, PluginsNames))
; ({plugin, Name, Vsn}) ->
- ct:pal("Name: ~p, Vsn: ~p", [Name, Vsn]),
+ ct:pal("Plugin Name: ~p, Vsn: ~p", [Name, Vsn]),
case lists:keyfind(Name, 1, PluginsNames) of
false ->
error({plugin_not_found, Name});
@@ -233,10 +233,10 @@ check_results(AppDir, Expected) ->
iolist_to_binary(rebar_app_info:original_vsn(App)))
end
; ({global_plugin, Name}) ->
- ct:pal("Name: ~p", [Name]),
+ ct:pal("Global Plugin Name: ~p", [Name]),
?assertNotEqual(false, lists:keyfind(Name, 1, GlobalPluginsNames))
; ({global_plugin, Name, Vsn}) ->
- ct:pal("Name: ~p, Vsn: ~p", [Name, Vsn]),
+ ct:pal("Global Plugin Name: ~p, Vsn: ~p", [Name, Vsn]),
case lists:keyfind(Name, 1, GlobalPluginsNames) of
false ->
error({global_plugin_not_found, Name});
@@ -245,10 +245,10 @@ check_results(AppDir, Expected) ->
iolist_to_binary(rebar_app_info:original_vsn(App)))
end
; ({lock, Name}) ->
- ct:pal("Name: ~p", [Name]),
+ ct:pal("Lock Name: ~p", [Name]),
?assertNotEqual(false, lists:keyfind(iolist_to_binary(Name), 1, Locks))
; ({lock, Name, Vsn}) ->
- ct:pal("Name: ~p, Vsn: ~p", [Name, Vsn]),
+ ct:pal("Lock Name: ~p, Vsn: ~p", [Name, Vsn]),
case lists:keyfind(iolist_to_binary(Name), 1, Locks) of
false ->
error({lock_not_found, Name});
diff --git a/test/rebar_upgrade_SUITE.erl b/test/rebar_upgrade_SUITE.erl
index 1dc0af2..793f10a 100644
--- a/test/rebar_upgrade_SUITE.erl
+++ b/test/rebar_upgrade_SUITE.erl
@@ -10,7 +10,7 @@ groups() ->
pair_a, pair_b, pair_ab, pair_c, pair_all,
triplet_a, triplet_b, triplet_c,
tree_a, tree_b, tree_c, tree_c2, tree_ac, tree_all,
- delete_d, promote]},
+ delete_d, promote, stable_lock, fwd_lock]},
{git, [], [{group, all}]},
{pkg, [], [{group, all}]}].
@@ -361,7 +361,30 @@ upgrades(promote) ->
{"C", "3", []}
],
["A","B","C","D"],
- {"C", [{"A","1"},{"C","3"},{"B","1"},{"D","1"}]}}.
+ {"C", [{"A","1"},{"C","3"},{"B","1"},{"D","1"}]}};
+upgrades(stable_lock) ->
+ {[{"A", "1", [{"C", "1", []}]},
+ {"B", "1", [{"D", "1", []}]}
+ ], % lock after this
+ [{"A", "2", [{"C", "2", []}]},
+ {"B", "2", [{"D", "2", []}]}
+ ],
+ [],
+ %% Run a regular lock and no app should be upgraded
+ {"any", [{"A","1"},{"C","1"},{"B","1"},{"D","1"}]}};
+upgrades(fwd_lock) ->
+ {[{"A", "1", [{"C", "1", []}]},
+ {"B", "1", [{"D", "1", []}]}
+ ],
+ [{"A", "2", [{"C", "2", []}]},
+ {"B", "2", [{"D", "2", []}]}
+ ],
+ ["A","B","C","D"],
+ %% For this one, we should build, rewrite the lock
+ %% file to include the result post-upgrade, and then
+ %% run a regular lock to see that the lock file is respected
+ %% in deps.
+ {"any", [{"A","2"},{"C","2"},{"B","2"},{"D","2"}]}}.
%% TODO: add a test that verifies that unlocking files and then
%% running the upgrade code is enough to properly upgrade things.
@@ -435,6 +458,46 @@ delete_d(Config) ->
?assertNotEqual([],
[1 || {"App ~ts is no longer needed and can be deleted.",
[<<"D">>]} <- Infos]).
+
+stable_lock(Config) ->
+ apply(?config(mock, Config), []),
+ {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
+ %% Install dependencies before re-mocking for an upgrade
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["lock"], {ok, []}),
+ {App, Unlocks} = ?config(expected, Config),
+ ct:pal("Upgrades: ~p -> ~p", [App, Unlocks]),
+ Expectation = case Unlocks of
+ {error, Term} -> {error, Term};
+ _ -> {ok, Unlocks}
+ end,
+ apply(?config(mock_update, Config), []),
+ NewRebarConf = rebar_test_utils:create_config(?config(apps, Config),
+ [{deps, ?config(next_top_deps, Config)}]),
+ {ok, NewRebarConfig} = file:consult(NewRebarConf),
+ rebar_test_utils:run_and_check(
+ Config, NewRebarConfig, ["lock", App], Expectation
+ ).
+
+fwd_lock(Config) ->
+ apply(?config(mock, Config), []),
+ {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
+ %% Install dependencies before re-mocking for an upgrade
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["lock"], {ok, []}),
+ {App, Unlocks} = ?config(expected, Config),
+ ct:pal("Upgrades: ~p -> ~p", [App, Unlocks]),
+ Expectation = case Unlocks of
+ {error, Term} -> {error, Term};
+ _ -> {ok, Unlocks}
+ end,
+ rewrite_locks(Expectation, Config),
+ apply(?config(mock_update, Config), []),
+ NewRebarConf = rebar_test_utils:create_config(?config(apps, Config),
+ [{deps, ?config(next_top_deps, Config)}]),
+ {ok, NewRebarConfig} = file:consult(NewRebarConf),
+ rebar_test_utils:run_and_check(
+ Config, NewRebarConfig, ["lock", App], Expectation
+ ).
+
run(Config) ->
apply(?config(mock, Config), []),
{ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
@@ -453,3 +516,20 @@ run(Config) ->
rebar_test_utils:run_and_check(
Config, NewRebarConfig, ["upgrade", App], Expectation
).
+
+rewrite_locks({ok, Expectations}, Config) ->
+ AppDir = ?config(apps, Config),
+ LockFile = filename:join([AppDir, "rebar.lock"]),
+ {ok, [Locks]} = file:consult(LockFile),
+ ExpLocks = [{list_to_binary(Name), Vsn}
+ || {lock, Name, Vsn} <- Expectations],
+ NewLocks = lists:foldl(
+ fun({App, {pkg, Name, _}, Lvl}, Acc) ->
+ Vsn = list_to_binary(proplists:get_value(App,ExpLocks)),
+ [{App, {pkg, Name, Vsn}, Lvl} | Acc]
+ ; ({App, {git, URL, {ref, _}}, Lvl}, Acc) ->
+ Vsn = proplists:get_value(App,ExpLocks),
+ [{App, {git, URL, {ref, Vsn}}, Lvl} | Acc]
+ end, [], Locks),
+ ct:pal("rewriting locks from ~p to~n~p", [Locks, NewLocks]),
+ file:write_file(LockFile, io_lib:format("~p.~n", [NewLocks])).