diff options
Diffstat (limited to 'src/rebar_prv_install_deps.erl')
-rw-r--r-- | src/rebar_prv_install_deps.erl | 137 |
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. |