|
|
@ -36,7 +36,8 @@ |
|
|
|
-include_lib("providers/include/providers.hrl"). |
|
|
|
|
|
|
|
-export([handle_deps/3, |
|
|
|
handle_deps/4]). |
|
|
|
handle_deps/4, |
|
|
|
handle_deps/5]). |
|
|
|
|
|
|
|
-export_type([dep/0]). |
|
|
|
|
|
|
@ -74,10 +75,12 @@ do(State) -> |
|
|
|
|
|
|
|
{SrcApps, State1} = |
|
|
|
lists:foldl(fun(Profile, {SrcAppsAcc, StateAcc}) -> |
|
|
|
Locks = rebar_state:get(StateAcc, {locks, Profile}, []), |
|
|
|
{ok, NewSrcApps, NewState} = |
|
|
|
handle_deps(Profile |
|
|
|
,StateAcc |
|
|
|
,rebar_state:get(StateAcc, {deps, Profile}, [])), |
|
|
|
,rebar_state:get(StateAcc, {deps, Profile}, []) |
|
|
|
,Locks), |
|
|
|
{NewSrcApps++SrcAppsAcc, NewState} |
|
|
|
end, {[], State}, lists:reverse(Profiles)), |
|
|
|
|
|
|
@ -123,22 +126,29 @@ format_error(Reason) -> |
|
|
|
-spec handle_deps(atom(), rebar_state:t(), list()) -> |
|
|
|
{ok, [rebar_app_info:t()], rebar_state:t()} | {error, string()}. |
|
|
|
handle_deps(Profile, State, Deps) -> |
|
|
|
handle_deps(Profile, State, Deps, false). |
|
|
|
handle_deps(Profile, State, Deps, false, []). |
|
|
|
|
|
|
|
-spec handle_deps(atom(), rebar_state:t(), list(), boolean() | {true, binary(), integer()}) |
|
|
|
-spec handle_deps(atom(), rebar_state:t(), list(), list() | boolean()) -> |
|
|
|
{ok, [rebar_app_info:t()], rebar_state:t()} | {error, string()}. |
|
|
|
handle_deps(Profile, State, Deps, Update) when is_boolean(Update) -> |
|
|
|
handle_deps(Profile, State, Deps, Update, []); |
|
|
|
handle_deps(Profile, State, Deps, Locks) when is_list(Locks) -> |
|
|
|
handle_deps(Profile, State, Deps, false, Locks). |
|
|
|
|
|
|
|
-spec handle_deps(atom(), rebar_state:t(), list(), boolean() | {true, binary(), integer()}, list()) |
|
|
|
-> {ok, [rebar_app_info:t()], rebar_state:t()} | {error, string()}. |
|
|
|
handle_deps(_Profile, State, [], _) -> |
|
|
|
handle_deps(_Profile, State, [], _, _) -> |
|
|
|
{ok, [], State}; |
|
|
|
handle_deps(Profile, State, Deps, Update) -> |
|
|
|
handle_deps(Profile, State, Deps, Update, Locks) -> |
|
|
|
%% Read in package index and dep graph |
|
|
|
{Packages, Graph} = rebar_packages:get_packages(State), |
|
|
|
%% Split source deps from pkg deps, needed to keep backwards compatibility |
|
|
|
DepsDir = rebar_dir:deps_dir(State), |
|
|
|
{SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps), |
|
|
|
{SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, State, Locks, 0), |
|
|
|
|
|
|
|
%% Fetch transitive src deps |
|
|
|
{State1, SrcApps, PkgDeps1, Seen} = |
|
|
|
update_src_deps(Profile, 0, SrcDeps, PkgDeps, [], State, Update, sets:new()), |
|
|
|
update_src_deps(Profile, 0, SrcDeps, PkgDeps, [], State, Update, sets:new(), Locks), |
|
|
|
|
|
|
|
{Solved, State2} = case PkgDeps1 of |
|
|
|
[] -> %% No pkg deps |
|
|
@ -156,6 +166,7 @@ handle_deps(Profile, State, Deps, Update) -> |
|
|
|
end, |
|
|
|
update_pkg_deps(Profile, S, Packages, Update, Seen, State1) |
|
|
|
end, |
|
|
|
|
|
|
|
AllDeps = lists:ukeymerge(2 |
|
|
|
,lists:ukeysort(2, SrcApps) |
|
|
|
,lists:ukeysort(2, Solved)), |
|
|
@ -176,7 +187,7 @@ update_pkg_deps(Profile, Pkgs, Packages, Update, Seen, State) -> |
|
|
|
AppInfo = package_to_app(DepsDir |
|
|
|
,Packages |
|
|
|
,Pkg), |
|
|
|
{SeenAcc1, StateAcc1} = maybe_lock(Profile, AppInfo, SeenAcc, StateAcc), |
|
|
|
{SeenAcc1, StateAcc1} = maybe_lock(Profile, AppInfo, SeenAcc, StateAcc, 0), |
|
|
|
case maybe_fetch(AppInfo, Update, SeenAcc1) of |
|
|
|
true -> |
|
|
|
{[AppInfo | Acc], SeenAcc1, StateAcc1}; |
|
|
@ -186,14 +197,14 @@ update_pkg_deps(Profile, Pkgs, Packages, Update, Seen, State) -> |
|
|
|
end, {[], Seen, State}, Pkgs), |
|
|
|
{Solved, State1}. |
|
|
|
|
|
|
|
maybe_lock(Profile, AppInfo, Seen, State) -> |
|
|
|
maybe_lock(Profile, AppInfo, Seen, State, Level) -> |
|
|
|
Name = rebar_app_info:name(AppInfo), |
|
|
|
case Profile of |
|
|
|
default -> |
|
|
|
case sets:is_element(Name, Seen) of |
|
|
|
false -> |
|
|
|
{sets:add_element(Name, Seen), |
|
|
|
rebar_state:lock(State, AppInfo)}; |
|
|
|
rebar_state:lock(State, rebar_app_info:dep_level(AppInfo, Level))}; |
|
|
|
true -> |
|
|
|
{Seen, State} |
|
|
|
end; |
|
|
@ -215,17 +226,17 @@ package_to_app(DepsDir, Packages, {Name, Vsn}) -> |
|
|
|
rebar_app_info:source(AppInfo2, {pkg, Name, Vsn, Link}) |
|
|
|
end. |
|
|
|
|
|
|
|
-spec update_src_deps(atom(), non_neg_integer(), list(), list(), list(), rebar_state:t(), boolean(), sets:set(binary())) -> {rebar_state:t(), list(), list(), sets:set(binary())}. |
|
|
|
update_src_deps(Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Update, Seen) -> |
|
|
|
case lists:foldl(fun(AppInfo, {SrcDepsAcc, PkgDepsAcc, SrcAppsAcc, StateAcc, SeenAcc}) -> |
|
|
|
-spec update_src_deps(atom(), non_neg_integer(), list(), list(), list(), rebar_state:t(), boolean(), sets:set(binary()), list()) -> {rebar_state:t(), list(), list(), sets:set(binary())}. |
|
|
|
update_src_deps(Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Update, Seen, Locks) -> |
|
|
|
case lists:foldl(fun(AppInfo, {SrcDepsAcc, PkgDepsAcc, SrcAppsAcc, StateAcc, SeenAcc, LocksAcc}) -> |
|
|
|
%% If not seen, add to list of locks to write out |
|
|
|
case sets:is_element(rebar_app_info:name(AppInfo), SeenAcc) of |
|
|
|
true -> |
|
|
|
warn_skip_deps(AppInfo), |
|
|
|
{SrcDepsAcc, PkgDepsAcc, SrcAppsAcc, StateAcc, SeenAcc}; |
|
|
|
{SrcDepsAcc, PkgDepsAcc, SrcAppsAcc, StateAcc, SeenAcc, LocksAcc}; |
|
|
|
false -> |
|
|
|
{SeenAcc1, StateAcc1} = maybe_lock(Profile, AppInfo, SeenAcc, StateAcc), |
|
|
|
{SrcDepsAcc1, PkgDepsAcc1, SrcAppsAcc1, StateAcc2} = |
|
|
|
{SeenAcc1, StateAcc1} = maybe_lock(Profile, AppInfo, SeenAcc, StateAcc, Level), |
|
|
|
{SrcDepsAcc1, PkgDepsAcc1, SrcAppsAcc1, StateAcc2, LocksAcc1} = |
|
|
|
case Update of |
|
|
|
{true, UpdateName, UpdateLevel} -> |
|
|
|
handle_update(AppInfo |
|
|
@ -235,7 +246,8 @@ update_src_deps(Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Update, Seen) |
|
|
|
,PkgDepsAcc |
|
|
|
,SrcAppsAcc |
|
|
|
,Level |
|
|
|
,StateAcc1); |
|
|
|
,StateAcc1 |
|
|
|
,LocksAcc); |
|
|
|
_ -> |
|
|
|
maybe_fetch(AppInfo, false, SeenAcc1), |
|
|
|
handle_dep(AppInfo |
|
|
@ -243,22 +255,22 @@ update_src_deps(Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Update, Seen) |
|
|
|
,PkgDepsAcc |
|
|
|
,SrcAppsAcc |
|
|
|
,Level |
|
|
|
,StateAcc1) |
|
|
|
,StateAcc1 |
|
|
|
,LocksAcc) |
|
|
|
end, |
|
|
|
{SrcDepsAcc1, PkgDepsAcc1, SrcAppsAcc1, StateAcc2, SeenAcc1} |
|
|
|
{SrcDepsAcc1, PkgDepsAcc1, SrcAppsAcc1, StateAcc2, SeenAcc1, LocksAcc1} |
|
|
|
end |
|
|
|
end, |
|
|
|
{[], PkgDeps, SrcApps, State, Seen}, |
|
|
|
{[], PkgDeps, SrcApps, State, Seen, Locks}, |
|
|
|
lists:sort(SrcDeps)) of |
|
|
|
{[], NewPkgDeps, NewSrcApps, State1, Seen1} -> |
|
|
|
{[], NewPkgDeps, NewSrcApps, State1, Seen1, _NewLocks} -> |
|
|
|
{State1, NewSrcApps, NewPkgDeps, Seen1}; |
|
|
|
{NewSrcDeps, NewPkgDeps, NewSrcApps, State1, Seen1} -> |
|
|
|
update_src_deps(Profile, Level+1, NewSrcDeps, NewPkgDeps, NewSrcApps, State1, Update, Seen1) |
|
|
|
{NewSrcDeps, NewPkgDeps, NewSrcApps, State1, Seen1, NewLocks} -> |
|
|
|
update_src_deps(Profile, Level+1, NewSrcDeps, NewPkgDeps, NewSrcApps, State1, Update, Seen1, NewLocks) |
|
|
|
end. |
|
|
|
|
|
|
|
handle_update(AppInfo, UpdateName, UpdateLevel, SrcDeps, PkgDeps, SrcApps, Level, State) -> |
|
|
|
handle_update(AppInfo, UpdateName, UpdateLevel, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) -> |
|
|
|
Name = rebar_app_info:name(AppInfo), |
|
|
|
Locks = rebar_state:get(State, locks, []), |
|
|
|
{_, _, _, DepLevel} = lists:keyfind(Name, 1, Locks), |
|
|
|
case UpdateLevel < DepLevel |
|
|
|
orelse Name =:= UpdateName of |
|
|
@ -270,39 +282,52 @@ handle_update(AppInfo, UpdateName, UpdateLevel, SrcDeps, PkgDeps, SrcApps, Level |
|
|
|
,PkgDeps |
|
|
|
,SrcApps |
|
|
|
,Level |
|
|
|
,State); |
|
|
|
,State |
|
|
|
,Locks); |
|
|
|
|
|
|
|
false -> |
|
|
|
{SrcDeps, PkgDeps, SrcApps, State} |
|
|
|
{SrcDeps, PkgDeps, SrcApps, State, Locks} |
|
|
|
end; |
|
|
|
false -> |
|
|
|
{SrcDeps, PkgDeps, SrcApps, State} |
|
|
|
{SrcDeps, PkgDeps, SrcApps, State, Locks} |
|
|
|
end. |
|
|
|
|
|
|
|
handle_dep(AppInfo, SrcDeps, PkgDeps, SrcApps, Level, State) -> |
|
|
|
handle_dep(AppInfo, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) -> |
|
|
|
DepsDir = rebar_dir:deps_dir(State), |
|
|
|
{AppInfo1, NewSrcDeps, NewPkgDeps} = |
|
|
|
handle_dep(State, DepsDir, AppInfo), |
|
|
|
{AppInfo1, NewSrcDeps, NewPkgDeps, NewLocks} = |
|
|
|
handle_dep(State, DepsDir, AppInfo, Locks, Level), |
|
|
|
AppInfo2 = rebar_app_info:dep_level(AppInfo1, Level), |
|
|
|
{NewSrcDeps ++ SrcDeps |
|
|
|
,NewPkgDeps++PkgDeps |
|
|
|
,[AppInfo2 | SrcApps] |
|
|
|
,State}. |
|
|
|
,State |
|
|
|
,NewLocks}. |
|
|
|
|
|
|
|
-spec handle_dep(rebar_state:t(), file:filename_all(), rebar_app_info:t()) -> |
|
|
|
-spec handle_dep(rebar_state:t(), file:filename_all(), rebar_app_info:t(), list(), integer()) -> |
|
|
|
{rebar_app_info:t(), [rebar_app_info:t()], [pkg_dep()]}. |
|
|
|
handle_dep(State, DepsDir, AppInfo) -> |
|
|
|
handle_dep(State, DepsDir, AppInfo, Locks, Level) -> |
|
|
|
Profiles = rebar_state:current_profiles(State), |
|
|
|
Name = rebar_app_info:name(AppInfo), |
|
|
|
|
|
|
|
C = rebar_config:consult(rebar_app_info:dir(AppInfo)), |
|
|
|
S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(AppInfo)), |
|
|
|
S1 = rebar_state:apply_profiles(S, Profiles), |
|
|
|
Deps = rebar_state:get(S1, deps, []), |
|
|
|
AppInfo1 = rebar_app_info:deps(AppInfo, rebar_state:deps_names(Deps)), |
|
|
|
{SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps), |
|
|
|
{AppInfo1, SrcDeps, PkgDeps}. |
|
|
|
|
|
|
|
S = rebar_app_info:state(AppInfo), |
|
|
|
S1 = rebar_state:new(S, C, rebar_app_info:dir(AppInfo)), |
|
|
|
S2 = rebar_state:apply_profiles(S1, Profiles), |
|
|
|
S3 = rebar_state:apply_overrides(S2, Name), |
|
|
|
AppInfo1 = rebar_app_info:state(AppInfo, S3), |
|
|
|
|
|
|
|
Deps = rebar_state:get(S3, deps, []), |
|
|
|
|
|
|
|
%% Update lock level to be the level the dep will have in this dep tree |
|
|
|
NewLocks = [{DepName, Source, LockLevel+Level} || |
|
|
|
{DepName, Source, LockLevel} <- rebar_state:get(S3, {locks, default}, [])], |
|
|
|
AppInfo2 = rebar_app_info:deps(AppInfo1, rebar_state:deps_names(Deps)), |
|
|
|
{SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, S3, Locks, Level), |
|
|
|
{AppInfo2, SrcDeps, PkgDeps, Locks++NewLocks}. |
|
|
|
|
|
|
|
-spec maybe_fetch(rebar_app_info:t(), boolean() | {true, binary(), integer()}, |
|
|
|
sets:set(binary())) -> boolean(). |
|
|
|
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), |
|
|
@ -355,39 +380,64 @@ maybe_fetch(AppInfo, Update, Seen) -> |
|
|
|
end |
|
|
|
end. |
|
|
|
|
|
|
|
-spec parse_deps(binary(), list()) -> {[rebar_app_info:t()], [pkg_dep()]}. |
|
|
|
parse_deps(DepsDir, Deps) -> |
|
|
|
lists:foldl(fun({Name, Vsn}, {SrcDepsAcc, PkgDepsAcc}) when is_list(Vsn) -> |
|
|
|
{SrcDepsAcc, [parse_goal(ec_cnv:to_binary(Name) |
|
|
|
,ec_cnv:to_binary(Vsn)) | PkgDepsAcc]}; |
|
|
|
(Name, {SrcDepsAcc, PkgDepsAcc}) when is_atom(Name) -> |
|
|
|
{SrcDepsAcc, [ec_cnv:to_binary(Name) | PkgDepsAcc]}; |
|
|
|
({Name, Source}, {SrcDepsAcc, PkgDepsAcc}) when is_tuple (Source) -> |
|
|
|
Dep = new_dep(DepsDir, Name, [], Source), |
|
|
|
{[Dep | SrcDepsAcc], PkgDepsAcc}; |
|
|
|
({Name, Source}, {SrcDepsAcc, PkgDepsAcc}) when is_tuple (Source) -> |
|
|
|
Dep = new_dep(DepsDir, Name, [], Source), |
|
|
|
{[Dep | SrcDepsAcc], PkgDepsAcc}; |
|
|
|
({Name, _Vsn, Source}, {SrcDepsAcc, PkgDepsAcc}) when is_tuple (Source) -> |
|
|
|
Dep = new_dep(DepsDir, Name, [], Source), |
|
|
|
{[Dep | SrcDepsAcc], PkgDepsAcc}; |
|
|
|
({Name, Source, Level}, {SrcDepsAcc, PkgDepsAcc}) when is_tuple (Source) |
|
|
|
, is_integer(Level) -> |
|
|
|
Dep = new_dep(DepsDir, Name, [], Source), |
|
|
|
{[Dep | SrcDepsAcc], PkgDepsAcc} |
|
|
|
-spec parse_deps(binary(), list(), list(), list(), integer()) -> {[rebar_app_info:t()], [pkg_dep()]}. |
|
|
|
parse_deps(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(Dep, Acc, DepsDir, State); |
|
|
|
LockedDep -> |
|
|
|
LockedLevel = element(3, LockedDep), |
|
|
|
case LockedLevel > Level of |
|
|
|
true -> |
|
|
|
parse_dep(Dep, Acc, DepsDir, State); |
|
|
|
false -> |
|
|
|
parse_dep(LockedDep, Acc, DepsDir, State) |
|
|
|
end |
|
|
|
end |
|
|
|
end, {[], []}, Deps). |
|
|
|
|
|
|
|
new_dep(DepsDir, Name, Vsn, Source) -> |
|
|
|
Dirs = [ec_cnv:to_list(filename:join(DepsDir, Name))], |
|
|
|
{ok, Dep} = case ec_lists:search(fun(Dir) -> |
|
|
|
rebar_app_info:discover(Dir) |
|
|
|
end, Dirs) of |
|
|
|
{ok, App, _} -> |
|
|
|
parse_dep({Name, Vsn}, {SrcDepsAcc, PkgDepsAcc}, _DepsDir, _State) when is_list(Vsn) -> |
|
|
|
{SrcDepsAcc, [parse_goal(ec_cnv:to_binary(Name) |
|
|
|
,ec_cnv:to_binary(Vsn)) | PkgDepsAcc]}; |
|
|
|
parse_dep(Name, {SrcDepsAcc, PkgDepsAcc}, _DepsDir, _State) when is_atom(Name) -> |
|
|
|
{SrcDepsAcc, [ec_cnv:to_binary(Name) | PkgDepsAcc]}; |
|
|
|
parse_dep({Name, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) -> |
|
|
|
Dep = new_dep(DepsDir, Name, [], Source, State), |
|
|
|
{[Dep | SrcDepsAcc], PkgDepsAcc}; |
|
|
|
parse_dep({Name, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) -> |
|
|
|
Dep = new_dep(DepsDir, Name, [], Source, State), |
|
|
|
{[Dep | SrcDepsAcc], PkgDepsAcc}; |
|
|
|
parse_dep({Name, _Vsn, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) -> |
|
|
|
Dep = new_dep(DepsDir, Name, [], Source, State), |
|
|
|
{[Dep | SrcDepsAcc], PkgDepsAcc}; |
|
|
|
parse_dep({Name, Source, Level}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) |
|
|
|
, is_integer(Level) -> |
|
|
|
Dep = new_dep(DepsDir, Name, [], Source, State), |
|
|
|
{[Dep | SrcDepsAcc], PkgDepsAcc}. |
|
|
|
|
|
|
|
new_dep(DepsDir, Name, Vsn, Source, State) -> |
|
|
|
Dir = ec_cnv:to_list(filename:join(DepsDir, Name)), |
|
|
|
{ok, Dep} = 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, |
|
|
|
rebar_app_info:source(Dep, Source). |
|
|
|
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)), |
|
|
|
rebar_app_info:source(Dep1, Source). |
|
|
|
|
|
|
|
-spec parse_goal(binary(), binary()) -> pkg_dep(). |
|
|
|
parse_goal(Name, Constraint) -> |
|
|
|