diff options
Diffstat (limited to 'src')
36 files changed, 1150 insertions, 1203 deletions
diff --git a/src/rebar.app.src b/src/rebar.app.src index 3164b73..c41ad92 100644 --- a/src/rebar.app.src +++ b/src/rebar.app.src @@ -21,22 +21,24 @@ {log_level, warn}, %% any_dir processing modules - {providers, [rebar_prv_escripter, + {providers, [rebar_prv_clean, rebar_prv_deps, rebar_prv_do, rebar_prv_lock, rebar_prv_install_deps, rebar_prv_packages, - rebar_erlydtl_compiler, + rebar_prv_erlydtl_compiler, rebar_prv_compile, rebar_prv_app_discovery, rebar_prv_shell, rebar_prv_tar, rebar_prv_new, rebar_prv_update, + rebar_prv_upgrade, rebar_prv_release, rebar_prv_version, rebar_prv_common_test, - rebar_prv_help]} + rebar_prv_help, + rebar_prv_test_deps]} ]} ]}. diff --git a/src/rebar3.erl b/src/rebar3.erl index dcd78f7..22c08ca 100644 --- a/src/rebar3.erl +++ b/src/rebar3.erl @@ -28,15 +28,16 @@ -export([main/1, run/2, - option_spec_list/0, + global_option_spec_list/0, + init_config/0, + init_config1/1, + set_options/2, parse_args/1, version/0, - log_level/1]). + log_level/0]). -include("rebar.hrl"). --define(DEFAULT_JOBS, 3). - %% ==================================================================== %% Public API %% ==================================================================== @@ -44,14 +45,21 @@ %% escript Entry point main(Args) -> case catch(run(Args)) of - ok -> + {ok, _State} -> ok; rebar_abort -> rebar_utils:delayed_halt(1); + {error, {Module, Reason}} -> + ?ERROR(Module:format_error(Reason, []), []), + rebar_utils:delayed_halt(1); + {error, Error} -> + ?ERROR(Error++"~n", []), + rebar_utils:delayed_halt(1); Error -> %% Nothing should percolate up from rebar_core; %% Dump this error to console - io:format("Uncaught error in rebar_core: ~p\n", [Error]), + ?ERROR("Uncaught error in rebar_core. Run with DEBUG=1 to see stacktrace~n", []), + ?DEBUG("Uncaught error: ~p~n", [Error]), rebar_utils:delayed_halt(1) end. @@ -59,7 +67,7 @@ main(Args) -> run(BaseState, Command) -> _ = application:load(rebar), BaseState1 = rebar_state:set(BaseState, task, Command), - run_aux(BaseState1, []). + run_aux(BaseState1, [Command]). %% ==================================================================== %% Internal functions @@ -67,24 +75,21 @@ run(BaseState, Command) -> run(RawArgs) -> ok = load_rebar_app(), - %% Parse out command line arguments -- what's left is a list of commands to - %% run -- and start running commands - Args = parse_args(RawArgs), - BaseConfig = init_config(Args), - {BaseConfig1, Args1} = set_options(BaseConfig, Args), - run_aux(BaseConfig1, Args1). + BaseConfig = init_config(), + {BaseConfig1, _Args1} = set_options(BaseConfig, {[], []}), + run_aux(BaseConfig1, RawArgs). load_rebar_app() -> %% Pre-load the rebar app so that we get default configuration ok = application:load(rebar). -init_config({Options, _NonOptArgs}) -> +init_config() -> %% Initialize logging system - Verbosity = log_level(Options), + Verbosity = log_level(), ok = rebar_log:init(command_line, Verbosity), - Config = case proplists:get_value(config, Options) of - undefined -> + Config = case os:getenv("REBAR_CONFIG") of + false -> rebar_config:consult_file(?DEFAULT_CONFIG_FILE); ConfigFile -> rebar_config:consult_file(ConfigFile) @@ -103,8 +108,8 @@ init_config({Options, _NonOptArgs}) -> true -> ?DEBUG("Load global config file ~p~n", [GlobalConfigFile]), - rebar_config:consult_file(GlobalConfigFile), - rebar_state:new(GlobalConfigFile, Config1); + GlobalConfig = rebar_state:new(rebar_config:consult_file(GlobalConfigFile)), + rebar_state:new(GlobalConfig, Config1); false -> rebar_state:new(Config1) end, @@ -123,7 +128,7 @@ init_config1(BaseConfig) -> BaseConfig end. -run_aux(State, Args) -> +run_aux(State, RawArgs) -> %% Make sure crypto is running case crypto:start() of ok -> ok; @@ -136,28 +141,33 @@ run_aux(State, Args) -> State1 = init_config1(State), + code:add_pathsa([filename:join(rebar_utils:get_cwd(), "plugins")]), %% Process each command, resetting any state between each one State2 = rebar_state:set(State1, base_dir, filename:absname(rebar_state:dir(State1))), {ok, Providers} = application:get_env(rebar, providers), - State3 = rebar_state:create_logic_providers(Providers, State2), - Task = rebar_state:get(State3, task, "help"), - rebar_core:process_command(rebar_state:command_args(State3, Args), list_to_atom(Task)), - ok. + + {ok, PluginProviders, State3} = rebar_plugins:install(State2), + rebar_core:update_code_path(State3), + + State4 = rebar_state:create_logic_providers(Providers++PluginProviders, State3), + {Task, Args} = parse_args(RawArgs), + + rebar_core:process_command(rebar_state:command_args(State4, Args), list_to_atom(Task)). %% %% Parse command line arguments using getopt and also filtering out any %% key=value pairs. What's left is the list of commands to run %% -parse_args(RawArgs) -> - %% Parse getopt options - OptSpecList = option_spec_list(), - case getopt:parse(OptSpecList, RawArgs) of - {ok, Args} -> - Args; - {error, {Reason, Data}} -> - ?ERROR("~s ~p~n~n", [Reason, Data]), - rebar_utils:delayed_halt(1) - end. +parse_args([]) -> + parse_args(["help"]); +parse_args([H | Rest]) when H =:= "-h" + ; H =:= "--help" -> + parse_args(["help" | Rest]); +parse_args([H | Rest]) when H =:= "-v" + ; H =:= "--version" -> + parse_args(["version" | Rest]); +parse_args([RawTask | RawRest]) -> + {RawTask, RawRest}. set_options(State, {Options, NonOptArgs}) -> GlobalDefines = proplists:get_all_values(defines, Options), @@ -166,32 +176,26 @@ set_options(State, {Options, NonOptArgs}) -> %% Set global variables based on getopt options State2 = set_global_flag(State1, Options, force), - State3 = case proplists:get_value(jobs, Options, ?DEFAULT_JOBS) of - ?DEFAULT_JOBS -> - State2; - Jobs -> - rebar_state:set(State2, jobs, Jobs) - end, Task = proplists:get_value(task, Options, "help"), - {rebar_state:set(State3, task, Task), NonOptArgs}. + {rebar_state:set(State2, task, Task), NonOptArgs}. %% %% get log level based on getopt option %% -log_level(Options) -> - case proplists:get_bool(quiet, Options) of - true -> - rebar_log:error_level(); +log_level() -> + case os:getenv("QUIET") of false -> DefaultLevel = rebar_log:default_level(), - case proplists:get_all_values(verbose, Options) of - [] -> + case os:getenv("DEBUG") of + false -> DefaultLevel; - Verbosities -> - DefaultLevel + lists:last(Verbosities) - end + _ -> + DefaultLevel + 3 + end; + _ -> + rebar_log:error_level() end. %% @@ -218,17 +222,12 @@ set_global_flag(State, Options, Flag) -> %% %% options accepted via getopt %% -option_spec_list() -> - Jobs = ?DEFAULT_JOBS, - JobsHelp = io_lib:format( - "Number of concurrent workers a command may use. Default: ~B", - [Jobs]), +global_option_spec_list() -> [ - %% {Name, ShortOpt, LongOpt, ArgSpec, HelpMsg} - {help, $h, "help", undefined, "Print this help."}, - {verbose, $v, "verbose", integer, "Verbosity level (-v, -vv)."}, - {version, $V, "version", undefined, "Show version information."}, - {jobs, $j, "jobs", integer, JobsHelp}, - {config, $C, "config", string, "Rebar config file to use."}, - {task, undefined, undefined, string, "Task to run."} + %% {Name, ShortOpt, LongOpt, ArgSpec, HelpMsg} + {help, $h, "help", undefined, "Print this help."}, + %{verbose, $v, "verbose", integer, "Verbosity level (-v, -vv)."}, + {version, $V, "version", undefined, "Show version information."}, + %{config, $C, "config", string, "Rebar config file to use."}, + {task, undefined, undefined, string, "Task to run."} ]. diff --git a/src/rebar_app_discover.erl b/src/rebar_app_discover.erl index c90a8df..ae4916e 100644 --- a/src/rebar_app_discover.erl +++ b/src/rebar_app_discover.erl @@ -13,7 +13,8 @@ do(State, LibDirs) -> Apps = find_apps(Dirs, all), ProjectDeps = rebar_state:deps_names(State), lists:foldl(fun(AppInfo, StateAcc) -> - rebar_state:project_apps(StateAcc, rebar_app_info:deps(AppInfo, ProjectDeps)) + ProjectDeps1 = lists:delete(rebar_app_info:name(AppInfo), ProjectDeps), + rebar_state:project_apps(StateAcc, rebar_app_info:deps(AppInfo, ProjectDeps1)) end, State, Apps). -spec all_app_dirs(list(file:name())) -> list(file:name()). @@ -47,14 +48,17 @@ app_dirs(LibDir) -> find_unbuilt_apps(LibDirs) -> find_apps(LibDirs, invalid). +-spec find_apps([file:filename_all()]) -> [rebar_app_info:t()]. find_apps(LibDirs) -> find_apps(LibDirs, valid). +-spec find_apps([file:filename_all()], valid | invalid | all) -> [rebar_app_info:t()]. find_apps(LibDirs, Validate) -> rebar_utils:filtermap(fun(AppDir) -> find_app(AppDir, Validate) end, all_app_dirs(LibDirs)). +-spec find_app(file:filename_all(), valid | invalid | all) -> {true, rebar_app_info:t()} | false. find_app(AppDir, Validate) -> AppFile = filelib:wildcard(filename:join([AppDir, "ebin", "*.app"])), AppSrcFile = filelib:wildcard(filename:join([AppDir, "src", "*.app.src"])), @@ -104,12 +108,17 @@ find_app(AppDir, Validate) -> app_dir(AppFile) -> filename:join(rebar_utils:droplast(filename:split(filename:dirname(AppFile)))). +-spec create_app_info(file:name(), file:name()) -> rebar_app_info:t() | error. create_app_info(AppDir, AppFile) -> case file:consult(AppFile) of {ok, [{application, AppName, AppDetails}]} -> AppVsn = proplists:get_value(vsn, AppDetails), + %AppDeps = proplists:get_value(applications, AppDetails, []), + C = rebar_config:consult(AppDir), + S = rebar_state:new(rebar_state:new(), C, AppDir), + AppDeps = rebar_state:deps_names(S), AbsCwd = filename:absname(rebar_utils:get_cwd()), - {ok, AppInfo} = rebar_app_info:new(AppName, AppVsn, AppDir), + {ok, AppInfo} = rebar_app_info:new(AppName, AppVsn, AppDir, AppDeps), RebarConfig = filename:join(AppDir, "rebar.config"), AppState = case filelib:is_file(RebarConfig) of true -> @@ -121,22 +130,28 @@ create_app_info(AppDir, AppFile) -> AppState1 = rebar_state:set(AppState, base_dir, AbsCwd), AppInfo1 = rebar_app_info:config( rebar_app_info:app_details(AppInfo, AppDetails), AppState1), - rebar_app_info:dir(AppInfo1, AppDir) + rebar_app_info:dir(AppInfo1, AppDir); + _ -> + error end. -spec validate_application_info(rebar_app_info:t()) -> boolean(). validate_application_info(AppInfo) -> EbinDir = rebar_app_info:ebin_dir(AppInfo), - AppFile = rebar_app_info:app_file(AppInfo), - AppDetail = rebar_app_info:app_details(AppInfo), - case get_modules_list(AppFile, AppDetail) of - {ok, List} -> - has_all_beams(EbinDir, List); - _Error -> - false + case rebar_app_info:app_file(AppInfo) of + undefined -> + false; + AppFile -> + AppDetail = rebar_app_info:app_details(AppInfo), + case get_modules_list(AppFile, AppDetail) of + {ok, List} -> + has_all_beams(EbinDir, List); + _Error -> + false + end end. --spec get_modules_list(file:name(), proplists:proplist()) -> +-spec get_modules_list(file:filename_all(), proplists:proplist()) -> {ok, list()} | {warning, Reason::term()} | {error, Reason::term()}. @@ -148,8 +163,7 @@ get_modules_list(AppFile, AppDetail) -> {ok, ModulesList} end. --spec has_all_beams(file:name(), list()) -> - ok | {error, Reason::term()}. +-spec has_all_beams(file:filename_all(), list()) -> boolean(). has_all_beams(EbinDir, [Module | ModuleList]) -> BeamFile = filename:join([EbinDir, ec_cnv:to_list(Module) ++ ".beam"]), diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl index 008bfd2..7a33811 100644 --- a/src/rebar_app_info.erl +++ b/src/rebar_app_info.erl @@ -1,7 +1,6 @@ -module(rebar_app_info). --export([new/0, - new/1, +-export([new/1, new/2, new/3, new/4, @@ -21,6 +20,8 @@ ebin_dir/1, deps/1, deps/2, + dep_level/1, + dep_level/2, dir/1, dir/2, source/1, @@ -31,43 +32,40 @@ -export_type([t/0]). -record(app_info_t, {name :: binary(), - app_file_src :: file:name() | undefined, - app_file :: file:name(), - config :: rebar_config:config() | undefined, - original_vsn :: string(), + app_file_src :: file:filename_all() | undefined, + app_file :: file:filename_all() | undefined, + config :: rebar_state:t() | undefined, + original_vsn :: binary() | string() | undefined, app_details=[] :: list(), deps=[] :: list(), + dep_level :: integer(), dir :: file:name(), - source :: string() | undefined, + source :: string() | tuple() | undefined, valid :: boolean()}). %%============================================================================ %% types %%============================================================================ --opaque t() :: record(app_info_t). +-type t() :: record(app_info_t). %%============================================================================ %% API %% ============================================================================ %% @doc Build a new, empty, app info value. This is not of a lot of use and you %% probably wont be doing this much. --spec new() -> {ok, t()}. -new() -> - {ok, #app_info_t{}}. - -spec new(atom() | binary() | string()) -> {ok, t()}. new(AppName) -> {ok, #app_info_t{name=ec_cnv:to_binary(AppName)}}. --spec new(atom() | binary() | string(), string()) -> +-spec new(atom() | binary() | string(), binary() | string()) -> {ok, t()}. new(AppName, Vsn) -> {ok, #app_info_t{name=ec_cnv:to_binary(AppName), original_vsn=Vsn}}. %% @doc build a complete version of the app info with all fields set. --spec new(atom() | binary() | string(), string(), file:name()) -> +-spec new(atom() | binary() | string(), binary() | string(), file:name()) -> {ok, t()}. new(AppName, Vsn, Dir) -> {ok, #app_info_t{name=ec_cnv:to_binary(AppName), @@ -75,7 +73,7 @@ new(AppName, Vsn, Dir) -> dir=Dir}}. %% @doc build a complete version of the app info with all fields set. --spec new(atom() | binary() | string(), string(), file:name(), list()) -> +-spec new(atom() | binary() | string(), binary() | string(), file:name(), list()) -> {ok, t()}. new(AppName, Vsn, Dir, Deps) -> {ok, #app_info_t{name=ec_cnv:to_binary(AppName), @@ -84,17 +82,16 @@ new(AppName, Vsn, Dir, Deps) -> deps=Deps}}. %% @doc discover a complete version of the app info with all fields set. --spec discover(file:name()) -> - {ok, t()}. +-spec discover(file:filename_all()) -> {ok, t()} | not_found. discover(Dir) -> case rebar_app_discover:find_app(Dir, all) of {true, AppInfo} -> {ok, AppInfo}; - _ -> + false -> not_found end. --spec name(t()) -> atom(). +-spec name(t()) -> binary(). name(#app_info_t{name=Name}) -> Name. @@ -102,15 +99,15 @@ name(#app_info_t{name=Name}) -> name(AppInfo=#app_info_t{}, AppName) -> AppInfo#app_info_t{name=ec_cnv:to_binary(AppName)}. --spec config(t()) -> rebar_config:confg(). +-spec config(t()) -> rebar_state:t(). config(#app_info_t{config=Config}) -> Config. --spec config(t(), rebar_config:confg()) -> t(). +-spec config(t(), rebar_state:t()) -> t(). config(AppInfo=#app_info_t{}, Config) -> AppInfo#app_info_t{config=Config}. --spec app_file_src(t()) -> file:name(). +-spec app_file_src(t()) -> file:filename_all() | undefined. app_file_src(#app_info_t{app_file_src=undefined, dir=Dir, name=Name}) -> AppFileSrc = filename:join([ec_cnv:to_list(Dir), "src", ec_cnv:to_list(Name)++".app.src"]), case filelib:is_file(AppFileSrc) of @@ -122,11 +119,11 @@ app_file_src(#app_info_t{app_file_src=undefined, dir=Dir, name=Name}) -> app_file_src(#app_info_t{app_file_src=AppFileSrc}) -> ec_cnv:to_list(AppFileSrc). --spec app_file_src(t(), file:name()) -> t(). +-spec app_file_src(t(), file:filename_all()) -> t(). app_file_src(AppInfo=#app_info_t{}, AppFileSrc) -> AppInfo#app_info_t{app_file_src=ec_cnv:to_list(AppFileSrc)}. --spec app_file(t()) -> file:name(). +-spec app_file(t()) -> file:filename_all() | undefined. app_file(#app_info_t{app_file=undefined, dir=Dir, name=Name}) -> AppFile = filename:join([ec_cnv:to_list(Dir), "ebin", ec_cnv:to_list(Name)++".app"]), case filelib:is_file(AppFile) of @@ -138,9 +135,9 @@ app_file(#app_info_t{app_file=undefined, dir=Dir, name=Name}) -> app_file(#app_info_t{app_file=AppFile}) -> AppFile. --spec app_file(t(), file:name()) -> t(). +-spec app_file(t(), file:filename_all()) -> t(). app_file(AppInfo=#app_info_t{}, AppFile) -> - AppInfo#app_info_t{app_file=ec_cnv:to_list(AppFile)}. + AppInfo#app_info_t{app_file=AppFile}. -spec app_details(t()) -> list(). app_details(#app_info_t{app_details=AppDetails}) -> @@ -154,7 +151,7 @@ app_details(AppInfo=#app_info_t{}, AppDetails) -> original_vsn(#app_info_t{original_vsn=Vsn}) -> Vsn. --spec original_vsn(t(), string()) -> string(). +-spec original_vsn(t(), string()) -> t(). original_vsn(AppInfo=#app_info_t{}, Vsn) -> AppInfo#app_info_t{original_vsn=Vsn}. @@ -166,6 +163,12 @@ deps(#app_info_t{deps=Deps}) -> deps(AppInfo=#app_info_t{}, Deps) -> AppInfo#app_info_t{deps=Deps}. +dep_level(AppInfo=#app_info_t{}, Level) -> + AppInfo#app_info_t{dep_level=Level}. + +dep_level(#app_info_t{dep_level=Level}) -> + Level. + -spec dir(t()) -> file:name(). dir(#app_info_t{dir=Dir}) -> Dir. @@ -178,11 +181,11 @@ dir(AppInfo=#app_info_t{}, Dir) -> ebin_dir(#app_info_t{dir=Dir}) -> filename:join(Dir, "ebin"). --spec source(t(), string()) -> t(). +-spec source(t(), string() | tuple()) -> t(). source(AppInfo=#app_info_t{}, Source) -> AppInfo#app_info_t{source=Source}. --spec source(t()) -> string(). +-spec source(t()) -> string() | tuple(). source(#app_info_t{source=Source}) -> Source. diff --git a/src/rebar_app_utils.erl b/src/rebar_app_utils.erl index 1c53743..8fc3df8 100644 --- a/src/rebar_app_utils.erl +++ b/src/rebar_app_utils.erl @@ -26,13 +26,14 @@ %% ------------------------------------------------------------------- -module(rebar_app_utils). --export([is_app_dir/0, is_app_dir/1, +-export([find/2, + find/3, + is_app_dir/0, is_app_dir/1, is_app_src/1, app_src_to_app/1, app_name/2, app_applications/2, - app_vsn/2, - is_skipped_app/2]). + app_vsn/2]). -export([load_app_file/2]). % TEMPORARY @@ -42,9 +43,22 @@ %% Public API %% =================================================================== +-spec find(binary(), [rebar_app_info:t()]) -> {ok, rebar_app_info:t()} | error. +find(Name, Apps) -> + ec_lists:find(fun(App) -> rebar_app_info:name(App) =:= Name end, Apps). + +-spec find(binary(), binary(), [rebar_app_info:t()]) -> {ok, rebar_app_info:t()} | error. +find(Name, Vsn, Apps) -> + ec_lists:find(fun(App) -> + rebar_app_info:name(App) =:= Name + andalso rebar_app_info:original_vsn(App) =:= Vsn + end, Apps). + +-spec is_app_dir() -> {true, file:name()} | false. is_app_dir() -> is_app_dir(rebar_utils:get_cwd()). +-spec is_app_dir(file:name()) -> {true, file:name()} | false. is_app_dir(Dir) -> SrcDir = filename:join([Dir, "src"]), AppSrc = filename:join([SrcDir, "*.app.src"]), @@ -109,30 +123,6 @@ app_vsn(Config, AppFile) -> [AppFile, Reason]) end. -is_skipped_app(Config, AppFile) -> - {Config1, ThisApp} = app_name(Config, AppFile), - %% Check for apps global parameter; this is a comma-delimited list - %% of apps on which we want to run commands - Skipped = - case get_apps(Config) of - undefined -> - %% No apps parameter specified, check the skip_apps list.. - case get_skip_apps(Config) of - undefined -> - %% No skip_apps list, run everything.. - false; - SkipApps -> - TargetApps = [list_to_atom(A) || - A <- string:tokens(SkipApps, ",")], - is_skipped(ThisApp, TargetApps) - end; - Apps -> - %% run only selected apps - TargetApps = [list_to_atom(A) || A <- string:tokens(Apps, ",")], - is_selected(ThisApp, TargetApps) - end, - {Config1, Skipped}. - %% =================================================================== %% Internal functions %% =================================================================== @@ -176,27 +166,3 @@ get_value(Key, AppInfo, AppFile) -> Value -> Value end. - -%% apps= for selecting apps -is_selected(ThisApp, TargetApps) -> - case lists:member(ThisApp, TargetApps) of - false -> - {true, ThisApp}; - true -> - false - end. - -%% skip_apps= for filtering apps -is_skipped(ThisApp, TargetApps) -> - case lists:member(ThisApp, TargetApps) of - false -> - false; - true -> - {true, ThisApp} - end. - -get_apps(Config) -> - rebar_config:get_global(Config, apps, undefined). - -get_skip_apps(Config) -> - rebar_config:get_global(Config, skip_apps, undefined). diff --git a/src/rebar_config.erl b/src/rebar_config.erl index a45bef9..7ef2488 100644 --- a/src/rebar_config.erl +++ b/src/rebar_config.erl @@ -35,11 +35,11 @@ %% Public API %% =================================================================== --spec consult(file:name()) -> {ok, any()}. +-spec consult(file:name()) -> [any()]. consult(Dir) -> consult_file(filename:join(Dir, ?DEFAULT_CONFIG_FILE)). --spec consult_file(file:name()) -> {ok, any()}. +-spec consult_file(file:name()) -> [any()]. consult_file(File) when is_binary(File) -> consult_file(binary_to_list(File)); consult_file(File) -> @@ -73,7 +73,6 @@ remove_script_ext(F) -> try_consult(File) -> case file:consult(File) of {ok, Terms} -> - ?DEBUG("Consult config file ~p~n", [File]), Terms; {error, enoent} -> []; diff --git a/src/rebar_core.erl b/src/rebar_core.erl index cb021e3..16d8f07 100644 --- a/src/rebar_core.erl +++ b/src/rebar_core.erl @@ -26,33 +26,61 @@ %% ------------------------------------------------------------------- -module(rebar_core). --export([process_command/2]). +-export([process_command/2 + ,update_code_path/1]). -include("rebar.hrl"). +-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), + TargetProviders = providers:get_target_providers(Command, Providers), + case providers:get_provider(Command, Providers) of + not_found -> + {error, io_lib:format("Command ~p not found", [Command])}; + CommandProvider -> + Opts = providers:opts(CommandProvider)++rebar3:global_option_spec_list(), + case Command of + do -> + do(TargetProviders, State); + _ -> + case getopt:parse(Opts, rebar_state:command_args(State)) of + {ok, Args} -> + State2 = rebar_state:command_parsed_args(State, Args), + do(TargetProviders, State2); + {error, {invalid_option, Option}} -> + {error, io_lib:format("Invalid option ~s on task ~p", [Option, Command])} + end + end + end. + +-spec do([atom()], rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. +do([], State) -> + {ok, State}; +do([ProviderName | Rest], State) -> + Provider = providers:get_provider(ProviderName + ,rebar_state:providers(State)), + case providers:do(Provider, State) of + {ok, State1} -> + do(Rest, State1); + {error, Error} -> + {error, Error} + end. + +update_code_path(State) -> true = rebar_utils:expand_code_path(), LibDirs = rebar_state:get(State, lib_dirs, ?DEFAULT_LIB_DIRS), - DepsDir = rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIRS), - _UpdatedCodePaths = update_code_path([DepsDir | LibDirs]), - rebar_prv_install_deps:setup_env(State), - - TargetProviders = rebar_provider:get_target_providers(Command, State), + DepsDir = rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR), + PluginsDir = rebar_state:get(State, plugins_dir, ?DEFAULT_PLUGINS_DIR), + _UpdatedCodePaths = update_code_path_([DepsDir, PluginsDir | LibDirs]). - lists:foldl(fun(TargetProvider, Conf) -> - Provider = rebar_provider:get_provider(TargetProvider - ,rebar_state:providers(Conf)), - {ok, Conf1} = rebar_provider:do(Provider, Conf), - Conf1 - end, State, TargetProviders). %% =================================================================== %% Internal functions %% =================================================================== -update_code_path([]) -> - no_change; -update_code_path(Paths) -> +update_code_path_(Paths) -> LibPaths = expand_lib_dirs(Paths, rebar_utils:get_cwd(), []), ok = code:add_pathsa(LibPaths), %% track just the paths we added, so we can remove them without diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl index 6a16977..33983e4 100644 --- a/src/rebar_erlc_compiler.erl +++ b/src/rebar_erlc_compiler.erl @@ -96,30 +96,30 @@ compile(Config, Dir) -> rebar_base_compiler:run(Config, check_files(rebar_state:get( Config, xrl_first_files, [])), - "src", ".xrl", "src", ".erl", + filename:join(Dir, "src"), ".xrl", filename:join(Dir, "src"), ".erl", fun compile_xrl/3), rebar_base_compiler:run(Config, check_files(rebar_state:get( Config, yrl_first_files, [])), - "src", ".yrl", "src", ".erl", + filename:join(Dir, "src"), ".yrl", filename:join(Dir, "src"), ".erl", fun compile_yrl/3), rebar_base_compiler:run(Config, check_files(rebar_state:get( Config, mib_first_files, [])), - "mibs", ".mib", "priv/mibs", ".bin", + filename:join(Dir, "mibs"), ".mib", filename:join([Dir, "priv", "mibs"]), ".bin", fun compile_mib/3), doterl_compile(Config, Dir). -spec clean(rebar_state:t(), file:filename()) -> 'ok'. -clean(Config, _AppFile) -> - MibFiles = rebar_utils:find_files("mibs", ?RE_PREFIX".*\\.mib\$"), +clean(Config, AppDir) -> + MibFiles = rebar_utils:find_files(filename:join(AppDir, "mibs"), ?RE_PREFIX".*\\.mib\$"), MIBs = [filename:rootname(filename:basename(MIB)) || MIB <- MibFiles], rebar_file_utils:delete_each( - [filename:join(["include",MIB++".hrl"]) || MIB <- MIBs]), + [filename:join([AppDir, "include",MIB++".hrl"]) || MIB <- MIBs]), lists:foreach(fun(F) -> ok = rebar_file_utils:rm_rf(F) end, - ["ebin/*.beam", "priv/mibs/*.bin"]), + [filename:join(AppDir, "ebin/*.beam"), filename:join(AppDir, "priv/mibs/*.bin")]), - YrlFiles = rebar_utils:find_files("src", ?RE_PREFIX".*\\.[x|y]rl\$"), + YrlFiles = rebar_utils:find_files(filename:join(AppDir, "src"), ?RE_PREFIX".*\\.[x|y]rl\$"), rebar_file_utils:delete_each( [ binary_to_list(iolist_to_binary(re:replace(F, "\\.[x|y]rl$", ".erl"))) || F <- YrlFiles ]), @@ -131,9 +131,9 @@ clean(Config, _AppFile) -> %% directory structure in ebin with .beam files within. As such, we want %% to scan whatever is left in the ebin/ directory for sub-dirs which %% satisfy our criteria. - BeamFiles = rebar_utils:find_files("ebin", ?RE_PREFIX".*\\.beam\$"), + BeamFiles = rebar_utils:find_files(filename:join(AppDir, "ebin"), ?RE_PREFIX".*\\.beam\$"), rebar_file_utils:delete_each(BeamFiles), - lists:foreach(fun(Dir) -> delete_dir(Dir, dirs(Dir)) end, dirs("ebin")), + lists:foreach(fun(Dir) -> delete_dir(Dir, dirs(Dir)) end, dirs(filename:join(AppDir, "ebin"))), ok. %% =================================================================== @@ -241,14 +241,14 @@ test_compile_config_and_opts(Config, ErlOpts, Cmd) -> %% *_first_files is questionable as the file would need to exist %% in all project directories for it to work. OptsAtom = list_to_atom(Cmd ++ "_compile_opts"), - TestOpts = rebar_state:get_list(Config3, OptsAtom, []), + TestOpts = rebar_state:get(Config3, OptsAtom, []), Opts0 = [{d, 'TEST'}] ++ ErlOpts ++ TestOpts ++ TriqOpts ++ PropErOpts ++ EqcOpts, Opts = [O || O <- Opts0, O =/= no_debug_info], Config4 = rebar_state:set(Config3, erl_opts, Opts), FirstFilesAtom = list_to_atom(Cmd ++ "_first_files"), - FirstErls = rebar_state:get_list(Config4, FirstFilesAtom, []), + FirstErls = rebar_state:get(Config4, FirstFilesAtom, []), Config5 = rebar_state:set(Config4, erl_first_files, FirstErls), {Config5, Opts}. @@ -274,7 +274,7 @@ define_if(Def, true) -> [{d, Def}]; define_if(_Def, false) -> []. is_lib_avail(Config, DictKey, Mod, Hrl, Name) -> - case rebar_state:get_xconf(Config, DictKey, undefined) of + case rebar_state:get(Config, DictKey, undefined) of undefined -> IsAvail = case code:lib_dir(Mod, include) of {error, bad_name} -> @@ -282,17 +282,17 @@ is_lib_avail(Config, DictKey, Mod, Hrl, Name) -> Dir -> filelib:is_regular(filename:join(Dir, Hrl)) end, - NewConfig = rebar_state:set_xconf(Config, DictKey, IsAvail), + NewConfig = rebar_state:set(Config, DictKey, IsAvail), ?DEBUG("~s availability: ~p\n", [Name, IsAvail]), {NewConfig, IsAvail}; IsAvail -> {Config, IsAvail} end. --spec doterl_compile(rebar_state:t(), file:filename()) -> 'ok'. -doterl_compile(Config, Dir) -> - ErlOpts = rebar_utils:erl_opts(Config), - doterl_compile(Config, Dir, [], ErlOpts). +-spec doterl_compile(rebar_state:t(), file:filename()) -> ok. +doterl_compile(State, Dir) -> + ErlOpts = rebar_utils:erl_opts(State), + doterl_compile(State, Dir, [], ErlOpts). doterl_compile(Config, Dir, MoreSources, ErlOpts) -> OutDir = filename:join(Dir, "ebin"), @@ -634,16 +634,19 @@ compile_yrl(Source, Target, Config) -> -spec compile_xrl_yrl(rebar_state:t(), file:filename(), file:filename(), list(), module()) -> 'ok'. compile_xrl_yrl(Config, Source, Target, Opts, Mod) -> + Dir = rebar_state:dir(Config), + Opts1 = [{includefile, filename:join(Dir, I)} || {includefile, I} <- Opts, + filename:pathtype(I) =:= relative], case needs_compile(Source, Target, []) of true -> - case Mod:file(Source, Opts ++ [{return, true}]) of + case Mod:file(Source, Opts1 ++ [{return, true}]) of {ok, _} -> ok; {ok, _Mod, Ws} -> rebar_base_compiler:ok_tuple(Config, Source, Ws); {error, Es, Ws} -> rebar_base_compiler:error_tuple(Config, Source, - Es, Ws, Opts) + Es, Ws, Opts1) end; false -> skipped diff --git a/src/rebar_fetch.erl b/src/rebar_fetch.erl index 6b31f6c..0a90848 100644 --- a/src/rebar_fetch.erl +++ b/src/rebar_fetch.erl @@ -49,14 +49,16 @@ lock_source(_AppDir, Source) -> download_source(AppDir, Source) -> TmpDir = ec_file:insecure_mkdtemp(), AppDir1 = ec_cnv:to_list(AppDir), + ec_file:mkdir_p(AppDir1), case download_source_tmp(TmpDir, Source) of {ok, _} -> - ec_file:mkdir_p(AppDir1), ok = ec_file:copy(TmpDir, filename:absname(AppDir1), [recursive]); {tarball, File} -> - ok = erl_tar:extract(File, [{cwd, - (filename:dirname(filename:absname(AppDir1)))} - ,compressed]) + ok = erl_tar:extract(File, [{cwd, TmpDir} + ,compressed]), + BaseName = filename:basename(AppDir1), + [FromDir] = filelib:wildcard(filename:join(TmpDir, BaseName++"-*")), + ec_file:copy(FromDir, AppDir1, [recursive]) end. download_source_tmp(TmpDir, {p4, Url}) -> diff --git a/src/rebar_packages.erl b/src/rebar_packages.erl index 103d3a3..cd979fa 100644 --- a/src/rebar_packages.erl +++ b/src/rebar_packages.erl @@ -4,7 +4,7 @@ -include("rebar.hrl"). --spec get_packages(rebar_state:t()) -> {list(), rlx_depsolver:t()}. +-spec get_packages(rebar_state:t()) -> {rebar_dict(), rlx_depsolver:t()}. get_packages(State) -> RebarDir = rebar_state:get(State, global_rebar_dir, filename:join(os:getenv("HOME"), ".rebar")), PackagesFile = filename:join(RebarDir, "packages"), @@ -12,12 +12,13 @@ get_packages(State) -> true -> try {ok, Binary} = file:read_file(PackagesFile), - binary_to_term(Binary) + {Dict, Graph} = binary_to_term(Binary), + {Dict, Graph} catch _:_ -> ?ERROR("Bad packages index, try to fix with `rebar update`~n", []), - {[], rlx_depsolver:new()} + {dict:new(), rlx_depsolver:new_graph()} end; false -> - {[], rlx_depsolver:new()} + {dict:new(), rlx_depsolver:new_graph()} end. diff --git a/src/rebar_plugins.erl b/src/rebar_plugins.erl index 0fdbc6d..b180ede 100644 --- a/src/rebar_plugins.erl +++ b/src/rebar_plugins.erl @@ -3,10 +3,36 @@ -module(rebar_plugins). --export([]). +-export([install/1]). -include("rebar.hrl"). %% =================================================================== %% Public API %% =================================================================== + +install(State) -> + State1 = rebar_state:set(State, deps_dir, ?DEFAULT_PLUGINS_DIR), + + Plugins = rebar_state:get(State1, plugins, []), + {ok, State2} = rebar_prv_install_deps:handle_deps(State1, Plugins), + + Apps = rebar_state:get(State2, all_deps, []), + ToBuild = lists:dropwhile(fun rebar_app_info:valid/1, Apps), + lists:foreach(fun(AppInfo) -> + C = rebar_config:consult(rebar_app_info:dir(AppInfo)), + S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(AppInfo)), + rebar_prv_compile:build(S, AppInfo) + end, ToBuild), + + PluginProviders = plugin_providers(Plugins), + {ok, PluginProviders, rebar_state:set(State2, deps_dir, ?DEFAULT_DEPS_DIR)}. + +plugin_providers(Plugins) -> + lists:map(fun({Plugin, _, _}) when is_atom(Plugin) -> + Plugin; + ({Plugin, _}) when is_atom(Plugin) -> + Plugin; + (Plugin) when is_atom(Plugin) -> + Plugin + end, Plugins). diff --git a/src/rebar_provider.erl b/src/rebar_provider.erl deleted file mode 100644 index e5d7520..0000000 --- a/src/rebar_provider.erl +++ /dev/null @@ -1,165 +0,0 @@ --module(rebar_provider). - -%% API --export([new/2, - do/2, - impl/1, - get_provider/2, - get_target_providers/2, - help/1, - format/1]). - --export_type([t/0]). - --include("rebar.hrl"). - -%%%=================================================================== -%%% Types -%%%=================================================================== - --opaque t() :: record(provider). - --type provider_name() :: atom(). - --ifdef(have_callback_support). - --callback init(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error(). --callback do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error(). - --else. - -%% In the case where R14 or lower is being used to compile the system -%% we need to export a behaviour info --export([behaviour_info/1]). --spec behaviour_info(atom()) -> [{atom(), arity()}] | undefined. -behaviour_info(callbacks) -> - [{init, 1}, - {do, 1}]; -behaviour_info(_) -> - undefined. - --endif. - -%%%=================================================================== -%%% API -%%%=================================================================== - -%% @doc create a new provider object from the specified module. The -%% module should implement the provider behaviour. -%% -%% @param ModuleName The module name. -%% @param State0 The current state of the system --spec new(module(), rebar_state:t()) -> - {ok, rebar_state:t()}. -new(ModuleName, State0) when is_atom(ModuleName) -> - case code:which(ModuleName) of - non_existing -> - ?ERROR("Module ~p does not exist.", [ModuleName]); - _ -> - ModuleName:init(State0) - end. - -%% @doc Manipulate the state of the system, that new state -%% -%% @param Provider the provider object -%% @param State the current state of the system --spec do(Provider::t(), rebar_state:t()) -> - {ok, rebar_state:t()}. -do(Provider, State) -> - {PreHooks, PostHooks} = rebar_state:hooks(State, Provider#provider.name), - {ok, State1} = run_hook_plugins(PreHooks, State), - {ok, State2} = (Provider#provider.provider_impl):do(State1), - run_hook_plugins(PostHooks, State2). - -run_hook_plugins(Hooks, State) -> - State1 = lists:foldl(fun(Hook, StateAcc) -> - {ok, StateAcc1} = rebar_provider:do(Hook, StateAcc), - StateAcc1 - end, State, Hooks), - {ok, State1}. - -%%% @doc get the name of the module that implements the provider -%%% @param Provider the provider object --spec impl(Provider::t()) -> module(). -impl(Provider) -> - Provider#provider.name. - -help(State) -> - Providers = rebar_state:providers(State), - Help = lists:sort([{ec_cnv:to_list(P#provider.name), P#provider.short_desc} || P <- Providers, - P#provider.bare =/= true]), - Longest = lists:max([length(X) || {X, _} <- Help]), - - lists:foreach(fun({Name, ShortDesc}) -> - Length = length(Name), - Spacing = lists:duplicate(Longest - Length + 8, " "), - io:format("~s~s~s~n", [Name, Spacing, ShortDesc]) - end, Help). - - -%% @doc print the provider module name -%% -%% @param T - The provider -%% @return An iolist describing the provider --spec format(t()) -> iolist(). -format(#provider{name=Name}) -> - atom_to_list(Name). - -get_target_providers(Target, State) -> - Providers = rebar_state:providers(State), - TargetProviders = lists:filter(fun(#provider{name=T}) when T =:= Target-> - true; - (#provider{name=T}) -> - false - end, Providers), - process_deps(TargetProviders, Providers). - --spec get_provider(provider_name(), [t()]) -> t(). -get_provider(ProviderName, [Provider = #provider{name = ProviderName} | _]) -> - Provider; -get_provider(ProviderName, [_ | Rest]) -> - get_provider(ProviderName, Rest); -get_provider(_ProviderName, _) -> - []. - -process_deps([], _Providers) -> - []; -process_deps(TargetProviders, Providers) -> - DepChain = lists:flatmap(fun(Provider) -> - {DC, _, _} = process_deps(Provider, Providers, []), - DC - end, TargetProviders), - ['NONE' | Rest] = - reorder_providers(lists:flatten([{'NONE', P#provider.name} || P <- TargetProviders] ++ DepChain)), - Rest. - -process_deps(Provider, Providers, Seen) -> - case lists:member(Provider, Seen) of - true -> - {[], Providers, Seen}; - false -> - Deps = Provider#provider.deps, - DepList = lists:map(fun(Dep) -> - {Dep, Provider#provider.name} - end, Deps), - {NewDeps, _, NewSeen} = - lists:foldl(fun(Arg, Acc) -> - process_dep(Arg, Acc) - end, - {[], Providers, Seen}, Deps), - {[DepList | NewDeps], Providers, NewSeen} - end. - -process_dep(ProviderName, {Deps, Providers, Seen}) -> - Provider = get_provider(ProviderName, Providers), - {NewDeps, _, NewSeen} = process_deps(Provider, Providers, [ProviderName | Seen]), - {[Deps | NewDeps], Providers, NewSeen}. - -%% @doc Reorder the providers according to thier dependency set. -reorder_providers(OProviderList) -> - case rebar_topo:sort(OProviderList) of - {ok, ProviderList} -> - ProviderList; - {cycle, _} -> - ?ERROR("There was a cycle in the provider list. Unable to complete build!", []) - end. diff --git a/src/rebar_prv_app_discovery.erl b/src/rebar_prv_app_discovery.erl index 897a38d..e2dcf23 100644 --- a/src/rebar_prv_app_discovery.erl +++ b/src/rebar_prv_app_discovery.erl @@ -3,10 +3,11 @@ -module(rebar_prv_app_discovery). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). -include("rebar.hrl"). @@ -19,18 +20,22 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = true, - deps = ?DEPS, - example = "", - short_desc = "", - desc = "", - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, true}, + {deps, ?DEPS}, + {example, ""}, + {short_desc, ""}, + {desc, ""}, + {opts, []}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()}. +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> LibDirs = rebar_state:get(State, lib_dirs, ?DEFAULT_LIB_DIRS), State1 = rebar_app_discover:do(State, LibDirs), {ok, State1}. + +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. diff --git a/src/rebar_prv_clean.erl b/src/rebar_prv_clean.erl new file mode 100644 index 0000000..72b85dc --- /dev/null +++ b/src/rebar_prv_clean.erl @@ -0,0 +1,44 @@ +%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% ex: ts=4 sw=4 et + +-module(rebar_prv_clean). + +-behaviour(provider). + +-export([init/1, + do/1, + format_error/2]). + +-include("rebar.hrl"). + +-define(PROVIDER, clean). +-define(DEPS, [app_discovery]). + +%% =================================================================== +%% Public API +%% =================================================================== + +-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. +init(State) -> + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar clean"}, + {short_desc, "Remove compiled beam files from apps."}, + {desc, ""}, + {opts, []}])), + {ok, State1}. + +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. +do(State) -> + ProjectApps = rebar_state:project_apps(State), + lists:foreach(fun(AppInfo) -> + ?INFO("Cleaning out ~s...~n", [rebar_app_info:name(AppInfo)]), + rebar_erlc_compiler:clean(State, ec_cnv:to_list(rebar_app_info:dir(AppInfo))) + end, ProjectApps), + {ok, State}. + +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl index b880d77..37d1920 100644 --- a/src/rebar_prv_common_test.erl +++ b/src/rebar_prv_common_test.erl @@ -6,6 +6,7 @@ -behaviour(rebar_provider). -export([init/1, + format_error/2, do/1]). -include("rebar.hrl"). @@ -19,15 +20,15 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, - #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar ct", - short_desc = "Run Common Tests", - desc = "", - opts = []}), + Provider = providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {deps, ?DEPS}, + {bare, false}, + {example, "rebar ct"}, + {short_desc, "Run Common Tests"}, + {desc, ""}, + {opts, ct_opts(State)}]), + State1 = rebar_state:add_provider(State, Provider), {ok, State1}. -spec do(rebar_state:t()) -> {ok, rebar_state:t()}. @@ -36,6 +37,106 @@ do(State) -> ct:run_test(Opts), {ok, State}. +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. + +ct_opts(State) -> + DefaultTestDir = filename:join([rebar_state:dir(State), "test"]), + DefaultLogsDir = filename:join([rebar_state:dir(State), "logs"]), + [{dir, undefined, "dir", {string, DefaultTestDir}, help(dir)}, %% dir + {suite, undefined, "suite", string, help(suite)}, %% comma-seperated list + {group, undefined, "group", string, help(group)}, %% comma-seperated list + {testcase, undefined, "case", string, help(testcase)}, %% comma-seperated list + {spec, undefined, "spec", string, help(spec)}, %% comma-seperated list + {join_specs, undefined, "join_specs", boolean, help(join_specs)}, %% Boolean + {label, undefined, "label", string, help(label)}, %% String + {config, undefined, "config", string, help(config)}, %% comma-seperated list + {userconfig, undefined, "userconfig", string, help(userconfig)}, %% [{CallbackMod, CfgStrings}] | {CallbackMod, CfgStrings} + {allow_user_terms, undefined, "allow_user_terms", boolean, help(allow_user_terms)}, %% Bool + {logdir, undefined, "logdir", {string, DefaultLogsDir}, help(logdir)}, %% string + {logopts, undefined, "logopts", string, help(logopts)}, %% enum, no_nl | no_src + {verbosity, undefined, "verbosity", string, help(verbosity)}, %% Integer OR [{Category, VLevel}] + {silent_connections, undefined, "silent_connections", string, + help(silent_connections)}, % all OR %% comma-seperated list + {stylesheet, undefined, "stylesheet", string, help(stylesheet)}, %% file + {cover, undefined, "cover", string, help(cover)}, %% file + {cover_stop, undefined, "cover_stop", boolean, help(cover_stop)}, %% Boolean + {event_handler, undefined, "event_handler", string, help(event_handler)}, %% EH | [EH] WHERE EH atom() | {atom(), InitArgs} | {[atom()], InitArgs} + {include, undefined, "include", string, help(include)}, + {abort_if_missing_suites, undefined, "abort_if_missing_suites", {boolean, true}, + help(abort_if_missing_suites)}, %% boolean + {multiply_timetraps, undefined, "multiply_timetraps", integer, + help(multiply_timetraps)}, %% integer + {scale_timetraps, undefined, "scale_timetraps", boolean, help(scale_timetraps)}, %% Boolean + {create_priv_dir, undefined, "create_priv_dir", string, help(create_priv_dir)}, %% enum: auto_per_run | auto_per_tc | manual_per_tc + {repeat, undefined, "repeat", integer, help(repeat)}, %% integer + {duration, undefined, "duration", string, help(duration)}, % format: HHMMSS + {until, undefined, "until", string, help(until)}, %% format: YYMoMoDD[HHMMSS] + {force_stop, undefined, "force_stop", string, help(force_stop)}, % enum: skip_rest, bool + {basic_html, undefined, "basic_html", boolean, help(basic_html)}, %% Booloean + {ct_hooks, undefined, "ct_hooks", string, help(ct_hooks)} %% List: [CTHModule | {CTHModule, CTHInitArgs}] where CTHModule is atom CthInitArgs is term + ]. + +help(dir) -> + "Test folder (default: test/)"; +help(suite) -> + "List of test suites to run"; +help(group) -> + "List of test groups to run"; +help(testcase) -> + "List of test cases to run"; +help(spec) -> + "List of test specs to run"; +help(join_specs) -> + ""; %% ?? +help(label) -> + "Test label"; +help(config) -> + "List of config files"; +help(allow_user_terms) -> + ""; %% ?? +help(logdir) -> + "Log folder"; +help(logopts) -> + ""; %% ?? +help(verbosity) -> + "Verbosity"; +help(silent_connections) -> + ""; %% ?? +help(stylesheet) -> + "Stylesheet to use for test results"; +help(cover) -> + "Cover file to use"; +help(cover_stop) -> + ""; %% ?? +help(event_handler) -> + "Event handlers to attach to the runner"; +help(include) -> + "Include folder"; +help(abort_if_missing_suites) -> + "Abort if suites are missing"; +help(multiply_timetraps) -> + ""; %% ?? +help(scale_timetraps) -> + ""; %% ?? +help(create_priv_dir) -> + ""; %% ?? +help(repeat) -> + "How often to repeat tests"; +help(duration) -> + "Max runtime (format: HHMMSS)"; +help(until) -> + "Run until (format: HHMMSS)"; +help(force_stop) -> + "Force stop after time"; +help(basic_html) -> + "Show basic HTML"; +help(ct_hooks) -> + ""; +help(userconfig) -> + "". + build_options(State) -> Arguments = rebar_state:command_args(State), Opts = parse_args(Arguments, []), diff --git a/src/rebar_prv_compile.erl b/src/rebar_prv_compile.erl index d89a4b0..30611cd 100644 --- a/src/rebar_prv_compile.erl +++ b/src/rebar_prv_compile.erl @@ -1,9 +1,10 @@ -module(rebar_prv_compile). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, do/1, + format_error/2, build/2]). -include("rebar.hrl"). @@ -11,34 +12,48 @@ -define(PROVIDER, compile). -define(DEPS, [lock]). +-define(DEFAULT_JOBS, 3). + %% =================================================================== %% Public API %% =================================================================== -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar compile", - short_desc = "Compile apps .app.src and .erl files.", - desc = "", - opts = []}), + JobsHelp = io_lib:format( + "Number of concurrent workers the compiler may use. Default: ~B", + [?DEFAULT_JOBS]), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar compile"}, + {short_desc, "Compile apps .app.src and .erl files."}, + {desc, ""}, + {opts, [ + {jobs, $j, "jobs", integer, JobsHelp} + ]}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error(). +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> - ProjectApps = rebar_state:project_apps(State), - Deps = rebar_state:get(State, deps_to_build, []), + {ok, State1} = handle_args(State), + + ProjectApps = rebar_state:project_apps(State1), + Deps = rebar_state:get(State1, deps_to_build, []), lists:foreach(fun(AppInfo) -> - C = rebar_config:consult(rebar_app_info:dir(AppInfo)), - S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(AppInfo)), + AppDir = rebar_app_info:dir(AppInfo), + C = rebar_config:consult(AppDir), + S = rebar_state:new(State1, C, AppDir), build(S, AppInfo) end, Deps++ProjectApps), - {ok, State}. + {ok, State1}. + +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. build(State, AppInfo) -> ?INFO("Compiling ~s~n", [rebar_app_info:name(AppInfo)]), @@ -49,3 +64,8 @@ build(State, AppInfo) -> %% =================================================================== %% Internal functions %% =================================================================== + +handle_args(State) -> + {Args, _} = rebar_state:command_parsed_args(State), + Jobs = proplists:get_value(jobs, Args, ?DEFAULT_JOBS), + {ok, rebar_state:set(State, jobs, Jobs)}. diff --git a/src/rebar_prv_deps.erl b/src/rebar_prv_deps.erl index 111f32f..80122ac 100644 --- a/src/rebar_prv_deps.erl +++ b/src/rebar_prv_deps.erl @@ -1,9 +1,10 @@ -module(rebar_prv_deps). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). -include("rebar.hrl"). @@ -12,20 +13,24 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = true, - deps = ?DEPS, - example = "rebar deps", - short_desc = "List dependencies", - desc = info("List dependencies"), - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, true}, + {deps, ?DEPS}, + {example, "rebar deps"}, + {short_desc, "List dependencies"}, + {desc, info("List dependencies")}, + {opts, []}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()}. +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> {ok, State}. +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. + info(Description) -> io_lib:format("~s.~n" "~n" diff --git a/src/rebar_prv_do.erl b/src/rebar_prv_do.erl index a2ac648..e66fdbd 100644 --- a/src/rebar_prv_do.erl +++ b/src/rebar_prv_do.erl @@ -3,10 +3,11 @@ -module(rebar_prv_do). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). -include("rebar.hrl"). @@ -19,27 +20,30 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar3 do <task1>, <task2>, ...", - short_desc = "Higher order provider for running multiple tasks in a sequence.", - desc = "", - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar3 do <task1>, <task2>, ..."}, + {short_desc, "Higher order provider for running multiple tasks in a sequence."}, + {desc, ""}, + {opts, []}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error(). +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> Tasks = args_to_tasks(rebar_state:command_args(State)), - State1 = lists:foldl(fun(TaskArgs, StateAcc) -> + lists:foldl(fun(TaskArgs, {ok, StateAcc}) -> [TaskStr | Args] = string:tokens(TaskArgs, " "), Task = list_to_atom(TaskStr), StateAcc1 = rebar_state:set(StateAcc, task, Task), StateAcc2 = rebar_state:command_args(StateAcc1, Args), rebar_core:process_command(StateAcc2, Task) - end, State, Tasks), - {ok, State1}. + end, {ok, State}, Tasks). + +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. args_to_tasks(Args) -> [string:strip(T) || T <- string:tokens(string:join(Args, " "), ",")]. diff --git a/src/rebar_erlydtl_compiler.erl b/src/rebar_prv_erlydtl_compiler.erl index 88ee20f..8d80cdd 100644 --- a/src/rebar_erlydtl_compiler.erl +++ b/src/rebar_prv_erlydtl_compiler.erl @@ -92,12 +92,13 @@ %% {doc_root, "templates"}, {module_ext, ""}, {source_ext, ".html"} %% ] %% ]}. --module(rebar_erlydtl_compiler). +-module(rebar_prv_erlydtl_compiler). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). %% for internal use only -export([info/2]). @@ -113,22 +114,23 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar erlydtl compile", - short_desc = "Compile erlydtl templates.", - desc = "", - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar erlydtl compile"}, + {short_desc, "Compile erlydtl templates."}, + {desc, ""}, + {opts, []}])), {ok, State1}. do(Config) -> MultiDtlOpts = erlydtl_opts(Config), OrigPath = code:get_path(), - true = code:add_path(rebar_utils:ebin_dir()), + %true = code:add_path(rebar_utils:ebin_dir()), Result = lists:foldl(fun(DtlOpts, _) -> + file:make_dir(option(out_dir, DtlOpts)), rebar_base_compiler:run(Config, [], option(doc_root, DtlOpts), option(source_ext, DtlOpts), @@ -144,6 +146,10 @@ do(Config) -> true = code:set_path(OrigPath), {Result, Config}. +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. + %% =================================================================== %% Internal functions %% =================================================================== @@ -230,24 +236,15 @@ do_compile(Config, Source, Target, DtlOpts) -> Opts = lists:ukeymerge(1, DtlOpts, Sorted), ?INFO("Compiling \"~s\" -> \"~s\" with options:~n ~s~n", [Source, Target, io_lib:format("~p", [Opts])]), - case erlydtl:compile(Source, - module_name(Target), + case erlydtl:compile_file(ec_cnv:to_list(Source), + list_to_atom(module_name(Target)), Opts) of - ok -> - ok; {ok, _Mod} -> ok; {ok, _Mod, Ws} -> rebar_base_compiler:ok_tuple(Config, Source, Ws); - {ok, _Mod, _Bin, Ws} -> - rebar_base_compiler:ok_tuple(Config, Source, Ws); error -> rebar_base_compiler:error_tuple(Config, Source, [], [], Opts); - {error, {_File, _Msgs} = Error} -> - rebar_base_compiler:error_tuple(Config, Source, [Error], [], Opts); - {error, Msg} -> - Es = [{Source, [{erlydtl_parser, Msg}]}], - rebar_base_compiler:error_tuple(Config, Source, Es, [], Opts); {error, Es, Ws} -> rebar_base_compiler:error_tuple(Config, Source, Es, Ws, Opts) end. diff --git a/src/rebar_prv_escripter.erl b/src/rebar_prv_escripter.erl deleted file mode 100644 index 418ac6c..0000000 --- a/src/rebar_prv_escripter.erl +++ /dev/null @@ -1,224 +0,0 @@ -%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 et -%% ------------------------------------------------------------------- -%% -%% rebar: Erlang Build Tools -%% -%% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com) -%% -%% Permission is hereby granted, free of charge, to any person obtaining a copy -%% of this software and associated documentation files (the "Software"), to deal -%% in the Software without restriction, including without limitation the rights -%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the Software is -%% furnished to do so, subject to the following conditions: -%% -%% The above copyright notice and this permission notice shall be included in -%% all copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -%% THE SOFTWARE. -%% ------------------------------------------------------------------- --module(rebar_prv_escripter). - --behaviour(rebar_provider). - --export([init/1, - do/1]). - --export([escriptize/2, - clean/2]). - -%% for internal use only --export([info/2]). - --include("rebar.hrl"). --include_lib("kernel/include/file.hrl"). - --define(PROVIDER, escriptize). --define(DEPS, [app_builder]). - -%% =================================================================== -%% Public API -%% =================================================================== - --spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar escriptize", - short_desc = "Build escript from project.", - desc = "", - opts = []}), - {ok, State1}. - --spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error(). -do(Config) -> - AppName = rebar_state:get_local(Config, escript_top_level_app, undefined), - App = rebar_state:get_app(Config, AppName), - {ok, Config1} = escriptize(Config, rebar_app_info:app_file(App)), - {ok, Config1}. - -escriptize(Config0, AppFile) -> - %% Extract the application name from the archive -- this is the default - %% name of the generated script - {Config, AppName} = rebar_app_utils:app_name(Config0, AppFile), - AppNameStr = atom_to_list(AppName), - - %% Get the output filename for the escript -- this may include dirs - Filename = rebar_state:get_local(Config, escript_name, AppName), - ok = filelib:ensure_dir(Filename), - - %% Look for a list of other applications (dependencies) to include - %% in the output file. We then use the .app files for each of these - %% to pull in all the .beam files. - InclBeams = get_app_beams( - rebar_state:get_local(Config, escript_incl_apps, []), []), - - %% Look for a list of extra files to include in the output file. - %% For internal rebar-private use only. Do not use outside rebar. - InclExtra = get_extra(Config), - - %% Construct the archive of everything in ebin/ dir -- put it on the - %% top-level of the zip file so that code loading works properly. - EbinPrefix = filename:join(AppNameStr, "ebin"), - EbinFiles = usort(load_files(EbinPrefix, "*", "ebin")), - ExtraFiles = usort(InclBeams ++ InclExtra), - Files = EbinFiles ++ ExtraFiles, - - case zip:create("mem", Files, [memory]) of - {ok, {"mem", ZipBin}} -> - %% Archive was successfully created. Prefix that binary with our - %% header and write to our escript file - Shebang = rebar_state:get(Config, escript_shebang, - "#!/usr/bin/env escript\n"), - Comment = rebar_state:get(Config, escript_comment, "%%\n"), - DefaultEmuArgs = ?FMT("%%! -pa ~s/~s/ebin\n", - [AppNameStr, AppNameStr]), - EmuArgs = rebar_state:get(Config, escript_emu_args, - DefaultEmuArgs), - Script = iolist_to_binary([Shebang, Comment, EmuArgs, ZipBin]), - case file:write_file(Filename, Script) of - ok -> - ok; - {error, WriteError} -> - ?ERROR("Failed to write ~p script: ~p\n", - [AppName, WriteError]), - ?FAIL - end; - {error, ZipError} -> - ?ERROR("Failed to construct ~p escript: ~p\n", - [AppName, ZipError]), - ?FAIL - end, - - %% Finally, update executable perms for our script - {ok, #file_info{mode = Mode}} = file:read_file_info(Filename), - ok = file:change_mode(Filename, Mode bor 8#00111), - {ok, Config}. - -clean(Config0, AppFile) -> - %% Extract the application name from the archive -- this is the default - %% name of the generated script - {Config, AppName} = rebar_app_utils:app_name(Config0, AppFile), - - %% Get the output filename for the escript -- this may include dirs - Filename = rebar_state:get_local(Config, escript_name, AppName), - rebar_file_utils:delete_each([Filename]), - {ok, Config}. - -%% =================================================================== -%% Internal functions -%% =================================================================== - -info(help, escriptize) -> - info_help("Generate escript archive"); -info(help, clean) -> - info_help("Delete generated escript archive"). - -info_help(Description) -> - ?CONSOLE( - "~s.~n" - "~n" - "Valid rebar.config options:~n" - " ~p~n" - " ~p~n" - " ~p~n" - " ~p~n" - " ~p~n", - [ - Description, - {escript_name, "application"}, - {escript_incl_apps, []}, - {escript_shebang, "#!/usr/bin/env escript\n"}, - {escript_comment, "%%\n"}, - {escript_emu_args, "%%! -pa application/application/ebin\n"} - ]). - -get_app_beams([], Acc) -> - Acc; -get_app_beams([App | Rest], Acc) -> - case code:lib_dir(App, ebin) of - {error, bad_name} -> - ?ABORT("Failed to get ebin/ directory for " - "~p escript_incl_apps.", [App]); - Path -> - Prefix = filename:join(atom_to_list(App), "ebin"), - Acc2 = load_files(Prefix, "*", Path), - get_app_beams(Rest, Acc2 ++ Acc) - end. - -get_extra(Config) -> - Extra = rebar_state:get_local(Config, escript_incl_extra, []), - lists:foldl(fun({Wildcard, Dir}, Files) -> - load_files(Wildcard, Dir) ++ Files - end, [], Extra). - -load_files(Wildcard, Dir) -> - load_files("", Wildcard, Dir). - -load_files(Prefix, Wildcard, Dir) -> - [read_file(Prefix, Filename, Dir) - || Filename <- filelib:wildcard(Wildcard, Dir)]. - -read_file(Prefix, Filename, Dir) -> - Filename1 = case Prefix of - "" -> - Filename; - _ -> - filename:join([Prefix, Filename]) - end, - [dir_entries(filename:dirname(Filename1)), - {Filename1, file_contents(filename:join(Dir, Filename))}]. - -file_contents(Filename) -> - {ok, Bin} = file:read_file(Filename), - Bin. - -%% Given a filename, return zip archive dir entries for each sub-dir. -%% Required to work around issues fixed in OTP-10071. -dir_entries(File) -> - Dirs = dirs(File), - [{Dir ++ "/", <<>>} || Dir <- Dirs]. - -%% Given "foo/bar/baz", return ["foo", "foo/bar", "foo/bar/baz"]. -dirs(Dir) -> - dirs1(filename:split(Dir), "", []). - -dirs1([], _, Acc) -> - lists:reverse(Acc); -dirs1([H|T], "", []) -> - dirs1(T, H, [H]); -dirs1([H|T], Last, Acc) -> - Dir = filename:join(Last, H), - dirs1(T, Dir, [Dir|Acc]). - -usort(List) -> - lists:ukeysort(1, lists:flatten(List)). diff --git a/src/rebar_prv_help.erl b/src/rebar_prv_help.erl index a9949e7..8300378 100644 --- a/src/rebar_prv_help.erl +++ b/src/rebar_prv_help.erl @@ -3,10 +3,11 @@ -module(rebar_prv_help). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). -include("rebar.hrl"). @@ -19,30 +20,49 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar help <task>", - short_desc = "Display a list of tasks or help for a given task or subtask.", - desc = "", - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar help <task>"}, + {short_desc, "Display a list of tasks or help for a given task or subtask."}, + {desc, "Display a list of tasks or help for a given task or subtask."}, + {opts, [ + {help_task, undefined, undefined, string, "Task to print help for."} + ]}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error(). +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> - help(State), - {ok, State}. + {Args, _} = rebar_state:command_parsed_args(State), + case proplists:get_value(help_task, Args, undefined) of + undefined -> + help(State), + {ok, State}; + Name -> + Providers = rebar_state:providers(State), + case providers:get_provider(list_to_atom(Name), Providers) of + not_found -> + {error, io_lib:format("Unknown task ~s", [Name])}; + Provider -> + providers:help(Provider), + {ok, State} + end + end. + +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. %% %% print help/usage string %% help(State) -> ?CONSOLE("Rebar is a tool for working with Erlang projects.~n~n", []), - OptSpecList = rebar3:option_spec_list(), + OptSpecList = rebar3:global_option_spec_list(), getopt:usage(OptSpecList, "rebar", "", []), ?CONSOLE("~nSeveral tasks are available:~n", []), - rebar_provider:help(State), + providers:help(rebar_state:providers(State)), ?CONSOLE("~nRun 'rebar help <TASK>' for details.~n~n", []). diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index d20f2b5..522420d 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -26,14 +26,16 @@ %% ------------------------------------------------------------------- -module(rebar_prv_install_deps). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). -include("rebar.hrl"). --export([setup_env/1]). +-export([handle_deps/2, + handle_deps/3]). %% for internal use only -export([get_deps_dir/1]). @@ -43,9 +45,9 @@ -define(DEPS, [app_discovery]). -type src_dep() :: {atom(), string(), {atom(), string(), string()}}. --type binary_dep() :: {atom(), binary()} | atom(). +-type pkg_dep() :: {atom(), binary()} | atom(). --type dep() :: src_dep() | binary_dep(). +-type dep() :: src_dep() | pkg_dep(). %% =================================================================== %% Public API @@ -53,174 +55,237 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = true, - deps = ?DEPS, - example = undefined, - short_desc = "Install dependencies", - desc = info("Install dependencies"), - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, true}, + {deps, ?DEPS}, + {example, undefined}, + {short_desc, "Install dependencies"}, + {desc, info("Install dependencies")}, + {opts, []}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()}. +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> - case rebar_state:get(State, locks, []) of - [] -> - handle_deps(State, ordsets:from_list(rebar_state:get(State, deps, []))); - Locks -> - handle_deps(State, ordsets:from_list(Locks)) + ProjectApps = rebar_state:project_apps(State), + {ok, State1} = case rebar_state:get(State, locks, []) of + [] -> + handle_deps(State, rebar_state:get(State, deps, [])); + Locks -> + handle_deps(State, Locks) + end, + + Source = ProjectApps ++ rebar_state:src_apps(State1), + case rebar_topo:sort_apps(Source) of + {ok, Sort} -> + {ok, rebar_state:set(State1, deps_to_build, lists:dropwhile(fun rebar_app_info:valid/1, Sort -- ProjectApps))}; + {error, Error} -> + {error, Error} end. -%% set REBAR_DEPS_DIR and ERL_LIBS environment variables -setup_env(State) -> - DepsDir = get_deps_dir(State), - %% include rebar's DepsDir in ERL_LIBS - Separator = case os:type() of - {win32, nt} -> - ";"; - _ -> - ":" - end, - ERL_LIBS = case os:getenv("ERL_LIBS") of - false -> - {"ERL_LIBS", DepsDir}; - PrevValue -> - {"ERL_LIBS", DepsDir ++ Separator ++ PrevValue} - end, - [{"REBAR_DEPS_DIR", DepsDir}, ERL_LIBS]. +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. -spec get_deps_dir(rebar_state:t()) -> file:filename_all(). get_deps_dir(State) -> BaseDir = rebar_state:get(State, base_dir, ""), - get_deps_dir(BaseDir, "deps"). + DepsDir = rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR), + get_deps_dir(BaseDir, DepsDir). --spec get_deps_dir(file:filename_all(), rebar_state:t()) -> file:filename_all(). +-spec get_deps_dir(file:filename_all(), file:filename_all()) -> file:filename_all(). get_deps_dir(DepsDir, App) -> filename:join(DepsDir, App). -%% =================================================================== -%% Internal functions -%% =================================================================== - -spec handle_deps(rebar_state:t(), [dep()]) -> {ok, rebar_state:t()}. -handle_deps(State, []) -> - {ok, State}; handle_deps(State, Deps) -> + handle_deps(State, Deps, false). + +-spec handle_deps(rebar_state:t(), [dep()], boolean() | {true, binary(), integer()}) + -> {ok, rebar_state:t()}. +handle_deps(State, [], _) -> + {ok, State}; +handle_deps(State, Deps, Update) -> %% Read in package index and dep graph {Packages, Graph} = rebar_packages:get_packages(State), - ProjectApps = rebar_state:project_apps(State), - %% Split source deps form binary deps, needed to keep backwards compatibility + %% Split source deps from pkg deps, needed to keep backwards compatibility DepsDir = get_deps_dir(State), - {SrcDeps, BinaryDeps} = parse_deps(DepsDir, Deps), - State1 = rebar_state:src_deps(rebar_state:binary_deps(State, BinaryDeps), + {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps), + State1 = rebar_state:src_deps(rebar_state:pkg_deps(State, PkgDeps), SrcDeps), %% Fetch transitive src deps - State2 = update_src_deps(State1), - Solved = case rebar_state:binary_deps(State2) of - [] -> %% No binary deps - []; - BinaryDeps1 -> - %% Find binary deps needed - {ok, S} = rlx_depsolver:solve(Graph, BinaryDeps1), - %% Create app_info record for each binary dep - lists:map(fun({Name, Vsn}) -> - AppInfo = package_to_app(DepsDir - ,Packages - ,Name - ,Vsn), - ok = maybe_fetch(AppInfo), - AppInfo - end, S) + State2 = update_src_deps(0, State1, Update), + Solved = case rebar_state:pkg_deps(State2) of + [] -> %% No pkg deps + []; + PkgDeps1 -> + %% Find pkg deps needed + {ok, S} = rlx_depsolver:solve(Graph, PkgDeps1), + %% Create app_info record for each pkg dep + [AppInfo || Pkg <- S, + AppInfo <- package_to_app(DepsDir + ,Packages + ,Pkg), + maybe_fetch(AppInfo, Update)] end, - Source = ProjectApps ++ ordsets:to_list(rebar_state:src_deps(State2)), - AllDeps = ordsets:union([ordsets:to_list(rebar_state:src_deps(State2)) - ,ordsets:from_list(Solved)]), - + AllDeps = lists:ukeymerge(2 + ,lists:ukeysort(2, rebar_state:src_apps(State2)) + ,lists:ukeysort(2, Solved)), %% Sort all apps to build order State3 = rebar_state:set(State2, all_deps, AllDeps), - {ok, Sort} = rebar_topo:sort_apps(ordsets:to_list(Source)), - {ok, rebar_state:set(State3, deps_to_build, lists:dropwhile(fun is_valid/1, Sort -- ProjectApps))}. + {ok, State3}. + +%% =================================================================== +%% Internal functions +%% =================================================================== --spec is_valid(rebar_app_info:t()) -> boolean(). -is_valid(App) -> - rebar_app_info:valid(App). +package_to_app(DepsDir, Packages, Pkg={_, Vsn}) -> + Name = ec_cnv:to_binary(rlx_depsolver:dep_pkg(Pkg)), + FmtVsn = iolist_to_binary(rlx_depsolver:format_version(Vsn)), + case dict:find({Name, FmtVsn}, Packages) of + error -> + []; + {ok, P} -> + PkgDeps = proplists:get_value(<<"deps">>, P, []), + Link = proplists:get_value(<<"link">>, P, ""), + {ok, AppInfo} = rebar_app_info:new(Name, FmtVsn), + AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps), + AppInfo2 = rebar_app_info:dir(AppInfo1, get_deps_dir(DepsDir, Name)), + [rebar_app_info:source(AppInfo2, Link)] + end. --spec package_to_app(file:name(), rlx_depsolver:t(), binary(), binary()) -> rebar_app_info:t(). -package_to_app(DepsDir, Packages, Name, Vsn) -> - FmtVsn = ec_cnv:to_binary(rlx_depsolver:format_version(Vsn)), +-spec update_src_deps(integer(), rebar_state:t(), boolean()) -> rebar_state:t(). +update_src_deps(Level, State, Update) -> + SrcDeps = rebar_state:src_deps(State), + case lists:foldl(fun(AppInfo, {SrcDepsAcc, PkgDepsAcc, StateAcc}) -> + case Update of + {true, UpdateName, UpdateLevel} -> + handle_update(AppInfo + ,UpdateName + ,UpdateLevel + ,SrcDepsAcc + ,PkgDepsAcc + ,Level + ,StateAcc); + _ -> + maybe_fetch(AppInfo, false), + handle_dep(AppInfo + ,SrcDepsAcc + ,PkgDepsAcc + ,Level + ,StateAcc) + end + end, {[], rebar_state:pkg_deps(State), State}, SrcDeps) of + {[], NewPkgDeps, State1} -> + rebar_state:pkg_deps(State1, NewPkgDeps); + {NewSrcDeps, NewPkgDeps, State1} -> + State2 = rebar_state:pkg_deps(State1, NewPkgDeps), + State3 = rebar_state:src_deps(State2, NewSrcDeps), + update_src_deps(Level+1, State3, Update) + end. - {ok, P} = dict:find({Name, FmtVsn}, Packages), - PkgDeps = proplists:get_value(<<"deps">>, P), - Link = proplists:get_value(<<"link">>, P), +handle_update(AppInfo, UpdateName, UpdateLevel, SrcDeps, PkgDeps, Level, State) -> + Name = rebar_app_info:name(AppInfo), + Locks = rebar_state:get(State, locks, []), + {_, _, _, DepLevel} = lists:keyfind(Name, 1, Locks), + case UpdateLevel < DepLevel + orelse Name =:= UpdateName of + true -> + case maybe_fetch(AppInfo, true) of + true -> + handle_dep(AppInfo + ,SrcDeps + ,PkgDeps + ,Level + ,State); - {ok, AppInfo} = rebar_app_info:new(Name, FmtVsn), - AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps), - AppInfo2 = - rebar_app_info:dir(AppInfo1, get_deps_dir(DepsDir, <<Name/binary, "-", FmtVsn/binary>>)), - rebar_app_info:source(AppInfo2, Link). + false -> + {SrcDeps, PkgDeps, State} + end; + false -> + {SrcDeps, PkgDeps, State} + end. --spec update_src_deps(rebar_state:t()) -> rebat_state:t(). -update_src_deps(State) -> - SrcDeps = rebar_state:src_deps(State), +handle_dep(AppInfo, SrcDeps, PkgDeps, Level, State) -> DepsDir = get_deps_dir(State), - case lists:foldl(fun(AppInfo, {SrcDepsAcc, BinaryDepsAcc}) -> - ok = maybe_fetch(AppInfo), - {AppInfo1, NewSrcDeps, NewBinaryDeps} = handle_dep(DepsDir, AppInfo), - {ordsets:union(ordsets:add_element(AppInfo1, SrcDepsAcc), NewSrcDeps) - ,NewBinaryDeps++BinaryDepsAcc} - end, {ordsets:new(), rebar_state:binary_deps(State)}, SrcDeps) of - {NewSrcDeps, NewBinaryDeps} when length(SrcDeps) =:= length(NewSrcDeps) -> - rebar_state:src_deps(rebar_state:binary_deps(State, NewBinaryDeps), NewSrcDeps); - {NewSrcDeps, NewBinaryDeps} -> - State1 = rebar_state:src_deps(rebar_state:binary_deps(State, NewBinaryDeps), NewSrcDeps), - update_src_deps(State1) - end. + {AppInfo1, NewSrcDeps, NewPkgDeps} = + handle_dep(DepsDir, AppInfo), + AppInfo2 = rebar_app_info:dep_level(AppInfo1, Level), + {NewSrcDeps ++ SrcDeps + ,NewPkgDeps++PkgDeps + ,rebar_state:src_apps(State, AppInfo2)}. --spec handle_dep(binary(), rebar_state:t()) -> {[rebar_app_info:t()], [binary_dep()]}. +-spec handle_dep(file:filename_all(), rebar_app_info:t()) -> + {rebar_app_info:t(), [rebar_app_info:t()], [pkg_dep()]}. handle_dep(DepsDir, AppInfo) -> C = rebar_config:consult(rebar_app_info:dir(AppInfo)), S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(AppInfo)), Deps = rebar_state:get(S, deps, []), AppInfo1 = rebar_app_info:deps(AppInfo, rebar_state:deps_names(S)), - {SrcDeps, BinaryDeps} = parse_deps(DepsDir, Deps), - {AppInfo1, SrcDeps, BinaryDeps}. + {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps), + {AppInfo1, SrcDeps, PkgDeps}. --spec maybe_fetch(rebar_app_info:t()) -> ok. -maybe_fetch(AppInfo) -> - AppDir = rebar_app_info:dir(AppInfo), - case filelib:is_dir(AppDir) of - false -> - ?INFO("Fetching ~s~n", [rebar_app_info:name(AppInfo)]), - Source = rebar_app_info:source(AppInfo), - rebar_fetch:download_source(AppDir, Source); - true -> - ok +-spec maybe_fetch(rebar_app_info:t(), boolean() | {true, binary(), integer()}) -> boolean(). +maybe_fetch(AppInfo, Update) -> + AppDir = ec_cnv:to_list(rebar_app_info:dir(AppInfo)), + Apps = rebar_app_discover:find_apps(["_checkouts"], all), + case rebar_app_utils:find(rebar_app_info:name(AppInfo), Apps) of + {ok, _} -> + %% Don't fetch dep if it exists in the _checkouts dir + false; + error -> + Exists = case rebar_app_utils:is_app_dir(filename:absname(AppDir)++"-*") of + {true, _} -> + true; + _ -> + case rebar_app_utils:is_app_dir(filename:absname(AppDir)) of + {true, _} -> + true; + _ -> + false + end + end, + + case not Exists orelse Update of + true -> + ?INFO("Fetching ~s~n", [rebar_app_info:name(AppInfo)]), + Source = rebar_app_info:source(AppInfo), + rebar_fetch:download_source(AppDir, Source), + true; + _ -> + false + end end. --spec parse_deps(binary(), [dep()]) -> {ordsets:ordset(rebar_app_info:t()), [binary_dep()]}. +-spec parse_deps(binary(), [dep()]) -> {[rebar_app_info:t()], [pkg_dep()]}. parse_deps(DepsDir, Deps) -> - lists:foldl(fun({Name, Vsn}, {SrcDepsAcc, BinaryDepsAcc}) -> + lists:foldl(fun({Name, Vsn}, {SrcDepsAcc, PkgDepsAcc}) -> {SrcDepsAcc, [parse_goal(ec_cnv:to_binary(Name) - ,ec_cnv:to_binary(Vsn)) | BinaryDepsAcc]}; - (Name, {SrcDepsAcc, BinaryDepsAcc}) when is_atom(Name) -> - {SrcDepsAcc, [ec_cnv:to_binary(Name) | BinaryDepsAcc]}; - ({Name, Vsn, Source}, {SrcDepsAcc, BinaryDepsAcc}) when is_tuple (Source) -> - Dir = ec_cnv:to_list(get_deps_dir(DepsDir, Name)), - {ok, Dep} = case rebar_app_info:discover(Dir) of - {ok, App} -> - {ok, App}; - not_found -> - rebar_app_info:new(Name, Vsn, Dir) - end, - Dep1 = rebar_app_info:source(Dep, Source), - {ordsets:add_element(Dep1, SrcDepsAcc), BinaryDepsAcc} - end, {ordsets:new(), []}, Deps). - --spec parse_goal(binary(), binary()) -> binary_dep(). + ,ec_cnv:to_binary(Vsn)) | PkgDepsAcc]}; + (Name, {SrcDepsAcc, PkgDepsAcc}) when is_atom(Name) -> + {SrcDepsAcc, [ec_cnv:to_binary(Name) | PkgDepsAcc]}; + ({Name, Vsn, Source}, {SrcDepsAcc, PkgDepsAcc}) when is_tuple (Source) -> + Dep = new_dep(DepsDir, Name, Vsn, Source), + {[Dep | SrcDepsAcc], PkgDepsAcc}; + ({Name, Vsn, Source, _Level}, {SrcDepsAcc, PkgDepsAcc}) when is_tuple (Source) -> + Dep = new_dep(DepsDir, Name, Vsn, Source), + {[Dep | SrcDepsAcc], PkgDepsAcc} + end, {[], []}, Deps). + +new_dep(DepsDir, Name, Vsn, Source) -> + Dir = ec_cnv:to_list(get_deps_dir(DepsDir, Name)), + {ok, Dep} = case rebar_app_info:discover(Dir) of + {ok, App} -> + {ok, App}; + not_found -> + rebar_app_info:new(Name, Vsn, Dir) + end, + rebar_app_info:source(Dep, Source). + +-spec parse_goal(binary(), binary()) -> pkg_dep(). parse_goal(Name, Constraint) -> case re:run(Constraint, "([^\\d]*)(\\d.*)", [{capture, [1,2], binary}]) of {match, [<<>>, Vsn]} -> @@ -236,9 +301,7 @@ info(Description) -> "~n" "Valid rebar.config options:~n" " ~p~n" - " ~p~n" - "Valid command line options:~n" - " deps_dir=\"deps\" (override default or rebar.config deps_dir)~n", + " ~p~n", [ Description, {deps_dir, "deps"}, diff --git a/src/rebar_prv_lock.erl b/src/rebar_prv_lock.erl index b4a7d8d..32c5f1a 100644 --- a/src/rebar_prv_lock.erl +++ b/src/rebar_prv_lock.erl @@ -1,9 +1,10 @@ -module(rebar_prv_lock). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). -include("rebar.hrl"). @@ -16,17 +17,17 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = true, - deps = ?DEPS, - example = "", - short_desc = "Locks dependencies.", - desc = info("Locks dependencies"), - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, true}, + {deps, ?DEPS}, + {example, ""}, + {short_desc, "Locks dependencies."}, + {desc, info("Locks dependencies")}, + {opts, []}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()}. +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> case rebar_state:get(State, locks, []) of [] -> @@ -40,7 +41,8 @@ do(State) -> Source when is_tuple(Source) -> {rebar_app_info:name(Dep) ,rebar_app_info:original_vsn(Dep) - ,rebar_fetch:lock_source(Dir, Source)}; + ,rebar_fetch:lock_source(Dir, Source) + ,rebar_app_info:dep_level(Dep)}; _Source -> {rebar_app_info:name(Dep) ,rebar_app_info:original_vsn(Dep)} @@ -53,5 +55,9 @@ do(State) -> {ok, State} end. +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. + info(_) -> "". diff --git a/src/rebar_prv_new.erl b/src/rebar_prv_new.erl index ed3c1b4..2555b4d 100644 --- a/src/rebar_prv_new.erl +++ b/src/rebar_prv_new.erl @@ -1,9 +1,10 @@ -module(rebar_prv_new). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). -include("rebar.hrl"). @@ -16,17 +17,17 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar new <template>", - short_desc = "Create new project from templates.", - desc = info(create), - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar new <template>"}, + {short_desc, "Create new project from templates."}, + {desc, info()}, + {opts, []}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()}. +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> case rebar_state:command_args(State) of [TemplateName] -> @@ -41,33 +42,17 @@ do(State) -> {ok, State} end. +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. + %% =================================================================== %% Internal functions %% =================================================================== -info(create) -> - io_lib:format( - "Create skel based on template and vars.~n" - "~n" - "Valid command line options:~n" - " template= [var=foo,...]~n", []); -info(create_app) -> - io_lib:format( - "Create simple app skel.~n" - "~n" - "Valid command line options:~n" - " [appid=myapp]~n", []); -info(create_lib) -> - io_lib:format( - "Create simple lib skel.~n" - "~n" - "Valid command line options:~n" - " [libid=mylib]~n", []); -info(create_node) -> +info() -> io_lib:format( - "Create simple node skel.~n" - "~n" - "Valid command line options:~n" - " [nodeid=mynode]~n", []); -info(list_templates) -> - io_lib:format("List available templates.~n", []). + "Create rebar project based on template and vars.~n" + "~n" + "Valid command line options:~n" + " template= [var=foo,...]~n", []). diff --git a/src/rebar_prv_packages.erl b/src/rebar_prv_packages.erl index 79c1cd2..be51833 100644 --- a/src/rebar_prv_packages.erl +++ b/src/rebar_prv_packages.erl @@ -1,9 +1,10 @@ -module(rebar_prv_packages). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). -include("rebar.hrl"). @@ -12,22 +13,26 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar pkgs", - short_desc = "List available packages.", - desc = info("List available packages"), - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar pkgs"}, + {short_desc, "List available packages."}, + {desc, info("List available packages")}, + {opts, []}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()}. +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> {Packages, _Graph} = rebar_packages:get_packages(State), print_packages(Packages), {ok, State}. +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. + print_packages(Packages) -> Keys = lists:keysort(1, dict:fetch_keys(Packages)), Pkgs = merge(Keys), diff --git a/src/rebar_prv_release.erl b/src/rebar_prv_release.erl index 4203c3a..572f909 100644 --- a/src/rebar_prv_release.erl +++ b/src/rebar_prv_release.erl @@ -3,10 +3,11 @@ -module(rebar_prv_release). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). -include("rebar.hrl"). @@ -19,17 +20,28 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar release", - short_desc = "Build release of project.", - desc = "", - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar release"}, + {short_desc, "Build release of project."}, + {desc, ""}, + {opts, relx:opt_spec_list()}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error(). -do(Config) -> - relx:main("release"), - {ok, Config}. +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. +do(State) -> + Options = rebar_state:command_args(State), + AllOptions = string:join(["release" | Options], " "), + case rebar_state:get(State, relx, []) of + [] -> + relx:main(AllOptions); + Config -> + relx:main([{config, Config}], AllOptions) + end, + {ok, State}. + +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. diff --git a/src/rebar_prv_shell.erl b/src/rebar_prv_shell.erl index 80f6bcf..24e357b 100644 --- a/src/rebar_prv_shell.erl +++ b/src/rebar_prv_shell.erl @@ -28,10 +28,11 @@ -module(rebar_prv_shell). -author("Kresten Krab Thorup <krab@trifork.com>"). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). -include("rebar.hrl"). @@ -44,21 +45,25 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar shell", - short_desc = "Run shell with project apps and deps in path.", - desc = info(), - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar shell"}, + {short_desc, "Run shell with project apps and deps in path."}, + {desc, info()}, + {opts, []}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error(). +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(Config) -> shell(), {ok, Config}. +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. + %% NOTE: %% this is an attempt to replicate `erl -pa ./ebin -pa deps/*/ebin`. it is %% mostly successful but does stop and then restart the user io system to get diff --git a/src/rebar_prv_tar.erl b/src/rebar_prv_tar.erl index 7f5ab4f..04a1b33 100644 --- a/src/rebar_prv_tar.erl +++ b/src/rebar_prv_tar.erl @@ -3,10 +3,11 @@ -module(rebar_prv_tar). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). -include("rebar.hrl"). @@ -19,17 +20,26 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar tar", - short_desc = "Tar archive of release built of project.", - desc = "", - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar tar"}, + {short_desc, "Tar archive of release built of project."}, + {desc, ""}, + {opts, []}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error(). -do(Config) -> - relx:main("release tar"), - {ok, Config}. +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. +do(State) -> + case rebar_state:get(State, relx, []) of + [] -> + relx:main(["release tar"]); + Config -> + relx:main([{config, Config}], ["release tar"]) + end, + {ok, State}. + +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. diff --git a/src/rebar_prv_test_deps.erl b/src/rebar_prv_test_deps.erl new file mode 100644 index 0000000..081b210 --- /dev/null +++ b/src/rebar_prv_test_deps.erl @@ -0,0 +1,63 @@ +-module(rebar_prv_test_deps). + +-behaviour(provider). + +-export([init/1, + do/1, + format_error/2]). + +-include("rebar.hrl"). + +-define(PROVIDER, test_deps). +-define(DEPS, [install_deps]). + +%% =================================================================== +%% Public API +%% =================================================================== + +-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. +init(State) -> + Providers = rebar_state:providers(State), + CompileProvider = providers:get_provider(compile, Providers), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, true}, + {deps, ?DEPS}, + {hooks, {[], [CompileProvider]}}, + {example, undefined}, + {short_desc, "Install dependencies needed only for testing."}, + {desc, ""}, + {opts, []}])), + {ok, State1}. + +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. +do(State) -> + ProjectApps = rebar_state:project_apps(State), + TestDeps = rebar_state:get(State, test_deps, []), + Names = [ec_cnv:to_binary(element(1, Dep)) || Dep <- TestDeps], + ProjectApps1 = [rebar_app_info:deps(A, Names) || A <- ProjectApps], + + {ok, State1} = rebar_prv_install_deps:handle_deps(State, TestDeps), + AllDeps = rebar_state:get(State1, all_deps, []), + + case rebar_topo:sort_apps(ProjectApps1++AllDeps) of + {ok, Sort} -> + _ToBuild = lists:dropwhile(fun rebar_app_info:valid/1, Sort), + %% lists:foreach(fun(AppInfo) -> + %% AppDir = rebar_app_info:dir(AppInfo), + %% C = rebar_config:consult(AppDir), + %% S = rebar_state:new(State1, C, AppDir), + %% rebar_prv_compile:build(S, AppInfo) + %% end, ToBuild), + {ok, State1}; + {error, Error} -> + {error, Error} + end. + +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. + +%% =================================================================== +%% Internal functions +%% =================================================================== diff --git a/src/rebar_prv_update.erl b/src/rebar_prv_update.erl index e19041a..0d388c8 100644 --- a/src/rebar_prv_update.erl +++ b/src/rebar_prv_update.erl @@ -3,10 +3,11 @@ -module(rebar_prv_update). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). -include("rebar.hrl"). @@ -19,41 +20,35 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar update cowboy", - short_desc = "Update package index or individual dependency.", - desc = "", - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar update"}, + {short_desc, "Update package index."}, + {desc, ""}, + {opts, []}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error(). +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> - case rebar_state:command_args(State) of - [Name] -> - ?ERROR("NOT IMPLEMENTED: Updating ~s~n", [Name]), - {ok, State}; - [] -> - ?INFO("Updating package index...~n", []), - Url = url(State), - %{ok, [Home]} = init:get_argument(home), - ec_file:mkdir_p(filename:join([os:getenv("HOME"), ".rebar"])), - PackagesFile = filename:join([os:getenv("HOME"), ".rebar", "packages"]), - {ok, RequestId} = httpc:request(get, {Url, []}, [], [{stream, PackagesFile}, {sync, false}]), - wait(RequestId, State) - end. - -wait(RequestId, State) -> - receive - {http, {RequestId, saved_to_file}} -> - {ok, State} - after - 500 -> - io:format("."), - wait(RequestId, State) - end. + ?INFO("Updating package index...~n", []), + try + Url = url(State), + %{ok, [Home]} = init:get_argument(home), + ec_file:mkdir_p(filename:join([os:getenv("HOME"), ".rebar"])), + PackagesFile = filename:join([os:getenv("HOME"), ".rebar", "packages"]), + {ok, _RequestId} = httpc:request(get, {Url, []}, [], [{stream, PackagesFile} + ,{sync, true}]) + catch + _:_ -> + {error, io_lib:format("Failed to write package index.~n", [])} + end, + {ok, State}. + +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. url(State) -> SystemArch = erlang:system_info(system_architecture), diff --git a/src/rebar_prv_upgrade.erl b/src/rebar_prv_upgrade.erl new file mode 100644 index 0000000..1668e1c --- /dev/null +++ b/src/rebar_prv_upgrade.erl @@ -0,0 +1,55 @@ +%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% ex: ts=4 sw=4 et + +-module(rebar_prv_upgrade). + +-behaviour(provider). + +-export([init/1, + do/1, + format_error/2]). + +-include("rebar.hrl"). + +-define(PROVIDER, upgrade). +-define(DEPS, [lock]). + +%% =================================================================== +%% Public API +%% =================================================================== + +-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. +init(State) -> + State1 = + rebar_state:add_provider(State, + providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar upgrade cowboy"}, + {short_desc, "Upgrade dependency."}, + {desc, ""}, + {opts, [ + {package, undefined, undefined, string, "Package to upgrade."} + ]}])), + {ok, State1}. + +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. +do(State) -> + {Args, _} = rebar_state:command_parsed_args(State), + Name = proplists:get_value(package, Args), + ?INFO("Updating ~s~n", [Name]), + Locks = rebar_state:get(State, locks, []), + case lists:keyfind(ec_cnv:to_binary(Name), 1, Locks) of + {_, _, _, Level} -> + Deps = rebar_state:get(State, deps), + Dep = lists:keyfind(list_to_atom(Name), 1, Deps), + rebar_prv_install_deps:handle_deps(State, [Dep], {true, ec_cnv:to_binary(Name), Level}), + {ok, State}; + _ -> + {error, io_lib:format("No such dependency ~s~n", [Name])} + end. + +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. diff --git a/src/rebar_prv_version.erl b/src/rebar_prv_version.erl index 9197438..1e907d1 100644 --- a/src/rebar_prv_version.erl +++ b/src/rebar_prv_version.erl @@ -3,10 +3,11 @@ -module(rebar_prv_version). --behaviour(rebar_provider). +-behaviour(provider). -export([init/1, - do/1]). + do/1, + format_error/2]). -include("rebar.hrl"). @@ -19,18 +20,22 @@ -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar version", - short_desc = "Print version for rebar and current Erlang.", - desc = "", - opts = []}), + State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar version"}, + {short_desc, "Print version for rebar and current Erlang."}, + {desc, ""}, + {opts, []}])), {ok, State1}. --spec do(rebar_state:t()) -> {ok, rebar_state:t()} | relx:error(). +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> rebar3:version(), {ok, State}. + +-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}. +format_error(Reason, State) -> + {io_lib:format("~p", [Reason]), State}. diff --git a/src/rebar_state.erl b/src/rebar_state.erl index 706c528..f39251d 100644 --- a/src/rebar_state.erl +++ b/src/rebar_state.erl @@ -3,49 +3,39 @@ -export([new/0, new/1, new/2, new/3, get/2, get/3, set/3, command_args/1, command_args/2, + command_parsed_args/1, command_parsed_args/2, dir/1, dir/2, - set_skip_dir/2, is_skip_dir/2, reset_skip_dirs/1, create_logic_providers/2, project_apps/1, project_apps/2, deps_names/1, - binary_deps/1, binary_deps/2, + pkg_deps/1, pkg_deps/2, src_deps/1, src_deps/2, + src_apps/1, src_apps/2, prepend_hook/3, append_hook/3, hooks/2, providers/1, providers/2, add_provider/2]). -include("rebar.hrl"). --ifdef(namespaced_types). -%% dict:dict() exists starting from Erlang 17. --type rebar_dict() :: dict:dict(term(), term()). --else. -%% dict() has been obsoleted in Erlang 17 and deprecated in 18. --type rebar_dict() :: dict(). --endif. +-record(state_t, {dir :: file:name(), + opts = [], --record(state_t, {dir :: file:filename(), - opts = [] :: list(), - local_opts = [] :: list(), - config = new_globals() :: rebar_dict(), + command_args = [], + command_parsed_args = [], - envs = new_env() :: rebar_dict(), - command_args = [] :: list(), + src_deps = [], + src_apps = [], + pkg_deps = [] :: [rlx_depsolver:constraint()], + project_apps = [], - src_deps = ordsets:new() :: ordsets:ordset(rebar_app_info:t()), - binary_deps = [], - project_apps = ordsets:new() :: ordsets:ordset(rebar_app_info:t()), - - providers = [], - hooks = [], - skip_dirs = new_skip_dirs() :: rebar_dict() }). + providers = []}). -export_type([t/0]). --opaque t() :: #state_t{}. +-type t() :: record(state_t). -spec new() -> t(). new() -> @@ -64,9 +54,9 @@ new(ParentState=#state_t{}, Config) -> -spec new(t(), list(), file:name()) -> t(). new(ParentState, Config, Dir) -> - _Opts = ParentState#state_t.opts, + Opts = ParentState#state_t.opts, LocalOpts = case rebar_config:consult_file(?LOCK_FILE) of - {ok, [D]} -> + [D] -> [{locks, D} | Config]; _ -> Config @@ -74,7 +64,7 @@ new(ParentState, Config, Dir) -> ProviderModules = [], create_logic_providers(ProviderModules, ParentState#state_t{dir=Dir - ,opts=LocalOpts}). + ,opts=lists:umerge(LocalOpts, Opts)}). get(State, Key) -> proplists:get_value(Key, State#state_t.opts). @@ -82,33 +72,23 @@ get(State, Key) -> get(State, Key, Default) -> proplists:get_value(Key, State#state_t.opts, Default). +-spec set(t(), any(), any()) -> t(). set(State, Key, Value) -> Opts = proplists:delete(Key, State#state_t.opts), State#state_t { opts = [{Key, Value} | Opts] }. -set_skip_dir(State, Dir) -> - OldSkipDirs = State#state_t.skip_dirs, - NewSkipDirs = case is_skip_dir(State, Dir) of - false -> - ?DEBUG("Adding skip dir: ~s\n", [Dir]), - dict:store(Dir, true, OldSkipDirs); - true -> - OldSkipDirs - end, - State#state_t{skip_dirs = NewSkipDirs}. - -is_skip_dir(State, Dir) -> - dict:is_key(Dir, State#state_t.skip_dirs). - -reset_skip_dirs(State) -> - State#state_t{skip_dirs = new_skip_dirs()}. - command_args(#state_t{command_args=CmdArgs}) -> CmdArgs. command_args(State, CmdArgs) -> State#state_t{command_args=CmdArgs}. +command_parsed_args(#state_t{command_parsed_args=CmdArgs}) -> + CmdArgs. + +command_parsed_args(State, CmdArgs) -> + State#state_t{command_parsed_args=CmdArgs}. + dir(#state_t{dir=Dir}) -> Dir. @@ -123,13 +103,14 @@ deps_names(State) -> ec_cnv:to_binary(Dep) end, Deps). -binary_deps(#state_t{binary_deps=BinaryDeps}) -> - BinaryDeps. +-spec pkg_deps(t()) -> [rlx_depsolver:constraint()]. +pkg_deps(#state_t{pkg_deps=PkgDeps}) -> + PkgDeps. -binary_deps(State=#state_t{binary_deps=BinaryDeps}, NewBinaryDeps) when is_list(BinaryDeps) -> - State#state_t{binary_deps=NewBinaryDeps}; -binary_deps(State=#state_t{binary_deps=BinaryDeps}, BinaryDep) -> - State#state_t{binary_deps=[BinaryDep | BinaryDeps]}. +pkg_deps(State=#state_t{pkg_deps=PkgDeps}, NewPkgDeps) when is_list(PkgDeps) -> + State#state_t{pkg_deps=NewPkgDeps}; +pkg_deps(State=#state_t{pkg_deps=PkgDeps}, PkgDep) -> + State#state_t{pkg_deps=[PkgDep | PkgDeps]}. src_deps(#state_t{src_deps=SrcDeps}) -> SrcDeps. @@ -137,7 +118,19 @@ src_deps(#state_t{src_deps=SrcDeps}) -> src_deps(State=#state_t{src_deps=SrcDeps}, NewSrcDeps) when is_list(SrcDeps) -> State#state_t{src_deps=NewSrcDeps}; src_deps(State=#state_t{src_deps=SrcDeps}, SrcDep) -> - State#state_t{src_deps=[SrcDep | SrcDeps]}. + Name = rebar_app_info:name(SrcDep), + NewSrcDeps = lists:keystore(Name, 2, SrcDeps, SrcDep), + State#state_t{src_deps=NewSrcDeps}. + +src_apps(#state_t{src_apps=SrcApps}) -> + SrcApps. + +src_apps(State=#state_t{src_apps=_SrcApps}, NewSrcApps) when is_list(NewSrcApps) -> + State#state_t{src_apps=NewSrcApps}; +src_apps(State=#state_t{src_apps=SrcApps}, NewSrcApp) -> + Name = rebar_app_info:name(NewSrcApp), + NewSrcApps = lists:keystore(Name, 2, SrcApps, NewSrcApp), + State#state_t{src_apps=NewSrcApps}. project_apps(#state_t{project_apps=Apps}) -> Apps. @@ -153,32 +146,44 @@ providers(#state_t{providers=Providers}) -> providers(State, NewProviders) -> State#state_t{providers=NewProviders}. +-spec add_provider(t(), providers:t()) -> t(). add_provider(State=#state_t{providers=Providers}, Provider) -> State#state_t{providers=[Provider | Providers]}. create_logic_providers(ProviderModules, State0) -> lists:foldl(fun(ProviderMod, Acc) -> - {ok, State1} = rebar_provider:new(ProviderMod, Acc), - State1 + case providers:new(ProviderMod, Acc) of + {error, Reason} -> + ?ERROR(Reason++"~n", []), + Acc; + {ok, State1} -> + State1 + end end, State0, ProviderModules). -prepend_hook(State=#state_t{hooks=Hooks}, Target, Hook) -> - {PreHooks, PostHooks} = proplists:get_value(Target, Hooks, {[], []}), - State#state_t{hooks=[{Target, {[Hook | PreHooks], PostHooks}} | proplists:delete(Target, Hooks)]}. +prepend_hook(State=#state_t{providers=Providers}, Target, Hook) -> + State#state_t{providers=add_hook(pre, Providers, Target, Hook)}. -append_hook(State=#state_t{hooks=Hooks}, Target, Hook) -> - {PreHooks, PostHooks} = proplists:get_value(Target, Hooks, {[], []}), - State#state_t{hooks=[{Target, {PreHooks, [Hook | PostHooks]}} | proplists:delete(Target, Hooks)]}. +append_hook(State=#state_t{providers=Providers}, Target, Hook) -> + State#state_t{providers=add_hook(post, Providers, Target, Hook)}. -hooks(#state_t{hooks=Hooks}, Target) -> - proplists:get_value(Target, Hooks, {[], []}). +-spec hooks(t(), atom()) -> {[providers:t()], [providers:t()]}. +hooks(_State=#state_t{providers=Providers}, Target) -> + Provider = providers:get_provider(Target, Providers), + providers:hooks(Provider). %% =================================================================== %% Internal functions %% =================================================================== -new_globals() -> dict:new(). - -new_env() -> dict:new(). - -new_skip_dirs() -> dict:new(). +add_hook(Which, Providers, Target, Hook) -> + Provider = providers:get_provider(Target, Providers), + Hooks = providers:hooks(Provider), + NewHooks = add_hook(Which, Hooks, Hook), + NewProvider = providers:hooks(Provider, NewHooks), + [NewProvider | lists:delete(Provider, Providers)]. + +add_hook(pre, {PreHooks, PostHooks}, Hook) -> + {[Hook | PreHooks], PostHooks}; +add_hook(post, {PreHooks, PostHooks}, Hook) -> + {PreHooks, [Hook | PostHooks]}. diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl index a795b66..b30c517 100644 --- a/src/rebar_templater.erl +++ b/src/rebar_templater.erl @@ -47,6 +47,8 @@ new(app, DirName, State) -> create1(State, DirName, "otp_app"); new(lib, DirName, State) -> create1(State, DirName, "otp_lib"); +new(plugin, DirName, State) -> + create1(State, DirName, "plugin"); new(rel, DirName, State) -> create1(State, DirName, "otp_rel"). @@ -78,7 +80,7 @@ create(State) -> resolve_variables([], Dict) -> Dict; resolve_variables([{Key, Value0} | Rest], Dict) when is_list(Value0) -> - Value = render(list_to_binary(Value0), Dict), + Value = render(Value0, Dict), resolve_variables(Rest, dict:store(Key, Value, Dict)); resolve_variables([{Key, {list, Dicts}} | Rest], Dict) when is_list(Dicts) -> %% just un-tag it so erlydtl can use it @@ -376,7 +378,7 @@ execute_template(Files, [{'case', Variable, Values, Instructions} | Rest], Templ ExistingFiles); execute_template(Files, [{template, Input, Output} | Rest], TemplateType, TemplateName, Context, Force, ExistingFiles) -> - InputName = filename:join(filename:dirname(TemplateName), Input), + _InputName = filename:join(filename:dirname(TemplateName), Input), %File = load_file(Files, TemplateType, InputName), OutputTemplateName = make_template_name("rebar_output_template", Output), {ok, OutputTemplateName1} = erlydtl:compile_template(Output, OutputTemplateName, ?ERLYDTL_COMPILE_OPTS), diff --git a/src/rebar_topo.erl b/src/rebar_topo.erl index 87ee234..de3351a 100644 --- a/src/rebar_topo.erl +++ b/src/rebar_topo.erl @@ -54,20 +54,18 @@ %% applications. This implies that you have already done the %% constraint solve before you pass the list of apps here to be %% sorted. --spec sort_apps([rebar_app_info:t()]) -> - {ok, [rebar_app_info:t()]} | - relx:error(). +-spec sort_apps([rebar_app_info:t()]) -> {ok, [rebar_app_info:t()]} | {error, any()}. sort_apps(Apps) -> Pairs = apps_to_pairs(Apps), case sort(Pairs) of {ok, Names} -> {ok, names_to_apps(Names, Apps)}; E -> - E + {error, E} end. %% @doc Do a topological sort on the list of pairs. --spec sort([pair()]) -> {ok, [atom()]} | relx:error(). +-spec sort([pair()]) -> {ok, [atom()]} | {error, any()}. sort(Pairs) -> iterate(Pairs, [], all(Pairs)). @@ -78,9 +76,9 @@ format_error({cycle, Pairs}) -> "before we can continue:\n", case Pairs of [{P1, P2}] -> - [rebar_util:indent(2), erlang:atom_to_list(P2), "->", erlang:atom_to_list(P1)]; + [rebar_utils:indent(2), erlang:atom_to_list(P2), "->", erlang:atom_to_list(P1)]; [{P1, P2} | Rest] -> - [rebar_util:indent(2), erlang:atom_to_list(P2), "->", erlang:atom_to_list(P1), + [rebar_utils:indent(2), erlang:atom_to_list(P2), "->", erlang:atom_to_list(P1), [["-> ", erlang:atom_to_list(PP2), " -> ", erlang:atom_to_list(PP1)] || {PP1, PP2} <- Rest]]; [] -> [] @@ -91,12 +89,12 @@ format_error({cycle, Pairs}) -> %%==================================================================== -spec names_to_apps([atom()], [rebar_app_info:t()]) -> [rebar_app_info:t()]. names_to_apps(Names, Apps) -> - [element(2, App) || App <- [find_app_by_name(Name, Apps) || Name <- Names], App =/= error]. + [element(2, App) || App <- [find_app_by_name(Name, Apps) || Name <- Names], App =/= error]. -spec find_app_by_name(atom(), [rebar_app_info:t()]) -> {ok, rebar_app_info:t()} | error. find_app_by_name(Name, Apps) -> ec_lists:find(fun(App) -> - rebar_app_info:name(App) =:= Name + ec_cnv:to_atom(rebar_app_info:name(App)) =:= ec_cnv:to_atom(Name) end, Apps). -spec apps_to_pairs([rebar_app_info:t()]) -> [pair()]. @@ -105,20 +103,20 @@ apps_to_pairs(Apps) -> -spec app_to_pairs(rebar_app_info:t()) -> [pair()]. app_to_pairs(App) -> - [{DepApp, rebar_app_info:name(App)} || + [{ec_cnv:to_atom(DepApp), ec_cnv:to_atom(rebar_app_info:name(App))} || DepApp <- rebar_app_info:deps(App)]. %% @doc Iterate over the system. @private -spec iterate([pair()], [name()], [name()]) -> - {ok, [name()]} | relx:error(). + {ok, [name()]} | {error, iolist()}. iterate([], L, All) -> {ok, remove_duplicates(L ++ subtract(All, L))}; iterate(Pairs, L, All) -> case subtract(lhs(Pairs), rhs(Pairs)) of [] -> - ?ERROR(format_error({cycle, Pairs}), []); + {error, format_error({cycle, Pairs})}; Lhs -> iterate(remove_pairs(Lhs, Pairs), L ++ Lhs, All) end. @@ -188,29 +186,27 @@ topo_2_test() -> topo_pairs_cycle_test() -> Pairs = [{app2, app1}, {app1, app2}, {stdlib, app1}], - ?assertMatch({error, {_, {cycle, [{app2, app1}, {app1, app2}]}}}, - sort(Pairs)). + ?assertMatch({error, _}, sort(Pairs)). topo_apps_cycle_test() -> - {ok, App1} = rebar_app_info:new(app1, "0.1", "/no-dir", [app2], [stdlib]), - {ok, App2} = rebar_app_info:new(app2, "0.1", "/no-dir", [app1], []), + {ok, App1} = rebar_app_info:new(app1, "0.1", "/no-dir", [app2]), + {ok, App2} = rebar_app_info:new(app2, "0.1", "/no-dir", [app1]), Apps = [App1, App2], - ?assertMatch({error, {_, {cycle, [{app2,app1},{app1,app2}]}}}, - sort_apps(Apps)). + ?assertMatch({error, _}, sort_apps(Apps)). topo_apps_good_test() -> Apps = [App || {ok, App} <- - [rebar_app_info:new(app1, "0.1", "/no-dir", [app2, zapp1], [stdlib, kernel]), - rebar_app_info:new(app2, "0.1", "/no-dir", [app3], []), - rebar_app_info:new(app3, "0.1", "/no-dir", [kernel], []), - rebar_app_info:new(zapp1, "0.1", "/no-dir", [app2,app3,zapp2], []), - rebar_app_info:new(stdlib, "0.1", "/no-dir", [], []), - rebar_app_info:new(kernel, "0.1", "/no-dir", [], []), - rebar_app_info:new(zapp2, "0.1", "/no-dir", [], [])]], + [rebar_app_info:new(app1, "0.1", "/no-dir", [app2, zapp1]), + rebar_app_info:new(app2, "0.1", "/no-dir", [app3]), + rebar_app_info:new(app3, "0.1", "/no-dir", [kernel]), + rebar_app_info:new(zapp1, "0.1", "/no-dir", [app2,app3,zapp2]), + rebar_app_info:new(stdlib, "0.1", "/no-dir", []), + rebar_app_info:new(kernel, "0.1", "/no-dir", []), + rebar_app_info:new(zapp2, "0.1", "/no-dir", [])]], {ok, Sorted} = sort_apps(Apps), ?assertMatch([stdlib, kernel, zapp2, app3, app2, zapp1, app1], - [rebar_app_info:name(App) || App <- Sorted]). + [ec_cnv:to_atom(rebar_app_info:name(App)) || App <- Sorted]). -endif. diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index b83c03e..87387be 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -30,42 +30,27 @@ filtermap/2, get_cwd/0, is_arch/1, - get_arch/0, - wordsize/0, sh/2, sh_send/3, + abort/0, + abort/2, + escript_foldl/3, find_files/2, find_files/3, - now_str/0, ensure_dir/1, beam_to_mod/1, beams/1, - erl_to_mod/1, - abort/0, - abort/2, - escript_foldl/3, find_executable/1, - prop_check/3, expand_code_path/0, - expand_env_variable/3, vcs_vsn/3, deprecated/3, deprecated/4, - get_deprecated_global/4, - get_deprecated_global/5, - get_experimental_global/3, - get_experimental_local/3, - get_deprecated_list/4, - get_deprecated_list/5, - get_deprecated_local/4, - get_deprecated_local/5, delayed_halt/1, erl_opts/1, src_dirs/1, ebin_dir/0, processing_base_dir/1, processing_base_dir/2, - patch_env/2, indent/1]). %% for internal use only @@ -177,11 +162,6 @@ find_files(Dir, Regex, Recursive) -> filelib:fold_files(Dir, Regex, Recursive, fun(F, Acc) -> [F | Acc] end, []). -now_str() -> - {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(), - lists:flatten(io_lib:format("~4b/~2..0b/~2..0b ~2..0b:~2..0b:~2..0b", - [Year, Month, Day, Hour, Minute, Second])). - %% TODO: filelib:ensure_dir/1 corrected in R13B04. Remove when we drop %% support for OTP releases older than R13B04. ensure_dir(Path) -> @@ -194,27 +174,6 @@ ensure_dir(Path) -> Error end. --spec abort() -> no_return(). -abort() -> - throw(rebar_abort). - --spec abort(string(), [term()]) -> no_return(). -abort(String, Args) -> - ?ERROR(String, Args), - abort(). - -%% TODO: Rename emulate_escript_foldl to escript_foldl and remove -%% this function when the time is right. escript:foldl/3 was an -%% undocumented exported fun and has been removed in R14. -escript_foldl(Fun, Acc, File) -> - {module, zip} = code:ensure_loaded(zip), - case erlang:function_exported(zip, foldl, 3) of - true -> - emulate_escript_foldl(Fun, Acc, File); - false -> - escript:foldl(Fun, Acc, File) - end. - find_executable(Name) -> case os:find_executable(Name) of false -> false; @@ -222,10 +181,6 @@ find_executable(Name) -> "\"" ++ filename:nativename(Path) ++ "\"" end. -%% Helper function for checking values and aborting when needed -prop_check(true, _, _) -> true; -prop_check(false, Msg, Args) -> ?ABORT(Msg, Args). - %% Convert all the entries in the code path to absolute paths. expand_code_path() -> CodePath = lists:foldl(fun(Path, Acc) -> @@ -233,25 +188,6 @@ expand_code_path() -> end, [], code:get_path()), code:set_path(lists:reverse(CodePath)). -%% -%% Given env. variable FOO we want to expand all references to -%% it in InStr. References can have two forms: $FOO and ${FOO} -%% The end of form $FOO is delimited with whitespace or eol -%% -expand_env_variable(InStr, VarName, RawVarValue) -> - case string:chr(InStr, $$) of - 0 -> - %% No variables to expand - InStr; - _ -> - ReOpts = [global, unicode, {return, list}], - VarValue = re:replace(RawVarValue, "\\\\", "\\\\\\\\", ReOpts), - %% Use a regex to match/replace: - %% Given variable "FOO": match $FOO\s | $FOOeol | ${FOO} - RegEx = io_lib:format("\\\$(~s(\\s|$)|{~s})", [VarName, VarName]), - re:replace(InStr, RegEx, [VarValue, "\\2"], ReOpts) - end. - vcs_vsn(Config, Vsn, Dir) -> Key = {Vsn, Dir}, Cache = rebar_state:get(Config, vsn_cache, dict:new()), @@ -265,33 +201,6 @@ vcs_vsn(Config, Vsn, Dir) -> {Config, VsnString} end. -get_deprecated_global(Config, OldOpt, NewOpt, When) -> - get_deprecated_global(Config, OldOpt, NewOpt, undefined, When). - -get_deprecated_global(Config, OldOpt, NewOpt, Default, When) -> - get_deprecated_3(fun rebar_state:get/3, - Config, OldOpt, NewOpt, Default, When). - -get_experimental_global(Config, Opt, Default) -> - get_experimental_3(fun rebar_state:get/3, Config, Opt, Default). - -get_experimental_local(Config, Opt, Default) -> - get_experimental_3(fun rebar_state:get/3, Config, Opt, Default). - -get_deprecated_list(Config, OldOpt, NewOpt, When) -> - get_deprecated_list(Config, OldOpt, NewOpt, undefined, When). - -get_deprecated_list(Config, OldOpt, NewOpt, Default, When) -> - get_deprecated_3(fun rebar_state:get_list/3, - Config, OldOpt, NewOpt, Default, When). - -get_deprecated_local(Config, OldOpt, NewOpt, When) -> - get_deprecated_local(Config, OldOpt, NewOpt, undefined, When). - -get_deprecated_local(Config, OldOpt, NewOpt, Default, When) -> - get_deprecated_3(fun rebar_state:get/3, - Config, OldOpt, NewOpt, Default, When). - deprecated(Old, New, Opts, When) when is_list(Opts) -> case lists:member(Old, Opts) of true -> @@ -337,7 +246,7 @@ delayed_halt(Code) -> end. %% @doc Return list of erl_opts --spec erl_opts(rebar_state:config()) -> list(). +-spec erl_opts(rebar_state:t()) -> list(). erl_opts(Config) -> RawErlOpts = filter_defines(rebar_state:get(Config, erl_opts, []), []), Defines = [{d, list_to_atom(D)} || @@ -367,25 +276,6 @@ processing_base_dir(State, Dir) -> AbsDir = filename:absname(Dir), AbsDir =:= rebar_state:get(State, base_dir). -%% @doc Returns the list of environment variables including 'REBAR' which -%% points to the rebar executable used to execute the currently running -%% command. The environment is not modified if rebar was invoked -%% programmatically. --spec patch_env(rebar_state:config(), [{string(), string()}]) - -> [{string(), string()}]. -patch_env(Config, []) -> - %% If we reached an empty list, the env did not contain the REBAR variable. - case rebar_state:get(Config, escript, "") of - "" -> % rebar was invoked programmatically - []; - Path -> - [{"REBAR", Path}] - end; -patch_env(_Config, [{"REBAR", _} | _]=All) -> - All; -patch_env(Config, [E | Rest]) -> - [E | patch_env(Config, Rest)]. - %% ==================================================================== %% Internal functions %% ==================================================================== @@ -426,30 +316,6 @@ otp_release1(Rel) -> binary:bin_to_list(Vsn, {0, Size - 1}) end. -get_deprecated_3(Get, Config, OldOpt, NewOpt, Default, When) -> - case Get(Config, NewOpt, Default) of - Default -> - case Get(Config, OldOpt, Default) of - Default -> - Default; - Old -> - deprecated(OldOpt, NewOpt, When), - Old - end; - New -> - New - end. - -get_experimental_3(Get, Config, Opt, Default) -> - Val = Get(Config, Opt, Default), - case Val of - Default -> - Default; - Val -> - ?CONSOLE("NOTICE: Using experimental option '~p'~n", [Opt]), - Val - end. - %% We do the shell variable substitution ourselves on Windows and hope that the %% command doesn't use any other shell magic. patch_on_windows(Cmd, Env) -> @@ -466,6 +332,25 @@ patch_on_windows(Cmd, Env) -> Cmd end. +%% +%% Given env. variable FOO we want to expand all references to +%% it in InStr. References can have two forms: $FOO and ${FOO} +%% The end of form $FOO is delimited with whitespace or eol +%% +expand_env_variable(InStr, VarName, RawVarValue) -> + case string:chr(InStr, $$) of + 0 -> + %% No variables to expand + InStr; + _ -> + ReOpts = [global, unicode, {return, list}], + VarValue = re:replace(RawVarValue, "\\\\", "\\\\\\\\", ReOpts), + %% Use a regex to match/replace: + %% Given variable "FOO": match $FOO\s | $FOOeol | ${FOO} + RegEx = io_lib:format("\\\$(~s(\\s|$)|{~s})", [VarName, VarName]), + re:replace(InStr, RegEx, [VarValue, "\\2"], ReOpts) + end. + expand_sh_flag(return_on_error) -> {error_handler, fun(_Command, Err) -> @@ -521,14 +406,19 @@ sh_loop(Port, Fun, Acc) -> beam_to_mod(Filename) -> list_to_atom(filename:basename(Filename, ".beam")). -erl_to_mod(Filename) -> - list_to_atom(filename:rootname(filename:basename(Filename))). - beams(Dir) -> filelib:fold_files(Dir, ".*\.beam\$", true, fun(F, Acc) -> [F | Acc] end, []). -emulate_escript_foldl(Fun, Acc, File) -> +-spec abort() -> no_return(). +abort() -> + throw(rebar_abort). +-spec abort(string(), [term()]) -> no_return(). +abort(String, Args) -> + ?ERROR(String, Args), + abort(). + +escript_foldl(Fun, Acc, File) -> case escript:extract(File, [compile_source]) of {ok, [_Shebang, _Comment, _EmuArgs, Body]} -> case Body of |