Sfoglia il codice sorgente

utility method for conditional creation of symlinks or missing app dirs

symlink_or_create_appsubdirs
alisdair sullivan 8 anni fa
parent
commit
152c112108
2 ha cambiato i file con 159 aggiunte e 17 eliminazioni
  1. +68
    -15
      src/rebar_file_utils.erl
  2. +91
    -2
      test/rebar_file_utils_SUITE.erl

+ 68
- 15
src/rebar_file_utils.erl Vedi File

@ -29,6 +29,8 @@
-export([try_consult/1,
consult_config/2,
format_error/1,
symlink_or_create/2,
symlink/2,
symlink_or_copy/2,
rm_rf/1,
cp_r/2,
@ -86,6 +88,36 @@ consult_config(State, Filename) ->
format_error({bad_term_file, AppFile, Reason}) ->
io_lib:format("Error reading file ~s: ~s", [AppFile, file:format_error(Reason)]).
-spec symlink_or_create(Source, Target) -> Result when
Source :: file:filename(),
Target :: file:filename(),
Result :: Ok | Error,
Ok :: ok,
Error :: {error, string()}.
symlink_or_create(Source, Target) ->
SourceExists = ec_file:is_dir(Source) orelse ec_file:is_symlink(Source),
case SourceExists of
true -> force_link(Source, Target);
false -> force_shadow_dir(Target)
end.
-spec symlink(Source, Target) -> Result when
Source :: file:filename(),
Target :: file:filename(),
Result :: Ok | Error,
Ok :: ok,
Error :: {error, string()}.
symlink(Source, Target) ->
case os:type() of
{win32, _} ->
S = unicode:characters_to_list(Source),
T = unicode:characters_to_list(Target),
win32_symlink(S, T);
_ ->
file:make_symlink(Source, Target)
end.
symlink_or_copy(Source, Target) ->
Link = case os:type() of
{win32, _} ->
@ -119,21 +151,6 @@ symlink_or_copy(Source, Target) ->
end
end.
win32_symlink(Source, Target) ->
Res = rebar_utils:sh(
?FMT("cmd /c mklink /j \"~s\" \"~s\"",
[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
true -> ok;
false ->
{error, lists:flatten(
io_lib:format("Failed to symlink ~s to ~s~n",
[Source, Target]))}
end.
%% @doc Remove files and directories.
%% Target is a single filename, directoryname or wildcard expression.
-spec rm_rf(string()) -> 'ok'.
@ -475,3 +492,39 @@ cp_r_win32(Source,Dest) ->
ok = cp_r_win32({filelib:is_dir(Src), Src}, Dst)
end, filelib:wildcard(Source)),
ok.
win32_symlink(Source, Target) ->
Res = rebar_utils:sh(
?FMT("cmd /c mklink /j \"~s\" \"~s\"",
[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
true -> ok;
false ->
{error, lists:flatten(
io_lib:format("Failed to symlink ~s to ~s~n",
[Source, Target]))}
end.
force_link(Source, Target) ->
%% remove any existing dir
ok = case ec_file:is_dir(Target) of
true -> ec_file:remove(Target, [recursive]);
false -> ok
end,
symlink(Source, Target).
force_shadow_dir(Target) ->
%% remove any existing symlink
ok = case ec_file:is_symlink(Target) of
true -> ec_file:remove(Target);
false -> ok
end,
%% if a directory already exists leave it unaltered, otherwise
%% create it
case ec_file:is_dir(Target) of
true -> ok;
false -> filelib:ensure_dir(filename:join([Target, "dummy"]))
end.

+ 91
- 2
test/rebar_file_utils_SUITE.erl Vedi File

@ -23,7 +23,11 @@
mv_file_diff/1,
mv_file_dir_same/1,
mv_file_dir_diff/1,
mv_no_clobber/1]).
mv_no_clobber/1,
symlink_existing_dir/1,
create_missing_dir/1,
delete_symlink_and_create_dir/1,
delete_dir_and_create_symlink/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@ -38,7 +42,11 @@ all() ->
canonical_path,
resolve_link,
split_dirname,
mv_warning_is_ignored].
mv_warning_is_ignored,
symlink_existing_dir,
create_missing_dir,
delete_symlink_and_create_dir,
delete_dir_and_create_symlink].
groups() ->
[{tmpdir, [], [raw_tmpdir, empty_tmpdir, simple_tmpdir, multi_tmpdir]},
@ -329,3 +337,84 @@ mk_base_dir(BasePath, Name) ->
Path = filename:join(BasePath, atom_to_list(Name) ++ Index),
ec_file:mkdir_p(Path),
Path.
symlink_existing_dir(Config) ->
PrivDir = ?config(priv_dir, Config),
Source = filename:join([PrivDir, "exists"]),
Target = filename:join([PrivDir, "_build", "exists"]),
ok = filelib:ensure_dir(filename:join([PrivDir, "_build", "dummy"])),
ok = filelib:ensure_dir(filename:join([Source, "dummy"])),
ok = rebar_file_utils:symlink_or_create(Source, Target),
%% `Target' should be a symlink not a directory, and `Source'
%% should exist
?assert(ec_file:is_symlink(Target)),
?assert(ec_file:is_dir(Source)).
create_missing_dir(Config) ->
PrivDir = ?config(priv_dir, Config),
Source = filename:join([PrivDir, "missing"]),
Target = filename:join([PrivDir, "_build", "missing"]),
ok = filelib:ensure_dir(filename:join([PrivDir, "_build", "dummy"])),
ok = rebar_file_utils:symlink_or_create(Source, Target),
%% `Target' should be a directory not a symlink, and `Source'
%% should not exist
?assert(ec_file:is_dir(Target)),
?assert(not ec_file:is_symlink(Target)),
?assert(not ec_file:is_dir(Source)).
delete_symlink_and_create_dir(Config) ->
PrivDir = ?config(priv_dir, Config),
Source = filename:join([PrivDir, "gone"]),
Target = filename:join([PrivDir, "_build", "gone"]),
ok = filelib:ensure_dir(filename:join([PrivDir, "_build", "dummy"])),
%% create dir temporarily to ensure symlink can be created
ok = filelib:ensure_dir(filename:join([Source, "dummy"])),
?assert(ec_file:is_dir(Source)),
ok = rebar_file_utils:symlink(Source, Target),
%% remove source dir
ok = ec_file:remove(Source, [recursive]),
?assert(ec_file:is_symlink(Target)),
?assert(not ec_file:is_dir(Source)),
ok = rebar_file_utils:symlink_or_create(Source, Target),
%% `Target' should be a directory not a symlink, and `Source'
%% should not exist
?assert(not ec_file:is_symlink(Target)),
?assert(ec_file:is_dir(Target)),
?assert(not ec_file:is_dir(Source)).
delete_dir_and_create_symlink(Config) ->
PrivDir = ?config(priv_dir, Config),
Source = filename:join([PrivDir, "created"]),
Target = filename:join([PrivDir, "_build", "created"]),
ok = filelib:ensure_dir(filename:join([PrivDir, "_build", "dummy"])),
ok = filelib:ensure_dir(filename:join([Source, "dummy"])),
ok = filelib:ensure_dir(filename:join([Target, "dummy"])),
?assert(not ec_file:is_symlink(Target)),
?assert(ec_file:is_dir(Target)),
?assert(ec_file:is_dir(Source)),
ok = rebar_file_utils:symlink_or_create(Source, Target),
%% `Target' should be a symlink not a directory, and `Source'
%% should exist
?assert(ec_file:is_symlink(Target)),
?assert(ec_file:is_dir(Source)).

Caricamento…
Annulla
Salva