Commit e0228e2b authored by Brad King's avatar Brad King
Browse files

cmake: Improve '-E create_symlink' edge case handling (#14713)

The logic added by commit ffc0b5e4 (Overwrite the symlink if it already
exists, 2007-02-15) does not recognize and remove existing broken links
before replacing them.  Improve the logic to remove any existing
destination file or link (but not directory).  On failure, report an
error message explaining why the existing path could not be removed or
the new one could not be created.

Add a RunCMake.CommandLine test to cover 'cmake -E' cases.  Start with
test cases covering 'cmake -E create_symlink' behavior on UNIX platforms.
parent d4ca30ae
......@@ -460,23 +460,25 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
else if (args[1] == "create_symlink" && args.size() == 4)
{
const char* destinationFileName = args[3].c_str();
if ( cmSystemTools::FileExists(destinationFileName) )
if((cmSystemTools::FileExists(destinationFileName) ||
cmSystemTools::FileIsSymlink(destinationFileName)) &&
!cmSystemTools::RemoveFile(destinationFileName))
{
if ( cmSystemTools::FileIsSymlink(destinationFileName) )
{
if ( !cmSystemTools::RemoveFile(destinationFileName) ||
cmSystemTools::FileExists(destinationFileName) )
{
return 0;
}
}
else
{
return 0;
}
std::string emsg = cmSystemTools::GetLastSystemError();
std::cerr <<
"failed to create symbolic link '" << destinationFileName <<
"' because existing path cannot be removed: " << emsg << "\n";
return 1;
}
if(!cmSystemTools::CreateSymlink(args[2].c_str(), args[3].c_str()))
{
std::string emsg = cmSystemTools::GetLastSystemError();
std::cerr <<
"failed to create symbolic link '" << destinationFileName <<
"': " << emsg << "\n";
return 1;
}
return cmSystemTools::CreateSymlink(args[2].c_str(),
args[3].c_str())? 0:1;
return 0;
}
// Internal CMake shared library support.
......
......@@ -111,5 +111,6 @@ add_RunCMake_test(File_Generate)
add_RunCMake_test(ExportWithoutLanguage)
add_RunCMake_test(target_link_libraries)
add_RunCMake_test(CheckModules)
add_RunCMake_test(CommandLine)
add_RunCMake_test(install)
if(NOT IS_SYMLINK ${RunCMake_TEST_BINARY_DIR}/L)
set(RunCMake_TEST_FAILED "Symlink 'L' incorrectly not created!")
endif()
if(EXISTS ${RunCMake_TEST_BINARY_DIR}/L)
set(RunCMake_TEST_FAILED "Symlink 'L' not broken!")
endif()
if(NOT IS_DIRECTORY ${RunCMake_TEST_BINARY_DIR}/L)
set(RunCMake_TEST_FAILED "Symlink 'L' not replaced correctly!")
endif()
failed to create symbolic link 'missing-dir/L':
failed to create symbolic link '\.' because existing path cannot be removed:
include(RunCMake)
if(UNIX)
run_cmake_command(E_create_symlink-missing-dir
${CMAKE_COMMAND} -E create_symlink T missing-dir/L
)
# Use a single build tree for a few tests without cleaning.
set(RunCMake_TEST_BINARY_DIR
${RunCMake_BINARY_DIR}/E_create_symlink-broken-build)
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
run_cmake_command(E_create_symlink-broken-create
${CMAKE_COMMAND} -E create_symlink T L
)
run_cmake_command(E_create_symlink-broken-replace
${CMAKE_COMMAND} -E create_symlink . L
)
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_NO_CLEAN)
run_cmake_command(E_create_symlink-no-replace-dir
${CMAKE_COMMAND} -E create_symlink T .
)
endif()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment