Compare commits

...

3개의 변경된 파일282개의 추가작업 그리고 20개의 파일을 삭제
분할 보기
  1. +87
    -15
      src/rebar_file_utils.erl
  2. +10
    -3
      src/rebar_prv_compile.erl
  3. +185
    -2
      test/rebar_file_utils_SUITE.erl

+ 87
- 15
src/rebar_file_utils.erl 파일 보기

@ -29,6 +29,8 @@
-export([try_consult/1,
consult_config/2,
format_error/1,
symlink_or_create_dir/2,
symlink/2,
symlink_or_copy/2,
rm_rf/1,
cp_r/2,
@ -86,6 +88,32 @@ 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_dir(Source, Target) -> Result when
Source :: file:filename(),
Target :: file:filename(),
Result :: Ok | Error,
Ok :: ok,
Error :: {error, string()}.
symlink_or_create_dir(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) ->
SourceExists = ec_file:is_dir(Source) orelse ec_file:is_symlink(Source),
case SourceExists of
true -> force_link(Source, Target);
false -> ok
end.
symlink_or_copy(Source, Target) ->
Link = case os:type() of
{win32, _} ->
@ -119,21 +147,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 +488,62 @@ cp_r_win32(Source,Dest) ->
ok = cp_r_win32({filelib:is_dir(Src), Src}, Dst)
end, filelib:wildcard(Source)),
ok.
force_link(Source, Target) ->
%% remove any existing dir
ok = case ec_file:is_dir(Target) andalso not ec_file:is_symlink(Target) of
true -> ec_file:remove(Target, [recursive]);
false -> ok
end,
%% symlink only if not already symlinked
ok = case ec_file:is_symlink(Target) of
true -> ok;
false -> do_symlink(Source, Target)
end.
force_shadow_dir(Target) ->
%% remove any existing symlink
case ec_file:is_symlink(Target) of
true -> rm_symlink(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.
do_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.
rm_symlink(Target) ->
%% on windows a symlink to a dir can only be deleted via a directory
%% delete. since we are mostly likely calling this function in the case
%% where the target of the symlink has been removed the only way to
%% detect this is via the `eperm` error
case ec_file:remove(Target) of
{error, eperm} -> file:del_dir(Target);
ok -> ok
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.

+ 10
- 3
src/rebar_prv_compile.erl 파일 보기

@ -195,13 +195,15 @@ copy_app_dirs(AppInfo, OldAppDir, AppDir) ->
%% If mibs exist it means we must ensure priv exists.
%% mibs files are compiled to priv/mibs/
filelib:ensure_dir(filename:join([OldAppDir, "priv", "dummy"])),
symlink_or_copy(OldAppDir, AppDir, "mibs");
symlink_or_create(OldAppDir, AppDir, "mibs");
false ->
ok
end,
{SrcDirs, ExtraDirs} = resolve_src_dirs(rebar_app_info:opts(AppInfo)),
%% some tools depend on 'priv' and/or 'include' existing
[symlink_or_create(OldAppDir, AppDir, Dir) || Dir <- ["priv", "include"]],
%% link to src_dirs to be adjacent to ebin is needed for R15 use of cover/xref
[symlink_or_copy(OldAppDir, AppDir, Dir) || Dir <- ["priv", "include"] ++ SrcDirs],
[symlink(OldAppDir, AppDir, Dir) || Dir <- SrcDirs],
%% copy all extra_src_dirs as they build into themselves and linking means they
%% are shared across profiles
[copy(OldAppDir, AppDir, Dir) || Dir <- ExtraDirs];
@ -209,11 +211,16 @@ copy_app_dirs(AppInfo, OldAppDir, AppDir) ->
ok
end.
symlink_or_copy(OldAppDir, AppDir, Dir) ->
symlink_or_create(OldAppDir, AppDir, Dir) ->
Source = filename:join([OldAppDir, Dir]),
Target = filename:join([AppDir, Dir]),
rebar_file_utils:symlink_or_copy(Source, Target).
symlink(OldAppDir, AppDir, Dir) ->
Source = filename:join([OldAppDir, Dir]),
Target = filename:join([AppDir, Dir]),
rebar_file_utils:symlink(Source, Target).
copy(OldAppDir, AppDir, Dir) ->
Source = filename:join([OldAppDir, Dir]),
Target = filename:join([AppDir, Dir]),

+ 185
- 2
test/rebar_file_utils_SUITE.erl 파일 보기

@ -23,7 +23,13 @@
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,
preserve_existing_symlink/1,
create_missing_dir/1,
preserve_existing_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 +44,13 @@ all() ->
canonical_path,
resolve_link,
split_dirname,
mv_warning_is_ignored].
mv_warning_is_ignored,
symlink_existing_dir,
preserve_existing_symlink,
create_missing_dir,
preserve_existing_dir,
delete_symlink_and_create_dir,
delete_dir_and_create_symlink].
groups() ->
[{tmpdir, [], [raw_tmpdir, empty_tmpdir, simple_tmpdir, multi_tmpdir]},
@ -329,3 +341,174 @@ 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", "test", "lib", "app", "exists"]),
ok = filelib:ensure_dir(filename:join([PrivDir, "_build", "test", "lib", "app", "dummy"])),
ok = filelib:ensure_dir(filename:join([Source, "dummy"])),
ok = rebar_file_utils:symlink_or_create_dir(Source, Target),
%% `Target' should be a symlink, and `Source'
%% should exist
?assert(ec_file:is_dir(Target)),
?assert(ec_file:is_symlink(Target)),
?assert(ec_file:is_dir(Source)),
%% repeat to check for idempotence
ok = rebar_file_utils:symlink_or_create_dir(Source, Target),
%% `Target' should be a symlink, and `Source'
%% should exist
?assert(ec_file:is_dir(Target)),
?assert(ec_file:is_symlink(Target)),
?assert(ec_file:is_dir(Source)).
preserve_existing_symlink(Config) ->
PrivDir = ?config(priv_dir, Config),
Source = filename:join([PrivDir, "symlinked"]),
Target = filename:join([PrivDir, "_build", "test", "lib", "app", "symlinked"]),
ok = filelib:ensure_dir(filename:join([PrivDir, "_build", "test", "lib", "app", "dummy"])),
ok = filelib:ensure_dir(filename:join([Source, "dummy"])),
ok = rebar_file_utils:symlink(Source, Target),
ok = rebar_file_utils:symlink_or_create_dir(Source, Target),
%% `Target' should be a symlink, and `Source'
%% should exist
?assert(ec_file:is_dir(Target)),
?assert(ec_file:is_symlink(Target)),
?assert(ec_file:is_dir(Source)),
%% repeat to check for idempotence
ok = rebar_file_utils:symlink_or_create_dir(Source, Target),
%% `Target' should be a symlink, and `Source'
%% should exist
?assert(ec_file:is_dir(Target)),
?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", "test", "lib", "app", "missing"]),
ok = filelib:ensure_dir(filename:join([PrivDir, "_build", "test", "lib", "app", "dummy"])),
ok = rebar_file_utils:symlink_or_create_dir(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)),
%% repeat to check for idempotence
ok = rebar_file_utils:symlink_or_create_dir(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)).
preserve_existing_dir(Config) ->
PrivDir = ?config(priv_dir, Config),
Source = filename:join([PrivDir, "created"]),
Target = filename:join([PrivDir, "_build", "test", "lib", "app", "created"]),
ok = filelib:ensure_dir(filename:join([PrivDir, "_build", "test", "lib", "app", "dummy"])),
ok = filelib:ensure_dir(filename:join([Target, "dummy"])),
ok = rebar_file_utils:symlink_or_create_dir(Source, Target),
%% `Target' should be a directory, 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)),
%% repeat to check for idempotence
ok = rebar_file_utils:symlink_or_create_dir(Source, Target),
%% `Target' should be a directory, 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", "test", "lib", "app", "gone"]),
ok = filelib:ensure_dir(filename:join([PrivDir, "_build", "test", "lib", "app", "dummy"])),
%% create dir temporarily to ensure symlink can be created
ok = filelib:ensure_dir(filename:join([Source, "dummy"])),
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_dir(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)),
%% repeat to check for idempotence
ok = rebar_file_utils:symlink_or_create_dir(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, "create"]),
Target = filename:join([PrivDir, "_build", "test", "lib", "app", "create"]),
ok = filelib:ensure_dir(filename:join([PrivDir, "_build", "test", "lib", "app", "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_dir(Source, Target),
%% `Target' should be a symlink not a directory, and `Source'
%% should exist
?assert(ec_file:is_dir(Target)),
?assert(ec_file:is_symlink(Target)),
?assert(ec_file:is_dir(Source)),
%% repeat to check for idempotence
ok = rebar_file_utils:symlink_or_create_dir(Source, Target),
%% `Target' should be a symlink not a directory, and `Source'
%% should exist
?assert(ec_file:is_dir(Target)),
?assert(ec_file:is_symlink(Target)),
?assert(ec_file:is_dir(Source)).

불러오는 중...
취소
저장