|
@ -42,6 +42,10 @@ |
|
|
-define(PROVIDER, deps). |
|
|
-define(PROVIDER, deps). |
|
|
-define(DEPS, [app_discovery]). |
|
|
-define(DEPS, [app_discovery]). |
|
|
|
|
|
|
|
|
|
|
|
-record(dep, {name :: binary(), |
|
|
|
|
|
vsn :: binary(), |
|
|
|
|
|
source :: binary()}). |
|
|
|
|
|
|
|
|
%% =================================================================== |
|
|
%% =================================================================== |
|
|
%% Public API |
|
|
%% Public API |
|
|
%% =================================================================== |
|
|
%% =================================================================== |
|
@ -54,7 +58,7 @@ init(State) -> |
|
|
deps = ?DEPS, |
|
|
deps = ?DEPS, |
|
|
example = "rebar deps", |
|
|
example = "rebar deps", |
|
|
short_desc = "Install dependencies", |
|
|
short_desc = "Install dependencies", |
|
|
desc = info_help("Install dependencies"), |
|
|
|
|
|
|
|
|
desc = info("Install dependencies"), |
|
|
opts = []}), |
|
|
opts = []}), |
|
|
{ok, State1}. |
|
|
{ok, State1}. |
|
|
|
|
|
|
|
@ -62,34 +66,32 @@ init(State) -> |
|
|
do(State) -> |
|
|
do(State) -> |
|
|
%% Read in package index and dep graph |
|
|
%% Read in package index and dep graph |
|
|
{Packages, Graph} = get_packages(State), |
|
|
{Packages, Graph} = get_packages(State), |
|
|
PtDeps = rebar_state:get(State, pt_deps, []), |
|
|
|
|
|
SrcDeps = rebar_state:get(State, src_deps, []), |
|
|
|
|
|
{State1, _PtDeps1} = update_deps(State, PtDeps), |
|
|
|
|
|
{State1, SrcDeps1} = update_deps(State, SrcDeps), |
|
|
|
|
|
|
|
|
|
|
|
case rebar_state:get(State1, deps, []) of |
|
|
|
|
|
|
|
|
case rebar_state:get(State, deps, []) of |
|
|
[] -> |
|
|
[] -> |
|
|
{ok, rebar_state:set(State1, deps, SrcDeps1)}; |
|
|
|
|
|
|
|
|
{ok, State}; |
|
|
Deps -> |
|
|
Deps -> |
|
|
Goals = lists:map(fun({Name, Vsn}) -> |
|
|
|
|
|
{atom_to_binary(Name, utf8), Vsn}; |
|
|
|
|
|
(Name) -> |
|
|
|
|
|
atom_to_binary(Name, utf8) |
|
|
|
|
|
end, Deps), |
|
|
|
|
|
{ok, Solved} = rlx_depsolver:solve(Graph, Goals), |
|
|
|
|
|
M = lists:map(fun({Name, Vsn}) -> |
|
|
|
|
|
FmtVsn = to_binary(rlx_depsolver:format_version(Vsn)), |
|
|
|
|
|
{ok, P} = dict:find({Name, FmtVsn}, Packages), |
|
|
|
|
|
Link = proplists:get_value(<<"link">>, P), |
|
|
|
|
|
{Name, Vsn, {Name |
|
|
|
|
|
,FmtVsn |
|
|
|
|
|
,Link}} |
|
|
|
|
|
end, Solved), |
|
|
|
|
|
|
|
|
|
|
|
{State2, Deps1} = update_deps(State1, M), |
|
|
|
|
|
State3 = rebar_state:set(State2, deps, Deps1), |
|
|
|
|
|
|
|
|
|
|
|
{ok, rebar_state:set(State3, goals, Goals)} |
|
|
|
|
|
|
|
|
%% Split source deps form binary deps, needed to keep backwards compatibility |
|
|
|
|
|
case parse_deps(Deps) of |
|
|
|
|
|
{SrcDeps, []} -> |
|
|
|
|
|
{State1, SrcDeps1} = update_src_deps(State, SrcDeps), |
|
|
|
|
|
{ok, rebar_state:set(State1, deps, SrcDeps1)}; |
|
|
|
|
|
{SrcDeps, Goals} -> |
|
|
|
|
|
{State1, _SrcDeps1} = update_src_deps(State, SrcDeps), |
|
|
|
|
|
{ok, Solved} = rlx_depsolver:solve(Graph, Goals), |
|
|
|
|
|
M = lists:map(fun({Name, Vsn}) -> |
|
|
|
|
|
FmtVsn = to_binary(rlx_depsolver:format_version(Vsn)), |
|
|
|
|
|
{ok, P} = dict:find({Name, FmtVsn}, Packages), |
|
|
|
|
|
Link = proplists:get_value(<<"link">>, P), |
|
|
|
|
|
{Name, Vsn, {Name |
|
|
|
|
|
,FmtVsn |
|
|
|
|
|
,Link}} |
|
|
|
|
|
end, Solved), |
|
|
|
|
|
|
|
|
|
|
|
{State2, Deps1} = update_deps(State1, M), |
|
|
|
|
|
State3 = rebar_state:set(State2, deps, Deps1), |
|
|
|
|
|
{ok, rebar_state:set(State3, goals, Goals)} |
|
|
|
|
|
end |
|
|
end. |
|
|
end. |
|
|
|
|
|
|
|
|
update_deps(State, Deps) -> |
|
|
update_deps(State, Deps) -> |
|
@ -100,75 +102,64 @@ update_deps(State, Deps) -> |
|
|
UnbuiltApps = rebar_app_discover:find_unbuilt_apps([DepsDir]), |
|
|
UnbuiltApps = rebar_app_discover:find_unbuilt_apps([DepsDir]), |
|
|
FoundApps = rebar_app_discover:find_apps([DepsDir]), |
|
|
FoundApps = rebar_app_discover:find_apps([DepsDir]), |
|
|
|
|
|
|
|
|
%% Resolve deps and their dependencies |
|
|
|
|
|
Deps1 = handle_deps(Deps, UnbuiltApps++FoundApps), |
|
|
|
|
|
|
|
|
download_missing_deps(State, DepsDir, FoundApps, UnbuiltApps, Deps). |
|
|
|
|
|
|
|
|
case download_missing_deps(State, DepsDir, FoundApps, UnbuiltApps, Deps1) of |
|
|
|
|
|
{State1, []} -> |
|
|
|
|
|
{State1, Deps1}; |
|
|
|
|
|
{State1, _} -> |
|
|
|
|
|
update_deps(State1, Deps1) |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
update_src_deps(State, Deps) -> |
|
|
|
|
|
DepsDir = get_deps_dir(State), |
|
|
|
|
|
|
|
|
handle_deps(Deps, Found) -> |
|
|
|
|
|
NewDeps = |
|
|
|
|
|
lists:foldl(fun(X, DepsAcc) -> |
|
|
|
|
|
C = rebar_config:consult(rebar_app_info:dir(X)), |
|
|
|
|
|
S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(X)), |
|
|
|
|
|
LocalDeps = rebar_state:get(S, deps, []), |
|
|
|
|
|
[LocalDeps | DepsAcc] |
|
|
|
|
|
end, [], Found), |
|
|
|
|
|
NewDeps1 = lists:flatten(NewDeps), |
|
|
|
|
|
|
|
|
|
|
|
%% Weed out duplicates |
|
|
|
|
|
lists:umerge(fun(A, B) -> |
|
|
|
|
|
dep_name(A) =:= dep_name(B) |
|
|
|
|
|
end, lists:usort(Deps), lists:usort(NewDeps1)). |
|
|
|
|
|
|
|
|
|
|
|
dep_name({Name, _, _}) -> |
|
|
|
|
|
Name; |
|
|
|
|
|
dep_name({Name, _}) -> |
|
|
|
|
|
Name; |
|
|
|
|
|
dep_name(Name) -> |
|
|
|
|
|
Name. |
|
|
|
|
|
|
|
|
%% Find available apps to fulfill dependencies |
|
|
|
|
|
%% Should only have to do this once, not every iteration |
|
|
|
|
|
UnbuiltApps = rebar_app_discover:find_unbuilt_apps([DepsDir]), |
|
|
|
|
|
FoundApps = rebar_app_discover:find_apps([DepsDir]), |
|
|
|
|
|
|
|
|
|
|
|
%% Resolve deps and their dependencies |
|
|
|
|
|
Deps1 = handle_src_deps(Deps, UnbuiltApps++FoundApps), |
|
|
|
|
|
{State1, Missing} = download_missing_deps(State, DepsDir, FoundApps, UnbuiltApps, Deps1), |
|
|
|
|
|
case dict:is_empty(Missing) of |
|
|
|
|
|
true -> |
|
|
|
|
|
{State1, Deps1}; |
|
|
|
|
|
false -> |
|
|
|
|
|
update_src_deps(State1, Missing) |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
to_binary(X) when is_binary(X) -> |
|
|
|
|
|
X; |
|
|
|
|
|
to_binary(X) when is_atom(X) -> |
|
|
|
|
|
atom_to_binary(X, utf8); |
|
|
|
|
|
to_binary(X) when is_list(X) -> |
|
|
|
|
|
iolist_to_binary(X). |
|
|
|
|
|
|
|
|
handle_src_deps(Deps, Found) -> |
|
|
|
|
|
lists:foldl(fun(X, DepsAcc) -> |
|
|
|
|
|
C = rebar_config:consult(rebar_app_info:dir(X)), |
|
|
|
|
|
S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(X)), |
|
|
|
|
|
{ParsedDeps, _Goals} = parse_deps(rebar_state:get(S, deps, [])), |
|
|
|
|
|
dict:merge(fun(_K, V1, _V2) -> V1 end, DepsAcc, ParsedDeps) |
|
|
|
|
|
end, Deps, Found). |
|
|
|
|
|
|
|
|
download_missing_deps(State, DepsDir, Found, Unbuilt, Deps) -> |
|
|
download_missing_deps(State, DepsDir, Found, Unbuilt, Deps) -> |
|
|
Missing = lists:filter(fun(X) -> |
|
|
|
|
|
not lists:any(fun(F) -> |
|
|
|
|
|
to_binary(dep_name(X)) =:= to_binary(rebar_app_info:name(F)) |
|
|
|
|
|
end, Found++Unbuilt) |
|
|
|
|
|
end, Deps), |
|
|
|
|
|
lists:map(fun({DepName, _DepVsn, DepSource}) -> |
|
|
|
|
|
TargetDir = get_deps_dir(DepsDir, DepName), |
|
|
|
|
|
case filelib:is_dir(TargetDir) of |
|
|
|
|
|
true -> |
|
|
|
|
|
ok; |
|
|
|
|
|
false -> |
|
|
|
|
|
?INFO("Fetching ~s ~s~n", [DepName |
|
|
|
|
|
,element(2, DepSource)]), |
|
|
|
|
|
rebar_fetch:download_source(TargetDir, DepSource), |
|
|
|
|
|
case rebar_app_discover:find_unbuilt_apps([TargetDir]) of |
|
|
|
|
|
[AppSrc] -> |
|
|
|
|
|
C = rebar_config:consult(rebar_app_info:dir(AppSrc)), |
|
|
|
|
|
S = rebar_state:new(rebar_state:new() |
|
|
|
|
|
,C |
|
|
|
|
|
,rebar_app_info:dir(AppSrc)), |
|
|
|
|
|
_AppInfo1 = rebar_prv_app_builder:build(S, AppSrc); |
|
|
|
|
|
[] -> |
|
|
|
|
|
[] |
|
|
|
|
|
end |
|
|
|
|
|
end |
|
|
|
|
|
end, Missing), |
|
|
|
|
|
|
|
|
|
|
|
{State, []}. |
|
|
|
|
|
|
|
|
Missing = |
|
|
|
|
|
dict:filter(fun(Key, _) -> |
|
|
|
|
|
not lists:any(fun(F) -> |
|
|
|
|
|
Key =:= to_binary(rebar_app_info:name(F)) |
|
|
|
|
|
end, Found++Unbuilt) |
|
|
|
|
|
end, Deps), |
|
|
|
|
|
dict:map(fun(_Key, #dep{name=Name, source=Source}) -> |
|
|
|
|
|
TargetDir = get_deps_dir(DepsDir, Name), |
|
|
|
|
|
case filelib:is_dir(TargetDir) of |
|
|
|
|
|
true -> |
|
|
|
|
|
ok; |
|
|
|
|
|
false -> |
|
|
|
|
|
?INFO("Fetching ~s ~s~n", [Name |
|
|
|
|
|
,element(2, Source)]), |
|
|
|
|
|
rebar_fetch:download_source(TargetDir, Source), |
|
|
|
|
|
case rebar_app_discover:find_unbuilt_apps([TargetDir]) of |
|
|
|
|
|
[AppSrc] -> |
|
|
|
|
|
C = rebar_config:consult(rebar_app_info:dir(AppSrc)), |
|
|
|
|
|
S = rebar_state:new(rebar_state:new() |
|
|
|
|
|
,C |
|
|
|
|
|
,rebar_app_info:dir(AppSrc)), |
|
|
|
|
|
rebar_prv_app_builder:build(S, AppSrc); |
|
|
|
|
|
[] -> |
|
|
|
|
|
[] |
|
|
|
|
|
end |
|
|
|
|
|
end |
|
|
|
|
|
end, Missing), |
|
|
|
|
|
|
|
|
|
|
|
{State, Missing}. |
|
|
|
|
|
|
|
|
%% set REBAR_DEPS_DIR and ERL_LIBS environment variables |
|
|
%% set REBAR_DEPS_DIR and ERL_LIBS environment variables |
|
|
setup_env(State) -> |
|
|
setup_env(State) -> |
|
@ -200,6 +191,40 @@ get_deps_dir(DepsDir, App) -> |
|
|
%% Internal functions |
|
|
%% Internal functions |
|
|
%% =================================================================== |
|
|
%% =================================================================== |
|
|
|
|
|
|
|
|
|
|
|
new({Name, Vsn, Source})-> |
|
|
|
|
|
#dep{name=to_binary(Name), vsn=to_binary(Vsn), source=Source}; |
|
|
|
|
|
new(Name) -> |
|
|
|
|
|
#dep{name=to_binary(Name)}. |
|
|
|
|
|
|
|
|
|
|
|
-spec name(record(dep)) -> binary(). |
|
|
|
|
|
name(#dep{name=Name}) -> |
|
|
|
|
|
Name. |
|
|
|
|
|
|
|
|
|
|
|
-spec vsn(record(dep)) -> binary(). |
|
|
|
|
|
vsn(#dep{vsn=Vsn}) -> |
|
|
|
|
|
Vsn. |
|
|
|
|
|
|
|
|
|
|
|
-spec source(record(dep)) -> tuple(). |
|
|
|
|
|
source(#dep{source=Source}) -> |
|
|
|
|
|
Source. |
|
|
|
|
|
|
|
|
|
|
|
to_binary(X) when is_binary(X) -> |
|
|
|
|
|
X; |
|
|
|
|
|
to_binary(X) when is_atom(X) -> |
|
|
|
|
|
atom_to_binary(X, utf8); |
|
|
|
|
|
to_binary(X) when is_list(X) -> |
|
|
|
|
|
iolist_to_binary(X). |
|
|
|
|
|
|
|
|
|
|
|
parse_deps(Deps) -> |
|
|
|
|
|
lists:foldl(fun({Name, Vsn}, {SrcDepsAcc, GoalsAcc}) -> |
|
|
|
|
|
{SrcDepsAcc, [{to_binary(Name), to_binary(Vsn)} | GoalsAcc]}; |
|
|
|
|
|
(Name, {SrcDepsAcc, GoalsAcc}) when is_atom(Name) -> |
|
|
|
|
|
{SrcDepsAcc, [to_binary(Name) | GoalsAcc]}; |
|
|
|
|
|
(SrcDep, {SrcDepsAcc, GoalsAcc}) -> |
|
|
|
|
|
Dep = new(SrcDep), |
|
|
|
|
|
{dict:store(name(Dep), Dep, SrcDepsAcc), GoalsAcc} |
|
|
|
|
|
end, {dict:new(), []}, Deps). |
|
|
|
|
|
|
|
|
get_packages(State) -> |
|
|
get_packages(State) -> |
|
|
RebarDir = rebar_state:get(State, global_rebar_dir, filename:join(os:getenv("HOME"), ".rebar")), |
|
|
RebarDir = rebar_state:get(State, global_rebar_dir, filename:join(os:getenv("HOME"), ".rebar")), |
|
|
PackagesFile = filename:join(RebarDir, "packages"), |
|
|
PackagesFile = filename:join(RebarDir, "packages"), |
|
@ -217,7 +242,7 @@ get_packages(State) -> |
|
|
{[], rlx_depsolver:new()} |
|
|
{[], rlx_depsolver:new()} |
|
|
end. |
|
|
end. |
|
|
|
|
|
|
|
|
info_help(Description) -> |
|
|
|
|
|
|
|
|
info(Description) -> |
|
|
io_lib:format("~s.~n" |
|
|
io_lib:format("~s.~n" |
|
|
"~n" |
|
|
"~n" |
|
|
"Valid rebar.config options:~n" |
|
|
"Valid rebar.config options:~n" |
|
|