Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

114 rindas
4.5 KiB

pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
  1. %%% @doc build a digraph of applications in order to figure out dependency
  2. %%% and compile order.
  3. -module(rebar_digraph).
  4. -export([compile_order/1
  5. ,restore_graph/1
  6. ,subgraph/2
  7. ,format_error/1]).
  8. -include("rebar.hrl").
  9. %% @doc Sort apps with topological sort to get proper build order
  10. -spec compile_order([rebar_app_info:t()]) ->
  11. {ok, [rebar_app_info:t()]} | {error, no_sort | {cycles, [[binary(),...]]}}.
  12. compile_order(Apps) ->
  13. Graph = digraph:new(),
  14. lists:foreach(fun(App) ->
  15. Name = rebar_app_info:name(App),
  16. Deps = all_apps_deps(App),
  17. add(Graph, {Name, Deps})
  18. end, Apps),
  19. Order =
  20. case digraph_utils:topsort(Graph) of
  21. false ->
  22. case digraph_utils:is_acyclic(Graph) of
  23. true ->
  24. {error, no_sort};
  25. false ->
  26. Cycles = lists:sort(
  27. [lists:sort(Comp) || Comp <- digraph_utils:strong_components(Graph),
  28. length(Comp)>1]),
  29. {error, {cycles, Cycles}}
  30. end;
  31. V ->
  32. {ok, names_to_apps(lists:reverse(V), Apps)}
  33. end,
  34. true = digraph:delete(Graph),
  35. Order.
  36. %% @private Add a package and its dependencies to an existing digraph
  37. -spec add(digraph:graph(), {PkgName, [Dep]}) -> ok when
  38. PkgName :: binary(),
  39. Dep :: {Name, term()} | Name,
  40. Name :: atom() | iodata().
  41. add(Graph, {PkgName, Deps}) ->
  42. case digraph:vertex(Graph, PkgName) of
  43. false ->
  44. V = digraph:add_vertex(Graph, PkgName);
  45. {V, []} ->
  46. V
  47. end,
  48. lists:foreach(fun(DepName) ->
  49. Name1 = case DepName of
  50. {Name, _Vsn} ->
  51. rebar_utils:to_binary(Name);
  52. Name ->
  53. rebar_utils:to_binary(Name)
  54. end,
  55. V3 = case digraph:vertex(Graph, Name1) of
  56. false ->
  57. digraph:add_vertex(Graph, Name1);
  58. {V2, []} ->
  59. V2
  60. end,
  61. digraph:add_edge(Graph, V, V3)
  62. end, Deps).
  63. %% @doc based on a list of vertices and edges, build a digraph.
  64. -spec restore_graph({[digraph:vertex()], [digraph:edge()]}) -> digraph:graph().
  65. restore_graph({Vs, Es}) ->
  66. Graph = digraph:new(),
  67. lists:foreach(fun({V, LastUpdated}) ->
  68. digraph:add_vertex(Graph, V, LastUpdated)
  69. end, Vs),
  70. lists:foreach(fun({V1, V2}) ->
  71. digraph:add_edge(Graph, V1, V2)
  72. end, Es),
  73. Graph.
  74. %% @doc convert a given exception's payload into an io description.
  75. -spec format_error(any()) -> iolist().
  76. format_error(no_solution) ->
  77. io_lib:format("No solution for packages found.", []).
  78. %%====================================================================
  79. %% Internal Functions
  80. %%====================================================================
  81. %% @doc alias for `digraph_utils:subgraph/2'.
  82. subgraph(Graph, Vertices) ->
  83. digraph_utils:subgraph(Graph, Vertices).
  84. %% @private from a list of app names, fetch the proper app info records
  85. %% for them.
  86. -spec names_to_apps([atom()], [rebar_app_info:t()]) -> [rebar_app_info:t()].
  87. names_to_apps(Names, Apps) ->
  88. [element(2, App) || App <- [find_app_by_name(Name, Apps) || Name <- Names], App =/= error].
  89. %% @private fetch the proper app info record for a given app name.
  90. -spec find_app_by_name(atom(), [rebar_app_info:t()]) -> {ok, rebar_app_info:t()} | error.
  91. find_app_by_name(Name, Apps) ->
  92. ec_lists:find(fun(App) ->
  93. rebar_app_info:name(App) =:= Name
  94. end, Apps).
  95. %% @private The union of all entries in the applications list for an app and
  96. %% the deps listed in its rebar.config is all deps that may be needed
  97. %% for building the app.
  98. -spec all_apps_deps(rebar_app_info:t()) -> [binary()].
  99. all_apps_deps(App) ->
  100. Applications = lists:usort([atom_to_binary(X, utf8) || X <- rebar_app_info:applications(App)]),
  101. Deps = lists:usort(lists:map(fun({Name, _}) -> Name; (Name) -> Name end, rebar_app_info:deps(App))),
  102. lists:umerge(Deps, Applications).