./ct_report/coverage/mongoose_service_deps.COVER.html

1 %% @doc Service dependency management
2
3 -module(mongoose_service_deps).
4
5 -export([resolve_deps/1, sort_deps/1]).
6
7 -type service_list() :: mongoose_service:service_list().
8 -type service_map() :: mongoose_service:service_map().
9
10 %% @doc Add dependencies to the service map
11 -spec resolve_deps(service_map()) -> service_map().
12 resolve_deps(Services) when is_map(Services) ->
13 4 resolve_deps(maps:to_list(Services), #{}).
14
15 -spec resolve_deps(service_list(), service_map()) -> service_map().
16 resolve_deps([], Acc) ->
17 4 Acc;
18 resolve_deps([{Service, Opts} | Rest], Acc) ->
19 4 {DepsToResolve, NewAcc} =
20 case Acc of
21 #{Service := PreviousOpts} ->
22
:-(
{[], Acc#{Service => merge_opts(PreviousOpts, Opts)}};
23 #{} ->
24 4 Deps = [{Dep, #{}} || Dep <- mongoose_service:get_deps(Service)],
25 4 {Deps, Acc#{Service => Opts}}
26 end,
27 4 resolve_deps(DepsToResolve ++ Rest, NewAcc).
28
29 %% Deps always have no options, so one argument has to be an empty map
30
:-(
merge_opts(#{}, Opts) -> Opts;
31
:-(
merge_opts(Opts, #{}) -> Opts.
32
33 %% @doc Sort services (which already include their dependencies) according to the dependency graph
34 -spec sort_deps(service_map()) -> service_list().
35 sort_deps(Services) when is_map(Services) ->
36 8 DepsGraph = digraph:new([acyclic, private]),
37 8 try
38 8 [add_service_with_deps(Service, DepsGraph) || Service <- maps:keys(Services)],
39 8 [{Service, maps:get(Service, Services)} || Service <- digraph_utils:topsort(DepsGraph)]
40 after
41 8 digraph:delete(DepsGraph)
42 end.
43
44 add_service_with_deps(Service, DepsGraph) ->
45 8 digraph:add_vertex(DepsGraph, Service),
46 8 lists:foreach(fun(DepService) -> add_service_dep(Service, DepService, DepsGraph) end,
47 mongoose_service:get_deps(Service)).
48
49 add_service_dep(Service, DepService, DepsGraph) ->
50
:-(
digraph:add_vertex(DepsGraph, DepService),
51
:-(
case digraph:add_edge(DepsGraph, DepService, Service) of
52 {error, Error} ->
53
:-(
{bad_edge, CyclePath} = Error,
54
:-(
error(#{what => resolving_dependencies_aborted,
55 text => <<"Service dependency cycle found">>,
56 service => Service,
57 dep_service => DepService,
58 cycle_path => CyclePath});
59 _Edge ->
60
:-(
ok
61 end.
Line Hits Source