Skip to content
6 changes: 5 additions & 1 deletion cmake/ecbuild_bundle.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ endmacro()
# [ BRANCH <gitbranch> | TAG <gittag> ]
# [ UPDATE | NOREMOTE ]
# [ MANUAL ]
# [ RECURSIVE ] )
# [ RECURSIVE ]
# [ SHALLOW ] )
#
# Options
# -------
Expand Down Expand Up @@ -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
# -----
#
Expand Down
59 changes: 50 additions & 9 deletions cmake/ecbuild_git.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ endif()
# [ BRANCH <gitbranch> | TAG <gittag> ]
# [ UPDATE | NOREMOTE ]
# [ MANUAL ]
# [ RECURSIVE ] )
# [ RECURSIVE ]
# [ SHALLOW ] )
#
# Options
# -------
Expand Down Expand Up @@ -60,11 +61,17 @@ 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.
# 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.
#
##############################################################################

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} )
Expand All @@ -77,13 +84,25 @@ 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()

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 )
set( _created_repo 0 )

get_filename_component( ABS_PAR_DIR "${_PAR_DIR}" ABSOLUTE )
get_filename_component( PARENT_DIR "${_PAR_DIR}/.." ABSOLUTE )
Expand All @@ -98,15 +117,26 @@ 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 )
Comment thread
mcakircali marked this conversation as resolved.
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( _created_repo 1 )
set( _needs_switch 1 )

endif()
Expand Down Expand Up @@ -164,7 +194,11 @@ function( ecbuild_git )
set( _needs_switch 1 )
endif()

if( DEFINED _PAR_BRANCH AND _PAR_UPDATE AND NOT _PAR_NOREMOTE )
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 AND NOT _PAR_SHALLOW )

add_custom_target( git_update_${_PAR_PROJECT}
COMMAND "${GIT_EXECUTABLE}" pull -q
Expand All @@ -189,7 +223,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 )
Comment thread
mcakircali marked this conversation as resolved.

ecbuild_info("git fetch --all @ ${ABS_PAR_DIR}")
execute_process( COMMAND "${GIT_EXECUTABLE}" fetch --all -q
Expand Down Expand Up @@ -221,10 +257,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}")
Expand All @@ -235,8 +272,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)
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand Down
10 changes: 10 additions & 0 deletions tests/ecbuild_bundle_shallow/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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}
)
62 changes: 62 additions & 0 deletions tests/ecbuild_bundle_shallow/run-test.sh
Original file line number Diff line number Diff line change
@@ -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
47 changes: 47 additions & 0 deletions tests/ecbuild_bundle_shallow/setup-umbrella-bundle.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/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
# ─────────────────────────────────────────────

UMBRELLA_GIT="file://$(dirname "${UMBRELLA_DIR}")/../bare-repos/$(basename "${UMBRELLA_DIR}").git"

cat > CMakeLists.txt <<EOF

cmake_minimum_required(VERSION 3.18 FATAL_ERROR)

find_package( ecbuild 3.12 REQUIRED HINTS ${CMAKE_SOURCE_DIR} )

project( umbrella-bundle LANGUAGES NONE )

ecbuild_bundle_initialize()

ecbuild_bundle(
PROJECT umbrella
GIT "${UMBRELLA_GIT}"
BRANCH main
RECURSIVE
SHALLOW
)

ecbuild_bundle_finalize()

EOF

cat > VERSION <<EOF
0.0.1
EOF
Loading
Loading