Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

108 рядки
4.3 KiB

10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
  1. %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% ex: ts=4 sw=4 et
  3. -module(rebar_prv_as).
  4. -behaviour(provider).
  5. -export([init/1,
  6. do/1,
  7. format_error/1]).
  8. -include("rebar.hrl").
  9. -define(PROVIDER, as).
  10. -define(DEPS, []).
  11. %% ===================================================================
  12. %% Public API
  13. %% ===================================================================
  14. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
  15. init(State) ->
  16. State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
  17. {module, ?MODULE},
  18. {bare, true},
  19. {deps, ?DEPS},
  20. {example, "rebar3 as <profile1>,<profile2>,... <task1>, <task2>, ..."},
  21. {short_desc, "Higher order provider for running multiple tasks in a sequence as a certain profiles."},
  22. {desc, "Higher order provider for running multiple tasks in a sequence as a certain profiles."},
  23. {opts, [{profile, undefined, undefined, string, "Profiles to run as."}]}])),
  24. {ok, State1}.
  25. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
  26. do(State) ->
  27. {Profiles, Tasks} = args_to_profiles_and_tasks(rebar_state:command_args(State)),
  28. case {Profiles, Tasks} of
  29. {[], _} ->
  30. {error, "At least one profile must be specified when using `as`"};
  31. {_, []} ->
  32. {error, "At least one task must be specified when using `as`"};
  33. _ ->
  34. warn_on_empty_profile(Profiles, State),
  35. State1 = rebar_state:apply_profiles(State, [list_to_atom(X) || X <- Profiles]),
  36. State2 = rebar_plugins:project_apps_install(State1),
  37. {FirstTask, FirstTaskArgs} = hd(Tasks),
  38. FirstTaskAtom = list_to_atom(FirstTask),
  39. case rebar_core:process_namespace(State2, FirstTaskAtom) of
  40. {ok, State3, NewTask} ->
  41. rebar_prv_do:do_tasks(
  42. [{atom_to_list(NewTask),FirstTaskArgs}|tl(Tasks)],
  43. State3
  44. );
  45. {error, Reason} ->
  46. {error, Reason}
  47. end
  48. end.
  49. -spec format_error(any()) -> iolist().
  50. format_error(Reason) ->
  51. io_lib:format("~p", [Reason]).
  52. args_to_profiles_and_tasks(Args) ->
  53. first_profile(Args).
  54. first_profile([]) -> {[], []};
  55. first_profile([ProfileList|Rest]) ->
  56. case re:split(ProfileList, ",", [{return, list}, {parts, 2}, unicode]) of
  57. %% `foo, bar`
  58. [P, ""] -> profiles(Rest, [P]);
  59. %% `foo,bar`
  60. [P, More] -> profiles([More] ++ Rest, [P]);
  61. %% `foo`
  62. [P] -> comma_or_end(Rest, [P])
  63. end.
  64. profiles([], Acc) -> {lists:reverse(Acc), rebar_utils:args_to_tasks([])};
  65. profiles([ProfileList|Rest], Acc) ->
  66. case re:split(ProfileList, ",", [{return, list}, {parts, 2}, unicode]) of
  67. %% `foo, bar`
  68. [P, ""] -> profiles(Rest, [P|Acc]);
  69. %% `foo,bar`
  70. [P, More] -> profiles([More] ++ Rest, [P|Acc]);
  71. %% `foo`
  72. [P] -> comma_or_end(Rest, [P|Acc])
  73. end.
  74. %% `, foo...`
  75. comma_or_end([","|Rest], Acc) ->
  76. profiles(Rest, Acc);
  77. %% `,foo...`
  78. comma_or_end(["," ++ Profile|Rest], Acc) ->
  79. profiles([Profile|Rest], Acc);
  80. comma_or_end(Tasks, Acc) ->
  81. {lists:reverse(Acc), rebar_utils:args_to_tasks(Tasks)}.
  82. %% If a profile is used by 'as' but has no entry under `profile` within
  83. %% the top level rebar.config or any project app's rebar.config print a warning.
  84. %% This is just to help developers, in case they forgot to define a profile but
  85. %% thought it was being used.
  86. warn_on_empty_profile(Profiles, State) ->
  87. ProjectApps = rebar_state:project_apps(State),
  88. DefinedProfiles = rebar_state:get(State, profiles, []) ++
  89. lists:flatten([rebar_app_info:get(AppInfo, profiles, []) || AppInfo <- ProjectApps]),
  90. [?WARN("No entry for profile ~ts in config.", [Profile])
  91. || Profile <- Profiles,
  92. not lists:keymember(list_to_atom(Profile), 1, DefinedProfiles),
  93. Profile =/= "global", Profile =/= "default"],
  94. ok.