forked from tuna/tunasync-scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
git-recursive.sh
executable file
·157 lines (140 loc) · 4.4 KB
/
git-recursive.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
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 <<EOF"
script_append "[submodule \"$path\"]"
script_append " active = true"
script_append " url = $mirror_url"
script_append "EOF"
script_append "mkdir -p $path"
script_append "git clone $mirror_url $path"
script_append "git submodule init $path"
script_append "git submodule update $path"
script_append "pushd $path"
git_sync_recursive ${urls[$i]} $git_path $commit
script_append "popd"
done
fi
}
function git_sync_recursive() {
depth=$(($depth+1))
local upstream=$1
local working_dir=$2
# it is ok that commit=""
local commit=$3
git_sync $1 $2
local ret=$?
if [[ $ret -ne 0 ]]; then
echon "git sync failed with rc=$ret"
return $ret
fi
if [[ ! -z "$RECURSIVE" ]]; then
working_dir_name=$(basename $2)
working_dir_name_no_git=${working_dir_name%%.git}
checkout_repo $working_dir $TMPDIR/$working_dir_name_no_git $commit
fi
depth=$(($depth-1))
}
path=$(basename $TUNASYNC_WORKING_DIR)
path_no_git=${path%%.git}
mirror_url=$(echo $TUNASYNC_WORKING_DIR | sed "s#$WORKING_DIR_BASE#$MIRROR_BASE_URL#")
script_append "mkdir -p $path_no_git"
script_append "git clone $mirror_url $path_no_git"
script_append "pushd $path_no_git"
git_sync_recursive $TUNASYNC_UPSTREAM_URL $TUNASYNC_WORKING_DIR
script_append "git submodule absorbgitdirs"
script_append "popd"
if [[ ! -z "$RECURSIVE" ]]; then
mv $GENERATED_SCRIPT.tmp $GENERATED_SCRIPT
fi
echo "Total size is" $(numfmt --to=iec $total_size)