Bläddra i källkod

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 år sedan
förälder
incheckning
31a24ad4ff
12 ändrade filer med 275 tillägg och 472 borttagningar
  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 Visa fil

@ -96,7 +96,7 @@ merge_deps(AppInfo, State) ->
{AppInfo1, State1}. {AppInfo1, State1}.
handle_profile(Profile, Name, AppState, State) -> 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}, []), TopLevelProfileDeps = rebar_state:get(State, {deps, Profile}, []),
AppProfileDeps = rebar_state:get(AppState, {deps, Profile}, []), AppProfileDeps = rebar_state:get(AppState, {deps, Profile}, []),
AppProfileDeps2 = rebar_utils:tup_dedup(rebar_utils:tup_sort(AppProfileDeps)), 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 %% Only deps not also specified in the top level config need
%% to be included in the parsed deps %% to be included in the parsed deps
NewDeps = ProfileDeps2 -- TopLevelProfileDeps, 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) -> parse_profile_deps(Profile, Name, Deps, AppState, State) ->
DepsDir = rebar_prv_install_deps:profile_dep_dir(State, Profile), DepsDir = rebar_prv_install_deps:profile_dep_dir(State, Profile),
Locks = rebar_state:get(State, {locks, 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) -> project_app_config(AppInfo, State) ->
C = rebar_config:consult(rebar_app_info:dir(AppInfo)), C = rebar_config:consult(rebar_app_info:dir(AppInfo)),

+ 12
- 1
src/rebar_app_info.erl Visa fil

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

+ 127
- 2
src/rebar_app_utils.erl Visa fil

@ -32,6 +32,9 @@
app_src_to_app/2, app_src_to_app/2,
validate_application_info/1, validate_application_info/1,
validate_application_info/2, validate_application_info/2,
parse_deps/5,
parse_deps/6,
dep_to_app/7,
format_error/1]). format_error/1]).
-include("rebar.hrl"). -include("rebar.hrl").
@ -87,6 +90,109 @@ validate_application_info(AppInfo, AppDetail) ->
end end
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) -> format_error(Error) ->
io_lib:format("~p", [Error]). io_lib:format("~p", [Error]).
@ -94,11 +200,30 @@ format_error(Error) ->
%% Internal functions %% 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()]) -> -spec has_all_beams(file:filename_all(), [module()]) ->
true | ?PRV_ERROR({missing_module, module()}). true | ?PRV_ERROR({missing_module, module()}).
has_all_beams(EbinDir, [Module | ModuleList]) -> 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 case filelib:is_file(BeamFile) of
true -> true ->
has_all_beams(EbinDir, ModuleList); has_all_beams(EbinDir, ModuleList);

+ 0
- 110
src/rebar_digraph.erl Visa fil

@ -2,8 +2,6 @@
-export([compile_order/1 -export([compile_order/1
,restore_graph/1 ,restore_graph/1
,cull_deps/2
,cull_deps/3
,subgraph/2 ,subgraph/2
,format_error/1]). ,format_error/1]).
@ -69,17 +67,6 @@ restore_graph({Vs, Es}) ->
end, Es), end, Es),
Graph. 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) -> format_error(no_solution) ->
io_lib:format("No solution for packages found.", []). io_lib:format("No solution for packages found.", []).
@ -87,103 +74,6 @@ format_error(no_solution) ->
%% Internal Functions %% 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) -> subgraph(Graph, Vertices) ->
digraph_utils:subgraph(Graph, Vertices). digraph_utils:subgraph(Graph, Vertices).

+ 19
- 7
src/rebar_packages.erl Visa fil

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

+ 85
- 310
src/rebar_prv_install_deps.erl Visa fil

