summaryrefslogtreecommitdiff
path: root/src/rebar_prv_install_deps.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rebar_prv_install_deps.erl')
-rw-r--r--src/rebar_prv_install_deps.erl137
1 files changed, 86 insertions, 51 deletions
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl
index 522420d..9fb1630 100644
--- a/src/rebar_prv_install_deps.erl
+++ b/src/rebar_prv_install_deps.erl
@@ -68,19 +68,26 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
ProjectApps = rebar_state:project_apps(State),
- {ok, State1} = case rebar_state:get(State, locks, []) of
- [] ->
- handle_deps(State, rebar_state:get(State, deps, []));
- Locks ->
- handle_deps(State, Locks)
- end,
-
- Source = ProjectApps ++ rebar_state:src_apps(State1),
- case rebar_topo:sort_apps(Source) of
- {ok, Sort} ->
- {ok, rebar_state:set(State1, deps_to_build, lists:dropwhile(fun rebar_app_info:valid/1, Sort -- ProjectApps))};
- {error, Error} ->
- {error, Error}
+ try
+ {ok, State1} = case rebar_state:get(State, locks, []) of
+ [] ->
+ handle_deps(State, rebar_state:get(State, deps, []));
+ Locks ->
+ handle_deps(State, Locks)
+ end,
+
+ Source = ProjectApps ++ rebar_state:src_apps(State1),
+ case rebar_topo:sort_apps(Source) of
+ {ok, Sort} ->
+ {ok, rebar_state:set(State1, deps_to_build,
+ lists:dropwhile(fun rebar_app_info:valid/1, Sort -- ProjectApps))};
+ {error, Error} ->
+ {error, Error}
+ end
+ catch
+ %% maybe_fetch will maybe_throw an exception to break out of some loops
+ _:Reason ->
+ {error, Reason}
end.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
@@ -102,7 +109,7 @@ handle_deps(State, Deps) ->
handle_deps(State, Deps, false).
-spec handle_deps(rebar_state:t(), [dep()], boolean() | {true, binary(), integer()})
- -> {ok, rebar_state:t()}.
+ -> {ok, rebar_state:t()} | {error, string()}.
handle_deps(State, [], _) ->
{ok, State};
handle_deps(State, Deps, Update) ->
@@ -116,10 +123,11 @@ handle_deps(State, Deps, Update) ->
SrcDeps),
%% Fetch transitive src deps
- State2 = update_src_deps(0, State1, Update),
+ {State2, _Seen} = update_src_deps(0, State1, Update, sets:new()),
+
Solved = case rebar_state:pkg_deps(State2) of
[] -> %% No pkg deps
- [];
+ [];
PkgDeps1 ->
%% Find pkg deps needed
{ok, S} = rlx_depsolver:solve(Graph, PkgDeps1),
@@ -128,12 +136,12 @@ handle_deps(State, Deps, Update) ->
AppInfo <- package_to_app(DepsDir
,Packages
,Pkg),
- maybe_fetch(AppInfo, Update)]
+ maybe_fetch(AppInfo, Update, sets:new())]
end,
AllDeps = lists:ukeymerge(2
- ,lists:ukeysort(2, rebar_state:src_apps(State2))
- ,lists:ukeysort(2, Solved)),
+ ,lists:ukeysort(2, rebar_state:src_apps(State2))
+ ,lists:ukeysort(2, Solved)),
%% Sort all apps to build order
State3 = rebar_state:set(State2, all_deps, AllDeps),
{ok, State3}.
@@ -154,37 +162,42 @@ package_to_app(DepsDir, Packages, Pkg={_, Vsn}) ->
{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)),
- [rebar_app_info:source(AppInfo2, Link)]
+ [rebar_app_info:source(AppInfo2, {pkg, Name, FmtVsn, Link})]
end.
--spec update_src_deps(integer(), rebar_state:t(), boolean()) -> rebar_state:t().
-update_src_deps(Level, State, Update) ->
+-spec update_src_deps(integer(), rebar_state:t(), boolean(), sets:set(binary())) ->
+ {rebar_state:t(), [binary()]}.
+update_src_deps(Level, State, Update, Seen) ->
SrcDeps = rebar_state:src_deps(State),
- case lists:foldl(fun(AppInfo, {SrcDepsAcc, PkgDepsAcc, StateAcc}) ->
- case Update of
- {true, UpdateName, UpdateLevel} ->
- handle_update(AppInfo
- ,UpdateName
- ,UpdateLevel
- ,SrcDepsAcc
- ,PkgDepsAcc
- ,Level
- ,StateAcc);
- _ ->
- maybe_fetch(AppInfo, false),
- handle_dep(AppInfo
- ,SrcDepsAcc
- ,PkgDepsAcc
- ,Level
- ,StateAcc)
- end
- end, {[], rebar_state:pkg_deps(State), State}, SrcDeps) of
- {[], NewPkgDeps, State1} ->
- rebar_state:pkg_deps(State1, NewPkgDeps);
- {NewSrcDeps, NewPkgDeps, State1} ->
+ case lists:foldl(fun(AppInfo, {SrcDepsAcc, PkgDepsAcc, StateAcc, SeenAcc}) ->
+ SeenAcc1 = sets:add_element(rebar_app_info:name(AppInfo), SeenAcc),
+ {SrcDepsAcc1, PkgDepsAcc1, StateAcc1} =
+ case Update of
+ {true, UpdateName, UpdateLevel} ->
+ handle_update(AppInfo
+ ,UpdateName
+ ,UpdateLevel
+ ,SrcDepsAcc
+ ,PkgDepsAcc
+ ,Level
+ ,StateAcc);
+ _ ->
+ maybe_fetch(AppInfo, false, SeenAcc),
+ handle_dep(AppInfo
+ ,SrcDepsAcc
+ ,PkgDepsAcc
+ ,Level
+ ,StateAcc)
+
+ end,
+ {SrcDepsAcc1, PkgDepsAcc1, StateAcc1, SeenAcc1}
+ end, {[], rebar_state:pkg_deps(State), State, Seen}, SrcDeps) of
+ {[], NewPkgDeps, State1, Seen1} ->
+ {rebar_state:pkg_deps(State1, NewPkgDeps), Seen1};
+ {NewSrcDeps, NewPkgDeps, State1, Seen1} ->
State2 = rebar_state:pkg_deps(State1, NewPkgDeps),
State3 = rebar_state:src_deps(State2, NewSrcDeps),
- update_src_deps(Level+1, State3, Update)
+ update_src_deps(Level+1, State3, Update, Seen1)
end.
handle_update(AppInfo, UpdateName, UpdateLevel, SrcDeps, PkgDeps, Level, State) ->
@@ -194,7 +207,7 @@ handle_update(AppInfo, UpdateName, UpdateLevel, SrcDeps, PkgDeps, Level, State)
case UpdateLevel < DepLevel
orelse Name =:= UpdateName of
true ->
- case maybe_fetch(AppInfo, true) of
+ case maybe_fetch(AppInfo, true, []) of
true ->
handle_dep(AppInfo
,SrcDeps
@@ -228,8 +241,9 @@ handle_dep(DepsDir, AppInfo) ->
{SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps),
{AppInfo1, SrcDeps, PkgDeps}.
--spec maybe_fetch(rebar_app_info:t(), boolean() | {true, binary(), integer()}) -> boolean().
-maybe_fetch(AppInfo, Update) ->
+-spec maybe_fetch(rebar_app_info:t(), boolean() | {true, binary(), integer()},
+ sets:set(binary())) -> boolean().
+maybe_fetch(AppInfo, Update, Seen) ->
AppDir = ec_cnv:to_list(rebar_app_info:dir(AppInfo)),
Apps = rebar_app_discover:find_apps(["_checkouts"], all),
case rebar_app_utils:find(rebar_app_info:name(AppInfo), Apps) of
@@ -253,10 +267,31 @@ maybe_fetch(AppInfo, Update) ->
true ->
?INFO("Fetching ~s~n", [rebar_app_info:name(AppInfo)]),
Source = rebar_app_info:source(AppInfo),
- rebar_fetch:download_source(AppDir, Source),
- true;
+ case rebar_fetch:download_source(AppDir, Source) of
+ {error, Reason} ->
+ throw(Reason);
+ Result ->
+ Result
+ end;
_ ->
- false
+ case sets:is_element(rebar_app_info:name(AppInfo), Seen) of
+ true ->
+ false;
+ false ->
+ Source = rebar_app_info:source(AppInfo),
+ case rebar_fetch:needs_update(AppDir, Source) of
+ true ->
+ ?INFO("Updating ~s~n", [rebar_app_info:name(AppInfo)]),
+ case rebar_fetch:download_source(AppDir, Source) of
+ {error, Reason} ->
+ throw(Reason);
+ Result ->
+ Result
+ end;
+ false ->
+ false
+ end
+ end
end
end.