|
|
- -module(rebar_digraph).
-
- -export([sort_apps/1
- ,restore_graph/1
- ,solve/2
- ,subgraph/2
- ,format_error/1]).
-
- -include("rebar.hrl").
-
- sort_apps(Apps) ->
- Graph = digraph:new(),
- lists:foreach(fun(App) ->
- Name = rebar_app_info:name(App),
- Deps = rebar_app_info:deps(App),
- add(Graph, {Name, Deps})
- end, Apps),
- case digraph_utils:topsort(Graph) of
- false ->
- {error, no_sort};
- V ->
- {ok, names_to_apps(lists:reverse(V), Apps)}
- end.
-
- add(Graph, {PkgName, Deps}) ->
- case digraph:vertex(Graph, PkgName) of
- false ->
- V = digraph:add_vertex(Graph, PkgName);
- {V, []} ->
- V
- end,
-
- lists:foreach(fun(DepName) ->
- V3 = case digraph:vertex(Graph, DepName) of
- false ->
- digraph:add_vertex(Graph, DepName);
- {V2, []} ->
- V2
- end,
- digraph:add_edge(Graph, V, V3)
- end, Deps).
-
- restore_graph({Vs, Es}) ->
- Graph = digraph:new(),
- lists:foreach(fun({V, LastUpdated}) ->
- digraph:add_vertex(Graph, V, LastUpdated)
- end, Vs),
- lists:foreach(fun({V1, V2}) ->
- digraph:add_edge(Graph, V1, V2)
- end, Es),
- Graph.
-
- solve(Graph, Vertices) ->
- solve(Graph, Vertices, lists:foldl(fun({Key, _}=N, Solution) ->
- dict:store(Key, N, Solution)
- end, dict:new(), Vertices)).
-
- solve(_Graph, [], Solution) ->
- {_, Vertices} = lists:unzip(dict:to_list(Solution)),
- {ok, Vertices};
- solve(Graph, Vertices, Solution) ->
- {NV, NS} =
- lists:foldl(fun(V, {NewVertices, SolutionAcc}) ->
- OutNeighbors = digraph:out_neighbours(Graph, V),
- lists:foldl(fun({Key, _}=N, {NewVertices1, SolutionAcc1}) ->
- case dict:is_key(Key, SolutionAcc1) of
- true ->
- {NewVertices1, SolutionAcc1};
- false ->
- {[N | NewVertices1], dict:store(Key, N, SolutionAcc1)}
- end
- end, {NewVertices, SolutionAcc}, OutNeighbors)
- end, {[], Solution}, Vertices),
- solve(Graph, NV, NS).
-
- subgraph(Graph, Vertices) ->
- digraph_utils:subgraph(Graph, Vertices).
-
- format_error(no_solution) ->
- io_lib:format("No solution for packages found.", []).
-
- %%====================================================================
- %% Internal Functions
- %%====================================================================
-
- -spec names_to_apps([atom()], [rebar_app_info:t()]) -> [rebar_app_info:t()].
- names_to_apps(Names, Apps) ->
- [element(2, App) || App <- [find_app_by_name(Name, Apps) || Name <- Names], App =/= error].
-
- -spec find_app_by_name(atom(), [rebar_app_info:t()]) -> {ok, rebar_app_info:t()} | error.
- find_app_by_name(Name, Apps) ->
- ec_lists:find(fun(App) ->
- ec_cnv:to_atom(rebar_app_info:name(App)) =:= ec_cnv:to_atom(Name)
- end, Apps).
|