| cmake_policy(VERSION 3.25) | |
| # Determine the remote URL of the project containing the working_directory. | |
| # This will leave output_variable unset if the URL can't be determined. | |
| function(_ep_get_git_remote_url output_variable working_directory) | |
| set("${output_variable}" "" PARENT_SCOPE) | |
| find_package(Git QUIET REQUIRED) | |
| execute_process( | |
| COMMAND ${GIT_EXECUTABLE} symbolic-ref --short HEAD | |
| WORKING_DIRECTORY "${working_directory}" | |
| OUTPUT_VARIABLE git_symbolic_ref | |
| OUTPUT_STRIP_TRAILING_WHITESPACE | |
| ERROR_QUIET | |
| ) | |
| if(NOT git_symbolic_ref STREQUAL "") | |
| # We are potentially on a branch. See if that branch is associated with | |
| # an upstream remote (might be just a local one or not a branch at all). | |
| execute_process( | |
| COMMAND ${GIT_EXECUTABLE} config branch.${git_symbolic_ref}.remote | |
| WORKING_DIRECTORY "${working_directory}" | |
| OUTPUT_VARIABLE git_remote_name | |
| OUTPUT_STRIP_TRAILING_WHITESPACE | |
| ERROR_QUIET | |
| ) | |
| endif() | |
| if(NOT git_remote_name) | |
| # Can't select a remote based on a branch. If there's only one remote, | |
| # or we have multiple remotes but one is called "origin", choose that. | |
| execute_process( | |
| COMMAND ${GIT_EXECUTABLE} remote | |
| WORKING_DIRECTORY "${working_directory}" | |
| OUTPUT_VARIABLE git_remote_list | |
| OUTPUT_STRIP_TRAILING_WHITESPACE | |
| ERROR_QUIET | |
| ) | |
| string(REPLACE "\n" ";" git_remote_list "${git_remote_list}") | |
| list(LENGTH git_remote_list git_remote_list_length) | |
| if(git_remote_list_length EQUAL 0) | |
| message(FATAL_ERROR "Git remote not found in parent project.") | |
| elseif(git_remote_list_length EQUAL 1) | |
| list(GET git_remote_list 0 git_remote_name) | |
| else() | |
| set(base_warning_msg "Multiple git remotes found for parent project") | |
| if("origin" IN_LIST git_remote_list) | |
| message(WARNING "${base_warning_msg}, defaulting to origin.") | |
| set(git_remote_name "origin") | |
| else() | |
| message(FATAL_ERROR "${base_warning_msg}, none of which are origin.") | |
| endif() | |
| endif() | |
| endif() | |
| if(GIT_VERSION VERSION_LESS 1.7.5) | |
| set(_git_remote_url_cmd_args config remote.${git_remote_name}.url) | |
| elseif(GIT_VERSION VERSION_LESS 2.7) | |
| set(_git_remote_url_cmd_args ls-remote --get-url ${git_remote_name}) | |
| else() | |
| set(_git_remote_url_cmd_args remote get-url ${git_remote_name}) | |
| endif() | |
| execute_process( | |
| COMMAND ${GIT_EXECUTABLE} ${_git_remote_url_cmd_args} | |
| WORKING_DIRECTORY "${working_directory}" | |
| OUTPUT_VARIABLE git_remote_url | |
| OUTPUT_STRIP_TRAILING_WHITESPACE | |
| COMMAND_ERROR_IS_FATAL LAST | |
| ENCODING UTF-8 # Needed to handle non-ascii characters in local paths | |
| ) | |
| set("${output_variable}" "${git_remote_url}" PARENT_SCOPE) | |
| endfunction() | |
| function(_ep_is_relative_git_remote output_variable remote_url) | |
| if(remote_url MATCHES "^\\.\\./") | |
| set("${output_variable}" TRUE PARENT_SCOPE) | |
| else() | |
| set("${output_variable}" FALSE PARENT_SCOPE) | |
| endif() | |
| endfunction() | |
| # Return an absolute remote URL given an existing remote URL and relative path. | |
| # The output_variable will be set to an empty string if an absolute URL | |
| # could not be computed (no error message is output). | |
| function(_ep_resolve_relative_git_remote | |
| output_variable | |
| parent_remote_url | |
| relative_remote_url | |
| ) | |
| set("${output_variable}" "" PARENT_SCOPE) | |
| if(parent_remote_url STREQUAL "") | |
| return() | |
| endif() | |
| string(REGEX MATCH | |
| "^(([A-Za-z0-9][A-Za-z0-9+.-]*)://)?(([^/@]+)@)?(\\[[A-Za-z0-9:]+\\]|[^/:]+)?([/:]/?)(.+(\\.git)?/?)$" | |
| git_remote_url_components | |
| "${parent_remote_url}" | |
| ) | |
| set(protocol "${CMAKE_MATCH_1}") | |
| set(auth "${CMAKE_MATCH_3}") | |
| set(host "${CMAKE_MATCH_5}") | |
| set(separator "${CMAKE_MATCH_6}") | |
| set(path "${CMAKE_MATCH_7}") | |
| string(REPLACE "/" ";" remote_path_components "${path}") | |
| string(REPLACE "/" ";" relative_path_components "${relative_remote_url}") | |
| foreach(relative_path_component IN LISTS relative_path_components) | |
| if(NOT relative_path_component STREQUAL "..") | |
| break() | |
| endif() | |
| list(LENGTH remote_path_components remote_path_component_count) | |
| if(remote_path_component_count LESS 1) | |
| return() | |
| endif() | |
| list(POP_BACK remote_path_components) | |
| list(POP_FRONT relative_path_components) | |
| endforeach() | |
| list(APPEND final_path_components ${remote_path_components} ${relative_path_components}) | |
| list(JOIN final_path_components "/" path) | |
| set("${output_variable}" "${protocol}${auth}${host}${separator}${path}" PARENT_SCOPE) | |
| endfunction() | |
| # The output_variable will be set to the original git_repository if it | |
| # could not be resolved (no error message is output). The original value is | |
| # also returned if it doesn't need to be resolved. | |
| function(_ep_resolve_git_remote | |
| output_variable | |
| git_repository | |
| cmp0150 | |
| cmp0150_old_base_dir | |
| ) | |
| if(git_repository STREQUAL "") | |
| set("${output_variable}" "" PARENT_SCOPE) | |
| return() | |
| endif() | |
| _ep_is_relative_git_remote(_git_repository_is_relative "${git_repository}") | |
| if(NOT _git_repository_is_relative) | |
| set("${output_variable}" "${git_repository}" PARENT_SCOPE) | |
| return() | |
| endif() | |
| if(cmp0150 STREQUAL "NEW") | |
| _ep_get_git_remote_url(_parent_git_remote_url "${CMAKE_CURRENT_SOURCE_DIR}") | |
| _ep_resolve_relative_git_remote(_resolved_git_remote_url "${_parent_git_remote_url}" "${git_repository}") | |
| if(_resolved_git_remote_url STREQUAL "") | |
| message(FATAL_ERROR | |
| "Failed to resolve relative git remote URL:\n" | |
| " Relative URL: ${git_repository}\n" | |
| " Parent URL: ${_parent_git_remote_url}" | |
| ) | |
| endif() | |
| set("${output_variable}" "${_resolved_git_remote_url}" PARENT_SCOPE) | |
| return() | |
| elseif(cmp0150 STREQUAL "") | |
| cmake_policy(GET_WARNING CMP0150 _cmp0150_warning) | |
| message(AUTHOR_WARNING | |
| "${_cmp0150_warning}\n" | |
| "A relative GIT_REPOSITORY path was detected. " | |
| "This will be interpreted as a local path to where the project is being cloned. " | |
| "Set GIT_REPOSITORY to an absolute path or set policy CMP0150 to NEW to avoid " | |
| "this warning." | |
| ) | |
| endif() | |
| set("${output_variable}" "${cmp0150_old_base_dir}/${git_repository}" PARENT_SCOPE) | |
| endfunction() |