From ad18970cd7bbcffd4d868ab1a9372f4e883a1728 Mon Sep 17 00:00:00 2001 From: Fred Hebert Date: Fri, 13 Mar 2015 16:07:02 +0000 Subject: Fix #267, refactor as/do/namespace interactions Breaking up initial call to parse from the ones deep inside the provider parsing to do smarter namespace detection, added 'as' the ability to look into these also, and cleaned up the code a whole lot that would depend on implicit assumptions. A side-effect is that 'do' is now valid for all namespaces, although it can be overriden. --- src/rebar3.erl | 2 +- src/rebar_core.erl | 89 ++++++++++++++++++++++------------------------------ src/rebar_prv_as.erl | 12 ++++++- 3 files changed, 50 insertions(+), 53 deletions(-) diff --git a/src/rebar3.erl b/src/rebar3.erl index 1b840cb..4f54c89 100644 --- a/src/rebar3.erl +++ b/src/rebar3.erl @@ -133,7 +133,7 @@ run_aux(State, GlobalPluginProviders, RawArgs) -> {Task, Args} = parse_args(RawArgs), - rebar_core:process_command(rebar_state:command_args(State6, Args), Task). + rebar_core:init_command(rebar_state:command_args(State6, Args), Task). init_config() -> %% Initialize logging system diff --git a/src/rebar_core.erl b/src/rebar_core.erl index 12cd1fc..db82766 100644 --- a/src/rebar_core.erl +++ b/src/rebar_core.erl @@ -26,69 +26,61 @@ %% ------------------------------------------------------------------- -module(rebar_core). --export([process_command/2]). +-export([init_command/2, process_namespace/2, process_command/2]). -include("rebar.hrl"). +init_command(State, do) -> + process_command(rebar_state:namespace(State, default), do); +init_command(State, as) -> + process_command(rebar_state:namespace(State, default), as); +init_command(State, Command) -> + case process_namespace(State, Command) of + {ok, State1, Command1} -> + process_command(State1, Command1); + {error, Reason} -> + {error, Reason} + end. + +process_namespace(_State, as) -> + {error, "Namespace 'as' is forbidden"}; +process_namespace(State, Command) -> + Providers = rebar_state:providers(State), + CommandProvider = providers:get_provider(Command, Providers, default), + case CommandProvider of + not_found -> + case providers:get_providers_by_namespace(Command, Providers) of + [] -> + {error, io_lib:format("Command ~p not found", [Command])}; + _ -> + %% Replay 'do' as a command of that namespace + {ok, rebar_state:namespace(State, Command), do} + end; + _ -> + {ok, rebar_state:namespace(State, default), Command} + end. + -spec process_command(rebar_state:t(), atom()) -> {ok, rebar_state:t()} | {error, string()}. process_command(State, Command) -> %% ? rebar_prv_install_deps:setup_env(State), Providers = rebar_state:providers(State), Namespace = rebar_state:namespace(State), - {TargetProviders, CommandProvider} = - case Namespace of - undefined -> - %% undefined namespace means 'default', but on the first run; - %% it is used as an implicit counter for the first vs. subsequent - %% runs. - {providers:get_target_providers(Command, Providers, default), - providers:get_provider(Command, Providers, default)}; - _ -> - {providers:get_target_providers(Command, Providers, Namespace), - providers:get_provider(Command, Providers, Namespace)} - end, - + TargetProviders = providers:get_target_providers(Command, Providers, Namespace), + CommandProvider = providers:get_provider(Command, Providers, Namespace), case CommandProvider of - not_found -> + not_found when Command =/= do -> case Namespace of - undefined -> - %% On the first run (Namespace = undefined), we use the - %% unfound command name to be a namespace. - case providers:get_providers_by_namespace(Command, Providers) of - [] -> - {error, io_lib:format("Command ~p not found", [Command])}; - _ -> - do([{default, do} | TargetProviders], - rebar_state:namespace(State, Command)) - end; default -> {error, io_lib:format("Command ~p not found", [Command])}; _ -> {error, io_lib:format("Command ~p not found in namespace ~p", [Command, Namespace])} end; + not_found when Command =:= do, Namespace =/= default -> + do([{default, do} | TargetProviders], State); CommandProvider -> case Command of - Command when Command =:= do, Namespace =:= undefined -> - %% We're definitely in the default namespace. 'do' doesn't - %% properly exist for non-default namespaces outside of - %% dynamic dispatch calls for namespaces. - do(TargetProviders, rebar_state:namespace(State, default)); - Command when Command =:= as, Namespace =:= undefined -> - %% Because of the possible forms such as: - %% 'rebar3 as profile task`, `rebar3 as profile do task` - %% and `rebar3 as profile namespace task`, we can only know - %% whether we're in the first 'as' or a namespace 'as' by - %% looking at profiles (as makes them non-default). - %% The namespace 'as' is banned. It also makes it impossible - %% to have both $REBAR_PROFILE set and use 'as' in a command - case rebar_state:current_profiles(State) of - [default] -> - do(TargetProviders, State); - _ -> - {error, "Namespace 'as' is forbidden"} - end; - Command when Command =:= do -> + do -> do(TargetProviders, State); _ -> Profiles = providers:profiles(CommandProvider), @@ -97,12 +89,7 @@ process_command(State, Command) -> case getopt:parse(Opts, rebar_state:command_args(State1)) of {ok, Args} -> State2 = rebar_state:command_parsed_args(State1, Args), - case Namespace of - undefined -> % we're executing commands, set the default namespace - do(TargetProviders, rebar_state:namespace(State2, default)); - _ -> - do(TargetProviders, State2) - end; + do(TargetProviders, State2); {error, {invalid_option, Option}} -> {error, io_lib:format("Invalid option ~s on task ~p", [Option, Command])} end diff --git a/src/rebar_prv_as.erl b/src/rebar_prv_as.erl index beee00d..6e3825f 100644 --- a/src/rebar_prv_as.erl +++ b/src/rebar_prv_as.erl @@ -38,7 +38,17 @@ do(State) -> {error, "At least one profile must be specified when using `as`"}; _ -> State1 = rebar_state:apply_profiles(State, [list_to_atom(X) || X <- Profiles]), - rebar_prv_do:do_tasks(Tasks, State1) + {FirstTask, FirstTaskArgs} = hd(Tasks), + FirstTaskAtom = list_to_atom(FirstTask), + case rebar_core:process_namespace(State1, FirstTaskAtom) of + {ok, State2, NewTask} -> + rebar_prv_do:do_tasks( + [{atom_to_list(NewTask),FirstTaskArgs}|tl(Tasks)], + State2 + ); + {error, Reason} -> + {error, Reason} + end end. -spec format_error(any()) -> iolist(). -- cgit v1.1