diff options
Diffstat (limited to 'src/rebar_prv_install_deps.erl')
-rw-r--r-- | src/rebar_prv_install_deps.erl | 143 |
1 files changed, 82 insertions, 61 deletions
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index 3e13fc2..ebb877b 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -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]} -> |