|
|
@ -42,6 +42,11 @@ |
|
|
|
-define(PROVIDER, install_deps). |
|
|
|
-define(DEPS, [app_discovery]). |
|
|
|
|
|
|
|
-type src_dep() :: {atom(), string(), {atom(), string(), string()}}. |
|
|
|
-type binary_dep() :: {atom(), binary()} | atom(). |
|
|
|
|
|
|
|
-type dep() :: src_dep() | binary_dep(). |
|
|
|
|
|
|
|
%% =================================================================== |
|
|
|
%% Public API |
|
|
|
%% =================================================================== |
|
|
@ -60,53 +65,9 @@ init(State) -> |
|
|
|
|
|
|
|
-spec do(rebar_state:t()) -> {ok, rebar_state:t()}. |
|
|
|
do(State) -> |
|
|
|
%% Read in package index and dep graph |
|
|
|
{Packages, Graph} = rebar_packages:get_packages(State), |
|
|
|
case rebar_state:get(State, locks, []) of |
|
|
|
[] -> |
|
|
|
case rebar_state:get(State, deps, []) of |
|
|
|
[] -> |
|
|
|
{ok, State}; |
|
|
|
Deps -> |
|
|
|
%% Split source deps form binary deps, needed to keep backwards compatibility |
|
|
|
DepsDir = get_deps_dir(State), |
|
|
|
{SrcDeps, Goals} = parse_deps(DepsDir, Deps), |
|
|
|
State1 = rebar_state:src_deps(rebar_state:goals(State, Goals), lists:ukeysort(2, SrcDeps)), |
|
|
|
State2 = update_src_deps(State1), |
|
|
|
case rebar_state:goals(State2) of |
|
|
|
[] -> |
|
|
|
ProjectApps = lists:map(fun(X) -> |
|
|
|
rebar_app_info:deps(X, [rebar_app_info:name(Y) || Y <- SrcDeps]) |
|
|
|
end, rebar_state:apps_to_build(State2)), |
|
|
|
FinalDeps = ProjectApps ++ rebar_state:src_deps(State2), |
|
|
|
{ok, Sort} = rebar_topo:sort_apps(FinalDeps), |
|
|
|
State3 = rebar_state:apps_to_build(State2, Sort), |
|
|
|
{ok, State3}; |
|
|
|
Goals1 -> |
|
|
|
{ok, Solved} = rlx_depsolver:solve(Graph, Goals1), |
|
|
|
Final = lists:map(fun({Name, Vsn}) -> |
|
|
|
FmtVsn = ec_cnv:to_binary(rlx_depsolver:format_version(Vsn)), |
|
|
|
{ok, P} = dict:find({Name, FmtVsn}, Packages), |
|
|
|
PkgDeps = proplists:get_value(<<"deps">>, P), |
|
|
|
Link = proplists:get_value(<<"link">>, P), |
|
|
|
Source = {Name, FmtVsn, Link}, |
|
|
|
{ok, AppInfo} = rebar_app_info:new(Name, FmtVsn), |
|
|
|
AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps), |
|
|
|
AppInfo2 = |
|
|
|
rebar_app_info:dir(AppInfo1, get_deps_dir(DepsDir, <<Name/binary, "-", FmtVsn/binary>>)), |
|
|
|
AppInfo3 = rebar_app_info:source(AppInfo2, Source), |
|
|
|
ok = maybe_fetch(AppInfo3), |
|
|
|
AppInfo3 |
|
|
|
end, Solved), |
|
|
|
ProjectApps = lists:map(fun(X) -> |
|
|
|
rebar_app_info:deps(X, [rebar_app_info:name(Y) || Y <- SrcDeps] ++ [element(1, G) || G <- Goals1]) |
|
|
|
end, rebar_state:apps_to_build(State2)), |
|
|
|
FinalDeps = ProjectApps ++ rebar_state:src_deps(State2) ++ Final, |
|
|
|
{ok, Sort} = rebar_topo:sort_apps(FinalDeps), |
|
|
|
State3 = rebar_state:apps_to_build(State2, Sort), |
|
|
|
{ok, State3} |
|
|
|
end |
|
|
|
end; |
|
|
|
handle_deps(State, rebar_state:get(State, deps, [])); |
|
|
|
_Locks -> |
|
|
|
{ok, State} |
|
|
|
end. |
|
|
@ -130,10 +91,12 @@ setup_env(State) -> |
|
|
|
[{"REBAR_DEPS_DIR", DepsDir}, ERL_LIBS]. |
|
|
|
|
|
|
|
|
|
|
|
-spec get_deps_dir(rebar_state:t()) -> file:filename_all(). |
|
|
|
get_deps_dir(State) -> |
|
|
|
BaseDir = rebar_state:get(State, base_dir, ""), |
|
|
|
get_deps_dir(BaseDir, "deps"). |
|
|
|
|
|
|
|
-spec get_deps_dir(file:filename_all(), rebar_state:t()) -> file:filename_all(). |
|
|
|
get_deps_dir(DepsDir, App) -> |
|
|
|
filename:join(DepsDir, App). |
|
|
|
|
|
|
@ -141,28 +104,84 @@ get_deps_dir(DepsDir, App) -> |
|
|
|
%% Internal functions |
|
|
|
%% =================================================================== |
|
|
|
|
|
|
|
handle_deps(State, []) -> |
|
|
|
{ok, State}; |
|
|
|
handle_deps(State, Deps) -> |
|
|
|
%% Read in package index and dep graph |
|
|
|
{Packages, Graph} = rebar_packages:get_packages(State), |
|
|
|
ProjectApps = rebar_state:project_apps(State), |
|
|
|
|
|
|
|
%% Split source deps form binary deps, needed to keep backwards compatibility |
|
|
|
DepsDir = get_deps_dir(State), |
|
|
|
{SrcDeps, BinaryDeps} = parse_deps(DepsDir, Deps), |
|
|
|
State1 = rebar_state:src_deps(rebar_state:binary_deps(State, BinaryDeps), |
|
|
|
lists:ukeysort(2, SrcDeps)), |
|
|
|
|
|
|
|
%% Fetch transitive src deps |
|
|
|
State2 = update_src_deps(State1), |
|
|
|
Solved = case rebar_state:binary_deps(State2) of |
|
|
|
[] -> %% No binary deps |
|
|
|
[]; |
|
|
|
BinaryDeps1 -> |
|
|
|
%% Find binary deps needed |
|
|
|
{ok, S} = rlx_depsolver:solve(Graph, BinaryDeps1), |
|
|
|
|
|
|
|
%% Create app_info record for each binary dep |
|
|
|
lists:map(fun({Name, Vsn}) -> |
|
|
|
AppInfo = package_to_app(DepsDir |
|
|
|
,Packages |
|
|
|
,Name |
|
|
|
,Vsn), |
|
|
|
ok = maybe_fetch(AppInfo), |
|
|
|
AppInfo |
|
|
|
end, S) |
|
|
|
end, |
|
|
|
|
|
|
|
FinalDeps = ProjectApps ++ rebar_state:src_deps(State2) ++ Solved, |
|
|
|
%% Sort all apps to build order |
|
|
|
{ok, Sort} = rebar_topo:sort_apps(FinalDeps), |
|
|
|
{ok, rebar_state:project_apps(State2, Sort)}. |
|
|
|
|
|
|
|
-spec package_to_app(file:name(), dict:dict(), binary(), binary()) -> rebar_app_info:t(). |
|
|
|
package_to_app(DepsDir, Packages, Name, Vsn) -> |
|
|
|
FmtVsn = ec_cnv:to_binary(rlx_depsolver:format_version(Vsn)), |
|
|
|
|
|
|
|
{ok, P} = dict:find({Name, FmtVsn}, Packages), |
|
|
|
PkgDeps = proplists:get_value(<<"deps">>, P), |
|
|
|
Link = proplists:get_value(<<"link">>, P), |
|
|
|
|
|
|
|
{ok, AppInfo} = rebar_app_info:new(Name, FmtVsn), |
|
|
|
AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps), |
|
|
|
AppInfo2 = |
|
|
|
rebar_app_info:dir(AppInfo1, get_deps_dir(DepsDir, <<Name/binary, "-", FmtVsn/binary>>)), |
|
|
|
rebar_app_info:source(AppInfo2, {Name, FmtVsn, Link}). |
|
|
|
|
|
|
|
-spec update_src_deps(rebar_state:t()) -> rebat_state:t(). |
|
|
|
update_src_deps(State) -> |
|
|
|
SrcDeps = rebar_state:src_deps(State), |
|
|
|
DepsDir = get_deps_dir(State), |
|
|
|
case lists:foldl(fun(AppInfo, {SrcDepsAcc, GoalsAcc}) -> |
|
|
|
case lists:foldl(fun(AppInfo, {SrcDepsAcc, BinaryDepsAcc}) -> |
|
|
|
ok = maybe_fetch(AppInfo), |
|
|
|
{NewSrcDeps, NewGoals} = handle_dep(DepsDir, AppInfo), |
|
|
|
{lists:ukeymerge(2, SrcDepsAcc, lists:ukeysort(2, NewSrcDeps)), NewGoals++GoalsAcc} |
|
|
|
end, {SrcDeps, rebar_state:goals(State)}, SrcDeps) of |
|
|
|
{SrcDeps, NewGoals} -> |
|
|
|
rebar_state:goals(State, NewGoals); |
|
|
|
{NewSrcDeps, NewGoals} -> |
|
|
|
io:format("NEWSRC ~p~n", [NewSrcDeps]), |
|
|
|
State1 = rebar_state:src_deps(rebar_state:goals(State, NewGoals), NewSrcDeps), |
|
|
|
{AppInfo1, NewSrcDeps, NewBinaryDeps} = handle_dep(DepsDir, AppInfo), |
|
|
|
{lists:ukeymerge(2, lists:ukeysort(2, [AppInfo1 | SrcDepsAcc]), lists:ukeysort(2, NewSrcDeps)), NewBinaryDeps++BinaryDepsAcc} |
|
|
|
end, {[], rebar_state:binary_deps(State)}, SrcDeps) of |
|
|
|
{NewSrcDeps, NewBinaryDeps} when length(SrcDeps) =:= length(NewSrcDeps) -> |
|
|
|
rebar_state:src_deps(rebar_state:binary_deps(State, NewBinaryDeps), NewSrcDeps); |
|
|
|
{NewSrcDeps, NewBinaryDeps} -> |
|
|
|
State1 = rebar_state:src_deps(rebar_state:binary_deps(State, NewBinaryDeps), NewSrcDeps), |
|
|
|
update_src_deps(State1) |
|
|
|
end. |
|
|
|
|
|
|
|
-spec handle_dep(binary(), rebar_state:t()) -> {[rebar_app_info:t()], [binary_dep()]}. |
|
|
|
handle_dep(DepsDir, AppInfo) -> |
|
|
|
C = rebar_config:consult(rebar_app_info:dir(AppInfo)), |
|
|
|
S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(AppInfo)), |
|
|
|
Deps = rebar_state:get(S, deps, []), |
|
|
|
parse_deps(DepsDir, Deps). |
|
|
|
AppInfo1 = rebar_app_info:deps(AppInfo, rebar_state:deps_names(S)), |
|
|
|
{SrcDeps, BinaryDeps} = parse_deps(DepsDir, Deps), |
|
|
|
{AppInfo1, SrcDeps, BinaryDeps}. |
|
|
|
|
|
|
|
-spec maybe_fetch(rebar_app_info:t()) -> ok. |
|
|
|
maybe_fetch(AppInfo) -> |
|
|
|
AppDir = rebar_app_info:dir(AppInfo), |
|
|
|
case filelib:is_dir(AppDir) of |
|
|
@ -174,19 +193,21 @@ maybe_fetch(AppInfo) -> |
|
|
|
ok |
|
|
|
end. |
|
|
|
|
|
|
|
-spec parse_deps(binary(), [dep()]) -> {[rebar_app_info:t()], [binary_dep()]}. |
|
|
|
parse_deps(DepsDir, Deps) -> |
|
|
|
lists:foldl(fun({Name, Vsn}, {SrcDepsAcc, GoalsAcc}) -> |
|
|
|
lists:foldl(fun({Name, Vsn}, {SrcDepsAcc, BinaryDepsAcc}) -> |
|
|
|
{SrcDepsAcc, [parse_goal(ec_cnv:to_binary(Name) |
|
|
|
,ec_cnv:to_binary(Vsn)) | GoalsAcc]}; |
|
|
|
(Name, {SrcDepsAcc, GoalsAcc}) when is_atom(Name) -> |
|
|
|
{SrcDepsAcc, [ec_cnv:to_binary(Name) | GoalsAcc]}; |
|
|
|
({Name, _, Source}, {SrcDepsAcc, GoalsAcc}) -> |
|
|
|
,ec_cnv:to_binary(Vsn)) | BinaryDepsAcc]}; |
|
|
|
(Name, {SrcDepsAcc, BinaryDepsAcc}) when is_atom(Name) -> |
|
|
|
{SrcDepsAcc, [ec_cnv:to_binary(Name) | BinaryDepsAcc]}; |
|
|
|
({Name, _, Source}, {SrcDepsAcc, BinaryDepsAcc}) -> |
|
|
|
{ok, Dep} = rebar_app_info:new(Name), |
|
|
|
Dep1 = rebar_app_info:source( |
|
|
|
rebar_app_info:dir(Dep, get_deps_dir(DepsDir, Name)), Source), |
|
|
|
{[Dep1 | SrcDepsAcc], GoalsAcc} |
|
|
|
{[Dep1 | SrcDepsAcc], BinaryDepsAcc} |
|
|
|
end, {[], []}, Deps). |
|
|
|
|
|
|
|
-spec parse_goal(binary(), binary()) -> binary_dep(). |
|
|
|
parse_goal(Name, Constraint) -> |
|
|
|
case re:run(Constraint, "([^\\d]*)(\\d.*)", [{capture, [1,2], binary}]) of |
|
|
|
{match, [<<>>, Vsn]} -> |
|
|
|