summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Watson <tim@rabbitmq.com>2013-11-26 12:17:28 +0000
committerTim Watson <tim@rabbitmq.com>2013-11-26 12:17:28 +0000
commit2e8ddf161965fbf33f18b6d862bc2d91f1a6ad9d (patch)
treeda42a116968b061e80c52414877580f5a86eb735
parent40612c20f440f971dd7f97af8b77dcd208432829 (diff)
downloadrabbitmq-server-git-2e8ddf161965fbf33f18b6d862bc2d91f1a6ad9d.tar.gz
De-duplicate dependency/graph building functions
-rw-r--r--src/app_utils.erl31
-rw-r--r--src/rabbit_misc.erl35
2 files changed, 40 insertions, 26 deletions
diff --git a/src/app_utils.erl b/src/app_utils.erl
index 22e2df44bb..82e4e276fe 100644
--- a/src/app_utils.erl
+++ b/src/app_utils.erl
@@ -78,32 +78,27 @@ wait_for_applications(Apps) ->
[wait_for_application(App) || App <- Apps], ok.
direct_dependencies(Root) ->
- G = digraph:new(),
Loaded = application:loaded_applications(),
- try
- [begin
- case digraph:vertex(G, App) of
- false -> digraph:add_vertex(G, App, App);
- _ -> ok = throw({graph_error, {vertex, duplicate, App}})
- end
- end || {App, _, _} <- Loaded],
- [digraph:add_edge(G, App, Dep) ||
- {App, Deps} <- [{App, app_dependencies(App)} ||
+ {ok, G} = rabbit_misc:build_graph(
+ fun() -> [{App, App} || {App, _, _} <- Loaded] end,
+ fun() -> [{App, Dep} ||
+ {App, Deps} <- [{App, app_dependencies(App)} ||
{App, _Desc, _Vsn} <- Loaded],
- Dep <- Deps],
+ Dep <- Deps]
+ end,
+ digraph:new()),
+ try
Deps = lists:foldl(
fun(E, Acc) ->
- {_, _InVertex, OutVertex, _Label} = digraph:edge(G, E),
- case is_reachable(G, OutVertex, Root) of
- [] -> sets:add_element(OutVertex, Acc);
- _ -> Acc
- end
+ {_, _InVertex, OutVertex, _Label} = digraph:edge(G, E),
+ case is_reachable(G, OutVertex, Root) of
+ [] -> sets:add_element(OutVertex, Acc);
+ _ -> Acc
+ end
end,
sets:from_list([Root]),
digraph:out_edges(G, Root)),
sets:to_list(Deps)
- catch {graph_error, Reason} ->
- {error, Reason}
after
true = digraph:delete(G)
end.
diff --git a/src/rabbit_misc.erl b/src/rabbit_misc.erl
index 26071a8aef..3708c625ef 100644
--- a/src/rabbit_misc.erl
+++ b/src/rabbit_misc.erl
@@ -52,7 +52,7 @@
-export([gb_trees_fold/3, gb_trees_foreach/2]).
-export([parse_arguments/3]).
-export([all_app_module_attributes/1]).
--export([all_module_attributes/1, build_acyclic_graph/3]).
+-export([all_module_attributes/1, build_graph/3, build_acyclic_graph/3]).
-export([now_ms/0]).
-export([const_ok/0, const/1]).
-export([ntoa/1, ntoab/1]).
@@ -91,8 +91,12 @@
:: rabbit_types:channel_exit() | rabbit_types:connection_exit()).
-type(digraph_label() :: term()).
-type(graph_vertex_fun() ::
+ fun (() -> [{digraph:vertex(), digraph_label()}])).
+-type(acyclic_graph_vertex_fun() ::
fun ((atom(), [term()]) -> [{digraph:vertex(), digraph_label()}])).
-type(graph_edge_fun() ::
+ fun (() -> [{digraph:vertex(), digraph:vertex()}])).
+-type(acyclic_graph_edge_fun() ::
fun ((atom(), [term()]) -> [{digraph:vertex(), digraph:vertex()}])).
-spec(method_record_type/1 :: (rabbit_framing:amqp_method_record())
@@ -210,8 +214,17 @@
-> {'ok', {atom(), [{string(), string()}], [string()]}} |
'no_command').
-spec(all_module_attributes/1 :: (atom()) -> [{atom(), [term()]}]).
+-spec(build_graph/3 ::
+ (graph_vertex_fun(), graph_edge_fun(),
+ [{atom(), [term()]}])
+ -> rabbit_types:ok_or_error2(digraph(),
+ {'vertex', 'duplicate', digraph:vertex()} |
+ {'edge', ({bad_vertex, digraph:vertex()} |
+ {bad_edge, [digraph:vertex()]}),
+ digraph:vertex(), digraph:vertex()})).
-spec(build_acyclic_graph/3 ::
- (graph_vertex_fun(), graph_edge_fun(), [{atom(), [term()]}])
+ (acyclic_graph_vertex_fun(),
+ acyclic_graph_edge_fun(), [{atom(), [term()]}])
-> rabbit_types:ok_or_error2(digraph(),
{'vertex', 'duplicate', digraph:vertex()} |
{'edge', ({bad_vertex, digraph:vertex()} |
@@ -884,25 +897,31 @@ find_module_attributes(Generator, Fold) ->
{ok, Modules} <- [application:get_key(App, modules)]])),
lists:foldl(Fold, [], Targets).
-build_acyclic_graph(VertexFun, EdgeFun, Graph) ->
- G = digraph:new([acyclic]),
+build_graph(VertexFun, EdgeFun, G) ->
try
[case digraph:vertex(G, Vertex) of
false -> digraph:add_vertex(G, Vertex, Label);
_ -> ok = throw({graph_error, {vertex, duplicate, Vertex}})
- end || {Module, Atts} <- Graph,
- {Vertex, Label} <- VertexFun(Module, Atts)],
+ end || {Vertex, Label} <- VertexFun()],
[case digraph:add_edge(G, From, To) of
{error, E} -> throw({graph_error, {edge, E, From, To}});
_ -> ok
- end || {Module, Atts} <- Graph,
- {From, To} <- EdgeFun(Module, Atts)],
+ end || {From, To} <- EdgeFun()],
{ok, G}
catch {graph_error, Reason} ->
true = digraph:delete(G),
{error, Reason}
end.
+build_acyclic_graph(VertexFun, EdgeFun, Graph) ->
+ build_graph(fun() -> [Vertex || {Module, Atts} <- Graph,
+ Vertex <- VertexFun(Module, Atts)]
+ end,
+ fun() -> [Edge || {Module, Atts} <- Graph,
+ Edge <- EdgeFun(Module, Atts)]
+ end,
+ digraph:new([acyclic])).
+
const_ok() -> ok.
const(X) -> fun () -> X end.