summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTristan Sloughter <t@crashfast.com>2014-08-23 21:39:54 -0500
committerTristan Sloughter <t@crashfast.com>2014-08-23 21:39:54 -0500
commit9c6e20d3287e532946a518f1455be8d6ddcf6b14 (patch)
tree4c4ff029a96c21e35af6c2a501aed91afa0bfec3
parentc172a8aaf9b310b3303b704739675bd69bb0b295 (diff)
use dict for deps
-rw-r--r--src/rebar_prv_deps.erl205
1 files changed, 115 insertions, 90 deletions
diff --git a/src/rebar_prv_deps.erl b/src/rebar_prv_deps.erl
index 4d72133..0e5cb31 100644
--- a/src/rebar_prv_deps.erl
+++ b/src/rebar_prv_deps.erl
@@ -42,6 +42,10 @@
-define(PROVIDER, deps).
-define(DEPS, [app_discovery]).
+-record(dep, {name :: binary(),
+ vsn :: binary(),
+ source :: binary()}).
+
%% ===================================================================
%% Public API
%% ===================================================================
@@ -54,7 +58,7 @@ init(State) ->
deps = ?DEPS,
example = "rebar deps",
short_desc = "Install dependencies",
- desc = info_help("Install dependencies"),
+ desc = info("Install dependencies"),
opts = []}),
{ok, State1}.
@@ -62,34 +66,32 @@ init(State) ->
do(State) ->
%% Read in package index and dep graph
{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 ->
- 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.
update_deps(State, Deps) ->
@@ -100,75 +102,64 @@ update_deps(State, Deps) ->
UnbuiltApps = rebar_app_discover:find_unbuilt_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) ->
- 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
setup_env(State) ->
@@ -200,6 +191,40 @@ get_deps_dir(DepsDir, App) ->
%% 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) ->
RebarDir = rebar_state:get(State, global_rebar_dir, filename:join(os:getenv("HOME"), ".rebar")),
PackagesFile = filename:join(RebarDir, "packages"),
@@ -217,7 +242,7 @@ get_packages(State) ->
{[], rlx_depsolver:new()}
end.
-info_help(Description) ->
+info(Description) ->
io_lib:format("~s.~n"
"~n"
"Valid rebar.config options:~n"