You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

94 lines
3.5 KiB

  1. -module(rebar_digraph).
  2. -export([sort_apps/1
  3. ,restore_graph/1
  4. ,solve/2
  5. ,subgraph/2
  6. ,format_error/1]).
  7. -include("rebar.hrl").
  8. sort_apps(Apps) ->
  9. Graph = digraph:new(),
  10. lists:foreach(fun(App) ->
  11. Name = rebar_app_info:name(App),
  12. Deps = rebar_app_info:deps(App),
  13. add(Graph, {Name, Deps})
  14. end, Apps),
  15. case digraph_utils:topsort(Graph) of
  16. false ->
  17. {error, no_sort};
  18. V ->
  19. {ok, names_to_apps(lists:reverse(V), Apps)}
  20. end.
  21. add(Graph, {PkgName, Deps}) ->
  22. case digraph:vertex(Graph, PkgName) of
  23. false ->
  24. V = digraph:add_vertex(Graph, PkgName);
  25. {V, []} ->
  26. V
  27. end,
  28. lists:foreach(fun(DepName) ->
  29. V3 = case digraph:vertex(Graph, DepName) of
  30. false ->
  31. digraph:add_vertex(Graph, DepName);
  32. {V2, []} ->
  33. V2
  34. end,
  35. digraph:add_edge(Graph, V, V3)
  36. end, Deps).
  37. restore_graph({Vs, Es}) ->
  38. Graph = digraph:new(),
  39. lists:foreach(fun({V, LastUpdated}) ->
  40. digraph:add_vertex(Graph, V, LastUpdated)
  41. end, Vs),
  42. lists:foreach(fun({V1, V2}) ->
  43. digraph:add_edge(Graph, V1, V2)
  44. end, Es),
  45. Graph.
  46. solve(Graph, Vertices) ->
  47. solve(Graph, Vertices, lists:foldl(fun({Key, _}=N, Solution) ->
  48. dict:store(Key, N, Solution)
  49. end, dict:new(), Vertices)).
  50. solve(_Graph, [], Solution) ->
  51. {_, Vertices} = lists:unzip(dict:to_list(Solution)),
  52. {ok, Vertices};
  53. solve(Graph, Vertices, Solution) ->
  54. {NV, NS} =
  55. lists:foldl(fun(V, {NewVertices, SolutionAcc}) ->
  56. OutNeighbors = digraph:out_neighbours(Graph, V),
  57. lists:foldl(fun({Key, _}=N, {NewVertices1, SolutionAcc1}) ->
  58. case dict:is_key(Key, SolutionAcc1) of
  59. true ->
  60. {NewVertices1, SolutionAcc1};
  61. false ->
  62. {[N | NewVertices1], dict:store(Key, N, SolutionAcc1)}
  63. end
  64. end, {NewVertices, SolutionAcc}, OutNeighbors)
  65. end, {[], Solution}, Vertices),
  66. solve(Graph, NV, NS).
  67. subgraph(Graph, Vertices) ->
  68. digraph_utils:subgraph(Graph, Vertices).
  69. format_error(no_solution) ->
  70. io_lib:format("No solution for packages found.", []).
  71. %%====================================================================
  72. %% Internal Functions
  73. %%====================================================================
  74. -spec names_to_apps([atom()], [rebar_app_info:t()]) -> [rebar_app_info:t()].
  75. names_to_apps(Names, Apps) ->
  76. [element(2, App) || App <- [find_app_by_name(Name, Apps) || Name <- Names], App =/= error].
  77. -spec find_app_by_name(atom(), [rebar_app_info:t()]) -> {ok, rebar_app_info:t()} | error.
  78. find_app_by_name(Name, Apps) ->
  79. ec_lists:find(fun(App) ->
  80. ec_cnv:to_atom(rebar_app_info:name(App)) =:= ec_cnv:to_atom(Name)
  81. end, Apps).