From 5e941a545bf5882ddf101cad383dc815fb651f26 Mon Sep 17 00:00:00 2001 From: Craig Scott Date: Sun, 9 May 2021 12:33:16 +1000 Subject: ExternalProject: Ensure git fetch if updating to hash we don't have yet In ac6a4d4884 (ExternalProject: Improve robustness of update step, 2020-10-17), the method used to check whether we already have a commit or not was changed from using git rev-list to git rev-parse. The new logic assumed rev-parse would output nothing if given a commit hash it didn't know about, but it simply prints the hash again without raising an error in this scenario. Amend that logic by adding ^{commit} to the ref to ensure we do get an error if that ref is not currently known. Fixes: #22166 --- Modules/ExternalProject-gitupdate.cmake.in | 2 +- Tests/RunCMake/ExternalProject/FetchGitRefs.cmake | 84 ++++++++++++++++++++++ .../ExternalProject/FetchGitRefs/CMakeLists.txt | 15 ++++ Tests/RunCMake/ExternalProject/FetchGitTags.cmake | 67 ----------------- .../ExternalProject/FetchGitTags/CMakeLists.txt | 15 ---- Tests/RunCMake/ExternalProject/RunCMakeTest.cmake | 2 +- 6 files changed, 101 insertions(+), 84 deletions(-) create mode 100644 Tests/RunCMake/ExternalProject/FetchGitRefs.cmake create mode 100644 Tests/RunCMake/ExternalProject/FetchGitRefs/CMakeLists.txt delete mode 100644 Tests/RunCMake/ExternalProject/FetchGitTags.cmake delete mode 100644 Tests/RunCMake/ExternalProject/FetchGitTags/CMakeLists.txt diff --git a/Modules/ExternalProject-gitupdate.cmake.in b/Modules/ExternalProject-gitupdate.cmake.in index 7033918..461e323 100644 --- a/Modules/ExternalProject-gitupdate.cmake.in +++ b/Modules/ExternalProject-gitupdate.cmake.in @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.5) function(get_hash_for_ref ref out_var err_var) execute_process( - COMMAND "@git_EXECUTABLE@" rev-parse "${ref}" + COMMAND "@git_EXECUTABLE@" rev-parse "${ref}^{commit}" WORKING_DIRECTORY "@work_dir@" RESULT_VARIABLE error_code OUTPUT_VARIABLE ref_hash diff --git a/Tests/RunCMake/ExternalProject/FetchGitRefs.cmake b/Tests/RunCMake/ExternalProject/FetchGitRefs.cmake new file mode 100644 index 0000000..a00908b --- /dev/null +++ b/Tests/RunCMake/ExternalProject/FetchGitRefs.cmake @@ -0,0 +1,84 @@ +find_package(Git QUIET REQUIRED) + +include(ExternalProject) + +set(srcRepo ${CMAKE_CURRENT_BINARY_DIR}/srcRepo) +set(srcDir ${CMAKE_CURRENT_BINARY_DIR}/src) +set(binDir ${CMAKE_CURRENT_BINARY_DIR}/build) +file(MAKE_DIRECTORY ${srcRepo}) +file(MAKE_DIRECTORY ${srcDir}) + +file(GLOB entries ${srcRepo}/*) +file(REMOVE_RECURSE ${entries} ${binDir}) +file(TOUCH ${srcRepo}/firstFile.txt) +configure_file(${CMAKE_CURRENT_LIST_DIR}/FetchGitRefs/CMakeLists.txt + ${srcDir}/CMakeLists.txt COPYONLY) + +function(execGitCommand) + execute_process( + WORKING_DIRECTORY ${srcRepo} + COMMAND ${GIT_EXECUTABLE} ${ARGN} + COMMAND_ECHO STDOUT + COMMAND_ERROR_IS_FATAL ANY + ) +endfunction() + +function(configureAndBuild tag) + execute_process(COMMAND ${CMAKE_COMMAND} + -G ${CMAKE_GENERATOR} -T "${CMAKE_GENERATOR_TOOLSET}" + -A "${CMAKE_GENERATOR_PLATFORM}" + -D repoDir:PATH=${srcRepo} + -D gitTag:STRING=${tag} + -B ${binDir} + -S ${srcDir} + COMMAND_ECHO STDOUT + COMMAND_ERROR_IS_FATAL ANY + ) + + execute_process(COMMAND ${CMAKE_COMMAND} --build ${binDir} --target fetcher + WORKING_DIRECTORY ${binDir} + COMMAND_ECHO STDOUT + COMMAND_ERROR_IS_FATAL ANY + ) +endfunction() + +# Setup a fresh source repo with a predictable default branch across all +# git versions +execGitCommand(-c init.defaultBranch=master init) +execGitCommand(config --add user.email "testauthor@cmake.org") +execGitCommand(config --add user.name testauthor) + +# Create the initial repo structure +execGitCommand(add firstFile.txt) +execGitCommand(commit -m "First file") + +message(STATUS "First configure-and-build") +configureAndBuild(master) + +# Create a tagged commit that is not on any branch. With git 2.20 or later, +# this commit won't be fetched without the --tags option. +file(TOUCH ${srcRepo}/secondFile.txt) +execGitCommand(add secondFile.txt) +execGitCommand(commit -m "Second file") +execGitCommand(tag -a -m "Adding tag" tag_of_interest) +execGitCommand(reset --hard HEAD~1) + +message(STATUS "Configure-and-build, update to tag") +configureAndBuild(tag_of_interest) + +# Do the same, but this time for a commit hash +file(TOUCH ${srcRepo}/thirdFile.txt) +execGitCommand(add thirdFile.txt) +execGitCommand(commit -m "Third file") +execGitCommand(tag -a -m "Adding another tag" check_for_hash) +execGitCommand(reset --hard HEAD~1) +execute_process( + WORKING_DIRECTORY ${srcRepo} + COMMAND ${GIT_EXECUTABLE} rev-parse check_for_hash + COMMAND_ERROR_IS_FATAL ANY + OUTPUT_VARIABLE commit_hash + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +message(STATUS "Configure-and-build, update to commit hash ${commit_hash}") +configureAndBuild(${commit_hash}) diff --git a/Tests/RunCMake/ExternalProject/FetchGitRefs/CMakeLists.txt b/Tests/RunCMake/ExternalProject/FetchGitRefs/CMakeLists.txt new file mode 100644 index 0000000..d9a380c --- /dev/null +++ b/Tests/RunCMake/ExternalProject/FetchGitRefs/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.19) +project(FetchTags LANGUAGES NONE) + +include(ExternalProject) + +# repoDir and gitTag are expected to be set as cache variables + +ExternalProject_Add(fetcher + GIT_REPOSITORY ${repoDir} + GIT_TAG ${gitTag} + GIT_REMOTE_UPDATE_STRATEGY CHECKOUT + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" +) diff --git a/Tests/RunCMake/ExternalProject/FetchGitTags.cmake b/Tests/RunCMake/ExternalProject/FetchGitTags.cmake deleted file mode 100644 index 37d1b40..0000000 --- a/Tests/RunCMake/ExternalProject/FetchGitTags.cmake +++ /dev/null @@ -1,67 +0,0 @@ -find_package(Git QUIET REQUIRED) - -include(ExternalProject) - -set(srcRepo ${CMAKE_CURRENT_BINARY_DIR}/srcRepo) -set(srcDir ${CMAKE_CURRENT_BINARY_DIR}/src) -set(binDir ${CMAKE_CURRENT_BINARY_DIR}/build) -file(MAKE_DIRECTORY ${srcRepo}) -file(MAKE_DIRECTORY ${srcDir}) - -file(GLOB entries ${srcRepo}/*) -file(REMOVE_RECURSE ${entries} ${binDir}) -file(TOUCH ${srcRepo}/firstFile.txt) -configure_file(${CMAKE_CURRENT_LIST_DIR}/FetchGitTags/CMakeLists.txt - ${srcDir}/CMakeLists.txt COPYONLY) - -function(execGitCommand) - execute_process( - WORKING_DIRECTORY ${srcRepo} - COMMAND ${GIT_EXECUTABLE} ${ARGN} - COMMAND_ECHO STDOUT - COMMAND_ERROR_IS_FATAL ANY - ) -endfunction() - -function(configureAndBuild tag) - execute_process(COMMAND ${CMAKE_COMMAND} - -G ${CMAKE_GENERATOR} -T "${CMAKE_GENERATOR_TOOLSET}" - -A "${CMAKE_GENERATOR_PLATFORM}" - -D repoDir:PATH=${srcRepo} - -D gitTag:STRING=${tag} - -B ${binDir} - -S ${srcDir} - COMMAND_ECHO STDOUT - COMMAND_ERROR_IS_FATAL ANY - ) - - execute_process(COMMAND ${CMAKE_COMMAND} --build ${binDir} --target fetcher - WORKING_DIRECTORY ${binDir} - COMMAND_ECHO STDOUT - COMMAND_ERROR_IS_FATAL ANY - ) -endfunction() - -# Setup a fresh source repo with a predictable default branch across all -# git versions -execGitCommand(-c init.defaultBranch=master init) -execGitCommand(config --add user.email "testauthor@cmake.org") -execGitCommand(config --add user.name testauthor) - -# Create the initial repo structure -execGitCommand(add firstFile.txt) -execGitCommand(commit -m "First file") - -message(STATUS "First configure-and-build") -configureAndBuild(master) - -# Create a tagged commit that is not on any branch. With git 2.20 or later, -# this commit won't be fetched without the --tags option. -file(TOUCH ${srcRepo}/secondFile.txt) -execGitCommand(add secondFile.txt) -execGitCommand(commit -m "Second file") -execGitCommand(tag -a -m "Adding tag" tag_of_interest) -execGitCommand(reset --hard HEAD~1) - -message(STATUS "Second configure-and-build") -configureAndBuild(tag_of_interest) diff --git a/Tests/RunCMake/ExternalProject/FetchGitTags/CMakeLists.txt b/Tests/RunCMake/ExternalProject/FetchGitTags/CMakeLists.txt deleted file mode 100644 index d9a380c..0000000 --- a/Tests/RunCMake/ExternalProject/FetchGitTags/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -cmake_minimum_required(VERSION 3.19) -project(FetchTags LANGUAGES NONE) - -include(ExternalProject) - -# repoDir and gitTag are expected to be set as cache variables - -ExternalProject_Add(fetcher - GIT_REPOSITORY ${repoDir} - GIT_TAG ${gitTag} - GIT_REMOTE_UPDATE_STRATEGY CHECKOUT - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" -) diff --git a/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake b/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake index 3205dd5..a4244e3 100644 --- a/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake +++ b/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake @@ -185,6 +185,6 @@ if(GIT_EXECUTABLE) # Note that there appear to be differences in where git writes its output to # on some platforms. It may go to stdout or stderr, so force it to be merged. set(RunCMake_TEST_OUTPUT_MERGE TRUE) - run_cmake(FetchGitTags) + run_cmake(FetchGitRefs) set(RunCMake_TEST_OUTPUT_MERGE FALSE) endif() -- cgit v0.12