diff options
-rw-r--r-- | src/rebar_file_utils.erl | 42 |
1 files changed, 35 insertions, 7 deletions
diff --git a/src/rebar_file_utils.erl b/src/rebar_file_utils.erl index d7716e5..c860513 100644 --- a/src/rebar_file_utils.erl +++ b/src/rebar_file_utils.erl @@ -105,7 +105,7 @@ symlink_or_copy(Source, Target) -> T = unicode:characters_to_list(Target), case filelib:is_dir(S) of true -> - win32_symlink(S, T); + win32_symlink_or_copy(S, T); false -> cp_r([S], T) end; @@ -119,20 +119,48 @@ symlink_or_copy(Source, Target) -> end end. -win32_symlink(Source, Target) -> +%% @private Compatibility function for windows +win32_symlink_or_copy(Source, Target) -> Res = rebar_utils:sh( ?FMT("cmd /c mklink /j \"~ts\" \"~ts\"", [rebar_utils:escape_double_quotes(filename:nativename(Target)), rebar_utils:escape_double_quotes(filename:nativename(Source))]), [{use_stdout, false}, return_on_error]), - case win32_ok(Res) of + case win32_mklink_ok(Res, Target) of true -> ok; - false -> - {error, lists:flatten( - io_lib:format("Failed to symlink ~ts to ~ts~n", - [Source, Target]))} + false -> cp_r_win32(Source, drop_last_dir_from_path(Target)) end. +%% @private specifically pattern match against the output +%% of the windows 'mklink' shell call; different values from +%% what win32_ok/1 handles +win32_mklink_ok({ok, _}, _) -> + true; +win32_mklink_ok({error,{1,"Local NTFS volumes are required to complete the operation.\n"}}, _) -> + false; +win32_mklink_ok({error,{1,"Cannot create a file when that file already exists.\n"}}, Target) -> + % File or dir is already in place; find if it is already a symlink (true) or + % if it is a directory (copy-required; false) + is_symlink(Target); +win32_mklink_ok(_, _) -> + false. + +%% @private +is_symlink(Filename) -> + {ok, Info} = file:read_link_info(Filename), + Info#file_info.type == symlink. + +%% @private +%% drops the last 'node' of the filename, presumably the last dir such as 'src' +%% this is because cp_r_win32/2 automatically adds the dir name, to appease +%% robocopy and be more uniform with POSIX +drop_last_dir_from_path([]) -> + []; +drop_last_dir_from_path(Path) -> + case lists:droplast(filename:split(Path)) of + [] -> []; + Dirs -> filename:join(Dirs) + end. %% @doc Remove files and directories. %% Target is a single filename, directoryname or wildcard expression. |