From f8b8a9a59f8f7eced57e9d68e86f11073eba20a8 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 16 Nov 2020 18:14:49 +0100 Subject: Add a script to synchronize the repo to a consistent (sub)set Make a few modifications to the dependency evaluation to include the revision of each dependency, and a method that checks each dependency out to the revision necessary to create a consistent set for the requested module. If the requested module is ".", check all modules out to the given revision. Can be called (ideally from a git-sync-to alias script): cmake -DSYNC_TO_MODULE="$1" -DSYNC_TO_BRANCH="$2" \ -P cmake/QtSynchronizeRepo.cmake Change-Id: I007e9f9023bae949907b64e264ae7869dff1da2e Reviewed-by: Alexandru Croitor --- cmake/QtSynchronizeRepo.cmake | 3 + cmake/QtTopLevelHelpers.cmake | 142 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 cmake/QtSynchronizeRepo.cmake diff --git a/cmake/QtSynchronizeRepo.cmake b/cmake/QtSynchronizeRepo.cmake new file mode 100644 index 00000000..522ea76e --- /dev/null +++ b/cmake/QtSynchronizeRepo.cmake @@ -0,0 +1,3 @@ +include(cmake/QtTopLevelHelpers.cmake) + +qt_internal_sync_to(${SYNC_TO_MODULE} ${SYNC_TO_BRANCH}) diff --git a/cmake/QtTopLevelHelpers.cmake b/cmake/QtTopLevelHelpers.cmake index 4aa560e3..b5ce1e8a 100644 --- a/cmake/QtTopLevelHelpers.cmake +++ b/cmake/QtTopLevelHelpers.cmake @@ -14,20 +14,30 @@ endfunction() # poor man's yaml parser, populating $out_dependencies with all dependencies # in the $depends_file +# Each entry will be in the format dependency/sha1 function(qt_internal_parse_dependencies depends_file out_dependencies) file(STRINGS "${depends_file}" lines) set(dependencies "") + set(dependency "") foreach(line IN LISTS lines) if(line STREQUAL "dependencies:") set(found_dependencies 1) - elseif(found_dependencies AND line MATCHES "^ (.*):$") - set(dependency ${CMAKE_MATCH_1}) - # dependencies are specified with relative path to this module - string(REPLACE "../" "" dependency ${dependency}) - list(APPEND dependencies ${dependency}) + elseif(found_dependencies) + if(line MATCHES "^ ref: (.*)$") + set(revision "${CMAKE_MATCH_1}") + list(APPEND dependencies ${dependency}/${revision}) + set(dependency "") + elseif (line MATCHES "^ (.*):$") + if(dependency) + message(FATAL_ERROR "Format error in ${depends_file} - ${dependency} does not specify revision!") + endif() + set(dependency "${CMAKE_MATCH_1}") + # dependencies are specified with relative path to this module + string(REPLACE "../" "" dependency ${dependency}) + endif() endif() endforeach() - message(DEBUG "qt_internal_parse_dependencies for ${depends_file}: ${module_list}") + message(DEBUG "qt_internal_parse_dependencies for ${depends_file}: ${dependencies} ${revisions}") set(${out_dependencies} "${dependencies}" PARENT_SCOPE) endfunction() @@ -38,7 +48,7 @@ endfunction() # dependencies. # Function calls itself recursively if a dependency is found that is not yet in $ordered. function(qt_internal_add_module_dependencies module ordered out_ordered out_has_dependencies - out_module_dependencies) + out_module_dependencies out_revisions) set(depends_file "${CMAKE_CURRENT_SOURCE_DIR}/${module}/dependencies.yaml") if(NOT EXISTS "${depends_file}") set(${out_has_dependencies} "" PARENT_SCOPE) @@ -46,28 +56,39 @@ function(qt_internal_add_module_dependencies module ordered out_ordered out_has_ endif() set(${out_has_dependencies} "1" PARENT_SCOPE) set(dependencies "") - qt_internal_parse_dependencies(${depends_file} dependencies) + qt_internal_parse_dependencies("${depends_file}" dependencies) # module hasn't been seen yet, append it list(FIND ordered "${module}" pindex) if (pindex EQUAL -1) list(LENGTH ordered pindex) - list(APPEND ordered ${module}) + list(APPEND ordered "${module}") + list(APPEND revisions "HEAD") endif() + set(modules_dependencies "") foreach(dependency IN LISTS dependencies) + string(FIND "${dependency}" "/" splitindex REVERSE) + string(SUBSTRING "${dependency}" ${splitindex} -1 revision) + string(SUBSTRING "${revision}" 1 -1 revision) + string(SUBSTRING "${dependency}" 0 ${splitindex} dependency) + list(APPEND modules_dependencies "${dependency}") list(FIND ordered "${dependency}" dindex) if (dindex EQUAL -1) # dependency hasnt' been seen yet - load it list(INSERT ordered ${pindex} "${dependency}") + list(INSERT revisions ${pindex} "${revision}") qt_internal_add_module_dependencies(${dependency} "${ordered}" ordered has_dependency - "${out_module_dependencies}") + "${out_module_dependencies}" revisions) elseif(dindex GREATER pindex) # otherwise, make sure it is before module list(REMOVE_AT ordered ${dindex}) + list(REMOVE_AT revisions ${dindex}) list(INSERT ordered ${pindex} "${dependency}") + list(INSERT revisions ${pindex} "${revision}") endif() endforeach() set(${out_ordered} "${ordered}" PARENT_SCOPE) - set(${out_module_dependencies} ${${out_module_dependencies}} ${dependencies} PARENT_SCOPE) + set(${out_module_dependencies} ${${out_module_dependencies}} ${modules_dependencies} PARENT_SCOPE) + set(${out_revisions} "${revisions}" PARENT_SCOPE) endfunction() # populates $out_all_ordered with the sequence of the modules that need @@ -82,7 +103,7 @@ function(qt_internal_sort_module_dependencies modules out_all_ordered dependenci endif() set(module_dependencies_list_var_name "${dependencies_map_prefix}${module}") qt_internal_add_module_dependencies(${module} "${ordered}" out_ordered module_depends - "${module_dependencies_list_var_name}") + "${module_dependencies_list_var_name}" revisions) set(${module_dependencies_list_var_name} "${${module_dependencies_list_var_name}}" PARENT_SCOPE) if(NOT module_depends) @@ -96,3 +117,100 @@ function(qt_internal_sort_module_dependencies modules out_all_ordered dependenci message(DEBUG "qt_internal_parse_dependencies sorted ${modules}: ${ordered}") set(${out_all_ordered} "${ordered}" PARENT_SCOPE) endfunction() + +# does what it says, but also updates submodules +function(qt_internal_checkout module revision) + message(NOTICE "Checking '${module}' out to revision '${revision}'") + execute_process( + COMMAND "git" "checkout" "${revision}" + WORKING_DIRECTORY "./${module}" + RESULT_VARIABLE git_result + OUTPUT_VARIABLE git_stdout + ERROR_VARIABLE git_stderr + ) + if (VERBOSE) + message(NOTICE ${git_stdout}) + endif() + if (git_result) + message(WARNING "${git_stdout}") + message(FATAL_ERROR "Failed to check '${module}' out to '${revision}': ${git_stderr}") + endif() + execute_process( + COMMAND "git" "submodule" "update" + WORKING_DIRECTORY "./${module}" + RESULT_VARIABLE git_result + OUTPUT_VARIABLE git_stdout + ERROR_VARIABLE git_stderr + ) +endfunction() + +# evaluates the dependencies for $module, and checks all dependencies +# out so that it is a consistent set +function(qt_internal_sync_to module) + if(ARGN) + set(revision "${ARGV1}") + # special casing "." as the target module - checkout all out to $revision + if("${module}" STREQUAL ".") + qt_internal_find_modules(modules) + foreach(module IN LISTS modules) + qt_internal_checkout("${module}" "${revision}") + endforeach() + return() + endif() + else() + set(revision "HEAD") + endif() + qt_internal_checkout("${module}" "${revision}") + + set(revision "") + set(checkedout "1") + # Load all dependencies for $module, then iterate over the dependencies in reverse order, + # and check out the first that isn't already at the required revision. + # Repeat everything (we need to reload dependencies after each checkout) until no more checkouts + # are done. + while(${checkedout}) + set(dependencies "") + set(revisions "") + set(prefix "") + qt_internal_add_module_dependencies(${module} "${dependencies}" dependencies has_dependencies prefix revisions) + message(DEBUG "${module} dependencies: ${dependencies}") + message(DEBUG "${module} revisions : ${revisions}") + + if (NOT has_dependencies) + message(NOTICE "Module ${module} has no dependencies") + return() + endif() + + list(LENGTH dependencies count) + math(EXPR count "${count} - 1") + set(checkedout 0) + foreach(i RANGE ${count} 0 -1 ) + list(GET dependencies ${i} dependency) + list(GET revisions ${i} revision) + if ("${revision}" STREQUAL "HEAD") + message(DEBUG "Not changing checked out revision of ${dependency}") + continue() + endif() + + execute_process( + COMMAND "git" "rev-parse" "HEAD" + WORKING_DIRECTORY "./${dependency}" + RESULT_VARIABLE git_result + OUTPUT_VARIABLE git_stdout + ERROR_VARIABLE git_stderr + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if (git_result) + message(WARNING "${git_stdout}") + message(FATAL_ERROR "Failed to get current HEAD of '${dependency}': ${git_stderr}") + endif() + if ("${git_stdout}" STREQUAL "${revision}") + continue() + endif() + + qt_internal_checkout("${dependency}" "${revision}") + set(checkedout 1) + break() + endforeach() + endwhile() +endfunction() -- cgit v1.2.3