chiark / gitweb /
5b54d16cc0f9a1cdbf0be5251d1943b5f5d3d535
[dgit.git] / infra / dgit-mirror-rsync
1 #!/bin/bash
2 #
3 # Mirror script for use as a dgit-repos-server mirror hook
4 #
5 # In addition to updated-hook (invoked by dgit-repos-server),
6 # this script also supports the following ACTIONs:
7 #   MIRROR-HOOK-SCRIPT ... setup [...]            create queue dir etc.
8 #   MIRROR-HOOK-SCRIPT ... backlog [...]          do all packages which need it
9 #   MIRROR-HOOK-SCRIPT ... all [...]              do all packages
10 #   MIRROR-HOOK-SCRIPT ... mirror PACKAGE [...]   do just that, longer timeout
11 #
12 # DISTRO-DIR must contain a file `mirror-settings' which is a bash
13 # script fragment assigning the following variables:
14 #   remoterepos         for rsync, in form user@host:/dir
15 # and optionally
16 #   hooktimeout         default 30 [sec]
17 #   rsynctimeout        default 900 [sec]
18 #   rsyncssh            default 'ssh -o batchmode=yes'
19 #   rsync               array, default (rsync -rltH --safe-links --delete)
20 #   repos               default DISTRO-DIR/repos
21 # (optional settings are all set before mirror-settings is included,
22 # so you can modify them with += or some such)
23
24 set -e
25 set -o pipefail
26 shopt -s nullglob
27
28 case "$DGIT_DRS_DEBUG" in
29 ''|0!1)         ;;
30 *)              set -x  ;;
31 esac
32
33 fail () {
34         echo >&2 "dgit-mirror-rsync: $*"; exit 127
35 }
36
37 if [ $# -lt 2 ]; then fail "too few arguments"; fi
38
39 self=$0
40 distrodir=$1;   shift
41 action=$1;      shift
42 package=$1
43
44 repos=$distrodir/repos
45
46 rsync=(rsync -rltH --safe-links --delete)
47 hooktimeout=30
48 rsynctimeout=900
49 rsyncssh='ssh -o batchmode=yes'
50
51 . $distrodir/mirror-settings
52
53 # contents of $queue
54 # $queue/$package.n     - mirror needed
55 # $queue/$package.a     - being attempted, or attempt failed
56 # $queue/$package.lock  - lock (with-lock-ex)
57 # $queue/$package.err   - stderr from failed (or current) run
58 # $queue/$package.log   - stderr from last successful run
59
60 cd $repos
61 queue=_mirror-queue
62
63 case "$remoterepos" in
64 *:/*|/*)        ;;
65 '')             fail "remoterepos config not set" ;;
66 *)              fail "remoterepos config does not match *:/* or /*" ;;
67 esac
68
69 actually () {
70         "${rsync[@]}" \
71                 --timeout=$rsynctimeout                         \
72                 -e "$rsyncssh"                                  \
73                 "$repos/$package.git"/.                         \
74                 "$remoterepos/$package.git"
75 }
76
77 reinvoke () {
78         newaction="$1"; shift
79
80         exec                                                    \
81         "$@"                                                    \
82         "$0"    "$distrodir" "reinvoke$newaction" "$package"
83 }
84
85 check-package-mirrorable () {
86         local repo=$repos/$package.git
87         local mode=$(stat -c%a "$repo")
88         case $mode in
89         *5)     return  0       ;;
90         *0)     return  1       ;;
91         *)      echo >&2 "unexpected mode $mode for $repo"; return 1    ;;
92         esac
93 }
94
95 lock-and-process () {
96         check-package-mirrorable || return 0
97         reinvoke -locked with-lock-ex -w "$queue/$package.lock"
98 }
99
100 attempt () {
101         exec >"$queue/$package.err" 2>&1
102         if actually; then
103                 rm "$queue/$package.a"
104                 mv -f "$queue/$package.err" "$queue/$package.log"
105                 rm "$queue/$package.lock"
106         else
107                 cat >&2 "$queue/$package.err"
108                 exit 127
109         fi
110 }
111
112 lock-and-process-baseof-f () {
113         package=${f##*/}
114         package=${package%.*}
115         lock-and-process
116 }
117
118 case "$action" in
119
120 updated-hook)
121         check-package-mirrorable || exit 0
122         touch "$queue/$package.n"
123         reinvoke -timed timeout --foreground $hooktimeout
124         ;;
125
126 reinvoke-timed)
127         (lock-and-process) >/dev/null 2>&1
128         ;;
129
130 mirror)
131         lock-and-process
132         ;;
133
134 reinvoke-locked)
135         touch "$queue/$package.a"
136         rm -f "$queue/$package.n"
137         attempt
138         ;;
139
140 backlog)
141         for f in $queue/*.[na]; do
142                 lock-and-process-baseof-f
143         done
144         ;;
145
146 all)
147         for f in [a-z0-9]*.git; do
148                 lock-and-process-baseof-f
149         done
150         ;;
151
152 setup)
153         test -d "$queue" || mkdir "$queue"
154         ;;
155
156 *)
157         fail "bad action $action"
158         ;;
159
160 esac