From c79d13f5e854ff84b4fe61a45ce666ee1c8479da Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Tue, 27 Jan 2015 20:52:35 -0800 Subject: factor out task/args parsing from `do` for use in other meta commands --- src/rebar_prv_do.erl | 8 +-- src/rebar_utils.erl | 55 ++++++++++++++++++++- test/rebar_utils_SUITE.erl | 120 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+), 7 deletions(-) create mode 100644 test/rebar_utils_SUITE.erl diff --git a/src/rebar_prv_do.erl b/src/rebar_prv_do.erl index 5dec7d8..83e57a1 100644 --- a/src/rebar_prv_do.erl +++ b/src/rebar_prv_do.erl @@ -32,13 +32,12 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> - Tasks = args_to_tasks(rebar_state:command_args(State)), + Tasks = rebar_utils:args_to_tasks(rebar_state:command_args(State)), do_tasks(Tasks, State). do_tasks([], State) -> {ok, State}; -do_tasks([TaskArgs | Tail], State) -> - [TaskStr | Args] = string:tokens(TaskArgs, " "), +do_tasks([{TaskStr, Args}|Tail], State) -> Task = list_to_atom(TaskStr), State1 = rebar_state:set(State, task, Task), State2 = rebar_state:command_args(State1, Args), @@ -52,6 +51,3 @@ do_tasks([TaskArgs | Tail], State) -> -spec format_error(any()) -> iolist(). format_error(Reason) -> io_lib:format("~p", [Reason]). - -args_to_tasks(Args) -> - [string:strip(T) || T <- string:tokens(string:join(Args, " "), ",")]. diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index d899dc5..85f59d6 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -47,7 +47,8 @@ deprecated/4, erl_opts/1, indent/1, - cleanup_code_path/1]). + cleanup_code_path/1, + args_to_tasks/1]). %% for internal use only -export([otp_release/0]). @@ -218,6 +219,12 @@ erl_opts(Config) -> [debug_info|Opts] end. +%% for use by `do` task + +%% note: this does not handle the case where you have an argument that +%% was enclosed in quotes and might have commas but should not be split. +args_to_tasks(Args) -> new_task(Args, []). + %% ==================================================================== %% Internal functions %% ==================================================================== @@ -467,3 +474,49 @@ cleanup_code_path(OrigPath) -> _ -> code:set_path(OrigPath) end. + +new_task([], Acc) -> lists:reverse(Acc); +new_task([TaskList|Rest], Acc) -> + case re:split(TaskList, ",", [{return, list}, {parts, 2}]) of + %% `do` consumes all remaining args + ["do" = Task|RestArgs] -> + lists:reverse([{Task, RestArgs ++ Rest}|Acc]); + %% single task terminated by a comma + [Task, ""] -> new_task(Rest, [{Task, []}|Acc]); + %% sequence of two or more tasks + [Task, More] -> new_task([More|Rest], [{Task, []}|Acc]); + %% single task not terminated by a comma + [Task] -> arg_or_flag(Rest, [{Task, []}|Acc]) + end. + +arg_or_flag([], [{Task, Args}|Acc]) -> + lists:reverse([{Task, lists:reverse(Args)}|Acc]); +%% case where you have `foo , bar` +arg_or_flag([","|Rest], Acc) -> new_task(Rest, Acc); +%% case where you have `foo ,bar` +arg_or_flag(["," ++ Task|Rest], Acc) -> new_task([Task|Rest], Acc); +%% a flag +arg_or_flag(["-" ++ _ = Flag|Rest], [{Task, Args}|Acc]) -> + case maybe_ends_in_comma(Flag) of + false -> arg_or_flag(Rest, [{Task, [Flag|Args]}|Acc]); + NewFlag -> new_task(Rest, [{Task, + lists:reverse([NewFlag|Args])}|Acc]) + end; +%% an argument or a sequence of arguments +arg_or_flag([ArgList|Rest], [{Task, Args}|Acc]) -> + case re:split(ArgList, ",", [{return, list}, {parts, 2}]) of + %% single arg terminated by a comma + [Arg, ""] -> new_task(Rest, [{Task, + lists:reverse([Arg|Args])}|Acc]); + %% sequence of two or more args/tasks + [Arg, More] -> new_task([More|Rest], [{Task, + lists:reverse([Arg|Args])}|Acc]); + %% single arg not terminated by a comma + [Arg] -> arg_or_flag(Rest, [{Task, [Arg|Args]}|Acc]) + end. + +maybe_ends_in_comma(H) -> + case lists:reverse(H) of + "," ++ Flag -> lists:reverse(Flag); + _ -> false + end. diff --git a/test/rebar_utils_SUITE.erl b/test/rebar_utils_SUITE.erl new file mode 100644 index 0000000..e9b32e2 --- /dev/null +++ b/test/rebar_utils_SUITE.erl @@ -0,0 +1,120 @@ +-module(rebar_utils_SUITE). + +-export([all/0, + groups/0, + init_per_group/2, + end_per_group/2, + empty_arglist/1, + single_task/1, + single_task_with_immediate_comma/1, + single_task_with_trailing_comma/1, + multiple_task/1, + multiple_task_no_spaces/1, + multiple_task_with_immediate_comma/1, + multiple_task_with_trailing_comma/1, + task_with_arg/1, + task_with_arg_with_immediate_comma/1, + task_with_arg_with_trailing_comma/1, + task_with_multiple_args/1, + task_with_flag/1, + task_with_flag_with_immediate_comma/1, + task_with_flag_with_trailing_comma/1, + task_with_flag_with_commas/1, + task_with_multiple_flags/1, + special_task_do/1]). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include_lib("kernel/include/file.hrl"). + + +all() -> + [{group, args_to_tasks}]. + +groups() -> + [{args_to_tasks, [], [empty_arglist, + single_task, + single_task_with_immediate_comma, + single_task_with_trailing_comma, + multiple_task, + multiple_task_no_spaces, + multiple_task_with_immediate_comma, + multiple_task_with_trailing_comma, + task_with_arg, + task_with_arg_with_immediate_comma, + task_with_arg_with_trailing_comma, + task_with_multiple_args, + task_with_flag, + task_with_flag_with_immediate_comma, + task_with_flag_with_trailing_comma, + task_with_flag_with_commas, + task_with_multiple_flags, + special_task_do]}]. + +init_per_group(_, Config) -> Config. +end_per_group(_, Config) -> Config. + +empty_arglist(_Config) -> + [] = rebar_utils:args_to_tasks([]). + +single_task(_Config) -> + [{"foo", []}] = rebar_utils:args_to_tasks(["foo"]). + +single_task_with_immediate_comma(_Config) -> + [{"foo", []}] = rebar_utils:args_to_tasks(["foo,"]). + +single_task_with_trailing_comma(_Config) -> + [{"foo", []}] = rebar_utils:args_to_tasks(["foo", ","]). + +multiple_task(_Config) -> + [{"foo", []}, {"bar", []}, {"baz", []}] = rebar_utils:args_to_tasks(["foo,", + "bar,", + "baz"]). + +multiple_task_no_spaces(_Config) -> + [{"foo", []}, {"bar", []}, {"baz", []}] = rebar_utils:args_to_tasks(["foo,bar,baz"]). + +multiple_task_with_immediate_comma(_Config) -> + [{"foo", []}, {"bar", []}, {"baz", []}] = rebar_utils:args_to_tasks(["foo,", + "bar,", + "baz,"]). + +multiple_task_with_trailing_comma(_Config) -> + [{"foo", []}, {"bar", []}, {"baz", []}] = rebar_utils:args_to_tasks(["foo", + ",", + "bar", + ",", + "baz", + ","]). +task_with_arg(_Config) -> + [{"foo", ["bar"]}] = rebar_utils:args_to_tasks(["foo", "bar"]). + +task_with_arg_with_immediate_comma(_Config) -> + [{"foo", ["bar"]}, {"baz", []}] = rebar_utils:args_to_tasks(["foo", "bar,", "baz"]). + +task_with_arg_with_trailing_comma(_Config) -> + [{"foo", ["bar"]}, {"baz", []}] = rebar_utils:args_to_tasks(["foo", "bar", ",", "baz"]). + +task_with_multiple_args(_Config) -> + [{"foo", ["bar", "baz"]}] = rebar_utils:args_to_tasks(["foo", "bar", "baz"]). + +task_with_flag(_Config) -> + [{"foo", ["--bar"]}] = rebar_utils:args_to_tasks(["foo", "--bar"]). + +task_with_flag_with_immediate_comma(_Config) -> + [{"foo", ["--bar"]}, {"baz", []}] = rebar_utils:args_to_tasks(["foo", "--bar,", "baz"]). + +task_with_flag_with_trailing_comma(_Config) -> + [{"foo", ["--bar"]}, {"baz", []}] = rebar_utils:args_to_tasks(["foo", "--bar", ",", "baz"]). + +task_with_flag_with_commas(_Config) -> + [{"foo", ["--bar=baz,qux"]}] = rebar_utils:args_to_tasks(["foo", "--bar=baz,qux"]). + +task_with_multiple_flags(_Config) -> + [{"foo", ["--bar", "--baz"]}] = rebar_utils:args_to_tasks(["foo", "--bar", "--baz"]). + +special_task_do(_Config) -> + [{"foo", []}, {"do", ["bar,", "baz"]}] = rebar_utils:args_to_tasks(["foo,", + "do", + "bar,", + "baz"]). -- cgit v1.1