瀏覽代碼

this patch treats pkg and src deps as equals, so level decides winner

Instead fetching and resolving src deps (which could depend on pkg deps)
and then pkg deps this patch combines the two into a single set of
iterations by level. The only difference between src and pkg deps in this
new install_deps is how their deps list is found -- from the config or
lock file for src deps and from the neighbors of the vertex for pkg.
pull/732/head
Tristan Sloughter 9 年之前
父節點
當前提交
31a24ad4ff
共有 12 個文件被更改,包括 275 次插入472 次删除
  1. +9
    -9
      src/rebar_app_discover.erl
  2. +12
    -1
      src/rebar_app_info.erl
  3. +127
    -2
      src/rebar_app_utils.erl
  4. +0
    -110
      src/rebar_digraph.erl
  5. +19
    -7
      src/rebar_packages.erl
  6. +85
    -310
      src/rebar_prv_install_deps.erl
  7. +1
    -1
      src/rebar_prv_packages.erl
  8. +1
    -2
      src/rebar_prv_upgrade.erl
  9. +13
    -4
      src/rebar_state.erl
  10. +3
    -1
      test/mock_pkg_resource.erl
  11. +1
    -1
      test/rebar_deps_SUITE.erl
  12. +4
    -24
      test/rebar_install_deps_SUITE.erl

+ 9
- 9
src/rebar_app_discover.erl 查看文件

@ -96,7 +96,7 @@ merge_deps(AppInfo, State) ->
{AppInfo1, State1}.
handle_profile(Profile, Name, AppState, State) ->
{TopSrc, TopPkg} = rebar_state:get(State, {parsed_deps, Profile}, {[], []}),
TopParsedDeps = rebar_state:get(State, {parsed_deps, Profile}, {[], []}),
TopLevelProfileDeps = rebar_state:get(State, {deps, Profile}, []),
AppProfileDeps = rebar_state:get(AppState, {deps, Profile}, []),
AppProfileDeps2 = rebar_utils:tup_dedup(rebar_utils:tup_sort(AppProfileDeps)),
@ -108,18 +108,18 @@ handle_profile(Profile, Name, AppState, State) ->
%% Only deps not also specified in the top level config need
%% to be included in the parsed deps
NewDeps = ProfileDeps2 -- TopLevelProfileDeps,
{ParsedSrc, ParsedPkg} = parse_profile_deps(Profile, Name, NewDeps, AppState, State1),
rebar_state:set(State1, {parsed_deps, Profile}, {TopSrc++ParsedSrc, TopPkg++ParsedPkg}).
ParsedDeps = parse_profile_deps(Profile, Name, NewDeps, AppState, State1),
rebar_state:set(State1, {parsed_deps, Profile}, TopParsedDeps++ParsedDeps).
parse_profile_deps(Profile, Name, Deps, AppState, State) ->
DepsDir = rebar_prv_install_deps:profile_dep_dir(State, Profile),
Locks = rebar_state:get(State, {locks, Profile}, []),
rebar_prv_install_deps:parse_deps(Name
,DepsDir
,Deps
,AppState
,Locks
,1).
rebar_app_utils:parse_deps(Name
,DepsDir
,Deps
,AppState
,Locks
,1).
project_app_config(AppInfo, State) ->
C = rebar_config:consult(rebar_app_info:dir(AppInfo)),

+ 12
- 1
src/rebar_app_info.erl 查看文件

