diff --git a/git-recursive.sh b/git-recursive.sh new file mode 100755 index 0000000..ff6ff6d --- /dev/null +++ b/git-recursive.sh @@ -0,0 +1,157 @@ +#!/bin/bash +if [[ -z "$TUNASYNC_UPSTREAM_URL" ]];then + echo "Please set the TUNASYNC_UPSTREAM_URL" + exit 1 +fi + +if [[ ! -z "$RECURSIVE" ]];then + echo "Sync in a recursive mode" +fi + +TMPDIR=${TMPDIR:-"/tmp"} + +MIRROR_BASE_URL=${MIRROR_BASE_URL:-"https://mirrors.tuna.tsinghua.edu.cn/git/"} +WORKING_DIR_BASE=${WORKING_DIR_BASE:-"/data/mirrors/git/"} +GENERATED_SCRIPT=${GENERATED_SCRIPT:-"/data/mirrors/git/qemu/qemu.sh"} + +if [[ ! -z "$RECURSIVE" ]]; then + echo "#!/usr/bin/env bash" > $GENERATED_SCRIPT.tmp +fi + +function script_append() { +if [[ ! -z "$RECURSIVE" ]]; then + echo "$1" >> $GENERATED_SCRIPT.tmp +fi +} + +depth=0 + +function echon() { + echo depth $depth $@ +} + +function repo_init() { + local upstream=$1 + local working_dir=$2 + git clone --mirror "$upstream" "$working_dir" +} + +function update_linux_git() { + local upstream=$1 + local working_dir=$2 + cd "$working_dir" + echon "==== SYNC $upstream START ====" + git remote set-url origin "$upstream" + /usr/bin/timeout -s INT 3600 git remote -v update -p + local ret=$? + [[ $ret -ne 0 ]] && echon "git update failed with rc=$ret" + local head=$(git remote show origin | awk '/HEAD branch:/ {print $NF}') + [[ -n "$head" ]] && echo "ref: refs/heads/$head" > HEAD + objs=$(find objects -type f | wc -l) + [[ "$objs" -gt 8 ]] && git repack -a -b -d + sz=$(git count-objects -v|grep -Po '(?<=size-pack: )\d+') + total_size=$(($total_size+1024*$sz)) + echon "==== SYNC $upstream DONE ====" + return $ret +} + +function git_sync() { + local upstream=$1 + local working_dir=$2 + if [[ ! -f "$working_dir/HEAD" ]]; then + echon "Initializing $upstream mirror" + repo_init $1 $2 + return $? + fi + update_linux_git $1 $2 +} + +function checkout_repo() { + local repo_dir="$1" + local work_tree="$2" + local commit="$3" + echon "Checkout $repo_dir to $work_tree" + rm -rf $work_tree + git clone "$repo_dir" "$work_tree" + local ret=$? + if [[ $ret -ne 0 ]]; then + echon "git clone failed with rc=$ret" + return $ret + fi + if [[ ! -z "$commit" ]]; then + echon "Worktree $work_tree switch to commit $commit" + git -C $work_tree checkout $commit + fi + + local repo_dir_no_git=${repo_dir%%.git} + local gitmodules="$work_tree/.gitmodules" + if [[ -f "$gitmodules" ]]; then + local paths_str=$(cat $gitmodules | grep path | cut -d '=' -f 2 | sed 's/^[[:blank:]]*//') + local urls_str=$(cat $gitmodules | grep url | cut -d '=' -f 2 | sed 's/^[[:blank:]]*//') + local -a paths + local -a urls + readarray -t paths <<<"$paths_str" + readarray -t urls <<<"$urls_str" + local -i i + for ((i=0;i<${#paths[@]};i++)); do + local path=${paths[$i]} + # ignore empty .gitmodules + if [[ "$path" == "" ]]; then + continue + fi + local commit=$(git -C $work_tree submodule status $path | cut -d ' ' -f 1 | cut -d '-' -f 2) + local git_path=$repo_dir_no_git/$path.git + mkdir -p $git_path + local mirror_url=$(echo $git_path | sed "s#$WORKING_DIR_BASE#$MIRROR_BASE_URL#") + script_append "cat >>.git/config <