summaryrefslogtreecommitdiff
path: root/src/rebar_digraph.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rebar_digraph.erl')
-rw-r--r--src/rebar_digraph.erl101
1 files changed, 101 insertions, 0 deletions
diff --git a/src/rebar_digraph.erl b/src/rebar_digraph.erl
new file mode 100644
index 0000000..decc542
--- /dev/null
+++ b/src/rebar_digraph.erl
@@ -0,0 +1,101 @@
+-module(rebar_digraph).
+
+-export([check_graph/2
+ ,restore_graph/1
+ ,store_graph/3
+ ,solve/2
+ ,subgraph/2]).
+
+-include("rebar.hrl").
+
+check_graph(_File, #graph{vsn=?GRAPH_VSN}) ->
+ ok;
+check_graph(File, #graph{vsn=Vsn}) ->
+ ?ABORT("~s file version is incompatible. expected: ~b got: ~b",
+ [File, ?GRAPH_VSN, Vsn]);
+check_graph(File, _) ->
+ ?ABORT("~s file is invalid. Please delete before next run.",
+ [File]).
+
+restore_graph({Vs, Es}) ->
+ G = digraph:new(),
+ lists:foreach(fun({V, LastUpdated}) ->
+ digraph:add_vertex(G, V, LastUpdated)
+ end, Vs),
+ lists:foreach(fun({V1, V2}) ->
+ digraph:add_edge(G, V1, V2)
+ end, Es),
+ G;
+restore_graph(File) ->
+ G = digraph:new(),
+ case file:read_file(File) of
+ {ok, Data} ->
+ try binary_to_term(Data) of
+ G ->
+ %% ok = check_erlcinfo(Config, Graph),
+ #graph{info=Graph} = G,
+ {Vs, Es} = Graph,
+ lists:foreach(
+ fun({V, LastUpdated}) ->
+ digraph:add_vertex(G, V, LastUpdated)
+ end, Vs),
+ lists:foreach(
+ fun({V1, V2}) ->
+ digraph:add_edge(G, V1, V2)
+ end, Es)
+ catch
+ error:badarg ->
+ ?ERROR(
+ "Failed (binary_to_term) to restore rebar info file."
+ " Discard file.", []),
+ ok
+ end;
+ _Err ->
+ ok
+ end,
+ G.
+
+store_graph(_G, _File, _Modified = false) ->
+ ok;
+store_graph(G, File, _Modified) ->
+ Vs = lists:map(
+ fun(V) ->
+ digraph:vertex(G, V)
+ end, digraph:vertices(G)),
+ Es = lists:flatmap(
+ fun({V, _}) ->
+ lists:map(
+ fun(E) ->
+ {_, V1, V2, _} = digraph:edge(G, E),
+ {V1, V2}
+ end, digraph:out_edges(G, V))
+ end, Vs),
+
+ ok = filelib:ensure_dir(File),
+ Data = term_to_binary(#graph{info={Vs, Es}}, [{compressed, 9}]),
+ file:write_file(File, Data).
+
+solve(Graph, Vertices) ->
+ solve(Graph, Vertices, dict:new()).
+
+solve(_Graph, [], Solution) ->
+ {_, Vertices} = lists:unzip(dict:to_list(Solution)),
+ 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) orelse
+ lists:keymember(Key, 1, Vertices) 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).