| 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() |