diff options
-rw-r--r-- | src/rebar_agent.erl | 6 | ||||
-rw-r--r-- | src/rebar_dir.erl | 6 | ||||
-rw-r--r-- | src/rebar_file_utils.erl | 90 | ||||
-rw-r--r-- | src/rebar_git_resource.erl | 2 | ||||
-rw-r--r-- | src/rebar_prv_common_test.erl | 41 | ||||
-rw-r--r-- | src/rebar_prv_dialyzer.erl | 10 | ||||
-rw-r--r-- | src/rebar_utils.erl | 14 | ||||
-rw-r--r-- | test/rebar_compile_SUITE.erl | 8 | ||||
-rw-r--r-- | test/rebar_hooks_SUITE.erl | 2 | ||||
-rw-r--r-- | test/rebar_test_utils.erl | 10 | ||||
-rw-r--r-- | test/rebar_utils_SUITE.erl | 17 |
11 files changed, 148 insertions, 58 deletions
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. |