Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

194 lignes
7.3 KiB

il y a 15 ans
il y a 15 ans
il y a 13 ans
il y a 15 ans
il y a 15 ans
il y a 13 ans
il y a 15 ans
il y a 15 ans
il y a 13 ans
il y a 14 ans
il y a 14 ans
il y a 14 ans
  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. write_file_if_contents_differ/2]).
  33. -include("rebar.hrl").
  34. %% ===================================================================
  35. %% Public API
  36. %% ===================================================================
  37. %% @doc Remove files and directories.
  38. %% Target is a single filename, directoryname or wildcard expression.
  39. -spec rm_rf(string()) -> 'ok'.
  40. rm_rf(Target) ->
  41. case os:type() of
  42. {unix, _} ->
  43. EscTarget = escape_spaces(Target),
  44. {ok, []} = rebar_utils:sh(?FMT("rm -rf ~s", [EscTarget]),
  45. [{use_stdout, false}, abort_on_error]),
  46. ok;
  47. {win32, _} ->
  48. Filelist = filelib:wildcard(Target),
  49. Dirs = [F || F <- Filelist, filelib:is_dir(F)],
  50. Files = Filelist -- Dirs,
  51. ok = delete_each(Files),
  52. ok = delete_each_dir_win32(Dirs),
  53. ok
  54. end.
  55. -spec cp_r(list(string()), file:filename()) -> 'ok'.
  56. cp_r([], _Dest) ->
  57. ok;
  58. cp_r(Sources, Dest) ->
  59. case os:type() of
  60. {unix, _} ->
  61. EscSources = [escape_spaces(Src) || Src <- Sources],
  62. SourceStr = string:join(EscSources, " "),
  63. {ok, []} = rebar_utils:sh(?FMT("cp -R ~s \"~s\"",
  64. [SourceStr, Dest]),
  65. [{use_stdout, false}, abort_on_error]),
  66. ok;
  67. {win32, _} ->
  68. lists:foreach(fun(Src) -> ok = cp_r_win32(Src,Dest) end, Sources),
  69. ok
  70. end.
  71. -spec mv(string(), file:filename()) -> 'ok'.
  72. mv(Source, Dest) ->
  73. case os:type() of
  74. {unix, _} ->
  75. EscSource = escape_spaces(Source),
  76. EscDest = escape_spaces(Dest),
  77. {ok, []} = rebar_utils:sh(?FMT("mv ~s ~s", [EscSource, EscDest]),
  78. [{use_stdout, false}, abort_on_error]),
  79. ok;
  80. {win32, _} ->
  81. {ok, R} = rebar_utils:sh(
  82. ?FMT("move /y \"~s\" \"~s\" 1> nul",
  83. [filename:nativename(Source),
  84. filename:nativename(Dest)]),
  85. [{use_stdout, false}, return_on_error]),
  86. case R of
  87. [] ->
  88. ok;
  89. _ ->
  90. {error, lists:flatten(
  91. io_lib:format("Failed to move ~s to ~s~n",
  92. [Source, Dest]))}
  93. end
  94. end.
  95. delete_each([]) ->
  96. ok;
  97. delete_each([File | Rest]) ->
  98. case file:delete(File) of
  99. ok ->
  100. delete_each(Rest);
  101. {error, enoent} ->
  102. delete_each(Rest);
  103. {error, Reason} ->
  104. ?ERROR("Failed to delete file ~s: ~p\n", [File, Reason]),
  105. ?FAIL
  106. end.
  107. write_file_if_contents_differ(Filename, Bytes) ->
  108. ToWrite = iolist_to_binary(Bytes),
  109. case file:read_file(Filename) of
  110. {ok, ToWrite} ->
  111. ok;
  112. {ok, _} ->
  113. file:write_file(Filename, ToWrite);
  114. {error, _} ->
  115. file:write_file(Filename, ToWrite)
  116. end.
  117. %% ===================================================================
  118. %% Internal functions
  119. %% ===================================================================
  120. delete_each_dir_win32([]) -> ok;
  121. delete_each_dir_win32([Dir | Rest]) ->
  122. {ok, []} = rebar_utils:sh(?FMT("rd /q /s \"~s\"",
  123. [filename:nativename(Dir)]),
  124. [{use_stdout, false}, return_on_error]),
  125. delete_each_dir_win32(Rest).
  126. xcopy_win32(Source,Dest)->
  127. {ok, R} = rebar_utils:sh(
  128. ?FMT("xcopy \"~s\" \"~s\" /q /y /e 2> nul",
  129. [filename:nativename(Source), filename:nativename(Dest)]),
  130. [{use_stdout, false}, return_on_error]),
  131. case length(R) > 0 of
  132. %% when xcopy fails, stdout is empty and and error message is printed
  133. %% to stderr (which is redirected to nul)
  134. true -> ok;
  135. false ->
  136. {error, lists:flatten(
  137. io_lib:format("Failed to xcopy from ~s to ~s~n",
  138. [Source, Dest]))}
  139. end.
  140. cp_r_win32({true, SourceDir}, {true, DestDir}) ->
  141. %% from directory to directory
  142. SourceBase = filename:basename(SourceDir),
  143. ok = case file:make_dir(filename:join(DestDir, SourceBase)) of
  144. {error, eexist} -> ok;
  145. Other -> Other
  146. end,
  147. ok = xcopy_win32(SourceDir, filename:join(DestDir, SourceBase));
  148. cp_r_win32({false, Source} = S,{true, DestDir}) ->
  149. %% from file to directory
  150. cp_r_win32(S, {false, filename:join(DestDir, filename:basename(Source))});
  151. cp_r_win32({false, Source},{false, Dest}) ->
  152. %% from file to file
  153. {ok,_} = file:copy(Source, Dest),
  154. ok;
  155. cp_r_win32({true, SourceDir}, {false, DestDir}) ->
  156. case filelib:is_regular(DestDir) of
  157. true ->
  158. %% From directory to file? This shouldn't happen
  159. {error, lists:flatten(
  160. io_lib:format("Cannot copy dir (~p) to file (~p)\n",
  161. [SourceDir, DestDir]))};
  162. false ->
  163. %% Specifying a target directory that doesn't currently exist.
  164. %% So let's attempt to create this directory
  165. case filelib:ensure_dir(filename:join(DestDir, "dummy")) of
  166. ok ->
  167. ok = xcopy_win32(SourceDir, DestDir);
  168. {error, Reason} ->
  169. {error, lists:flatten(
  170. io_lib:format("Unable to create dir ~p: ~p\n",
  171. [DestDir, Reason]))}
  172. end
  173. end;
  174. cp_r_win32(Source,Dest) ->
  175. Dst = {filelib:is_dir(Dest), Dest},
  176. lists:foreach(fun(Src) ->
  177. ok = cp_r_win32({filelib:is_dir(Src), Src}, Dst)
  178. end, filelib:wildcard(Source)),
  179. ok.
  180. escape_spaces(Str) ->
  181. re:replace(Str, " ", "\\\\ ", [global, {return, list}]).