shared_internal_commands.cmake 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. cmake_policy(VERSION 3.25)
  2. # Determine the remote URL of the project containing the working_directory.
  3. # This will leave output_variable unset if the URL can't be determined.
  4. function(_ep_get_git_remote_url output_variable working_directory)
  5. set("${output_variable}" "" PARENT_SCOPE)
  6. find_package(Git QUIET REQUIRED)
  7. execute_process(
  8. COMMAND ${GIT_EXECUTABLE} symbolic-ref --short HEAD
  9. WORKING_DIRECTORY "${working_directory}"
  10. OUTPUT_VARIABLE git_symbolic_ref
  11. OUTPUT_STRIP_TRAILING_WHITESPACE
  12. ERROR_QUIET
  13. )
  14. if(NOT git_symbolic_ref STREQUAL "")
  15. # We are potentially on a branch. See if that branch is associated with
  16. # an upstream remote (might be just a local one or not a branch at all).
  17. execute_process(
  18. COMMAND ${GIT_EXECUTABLE} config branch.${git_symbolic_ref}.remote
  19. WORKING_DIRECTORY "${working_directory}"
  20. OUTPUT_VARIABLE git_remote_name
  21. OUTPUT_STRIP_TRAILING_WHITESPACE
  22. ERROR_QUIET
  23. )
  24. endif()
  25. if(NOT git_remote_name)
  26. # Can't select a remote based on a branch. If there's only one remote,
  27. # or we have multiple remotes but one is called "origin", choose that.
  28. execute_process(
  29. COMMAND ${GIT_EXECUTABLE} remote
  30. WORKING_DIRECTORY "${working_directory}"
  31. OUTPUT_VARIABLE git_remote_list
  32. OUTPUT_STRIP_TRAILING_WHITESPACE
  33. ERROR_QUIET
  34. )
  35. string(REPLACE "\n" ";" git_remote_list "${git_remote_list}")
  36. list(LENGTH git_remote_list git_remote_list_length)
  37. if(git_remote_list_length EQUAL 0)
  38. message(FATAL_ERROR "Git remote not found in parent project.")
  39. elseif(git_remote_list_length EQUAL 1)
  40. list(GET git_remote_list 0 git_remote_name)
  41. else()
  42. set(base_warning_msg "Multiple git remotes found for parent project")
  43. if("origin" IN_LIST git_remote_list)
  44. message(WARNING "${base_warning_msg}, defaulting to origin.")
  45. set(git_remote_name "origin")
  46. else()
  47. message(FATAL_ERROR "${base_warning_msg}, none of which are origin.")
  48. endif()
  49. endif()
  50. endif()
  51. if(GIT_VERSION VERSION_LESS 1.7.5)
  52. set(_git_remote_url_cmd_args config remote.${git_remote_name}.url)
  53. elseif(GIT_VERSION VERSION_LESS 2.7)
  54. set(_git_remote_url_cmd_args ls-remote --get-url ${git_remote_name})
  55. else()
  56. set(_git_remote_url_cmd_args remote get-url ${git_remote_name})
  57. endif()
  58. execute_process(
  59. COMMAND ${GIT_EXECUTABLE} ${_git_remote_url_cmd_args}
  60. WORKING_DIRECTORY "${working_directory}"
  61. OUTPUT_VARIABLE git_remote_url
  62. OUTPUT_STRIP_TRAILING_WHITESPACE
  63. COMMAND_ERROR_IS_FATAL LAST
  64. ENCODING UTF-8 # Needed to handle non-ascii characters in local paths
  65. )
  66. set("${output_variable}" "${git_remote_url}" PARENT_SCOPE)
  67. endfunction()
  68. function(_ep_is_relative_git_remote output_variable remote_url)
  69. if(remote_url MATCHES "^\\.\\./")
  70. set("${output_variable}" TRUE PARENT_SCOPE)
  71. else()
  72. set("${output_variable}" FALSE PARENT_SCOPE)
  73. endif()
  74. endfunction()
  75. # Return an absolute remote URL given an existing remote URL and relative path.
  76. # The output_variable will be set to an empty string if an absolute URL
  77. # could not be computed (no error message is output).
  78. function(_ep_resolve_relative_git_remote
  79. output_variable
  80. parent_remote_url
  81. relative_remote_url
  82. )
  83. set("${output_variable}" "" PARENT_SCOPE)
  84. if(parent_remote_url STREQUAL "")
  85. return()
  86. endif()
  87. string(REGEX MATCH
  88. "^(([A-Za-z0-9][A-Za-z0-9+.-]*)://)?(([^/@]+)@)?(\\[[A-Za-z0-9:]+\\]|[^/:]+)?([/:]/?)(.+(\\.git)?/?)$"
  89. git_remote_url_components
  90. "${parent_remote_url}"
  91. )
  92. set(protocol "${CMAKE_MATCH_1}")
  93. set(auth "${CMAKE_MATCH_3}")
  94. set(host "${CMAKE_MATCH_5}")
  95. set(separator "${CMAKE_MATCH_6}")
  96. set(path "${CMAKE_MATCH_7}")
  97. string(REPLACE "/" ";" remote_path_components "${path}")
  98. string(REPLACE "/" ";" relative_path_components "${relative_remote_url}")
  99. foreach(relative_path_component IN LISTS relative_path_components)
  100. if(NOT relative_path_component STREQUAL "..")
  101. break()
  102. endif()
  103. list(LENGTH remote_path_components remote_path_component_count)
  104. if(remote_path_component_count LESS 1)
  105. return()
  106. endif()
  107. list(POP_BACK remote_path_components)
  108. list(POP_FRONT relative_path_components)
  109. endforeach()
  110. list(APPEND final_path_components ${remote_path_components} ${relative_path_components})
  111. list(JOIN final_path_components "/" path)
  112. set("${output_variable}" "${protocol}${auth}${host}${separator}${path}" PARENT_SCOPE)
  113. endfunction()
  114. # The output_variable will be set to the original git_repository if it
  115. # could not be resolved (no error message is output). The original value is
  116. # also returned if it doesn't need to be resolved.
  117. function(_ep_resolve_git_remote
  118. output_variable
  119. git_repository
  120. cmp0150
  121. cmp0150_old_base_dir
  122. )
  123. if(git_repository STREQUAL "")
  124. set("${output_variable}" "" PARENT_SCOPE)
  125. return()
  126. endif()
  127. _ep_is_relative_git_remote(_git_repository_is_relative "${git_repository}")
  128. if(NOT _git_repository_is_relative)
  129. set("${output_variable}" "${git_repository}" PARENT_SCOPE)
  130. return()
  131. endif()
  132. if(cmp0150 STREQUAL "NEW")
  133. _ep_get_git_remote_url(_parent_git_remote_url "${CMAKE_CURRENT_SOURCE_DIR}")
  134. _ep_resolve_relative_git_remote(_resolved_git_remote_url "${_parent_git_remote_url}" "${git_repository}")
  135. if(_resolved_git_remote_url STREQUAL "")
  136. message(FATAL_ERROR
  137. "Failed to resolve relative git remote URL:\n"
  138. " Relative URL: ${git_repository}\n"
  139. " Parent URL: ${_parent_git_remote_url}"
  140. )
  141. endif()
  142. set("${output_variable}" "${_resolved_git_remote_url}" PARENT_SCOPE)
  143. return()
  144. elseif(cmp0150 STREQUAL "")
  145. cmake_policy(GET_WARNING CMP0150 _cmp0150_warning)
  146. message(AUTHOR_WARNING
  147. "${_cmp0150_warning}\n"
  148. "A relative GIT_REPOSITORY path was detected. "
  149. "This will be interpreted as a local path to where the project is being cloned. "
  150. "Set GIT_REPOSITORY to an absolute path or set policy CMP0150 to NEW to avoid "
  151. "this warning."
  152. )
  153. endif()
  154. set("${output_variable}" "${cmp0150_old_base_dir}/${git_repository}" PARENT_SCOPE)
  155. endfunction()