diff options
author | Tristan Sloughter <t@crashfast.com> | 2016-02-21 09:47:31 -0600 |
---|---|---|
committer | Tristan Sloughter <t@crashfast.com> | 2016-02-21 09:47:31 -0600 |
commit | 862486cac743174b6a3a2ffb487dc851ea97020a (patch) | |
tree | ae01a72905fbfa81fa8fd0c4ac5bbbf4f717698c | |
parent | e3437c1dfbb170fe07793004738c29963b887466 (diff) | |
parent | caf4468f3bbbea75be35e0cf0560990b5db66e7e (diff) |
Merge pull request #1061 from ferd/future-proof-lockfiles
Make lock files future-proof
-rw-r--r-- | src/rebar_app_info.erl | 8 | ||||
-rw-r--r-- | src/rebar_config.erl | 38 | ||||
-rw-r--r-- | src/rebar_prv_lock.erl | 3 | ||||
-rw-r--r-- | src/rebar_prv_unlock.erl | 9 | ||||
-rw-r--r-- | src/rebar_state.erl | 8 | ||||
-rw-r--r-- | test/rebar_lock_SUITE.erl | 46 |
6 files changed, 95 insertions, 17 deletions
diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl index 9fee4e0..cf3b82e 100644 --- a/src/rebar_app_info.erl +++ b/src/rebar_app_info.erl @@ -165,13 +165,13 @@ update_opts(AppInfo, Opts, Config) -> deps_from_config(Dir, Config) -> case rebar_config:consult_lock_file(filename:join(Dir, ?LOCK_FILE)) of - [D] -> + [] -> + [{{deps, default}, proplists:get_value(deps, Config, [])}]; + D -> %% 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], - [{{locks, default}, D}, {{deps, default}, Deps}]; - _ -> - [{{deps, default}, proplists:get_value(deps, Config, [])}] + [{{locks, default}, D}, {{deps, default}, Deps}] end. %% @doc discover a complete version of the app info with all fields set. diff --git a/src/rebar_config.erl b/src/rebar_config.erl index 61301cb..8d7bcf4 100644 --- a/src/rebar_config.erl +++ b/src/rebar_config.erl @@ -30,6 +30,7 @@ ,consult_app_file/1 ,consult_file/1 ,consult_lock_file/1 + ,write_lock_file/2 ,verify_config_format/1 ,format_error/1 @@ -50,7 +51,40 @@ consult_app_file(File) -> consult_file_(File). consult_lock_file(File) -> - consult_file_(File). + Terms = consult_file_(File), + case Terms of + [] -> + []; + [Locks] when is_list(Locks) -> % beta lock file + Locks; + [{Vsn, Locks}|Attrs] when is_list(Locks) -> % versioned lock file + %% Make sure the warning above is to be shown whenever a version + %% newer than the current one is being used, as we can't parse + %% all the contents of the lock file properly. + ?WARN("Rebar3 detected a lock file from a newer version. " + "It will be loaded in compatibility mode, but important " + "information may be missing or lost. It is recommended to " + "upgrade Rebar3.", []), + read_attrs(Vsn, Locks, Attrs) + end. + +write_lock_file(LockFile, Locks) -> + NewLocks = write_attrs(Locks), + %% Write locks in the beta format, at least until it's been long + %% enough we can start modifying the lock format. + file:write_file(LockFile, io_lib:format("~p.~n", [NewLocks])). + +read_attrs(_Vsn, Locks, _Attrs) -> + %% Beta copy does not know how to expand attributes, but + %% is ready to support it. + Locks. + +write_attrs(Locks) -> + %% No attribute known that needs to be taken out of the structure, + %% just return terms as is. + Locks. + + consult_file(File) -> Terms = consult_file_(File), @@ -87,7 +121,7 @@ verify_config_format([Term | _]) -> merge_locks(Config, []) -> Config; %% lockfile with entries -merge_locks(Config, [Locks]) -> +merge_locks(Config, Locks) -> ConfigDeps = proplists:get_value(deps, Config, []), %% We want the top level deps only from the lock file. %% This ensures deterministic overrides for configs. diff --git a/src/rebar_prv_lock.erl b/src/rebar_prv_lock.erl index 8578979..cbe8dfe 100644 --- a/src/rebar_prv_lock.erl +++ b/src/rebar_prv_lock.erl @@ -35,8 +35,7 @@ do(State) -> OldLocks = rebar_state:get(State, {locks, default}, []), Locks = lists:keysort(1, build_locks(State)), Dir = rebar_state:dir(State), - file:write_file(filename:join(Dir, ?LOCK_FILE), - io_lib:format("~p.~n", [Locks])), + rebar_config:write_lock_file(filename:join(Dir, ?LOCK_FILE), Locks), State1 = rebar_state:set(State, {locks, default}, Locks), OldLockNames = [element(1,L) || L <- OldLocks], diff --git a/src/rebar_prv_unlock.erl b/src/rebar_prv_unlock.erl index b049c92..7ff0d89 100644 --- a/src/rebar_prv_unlock.erl +++ b/src/rebar_prv_unlock.erl @@ -46,15 +46,14 @@ do(State) -> {ok, State}; {error, Reason} -> ?PRV_ERROR({file,Reason}); - {ok, [Locks]} -> + {ok, _} -> + Locks = rebar_config:consult_lock_file(LockFile), case handle_unlocks(State, Locks, LockFile) of ok -> {ok, State}; {error, Reason} -> ?PRV_ERROR({file,Reason}) - end; - {ok, _Other} -> - ?PRV_ERROR(unknown_lock_format) + end end. -spec format_error(any()) -> iolist(). @@ -74,7 +73,7 @@ handle_unlocks(State, Locks, LockFile) -> _ when Names =:= [] -> % implicitly all locks file:delete(LockFile); NewLocks -> - file:write_file(LockFile, io_lib:format("~p.~n", [NewLocks])) + rebar_config:write_lock_file(LockFile, NewLocks) end. parse_names(Bin) -> diff --git a/src/rebar_state.erl b/src/rebar_state.erl index 0c07b2a..5ec2aef 100644 --- a/src/rebar_state.erl +++ b/src/rebar_state.erl @@ -115,13 +115,13 @@ new(ParentState, Config, Deps, Dir) -> deps_from_config(Dir, Config) -> case rebar_config:consult_lock_file(filename:join(Dir, ?LOCK_FILE)) of - [D] -> + [] -> + [{{deps, default}, proplists:get_value(deps, Config, [])}]; + D -> %% 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], - [{{locks, default}, D}, {{deps, default}, Deps}]; - _ -> - [{{deps, default}, proplists:get_value(deps, Config, [])}] + [{{locks, default}, D}, {{deps, default}, Deps}] end. base_state() -> diff --git a/test/rebar_lock_SUITE.erl b/test/rebar_lock_SUITE.erl new file mode 100644 index 0000000..00875f7 --- /dev/null +++ b/test/rebar_lock_SUITE.erl @@ -0,0 +1,46 @@ +%%% Most locking tests are implicit in other test suites handling +%%% dependencies. +%%% This suite is to test the compatibility layers between various +%%% versions of lockfiles. +-module(rebar_lock_SUITE). +-compile(export_all). +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +all() -> [current_version, future_versions_no_attrs, future_versions_attrs]. + +current_version(Config) -> + %% Current version just dumps the locks as is on disk. + LockFile = filename:join(?config(priv_dir, Config), "current_version"), + Locks = [{<<"app1">>, {git,"some_url", {ref,"some_ref"}}, 2}, + {<<"app2">>, {git,"some_url", {ref,"some_ref"}}, 0}, + {<<"app3">>, {hg,"some_url", {ref,"some_ref"}}, 1}, + {<<"pkg1">>,{pkg,<<"name">>,<<"0.1.6">>},3}], + file:write_file(LockFile, io_lib:format("~p.~n", [Locks])), + ?assertEqual(Locks, rebar_config:consult_lock_file(LockFile)). + +future_versions_no_attrs(Config) -> + %% Future versions will keep the same core attribute in there, but + %% will do so under a new format bundled with a version and potentially + %% some trailing attributes + LockFile = filename:join(?config(priv_dir, Config), "future_versions"), + Locks = [{<<"app1">>, {git,"some_url", {ref,"some_ref"}}, 2}, + {<<"app2">>, {git,"some_url", {ref,"some_ref"}}, 0}, + {<<"app3">>, {hg,"some_url", {ref,"some_ref"}}, 1}, + {<<"pkg1">>,{pkg,<<"name">>,<<"0.1.6">>},3}], + LockData = {"3.5.2", Locks}, + file:write_file(LockFile, io_lib:format("~p.~n", [LockData])), + ?assertEqual(Locks, rebar_config:consult_lock_file(LockFile)). + +future_versions_attrs(Config) -> + %% Future versions will keep the same core attribute in there, but + %% will do so under a new format bundled with a version and potentially + %% some trailing attributes + LockFile = filename:join(?config(priv_dir, Config), "future_versions"), + Locks = [{<<"app1">>, {git,"some_url", {ref,"some_ref"}}, 2}, + {<<"app2">>, {git,"some_url", {ref,"some_ref"}}, 0}, + {<<"app3">>, {hg,"some_url", {ref,"some_ref"}}, 1}, + {<<"pkg1">>,{pkg,<<"name">>,<<"0.1.6">>},3}], + LockData = {"3.5.2", Locks}, + file:write_file(LockFile, io_lib:format("~p.~na.~n{b,c}.~n[d,e,f].~n", [LockData])), + ?assertEqual(Locks, rebar_config:consult_lock_file(LockFile)). |