@ -34,6 +34,8 @@
dir/2,
out_dir/1,
out_dir/2,
resource_type/1,
resource_type/2,
source/1,
source/2,
state/1,
@ -64,6 +66,7 @@
dep_level=0 :: integer(),
dir :: file:name(),
out_dir :: file:name(),
resource_type :: pkg | src,
source :: string() | tuple() | undefined,
state :: rebar_state:t() | undefined,
is_lock=false :: boolean(),
@ -274,6 +277,14 @@ out_dir(AppInfo=#app_info_t{}, OutDir) ->
ebin_dir(#app_info_t{out_dir=OutDir}) ->
ec_cnv:to_list(filename:join(OutDir, "ebin")).
-spec resource_type(t(), pkg | src) -> t().
resource_type(AppInfo=#app_info_t{}, Type) ->
AppInfo#app_info_t{resource_type=Type}.
-spec resource_type(t()) -> pkg | src.
resource_type(#app_info_t{resource_type=ResourceType}) ->
ResourceType.
-spec source(t(), string() | tuple()) -> t().
source(AppInfo=#app_info_t{}, Source) ->
AppInfo#app_info_t{source=Source}.
@ -316,7 +327,7 @@ is_checkout(#app_info_t{is_checkout=IsCheckout}) ->
-spec valid(t()) -> boolean().
valid(AppInfo=#app_info_t{valid=undefined, state=State}) ->
case rebar_app_utils:validate_application_info(AppInfo)
case rebar_app_utils:validate_application_info(AppInfo) =:= true
andalso rebar_state:has_all_artifacts(State) =:= true of
true ->
true;

+ 127
- 2
src/rebar_app_utils.erl 查看文件

@ -32,6 +32,9 @@
app_src_to_app/2,
validate_application_info/1,
validate_application_info/2,
parse_deps/5,
parse_deps/6,
dep_to_app/7,
format_error/1]).
-include("rebar.hrl").
@ -87,6 +90,109 @@ validate_application_info(AppInfo, AppDetail) ->
end
end.
-spec parse_deps(binary(), list(), rebar_state:t(), list(), integer()) -> {[rebar_app_info:t()], [tuple()]}.
parse_deps(DepsDir, Deps, State, Locks, Level) ->
parse_deps(root, DepsDir, Deps, State, Locks, Level).
parse_deps(Parent, DepsDir, Deps, State, Locks, Level) ->
[parse_dep(Dep, Parent, DepsDir, State, Locks, Level) || Dep <- Deps].
parse_dep(Dep, Parent, DepsDir, State, Locks, Level) ->
Name = case Dep of
Dep when is_tuple(Dep) ->
element(1, Dep);
Dep ->
Dep
end,
case lists:keyfind(ec_cnv:to_binary(Name), 1, Locks) of
false ->
parse_dep(Parent, Dep, DepsDir, false, State);
LockedDep ->
LockedLevel = element(3, LockedDep),
case LockedLevel > Level of
true ->
parse_dep(Parent, Dep, DepsDir, false, State);
false ->
parse_dep(Parent, LockedDep, DepsDir, true, State)
end
end.
parse_dep(Parent, {Name, Vsn}, DepsDir, IsLock, State) when is_list(Vsn); is_binary(Vsn) ->
%% Versioned Package dependency
CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
case rebar_app_info:discover(CheckoutsDir) of
{ok, _App} ->
dep_to_app(root, DepsDir, Name, [], [], IsLock, State);
not_found ->
{PkgName, PkgVsn} = parse_goal(ec_cnv:to_binary(Name)
,ec_cnv:to_binary(Vsn)),
Source = {pkg, PkgName, PkgVsn},
rebar_app_info:resource_type(dep_to_app(Parent, DepsDir, PkgName, PkgVsn, Source, IsLock, State), pkg)
end;
parse_dep(Parent, Name, DepsDir, IsLock, State) when is_atom(Name); is_binary(Name) ->
%% Unversioned package dependency
{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_to_app(root, DepsDir, Name, [], [], IsLock, State);
not_found ->
Source = {pkg, PkgName, PkgVsn},
rebar_app_info:resource_type(dep_to_app(Parent, DepsDir, PkgName, PkgVsn, Source, IsLock, State), pkg)
end;
parse_dep(Parent, {Name, Source}, DepsDir, IsLock, State) when is_tuple(Source) ->
dep_to_app(Parent, DepsDir, Name, [], Source, IsLock, State);
parse_dep(Parent, {Name, _Vsn, Source}, DepsDir, IsLock, State) when is_tuple(Source) ->
dep_to_app(Parent, DepsDir, Name, [], Source, IsLock, State);
parse_dep(Parent, {Name, _Vsn, Source, Opts}, DepsDir, IsLock, State) when is_tuple(Source) ->
?WARN("Dependency option list ~p in ~p is not supported and will be ignored", [Opts, Name]),
dep_to_app(Parent, DepsDir, Name, [], Source, IsLock, State);
parse_dep(Parent, {_Name, {pkg, Name, Vsn}, Level}, 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_to_app(root, DepsDir, Name, [], [], IsLock, State);
not_found ->
Source = {pkg, Name, Vsn},
rebar_app_info:resource_type(dep_to_app(Parent, DepsDir, Name, Vsn, Source, IsLock, State), pkg)
end;
parse_dep(Parent, {Name, Source, Level}, DepsDir, IsLock, State) when is_tuple(Source)
, is_integer(Level) ->
dep_to_app(Parent, DepsDir, Name, [], Source, IsLock, State);
parse_dep(_, Dep, _, _, _) ->
throw(?PRV_ERROR({parse_dep, Dep})).
dep_to_app(Parent, DepsDir, Name, Vsn, Source, IsLock, State) ->
CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
BaseDir = rebar_state:get(State, base_dir, []),
{ok, Dep} = case rebar_app_info:discover(CheckoutsDir) of
{ok, App} ->
{ok, rebar_app_info:is_checkout(App, true)};
not_found ->
Dir = ec_cnv:to_list(filename:join(DepsDir, Name)),
case rebar_app_info:discover(Dir) of
{ok, App} ->
{ok, App};
not_found ->
rebar_app_info:new(Name, Vsn,
ec_cnv:to_list(filename:join(DepsDir, Name)))
end
end,
C = rebar_config:consult(rebar_app_info:dir(Dep)),
S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(Dep)),
Overrides = rebar_state:get(State, overrides, []),
ParentOverrides = rebar_state:overrides(State),
S1 = rebar_state:set(rebar_state:overrides(S, ParentOverrides++Overrides), base_dir, BaseDir),
Dep1 = rebar_app_info:state(Dep, S1),
AppInfo = rebar_app_info:is_lock(rebar_app_info:source(Dep1, Source), IsLock),
ResourceType = case Source of
{pkg, _, _} ->
pkg;
_ ->
src
end,
rebar_app_info:resource_type(rebar_app_info:parent(AppInfo, Parent), ResourceType).
format_error(Error) ->
io_lib:format("~p", [Error]).
@ -94,11 +200,30 @@ format_error(Error) ->
%% Internal functions
%% ===================================================================
-spec parse_goal(binary(), binary()) -> {binary(), binary()} | {binary(), binary(), binary()}.
parse_goal(Name, Constraint) ->
case re:run(Constraint, "([^\\d]*)(\\d.*)", [{capture, [1,2], binary}]) of
{match, [<<>>, Vsn]} ->
{Name, Vsn};
{match, [Op, Vsn]} ->
{Name, Vsn, binary_to_atom(Op, utf8)};
nomatch ->
throw(?PRV_ERROR({bad_constraint, Name, Constraint}))
end.
get_package(Dep, State) ->
case rebar_state:registry(State) of
{ok, T} ->
{ok, HighestDepVsn} = rebar_packages:find_highest_matching(Dep, "0", T),
{Dep, HighestDepVsn};
error ->
throw(?PRV_ERROR({load_registry_fail, Dep}))
end.
-spec has_all_beams(file:filename_all(), [module()]) ->
true | ?PRV_ERROR({missing_module, module()}).
has_all_beams(EbinDir, [Module | ModuleList]) ->
BeamFile = filename:join([EbinDir,
ec_cnv:to_list(Module) ++ ".beam"]),
BeamFile = filename:join([EbinDir, ec_cnv:to_list(Module) ++ ".beam"]),
case filelib:is_file(BeamFile) of
true ->
has_all_beams(EbinDir, ModuleList);

+ 0
- 110
src/rebar_digraph.erl 查看文件

@ -2,8 +2,6 @@
-export([compile_order/1
,restore_graph/1
,cull_deps/2
,cull_deps/3
,subgraph/2
,format_error/1]).
@ -69,17 +67,6 @@ restore_graph({Vs, Es}) ->
end, Es),
Graph.
%% Pick packages to fullfill dependencies
%% The first dep while traversing the graph is chosen and any conflicting
%% dep encountered later on is ignored.
cull_deps(Graph, Vertices) ->
cull_deps(Graph, Vertices, sets:new()).
cull_deps(Graph, Vertices, Seen) ->
Vertices1 = lists:keysort(2, Vertices),
{Solution, Levels, Discarded} = {dict:new(), dict:new(), sets:new()},
cull_deps(Graph, Vertices1, Levels, Solution, Seen, Discarded).
format_error(no_solution) ->
io_lib:format("No solution for packages found.", []).
@ -87,103 +74,6 @@ format_error(no_solution) ->
%% Internal Functions
%%====================================================================
cull_deps(_Graph, [], Levels, Solution, _, Discarded) ->
{_, Vertices} = lists:unzip(dict:to_list(Solution)),
LvlVertices = [{Profile, {Parent, App, Vsn, dict:fetch(App, Levels)}}
|| {Profile, {Parent,App,Vsn}} <- Vertices],
{ok, LvlVertices, sets:to_list(Discarded)};
cull_deps(Graph, [{Profile, Level, Vs} | Vertices], Levels, Solution, Seen, Discarded) ->
{NV, NS, LS, DS} =
lists:foldl(fun({Parent, Name, Vsn}, {Acc, SolutionAcc, LevelsAcc, DiscardedAcc}) ->
{SolutionAcc1, LevelsAcc1, DiscardedAcc1} =
maybe_add_to_solution(Profile, Level, Name, {Name, Vsn}, Parent
,SolutionAcc
,LevelsAcc, Seen, DiscardedAcc),
OutNeighbors = digraph:out_neighbours(Graph, {Name,Vsn}),
{NewVertices, DiscardedAcc2} = handle_neighbors(Profile, Level, Name
,OutNeighbors, Acc, SolutionAcc1
,Seen, DiscardedAcc1),
{NewVertices, SolutionAcc1, LevelsAcc1, DiscardedAcc2}
end, {[], Solution, Levels, Discarded}, Vs),
NewVertices = combine_profile_levels(Vertices, NV),
cull_deps(Graph, NewVertices, LS, NS, Seen, DS).
%% Combine lists of deps that have the same profile and level
combine_profile_levels(Vertices, NewVertices) ->
V = lists:foldl(fun({Profile, Level, Vs}, Acc) ->
case ec_lists:find(fun({P, L, _}) ->
P =:= Profile andalso L =:= Level
end, Acc) of
{ok, {_, _, OldVs}=Old} ->
lists:delete(Old, Acc)++[{Profile, Level, lists:keysort(1, OldVs++Vs)}];
error ->
Acc++[{Profile, Level, Vs}]
end
end, Vertices, NewVertices),
lists:keysort(2, V).
%% For each outgoing edge of a dep check if it should be added to the solution
%% and add it to the list of vertices to do the same for
handle_neighbors(Profile, Level, Parent, OutNeighbors, Vertices
,Solution, Seen, Discarded) ->
case lists:foldl(fun({Name, Vsn}=Value, {NewVertices, Discarded1}) ->
case dict:find(Name, Solution) of
{ok, {Profile, {Parent, Name, Vsn}}} -> % already seen
{NewVertices,
Discarded1};
{ok, _} -> % conflict resolution!
%% Warn on different version
{NewVertices,
sets:add_element(Value, Discarded1)};
error ->
%% We check Seen separately because we don't care
%% to warn if the exact same version of a package
%% was already part of the solution but we do
%% if it was simply seen in source deps
case sets:is_element(Name, Seen) of
true ->
{NewVertices,
sets:add_element(Value, Discarded1)};
false ->
{[{Parent, Name, Vsn} | NewVertices],
Discarded1}
end
end
end, {[], Discarded}, OutNeighbors) of
{[], DiscardedAcc2} ->
{Vertices, DiscardedAcc2};
{NewVertices1, DiscardedAcc2} ->
{Vertices++[{Profile, Level+1, NewVertices1}] ,DiscardedAcc2}
end.
maybe_add_to_solution(Profile, Level, Key, {Name, Vsn}=Value, Parent
,Solution, Levels, Seen, Discarded) ->
case dict:find(Key, Solution) of
{ok, {Profile, {Parent, Name, Vsn}}} -> % already seen
{Solution,
Levels,
Discarded};
{ok, _} -> % conflict resolution!
%% Warn on different version
{Solution,
Levels,
sets:add_element(Value, Discarded)};
error ->
%% We check Seen separately because we don't care to warn if the exact
%% same version of a package was already part of the solution but we do
%% if it was simply seen in source deps
case sets:is_element(Name, Seen) of
true ->
{Solution,
Levels,
sets:add_element(Value, Discarded)};
false ->
{dict:store(Key, {Profile, {Parent, Name, Vsn}}, Solution),
dict:store(Key, Level, Levels),
Discarded}
end
end.
subgraph(Graph, Vertices) ->
digraph_utils:subgraph(Graph, Vertices).

+ 19
- 7
src/rebar_packages.erl 查看文件

@ -1,6 +1,7 @@
-module(rebar_packages).
-export([packages/1
,packages_graph/1
,registry/1
,package_dir/1
,check_registry/3
@ -15,32 +16,43 @@
-type vsn() :: binary().
-type package() :: pkg_name() | {pkg_name(), vsn()}.
-spec packages(rebar_state:t()) -> {rebar_dict(), rebar_digraph()}.
-spec packages(rebar_state:t()) -> rebar_dict().
%% DON'T USE IT! Use rebar_state:packages(State) instead.
packages(State) ->
RegistryDir = package_dir(State),
DictFile = filename:join(RegistryDir, "dict"),
try
{ok, DictBinary} = file:read_file(DictFile),
binary_to_term(DictBinary)
catch
_:_ ->
?ERROR("Bad packages index, try to fix with `rebar3 update`", []),
dict:new()
end.
-spec packages_graph(rebar_state:t()) -> rebar_digraph().
packages_graph(State) ->
RegistryDir = package_dir(State),
Edges = filename:join(RegistryDir, "edges"),
Vertices = filename:join(RegistryDir, "vertices"),
Neighbors = filename:join(RegistryDir, "neighbors"),
case lists:all(fun(X) -> filelib:is_file(X) end, [DictFile, Edges, Vertices, Neighbors]) of
case lists:all(fun(X) -> filelib:is_file(X) end, [Edges, Vertices, Neighbors]) of
true ->
try
{ok, DictBinary} = file:read_file(DictFile),
Dict = binary_to_term(DictBinary),
{ok, EdgesTab} = ets:file2tab(Edges),
{ok, VerticesTab} = ets:file2tab(Vertices),
{ok, NeighborsTab} = ets:file2tab(Neighbors),
{Dict, {digraph, EdgesTab, VerticesTab, NeighborsTab, true}}
{digraph, EdgesTab, VerticesTab, NeighborsTab, true}
catch
_:_ ->
?ERROR("Bad packages index, try to fix with `rebar3 update`", []),
{dict:new(), digraph:new()}
digraph:new()
end;
false ->
?ERROR("Bad packages index, try to fix with `rebar3 update`", []),
{dict:new(), digraph:new()}
digraph:new()
end.
-spec registry(rebar_state:t()) -> {ok, ets:tid()} | {error, any()}.

+ 85
- 310
src/rebar_prv_install_deps.erl 查看文件

@ -36,8 +36,6 @@
-include_lib("providers/include/providers.hrl").
-export([handle_deps_as_profile/4,
parse_deps/5,
parse_deps/6,
profile_dep_dir/2,
find_cycles/1,
cull_compile/2]).
@ -125,17 +123,12 @@ handle_deps_as_profile(Profile, State, Deps, Upgrade) ->
Locks = [],
Level = 0,
DepsDir = profile_dep_dir(State, Profile),
{SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, State, Locks, Level),
AllSrcProfileDeps = [{Profile, SrcDeps, Locks, Level}],
AllPkgProfileDeps = case PkgDeps of
[] ->
[];
_ ->
[{Profile, Level, PkgDeps}]
end,
{AllApps, PkgDeps1, Seen, State1} = handle_profile_level(AllSrcProfileDeps, AllPkgProfileDeps, Locks, sets:new(), Upgrade, State),
handle_profile_pkg_level(PkgDeps1, AllApps, Seen, Upgrade, [], State1).
Deps1 = rebar_app_utils:parse_deps(DepsDir, Deps, State, Locks, Level),
ProfileLevelDeps = [{Profile, Deps1, Level}],
Graph = rebar_state:packages_graph(State),
Registry = rebar_packages:registry(State),
State1 = rebar_state:packages_graph(rebar_state:registry(State, Registry), Graph),
handle_profile_level(ProfileLevelDeps, [], sets:new(), Upgrade, Locks, State1, Graph).
%% ===================================================================
%% Internal functions
@ -144,71 +137,33 @@ handle_deps_as_profile(Profile, State, Deps, Upgrade) ->
%% finds all the deps in `{deps, ...}` for each profile provided.
deps_per_profile(Profiles, Upgrade, State) ->
Level = 0,
{AllProfileDeps, PkgDeps} = lists:foldl(fun(Profile, {SrcAcc, PkgAcc}) ->
case parse_profile_deps(State, Profile, Level) of
{Src, {_, _, []}} ->
{[Src | SrcAcc], PkgAcc};
{Src, Pkg} ->
{[Src | SrcAcc], [Pkg | PkgAcc]}
end
end, {[], []}, Profiles),
{AllApps, PkgDeps1, Seen, State1} = handle_profile_level(AllProfileDeps, PkgDeps, [], sets:new(), Upgrade, State),
Locks = rebar_state:get(State, {locks, default}, []),
handle_profile_pkg_level(PkgDeps1, AllApps, Seen, Upgrade, Locks, State1).
parse_profile_deps(State, Profile, Level) ->
Locks = rebar_state:get(State, {locks, Profile}, []),
{SrcDeps, PkgDeps} = rebar_state:get(State, {parsed_deps, Profile}, {[], []}),
{{Profile, SrcDeps, Locks, Level}, {Profile, Level, PkgDeps}}.
Deps = lists:foldl(fun(Profile, DepAcc) ->
[parsed_profile_deps(State, Profile, Level) | DepAcc]
end, [], Profiles),
Graph = rebar_state:packages_graph(State),
Registry = rebar_packages:registry(State),
State1 = rebar_state:packages_graph(rebar_state:registry(State, Registry), Graph),
handle_profile_level(Deps, [], sets:new(), Upgrade, Locks, State1, Graph).
parsed_profile_deps(State, Profile, Level) ->
ParsedDeps = rebar_state:get(State, {parsed_deps, Profile}, []),
{Profile, ParsedDeps, Level}.
%% Level-order traversal of all dependencies, across profiles.
%% If profiles x,y,z are present, then the traversal will go:
%% x0, y0, z0, x1, y1, z1, ..., xN, yN, zN.
handle_profile_level([], PkgDeps, SrcApps, Seen, _Upgrade, State) ->
{SrcApps, PkgDeps, Seen, State};
handle_profile_level([{Profile, SrcDeps, Locks, Level} | Rest], PkgDeps, SrcApps, Seen, Upgrade, State) ->
{SrcDeps1, PkgDeps1, SrcApps1, State1, Seen1, Locks1} =
update_src_deps(Profile, Level, SrcDeps, [], SrcApps
,State, Upgrade, Seen, Locks),
SrcDeps2 = case SrcDeps1 of
handle_profile_level([], Apps, _Seen, _Upgrade, _Locks, State, _Graph) ->
{Apps, State};
handle_profile_level([{Profile, Deps, Level} | Rest], Apps, Seen, Upgrade, Locks, State, Graph) ->
{Deps1, Apps1, State1, Seen1} =
update_deps(Profile, Level, Deps, Apps
,State, Upgrade, Seen, Locks, Graph),
Deps2 = case Deps1 of
[] -> Rest;
_ -> Rest ++ [{Profile, SrcDeps1, Locks1, Level+1}]
_ -> Rest ++ [{Profile, Deps1, Level+1}]
end,
handle_profile_level(SrcDeps2, case PkgDeps1 of
[] ->
PkgDeps;
_ ->
[{Profile, Level+1, PkgDeps1} | PkgDeps]
end, SrcApps1, sets:union(Seen, Seen1), Upgrade, State1).
handle_profile_pkg_level([], AllApps, _Seen, _Upgrade, _Locks, State) ->
{AllApps, State};
handle_profile_pkg_level(PkgDeps, AllApps, Seen, Upgrade, Locks, State) ->
%% Read in package index and dep graph
{Packages, Graph} = rebar_state:packages(State),
Registry = rebar_state:registry(State),
State1 = rebar_state:packages(rebar_state:registry(State, Registry)
,{Packages, Graph}),
S = case rebar_digraph:cull_deps(Graph, lists:keysort(2, PkgDeps), Seen) of
{ok, [], []} ->
throw({rebar_digraph, no_solution});
{ok, [], Discarded} ->
[warn_skip_pkg(Pkg, State) || Upgrade =:= false,
Pkg <- Discarded,
not(pkg_locked(Pkg, Locks))],
[];
{ok, Solution, []} ->
Solution;
{ok, Solution, Discarded} ->
[warn_skip_pkg(Pkg, State) || Upgrade =:= false,
Pkg <- Discarded,
not(pkg_locked(Pkg, Locks))],
Solution
end,
{PkgApps, State2} = update_pkg_deps(S, Packages, Upgrade, Seen, State1, Locks),
{AllApps++PkgApps, State2}.
handle_profile_level(Deps2, Apps1, sets:union(Seen, Seen1), Upgrade, Locks, State1, Graph).
find_cycles(Apps) ->
case rebar_digraph:compile_order(Apps) of
@ -220,38 +175,6 @@ find_cycles(Apps) ->
cull_compile(TopSortedDeps, ProjectApps) ->
lists:dropwhile(fun not_needs_compile/1, TopSortedDeps -- ProjectApps).
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(Pkgs, Packages, Upgrade, Seen, State, Locks) ->
{Solved, _, State1}
= lists:foldl(fun({Profile, Pkg}, {Acc, SeenAcc, StateAcc}) ->
DepsDir = profile_dep_dir(State, Profile),
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, Locks, State) ->
IsLock = pkg_locked(Pkg, Locks),
AppInfo = package_to_app(DepsDir, Packages, Pkg, IsLock, State),
case sets:is_element(rebar_app_info:name(AppInfo), Seen) of
true ->
{Fetched, Seen, State};
false ->
Deps = rebar_app_info:deps(AppInfo),
Level = rebar_app_info:dep_level(AppInfo),
{NewSeen, NewState} = maybe_lock(Profile, AppInfo, Seen, State, Level),
{_, AppInfo1} = maybe_fetch(AppInfo, Profile, Upgrade, Seen, NewState),
{AppInfo2, _, _, _, _} =
handle_dep(NewState, Profile, DepsDir, AppInfo1, Locks, Level),
AppInfo3 = rebar_app_info:deps(AppInfo2, Deps),
{[AppInfo3 | Fetched], NewSeen, NewState}
end.
maybe_lock(Profile, AppInfo, Seen, State, Level) ->
Name = rebar_app_info:name(AppInfo),
case rebar_app_info:is_checkout(AppInfo) of
@ -278,49 +201,28 @@ maybe_lock(Profile, AppInfo, Seen, State, Level) ->
{sets:add_element(Name, Seen), State}
end.
package_to_app(DepsDir, Packages, {Parent, Name, Vsn, Level}, IsLock, State) ->
case dict:find({Name, Vsn}, Packages) of
error ->
case rebar_packages:check_registry(Name, Vsn, State) of
true ->
throw(?PRV_ERROR({not_rebar_package, Name, Vsn}));
false ->
throw(?PRV_ERROR({missing_package, Name, Vsn}))
end;
{ok, PkgDeps} ->
Source = {pkg, Name, Vsn},
AppInfo = new_dep(root, DepsDir, Name, Vsn, Source, IsLock, State),
AppInfo1 = rebar_app_info:dep_level(rebar_app_info:deps(AppInfo, PkgDeps), Level),
BaseDir = rebar_state:get(State, base_dir, []),
AppState1 = rebar_state:set(rebar_app_info:state(AppInfo1), base_dir, BaseDir),
rebar_app_info:parent(rebar_app_info:state(AppInfo1, AppState1), Parent)
end.
-spec update_src_deps(atom(), non_neg_integer(), list(), list(), list(), rebar_state:t(), boolean(), sets:set(binary()), list()) -> {list(), list(), list(), rebar_state:t(), sets:set(binary()), list()}.
update_src_deps(Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, Seen, Locks) ->
update_deps(Profile, Level, Deps, Apps, State, Upgrade, Seen, Locks, Graph) ->
lists:foldl(
fun(AppInfo, {SrcDepsAcc, PkgDepsAcc, SrcAppsAcc, StateAcc, SeenAcc, LocksAcc}) ->
update_src_dep(AppInfo, Profile, Level,
SrcDepsAcc, PkgDepsAcc, SrcAppsAcc, StateAcc,
Upgrade, SeenAcc, Locks, LocksAcc)
fun(AppInfo, {DepsAcc, AppsAcc, StateAcc, SeenAcc}) ->
update_dep(AppInfo, Profile, Level,
DepsAcc, AppsAcc, StateAcc,
Upgrade, SeenAcc, Locks, Graph)
end,
{[], PkgDeps, SrcApps, State, Seen, Locks},
rebar_utils:sort_deps(SrcDeps)).
{[], Apps, State, Seen},
rebar_utils:sort_deps(Deps)).
update_src_dep(AppInfo, Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, Seen, BaseLocks, Locks) ->
update_dep(AppInfo, Profile, Level, Deps, Apps, State, Upgrade, Seen, Locks, Graph) ->
%% If not seen, add to list of locks to write out
Name = rebar_app_info:name(AppInfo),
case sets:is_element(Name, Seen) of
true ->
update_seen_src_dep(AppInfo, Profile, Level,
SrcDeps, PkgDeps, SrcApps,
State, Upgrade, Seen, BaseLocks, Locks);
update_seen_dep(AppInfo, Profile, Level,
Deps, Apps,
State, Upgrade, Seen, Locks);
false ->
update_unseen_src_dep(AppInfo, Profile, Level,
SrcDeps, PkgDeps, SrcApps,
State, Upgrade, Seen, Locks)
update_unseen_dep(AppInfo, Profile, Level,
Deps, Apps,
State, Upgrade, Seen, Locks, Graph)
end.
profile_dep_dir(State, Profile) ->
@ -329,41 +231,31 @@ profile_dep_dir(State, Profile) ->
_ -> rebar_dir:deps_dir(State)
end.
update_seen_src_dep(AppInfo, _Profile, _Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, Seen, BaseLocks, Locks) ->
update_seen_dep(AppInfo, _Profile, _Level, Deps, Apps, State, Upgrade, Seen, Locks) ->
Name = rebar_app_info:name(AppInfo),
%% If seen from lock file or user requested an upgrade
%% don't print warning about skipping
case lists:keymember(Name, 1, BaseLocks) of
case lists:keymember(Name, 1, Locks) of
false when Upgrade -> ok;
false when not Upgrade -> warn_skip_deps(AppInfo, State);
true -> ok
end,
{SrcDeps, PkgDeps, SrcApps, State, Seen, Locks}.
{Deps, Apps, State, Seen}.
update_unseen_src_dep(AppInfo, Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, Seen, Locks) ->
update_unseen_dep(AppInfo, Profile, Level, Deps, Apps, State, Upgrade, Seen, Locks, Graph) ->
{NewSeen, State1} = maybe_lock(Profile, AppInfo, Seen, State, Level),
{_, AppInfo1} = maybe_fetch(AppInfo, Profile, Upgrade, Seen, State1),
{NewSrcDeps, NewPkgDeps, NewSrcApps, State2, NewLocks} =
handle_dep(AppInfo1, Profile, SrcDeps, PkgDeps, SrcApps,
Level, State1, Locks),
{NewSrcDeps, NewPkgDeps, NewSrcApps, State2, NewSeen, NewLocks}.
handle_dep(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) ->
DepsDir = profile_dep_dir(State, Profile),
{AppInfo1, NewSrcDeps, NewPkgDeps, NewLocks, State1} =
handle_dep(State, Profile, DepsDir, AppInfo, Locks, Level),
AppInfo2 = rebar_app_info:dep_level(AppInfo1, Level),
{NewSrcDeps ++ SrcDeps
,NewPkgDeps++PkgDeps
,[AppInfo2 | SrcApps]
,State1
,NewLocks}.
-spec handle_dep(rebar_state:t(), atom(), file:filename_all(), rebar_app_info:t(), list(), integer()) ->
{rebar_app_info:t(), [rebar_app_info:t()], [pkg_dep()], [integer()], rebar_state:t()}.
handle_dep(State, Profile, DepsDir, AppInfo, Locks, Level) ->
{AppInfo2, NewDeps, State2} =
handle_dep(State1, Profile, DepsDir, AppInfo1, Locks, Level, Graph),
AppInfo3 = rebar_app_info:dep_level(AppInfo2, Level),
{NewDeps ++ Deps, [AppInfo3 | Apps], State2, NewSeen}.
-spec handle_dep(rebar_state:t(), atom(), file:filename_all(), rebar_app_info:t(), list(), integer(), rebar_dict()) -> {rebar_app_info:t(), [rebar_app_info:t()], [pkg_dep()], [integer()], rebar_state:t()}.
handle_dep(State, Profile, DepsDir, AppInfo, Locks, Level, Graph) ->
Profiles = rebar_state:current_profiles(State),
Name = rebar_app_info:name(AppInfo),
Vsn = rebar_app_info:original_vsn(AppInfo),
%% Deps may be under a sub project app, find it and use its state if so
S0 = rebar_app_info:state(AppInfo),
@ -375,23 +267,26 @@ handle_dep(State, Profile, DepsDir, AppInfo, Locks, Level) ->
S3 = rebar_state:apply_profiles(S2, Profiles),
Plugins = rebar_state:get(S3, plugins, []),
S4 = rebar_state:set(S3, {plugins, Profile}, Plugins),
AppInfo1 = rebar_app_info:state(AppInfo, S4),
rebar_utils:check_min_otp_version(rebar_state:get(S4, minimum_otp_vsn, undefined)),
rebar_utils:check_blacklisted_otp_versions(rebar_state:get(S4, blacklisted_otp_vsns, [])),
%% Dep may have plugins to install. Find and install here.
S5 = rebar_plugins:install(S4),
AppInfo2 = rebar_app_info:state(AppInfo1, S5),
AppInfo1 = rebar_app_info:state(AppInfo, S5),
%% Upgrade lock level to be the level the dep will have in this dep tree
Deps = rebar_state:get(S5, {deps, default}, []),
NewLocks = Locks++[{DepName, Source, LockLevel+Level} ||
{DepName, Source, LockLevel} <- rebar_state:get(S5, {locks, default}, [])],
AppInfo3 = rebar_app_info:deps(AppInfo2, rebar_state:deps_names(Deps)),
{SrcDeps, PkgDeps} = parse_deps(rebar_app_info:name(AppInfo3), DepsDir, Deps
,S5, NewLocks, Level+1),
{AppInfo3, SrcDeps, PkgDeps, NewLocks, State}.
case rebar_app_info:resource_type(AppInfo1) of
pkg ->
NewDeps = digraph:out_neighbours(Graph, {ec_cnv:to_binary(Name), ec_cnv:to_binary(Vsn)}),
NewDeps1 = rebar_app_utils:parse_deps(Name, DepsDir, NewDeps, S5, Locks, Level+1),
{rebar_app_info:deps(AppInfo1, NewDeps), NewDeps1, State};
_ ->
Deps = rebar_state:get(S5, {deps, default}, []),
AppInfo2 = rebar_app_info:deps(AppInfo1, rebar_state:deps_names(Deps)),
Deps1 = rebar_app_utils:parse_deps(Name, DepsDir, Deps, S5, Locks, Level+1),
{AppInfo2, Deps1, State}
end.
-spec maybe_fetch(rebar_app_info:t(), atom(), boolean(),
sets:set(binary()), rebar_state:t()) -> {boolean(), rebar_app_info:t()}.
@ -406,20 +301,20 @@ maybe_fetch(AppInfo, Profile, Upgrade, Seen, State) ->
false ->
true = fetch_app(AppInfo, AppDir, State),
maybe_symlink_default(State, Profile, AppDir, AppInfo),
{true, update_app_info(AppDir, AppInfo)};
{true, rebar_app_info:valid(update_app_info(AppDir, AppInfo), false)};
{true, AppInfo1} ->
%% Preserve the state we created with overrides
AppInfo2 = copy_app_info(AppInfo, AppInfo1),
AppState = rebar_app_info:state(AppInfo),
Parent = rebar_app_info:parent(AppInfo),
Source = rebar_app_info:source(AppInfo),
AppInfo2 = rebar_app_info:parent(rebar_app_info:state(AppInfo1, AppState), Parent),
AppInfo3 = rebar_app_info:source(AppInfo2, Source),
case sets:is_element(rebar_app_info:name(AppInfo), Seen) of
AppInfo3 = rebar_app_info:state(AppInfo2, AppState),
case sets:is_element(rebar_app_info:name(AppInfo3), Seen) of
true ->
{false, AppInfo3};
false ->
maybe_symlink_default(State, Profile, AppDir, AppInfo3),
{maybe_upgrade(AppInfo, AppDir, Upgrade, State), AppInfo3}
MaybeUpgrade = maybe_upgrade(AppInfo, AppDir, Upgrade, State),
AppInfo4 = update_app_info(AppDir, AppInfo3),
{MaybeUpgrade, AppInfo4}
end
end
end.
@ -467,106 +362,6 @@ make_relative_to_root(State, Path) when is_list(Path) ->
Root = rebar_dir:root_dir(State),
rebar_dir:make_relative_path(Path, Root).
-spec parse_deps(binary(), list(), rebar_state:t(), list(), integer()) -> {[rebar_app_info:t()], [tuple()]}.
parse_deps(DepsDir, Deps, State, Locks, Level) ->
parse_deps(root, DepsDir, Deps, State, Locks, Level).
parse_deps(Parent, DepsDir, Deps, State, Locks, Level) ->
lists:foldl(fun(Dep, Acc) ->
Name = case Dep of
Dep when is_tuple(Dep) ->
element(1, Dep);
Dep ->
Dep
end,
case lists:keyfind(ec_cnv:to_binary(Name), 1, Locks) of
false ->
parse_dep(Parent, Dep, Acc, DepsDir, false, State);
LockedDep ->
LockedLevel = element(3, LockedDep),
case LockedLevel > Level of
true ->
parse_dep(Parent, Dep, Acc, DepsDir, false, State);
false ->
parse_dep(Parent, LockedDep, Acc, DepsDir, true, State)
end
end
end, {[], []}, Deps).
parse_dep(Parent, {Name, Vsn}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_list(Vsn) ->
%% Versioned Package dependency
CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
case rebar_app_info:discover(CheckoutsDir) of
{ok, _App} ->
Dep = new_dep(root, DepsDir, Name, [], [], IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
not_found ->
{SrcDepsAcc, [parse_goal(Parent
,ec_cnv:to_binary(Name)
,ec_cnv:to_binary(Vsn)) | PkgDepsAcc]}
end;
parse_dep(Parent, Name, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_atom(Name); is_binary(Name) ->
%% Unversioned package dependency
{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(root, DepsDir, Name, [], [], IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
not_found ->
{SrcDepsAcc, [{Parent, PkgName, PkgVsn} | PkgDepsAcc]}
end;
parse_dep(Parent, {Name, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_tuple(Source) ->
Dep = new_dep(Parent, DepsDir, Name, [], Source, IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
parse_dep(Parent, {Name, _Vsn, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_tuple(Source) ->
Dep = new_dep(Parent, DepsDir, Name, [], Source, IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
parse_dep(Parent, {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(Parent, DepsDir, Name, [], Source, IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
parse_dep(Parent, {_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(root, DepsDir, Name, [], [], IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
not_found ->
{SrcDepsAcc, [{Parent, Name, Vsn} | PkgDepsAcc]}
end;
parse_dep(Parent, {Name, Source, Level}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_tuple(Source)
, is_integer(Level) ->
Dep = new_dep(Parent, DepsDir, Name, [], Source, IsLock, State),
{[Dep | SrcDepsAcc], PkgDepsAcc};
parse_dep(_, Dep, _, _, _, _) ->
throw(?PRV_ERROR({parse_dep, Dep})).
new_dep(Parent, 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} ->
{ok, rebar_app_info:is_checkout(App, true)};
not_found ->
Dir = ec_cnv:to_list(filename:join(DepsDir, Name)),
case rebar_app_info:discover(Dir) of
{ok, App} ->
{ok, App};
not_found ->
rebar_app_info:new(Name, Vsn,
ec_cnv:to_list(filename:join(DepsDir, Name)))
end
end,
C = rebar_config:consult(rebar_app_info:dir(Dep)),
S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(Dep)),
Overrides = rebar_state:get(State, overrides, []),
ParentOverrides = rebar_state:overrides(State),
Dep1 = rebar_app_info:state(Dep,
rebar_state:overrides(S, ParentOverrides++Overrides)),
AppInfo = rebar_app_info:is_lock(rebar_app_info:source(Dep1, Source), IsLock),
rebar_app_info:parent(AppInfo, Parent).
fetch_app(AppInfo, AppDir, State) ->
?INFO("Fetching ~s (~p)", [rebar_app_info:name(AppInfo), rebar_app_info:source(AppInfo)]),
Source = rebar_app_info:source(AppInfo),
@ -577,15 +372,24 @@ fetch_app(AppInfo, AppDir, State) ->
%% be read in an parsed.
update_app_info(AppDir, AppInfo) ->
{ok, Found} = rebar_app_info:discover(AppDir),
Parent = rebar_app_info:parent(AppInfo),
Source = rebar_app_info:source(AppInfo),
AppDetails = rebar_app_info:app_details(Found),
Vsn = rebar_app_info:original_vsn(Found),
Applications = proplists:get_value(applications, AppDetails, []),
IncludedApplications = proplists:get_value(included_applications, AppDetails, []),
AppInfo1 = rebar_app_info:applications(
AppInfo1 = rebar_app_info:original_vsn(rebar_app_info:applications(
rebar_app_info:app_details(AppInfo, AppDetails),
IncludedApplications++Applications),
rebar_app_info:source(rebar_app_info:parent(rebar_app_info:valid(AppInfo1, false), Parent), Source).
IncludedApplications++Applications), Vsn),
AppInfo2 = copy_app_info(AppInfo, AppInfo1),
rebar_app_info:valid(AppInfo2, undefined).
copy_app_info(OldAppInfo, NewAppInfo) ->
ResourceType = rebar_app_info:resource_type(OldAppInfo),
Parent = rebar_app_info:parent(OldAppInfo),
Source = rebar_app_info:source(OldAppInfo),
rebar_app_info:resource_type(
rebar_app_info:source(
rebar_app_info:parent(NewAppInfo, Parent), Source), ResourceType).
maybe_upgrade(AppInfo, AppDir, Upgrade, State) ->
Source = rebar_app_info:source(AppInfo),
@ -608,17 +412,6 @@ maybe_upgrade(AppInfo, AppDir, Upgrade, State) ->
false
end.
-spec parse_goal(binary() | root, binary(), binary()) -> {binary(), binary()} | {binary(), binary(), binary()}.
parse_goal(Parent, Name, Constraint) ->
case re:run(Constraint, "([^\\d]*)(\\d.*)", [{capture, [1,2], binary}]) of
{match, [<<>>, Vsn]} ->
{Parent, Name, Vsn};
{match, [Op, Vsn]} ->
{Parent, Name, Vsn, binary_to_atom(Op, utf8)};
nomatch ->
throw(?PRV_ERROR({bad_constraint, Name, Constraint}))
end.
warn_skip_deps(AppInfo, State) ->
Msg = "Skipping ~s (from ~p) as an app of the same name "
"has already been fetched",
@ -629,25 +422,7 @@ warn_skip_deps(AppInfo, State) ->
true -> ?ERROR(Msg, Args), ?FAIL
end.
warn_skip_pkg({Name, Source}, State) ->
Msg = "Skipping ~s (version ~s from package index) as an app of the same "
"name has already been fetched",
Args = [Name, Source],
case rebar_state:get(State, deps_error_on_conflict, false) of
false -> ?WARN(Msg, Args);
true -> ?ERROR(Msg, Args), ?FAIL
end.
not_needs_compile(App) ->
not(rebar_app_info:is_checkout(App))
andalso rebar_app_info:valid(App)
andalso rebar_state:has_all_artifacts(rebar_app_info:state(App)) =:= true.
get_package(Dep, State) ->
case rebar_state:registry(State) of
{ok, T} ->
{ok, HighestDepVsn} = rebar_packages:find_highest_matching(Dep, "0", T),
{Dep, HighestDepVsn};
error ->
throw(?PRV_ERROR({load_registry_fail, Dep}))
end.

+ 1
- 1
src/rebar_prv_packages.erl 查看文件

@ -27,7 +27,7 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
{Dict, _} = rebar_state:packages(State),
Dict = rebar_packages:packages(State),
print_packages(Dict),
{ok, State}.

+ 1
- 2
src/rebar_prv_upgrade.erl 查看文件

@ -54,7 +54,7 @@ do(State) ->
Deps0 = top_level_deps(Deps, Locks),
State1 = rebar_state:set(State, {deps, default}, Deps0),
DepsDir = rebar_prv_install_deps:profile_dep_dir(State, default),
D = rebar_prv_install_deps:parse_deps(root, DepsDir, Deps0, State1, Locks0, 0),
D = rebar_app_utils:parse_deps(root, DepsDir, Deps0, State1, Locks0, 0),
State2 = rebar_state:set(State1, {parsed_deps, default}, D),
State3 = rebar_state:set(State2, {locks, default}, Locks0),
State4 = rebar_state:set(State3, upgrade, true),
@ -83,7 +83,6 @@ format_error({transitive_dependency, Name}) ->
format_error(Reason) ->
io_lib:format("~p", [Reason]).
parse_names(Bin, Locks) ->
case lists:usort(re:split(Bin, <<" *, *">>, [trim])) of
%% Nothing submitted, use *all* apps

+ 13
- 4
src/rebar_state.erl 查看文件

@ -38,7 +38,8 @@
overrides/1, overrides/2,
apply_overrides/2,
packages/1, packages/2,
packages_graph/1, packages_graph/2,
packages/1,
registry/1, registry/2,
resources/1, resources/2, add_resource/2,
@ -65,7 +66,8 @@
all_plugin_deps = [] :: [rebar_app_info:t()],
all_deps = [] :: [rebar_app_info:t()],
packages = undefined :: {rebar_dict(), rebar_digraph()} | undefined,
packages = undefined :: rebar_dict(),
packages_graph = undefined :: rebar_digraph() | undefined,
registry = undefined :: {ok, ets:tid()} | error | undefined,
overrides = [],
resources = [],
@ -96,7 +98,9 @@ new(Config) when is_list(Config) ->
load_package_registry(Config0) ->
Registry = rebar_packages:registry(Config0),
Packages = rebar_packages:packages(Config0),
PackagesGraph = rebar_packages:packages_graph(Config0),
Config0#state_t{registry = Registry,
packages_graph = PackagesGraph,
packages = Packages}.
-spec new(t() | atom(), list()) -> t().
@ -451,8 +455,13 @@ packages(#state_t{packages=undefined}) ->
packages(#state_t{packages=Packages}) ->
Packages.
packages(State, Packages) ->
State#state_t{packages=Packages}.
packages_graph(#state_t{packages_graph=undefined}) ->
throw(packages_usage_error);
packages_graph(#state_t{packages_graph=PackagesGraph}) ->
PackagesGraph.
packages_graph(State, PackagesGraph) ->
State#state_t{packages_graph=PackagesGraph}.
registry(#state_t{registry=undefined}) ->
throw(registry_usage_error);

+ 3
- 1
test/mock_pkg_resource.erl 查看文件

@ -119,7 +119,9 @@ mock_pkg_index(Opts) ->
meck:expect(rebar_state, registry,
fun(_State) -> {ok, to_registry(Deps)} end),
meck:expect(rebar_state, packages,
fun(_State) -> {Dict, Digraph} end).
fun(_State) -> Dict end),
meck:expect(rebar_state, packages_graph,
fun(_State) -> Digraph end).
%%%%%%%%%%%%%%%
%%% Helpers %%%

+ 1
- 1
test/rebar_deps_SUITE.erl 查看文件

@ -297,5 +297,5 @@ in_warnings(git, Warns, NameRaw, VsnRaw) ->
in_warnings(pkg, Warns, NameRaw, VsnRaw) ->
Name = iolist_to_binary(NameRaw),
Vsn = iolist_to_binary(VsnRaw),
1 =< length([1 || {_, [AppName, AppVsn]} <- Warns,
1 =< length([1 || {_, [AppName, {pkg, _, AppVsn}]} <- Warns,
AppName =:= Name, AppVsn =:= Vsn]).

+ 4
- 24
test/rebar_install_deps_SUITE.erl 查看文件

@ -15,9 +15,9 @@ groups() ->
{git, [], [{group, unique}]},
{pkg, [], [{group, unique}]},
{mixed, [], [
m_flat1, m_flat2, m_circular1, m_circular2, m_circular3,
m_flat1, m_flat2, m_circular1, m_circular2,
m_pick_source1, m_pick_source2, m_pick_source3,
m_pick_source4, m_pick_source5, m_source_to_pkg,
m_source_to_pkg,
m_pkg_level1, m_pkg_level2, m_pkg_level3, m_pkg_level3_alpha_order
]}
].
@ -199,39 +199,22 @@ mdeps(m_circular2) ->
{[{"B", [{"c", [{"b", []}]}]}],
[],
{error, {rebar_prv_install_deps, {cycles, [[<<"B">>,<<"C">>]]}}}};
mdeps(m_circular3) ->
%% Spot the circular dep due to being to low in the deps tree
%% but as a source dep, taking precedence over packages
{[{"B", [{"C", "2", [{"B", []}]}]},
{"c", "1", [{"d",[]}]}],
[],
{error, {rebar_prv_install_deps, {cycles, [[<<"B">>,<<"C">>]]}}}};
mdeps(m_pick_source1) ->
{[{"B", [{"D", []}]},
{"c", [{"d", []}]}],
["d"],
{ok, ["B", "c", "D"]}};
mdeps(m_pick_source2) ->
{[{"b", [{"d", []}]},
{"C", [{"D", []}]}],
["d"],
{ok, ["b", "C", "D"]}};
mdeps(m_pick_source3) ->
%% The order of declaration is important.
{[{"b", []},
{"B", []}],
[],
{ok, ["b"]}};
mdeps(m_pick_source4) ->
mdeps(m_pick_source3) ->
{[{"B", []},
{"b", []}],
[],
{ok, ["B"]}};
mdeps(m_pick_source5) ->
{[{"B", [{"d", []}]},
{"C", [{"D", []}]}],
["d"],
{ok, ["B", "C", "D"]}};
mdeps(m_source_to_pkg) ->
{[{"B", [{"c",[{"d", []}]}]}],
[],
@ -438,12 +421,9 @@ m_flat1(Config) -> run(Config).
m_flat2(Config) -> run(Config).
m_circular1(Config) -> run(Config).
m_circular2(Config) -> run(Config).
m_circular3(Config) -> run(Config).
m_pick_source1(Config) -> run(Config).
m_pick_source2(Config) -> run(Config).
m_pick_source3(Config) -> run(Config).
m_pick_source4(Config) -> run(Config).
m_pick_source5(Config) -> run(Config).
m_source_to_pkg(Config) -> run(Config).
m_pkg_level1(Config) -> run(Config).
m_pkg_level2(Config) -> run(Config).
@ -483,5 +463,5 @@ in_warnings(git, Warns, NameRaw, VsnRaw) ->
in_warnings(pkg, Warns, NameRaw, VsnRaw) ->
Name = iolist_to_binary(NameRaw),
Vsn = iolist_to_binary(VsnRaw),
1 =< length([1 || {_, [AppName, AppVsn]} <- Warns,
1 =< length([1 || {_, [AppName, {pkg, _, AppVsn}]} <- Warns,
AppName =:= Name, AppVsn =:= Vsn]).

Loading…
取消
儲存