diff --git a/cmake/QtIRGitHelpers.cmake b/cmake/QtIRGitHelpers.cmake index 288f4ac7..d851b65a 100644 --- a/cmake/QtIRGitHelpers.cmake +++ b/cmake/QtIRGitHelpers.cmake @@ -93,9 +93,15 @@ function(qt_ir_run_git_submodule_init submodules working_directory) qt_ir_setup_commit_template("${working_directory}" "${working_directory}") endfunction() -# Add gerrit remotes to the repository. -function(qt_ir_add_git_remotes repo_name working_directory) - set(gerrit_ssh_base "ssh://@USER@codereview.qt-project.org@PORT@/qt/") +# Add gerrit remotes to the repository located in the working_directory. +# repo_relative_url is the relative URL of the repository. +# Examples: +# - qt5 +# - qttools.git +# - ../playground/qlitehtml.git +# - ../qt/qttools-litehtml.git +function(qt_ir_add_git_remotes repo_relative_url working_directory) + set(gerrit_ssh_base "ssh://@USER@codereview.qt-project.org@PORT@/") set(gerrit_repo_url "${gerrit_ssh_base}") qt_ir_get_option_value(codereview-username username) @@ -110,7 +116,10 @@ function(qt_ir_add_git_remotes repo_name working_directory) string(REPLACE "@PORT@" "" gerrit_repo_url "${gerrit_repo_url}") endif() - string(APPEND gerrit_repo_url "${repo_name}") + set(namespace "qt") + set(repo_relative_url_with_namespace "${namespace}/${repo_relative_url}") + qt_ir_normalize_git_url("${repo_relative_url_with_namespace}" normalized_url) + string(APPEND gerrit_repo_url "${normalized_url}") qt_ir_execute_process_and_log_and_handle_error( COMMAND_ARGS git config remote.gerrit.url "${gerrit_repo_url}" @@ -193,15 +202,21 @@ function(qt_ir_clone_one_submodule submodule_name) set(submodule_base_git_path "${${prefix}_${submodule_name}_base_git_path}") set(submodule_url "${submodule_base_git_path}") - qt_ir_has_url_scheme("${submodule_url}" has_url_scheme) + qt_ir_parse_git_url( + URL "${submodule_url}" + OUT_VAR_HAS_URL_SCHEME has_url_scheme + ) + if(NOT has_url_scheme AND arg_BASE_URL) set(submodule_url "${arg_BASE_URL}${submodule_url}") + qt_ir_normalize_git_url("${submodule_url}" submodule_url) endif() qt_ir_get_mirror(mirror_url) set(mirror "") if(NOT has_url_scheme AND mirror_url AND (should_clone OR arg_FETCH)) set(mirror "${mirror_url}${submodule_base_git_path}") + qt_ir_normalize_git_url("${mirror}" mirror) endif() set(mirror_or_original_url "${submodule_url}") diff --git a/cmake/QtIRParsingHelpers.cmake b/cmake/QtIRParsingHelpers.cmake index d7d3f20e..04a34423 100644 --- a/cmake/QtIRParsingHelpers.cmake +++ b/cmake/QtIRParsingHelpers.cmake @@ -40,16 +40,77 @@ function(qt_ir_get_git_config_contents out_var) set(${out_var} "${git_output}" PARENT_SCOPE) endfunction() -# Checks whether the given url has a scheme like https:// or is just a -# relative path. -function(qt_ir_has_url_scheme url out_var) - string(REGEX MATCH "^[a-z][a-z0-9+\-.]*://" has_url_scheme "${url}") +# Parses a git repo url to: +# - check if the given url has a scheme like https:// or git:// or is just a +# relative path with no scheme (possibly containing '../' segments) +# - extracts the scheme if it exists +# - extracts the url without the scheme +function(qt_ir_parse_git_url) + set(options "") + set(oneValueArgs + URL + OUT_VAR_HAS_URL_SCHEME + OUT_VAR_SCHEME + OUT_VAR_URL_WITHOUT_SCHEME + ) + set(multiValueArgs "") + cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + string(REGEX MATCH "^([a-z][a-z0-9+\-.]*://)(.+)" url_scheme_match "${arg_URL}") + + if(url_scheme_match) + set(has_url_scheme TRUE) + set(scheme "${CMAKE_MATCH_1}") + set(url_without_scheme "${CMAKE_MATCH_2}") + else() + set(has_url_scheme FALSE) + set(scheme "") + set(url_without_scheme "${url}") + endif() + + if(arg_OUT_VAR_HAS_URL_SCHEME) + set(${arg_OUT_VAR_HAS_URL_SCHEME} "${has_url_scheme}" PARENT_SCOPE) + endif() + + if(arg_OUT_VAR_SCHEME) + set(${arg_OUT_VAR_SCHEME} "${scheme}" PARENT_SCOPE) + endif() + + if(arg_OUT_VAR_URL_WITHOUT_SCHEME) + set(${arg_OUT_VAR_URL_WITHOUT_SCHEME} "${url_without_scheme}" PARENT_SCOPE) + endif() +endfunction() + +# Normalizes a url that contains '../' path segments. +# Removes the '../' segments and the directories that they precede. +# Example: +# git://code.qt.io/qt/../playground/qlitehtml.git +# will be normalized to: +# git://code.qt.io/playground/qlitehtml.git +function(qt_ir_normalize_git_url url out_var) + # The exact perl code was while ($base =~ s,(?!\.\./)[^/]+/\.\./,,g) {} + # That got rid of ../ and ../../ in the path, but it broke down + # when more than two '../' segments were present. + # + # In CMake, we instead parse the url to get the non-scheme suffix, + # use get_filename_component(ABSOLUTE) to resolve the url as if it was a relative path + # and then re-add the scheme if it was present. + qt_ir_parse_git_url( + URL "${url}" + OUT_VAR_HAS_URL_SCHEME has_url_scheme + OUT_VAR_SCHEME url_scheme + OUT_VAR_URL_WITHOUT_SCHEME url_without_scheme + ) + + # Note the empty BASE_DIR is important, otherwise the path is relative to + # ${CMAKE_CURRENT_SOURCE_DIR}. + get_filename_component(normalized_url "${url_without_scheme}" ABSOLUTE BASE_DIR "") if(has_url_scheme) - set(${out_var} TRUE PARENT_SCOPE) - else() - set(${out_var} FALSE PARENT_SCOPE) + string(PREPEND normalized_url "${url_scheme}") endif() + + set(${out_var} "${normalized_url}" PARENT_SCOPE) endfunction() # Parses a key-value line from a .git/config or .gitmodules file @@ -79,14 +140,22 @@ endmacro() # url_value # the url where to clone a repo from # in perl script it was called $base -# e.g. '../qtbase.git', 'https://code.qt.io/playground/qlitehtml.git' +# Examples: +# - '../qtbase.git' +# - 'https://code.qt.io/playground/qlitehtml.git' +# - '../../playground/qlitehtml.git' # parent_repo_base_git_path # the base git path of the parent of the submodule # it is either a relative dir or a full url # in the perl script it was called $my_repo_base, # it was passed as first arg to git_clone_all_submodules, # it was passed the value of $subbases{$module} when doing recursive submodule cloning -# e.g. 'qt5', 'tqtc-qt5', 'qtdeclarative.git', 'https://code.qt.io/playground/qlitehtml.git' +# Examples: +# - 'qt5' +# - 'tqtc-qt5' +# - 'qtdeclarative.git' +# - 'qttools.git' +# - 'https://code.qt.io/playground/qlitehtml.git' # # Outputs # @@ -94,21 +163,21 @@ endmacro() # just the value of ${url_value} # ${out_var_prefix}_${submodule_name}_base_git_path # the whole url if it has a scheme, otherwise it's the value of -# ${url_value} relative to ${parent_repo_base_git_path}, so all the ../ are collapsed -# e.g. 'qtdeclarative.git' -# 'https://code.qt.io/playground/qlitehtml.git', +# ${url_value} relative to ${parent_repo_base_git_path}, so some of the '../' segments +# are collapsed depending on how many path segments are available in +# ${parent_repo_base_git_path}. +# Examples: +# - 'qtdeclarative.git' +# - 'https://code.qt.io/playground/qlitehtml.git' +# - '../playground/qlitehtml.git' macro(qt_ir_parse_git_url_key out_var_prefix submodule_name url_value parent_repo_base_git_path) - qt_ir_has_url_scheme("${url_value}" has_url_scheme) + qt_ir_parse_git_url( + URL "${url_value}" + OUT_VAR_HAS_URL_SCHEME has_url_scheme + ) if(NOT has_url_scheme) set(base_git_path "${parent_repo_base_git_path}/${url_value}") - - # The exact code perl code was while ($base =~ s,(?!\.\./)[^/]+/\.\./,,g) {} - # That got rid of ../ and ../../ in the path, but it broke down - # when more than two ../ were present. - # We just use ABSOLUTE to resolve the path and get rid of all ../ - # Note the empty BASE_DIR is important, otherwise the path is relative to - # ${CMAKE_CURRENT_SOURCE_DIR}. - get_filename_component(base_git_path "${base_git_path}" ABSOLUTE BASE_DIR "") + qt_ir_normalize_git_url("${base_git_path}" base_git_path) else() set(base_git_path "${url_value}") endif()