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.

108 lines
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.