summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam H <unknown>2017-08-10 10:05:01 -0400
committerFred Hebert <mononcqc@ferd.ca>2017-08-10 10:05:01 -0400
commit0588936de12fe5b1607c6a23e300904e8f0fc6c0 (patch)
tree54104838166e90a5f5b967696355ef21528316eb
parent2939110eb85bed0dd494bf0ddeb4c07f5e46bfc7 (diff)
Support Windows with non-NTFS filesystems
The code for symlink handling failed whenever a win32 platform with no symlink capability would be detected. This patch is provided by William H from the support ticket at http://www.rebar3.org/v3/discuss/598225c90365bb00144bc07f, which adds detection of failures in non-NTFS scenarios on Win32, and then copies files instead of bailing out. The end result should be appropriate support for such a platform.
-rw-r--r--src/rebar_file_utils.erl42
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.