227 lines
6.9 KiB
Bash
Executable File
227 lines
6.9 KiB
Bash
Executable File
#!/bin/sh
|
|
# Update mars-nwe submodules.
|
|
#
|
|
# Policy:
|
|
# - mars-* / private submodules are updated to their latest configured branch;
|
|
# - external upstream submodules are checked out at release tags;
|
|
# - nested submodules are initialized, but are not blindly advanced with
|
|
# --remote --recursive.
|
|
|
|
set -eu
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Edit external release pins here.
|
|
# Add one PATH=TAG line per external repository.
|
|
# PATH is relative to the mars-nwe root.
|
|
# -----------------------------------------------------------------------------
|
|
EXTERNAL_TAG_PINS='third_party/yyjson=0.12.0
|
|
third_party/zlog=1.2.18
|
|
third_party/libsodium/libsodium=1.0.20-FINAL'
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Auto-commit root gitlink changes after a successful update.
|
|
# Set AUTO_COMMIT=0 or pass --no-commit to disable.
|
|
# -----------------------------------------------------------------------------
|
|
AUTO_COMMIT=1
|
|
AUTO_COMMIT_MESSAGE='Update submodule pins'
|
|
|
|
usage() {
|
|
cat <<USAGE
|
|
Usage: ./update-submodules.sh [options]
|
|
|
|
Options:
|
|
--init-only Do not fetch/merge remotes or checkout tag pins; only
|
|
initialize/update everything to the commits pinned by
|
|
the current superproject and submodules.
|
|
|
|
--no-default-tags Do not use the built-in external release pins.
|
|
|
|
--tag PATH=TAG Pin an external submodule to TAG after updating. Can be
|
|
given more than once. PATH is relative to the mars-nwe
|
|
root, for example third_party/yyjson or
|
|
third_party/libsodium/libsodium.
|
|
|
|
--no-commit Do not automatically commit root gitlink changes.
|
|
|
|
--commit-message TEXT Commit message used when AUTO_COMMIT is enabled.
|
|
|
|
Default tag pins:
|
|
$(printf '%s\n' "$EXTERNAL_TAG_PINS" | sed 's/^/ /')
|
|
|
|
This script intentionally does not run:
|
|
git submodule update --remote --merge --recursive
|
|
|
|
That command would also try to advance nested external submodules, e.g.
|
|
third_party/libsodium/libsodium, instead of keeping them on the selected
|
|
release tag.
|
|
USAGE
|
|
}
|
|
|
|
init_only=0
|
|
use_default_tags=1
|
|
extra_tag_pins=''
|
|
status_printed=0
|
|
|
|
print_status() {
|
|
status_printed=1
|
|
echo "Current recursive submodule status:"
|
|
git submodule status --recursive || true
|
|
}
|
|
|
|
on_exit() {
|
|
rc=$?
|
|
if [ -f .gitmodules ] && [ "$status_printed" -eq 0 ]; then
|
|
print_status
|
|
fi
|
|
if [ "$rc" -ne 0 ]; then
|
|
echo "update-submodules.sh failed with exit code $rc" >&2
|
|
fi
|
|
exit "$rc"
|
|
}
|
|
trap on_exit EXIT
|
|
|
|
add_tag_pin() {
|
|
case "$1" in
|
|
*=*) extra_tag_pins=${extra_tag_pins}${extra_tag_pins:+"
|
|
"}$1 ;;
|
|
*) echo "error: --tag expects PATH=TAG, got '$1'" >&2; exit 2 ;;
|
|
esac
|
|
}
|
|
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
--init-only) init_only=1; shift ;;
|
|
--no-default-tags) use_default_tags=0; shift ;;
|
|
--no-commit) AUTO_COMMIT=0; shift ;;
|
|
--commit-message)
|
|
[ "$#" -ge 2 ] || { echo "error: --commit-message needs text" >&2; exit 2; }
|
|
AUTO_COMMIT_MESSAGE=$2
|
|
shift 2
|
|
;;
|
|
--commit-message=*) AUTO_COMMIT_MESSAGE=${1#--commit-message=}; shift ;;
|
|
--tag)
|
|
[ "$#" -ge 2 ] || { echo "error: --tag needs PATH=TAG" >&2; exit 2; }
|
|
add_tag_pin "$2"
|
|
shift 2
|
|
;;
|
|
--tag=*) add_tag_pin "${1#--tag=}"; shift ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) usage >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
tag_pins=''
|
|
if [ "$use_default_tags" -eq 1 ]; then
|
|
tag_pins=$EXTERNAL_TAG_PINS
|
|
fi
|
|
if [ -n "$extra_tag_pins" ]; then
|
|
tag_pins=${tag_pins}${tag_pins:+"
|
|
"}$extra_tag_pins
|
|
fi
|
|
|
|
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
|
cd "$script_dir"
|
|
|
|
if [ ! -f .gitmodules ]; then
|
|
echo "error: .gitmodules not found; run this from the mars-nwe root" >&2
|
|
exit 1
|
|
fi
|
|
|
|
pin_tag() {
|
|
path=$1
|
|
tag=$2
|
|
|
|
if [ ! -d "$path" ]; then
|
|
echo "error: cannot pin '$path': directory does not exist" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "==> $path: checking out tag $tag"
|
|
|
|
# Fetch tags when a remote is configured. If the machine is offline but the
|
|
# tag is already present locally, continue and try the checkout anyway.
|
|
if git -C "$path" remote get-url origin >/dev/null 2>&1; then
|
|
git -C "$path" fetch --tags origin || true
|
|
fi
|
|
|
|
if git -C "$path" rev-parse -q --verify "refs/tags/$tag" >/dev/null; then
|
|
git -C "$path" checkout -q "tags/$tag"
|
|
else
|
|
echo "error: tag '$tag' was not found in '$path'" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
is_pinned_path() {
|
|
needle=$1
|
|
printf '%s\n' "$tag_pins" | while IFS='=' read -r path _tag; do
|
|
[ -n "$path" ] || continue
|
|
[ "$path" = "$needle" ] && { echo yes; exit 0; }
|
|
done | grep -q yes
|
|
}
|
|
|
|
has_nested_submodules() {
|
|
path=$1
|
|
[ -f "$path/.gitmodules" ]
|
|
}
|
|
|
|
# First make sure the top-level submodule working trees exist.
|
|
git submodule update --init
|
|
|
|
if [ "$init_only" -eq 0 ]; then
|
|
echo "Updating own top-level submodules from their configured remotes..."
|
|
git config --file .gitmodules --get-regexp '^submodule\..*\.path$' |
|
|
while read -r _key path; do
|
|
[ -n "$path" ] || continue
|
|
if is_pinned_path "$path"; then
|
|
echo "==> $path: external tag-pinned submodule, skip latest remote update"
|
|
else
|
|
echo "==> $path"
|
|
git submodule update --remote --merge -- "$path"
|
|
fi
|
|
done
|
|
else
|
|
echo "Skipping remote updates; restoring pinned submodule commits only."
|
|
fi
|
|
|
|
# Initialize nested submodules only inside their parent submodule. Do not run a
|
|
# root-level recursive update here, because that would reset already-updated
|
|
# top-level submodules back to the commits recorded in the parent repository.
|
|
echo "Synchronizing nested submodules to pinned commits..."
|
|
git config --file .gitmodules --get-regexp '^submodule\..*\.path$' |
|
|
while read -r _key path; do
|
|
[ -n "$path" ] || continue
|
|
if has_nested_submodules "$path"; then
|
|
echo "==> $path: nested submodules"
|
|
git -C "$path" submodule update --init --recursive
|
|
fi
|
|
done
|
|
|
|
if [ "$init_only" -eq 0 ] && [ -n "$tag_pins" ]; then
|
|
echo "Applying external release tag pins..."
|
|
printf '%s\n' "$tag_pins" | while IFS='=' read -r path tag; do
|
|
[ -n "$path" ] || continue
|
|
[ -n "$tag" ] || { echo "error: empty tag for '$path'" >&2; exit 2; }
|
|
pin_tag "$path" "$tag"
|
|
done
|
|
fi
|
|
|
|
print_status
|
|
|
|
if [ "$init_only" -eq 0 ] && [ "$AUTO_COMMIT" -eq 1 ]; then
|
|
echo "Staging root submodule gitlink/script changes..."
|
|
git add update-submodules.sh
|
|
git config --file .gitmodules --get-regexp '^submodule\..*\.path$' |
|
|
while read -r _key path; do
|
|
[ -n "$path" ] || continue
|
|
git add "$path"
|
|
done
|
|
|
|
if git diff --cached --quiet; then
|
|
echo "No root changes to commit."
|
|
else
|
|
echo "Committing root changes: $AUTO_COMMIT_MESSAGE"
|
|
git commit -m "$AUTO_COMMIT_MESSAGE"
|
|
fi
|
|
fi
|