#!/bin/bash
submodule_is_initialized() {
local path="$1"
[[ -e "${path}/.git" ]] || return 1
git -C "${path}" rev-parse --is-inside-work-tree >/dev/null 2>&1
}
submodule_update_block_reason() {
local path="$1"
if ! submodule_is_initialized "${path}"; then
echo "not initialized"
return 0
fi
if [[ -n "$(git -C "${path}" status --porcelain)" ]]; then
echo "has uncommitted changes"
return 0
fi
local head_commit
head_commit="$(git -C "${path}" rev-parse HEAD 2>/dev/null || echo "")"
local expected_commit
expected_commit="$(git ls-tree HEAD "${path}" | awk '{print $3}')"
if [[ "${head_commit}" != "${expected_commit}" ]]; then
echo "currently checked out to ${head_commit:0:7}, expected ${expected_commit:0:7}"
return 0
fi
return 1
}
update_submodules() {
if [[ "${SKIP_SUBMODULES}" == true ]]; then
log_info "Skipping submodule initialization/update (--skip-submodules)."
log_skipped "Git submodules"
return 0
fi
log_info "Synchronizing submodule URLs..."
git submodule sync --recursive >/dev/null
local submodules=()
local sm_path
while IFS= read -r sm_path; do
[[ -n "${sm_path}" ]] && submodules+=("${sm_path}")
done <<< "$(git config --file .gitmodules --get-regexp path | awk '{ print $2 }')"
local to_update=()
local skipped=()
for sm in "${submodules[@]}"; do
local reason
if reason="$(submodule_update_block_reason "${sm}")"; then
if [[ "${reason}" == "not initialized" ]]; then
to_update+=("${sm}")
else
skipped+=("${sm} (${reason})")
fi
else
to_update+=("${sm}")
fi
done
if [[ ${#skipped[@]} -gt 0 ]]; then
log_warn "The following submodules will NOT be updated automatically:"
for sm in "${skipped[@]}"; do
echo " - ${sm}"
done
echo ""
if ! ask_yn "Continue anyway?" "y"; then
log_error "Submodule update aborted by user."
exit 1
fi
fi
if [[ ${#to_update[@]} -gt 0 ]]; then
log_info "Updating submodules..."
for sm in "${to_update[@]}"; do
log_info " -> ${sm}"
run_cmd git submodule update --init --recursive "${sm}"
done
log_done "Submodules updated"
else
log_info "All submodules are up to date."
log_done "Submodules checked"
fi
}