@ -36,8 +36,6 @@
-include_lib("providers/include/providers.hrl"). -include_lib("providers/include/providers.hrl").
-export([handle_deps_as_profile/4, -export([handle_deps_as_profile/4,
parse_deps/5,
parse_deps/6,
profile_dep_dir/2, profile_dep_dir/2,
find_cycles/1, find_cycles/1,
cull_compile/2]). cull_compile/2]).
@ -125,17 +123,12 @@ handle_deps_as_profile(Profile, State, Deps, Upgrade) ->
Locks = [], Locks = [],
Level = 0, Level = 0,
DepsDir = profile_dep_dir(State, Profile), 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 %% Internal functions
@ -144,71 +137,33 @@ handle_deps_as_profile(Profile, State, Deps, Upgrade) ->
%% finds all the deps in `{deps, ...}` for each profile provided. %% finds all the deps in `{deps, ...}` for each profile provided.
deps_per_profile(Profiles, Upgrade, State) -> deps_per_profile(Profiles, Upgrade, State) ->
Level = 0, 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}, []), 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. %% Level-order traversal of all dependencies, across profiles.
%% If profiles x,y,z are present, then the traversal will go: %% If profiles x,y,z are present, then the traversal will go:
%% x0, y0, z0, x1, y1, z1, ..., xN, yN, zN. %% 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;
_ -> Rest ++ [{Profile, SrcDeps1, Locks1, Level+1}]
_ -> Rest ++ [{Profile, Deps1, Level+1}]
end, 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) -> find_cycles(Apps) ->
case rebar_digraph:compile_order(Apps) of case rebar_digraph:compile_order(Apps) of
@ -220,38 +175,6 @@ find_cycles(Apps) ->
cull_compile(TopSortedDeps, ProjectApps) -> cull_compile(TopSortedDeps, ProjectApps) ->
lists:dropwhile(fun not_needs_compile/1, 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) -> maybe_lock(Profile, AppInfo, Seen, State, Level) ->
Name = rebar_app_info:name(AppInfo), Name = rebar_app_info:name(AppInfo),
case rebar_app_info:is_checkout(AppInfo) of 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} {sets:add_element(Name, Seen), State}
end. 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( 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, 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 %% If not seen, add to list of locks to write out
Name = rebar_app_info:name(AppInfo), Name = rebar_app_info:name(AppInfo),
case sets:is_element(Name, Seen) of case sets:is_element(Name, Seen) of
true -> 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 -> 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. end.
profile_dep_dir(State, Profile) -> profile_dep_dir(State, Profile) ->
@ -329,41 +231,31 @@ profile_dep_dir(State, Profile) ->
_ -> rebar_dir:deps_dir(State) _ -> rebar_dir:deps_dir(State)
end. 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), Name = rebar_app_info:name(AppInfo),
%% If seen from lock file or user requested an upgrade %% If seen from lock file or user requested an upgrade
%% don't print warning about skipping %% 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 Upgrade -> ok;
false when not Upgrade -> warn_skip_deps(AppInfo, State); false when not Upgrade -> warn_skip_deps(AppInfo, State);
true -> ok true -> ok
end, 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), {NewSeen, State1} = maybe_lock(Profile, AppInfo, Seen, State, Level),
{_, AppInfo1} = maybe_fetch(AppInfo, Profile, Upgrade, Seen, State1), {_, 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), 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), Profiles = rebar_state:current_profiles(State),
Name = rebar_app_info:name(AppInfo), 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 %% Deps may be under a sub project app, find it and use its state if so
S0 = rebar_app_info:state(AppInfo), 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), S3 = rebar_state:apply_profiles(S2, Profiles),
Plugins = rebar_state:get(S3, plugins, []), Plugins = rebar_state:get(S3, plugins, []),
S4 = rebar_state:set(S3, {plugins, Profile}, 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_min_otp_version(rebar_state:get(S4, minimum_otp_vsn, undefined)),
rebar_utils:check_blacklisted_otp_versions(rebar_state:get(S4, blacklisted_otp_vsns, [])), rebar_utils:check_blacklisted_otp_versions(rebar_state:get(S4, blacklisted_otp_vsns, [])),
%% Dep may have plugins to install. Find and install here. %% Dep may have plugins to install. Find and install here.
S5 = rebar_plugins:install(S4), 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 %% 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(), -spec maybe_fetch(rebar_app_info:t(), atom(), boolean(),
sets:set(binary()), rebar_state:t()) -> {boolean(), rebar_app_info:t()}. sets:set(binary()), rebar_state:t()) -> {boolean(), rebar_app_info:t()}.
@ -406,20 +301,20 @@ maybe_fetch(AppInfo, Profile, Upgrade, Seen, State) ->
false -> false ->
true = fetch_app(AppInfo, AppDir, State), true = fetch_app(AppInfo, AppDir, State),
maybe_symlink_default(State, Profile, AppDir, AppInfo), 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} -> {true, AppInfo1} ->
%% Preserve the state we created with overrides %% Preserve the state we created with overrides
AppInfo2 = copy_app_info(AppInfo, AppInfo1),
AppState = rebar_app_info:state(AppInfo), 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 -> true ->
{false, AppInfo3}; {false, AppInfo3};
false -> false ->
maybe_symlink_default(State, Profile, AppDir, AppInfo3), 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 end
end. end.
@ -467,106 +362,6 @@ make_relative_to_root(State, Path) when is_list(Path) ->
Root = rebar_dir:root_dir(State), Root = rebar_dir:root_dir(State),
rebar_dir:make_relative_path(Path, Root). 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) -> fetch_app(AppInfo, AppDir, State) ->
?INFO("Fetching ~s (~p)", [rebar_app_info:name(AppInfo), rebar_app_info:source(AppInfo)]), ?INFO("Fetching ~s (~p)", [rebar_app_info:name(AppInfo), rebar_app_info:source(AppInfo)]),
Source = 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. %% be read in an parsed.
update_app_info(AppDir, AppInfo) -> update_app_info(AppDir, AppInfo) ->
{ok, Found} = rebar_app_info:discover(AppDir), {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), AppDetails = rebar_app_info:app_details(Found),
Vsn = rebar_app_info:original_vsn(Found),
Applications = proplists:get_value(applications, AppDetails, []), Applications = proplists:get_value(applications, AppDetails, []),
IncludedApplications = proplists:get_value(included_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), 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) -> maybe_upgrade(AppInfo, AppDir, Upgrade, State) ->
Source = rebar_app_info:source(AppInfo), Source = rebar_app_info:source(AppInfo),
@ -608,17 +412,6 @@ maybe_upgrade(AppInfo, AppDir, Upgrade, State) ->
false false
end. 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) -> warn_skip_deps(AppInfo, State) ->
Msg = "Skipping ~s (from ~p) as an app of the same name " Msg = "Skipping ~s (from ~p) as an app of the same name "
"has already been fetched", "has already been fetched",
@ -629,25 +422,7 @@ warn_skip_deps(AppInfo, State) ->
true -> ?ERROR(Msg, Args), ?FAIL true -> ?ERROR(Msg, Args), ?FAIL
end. 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_needs_compile(App) ->
not(rebar_app_info:is_checkout(App)) not(rebar_app_info:is_checkout(App))
andalso rebar_app_info:valid(App) andalso rebar_app_info:valid(App)
andalso rebar_state:has_all_artifacts(rebar_app_info:state(App)) =:= true. 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 Visa fil

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

