From eda5abad72da6c6f33fb2dc28518c4bbb08f5089 Mon Sep 17 00:00:00 2001 From: Metin Cakircali Date: Thu, 21 May 2026 17:51:52 +0200 Subject: [PATCH 01/10] shallow clone --- cmake/ecbuild_git.cmake | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/cmake/ecbuild_git.cmake b/cmake/ecbuild_git.cmake index 13763c17..cc8eaf10 100644 --- a/cmake/ecbuild_git.cmake +++ b/cmake/ecbuild_git.cmake @@ -64,7 +64,7 @@ endif() function( ecbuild_git ) - set( options UPDATE NOREMOTE MANUAL RECURSIVE ) + set( options UPDATE NOREMOTE MANUAL RECURSIVE SHALLOW ) set( single_value_args PROJECT DIR URL TAG BRANCH ) set( multi_value_args ) cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} ) @@ -98,13 +98,23 @@ function( ecbuild_git ) if( NOT EXISTS "${_PAR_DIR}" ) + set( _clone_args ) + if( _PAR_SHALLOW ) + list( APPEND _clone_args "--depth" "1" ) + if( DEFINED _PAR_BRANCH ) + list( APPEND _clone_args "--branch" "${_PAR_BRANCH}" ) + elseif( DEFINED _PAR_TAG ) + list( APPEND _clone_args "--branch" "${_PAR_TAG}" ) + endif() + endif() + ecbuild_info( "Cloning ${_PAR_PROJECT} from ${_PAR_URL} into ${_PAR_DIR}...") execute_process( - COMMAND ${GIT_EXECUTABLE} "clone" ${_PAR_URL} ${clone_args} ${_PAR_DIR} "-q" + COMMAND ${GIT_EXECUTABLE} "clone" ${_PAR_URL} ${_clone_args} ${_PAR_DIR} "-q" RESULT_VARIABLE nok ERROR_VARIABLE error WORKING_DIRECTORY "${PARENT_DIR}") if(nok) - ecbuild_critical("${_PAR_DIR} git clone failed:\n ${GIT_EXECUTABLE} clone ${_PAR_URL} ${clone_args} ${_PAR_DIR} -q\n ${error}\n") + ecbuild_critical("${_PAR_DIR} git clone failed:\n ${GIT_EXECUTABLE} clone ${_PAR_URL} ${_clone_args} ${_PAR_DIR} -q\n ${error}\n") endif() ecbuild_info( "${_PAR_DIR} retrieved.") set( _needs_switch 1 ) @@ -235,8 +245,12 @@ function( ecbuild_git ) endif() #################################################################################### if( _PAR_RECURSIVE ) - ecbuild_info("git submodule --quiet update --init --recursive @ ${ABS_PAR_DIR}") - execute_process( COMMAND "${GIT_EXECUTABLE}" submodule --quiet update --init --recursive + set( _submodule_args submodule --quiet update --init --recursive ) + if( _PAR_SHALLOW ) + list( APPEND _submodule_args "--depth" "1" ) + endif() + ecbuild_info("git ${_submodule_args} @ ${ABS_PAR_DIR}") + execute_process( COMMAND "${GIT_EXECUTABLE}" ${_submodule_args} RESULT_VARIABLE nok ERROR_VARIABLE error WORKING_DIRECTORY "${ABS_PAR_DIR}") if(nok) From c04134a5021bb7e66b4bb088aa480e3fa96ce7ab Mon Sep 17 00:00:00 2001 From: Metin Cakircali Date: Thu, 21 May 2026 18:59:49 +0200 Subject: [PATCH 02/10] add doc for shallow option --- cmake/ecbuild_git.cmake | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmake/ecbuild_git.cmake b/cmake/ecbuild_git.cmake index cc8eaf10..49331a25 100644 --- a/cmake/ecbuild_git.cmake +++ b/cmake/ecbuild_git.cmake @@ -28,7 +28,8 @@ endif() # [ BRANCH | TAG ] # [ UPDATE | NOREMOTE ] # [ MANUAL ] -# [ RECURSIVE ] ) +# [ RECURSIVE ] +# [ SHALLOW ] ) # # Options # ------- @@ -60,6 +61,10 @@ endif() # RECURSIVE : optional # Do a recursive fetch or update # +# SHALLOW : optional +# Do a shallow clone (``--depth 1``) on initial checkout. +# When combined with RECURSIVE, submodules are also fetched at depth 1. +# ############################################################################## function( ecbuild_git ) From 39b22d3feb15f9a45aaff621b74af5adc3a3091e Mon Sep 17 00:00:00 2001 From: Metin Cakircali Date: Thu, 21 May 2026 19:10:01 +0200 Subject: [PATCH 03/10] skip fetch and pull when shallow --- cmake/ecbuild_git.cmake | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmake/ecbuild_git.cmake b/cmake/ecbuild_git.cmake index 49331a25..1d4fafdf 100644 --- a/cmake/ecbuild_git.cmake +++ b/cmake/ecbuild_git.cmake @@ -204,7 +204,9 @@ function( ecbuild_git ) # fetching latest tags and branches - if( NOT _PAR_NOREMOTE ) + if( _PAR_SHALLOW ) + ecbuild_info("${_PAR_DIR} is SHALLOW : Skipping fetch") + elseif( NOT _PAR_NOREMOTE ) ecbuild_info("git fetch --all @ ${ABS_PAR_DIR}") execute_process( COMMAND "${GIT_EXECUTABLE}" fetch --all -q @@ -236,10 +238,11 @@ function( ecbuild_git ) ecbuild_critical("git checkout ${_gitref} on ${_PAR_DIR} failed:\n ${GIT_EXECUTABLE} checkout -q ${_gitref}\n ${error}") endif() - if( DEFINED _PAR_BRANCH AND _PAR_UPDATE ) ############################################################################# + if( DEFINED _PAR_BRANCH AND _PAR_UPDATE AND NOT _PAR_SHALLOW ) ############################# # Use git pull --ff-only, we WANT this to fail on upstream rebase and # we DON'T want merge commits here! + # Skipped for SHALLOW clones to avoid deepening history. execute_process( COMMAND "${GIT_EXECUTABLE}" pull -q --ff-only RESULT_VARIABLE nok ERROR_VARIABLE error WORKING_DIRECTORY "${ABS_PAR_DIR}") From d543574ebcd77c9bf07ba2c1cec066a54faf6b5d Mon Sep 17 00:00:00 2001 From: Metin Cakircali Date: Thu, 21 May 2026 19:43:53 +0200 Subject: [PATCH 04/10] add doc for shallow option to ecbuild_bundle --- cmake/ecbuild_bundle.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/ecbuild_bundle.cmake b/cmake/ecbuild_bundle.cmake index c68e5213..a6d0535d 100644 --- a/cmake/ecbuild_bundle.cmake +++ b/cmake/ecbuild_bundle.cmake @@ -66,7 +66,8 @@ endmacro() # [ BRANCH | TAG ] # [ UPDATE | NOREMOTE ] # [ MANUAL ] -# [ RECURSIVE ] ) +# [ RECURSIVE ] +# [ SHALLOW ] ) # # Options # ------- @@ -101,6 +102,9 @@ endmacro() # RECURSIVE : optional # Do a recursive fetch or update # +# SHALLOW : optional +# Do a shallow clone (depth=1). See ``ecbuild_git`` for details. +# # Usage # ----- # From bdacb96d9e77d4d92df92ae27b438a2c3eacf96c Mon Sep 17 00:00:00 2001 From: Metin Cakircali Date: Fri, 22 May 2026 09:32:12 +0200 Subject: [PATCH 05/10] guard commit id for shallow --- cmake/ecbuild_git.cmake | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmake/ecbuild_git.cmake b/cmake/ecbuild_git.cmake index 1d4fafdf..93d6e5fc 100644 --- a/cmake/ecbuild_git.cmake +++ b/cmake/ecbuild_git.cmake @@ -64,6 +64,7 @@ endif() # SHALLOW : optional # Do a shallow clone (``--depth 1``) on initial checkout. # When combined with RECURSIVE, submodules are also fetched at depth 1. +# Cannot be combined with TAG when it's a commit ID (SHA) # ############################################################################## @@ -86,6 +87,13 @@ function( ecbuild_git ) ecbuild_critical("Unknown keywords given to ecbuild_git(): \"${_PAR_UNPARSED_ARGUMENTS}\"") endif() + if( _PAR_SHALLOW AND DEFINED _PAR_TAG ) + string(LENGTH "${_PAR_TAG}" _tag_len) + if( _tag_len GREATER_EQUAL 7 AND _tag_len LESS_EQUAL 40 AND _PAR_TAG MATCHES "^[0-9a-fA-F]+$" ) + ecbuild_critical("SHALLOW cloning cannot be used: TAG (${_PAR_TAG}) looks like a commit ID (SHA)!") + endif() + endif() + if( ECBUILD_GIT ) set( _needs_switch 0 ) From f20d7f2465f5c9c7c4c056afa2e9581ed868c125 Mon Sep 17 00:00:00 2001 From: Metin Cakircali Date: Fri, 22 May 2026 09:48:13 +0200 Subject: [PATCH 06/10] guard switching for shallow --- cmake/ecbuild_git.cmake | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cmake/ecbuild_git.cmake b/cmake/ecbuild_git.cmake index 93d6e5fc..69ba1af9 100644 --- a/cmake/ecbuild_git.cmake +++ b/cmake/ecbuild_git.cmake @@ -64,7 +64,8 @@ endif() # SHALLOW : optional # Do a shallow clone (``--depth 1``) on initial checkout. # When combined with RECURSIVE, submodules are also fetched at depth 1. -# Cannot be combined with TAG when it's a commit ID (SHA) +# Cannot be combined with TAG when it's a commit ID (SHA). +# SHALLOW is not switchable and will fail if UPDATE is requested on an existing shallow clone. # ############################################################################## @@ -97,6 +98,7 @@ function( ecbuild_git ) if( ECBUILD_GIT ) set( _needs_switch 0 ) + set( _created_repo 0 ) get_filename_component( ABS_PAR_DIR "${_PAR_DIR}" ABSOLUTE ) get_filename_component( PARENT_DIR "${_PAR_DIR}/.." ABSOLUTE ) @@ -130,6 +132,7 @@ function( ecbuild_git ) ecbuild_critical("${_PAR_DIR} git clone failed:\n ${GIT_EXECUTABLE} clone ${_PAR_URL} ${_clone_args} ${_PAR_DIR} -q\n ${error}\n") endif() ecbuild_info( "${_PAR_DIR} retrieved.") + set( _created_repo 1 ) set( _needs_switch 1 ) endif() @@ -187,6 +190,10 @@ function( ecbuild_git ) set( _needs_switch 1 ) endif() + if( _PAR_SHALLOW AND _needs_switch AND NOT _created_repo ) + ecbuild_critical("SHALLOW repository ${_PAR_DIR} is not switchable.") + endif() + if( DEFINED _PAR_BRANCH AND _PAR_UPDATE AND NOT _PAR_NOREMOTE ) add_custom_target( git_update_${_PAR_PROJECT} From c8811ce4b0d1cdafd2d8f0aed28e93674a123fcf Mon Sep 17 00:00:00 2001 From: Metin Cakircali Date: Fri, 22 May 2026 15:01:30 +0200 Subject: [PATCH 07/10] guard pull for shallow --- cmake/ecbuild_git.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/ecbuild_git.cmake b/cmake/ecbuild_git.cmake index 69ba1af9..54bb3bdc 100644 --- a/cmake/ecbuild_git.cmake +++ b/cmake/ecbuild_git.cmake @@ -194,7 +194,7 @@ function( ecbuild_git ) ecbuild_critical("SHALLOW repository ${_PAR_DIR} is not switchable.") endif() - if( DEFINED _PAR_BRANCH AND _PAR_UPDATE AND NOT _PAR_NOREMOTE ) + if( DEFINED _PAR_BRANCH AND _PAR_UPDATE AND NOT _PAR_NOREMOTE AND NOT _PAR_SHALLOW ) add_custom_target( git_update_${_PAR_PROJECT} COMMAND "${GIT_EXECUTABLE}" pull -q From d9a0d6608fcfe2f5f3260c4a635802fb09707e6d Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Wed, 27 May 2026 11:15:22 +0100 Subject: [PATCH 08/10] Add test for ecbuild_bundle with shallow option --- tests/CMakeLists.txt | 1 + tests/ecbuild_bundle_shallow/CMakeLists.txt | 10 ++ tests/ecbuild_bundle_shallow/run-test.sh | 62 +++++++++ .../setup-umbrella-bundle.sh | 44 +++++++ .../setup-umbrella-project.sh | 118 ++++++++++++++++++ 5 files changed, 235 insertions(+) create mode 100644 tests/ecbuild_bundle_shallow/CMakeLists.txt create mode 100755 tests/ecbuild_bundle_shallow/run-test.sh create mode 100644 tests/ecbuild_bundle_shallow/setup-umbrella-bundle.sh create mode 100644 tests/ecbuild_bundle_shallow/setup-umbrella-project.sh diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d6b82683..9cecbc06 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,6 +7,7 @@ add_subdirectory( ecbuild_remove_fortran_flags ) # ECBUILD-484 add_subdirectory( ecbuild_add_option ) add_subdirectory( ecbuild_add_option_multiproject_defaults ) add_subdirectory( ecbuild_add_flags ) +add_subdirectory( ecbuild_bundle_shallow ) add_subdirectory( ecbuild_find_package ) add_subdirectory( ecbuild_find_python ) add_subdirectory( find_ecbuild ) diff --git a/tests/ecbuild_bundle_shallow/CMakeLists.txt b/tests/ecbuild_bundle_shallow/CMakeLists.txt new file mode 100644 index 00000000..74a82e34 --- /dev/null +++ b/tests/ecbuild_bundle_shallow/CMakeLists.txt @@ -0,0 +1,10 @@ + +ecbuild_add_test( + TARGET test_ecbuild_bundle_shallow + TYPE SCRIPT + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/run-test.sh + ENVIRONMENT + CMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR} + CMAKE_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} + CMAKE_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} +) diff --git a/tests/ecbuild_bundle_shallow/run-test.sh b/tests/ecbuild_bundle_shallow/run-test.sh new file mode 100755 index 00000000..12d415e1 --- /dev/null +++ b/tests/ecbuild_bundle_shallow/run-test.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash + +set -e +set -x + +HERE="$( cd $( dirname "${BASH_SOURCE[0]}" ) && pwd -P )" + +ECBUILD_PATH=${CMAKE_SOURCE_DIR}/bin +SOURCE_TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR} +BINARY_TEST_DIR=${CMAKE_CURRENT_BINARY_DIR} + +# Git 2.38.1+ blocks local file:// submodule clones by default. +# Allow them for the duration of this script only. +export GIT_CONFIG_COUNT=1 +export GIT_CONFIG_KEY_0=protocol.file.allow +export GIT_CONFIG_VALUE_0=always + +# Add ecbuild to path +export PATH=$ECBUILD_PATH:$PATH + +# ---- cleanup ----------------------------------------- +rm -rf "${BINARY_TEST_DIR}/workspace" + +# ---- setup umbrella project (with submodules) -------- +cd "${BINARY_TEST_DIR}" +bash "${SOURCE_TEST_DIR}/setup-umbrella-project.sh" \ + "${BINARY_TEST_DIR}/workspace/projects" + +# ---- setup umbrella bundle --------------------------- +cd "${BINARY_TEST_DIR}" +bash "${SOURCE_TEST_DIR}/setup-umbrella-bundle.sh" \ + "${BINARY_TEST_DIR}/workspace/bundle" \ + "${BINARY_TEST_DIR}/workspace/projects/umbrella" + +# ---- configure umbrella bundle ----------------------- +cd ${BINARY_TEST_DIR}/workspace +mkdir build +cd build +ecbuild --prefix=$(pwd)/install -- ../bundle + +# ---- check shallowness (umbrella) -------------------- +cd ${BINARY_TEST_DIR}/workspace/bundle/umbrella + +if [[ "$(git rev-parse --is-shallow-repository)" == "true" ]]; then + echo "Submodule is shallow: PASS" + exit 0 +else + echo "Submodule is not shallow: FAIL" + exit 1 +fi + +# ---- check shallowness (umbrella submodules) --------- +for sub in alpha beta gamma; do + cd "${BINARY_TEST_DIR}/workspace/bundle/umbrella/${sub}" + + if [[ "$(git rev-parse --is-shallow-repository)" == "true" ]]; then + echo "Submodule $sub is shallow: PASS" + else + echo "Submodule $sub is not shallow: FAIL" + exit 1 + fi +done diff --git a/tests/ecbuild_bundle_shallow/setup-umbrella-bundle.sh b/tests/ecbuild_bundle_shallow/setup-umbrella-bundle.sh new file mode 100644 index 00000000..13c6e139 --- /dev/null +++ b/tests/ecbuild_bundle_shallow/setup-umbrella-bundle.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +# ───────────────────────────────────────────── +# Configuration +# ───────────────────────────────────────────── +BASE_DIR="${1:-$(pwd)/bundle}" +UMBRELLA_DIR="${2:-$(pwd)/projects/umbrella}" + +echo "==> Creating bundle workspace at: $BASE_DIR" +mkdir -p "$BASE_DIR" +cd "$BASE_DIR" + +# ───────────────────────────────────────────── +# Create the umbrella bundle +# ───────────────────────────────────────────── +cat > CMakeLists.txt < VERSION < Creating workspace at: $BASE_DIR" +mkdir -p "$BASE_DIR" +cd "$BASE_DIR" + +# ───────────────────────────────────────────── +# Helper: make a commit +# ───────────────────────────────────────────── +commit() { + git add -A + git commit -m "$1" +} + +# ───────────────────────────────────────────── +# Create the 3 dummy projects +# ───────────────────────────────────────────── +for proj in "${PROJECTS[@]}"; do + echo "" + echo "──> Setting up project: $proj" + mkdir -p "$proj" + cd "$proj" + git init -b main + git config user.email "demo@example.com" + git config user.name "Demo User" + + # Initial commit with README + cat > README.md < "src/$proj.sh" <> README.md < config.env < Setting up umbrella project: $UMBRELLA" +mkdir -p "$UMBRELLA" +cd "$UMBRELLA" +git init -b main +git config user.email "demo@example.com" +git config user.name "Demo User" + +# Initial README +cat > README.md < CMakeLists.txt < $SUBMOD_PATH" +done +commit "Add submodules: alpha, beta, gamma" + +# A follow-up commit that records a pinned state +cat >> README.md < Date: Wed, 27 May 2026 13:13:31 +0200 Subject: [PATCH 09/10] fix test shallow option --- .../ecbuild_bundle_shallow/setup-umbrella-bundle.sh | 5 ++++- .../setup-umbrella-project.sh | 13 +++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/tests/ecbuild_bundle_shallow/setup-umbrella-bundle.sh b/tests/ecbuild_bundle_shallow/setup-umbrella-bundle.sh index 13c6e139..3902ab82 100644 --- a/tests/ecbuild_bundle_shallow/setup-umbrella-bundle.sh +++ b/tests/ecbuild_bundle_shallow/setup-umbrella-bundle.sh @@ -17,6 +17,9 @@ cd "$BASE_DIR" # ───────────────────────────────────────────── # Create the umbrella bundle # ───────────────────────────────────────────── + +UMBRELLA_GIT="file://$(dirname "${UMBRELLA_DIR}")/../bare-repos/$(basename "${UMBRELLA_DIR}").git" + cat > CMakeLists.txt < $SUBMOD_PATH" + git clone --bare "$BASE_DIR/$proj" "$BARE_DIR/$proj.git" >/dev/null 2>&1 + git submodule add "file://$BARE_DIR/$proj.git" "$proj" done commit "Add submodules: alpha, beta, gamma" @@ -116,3 +118,6 @@ Submodule remotes point to local sibling directories for demo purposes. Replace the URLs in \`.gitmodules\` with real remote URLs before sharing. EOF commit "docs: note about submodule remote URLs" + +# IMPORTANT: bare repo to ensure shallow clone behavior is honored +git clone --bare "$(pwd)" "$BARE_DIR/$UMBRELLA.git" >/dev/null 2>&1 From 4a25639bd1d6a5e8185ff6b80a2da031868c9763 Mon Sep 17 00:00:00 2001 From: Metin Cakircali Date: Wed, 27 May 2026 13:25:30 +0200 Subject: [PATCH 10/10] add warning for update + shallow --- cmake/ecbuild_git.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/ecbuild_git.cmake b/cmake/ecbuild_git.cmake index 54bb3bdc..6a35113d 100644 --- a/cmake/ecbuild_git.cmake +++ b/cmake/ecbuild_git.cmake @@ -84,6 +84,10 @@ function( ecbuild_git ) ecbuild_critical( "Cannot pass both NOREMOTE and UPDATE in macro ecbuild_git" ) endif() + if( _PAR_UPDATE AND _PAR_SHALLOW ) + ecbuild_warn("UPDATE and SHALLOW conflict — shallow clones aren't switchable; UPDATE may be ignored or fail.") + endif() + if(_PAR_UNPARSED_ARGUMENTS) ecbuild_critical("Unknown keywords given to ecbuild_git(): \"${_PAR_UNPARSED_ARGUMENTS}\"") endif()