ExternalProject-gitupdate.cmake.in 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. # file Copyright.txt or https://cmake.org/licensing for details.
  3. cmake_minimum_required(VERSION 3.5)
  4. execute_process(
  5. COMMAND "@git_EXECUTABLE@" rev-list --max-count=1 HEAD
  6. WORKING_DIRECTORY "@work_dir@"
  7. RESULT_VARIABLE error_code
  8. OUTPUT_VARIABLE head_sha
  9. OUTPUT_STRIP_TRAILING_WHITESPACE
  10. )
  11. if(error_code)
  12. message(FATAL_ERROR "Failed to get the hash for HEAD")
  13. endif()
  14. execute_process(
  15. COMMAND "@git_EXECUTABLE@" show-ref "@git_tag@"
  16. WORKING_DIRECTORY "@work_dir@"
  17. OUTPUT_VARIABLE show_ref_output
  18. )
  19. # If a remote ref is asked for, which can possibly move around,
  20. # we must always do a fetch and checkout.
  21. if("${show_ref_output}" MATCHES "remotes")
  22. set(is_remote_ref 1)
  23. else()
  24. set(is_remote_ref 0)
  25. endif()
  26. # Tag is in the form <remote>/<tag> (i.e. origin/master) we must strip
  27. # the remote from the tag.
  28. if("${show_ref_output}" MATCHES "refs/remotes/@git_tag@")
  29. string(REGEX MATCH "^([^/]+)/(.+)$" _unused "@git_tag@")
  30. set(git_remote "${CMAKE_MATCH_1}")
  31. set(git_tag "${CMAKE_MATCH_2}")
  32. else()
  33. set(git_remote "@git_remote_name@")
  34. set(git_tag "@git_tag@")
  35. endif()
  36. # This will fail if the tag does not exist (it probably has not been fetched
  37. # yet).
  38. execute_process(
  39. COMMAND "@git_EXECUTABLE@" rev-list --max-count=1 "${git_tag}"
  40. WORKING_DIRECTORY "@work_dir@"
  41. RESULT_VARIABLE error_code
  42. OUTPUT_VARIABLE tag_sha
  43. OUTPUT_STRIP_TRAILING_WHITESPACE
  44. )
  45. # Is the hash checkout out that we want?
  46. if(error_code OR is_remote_ref OR NOT ("${tag_sha}" STREQUAL "${head_sha}"))
  47. execute_process(
  48. COMMAND "@git_EXECUTABLE@" fetch
  49. WORKING_DIRECTORY "@work_dir@"
  50. RESULT_VARIABLE error_code
  51. )
  52. if(error_code)
  53. message(FATAL_ERROR "Failed to fetch repository '@git_repository@'")
  54. endif()
  55. if(is_remote_ref AND NOT "@git_update_strategy@" STREQUAL "CHECKOUT")
  56. # Check if stash is needed
  57. execute_process(
  58. COMMAND "@git_EXECUTABLE@" status --porcelain
  59. WORKING_DIRECTORY "@work_dir@"
  60. RESULT_VARIABLE error_code
  61. OUTPUT_VARIABLE repo_status
  62. )
  63. if(error_code)
  64. message(FATAL_ERROR "Failed to get the status")
  65. endif()
  66. string(LENGTH "${repo_status}" need_stash)
  67. # If not in clean state, stash changes in order to be able to be able to
  68. # perform git pull --rebase
  69. if(need_stash)
  70. execute_process(
  71. COMMAND "@git_EXECUTABLE@" stash save @git_stash_save_options@
  72. WORKING_DIRECTORY "@work_dir@"
  73. RESULT_VARIABLE error_code
  74. )
  75. if(error_code)
  76. message(FATAL_ERROR "Failed to stash changes")
  77. endif()
  78. endif()
  79. # Pull changes from the remote branch
  80. execute_process(
  81. COMMAND "@git_EXECUTABLE@" rebase "${git_remote}/${git_tag}"
  82. WORKING_DIRECTORY "@work_dir@"
  83. RESULT_VARIABLE error_code
  84. OUTPUT_VARIABLE rebase_output
  85. ERROR_VARIABLE rebase_output
  86. )
  87. if(error_code)
  88. # Rebase failed, undo the rebase attempt before continuing
  89. execute_process(
  90. COMMAND "@git_EXECUTABLE@" rebase --abort
  91. WORKING_DIRECTORY "@work_dir@"
  92. )
  93. if(NOT "@git_update_strategy@" STREQUAL "REBASE_CHECKOUT")
  94. # Not allowed to do a checkout as a fallback, so cannot proceed
  95. if(need_stash)
  96. execute_process(
  97. COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
  98. WORKING_DIRECTORY "@work_dir@"
  99. )
  100. endif()
  101. message(FATAL_ERROR "\nFailed to rebase in: '@work_dir@'."
  102. "\nOutput from the attempted rebase follows:"
  103. "\n${rebase_output}"
  104. "\n\nYou will have to resolve the conflicts manually")
  105. endif()
  106. # Fall back to checkout. We create an annotated tag so that the user
  107. # can manually inspect the situation and revert if required.
  108. # We can't log the failed rebase output because MSVC sees it and
  109. # intervenes, causing the build to fail even though it completes.
  110. # Write it to a file instead.
  111. string(TIMESTAMP tag_timestamp "%Y%m%dT%H%M%S" UTC)
  112. set(tag_name _cmake_ExternalProject_moved_from_here_${tag_timestamp}Z)
  113. set(error_log_file ${CMAKE_CURRENT_LIST_DIR}/rebase_error_${tag_timestamp}Z.log)
  114. file(WRITE ${error_log_file} "${rebase_output}")
  115. message(WARNING "Rebase failed, output has been saved to ${error_log_file}"
  116. "\nFalling back to checkout, previous commit tagged as ${tag_name}")
  117. execute_process(
  118. COMMAND "@git_EXECUTABLE@" tag -a
  119. -m "ExternalProject attempting to move from here to ${git_remote}/${git_tag}"
  120. ${tag_name}
  121. WORKING_DIRECTORY "@work_dir@"
  122. RESULT_VARIABLE error_code
  123. )
  124. if(error_code)
  125. message(FATAL_ERROR "Failed to add marker tag")
  126. endif()
  127. execute_process(
  128. COMMAND "@git_EXECUTABLE@" checkout ${git_remote}/${git_tag}
  129. WORKING_DIRECTORY "@work_dir@"
  130. RESULT_VARIABLE error_code
  131. )
  132. if(error_code)
  133. message(FATAL_ERROR "Failed to checkout : '${git_remote}/${git_tag}'")
  134. endif()
  135. endif()
  136. if(need_stash)
  137. execute_process(
  138. COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
  139. WORKING_DIRECTORY "@work_dir@"
  140. RESULT_VARIABLE error_code
  141. )
  142. if(error_code)
  143. # Stash pop --index failed: Try again dropping the index
  144. execute_process(
  145. COMMAND "@git_EXECUTABLE@" reset --hard --quiet
  146. WORKING_DIRECTORY "@work_dir@"
  147. RESULT_VARIABLE error_code
  148. )
  149. execute_process(
  150. COMMAND "@git_EXECUTABLE@" stash pop --quiet
  151. WORKING_DIRECTORY "@work_dir@"
  152. RESULT_VARIABLE error_code
  153. )
  154. if(error_code)
  155. # Stash pop failed: Restore previous state.
  156. execute_process(
  157. COMMAND "@git_EXECUTABLE@" reset --hard --quiet ${head_sha}
  158. WORKING_DIRECTORY "@work_dir@"
  159. )
  160. execute_process(
  161. COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
  162. WORKING_DIRECTORY "@work_dir@"
  163. )
  164. message(FATAL_ERROR "\nFailed to unstash changes in: '@work_dir@'."
  165. "\nYou will have to resolve the conflicts manually")
  166. endif()
  167. endif()
  168. endif()
  169. else()
  170. execute_process(
  171. COMMAND "@git_EXECUTABLE@" checkout "${git_tag}"
  172. WORKING_DIRECTORY "@work_dir@"
  173. RESULT_VARIABLE error_code
  174. )
  175. if(error_code)
  176. message(FATAL_ERROR "Failed to checkout tag: '${git_tag}'")
  177. endif()
  178. endif()
  179. set(init_submodules "@init_submodules@")
  180. if(init_submodules)
  181. execute_process(
  182. COMMAND "@git_EXECUTABLE@" submodule update @git_submodules_recurse@ --init @git_submodules@
  183. WORKING_DIRECTORY "@work_dir@"
  184. RESULT_VARIABLE error_code
  185. )
  186. endif()
  187. if(error_code)
  188. message(FATAL_ERROR "Failed to update submodules in: '@work_dir@'")
  189. endif()
  190. endif()