Selaa lähdekoodia

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.
pull/268/head
Fred Hebert 10 vuotta sitten
vanhempi
commit
ad18970cd7
3 muutettua tiedostoa jossa 50 lisäystä ja 53 poistoa
  1. +1
    -1
      src/rebar3.erl
  2. +38
    -51
      src/rebar_core.erl
  3. +11
    -1
      src/rebar_prv_as.erl

+ 1
- 1
src/rebar3.erl Näytä tiedosto

@ -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

+ 38
- 51
src/rebar_core.erl Näytä tiedosto

@ -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

+ 11
- 1
src/rebar_prv_as.erl Näytä tiedosto

@ -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().

Ladataan…
Peruuta
Tallenna