diff options
Diffstat (limited to 'src')
-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 | 29 | ||||
-rw-r--r-- | src/rebar_prv_dialyzer.erl | 10 | ||||
-rw-r--r-- | src/rebar_utils.erl | 14 |
7 files changed, 112 insertions, 45 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 aab76b4..2b024cf 100644 --- a/src/rebar_prv_common_test.erl +++ b/src/rebar_prv_common_test.erl @@ -347,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) -> |