Browse Source

Issue #1704: Fix alias provider argument passing

The way arguments are passed by the alias provider is not compatible
with all rebar providers/commands. Especially the release (relx)
provider does not like getting its arguments as a plain string. It
expects its arguments in a pre-parsed format as returned by
getopt:parse/2.

Other commands, e.g. eunit, seem to be fine with both ways of argument
passing. Therefore, this fix changes the alias provider argument passing
to the getopt format in general.
pull/1707/head
Tobias Schlager 7 years ago
parent
commit
cc70e4fe2f
2 changed files with 72 additions and 24 deletions
  1. +46
    -23
      src/rebar_prv_alias.erl
  2. +26
    -1
      test/rebar_alias_SUITE.erl

+ 46
- 23
src/rebar_prv_alias.erl View File

@ -70,33 +70,56 @@ example(Alias) ->
"rebar3 " ++ atom_to_list(Alias).
desc(Cmds) ->
"Equivalent to running: rebar3 do " ++
rebar_string:join(lists:map(fun({Cmd, Args}) ->
atom_to_list(Cmd) ++ " " ++ Args;
(Cmd) ->
atom_to_list(Cmd)
end, Cmds), ",").
"Equivalent to running: rebar3 do "
++ rebar_string:join(lists:map(fun to_desc/1, Cmds), ",").
to_desc({Cmd, Args}) ->
atom_to_list(Cmd) ++ " " ++ Args;
to_desc(Cmd) ->
atom_to_list(Cmd).
module(Name) ->
{attribute,1,module,Name}.
{attribute, 1, module, Name}.
exports() ->
{attribute,1,export,[{do,1}]}.
{attribute, 1, export, [{do, 1}]}.
do_func(Cmds) ->
{function,1,do,1,
[{clause,1,
[{var,1,'State'}],
{function, 1, do, 1,
[{clause, 1,
[{var, 1, 'State'}],
[],
[{call,1,
{remote,1,{atom,1,rebar_prv_do},{atom,1,do_tasks}},
[to_args(Cmds),{var,1,'State'}]}]}]}.
to_args([]) ->
{nil,1};
to_args([{Cmd, Args} | Rest]) ->
{cons,1,{tuple,1,[{string,1,atom_to_list(Cmd)},{string,1,Args}]}, to_args(Rest)};
to_args([Cmd | Rest]) ->
{cons,1,{tuple,1,[{string,1,atom_to_list(Cmd)},{nil,1}]}, to_args(Rest)}.
[{call, 1,
{remote, 1, {atom, 1, rebar_prv_do}, {atom, 1, do_tasks}},
[make_args(Cmds), {var, 1, 'State'}]}]}]}.
make_args(Cmds) ->
make_list(
lists:map(fun make_tuple/1,
lists:map(fun make_arg/1, Cmds))).
make_arg({Cmd, Args}) ->
{make_string(Cmd), make_list([make_string(A) || A <- split_args(Args)])};
make_arg(Cmd) ->
{make_string(Cmd), make_list([])}.
make_tuple(Tuple) ->
{tuple, 1, tuple_to_list(Tuple)}.
make_list(List) ->
lists:foldr(
fun(Elem, Acc) -> {cons, 1, Elem, Acc} end,
{nil, 1},
List).
make_string(Atom) when is_atom(Atom) ->
make_string(atom_to_list(Atom));
make_string(String) when is_list(String) ->
{string, 1, String}.
%% In case someone used the long option format, the option needs to get
%% separated from its value.
split_args(Args) ->
rebar_string:lexemes(
lists:map(fun($=) -> 32; (C) -> C end, Args),
" ").

+ 26
- 1
test/rebar_alias_SUITE.erl View File

@ -13,7 +13,7 @@ init_per_testcase(_, Config) ->
end_per_testcase(_, _Config) ->
ok.
all() -> [command, args, many, override_default, no_circular].
all() -> [command, args, many, override_default, no_circular, release].
%% namespaces: unsupported, untested.
command() ->
@ -111,3 +111,28 @@ no_circular(Config) ->
{error, [$C,$o,$m,$m,$a,$n,$d,$ ,"test",$ ,$n,$o,$t,$ ,
$f,$o,$u,$n,$d]}),
ok.
release() ->
[{doc, "An alias for a release command"}].
release(Config) ->
AppDir = ?config(apps, Config),
Name = rebar_test_utils:create_random_name("alias_release_"),
Vsn = rebar_test_utils:create_random_vsn(),
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
RebarConfig = [{relx,
[{release, {skipped_release, Vsn}, []},
{release, {the_release, Vsn}, [list_to_atom(Name)]},
{lib_dirs, [AppDir]}]},
{alias,
[{the_rel1, [clean, {release, "-n the_release"}]},
{the_rel2, [clean, {release, "--relname=the_release"}]}]}],
rebar_test_utils:run_and_check(
Config, RebarConfig,
["the_rel1"],
{ok, [{release, the_release, Vsn, false}]}),
rebar_test_utils:run_and_check(
Config, RebarConfig,
["the_rel2"],
{ok, [{release, the_release, Vsn, false}]}),
ok.

Loading…
Cancel
Save