aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTristan Sloughter <[email protected]>2019-04-18 07:53:34 -0600
committerGitHub <[email protected]>2019-04-18 07:53:34 -0600
commitead9e974a88344154506be95285cd98f64d7ff0f (patch)
tree0ff017728bcb312551e8b9d6c784886fa366cfab
parent8ff1e44cebf3aee09969a9324c04074ba87f10b9 (diff)
parent476b439de0077b6f7a60622d2498b85e6f52698a (diff)
downloadrelx-ead9e974a88344154506be95285cd98f64d7ff0f.tar.gz
relx-ead9e974a88344154506be95285cd98f64d7ff0f.tar.bz2
relx-ead9e974a88344154506be95285cd98f64d7ff0f.zip
Merge pull request #714 from tolbrino/tb-fix-windows-links
Fix link handling on Windows
-rw-r--r--src/rlx_util.erl120
1 files changed, 53 insertions, 67 deletions
diff --git a/src/rlx_util.erl b/src/rlx_util.erl
index b3fc2b7..5d3744d 100644
--- a/src/rlx_util.erl
+++ b/src/rlx_util.erl
@@ -45,6 +45,8 @@
-define(DFLT_INTENSITY, high).
-define(ONE_LEVEL_INDENT, " ").
+
+-include_lib("kernel/include/file.hrl").
%%============================================================================
%% types
%%============================================================================
@@ -233,81 +235,65 @@ symlink_or_copy(Source, Target) ->
ok;
{error, eexist} ->
{error, eexist};
- {error, _} ->
- case os:type() of
- {win32, _} ->
- S = unicode:characters_to_list(Source),
- T = unicode:characters_to_list(Target),
- win32_symlink(filename:nativename(S), filename:nativename(T));
+ {error, Err} ->
+ case {os:type(), Err} of
+ {{win32, _}, eperm} ->
+ % We get eperm on Windows if we do not have
+ % SeCreateSymbolicLinkPrivilege
+ % Try the next alternative
+ win32_make_junction_or_copy(Source, Target);
_ ->
- case filelib:is_dir(Target) of
- true -> ok;
- false ->
- cp_r([Source], Target)
- end
+ % On other systems we try to copy next
+ cp_r(Source, Target)
end
end.
+cp_r(Source, Target) ->
+ ec_file:copy(Source, Target, [{recursive, true}, {fileinfo, [mode, time, owner, group]}]).
-win32_symlink(Source, Target) ->
- os:cmd("cmd /c mklink /j " ++ Target ++ " " ++ Source),
- ok.
-
--spec cp_r(list(string()), file:filename()) -> 'ok'.
-cp_r(Sources, Dest) ->
- case os:type() of
- {unix, _} ->
- ok;
- {win32, _} ->
- lists:foreach(fun(Src) -> ok = cp_r_win32(Src,Dest) end, Sources),
- ok
+win32_make_junction_or_copy(Source, Target) ->
+ case filelib:is_dir(Source) of
+ true ->
+ win32_make_junction(Source, Target);
+ _ ->
+ cp_r(Source, Target)
end.
-xcopy_win32(Source,Dest)->
- %% "xcopy \"~s\" \"~s\" /q /y /e 2> nul", Chanegd to robocopy to
- %% handle long names. May have issues with older windows.
- os:cmd("robocopy " ++ Source ++ " " ++ Dest ++ " /e /is"),
- ok.
-
-cp_r_win32({true, SourceDir}, {true, DestDir}) ->
- %% from directory to directory
- ok = case file:make_dir(DestDir) of
- {error, eexist} -> ok;
- Other -> Other
- end,
- 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))});
-cp_r_win32({false, Source},{false, Dest}) ->
- %% from file to file
- {ok,_} = file:copy(Source, Dest),
- ok;
-cp_r_win32({true, SourceDir}, {false, DestDir}) ->
- case filelib:is_regular(DestDir) of
- true ->
- %% From directory to file? This shouldn't happen
- {error, lists:flatten(
- io_lib:format("Cannot copy dir (~p) to file (~p)\n",
- [SourceDir, DestDir]))};
- false ->
- %% Specifying a target directory that doesn't currently exist.
- %% So let's attempt to create this directory
- case filelib:ensure_dir(filename:join(DestDir, "dummy")) of
- ok ->
- ok = xcopy_win32(SourceDir, DestDir);
+win32_make_junction(Source, Target) ->
+ % The mklink will fail if the target already exists, check for that first
+ case file:read_link_info(Target) of
+ {error, enoent} ->
+ win32_make_junction_cmd(Source, Target);
+ {ok, #file_info{type = symlink}} ->
+ case file:read_link(Target) of
+ {ok, Source} ->
+ ok;
+ {ok, _} ->
+ ok = file:del_dir(Target),
+ win32_make_junction_cmd(Source, Target);
{error, Reason} ->
- {error, lists:flatten(
- io_lib:format("Unable to create dir ~p: ~p\n",
- [DestDir, Reason]))}
- end
- end;
-cp_r_win32(Source,Dest) ->
- Dst = {filelib:is_dir(Dest), Dest},
- lists:foreach(fun(Src) ->
- ok = cp_r_win32({filelib:is_dir(Src), Src}, Dst)
- end, filelib:wildcard(Source)),
- ok.
+ {error, {readlink, Reason}}
+ end;
+ {ok, #file_info{type = _Type}} ->
+ % Directory already exists, so we overwrite the copy
+ cp_r(Source, Target);
+ Error ->
+ Error
+ end.
+
+win32_make_junction_cmd(Source, Target) ->
+ S = unicode:characters_to_list(Source),
+ T = unicode:characters_to_list(Target),
+ Cmd = "cmd /c mklink /j " ++ filename:nativename(T) ++ " " ++ filename:nativename(S),
+ case os:cmd(Cmd) of
+ "Junction created " ++ _ ->
+ ok;
+ [] ->
+ % When mklink fails it prints the error message to stderr which
+ % is not picked up by os:cmd() hence this case switch is for
+ % an empty message
+ cp_r(Source, Target)
+ end.
%% @doc Returns the color intensity, we first check the application envorinment
%% if that is not set we check the environment variable RELX_COLOR.