選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

180 行
7.0 KiB

15年前
15年前
15年前
15年前
15年前
15年前
  1. %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% ex: ts=4 sw=4 et
  3. %% -------------------------------------------------------------------
  4. %%
  5. %% rebar: Erlang Build Tools
  6. %%
  7. %% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com)
  8. %%
  9. %% Permission is hereby granted, free of charge, to any person obtaining a copy
  10. %% of this software and associated documentation files (the "Software"), to deal
  11. %% in the Software without restriction, including without limitation the rights
  12. %% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. %% copies of the Software, and to permit persons to whom the Software is
  14. %% furnished to do so, subject to the following conditions:
  15. %%
  16. %% The above copyright notice and this permission notice shall be included in
  17. %% all copies or substantial portions of the Software.
  18. %%
  19. %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. %% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. %% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. %% THE SOFTWARE.
  26. %% -------------------------------------------------------------------
  27. -module(rebar_file_utils).
  28. -export([rm_rf/1,
  29. cp_r/2,
  30. mv/2,
  31. delete_each/1]).
  32. -include("rebar.hrl").
  33. %% ===================================================================
  34. %% Public API
  35. %% ===================================================================
  36. %% @doc Remove files and directories.
  37. %% Target is a single filename, directoryname or wildcard expression.
  38. -spec rm_rf(Target::string()) -> ok.
  39. rm_rf(Target) ->
  40. case os:type() of
  41. {unix, _} ->
  42. EscTarget = escape_spaces(Target),
  43. {ok, []} = rebar_utils:sh(?FMT("rm -rf ~s", [EscTarget]),
  44. [{use_stdout, false}, return_on_error]),
  45. ok;
  46. {win32, _} ->
  47. Filelist = filelib:wildcard(Target),
  48. Dirs = [F || F <- Filelist, filelib:is_dir(F)],
  49. Files = Filelist -- Dirs,
  50. ok = delete_each(Files),
  51. ok = delete_each_dir_win32(Dirs),
  52. ok
  53. end.
  54. -spec cp_r(Sources::list(string()), Dest::file:filename()) -> ok.
  55. cp_r(Sources, Dest) ->
  56. case os:type() of
  57. {unix, _} ->
  58. EscSources = [escape_spaces(Src) || Src <- Sources],
  59. SourceStr = string:join(EscSources, " "),
  60. {ok, []} = rebar_utils:sh(?FMT("cp -R ~s \"~s\"",
  61. [SourceStr, Dest]),
  62. [{use_stdout, false}, return_on_error]),
  63. ok;
  64. {win32, _} ->
  65. lists:foreach(fun(Src) -> ok = cp_r_win32(Src,Dest) end, Sources),
  66. ok
  67. end.
  68. -spec mv(Source::string(), Dest::file:filename()) -> ok.
  69. mv(Source, Dest) ->
  70. case os:type() of
  71. {unix, _} ->
  72. EscSource = escape_spaces(Source),
  73. EscDest = escape_spaces(Dest),
  74. {ok, []} = rebar_utils:sh(?FMT("mv ~s ~s", [EscSource, EscDest]),
  75. [{use_stdout, false}, return_on_error]),
  76. ok;
  77. {win32, _} ->
  78. {ok, R} = rebar_utils:sh(
  79. ?FMT("move /y \"~s\" \"~s\" 1> nul",
  80. [filename:nativename(Source),
  81. filename:nativename(Dest)]),
  82. [{use_stdout, false}, return_on_error]),
  83. case R of
  84. [] ->
  85. ok;
  86. _ ->
  87. {error, lists:flatten(
  88. io_lib:format("Failed to move ~s to ~s~n",
  89. [Source, Dest]))}
  90. end
  91. end.
  92. delete_each([]) ->
  93. ok;
  94. delete_each([File | Rest]) ->
  95. case file:delete(File) of
  96. ok ->
  97. delete_each(Rest);
  98. {error, enoent} ->
  99. delete_each(Rest);
  100. {error, Reason} ->
  101. ?ERROR("Failed to delete file ~s: ~p\n", [File, Reason]),
  102. ?FAIL
  103. end.
  104. %% ===================================================================
  105. %% Internal functions
  106. %% ===================================================================
  107. delete_each_dir_win32([]) -> ok;
  108. delete_each_dir_win32([Dir | Rest]) ->
  109. {ok, []} = rebar_utils:sh(?FMT("rd /q /s \"~s\"",
  110. [filename:nativename(Dir)]),
  111. [{use_stdout, false}, return_on_error]),
  112. delete_each_dir_win32(Rest).
  113. xcopy_win32(Source,Dest)->
  114. {ok, R} = rebar_utils:sh(
  115. ?FMT("xcopy \"~s\" \"~s\" /q /y /e 2> nul",
  116. [filename:nativename(Source), filename:nativename(Dest)]),
  117. [{use_stdout, false}, return_on_error]),
  118. case length(R) > 0 of
  119. %% when xcopy fails, stdout is empty and and error message is printed
  120. %% to stderr (which is redirected to nul)
  121. true -> ok;
  122. false ->
  123. {error, lists:flatten(
  124. io_lib:format("Failed to xcopy from ~s to ~s~n",
  125. [Source, Dest]))}
  126. end.
  127. cp_r_win32({true, SourceDir}, {true, DestDir}) ->
  128. %% from directory to directory
  129. SourceBase = filename:basename(SourceDir),
  130. ok = case file:make_dir(filename:join(DestDir, SourceBase)) of
  131. {error, eexist} -> ok;
  132. Other -> Other
  133. end,
  134. ok = xcopy_win32(SourceDir, filename:join(DestDir, SourceBase));
  135. cp_r_win32({false, Source} = S,{true, DestDir}) ->
  136. %% from file to directory
  137. cp_r_win32(S, {false, filename:join(DestDir, filename:basename(Source))});
  138. cp_r_win32({false, Source},{false, Dest}) ->
  139. %% from file to file
  140. {ok,_} = file:copy(Source, Dest),
  141. ok;
  142. cp_r_win32({true, SourceDir}, {false, DestDir}) ->
  143. case filelib:is_regular(DestDir) of
  144. true ->
  145. %% From directory to file? This shouldn't happen
  146. {error, lists:flatten(
  147. io_lib:format("Cannot copy dir (~p) to file (~p)\n",
  148. [SourceDir, DestDir]))};
  149. false ->
  150. %% Specifying a target directory that doesn't currently exist.
  151. %% So let's attempt to create this directory
  152. case filelib:ensure_dir(filename:join(DestDir, "dummy")) of
  153. ok ->
  154. ok = xcopy_win32(SourceDir, DestDir);
  155. {error, Reason} ->
  156. {error, lists:flatten(
  157. io_lib:format("Unable to create dir ~p: ~p\n",
  158. [DestDir, Reason]))}
  159. end
  160. end;
  161. cp_r_win32(Source,Dest) ->
  162. Dst = {filelib:is_dir(Dest), Dest},
  163. lists:foreach(fun(Src) ->
  164. ok = cp_r_win32({filelib:is_dir(Src), Src}, Dst)
  165. end, filelib:wildcard(Source)),
  166. ok.
  167. escape_spaces(Str) ->
  168. re:replace(Str, " ", "\\\\ ", [global, {return, list}]).