summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbootstrap24
-rw-r--r--rebar.config11
-rw-r--r--rebar.lock8
-rw-r--r--src/rebar3.erl4
-rw-r--r--src/rebar_app_discover.erl121
-rw-r--r--src/rebar_app_info.erl13
-rw-r--r--src/rebar_config.erl10
-rw-r--r--src/rebar_packages.erl4
-rw-r--r--src/rebar_prv_clean.erl3
-rw-r--r--src/rebar_prv_common_test.erl27
-rw-r--r--src/rebar_prv_escriptize.erl23
-rw-r--r--src/rebar_prv_eunit.erl17
-rw-r--r--src/rebar_prv_path.erl4
-rw-r--r--src/rebar_prv_plugins.erl11
-rw-r--r--src/rebar_prv_upgrade.erl2
-rw-r--r--src/rebar_templater.erl11
-rw-r--r--src/rebar_utils.erl2
-rw-r--r--test/rebar_compile_SUITE.erl46
-rw-r--r--test/rebar_ct_SUITE.erl41
-rw-r--r--test/rebar_eunit_SUITE.erl5
-rw-r--r--test/rebar_src_dirs_SUITE.erl98
-rw-r--r--test/rebar_test_utils.erl4
22 files changed, 357 insertions, 132 deletions
diff --git a/bootstrap b/bootstrap
index 8b9b001..b797b6e 100755
--- a/bootstrap
+++ b/bootstrap
@@ -52,21 +52,7 @@ main(_) ->
rebar3:run(["escriptize"]),
%% Done with compile, can turn back on error logger
- error_logger:tty(true),
-
- %% Finally, update executable perms for our script on *nix,
- %% or write out script files on win32.
- ec_file:copy("_build/default/bin/rebar3", "./rebar3"),
- case os:type() of
- {unix,_} ->
- [] = os:cmd("chmod u+x rebar3"),
- ok;
- {win32,_} ->
- write_windows_scripts(),
- ok;
- _ ->
- ok
- end.
+ error_logger:tty(true).
default_registry_file() ->
{ok, [[Home]]} = init:get_argument(home),
@@ -305,14 +291,6 @@ reset_env() ->
application:unload(rebar),
application:load(rebar).
-write_windows_scripts() ->
- CmdScript=
- "@echo off\r\n"
- "setlocal\r\n"
- "set rebarscript=%~f0\r\n"
- "escript.exe \"%rebarscript:.cmd=%\" %*\r\n",
- ok = file:write_file("rebar3.cmd", CmdScript).
-
get_deps() ->
case file:consult("rebar.lock") of
{ok, [[]]} ->
diff --git a/rebar.config b/rebar.config
index 1d853c4..36ef8c7 100644
--- a/rebar.config
+++ b/rebar.config
@@ -7,14 +7,19 @@
{providers, "1.6.0"},
{getopt, "0.8.2"},
{bbmustache, "1.3.0"},
- {relx, "3.22.2"},
+ {relx, "3.22.3"},
{cf, "0.2.2"},
- {cth_readable, "1.2.3"},
+ {cth_readable, "1.2.4"},
{eunit_formatters, "0.3.1"}]}.
{post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)",
escriptize,
- "cp $REBAR_BUILD_DIR/bin/rebar3 ./rebar3 && chmod u+x rebar3"}]}.
+ "cp \"$REBAR_BUILD_DIR/bin/rebar3\" ./rebar3"},
+ {"win32",
+ escriptize,
+ "robocopy \"%REBAR_BUILD_DIR%/bin/\" ./ rebar3* "
+ "/njs /njh /nfl /ndl & exit /b 0"} % silence things
+ ]}.
{escript_name, rebar3}.
{escript_emu_args, "%%! +sbtu +A0\n"}.
diff --git a/rebar.lock b/rebar.lock
index abcee59..ddc93dc 100644
--- a/rebar.lock
+++ b/rebar.lock
@@ -2,23 +2,23 @@
[{<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.3.0">>},0},
{<<"certifi">>,{pkg,<<"certifi">>,<<"0.4.0">>},0},
{<<"cf">>,{pkg,<<"cf">>,<<"0.2.2">>},0},
- {<<"cth_readable">>,{pkg,<<"cth_readable">>,<<"1.2.3">>},0},
+ {<<"cth_readable">>,{pkg,<<"cth_readable">>,<<"1.2.4">>},0},
{<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"1.0.0">>},0},
{<<"eunit_formatters">>,{pkg,<<"eunit_formatters">>,<<"0.3.1">>},0},
{<<"getopt">>,{pkg,<<"getopt">>,<<"0.8.2">>},0},
{<<"providers">>,{pkg,<<"providers">>,<<"1.6.0">>},0},
- {<<"relx">>,{pkg,<<"relx">>,<<"3.22.2">>},0},
+ {<<"relx">>,{pkg,<<"relx">>,<<"3.22.3">>},0},
{<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.1">>},0}]}.
[
{pkg_hash,[
{<<"bbmustache">>, <<"2010ADAE78830992A4C69680115ECD7D475DD03A72C076BBADDCCBF2D4B32035">>},
{<<"certifi">>, <<"A7966EFB868B179023618D29A407548F70C52466BF1849B9E8EBD0E34B7EA11F">>},
{<<"cf">>, <<"7F2913FFF90ABCABD0F489896CFEB0B0674F6C8DF6C10B17A83175448029896C">>},
- {<<"cth_readable">>, <<"293120673DFF82F0768612C5282E35C40CACC1B6F94FE99077438FD3749D0E27">>},
+ {<<"cth_readable">>, <<"F89D353BA7D6C9D7F8141AF5CE4CB7E796F214B75766960DF480AB2B339C43CE">>},
{<<"erlware_commons">>, <<"087467DE5833C0BB5B3CCDD387F9E9C1FB816A75B7A709629BF24B5ED3246C51">>},
{<<"eunit_formatters">>, <<"7A6FC351EB5B873E2356B8852EB751E20C13A72FBCA03393CF682B8483509573">>},
{<<"getopt">>, <<"B17556DB683000BA50370B16C0619DF1337E7AF7ECBF7D64FBF8D1D6BCE3109B">>},
{<<"providers">>, <<"DB0E2F9043AE60C0155205FCD238D68516331D0E5146155E33D1E79DC452964A">>},
- {<<"relx">>, <<"AEE2EF6E9AC6D21D6661133B7A0BE6E81424DE9CDCA0012FC008BC677297C469">>},
+ {<<"relx">>, <<"36CB10F463E3834CE7BAF685F18D80D6B415BA9B227649E1140D091077A55246">>},
{<<"ssl_verify_fun">>, <<"28A4D65B7F59893BC2C7DE786DEC1E1555BD742D336043FE644AE956C3497FBE">>}]}
].
diff --git a/src/rebar3.erl b/src/rebar3.erl
index 56bf3e8..1e1d0b0 100644
--- a/src/rebar3.erl
+++ b/src/rebar3.erl
@@ -176,7 +176,7 @@ init_config() ->
Verbosity = log_level(),
ok = rebar_log:init(command_line, Verbosity),
- Config = rebar_config:consult(),
+ Config = rebar_config:consult_root(),
Config1 = rebar_config:merge_locks(Config, rebar_config:consult_lock_file(?LOCK_FILE)),
%% If $HOME/.config/rebar3/rebar.config exists load and use as global config
@@ -344,7 +344,7 @@ start_and_load_apps(Caller) ->
ensure_running(asn1, Caller),
ensure_running(public_key, Caller),
ensure_running(ssl, Caller),
- inets:start(),
+ ensure_running(inets, Caller),
inets:start(httpc, [{profile, rebar}]).
%% @doc Make sure a required app is running, or display an error message
diff --git a/src/rebar_app_discover.erl b/src/rebar_app_discover.erl
index fd55960..db74cd3 100644
--- a/src/rebar_app_discover.erl
+++ b/src/rebar_app_discover.erl
@@ -7,8 +7,10 @@
find_unbuilt_apps/1,
find_apps/1,
find_apps/2,
+ find_apps/3,
find_app/2,
- find_app/3]).
+ find_app/3,
+ find_app/4]).
-include("rebar.hrl").
-include_lib("providers/include/providers.hrl").
@@ -20,7 +22,9 @@
do(State, LibDirs) ->
BaseDir = rebar_state:dir(State),
Dirs = [filename:join(BaseDir, LibDir) || LibDir <- LibDirs],
- Apps = find_apps(Dirs, all),
+ RebarOpts = rebar_state:opts(State),
+ SrcDirs = rebar_dir:src_dirs(RebarOpts, ["src"]),
+ Apps = find_apps(Dirs, SrcDirs, all),
ProjectDeps = rebar_state:deps_names(State),
DepsDir = rebar_dir:deps_dir(State),
CurrentProfiles = rebar_state:current_profiles(State),
@@ -179,32 +183,44 @@ reset_hooks(Opts) ->
rebar_opts:set(OptsAcc, Key, [])
end, Opts, [post_hooks, pre_hooks, provider_hooks, artifacts]).
-%% @doc find the directories for all apps
--spec all_app_dirs([file:name()]) -> [file:name()].
+%% @private find the directories for all apps, while detecting their source dirs
+%% Returns the app dir with the respective src_dirs for them, in that order,
+%% for every app found.
+-spec all_app_dirs([file:name()]) -> [{file:name(), [file:name()]}].
all_app_dirs(LibDirs) ->
lists:flatmap(fun(LibDir) ->
- app_dirs(LibDir)
+ SrcDirs = find_config_src(LibDir, ["src"]),
+ app_dirs(LibDir, SrcDirs)
end, LibDirs).
-%% @doc find the directories based on the library directories
--spec app_dirs([file:name()]) -> [file:name()].
-app_dirs(LibDir) ->
- Path1 = filename:join([LibDir,
- "src",
- "*.app.src"]),
-
- Path2 = filename:join([LibDir,
- "src",
- "*.app.src.script"]),
-
- Path3 = filename:join([LibDir,
- "ebin",
- "*.app"]),
+%% @private find the directories for all apps based on their source dirs
+%% Returns the app dir with the respective src_dirs for them, in that order,
+%% for every app found.
+-spec all_app_dirs([file:name()], [file:name()]) -> [{file:name(), [file:name()]}].
+all_app_dirs(LibDirs, SrcDirs) ->
+ lists:flatmap(fun(LibDir) -> app_dirs(LibDir, SrcDirs) end, LibDirs).
+
+%% @private find the directories based on the library directories.
+%% Returns the app dir with the respective src_dirs for them, in that order,
+%% for every app found.
+%%
+%% The function returns the src directories since they might have been
+%% detected in a top-level loop and we want to skip further detection
+%% starting now.
+-spec app_dirs([file:name()], [file:name()]) -> [{file:name(), [file:name()]}].
+app_dirs(LibDir, SrcDirs) ->
+ Paths = lists:append([
+ [filename:join([LibDir, SrcDir, "*.app.src"]),
+ filename:join([LibDir, SrcDir, "*.app.src.script"])]
+ || SrcDir <- SrcDirs
+ ]),
+ EbinPath = filename:join([LibDir, "ebin", "*.app"]),
lists:usort(lists:foldl(fun(Path, Acc) ->
- Files = filelib:wildcard(ec_cnv:to_list(Path)),
- [app_dir(File) || File <- Files] ++ Acc
- end, [], [Path1, Path2, Path3])).
+ Files = filelib:wildcard(ec_cnv:to_list(Path)),
+ [{app_dir(File), SrcDirs}
+ || File <- Files] ++ Acc
+ end, [], [EbinPath | Paths])).
%% @doc find all apps that haven't been built in a list of directories
-spec find_unbuilt_apps([file:filename_all()]) -> [rebar_app_info:t()].
@@ -222,16 +238,32 @@ find_apps(LibDirs) ->
%% app info records.
-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)).
+ rebar_utils:filtermap(
+ fun({AppDir, AppSrcDirs}) ->
+ find_app(rebar_app_info:new(), AppDir, AppSrcDirs, Validate)
+ end,
+ all_app_dirs(LibDirs)
+ ).
+
+%% @doc for each directory passed, with the configured source directories,
+%% find all apps according to the validity rule passed in.
+%% Returns all the related app info records.
+-spec find_apps([file:filename_all()], [file:filename_all()], valid | invalid | all) -> [rebar_app_info:t()].
+find_apps(LibDirs, SrcDirs, Validate) ->
+ rebar_utils:filtermap(
+ fun({AppDir, AppSrcDirs}) ->
+ find_app(rebar_app_info:new(), AppDir, AppSrcDirs, Validate)
+ end,
+ all_app_dirs(LibDirs, SrcDirs)
+ ).
%% @doc check that a given app in a directory is there, and whether it's
%% valid or not based on the second argument. Returns the related
%% app info record.
-spec find_app(file:filename_all(), valid | invalid | all) -> {true, rebar_app_info:t()} | false.
find_app(AppDir, Validate) ->
- find_app(rebar_app_info:new(), AppDir, Validate).
+ SrcDirs = find_config_src(AppDir, ["src"]),
+ find_app(rebar_app_info:new(), AppDir, SrcDirs, Validate).
%% @doc check that a given app in a directory is there, and whether it's
%% valid or not based on the second argument. Returns the related
@@ -239,9 +271,29 @@ find_app(AppDir, Validate) ->
-spec find_app(rebar_app_info:t(), file:filename_all(), valid | invalid | all) ->
{true, rebar_app_info:t()} | false.
find_app(AppInfo, AppDir, Validate) ->
+ %% if no src dir is passed, figure it out from the app info, with a default
+ %% of src/
+ AppOpts = rebar_app_info:opts(AppInfo),
+ SrcDirs = rebar_dir:src_dirs(AppOpts, ["src"]),
+ find_app(AppInfo, AppDir, SrcDirs, Validate).
+
+%% @doc check that a given app in a directory is there, and whether it's
+%% valid or not based on the second argument. The third argument includes
+%% the directories where source files can be located. Returns the related
+%% app info record.
+-spec find_app(rebar_app_info:t(), file:filename_all(),
+ [file:filename_all()], valid | invalid | all) ->
+ {true, rebar_app_info:t()} | false.
+find_app(AppInfo, AppDir, SrcDirs, Validate) ->
AppFile = filelib:wildcard(filename:join([AppDir, "ebin", "*.app"])),
- AppSrcFile = filelib:wildcard(filename:join([AppDir, "src", "*.app.src"])),
- AppSrcScriptFile = filelib:wildcard(filename:join([AppDir, "src", "*.app.src.script"])),
+ AppSrcFile = lists:append(
+ [filelib:wildcard(filename:join([AppDir, SrcDir, "*.app.src"]))
+ || SrcDir <- SrcDirs]
+ ),
+ AppSrcScriptFile = lists:append(
+ [filelib:wildcard(filename:join([AppDir, SrcDir, "*.app.src.script"]))
+ || SrcDir <- SrcDirs]
+ ),
try_handle_app_file(AppInfo, AppFile, AppDir, AppSrcFile, AppSrcScriptFile, Validate).
%% @doc find the directory that an appfile has
@@ -358,3 +410,16 @@ enable(State, AppInfo) ->
-spec to_atom(binary()) -> atom().
to_atom(Bin) ->
list_to_atom(binary_to_list(Bin)).
+
+%% @private when looking for unknown apps, it's possible they have a
+%% rebar.config file specifying non-standard src_dirs. Check for a
+%% possible config file and extract src_dirs from it.
+find_config_src(AppDir, Default) ->
+ case rebar_config:consult(AppDir) of
+ [] ->
+ Default;
+ Terms ->
+ %% TODO: handle profiles I guess, but we don't have that info
+ proplists:get_value(src_dirs, Terms, Default)
+ end.
+
diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl
index fdaadb8..62ec6dd 100644
--- a/src/rebar_app_info.erl
+++ b/src/rebar_app_info.erl
@@ -248,13 +248,12 @@ set(AppInfo=#app_info_t{opts=Opts}, Key, Value) ->
%% @doc finds the .app.src file for an app, if any.
-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
- true ->
- AppFileSrc;
- false ->
- undefined
+app_file_src(#app_info_t{app_file_src=undefined, dir=Dir, name=Name, opts=Opts}) ->
+ CandidatePaths = [filename:join([ec_cnv:to_list(Dir), Src, ec_cnv:to_list(Name)++".app.src"])
+ || Src <- rebar_opts:get(Opts, src_dirs, ["src"])],
+ case lists:dropwhile(fun(Path) -> not filelib:is_file(Path) end, CandidatePaths) of
+ [] -> undefined;
+ [AppFileSrc|_] -> AppFileSrc
end;
app_file_src(#app_info_t{app_file_src=AppFileSrc}) ->
ec_cnv:to_list(AppFileSrc).
diff --git a/src/rebar_config.erl b/src/rebar_config.erl
index 97e27ab..82ff0d9 100644
--- a/src/rebar_config.erl
+++ b/src/rebar_config.erl
@@ -26,7 +26,7 @@
%% -------------------------------------------------------------------
-module(rebar_config).
--export([consult/0
+-export([consult_root/0
,consult/1
,consult_app_file/1
,consult_file/1
@@ -46,15 +46,15 @@
%% Public API
%% ===================================================================
-%% @doc reads the default config file.
--spec consult() -> [any()].
-consult() ->
+%% @doc reads the default config file at the top of a full project
+-spec consult_root() -> [any()].
+consult_root() ->
consult_file(config_file()).
%% @doc reads the default config file in a given directory.
-spec consult(file:name()) -> [any()].
consult(Dir) ->
- consult_file(filename:join(Dir, config_file())).
+ consult_file(filename:join(Dir, ?DEFAULT_CONFIG_FILE)).
%% @doc reads a given app file, including the `.script' variations,
%% if any can be found.
diff --git a/src/rebar_packages.erl b/src/rebar_packages.erl
index 4cce5a8..5b6ab5c 100644
--- a/src/rebar_packages.erl
+++ b/src/rebar_packages.erl
@@ -207,10 +207,10 @@ handle_single_vsn(Pkg, PkgVsn, Dep, Vsn, Constraint) ->
false ->
case {Pkg, PkgVsn} of
{undefined, undefined} ->
- ?WARN("Only existing version of ~s is ~s which does not match constraint ~~> ~s. "
+ ?DEBUG("Only existing version of ~s is ~s which does not match constraint ~~> ~s. "
"Using anyway, but it is not guaranteed to work.", [Dep, Vsn, Constraint]);
_ ->
- ?WARN("[~s:~s] Only existing version of ~s is ~s which does not match constraint ~~> ~s. "
+ ?DEBUG("[~s:~s] Only existing version of ~s is ~s which does not match constraint ~~> ~s. "
"Using anyway, but it is not guaranteed to work.", [Pkg, PkgVsn, Dep, Vsn, Constraint])
end,
{ok, Vsn}
diff --git a/src/rebar_prv_clean.erl b/src/rebar_prv_clean.erl
index 8f31fdd..d185f75 100644
--- a/src/rebar_prv_clean.erl
+++ b/src/rebar_prv_clean.erl
@@ -44,7 +44,8 @@ do(State) ->
case All of
true ->
DepsDir = rebar_dir:deps_dir(State1),
- AllApps = rebar_app_discover:find_apps([filename:join(DepsDir, "*")], all),
+ DepsDirs = filelib:wildcard(filename:join(DepsDir, "*")),
+ AllApps = rebar_app_discover:find_apps(DepsDirs, all),
clean_apps(State1, Providers, AllApps);
false ->
ProjectApps = rebar_state:project_apps(State1),
diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl
index 2ac8fc7..7a060f8 100644
--- a/src/rebar_prv_common_test.erl
+++ b/src/rebar_prv_common_test.erl
@@ -431,18 +431,21 @@ test_dirs(State, Apps, Opts) ->
set_compile_dirs(State, Apps, join(Suites, Dir));
{_Suites, _Dirs} -> {error, "Only a single directory may be specified when specifying suites"}
end;
- Specs0 ->
- case get_dirs_from_specs(Specs0) of
- {ok,{Specs,SuiteDirs}} ->
- {State1,Apps1} = set_compile_dirs1(State, Apps,
- {dir, SuiteDirs}),
- {State2,Apps2} = set_compile_dirs1(State1, Apps1,
- {spec, Specs}),
- [maybe_copy_spec(State2,Apps2,S) || S <- Specs],
- {ok, rebar_state:project_apps(State2, Apps2)};
- Error ->
- Error
- end
+ Spec when is_integer(hd(Spec)) ->
+ spec_test_dirs(State, Apps, [Spec]);
+ Specs ->
+ spec_test_dirs(State, Apps, Specs)
+ end.
+
+spec_test_dirs(State, Apps, Specs0) ->
+ case get_dirs_from_specs(Specs0) of
+ {ok,{Specs,SuiteDirs}} ->
+ {State1,Apps1} = set_compile_dirs1(State, Apps, {dir, SuiteDirs}),
+ {State2,Apps2} = set_compile_dirs1(State1, Apps1, {spec, Specs}),
+ [maybe_copy_spec(State2,Apps2,S) || S <- Specs],
+ {ok, rebar_state:project_apps(State2, Apps2)};
+ Error ->
+ Error
end.
join(Suite, Dir) when is_integer(hd(Suite)) ->
diff --git a/src/rebar_prv_escriptize.erl b/src/rebar_prv_escriptize.erl
index 7ee20c2..56b0d8a 100644
--- a/src/rebar_prv_escriptize.erl
+++ b/src/rebar_prv_escriptize.erl
@@ -130,9 +130,15 @@ escriptize(State0, App) ->
throw(?PRV_ERROR({escript_creation_failed, AppName, EscriptError}))
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),
+ %% Finally, update executable perms for our script on *nix or write out
+ %% script files on win32
+ case os:type() of
+ {unix, _} ->
+ {ok, #file_info{mode = Mode}} = file:read_file_info(Filename),
+ ok = file:change_mode(Filename, Mode bor 8#00111);
+ {win32, _} ->
+ write_windows_script(Filename)
+ end,
{ok, State}.
-spec format_error(any()) -> iolist().
@@ -258,3 +264,14 @@ def(Rm, State, Key, Default) ->
rm_newline(String) ->
[C || C <- String, C =/= $\n].
+
+write_windows_script(Target) ->
+ CmdPath = if is_binary(Target) -> <<Target/binary, ".cmd">>;
+ is_list(Target) -> Target ++ ".cmd"
+ end,
+ CmdScript=
+ "@echo off\r\n"
+ "setlocal\r\n"
+ "set rebarscript=%~f0\r\n"
+ "escript.exe \"%rebarscript:.cmd=%\" %*\r\n",
+ ok = file:write_file(CmdPath, CmdScript).
diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl
index 7d44137..65addc3 100644
--- a/src/rebar_prv_eunit.erl
+++ b/src/rebar_prv_eunit.erl
@@ -83,13 +83,16 @@ run_tests(State, Tests) ->
EUnitOpts = resolve_eunit_opts(State),
?DEBUG("eunit_tests ~p", [T]),
?DEBUG("eunit_opts ~p", [EUnitOpts]),
- Result = eunit:test(T, EUnitOpts),
- ok = maybe_write_coverdata(State),
- case handle_results(Result) of
- {error, Reason} ->
- ?PRV_ERROR(Reason);
- ok ->
- {ok, State}
+ try eunit:test(T, EUnitOpts) of
+ Result ->
+ ok = maybe_write_coverdata(State),
+ case handle_results(Result) of
+ {error, Reason} ->
+ ?PRV_ERROR(Reason);
+ ok ->
+ {ok, State}
+ end
+ catch error:badarg -> ?PRV_ERROR({error, badarg})
end.
-spec format_error(any()) -> iolist().
diff --git a/src/rebar_prv_path.erl b/src/rebar_prv_path.erl
index 4259eec..d8e14a4 100644
--- a/src/rebar_prv_path.erl
+++ b/src/rebar_prv_path.erl
@@ -27,7 +27,7 @@ init(State) ->
{example, "rebar3 path"},
{short_desc, "Print paths to build dirs in current profile."},
{desc, "Print paths to build dirs in current profile."},
- {opts, eunit_opts(State)}])),
+ {opts, path_opts(State)}])),
{ok, State1}.
@@ -107,7 +107,7 @@ normalize(AppName) when is_list(AppName) -> AppName;
normalize(AppName) when is_atom(AppName) -> atom_to_list(AppName);
normalize(AppName) when is_binary(AppName) -> binary_to_list(AppName).
-eunit_opts(_State) ->
+path_opts(_State) ->
[{app, undefined, "app", string, help(app)},
{base, undefined, "base", boolean, help(base)},
{bin, undefined, "bin", boolean, help(bin)},
diff --git a/src/rebar_prv_plugins.erl b/src/rebar_prv_plugins.erl
index 7e6b88e..c76dae1 100644
--- a/src/rebar_prv_plugins.erl
+++ b/src/rebar_prv_plugins.erl
@@ -34,14 +34,17 @@ do(State) ->
GlobalConfigFile = rebar_dir:global_config(),
GlobalConfig = rebar_state:new(rebar_config:consult_file(GlobalConfigFile)),
GlobalPlugins = rebar_state:get(GlobalConfig, plugins, []),
+ GlobalSrcDirs = rebar_state:get(GlobalConfig, src_dirs, ["src"]),
GlobalPluginsDir = filename:join([rebar_dir:global_cache_dir(rebar_state:opts(State)), "plugins", "*"]),
- GlobalApps = rebar_app_discover:find_apps([GlobalPluginsDir], all),
+ GlobalApps = rebar_app_discover:find_apps([GlobalPluginsDir], GlobalSrcDirs, all),
display_plugins("Global plugins", GlobalApps, GlobalPlugins),
+ RebarOpts = rebar_state:opts(State),
+ SrcDirs = rebar_dir:src_dirs(RebarOpts, ["src"]),
Plugins = rebar_state:get(State, plugins, []),
- PluginsDir = filename:join(rebar_dir:plugins_dir(State), "*"),
- CheckoutsDir = filename:join(rebar_dir:checkouts_dir(State), "*"),
- Apps = rebar_app_discover:find_apps([CheckoutsDir, PluginsDir], all),
+ PluginsDirs = filelib:wildcard(filename:join(rebar_dir:plugins_dir(State), "*")),
+ CheckoutsDirs = filelib:wildcard(filename:join(rebar_dir:checkouts_dir(State), "*")),
+ Apps = rebar_app_discover:find_apps(CheckoutsDirs++PluginsDirs, SrcDirs, all),
display_plugins("Local plugins", Apps, Plugins),
{ok, State}.
diff --git a/src/rebar_prv_upgrade.erl b/src/rebar_prv_upgrade.erl
index 18c307b..34631ff 100644
--- a/src/rebar_prv_upgrade.erl
+++ b/src/rebar_prv_upgrade.erl
@@ -32,7 +32,7 @@ init(State) ->
{deps, ?DEPS},
{example, "rebar3 upgrade [cowboy[,ranch]]"},
{short_desc, "Upgrade dependencies."},
- {desc, "Upgrade project dependecies. Mentioning no application "
+ {desc, "Upgrade project dependencies. Mentioning no application "
"will upgrade all dependencies. To upgrade specific dependencies, "
"their names can be listed in the command."},
{opts, [
diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl
index 9b33ec5..1c28788 100644
--- a/src/rebar_templater.erl
+++ b/src/rebar_templater.erl
@@ -334,8 +334,19 @@ find_plugin_templates(State) ->
|| App <- rebar_state:all_plugin_deps(State),
Priv <- [rebar_app_info:priv_dir(App)],
Priv =/= undefined,
+ File <- rebar_utils:find_files(Priv, ?TEMPLATE_RE)]
+ ++ %% and add global plugins too
+ [{plugin, File}
+ || PSource <- rebar_state:get(State, {plugins, global}, []),
+ Plugin <- [plugin_provider(PSource)],
+ is_atom(Plugin),
+ Priv <- [code:priv_dir(Plugin)],
+ Priv =/= undefined,
File <- rebar_utils:find_files(Priv, ?TEMPLATE_RE)].
+plugin_provider(P) when is_atom(P) -> P;
+plugin_provider(T) when is_tuple(T) -> element(1, T).
+
%% Take an existing list of templates and tag them by name the way
%% the user would enter it from the CLI
tag_names(List) ->
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index c357e94..c684e2d 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -857,7 +857,7 @@ url_append_path(Url, ExtraPath) ->
escape_chars(Str) when is_atom(Str) ->
escape_chars(atom_to_list(Str));
escape_chars(Str) ->
- re:replace(Str, "([ ()?`!$&;])", "\\\\&", [global, {return, list}]).
+ re:replace(Str, "([ ()?`!$&;\"\'])", "\\\\&", [global, {return, list}]).
%% "escape inside these"
escape_double_quotes(Str) ->
diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl
index 9f01496..5a18745 100644
--- a/test/rebar_compile_SUITE.erl
+++ b/test/rebar_compile_SUITE.erl
@@ -78,21 +78,10 @@ all() ->
recompile_when_parse_transform_as_opt_changes,
recompile_when_parse_transform_inline_changes,
regex_filter_skip, regex_filter_regression,
- %% recompile behaviour when `ERL_COMPILER_OPTIONS` differs prior to 19.x
- recursive, no_recursive] ++ recompile_when_env_changes_test().
-
-recompile_when_env_changes_test() ->
- _ = code:ensure_loaded(os),
- UnSetEnv = erlang:function_exported(os, unsetenv, 1),
- _ = code:ensure_loaded(compile),
- EnvOpts = erlang:function_exported(compile, env_compiler_options, 0),
- case {UnSetEnv, EnvOpts} of
- {true, true} ->
- [dont_recompile_when_erl_compiler_options_env_does_not_change,
- recompile_when_erl_compiler_options_env_changes];
- {true, false} -> [always_recompile_when_erl_compiler_options_set];
- {false, _} -> []
- end.
+ recursive, no_recursive,
+ always_recompile_when_erl_compiler_options_set,
+ dont_recompile_when_erl_compiler_options_env_does_not_change,
+ recompile_when_erl_compiler_options_env_changes].
groups() ->
[{basic_app, [], [build_basic_app, paths_basic_app, clean_basic_app]},
@@ -266,7 +255,31 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
ok.
-init_per_testcase(_, Config) ->
+init_per_testcase(Test, Config) when
+ Test == dont_recompile_when_erl_compiler_options_env_does_not_change
+ orelse
+ Test == recompile_when_erl_compiler_options_env_changes ->
+ _ = code:ensure_loaded(os),
+ UnSetEnv = erlang:function_exported(os, unsetenv, 1),
+ _ = code:ensure_loaded(compile),
+ EnvOpts = erlang:function_exported(compile, env_compiler_options, 0),
+ case {UnSetEnv, EnvOpts} of
+ {true, true} -> maybe_init_config(Config);
+ _ -> {skip, "compile:env_compiler_options/0 unavailable"}
+ end;
+init_per_testcase(always_recompile_when_erl_compiler_options_set, Config) ->
+ _ = code:ensure_loaded(os),
+ UnSetEnv = erlang:function_exported(os, unsetenv, 1),
+ _ = code:ensure_loaded(compile),
+ EnvOpts = erlang:function_exported(compile, env_compiler_options, 0),
+ case {UnSetEnv, EnvOpts} of
+ {true, true} -> {skip, "compile:env_compiler_options/0 available"};
+ {true, false} -> maybe_init_config(Config);
+ _ -> {skip, "os:unsetenv/1 unavailable"}
+ end;
+init_per_testcase(_, Config) -> maybe_init_config(Config).
+
+maybe_init_config(Config) ->
case ?config(apps, Config) of
undefined -> rebar_test_utils:init_rebar_state(Config);
_ -> Config
@@ -276,7 +289,6 @@ end_per_testcase(_, _Config) ->
catch meck:unload().
-
%% test cases
build_basic_app(Config) ->
diff --git a/test/rebar_ct_SUITE.erl b/test/rebar_ct_SUITE.erl
index 06dc76e..586e7b5 100644
--- a/test/rebar_ct_SUITE.erl
+++ b/test/rebar_ct_SUITE.erl
@@ -55,7 +55,8 @@
testspec/1,
testspec_at_root/1,
testspec_parse_error/1,
- cmd_vs_cfg_opts/1]).
+ cmd_vs_cfg_opts/1,
+ single_testspec_in_ct_opts/1]).
-include_lib("eunit/include/eunit.hrl").
-include_lib("common_test/include/ct.hrl").
@@ -75,7 +76,8 @@ all() -> [{group, basic_app},
testspec,
testspec_at_root,
testspec_parse_error,
- cmd_vs_cfg_opts].
+ cmd_vs_cfg_opts,
+ single_testspec_in_ct_opts].
groups() -> [{basic_app, [], [basic_app_default_dirs,
basic_app_default_beams,
@@ -1548,6 +1550,41 @@ cmd_vs_cfg_opts(Config) ->
ok.
+single_testspec_in_ct_opts(Config) ->
+ C = rebar_test_utils:init_rebar_state(Config, "ct_testspec_"),
+
+ AppDir = ?config(apps, C),
+
+ Name = rebar_test_utils:create_random_name("ct_testspec_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ Spec = filename:join([AppDir, "test", "some.spec"]),
+ ok = filelib:ensure_dir(Spec),
+ ok = file:write_file(Spec, "{suites,\".\",all}.\n"),
+
+ {ok,Wd} = file:get_cwd(),
+ ok = file:set_cwd(AppDir),
+
+ RebarConfig = [{ct_opts, [{spec,"test/some.spec"}]}],
+
+ {ok, State} = rebar_test_utils:run_and_check(C, RebarConfig, ["as", "test", "lock"], return),
+
+ Providers = rebar_state:providers(State),
+ Namespace = rebar_state:namespace(State),
+ CommandProvider = providers:get_provider(ct, Providers, Namespace),
+ GetOptSpec = providers:opts(CommandProvider),
+
+ %% Testspec in "test" directory
+ {ok, GetOptResult1} = getopt:parse(GetOptSpec, []),
+ State1 = rebar_state:command_parsed_args(State, GetOptResult1),
+ Tests1 = rebar_prv_common_test:prepare_tests(State1),
+ {ok, T1} = Tests1,
+ "test/some.spec" = proplists:get_value(spec,T1),
+ {ok, _NewState} = rebar_prv_common_test:compile(State1, Tests1),
+
+ ok = file:set_cwd(Wd),
+ ok.
+
%% helper for generating test data
test_suite(Name) ->
io_lib:format("-module(~ts_SUITE).\n"
diff --git a/test/rebar_eunit_SUITE.erl b/test/rebar_eunit_SUITE.erl
index 6fb325b..4805b3d 100644
--- a/test/rebar_eunit_SUITE.erl
+++ b/test/rebar_eunit_SUITE.erl
@@ -1,7 +1,8 @@
-module(rebar_eunit_SUITE).
-export([all/0, groups/0]).
--export([init_per_suite/1, init_per_group/2, end_per_group/2]).
+-export([init_per_suite/1, end_per_suite/1]).
+-export([init_per_group/2, end_per_group/2]).
-export([basic_app_compiles/1, basic_app_files/1]).
-export([basic_app_exports/1, basic_app_testset/1]).
-export([basic_app_eunit_macro/1]).
@@ -60,6 +61,8 @@ init_per_suite(Config) ->
{ok, _} = zip:extract(filename:join([PrivDir, "multi_app.zip"]), [{cwd, PrivDir}]),
Config.
+end_per_suite(Config) -> Config.
+
init_per_group(basic_app, Config) ->
GroupState = rebar_test_utils:init_rebar_state(Config, "basic_app_"),
diff --git a/test/rebar_src_dirs_SUITE.erl b/test/rebar_src_dirs_SUITE.erl
index f854a94..bc22160 100644
--- a/test/rebar_src_dirs_SUITE.erl
+++ b/test/rebar_src_dirs_SUITE.erl
@@ -11,12 +11,16 @@
src_dirs_in_erl_opts/1,
extra_src_dirs_in_erl_opts/1,
src_dirs_at_root_and_in_erl_opts/1,
+ dupe_src_dirs_at_root_and_in_erl_opts/1,
extra_src_dirs_at_root_and_in_erl_opts/1,
build_basic_app/1,
build_multi_apps/1,
- src_dir_takes_precedence_over_extra/1]).
+ src_dir_takes_precedence_over_extra/1,
+ src_dir_checkout_dep/1,
+ app_src_info/1]).
-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
suite() ->
[].
@@ -35,8 +39,11 @@ end_per_testcase(_, _Config) -> ok.
all() ->
[src_dirs_at_root, extra_src_dirs_at_root,
src_dirs_in_erl_opts, extra_src_dirs_in_erl_opts,
- src_dirs_at_root_and_in_erl_opts, extra_src_dirs_at_root_and_in_erl_opts,
- build_basic_app, build_multi_apps, src_dir_takes_precedence_over_extra].
+ src_dirs_at_root_and_in_erl_opts,
+ dupe_src_dirs_at_root_and_in_erl_opts,
+ extra_src_dirs_at_root_and_in_erl_opts,
+ build_basic_app, build_multi_apps, src_dir_takes_precedence_over_extra,
+ src_dir_checkout_dep, app_src_info].
src_dirs_at_root(Config) ->
AppDir = ?config(apps, Config),
@@ -93,15 +100,47 @@ extra_src_dirs_in_erl_opts(Config) ->
src_dirs_at_root_and_in_erl_opts(Config) ->
AppDir = ?config(apps, Config),
- Name = rebar_test_utils:create_random_name("app1_"),
+ Name = rebar_test_utils:create_random_name("src_dirs_root_erlopts_"),
Vsn = rebar_test_utils:create_random_vsn(),
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
RebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar"]}]}, {src_dirs, ["baz", "qux"]}],
+ %% move the .app.src file to one of the subdirs, out of src/
+ filelib:ensure_dir(filename:join([AppDir, "qux", "fake"])),
+ rebar_file_utils:mv(filename:join([AppDir, "src", Name ++ ".app.src"]),
+ filename:join([AppDir, "qux", Name ++ ".app.src"])),
+
{ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return),
- ["bar", "baz", "foo", "qux"] = rebar_dir:src_dirs(rebar_state:opts(State), []).
+ ["bar", "baz", "foo", "qux"] = rebar_dir:src_dirs(rebar_state:opts(State), []),
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"],
+ {ok, [{app, Name}]}),
+ ok.
+
+dupe_src_dirs_at_root_and_in_erl_opts(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("dupe_src_dirs_root_erlopts_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar"]}]}, {src_dirs, ["baz", "qux"]}],
+
+ %% move the .app.src file to one of the subdirs, out of src/
+ filelib:ensure_dir(filename:join([AppDir, "qux", "fake"])),
+ filelib:ensure_dir(filename:join([AppDir, "foo", "fake"])),
+ Src1 = filename:join([AppDir, "qux", Name ++ ".app.src"]),
+ Src2 = filename:join([AppDir, "foo", Name ++ ".app.src"]),
+ rebar_file_utils:mv(filename:join([AppDir, "src", Name ++ ".app.src"]),
+ Src1),
+ %% Then copy it over to create a conflict with dupes
+ file:copy(Src1, Src2),
+
+ {error, {rebar_prv_app_discovery, {multiple_app_files, [Src2, Src1]}}} =
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return),
+
+ ok.
extra_src_dirs_at_root_and_in_erl_opts(Config) ->
AppDir = ?config(apps, Config),
@@ -236,3 +275,52 @@ src_dir_takes_precedence_over_extra(Config) ->
[{application, _, KVs}] = App,
Mods = proplists:get_value(modules, KVs),
true = lists:member(extra, Mods).
+
+src_dir_checkout_dep(Config) ->
+ AppDir = ?config(apps, Config),
+ AppName = rebar_test_utils:create_random_name("src_dir_checkout_app"),
+ DepName = rebar_test_utils:create_random_name("src_dir_checkout_dep"),
+ AtomDep = list_to_atom(DepName),
+
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, AppName, Vsn, [kernel, stdlib]),
+ RebarConfig = [{deps, [AtomDep]}],
+
+ DepDir = filename:join([?config(checkouts, Config), DepName]),
+ ct:pal("checkouts dir: ~p", [DepDir]),
+ rebar_test_utils:create_app(DepDir, DepName, Vsn, [kernel, stdlib]),
+
+
+ %% move the .app.src file to one of the subdirs, out of src/
+ rebar_file_utils:mv(filename:join([DepDir, "src"]),
+ filename:join([DepDir, "qux"])),
+ DepRebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar"]}]},
+ {src_dirs, ["baz", "qux"]}],
+ file:write_file(filename:join([DepDir, "rebar.config"]),
+ io_lib:format("~p.~n~p.~n", DepRebarConfig)),
+
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["compile"],
+ {ok, [{checkout, DepName}, {app, AppName}]}
+ ),
+ ok.
+
+app_src_info(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ AppName1 = rebar_test_utils:create_random_name("app_src_info"),
+ AppDir1 = filename:join(PrivDir, AppName1),
+ {ok, Info1} = rebar_app_info:new(AppName1, "1.0.0", AppDir1),
+ AppSrc1 = filename:join([AppDir1, "src", AppName1 ++ ".app.src"]),
+ ok = filelib:ensure_dir(AppSrc1),
+ ok = file:write_file(AppSrc1, "[]."),
+ ?assertEqual(AppSrc1, rebar_app_info:app_file_src(Info1)),
+
+ AppName2 = rebar_test_utils:create_random_name("app_src_info"),
+ AppDir2 = filename:join(PrivDir, AppName2),
+ {ok, Info2Tmp} = rebar_app_info:new(AppName2, "1.0.0", AppDir2),
+ Info2 = rebar_app_info:set(Info2Tmp, src_dirs, ["foo", "bar", "baz"]),
+ AppSrc2 = filename:join([AppDir2, "bar", AppName2 ++ ".app.src"]),
+ ok = filelib:ensure_dir(AppSrc2),
+ ok = file:write_file(AppSrc2, "[]."),
+ ?assertEqual(AppSrc2, rebar_app_info:app_file_src(Info2)),
+ ok.
diff --git a/test/rebar_test_utils.erl b/test/rebar_test_utils.erl
index 8c177c9..3b8ffac 100644
--- a/test/rebar_test_utils.erl
+++ b/test/rebar_test_utils.erl
@@ -218,7 +218,7 @@ check_results(AppDir, Expected, ProfileRun) ->
BuildDirs = filelib:wildcard(filename:join([AppDir, "_build", ProfileRun, "lib", "*"])),
PluginDirs = filelib:wildcard(filename:join([AppDir, "_build", ProfileRun, "plugins", "*"])),
GlobalPluginDirs = filelib:wildcard(filename:join([AppDir, "global", "plugins", "*"])),
- CheckoutsDir = filename:join([AppDir, "_checkouts", "*"]),
+ CheckoutsDirs = filelib:wildcard(filename:join([AppDir, "_checkouts", "*"])),
LockFile = filename:join([AppDir, "rebar.lock"]),
Locks = lists:flatten(rebar_config:consult_lock_file(LockFile)),
@@ -230,7 +230,7 @@ check_results(AppDir, Expected, ProfileRun) ->
Deps = rebar_app_discover:find_apps(BuildDirs, all),
DepsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Deps],
- Checkouts = rebar_app_discover:find_apps([CheckoutsDir], all),
+ Checkouts = rebar_app_discover:find_apps(CheckoutsDirs, all),
CheckoutsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Checkouts],
Plugins = rebar_app_discover:find_apps(PluginDirs, all),
PluginsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Plugins],