| # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying | 
 | # file Copyright.txt or https://cmake.org/licensing for details. | 
 |  | 
 | cmake_minimum_required(VERSION 3.5) | 
 |  | 
 | function(get_hash_for_ref ref out_var err_var) | 
 |   execute_process( | 
 |     COMMAND "@git_EXECUTABLE@" rev-parse "${ref}^0" | 
 |     WORKING_DIRECTORY "@work_dir@" | 
 |     RESULT_VARIABLE error_code | 
 |     OUTPUT_VARIABLE ref_hash | 
 |     ERROR_VARIABLE error_msg | 
 |     OUTPUT_STRIP_TRAILING_WHITESPACE | 
 |   ) | 
 |   if(error_code) | 
 |     set(${out_var} "" PARENT_SCOPE) | 
 |   else() | 
 |     set(${out_var} "${ref_hash}" PARENT_SCOPE) | 
 |   endif() | 
 |   set(${err_var} "${error_msg}" PARENT_SCOPE) | 
 | endfunction() | 
 |  | 
 | get_hash_for_ref(HEAD head_sha error_msg) | 
 | if(head_sha STREQUAL "") | 
 |   message(FATAL_ERROR "Failed to get the hash for HEAD:\n${error_msg}") | 
 | endif() | 
 |  | 
 |  | 
 | execute_process( | 
 |   COMMAND "@git_EXECUTABLE@" show-ref "@git_tag@" | 
 |   WORKING_DIRECTORY "@work_dir@" | 
 |   OUTPUT_VARIABLE show_ref_output | 
 | ) | 
 | if(show_ref_output MATCHES "^[a-z0-9]+[ \\t]+refs/remotes/") | 
 |   # Given a full remote/branch-name and we know about it already. Since | 
 |   # branches can move around, we always have to fetch. | 
 |   set(fetch_required YES) | 
 |   set(checkout_name "@git_tag@") | 
 |  | 
 | elseif(show_ref_output MATCHES "^[a-z0-9]+[ \\t]+refs/tags/") | 
 |   # Given a tag name that we already know about. We don't know if the tag we | 
 |   # have matches the remote though (tags can move), so we should fetch. | 
 |   set(fetch_required YES) | 
 |   set(checkout_name "@git_tag@") | 
 |  | 
 |   # Special case to preserve backward compatibility: if we are already at the | 
 |   # same commit as the tag we hold locally, don't do a fetch and assume the tag | 
 |   # hasn't moved on the remote. | 
 |   # FIXME: We should provide an option to always fetch for this case | 
 |   get_hash_for_ref("@git_tag@" tag_sha error_msg) | 
 |   if(tag_sha STREQUAL head_sha) | 
 |     message(VERBOSE "Already at requested tag: ${tag_sha}") | 
 |     return() | 
 |   endif() | 
 |  | 
 | elseif(show_ref_output MATCHES "^[a-z0-9]+[ \\t]+refs/heads/") | 
 |   # Given a branch name without any remote and we already have a branch by that | 
 |   # name. We might already have that branch checked out or it might be a | 
 |   # different branch. It isn't safe to use a bare branch name without the | 
 |   # remote, so do a fetch and replace the ref with one that includes the remote. | 
 |   set(fetch_required YES) | 
 |   set(checkout_name "@git_remote_name@/@git_tag@") | 
 |  | 
 | else() | 
 |   get_hash_for_ref("@git_tag@" tag_sha error_msg) | 
 |   if(tag_sha STREQUAL head_sha) | 
 |     # Have the right commit checked out already | 
 |     message(VERBOSE "Already at requested ref: ${tag_sha}") | 
 |     return() | 
 |  | 
 |   elseif(tag_sha STREQUAL "") | 
 |     # We don't know about this ref yet, so we have no choice but to fetch. | 
 |     # We deliberately swallow any error message at the default log level | 
 |     # because it can be confusing for users to see a failed git command. | 
 |     # That failure is being handled here, so it isn't an error. | 
 |     set(fetch_required YES) | 
 |     set(checkout_name "@git_tag@") | 
 |     if(NOT error_msg STREQUAL "") | 
 |       message(VERBOSE "${error_msg}") | 
 |     endif() | 
 |  | 
 |   else() | 
 |     # We have the commit, so we know we were asked to find a commit hash | 
 |     # (otherwise it would have been handled further above), but we don't | 
 |     # have that commit checked out yet | 
 |     set(fetch_required NO) | 
 |     set(checkout_name "@git_tag@") | 
 |     if(NOT error_msg STREQUAL "") | 
 |       message(WARNING "${error_msg}") | 
 |     endif() | 
 |  | 
 |   endif() | 
 | endif() | 
 |  | 
 | if(fetch_required) | 
 |   message(VERBOSE "Fetching latest from the remote @git_remote_name@") | 
 |   execute_process( | 
 |     COMMAND "@git_EXECUTABLE@" fetch --tags --force "@git_remote_name@" | 
 |     WORKING_DIRECTORY "@work_dir@" | 
 |     COMMAND_ERROR_IS_FATAL ANY | 
 |   ) | 
 | endif() | 
 |  | 
 | set(git_update_strategy "@git_update_strategy@") | 
 | if(git_update_strategy STREQUAL "") | 
 |   # Backward compatibility requires REBASE as the default behavior | 
 |   set(git_update_strategy REBASE) | 
 | endif() | 
 |  | 
 | if(git_update_strategy MATCHES "^REBASE(_CHECKOUT)?$") | 
 |   # Asked to potentially try to rebase first, maybe with fallback to checkout. | 
 |   # We can't if we aren't already on a branch and we shouldn't if that local | 
 |   # branch isn't tracking the one we want to checkout. | 
 |   execute_process( | 
 |     COMMAND "@git_EXECUTABLE@" symbolic-ref -q HEAD | 
 |     WORKING_DIRECTORY "@work_dir@" | 
 |     OUTPUT_VARIABLE current_branch | 
 |     OUTPUT_STRIP_TRAILING_WHITESPACE | 
 |     # Don't test for an error. If this isn't a branch, we get a non-zero error | 
 |     # code but empty output. | 
 |   ) | 
 |  | 
 |   if(current_branch STREQUAL "") | 
 |     # Not on a branch, checkout is the only sensible option since any rebase | 
 |     # would always fail (and backward compatibility requires us to checkout in | 
 |     # this situation) | 
 |     set(git_update_strategy CHECKOUT) | 
 |  | 
 |   else() | 
 |     execute_process( | 
 |       COMMAND "@git_EXECUTABLE@" for-each-ref "--format='%(upstream:short)'" "${current_branch}" | 
 |       WORKING_DIRECTORY "@work_dir@" | 
 |       OUTPUT_VARIABLE upstream_branch | 
 |       OUTPUT_STRIP_TRAILING_WHITESPACE | 
 |       COMMAND_ERROR_IS_FATAL ANY  # There is no error if no upstream is set | 
 |     ) | 
 |     if(NOT upstream_branch STREQUAL checkout_name) | 
 |       # Not safe to rebase when asked to checkout a different branch to the one | 
 |       # we are tracking. If we did rebase, we could end up with arbitrary | 
 |       # commits added to the ref we were asked to checkout if the current local | 
 |       # branch happens to be able to rebase onto the target branch. There would | 
 |       # be no error message and the user wouldn't know this was occurring. | 
 |       set(git_update_strategy CHECKOUT) | 
 |     endif() | 
 |  | 
 |   endif() | 
 | elseif(NOT git_update_strategy STREQUAL "CHECKOUT") | 
 |   message(FATAL_ERROR "Unsupported git update strategy: ${git_update_strategy}") | 
 | endif() | 
 |  | 
 |  | 
 | # Check if stash is needed | 
 | execute_process( | 
 |   COMMAND "@git_EXECUTABLE@" status --porcelain | 
 |   WORKING_DIRECTORY "@work_dir@" | 
 |   RESULT_VARIABLE error_code | 
 |   OUTPUT_VARIABLE repo_status | 
 | ) | 
 | if(error_code) | 
 |   message(FATAL_ERROR "Failed to get the status") | 
 | endif() | 
 | string(LENGTH "${repo_status}" need_stash) | 
 |  | 
 | # If not in clean state, stash changes in order to be able to perform a | 
 | # rebase or checkout without losing those changes permanently | 
 | if(need_stash) | 
 |   execute_process( | 
 |     COMMAND "@git_EXECUTABLE@" stash save @git_stash_save_options@ | 
 |     WORKING_DIRECTORY "@work_dir@" | 
 |     COMMAND_ERROR_IS_FATAL ANY | 
 |   ) | 
 | endif() | 
 |  | 
 | if(git_update_strategy STREQUAL "CHECKOUT") | 
 |   execute_process( | 
 |     COMMAND "@git_EXECUTABLE@" checkout "${checkout_name}" | 
 |     WORKING_DIRECTORY "@work_dir@" | 
 |     COMMAND_ERROR_IS_FATAL ANY | 
 |   ) | 
 | else() | 
 |   execute_process( | 
 |     COMMAND "@git_EXECUTABLE@" rebase "${checkout_name}" | 
 |     WORKING_DIRECTORY "@work_dir@" | 
 |     RESULT_VARIABLE error_code | 
 |     OUTPUT_VARIABLE rebase_output | 
 |     ERROR_VARIABLE  rebase_output | 
 |   ) | 
 |   if(error_code) | 
 |     # Rebase failed, undo the rebase attempt before continuing | 
 |     execute_process( | 
 |       COMMAND "@git_EXECUTABLE@" rebase --abort | 
 |       WORKING_DIRECTORY "@work_dir@" | 
 |     ) | 
 |  | 
 |     if(NOT git_update_strategy STREQUAL "REBASE_CHECKOUT") | 
 |       # Not allowed to do a checkout as a fallback, so cannot proceed | 
 |       if(need_stash) | 
 |         execute_process( | 
 |           COMMAND "@git_EXECUTABLE@" stash pop --index --quiet | 
 |           WORKING_DIRECTORY "@work_dir@" | 
 |           ) | 
 |       endif() | 
 |       message(FATAL_ERROR "\nFailed to rebase in: '@work_dir@'." | 
 |                           "\nOutput from the attempted rebase follows:" | 
 |                           "\n${rebase_output}" | 
 |                           "\n\nYou will have to resolve the conflicts manually") | 
 |     endif() | 
 |  | 
 |     # Fall back to checkout. We create an annotated tag so that the user | 
 |     # can manually inspect the situation and revert if required. | 
 |     # We can't log the failed rebase output because MSVC sees it and | 
 |     # intervenes, causing the build to fail even though it completes. | 
 |     # Write it to a file instead. | 
 |     string(TIMESTAMP tag_timestamp "%Y%m%dT%H%M%S" UTC) | 
 |     set(tag_name _cmake_ExternalProject_moved_from_here_${tag_timestamp}Z) | 
 |     set(error_log_file ${CMAKE_CURRENT_LIST_DIR}/rebase_error_${tag_timestamp}Z.log) | 
 |     file(WRITE ${error_log_file} "${rebase_output}") | 
 |     message(WARNING "Rebase failed, output has been saved to ${error_log_file}" | 
 |                     "\nFalling back to checkout, previous commit tagged as ${tag_name}") | 
 |     execute_process( | 
 |       COMMAND "@git_EXECUTABLE@" tag -a | 
 |               -m "ExternalProject attempting to move from here to ${checkout_name}" | 
 |               ${tag_name} | 
 |       WORKING_DIRECTORY "@work_dir@" | 
 |       COMMAND_ERROR_IS_FATAL ANY | 
 |     ) | 
 |  | 
 |     execute_process( | 
 |       COMMAND "@git_EXECUTABLE@" checkout "${checkout_name}" | 
 |       WORKING_DIRECTORY "@work_dir@" | 
 |       COMMAND_ERROR_IS_FATAL ANY | 
 |     ) | 
 |   endif() | 
 | endif() | 
 |  | 
 | if(need_stash) | 
 |   # Put back the stashed changes | 
 |   execute_process( | 
 |     COMMAND "@git_EXECUTABLE@" stash pop --index --quiet | 
 |     WORKING_DIRECTORY "@work_dir@" | 
 |     RESULT_VARIABLE error_code | 
 |     ) | 
 |   if(error_code) | 
 |     # Stash pop --index failed: Try again dropping the index | 
 |     execute_process( | 
 |       COMMAND "@git_EXECUTABLE@" reset --hard --quiet | 
 |       WORKING_DIRECTORY "@work_dir@" | 
 |     ) | 
 |     execute_process( | 
 |       COMMAND "@git_EXECUTABLE@" stash pop --quiet | 
 |       WORKING_DIRECTORY "@work_dir@" | 
 |       RESULT_VARIABLE error_code | 
 |     ) | 
 |     if(error_code) | 
 |       # Stash pop failed: Restore previous state. | 
 |       execute_process( | 
 |         COMMAND "@git_EXECUTABLE@" reset --hard --quiet ${head_sha} | 
 |         WORKING_DIRECTORY "@work_dir@" | 
 |       ) | 
 |       execute_process( | 
 |         COMMAND "@git_EXECUTABLE@" stash pop --index --quiet | 
 |         WORKING_DIRECTORY "@work_dir@" | 
 |       ) | 
 |       message(FATAL_ERROR "\nFailed to unstash changes in: '@work_dir@'." | 
 |                           "\nYou will have to resolve the conflicts manually") | 
 |     endif() | 
 |   endif() | 
 | endif() | 
 |  | 
 | set(init_submodules "@init_submodules@") | 
 | if(init_submodules) | 
 |   execute_process( | 
 |     COMMAND "@git_EXECUTABLE@" submodule update @git_submodules_recurse@ --init @git_submodules@ | 
 |     WORKING_DIRECTORY "@work_dir@" | 
 |     COMMAND_ERROR_IS_FATAL ANY | 
 |   ) | 
 | endif() |