Skip to content

Commit

Permalink
Merge pull request #2825 from paulo-ferraz-oliveira/feature/command-a…
Browse files Browse the repository at this point in the history
…lias

Add command rebar3 alias
  • Loading branch information
ferd authored Aug 26, 2023
2 parents 11c2de0 + 6c20c5a commit 393c7cb
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 10 deletions.
62 changes: 53 additions & 9 deletions apps/rebar/src/rebar_prv_alias.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,62 @@
%%% years of stability. Only some error checks were added
-module(rebar_prv_alias).

-export([init/1]).
-behaviour(provider).

-export([init/1, do/1, format_error/1]).
-include("rebar.hrl").

-define(PROVIDER, alias).
-define(CREATED_ALIASES_KEY, '_rebar_prv_alias_created_aliases').

%% ===================================================================
%% Public API
%% ===================================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
Aliases = rebar_state:get(State, alias, []),
lists:foldl(fun({Alias, Cmds}, {ok, StateAcc}) ->
case validate_provider(Alias, Cmds, State) of
true -> init_alias(Alias, Cmds, StateAcc);
false -> {ok, State}
end
end, {ok, State}, Aliases).
{StateWithAliases, AliasesDefs}
= lists:foldl(
fun({Alias, Cmds}, {StateAcc, AliasesDefsAcc} = Acc) ->
case validate_provider(Alias, Cmds, State) of
true ->
StateWithAlias = init_alias(Alias, Cmds, StateAcc),
AliasesDefsWithAlias = [{Alias, Cmds} | AliasesDefsAcc],
{StateWithAlias, AliasesDefsWithAlias};
false ->
Acc
end
end,
{State, []},
Aliases
),
AliasProvider = providers:create([{name, ?PROVIDER},
{module, ?MODULE},
{bare, true},
{deps, []},
{example, "rebar3 alias"},
{short_desc, "List aliases' definitions."},
{desc, "List aliases' definitions."},
{opts, []}]),
StateWithProvider = rebar_state:add_provider(StateWithAliases, AliasProvider),
StateWithAliasesDefs = rebar_state:set(StateWithProvider, ?CREATED_ALIASES_KEY, AliasesDefs),
{ok, StateWithAliasesDefs}.

-spec do(rebar_state:t()) -> {ok, rebar_state:t()}.
do(State) ->
lists:foreach(
fun ({Alias, Cmds}) ->
AliasStr = atom_to_list(Alias),
CmdsStr = cmds_string(Cmds),
?CONSOLE("~ts=~ts", [AliasStr, CmdsStr])
end,
rebar_state:get(State, ?CREATED_ALIASES_KEY, [])
),
{ok, State}.

-spec format_error(any()) -> iolist().
format_error(Reason) ->
io_lib:format("~p", [Reason]).

-dialyzer([{no_opaque, init_alias/3}, {no_return, init_alias/3}]). % warnings relate to use of opaque structures in :forms
init_alias(Alias, Cmds, State) ->
Expand All @@ -43,7 +84,7 @@ init_alias(Alias, Cmds, State) ->
{short_desc, desc(Cmds)},
{desc, desc(Cmds)}
]),
{ok, rebar_state:add_provider(State, Provider)}.
rebar_state:add_provider(State, Provider).

validate_provider(Alias, Cmds, State) ->
%% This would be caught and prevented anyway, but the warning
Expand Down Expand Up @@ -73,7 +114,10 @@ example(Alias) ->
-dialyzer({no_unused, desc/1}). % required since we suppress warnings for init_alias/3
desc(Cmds) ->
"Equivalent to running: rebar3 do "
++ rebar_string:join(lists:map(fun to_desc/1, Cmds), ",").
++ cmds_string(Cmds).

cmds_string(Cmds) ->
rebar_string:join(lists:map(fun to_desc/1, Cmds), ",").

to_desc({Cmd, Args}) when is_list(Args) ->
atom_to_list(Cmd) ++ " " ++ Args;
Expand Down
43 changes: 42 additions & 1 deletion apps/rebar/test/rebar_alias_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ end_per_testcase(_, _Config) ->
ok.

all() -> [command, args, many, override_default, no_circular, release,
check_namespaces, create_lib].
check_namespaces, create_lib, command_console].

command() ->
[{doc, "Runs multiple regular commands as one alias"}].
Expand Down Expand Up @@ -163,3 +163,44 @@ create_lib(Config) ->
"../../../../shouldexist/src/shouldexist.app.src"),
?assert(filelib:is_file(AppFile)),
ok.

command_console() ->
[{doc, "Test console output as per `rebar3 alias`"}].
command_console(Config) ->
State = ?config(state, Config),
RebarConfig
= [{alias, [
{test, [compile, {unlock,"-a"}]},
{test, [{eunit,"-c"}, cover]},
{nolock, [compile, {unlock,"-a"}]},
{compile1, [help]},
{test1, [help, {test,"-a"}, compile]},
{the_rel1, [clean, {release, "-n the_release"}]},
{the_rel2, [clean, {release, "--relname=the_release"}]},
{test, [{eunit,"-c"}, {plugins, list}]},
{test, [compile, {do, "new lib shouldexist"}]}
]}],
AppDir = ?config(apps, Config),

%% validate output as <alias>=..., as this format is considered part of the interface,
%% for consumption; order is not important though
ct:capture_start(),
rebar3:run(rebar_state:new(State, RebarConfig, AppDir), ["alias"]),
ct:capture_stop(),
AllCaptured = ct:capture_get(),

Aliases = proplists:get_keys(proplists:get_value(alias, RebarConfig)),
[] = lists:foldl(
fun (Captured, AliasesAcc) ->
Match = re:run(Captured, "^([^=]+)=.*", [{capture, all_but_first}]),
case Match of
no_match ->
AliasesAcc;
{match, [{Start, End}]} ->
CapturedPref = string:sub_string(Captured, Start+1, End),
lists:delete(list_to_existing_atom(CapturedPref), AliasesAcc)
end
end,
Aliases,
AllCaptured
).

0 comments on commit 393c7cb

Please sign in to comment.