+ 1
- 2
src/rebar_prv_upgrade.erl Visa fil

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

+ 13
- 4
src/rebar_state.erl Visa fil

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

+ 3
- 1
test/mock_pkg_resource.erl Visa fil

@ -119,7 +119,9 @@ mock_pkg_index(Opts) ->
meck:expect(rebar_state, registry, meck:expect(rebar_state, registry,
fun(_State) -> {ok, to_registry(Deps)} end), fun(_State) -> {ok, to_registry(Deps)} end),
meck:expect(rebar_state, packages, 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 %%% %%% Helpers %%%

+ 1
- 1
test/rebar_deps_SUITE.erl Visa fil

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

+ 4
- 24
test/rebar_install_deps_SUITE.erl Visa fil

@ -15,9 +15,9 @@ groups() ->
{git, [], [{group, unique}]}, {git, [], [{group, unique}]},
{pkg, [], [{group, unique}]}, {pkg, [], [{group, unique}]},
{mixed, [], [ {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_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 m_pkg_level1, m_pkg_level2, m_pkg_level3, m_pkg_level3_alpha_order
]} ]}
]. ].
@ -199,39 +199,22 @@ mdeps(m_circular2) ->
{[{"B", [{"c", [{"b", []}]}]}], {[{"B", [{"c", [{"b", []}]}]}],
[], [],
{error, {rebar_prv_install_deps, {cycles, [[<<"B">>,<<"C">>]]}}}}; {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) -> mdeps(m_pick_source1) ->
{[{"B", [{"D", []}]}, {[{"B", [{"D", []}]},
{"c", [{"d", []}]}], {"c", [{"d", []}]}],
["d"], ["d"],
{ok, ["B", "c", "D"]}}; {ok, ["B", "c", "D"]}};
mdeps(m_pick_source2) -> mdeps(m_pick_source2) ->
{[{"b", [{"d", []}]},
{"C", [{"D", []}]}],
["d"],
{ok, ["b", "C", "D"]}};
mdeps(m_pick_source3) ->
%% The order of declaration is important. %% The order of declaration is important.
{[{"b", []}, {[{"b", []},
{"B", []}], {"B", []}],
[], [],
{ok, ["b"]}}; {ok, ["b"]}};
mdeps(m_pick_source4) ->
mdeps(m_pick_source3) ->
{[{"B", []}, {[{"B", []},
{"b", []}], {"b", []}],
[], [],
{ok, ["B"]}}; {ok, ["B"]}};
mdeps(m_pick_source5) ->
{[{"B", [{"d", []}]},
{"C", [{"D", []}]}],
["d"],
{ok, ["B", "C", "D"]}};
mdeps(m_source_to_pkg) -> mdeps(m_source_to_pkg) ->
{[{"B", [{"c",[{"d", []}]}]}], {[{"B", [{"c",[{"d", []}]}]}],
[], [],
@ -438,12 +421,9 @@ m_flat1(Config) -> run(Config).
m_flat2(Config) -> run(Config). m_flat2(Config) -> run(Config).
m_circular1(Config) -> run(Config). m_circular1(Config) -> run(Config).
m_circular2(Config) -> run(Config). m_circular2(Config) -> run(Config).
m_circular3(Config) -> run(Config).
m_pick_source1(Config) -> run(Config). m_pick_source1(Config) -> run(Config).
m_pick_source2(Config) -> run(Config). m_pick_source2(Config) -> run(Config).
m_pick_source3(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_source_to_pkg(Config) -> run(Config).
m_pkg_level1(Config) -> run(Config). m_pkg_level1(Config) -> run(Config).
m_pkg_level2(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) -> in_warnings(pkg, Warns, NameRaw, VsnRaw) ->
Name = iolist_to_binary(NameRaw), Name = iolist_to_binary(NameRaw),
Vsn = iolist_to_binary(VsnRaw), Vsn = iolist_to_binary(VsnRaw),
1 =< length([1 || {_, [AppName, AppVsn]} <- Warns,
1 =< length([1 || {_, [AppName, {pkg, _, AppVsn}]} <- Warns,
AppName =:= Name, AppVsn =:= Vsn]). AppName =:= Name, AppVsn =:= Vsn]).

Laddar…
Avbryt
Spara