diff options
| author | William H <unknown> | 2017-08-10 10:05:01 -0400 | 
|---|---|---|
| committer | Fred Hebert <mononcqc@ferd.ca> | 2017-08-10 10:05:01 -0400 | 
| commit | 0588936de12fe5b1607c6a23e300904e8f0fc6c0 (patch) | |
| tree | 54104838166e90a5f5b967696355ef21528316eb /src | |
| parent | 2939110eb85bed0dd494bf0ddeb4c07f5e46bfc7 (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.
Diffstat (limited to 'src')
| -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. | 
