#!/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 <&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