diff --git a/src/rebar_file_utils.erl b/src/rebar_file_utils.erl index 89c6d931..9eaf8023 100644 --- a/src/rebar_file_utils.erl +++ b/src/rebar_file_utils.erl @@ -29,7 +29,7 @@ -export([try_consult/1, consult_config/2, format_error/1, - symlink_or_create/2, + symlink_or_create_dir/2, symlink/2, symlink_or_copy/2, rm_rf/1, @@ -88,13 +88,13 @@ 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 +-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(Source, Target) -> +symlink_or_create_dir(Source, Target) -> SourceExists = ec_file:is_dir(Source) orelse ec_file:is_symlink(Source), case SourceExists of @@ -509,11 +509,15 @@ win32_symlink(Source, Target) -> force_link(Source, Target) -> %% remove any existing dir - ok = case ec_file:is_dir(Target) of + 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(Source, Target). + %% symlink only if not already symlinked + ok = case ec_file:is_symlink(Target) of + true -> ok; + false -> symlink(Source, Target) + end. force_shadow_dir(Target) -> %% remove any existing symlink diff --git a/test/rebar_file_utils_SUITE.erl b/test/rebar_file_utils_SUITE.erl index f8825d69..f38adf4a 100644 --- a/test/rebar_file_utils_SUITE.erl +++ b/test/rebar_file_utils_SUITE.erl @@ -25,7 +25,9 @@ mv_file_dir_diff/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]). @@ -44,7 +46,9 @@ all() -> split_dirname, 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]. @@ -343,15 +347,35 @@ 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"])), + 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(Source, Target), + ok = rebar_file_utils:symlink_or_create_dir(Source, Target), - %% `Target' should be a symlink not a directory, and `Source' + %% `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)). @@ -359,10 +383,10 @@ 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"])), + 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(Source, Target), + ok = rebar_file_utils:symlink_or_create_dir(Source, Target), %% `Target' should be a directory not a symlink, and `Source' %% should not exist @@ -370,18 +394,33 @@ create_missing_dir(Config) -> ?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)). + 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"])), + 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"])), - ?assert(ec_file:is_dir(Source)), - ok = rebar_file_utils:symlink(Source, Target), %% remove source dir @@ -390,7 +429,7 @@ delete_symlink_and_create_dir(Config) -> ?assert(ec_file:is_symlink(Target)), ?assert(not ec_file:is_dir(Source)), - ok = rebar_file_utils:symlink_or_create(Source, Target), + ok = rebar_file_utils:symlink_or_create_dir(Source, Target), %% `Target' should be a directory not a symlink, and `Source' %% should not exist @@ -401,9 +440,9 @@ delete_symlink_and_create_dir(Config) -> 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"])), + 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"])), @@ -412,9 +451,10 @@ delete_dir_and_create_symlink(Config) -> ?assert(ec_file:is_dir(Target)), ?assert(ec_file:is_dir(Source)), - ok = rebar_file_utils:symlink_or_create(Source, Target), + 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)). \ No newline at end of file