summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rebar.config2
-rw-r--r--src/rebar_agent.erl6
-rw-r--r--src/rebar_dir.erl6
-rw-r--r--src/rebar_file_utils.erl90
-rw-r--r--src/rebar_git_resource.erl2
-rw-r--r--src/rebar_prv_common_test.erl41
-rw-r--r--src/rebar_prv_dialyzer.erl10
-rw-r--r--src/rebar_utils.erl14
-rw-r--r--test/rebar_compile_SUITE.erl8
-rw-r--r--test/rebar_hooks_SUITE.erl2
-rw-r--r--test/rebar_test_utils.erl10
-rw-r--r--test/rebar_utils_SUITE.erl17
12 files changed, 149 insertions, 59 deletions
diff --git a/rebar.config b/rebar.config
index f31f0af..bd0f517 100644
--- a/rebar.config
+++ b/rebar.config
@@ -9,7 +9,7 @@
{relx, "3.0.0"}]}.
{escript_name, rebar3}.
-{escript_emu_args, "%%! +Bc +sbtu +A0\n"}.
+{escript_emu_args, "%%! +sbtu +A0\n"}.
%% escript_incl_extra is for internal rebar-private use only.
%% Do not use outside rebar. Config interface is not stable.
{escript_incl_extra, [{"_build/default/lib/relx/priv/templates/*", "."},
diff --git a/src/rebar_agent.erl b/src/rebar_agent.erl
index 0432fb8..674e002 100644
--- a/src/rebar_agent.erl
+++ b/src/rebar_agent.erl
@@ -20,7 +20,7 @@ do(Namespace, Command) when is_atom(Namespace), is_atom(Command) ->
gen_server:call(?MODULE, {cmd, Namespace, Command}, infinity).
init(State) ->
- {ok, Cwd} = file:get_cwd(),
+ Cwd = rebar_dir:get_cwd(),
{ok, #state{state=State, cwd=Cwd}}.
handle_call({cmd, Command}, _From, State=#state{state=RState, cwd=Cwd}) ->
@@ -48,8 +48,8 @@ terminate(_Reason, _State) ->
run(Namespace, Command, RState, Cwd) ->
try
- case file:get_cwd() of
- {ok, Cwd} ->
+ case rebar_dir:get_cwd() of
+ Cwd ->
Args = [atom_to_list(Namespace), atom_to_list(Command)],
CmdState0 = refresh_state(RState, Cwd),
CmdState1 = rebar_state:set(CmdState0, task, atom_to_list(Command)),
diff --git a/src/rebar_dir.erl b/src/rebar_dir.erl
index e226633..7af94ea 100644
--- a/src/rebar_dir.erl
+++ b/src/rebar_dir.erl
@@ -100,7 +100,11 @@ local_cache_dir(Dir) ->
get_cwd() ->
{ok, Dir} = file:get_cwd(),
- Dir.
+ %% On windows cwd may return capital letter for drive,
+ %% for example C:/foobar. But as said in http://www.erlang.org/doc/man/filename.html#join-1
+ %% filename:join/1,2 anyway will convert drive-letter to lowercase, so we have to "internalize"
+ %% cwd as soon as it possible.
+ filename:join([Dir]).
template_globals(State) ->
filename:join([global_config_dir(State), "templates", "globals"]).
diff --git a/src/rebar_file_utils.erl b/src/rebar_file_utils.erl
index ad30172..3fc5698 100644
--- a/src/rebar_file_utils.erl
+++ b/src/rebar_file_utils.erl
@@ -36,10 +36,14 @@
write_file_if_contents_differ/2,
system_tmpdir/0,
system_tmpdir/1,
- reset_dir/1]).
+ reset_dir/1,
+ touch/1]).
-include("rebar.hrl").
+
-include_lib("providers/include/providers.hrl").
+-include_lib("kernel/include/file.hrl").
+
%% ===================================================================
%% Public API
@@ -71,9 +75,40 @@ symlink_or_copy(Source, Target) ->
{error, eexist} ->
ok;
{error, _} ->
- cp_r([Source], Target)
+ case os:type() of
+ {win32, _} ->
+ S = unicode:characters_to_list(Source),
+ T = unicode:characters_to_list(Target),
+ case filelib:is_dir(S) of
+ true ->
+ win32_symlink(S, T);
+ false ->
+ cp_r([S], T)
+ end;
+ _ ->
+ case filelib:is_dir(Target) of
+ true ->
+ ok;
+ false ->
+ cp_r([Source], Target)
+ end
+ end
+ end.
+
+win32_symlink(Source, Target) ->
+ Res = rebar_utils:sh(
+ ?FMT("cmd /c mklink /j \"~s\" \"~s\"",
+ [filename:nativename(Target), filename:nativename(Source)]),
+ [{use_stdout, false}, return_on_error]),
+ case win32_ok(Res) of
+ true -> ok;
+ false ->
+ {error, lists:flatten(
+ io_lib:format("Failed to symlink ~s to ~s~n",
+ [Source, Target]))}
end.
+
%% @doc Remove files and directories.
%% Target is a single filename, directoryname or wildcard expression.
-spec rm_rf(string()) -> 'ok'.
@@ -120,21 +155,24 @@ mv(Source, Dest) ->
[{use_stdout, false}, abort_on_error]),
ok;
{win32, _} ->
- {ok, R} = rebar_utils:sh(
- ?FMT("move /y \"~s\" \"~s\" 1> nul",
+ Res = rebar_utils:sh(
+ ?FMT("robocopy /move /s \"~s\" \"~s\" 1> nul",
[filename:nativename(Source),
filename:nativename(Dest)]),
[{use_stdout, false}, return_on_error]),
- case R of
- [] ->
- ok;
- _ ->
+ case win32_ok(Res) of
+ true -> ok;
+ false ->
{error, lists:flatten(
io_lib:format("Failed to move ~s to ~s~n",
[Source, Dest]))}
end
end.
+win32_ok({ok, _}) -> true;
+win32_ok({error, {Rc, _}}) when Rc<9; Rc=:=16 -> true;
+win32_ok(_) -> false.
+
delete_each([]) ->
ok;
delete_each([File | Rest]) ->
@@ -186,6 +224,17 @@ reset_dir(Path) ->
%% recreate the directory
filelib:ensure_dir(filename:join([Path, "dummy.beam"])).
+
+%% Linux touch but using erlang functions to work in bot *nix os and
+%% windows
+-spec touch(Path) -> ok | {error, Reason} when
+ Path :: file:name(),
+ Reason :: file:posix().
+touch(Path) ->
+ {ok, A} = file:read_file_info(Path),
+ ok = file:write_file_info(Path, A#file_info{mtime = calendar:local_time(),
+ atime = calendar:local_time()}).
+
%% ===================================================================
%% Internal functions
%% ===================================================================
@@ -198,28 +247,27 @@ delete_each_dir_win32([Dir | Rest]) ->
delete_each_dir_win32(Rest).
xcopy_win32(Source,Dest)->
- {ok, R} = rebar_utils:sh(
- ?FMT("xcopy \"~s\" \"~s\" /q /y /e 2> nul",
+ %% "xcopy \"~s\" \"~s\" /q /y /e 2> nul", Chanegd to robocopy to
+ %% handle long names. May have issues with older windows.
+ Res = rebar_utils:sh(
+ ?FMT("robocopy \"~s\" \"~s\" /e /is /purge 2> nul",
[filename:nativename(Source), filename:nativename(Dest)]),
[{use_stdout, false}, return_on_error]),
- case length(R) > 0 of
- %% when xcopy fails, stdout is empty and and error message is printed
- %% to stderr (which is redirected to nul)
- true -> ok;
- false ->
- {error, lists:flatten(
- io_lib:format("Failed to xcopy from ~s to ~s~n",
- [Source, Dest]))}
+ case win32_ok(Res) of
+ true -> ok;
+ false ->
+ {error, lists:flatten(
+ io_lib:format("Failed to copy ~s to ~s~n",
+ [Source, Dest]))}
end.
cp_r_win32({true, SourceDir}, {true, DestDir}) ->
%% from directory to directory
- SourceBase = filename:basename(SourceDir),
- ok = case file:make_dir(filename:join(DestDir, SourceBase)) of
+ ok = case file:make_dir(DestDir) of
{error, eexist} -> ok;
Other -> Other
end,
- ok = xcopy_win32(SourceDir, filename:join(DestDir, SourceBase));
+ ok = xcopy_win32(SourceDir, DestDir);
cp_r_win32({false, Source} = S,{true, DestDir}) ->
%% from file to directory
cp_r_win32(S, {false, filename:join(DestDir, filename:basename(Source))});
diff --git a/src/rebar_git_resource.erl b/src/rebar_git_resource.erl
index 2d83579..dfec86a 100644
--- a/src/rebar_git_resource.erl
+++ b/src/rebar_git_resource.erl
@@ -109,7 +109,7 @@ download(Dir, {git, Url, Rev}, _State) ->
rebar_utils:sh(?FMT("git checkout -q ~s", [Rev]), [{cd, Dir}]).
make_vsn(Dir) ->
- {ok, Cwd} = file:get_cwd(),
+ Cwd = rebar_dir:get_cwd(),
try
ok = file:set_cwd(Dir),
{Vsn, RawRef, RawCount} = collect_default_refcount(),
diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl
index 710922a..2b024cf 100644
--- a/src/rebar_prv_common_test.erl
+++ b/src/rebar_prv_common_test.erl
@@ -105,14 +105,18 @@ run_test_verbose(Opts) -> handle_results(ct:run_test(Opts)).
run_test_quiet(Opts) ->
Pid = self(),
+ Ref = erlang:make_ref(),
LogDir = proplists:get_value(logdir, Opts),
- erlang:spawn_monitor(fun() ->
+ {_, Monitor} = erlang:spawn_monitor(fun() ->
{ok, F} = file:open(filename:join([LogDir, "ct.latest.log"]),
[write]),
true = group_leader(F, self()),
- Pid ! ct:run_test(Opts)
+ Pid ! {Ref, ct:run_test(Opts)}
end),
- receive Result -> handle_quiet_results(Opts, Result) end.
+ receive
+ {Ref, Result} -> handle_quiet_results(Opts, Result);
+ {'DOWN', Monitor, _, _, Reason} -> handle_results(?PRV_ERROR(Reason))
+ end.
handle_results(Results) when is_list(Results) ->
Result = lists:foldl(fun sum_results/2, {0, 0, {0,0}}, Results),
@@ -132,8 +136,6 @@ sum_results({Passed, Failed, {UserSkipped, AutoSkipped}},
handle_quiet_results(_, {error, _} = Result) ->
handle_results(Result);
-handle_quiet_results(_, {'DOWN', _, _, _, Reason}) ->
- handle_results(?PRV_ERROR(Reason));
handle_quiet_results(CTOpts, Results) when is_list(Results) ->
_ = [format_result(Result) || Result <- Results],
case handle_results(Results) of
@@ -345,23 +347,26 @@ reduce_path([_|Acc], [".."|Rest]) -> reduce_path(Acc, Rest);
reduce_path([], [".."|Rest]) -> reduce_path([], Rest);
reduce_path(Acc, [Component|Rest]) -> reduce_path([Component|Acc], Rest).
-remove_links(Path) ->
- case ec_file:is_dir(Path) of
- false -> ok;
- true -> remove_links1(Path)
- end.
-remove_links1(Path) ->
+remove_links(Path) ->
+ IsDir = ec_file:is_dir(Path),
case ec_file:is_symlink(Path) of
- true ->
- file:delete(Path);
- false ->
- lists:foreach(fun(ChildPath) ->
- remove_links(ChildPath)
- end, sub_dirs(Path))
+ true when IsDir ->
+ delete_dir_link(Path);
+ false when IsDir ->
+ lists:foreach(fun(ChildPath) ->
+ remove_links(ChildPath)
+ end, dir_entries(Path));
+ _ -> file:delete(Path)
end.
-sub_dirs(Path) ->
+delete_dir_link(Path) ->
+ case os:type() of
+ {unix, _} -> file:delete(Path);
+ {win32, _} -> file:del_dir(Path)
+ end.
+
+dir_entries(Path) ->
{ok, SubDirs} = file:list_dir(Path),
[filename:join(Path, SubDir) || SubDir <- SubDirs].
diff --git a/src/rebar_prv_dialyzer.erl b/src/rebar_prv_dialyzer.erl
index 15f1dac..1cf7b71 100644
--- a/src/rebar_prv_dialyzer.erl
+++ b/src/rebar_prv_dialyzer.erl
@@ -72,6 +72,7 @@ short_desc() ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
+ maybe_fix_env(),
?INFO("Dialyzer starting, this may take a while...", []),
code:add_pathsa(rebar_state:code_paths(State, all_deps)),
Plt = get_plt(State),
@@ -91,6 +92,13 @@ do(State) ->
rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default))
end.
+%% This is used to workaround dialyzer quirk discussed here
+%% https://github.com/rebar/rebar3/pull/489#issuecomment-107953541
+%% Dialyzer gets default plt location wrong way by peeking HOME environment
+%% variable which usually is not defined on Windows.
+maybe_fix_env() ->
+ os:putenv("DIALYZER_PLT", filename:join(rebar_dir:home_dir(), ".dialyzer_plt")).
+
-spec format_error(any()) -> iolist().
format_error({error_processing_apps, Error}) ->
io_lib:format("Error in dialyzing apps: ~s", [Error]);
@@ -380,7 +388,7 @@ run_dialyzer(State, Opts, Output) ->
{check_plt, false} |
Opts],
?DEBUG("Running dialyzer with options: ~p~n", [Opts2]),
- _ = dialyzer:run(Opts2),
+ dialyzer:run(Opts2),
{0, State}
end.
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index cc59ed0..0cbc7c2 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -154,7 +154,7 @@ sh(Command0, Options0) ->
Command = lists:flatten(patch_on_windows(Command0, proplists:get_value(env, Options, []))),
PortSettings = proplists:get_all_values(port_settings, Options) ++
- [exit_status, {line, 16384}, use_stdio, stderr_to_stdout, hide],
+ [exit_status, {line, 16384}, use_stdio, stderr_to_stdout, hide, eof],
?DEBUG("Port Cmd: ~s\nPort Opts: ~p\n", [Command, PortSettings]),
Port = open_port({spawn, Command}, PortSettings),
@@ -435,10 +435,14 @@ sh_loop(Port, Fun, Acc) ->
sh_loop(Port, Fun, Fun(Line ++ "\n", Acc));
{Port, {data, {noeol, Line}}} ->
sh_loop(Port, Fun, Fun(Line, Acc));
- {Port, {exit_status, 0}} ->
- {ok, lists:flatten(lists:reverse(Acc))};
- {Port, {exit_status, Rc}} ->
- {error, {Rc, lists:flatten(lists:reverse(Acc))}}
+ {Port, eof} ->
+ Data = lists:flatten(lists:reverse(Acc)),
+ receive
+ {Port, {exit_status, 0}} ->
+ {ok, Data};
+ {Port, {exit_status, Rc}} ->
+ {error, {Rc, Data}}
+ end
end.
beam_to_mod(Dir, Filename) ->
diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl
index 8ee8af4..8dca46c 100644
--- a/test/rebar_compile_SUITE.erl
+++ b/test/rebar_compile_SUITE.erl
@@ -163,9 +163,10 @@ recompile_when_hrl_changes(Config) ->
ModTime = [filelib:last_modified(filename:join([EbinDir, F]))
|| F <- Files, filename:extension(F) == ".beam"],
+
timer:sleep(1000),
- os:cmd("touch " ++ HeaderFile),
+ rebar_file_utils:touch(HeaderFile),
rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
@@ -274,9 +275,9 @@ delete_beam_if_source_deleted(Config) ->
rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
- SrcDir = filename:join([AppDir, "_build", "default", "lib", Name, "src"]),
+ _SrcDir = filename:join([AppDir, "_build", "default", "lib", Name, "src"]),
?assert(filelib:is_regular(filename:join(EbinDir, "not_a_real_src_" ++ Name ++ ".beam"))),
- file:delete(filename:join(SrcDir, "not_a_real_src_" ++ Name ++ ".erl")),
+ file:delete(filename:join([AppDir, "src", "not_a_real_src_" ++ Name ++ ".erl"])),
rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
@@ -307,6 +308,7 @@ deps_in_path(Config) ->
?assertEqual([], [Path || Path <- code:get_path(),
{match, _} <- [re:run(Path, DepName)]]),
%% Hope not to find pkg name in there
+
?assertEqual([], [Path || Path <- code:get_path(),
{match, _} <- [re:run(Path, PkgName)]]),
%% Build things
diff --git a/test/rebar_hooks_SUITE.erl b/test/rebar_hooks_SUITE.erl
index ec5cc9a..85ca0e5 100644
--- a/test/rebar_hooks_SUITE.erl
+++ b/test/rebar_hooks_SUITE.erl
@@ -114,7 +114,7 @@ run_hooks_for_plugins(Config) ->
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
PluginName = rebar_test_utils:create_random_name("plugin1_"),
- mock_git_resource:mock([{config, [{pre_hooks, [{compile, "touch randomfile"}]}]}]),
+ mock_git_resource:mock([{config, [{pre_hooks, [{compile, "echo whatsup > randomfile"}]}]}]),
RConfFile = rebar_test_utils:create_config(AppDir,
[{plugins, [
diff --git a/test/rebar_test_utils.erl b/test/rebar_test_utils.erl
index e5de0a6..4943d4b 100644
--- a/test/rebar_test_utils.erl
+++ b/test/rebar_test_utils.erl
@@ -105,16 +105,22 @@ create_config(AppDir, Contents) ->
%% @doc Util to create a random variation of a given name.
create_random_name(Name) ->
- random:seed(os:timestamp()),
+ random_seed(),
Name ++ erlang:integer_to_list(random:uniform(1000000)).
%% @doc Util to create a random variation of a given version.
create_random_vsn() ->
- random:seed(os:timestamp()),
+ random_seed(),
lists:flatten([erlang:integer_to_list(random:uniform(100)),
".", erlang:integer_to_list(random:uniform(100)),
".", erlang:integer_to_list(random:uniform(100))]).
+random_seed() ->
+ <<A:32, B:32, C:32>> = crypto:rand_bytes(12),
+ random:seed({A,B,C}).
+
+
+
expand_deps(_, []) -> [];
expand_deps(git, [{Name, Deps} | Rest]) ->
Dep = {Name, ".*", {git, "https://example.org/user/"++Name++".git", "master"}},
diff --git a/test/rebar_utils_SUITE.erl b/test/rebar_utils_SUITE.erl
index e9b32e2..f04ab63 100644
--- a/test/rebar_utils_SUITE.erl
+++ b/test/rebar_utils_SUITE.erl
@@ -21,7 +21,8 @@
task_with_flag_with_trailing_comma/1,
task_with_flag_with_commas/1,
task_with_multiple_flags/1,
- special_task_do/1]).
+ special_task_do/1,
+ sh_does_not_miss_messages/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -29,7 +30,8 @@
all() ->
- [{group, args_to_tasks}].
+ [{group, args_to_tasks},
+ sh_does_not_miss_messages].
groups() ->
[{args_to_tasks, [], [empty_arglist,
@@ -118,3 +120,14 @@ special_task_do(_Config) ->
"do",
"bar,",
"baz"]).
+sh_does_not_miss_messages(_Config) ->
+ Source = "~nmain(_) ->~n io:format(\"donotmissme\").~n",
+ file:write_file("do_not_miss_messages", io_lib:format(Source,[])),
+ {ok, "donotmissme"} = rebar_utils:sh("escript do_not_miss_messages", []),
+ AnyMessageRemained =
+ receive
+ What -> What
+ after 100 ->
+ false
+ end,
+ AnyMessageRemained = false.