ExternalProject-gitupdate.cmake.in 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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)
  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 perform a
  68. # rebase or checkout without losing those changes permanently
  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. if("@git_update_strategy@" STREQUAL "CHECKOUT")
  80. execute_process(
  81. COMMAND "@git_EXECUTABLE@" checkout "${git_remote}/${git_tag}"
  82. WORKING_DIRECTORY "@work_dir@"
  83. RESULT_VARIABLE error_code
  84. )
  85. if(error_code)
  86. message(FATAL_ERROR "Failed to checkout tag: '${git_remote}/${git_tag}'")
  87. endif()
  88. else()
  89. # Pull changes from the remote branch
  90. execute_process(
  91. COMMAND "@git_EXECUTABLE@" rebase "${git_remote}/${git_tag}"
  92. WORKING_DIRECTORY "@work_dir@"
  93. RESULT_VARIABLE error_code
  94. OUTPUT_VARIABLE rebase_output
  95. ERROR_VARIABLE rebase_output
  96. )
  97. if(error_code)
  98. # Rebase failed, undo the rebase attempt before continuing
  99. execute_process(
  100. COMMAND "@git_EXECUTABLE@" rebase --abort
  101. WORKING_DIRECTORY "@work_dir@"
  102. )
  103. if(NOT "@git_update_strategy@" STREQUAL "REBASE_CHECKOUT")
  104. # Not allowed to do a checkout as a fallback, so cannot proceed
  105. if(need_stash)
  106. execute_process(
  107. COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
  108. WORKING_DIRECTORY "@work_dir@"
  109. )
  110. endif()
  111. message(FATAL_ERROR "\nFailed to rebase in: '@work_dir@'."
  112. "\nOutput from the attempted rebase follows:"
  113. "\n${rebase_output}"
  114. "\n\nYou will have to resolve the conflicts manually")
  115. endif()
  116. # Fall back to checkout. We create an annotated tag so that the user
  117. # can manually inspect the situation and revert if required.
  118. # We can't log the failed rebase output because MSVC sees it and
  119. # intervenes, causing the build to fail even though it completes.
  120. # Write it to a file instead.
  121. string(TIMESTAMP tag_timestamp "%Y%m%dT%H%M%S" UTC)
  122. set(tag_name _cmake_ExternalProject_moved_from_here_${tag_timestamp}Z)
  123. set(error_log_file ${CMAKE_CURRENT_LIST_DIR}/rebase_error_${tag_timestamp}Z.log)
  124. file(WRITE ${error_log_file} "${rebase_output}")
  125. message(WARNING "Rebase failed, output has been saved to ${error_log_file}"
  126. "\nFalling back to checkout, previous commit tagged as ${tag_name}")
  127. execute_process(
  128. COMMAND "@git_EXECUTABLE@" tag -a
  129. -m "ExternalProject attempting to move from here to ${git_remote}/${git_tag}"
  130. ${tag_name}
  131. WORKING_DIRECTORY "@work_dir@"
  132. RESULT_VARIABLE error_code
  133. )
  134. if(error_code)
  135. message(FATAL_ERROR "Failed to add marker tag")
  136. endif()
  137. execute_process(
  138. COMMAND "@git_EXECUTABLE@" checkout "${git_remote}/${git_tag}"
  139. WORKING_DIRECTORY "@work_dir@"
  140. RESULT_VARIABLE error_code
  141. )
  142. if(error_code)
  143. message(FATAL_ERROR "Failed to checkout : '${git_remote}/${git_tag}'")
  144. endif()
  145. endif()
  146. endif()
  147. if(need_stash)
  148. execute_process(
  149. COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
  150. WORKING_DIRECTORY "@work_dir@"
  151. RESULT_VARIABLE error_code
  152. )
  153. if(error_code)
  154. # Stash pop --index failed: Try again dropping the index
  155. execute_process(
  156. COMMAND "@git_EXECUTABLE@" reset --hard --quiet
  157. WORKING_DIRECTORY "@work_dir@"
  158. RESULT_VARIABLE error_code
  159. )
  160. execute_process(
  161. COMMAND "@git_EXECUTABLE@" stash pop --quiet
  162. WORKING_DIRECTORY "@work_dir@"
  163. RESULT_VARIABLE error_code
  164. )
  165. if(error_code)
  166. # Stash pop failed: Restore previous state.
  167. execute_process(
  168. COMMAND "@git_EXECUTABLE@" reset --hard --quiet ${head_sha}
  169. WORKING_DIRECTORY "@work_dir@"
  170. )
  171. execute_process(
  172. COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
  173. WORKING_DIRECTORY "@work_dir@"
  174. )
  175. message(FATAL_ERROR "\nFailed to unstash changes in: '@work_dir@'."
  176. "\nYou will have to resolve the conflicts manually")
  177. endif()
  178. endif()
  179. endif()
  180. else()
  181. execute_process(
  182. COMMAND "@git_EXECUTABLE@" checkout "${git_tag}"
  183. WORKING_DIRECTORY "@work_dir@"
  184. RESULT_VARIABLE error_code
  185. )
  186. if(error_code)
  187. message(FATAL_ERROR "Failed to checkout tag: '${git_tag}'")
  188. endif()
  189. endif()
  190. set(init_submodules "@init_submodules@")
  191. if(init_submodules)
  192. execute_process(
  193. COMMAND "@git_EXECUTABLE@" submodule update @git_submodules_recurse@ --init @git_submodules@
  194. WORKING_DIRECTORY "@work_dir@"
  195. RESULT_VARIABLE error_code
  196. )
  197. endif()
  198. if(error_code)
  199. message(FATAL_ERROR "Failed to update submodules in: '@work_dir@'")
  200. endif()
  201. endif()