taskd/clone.sh: clean up git-svn temp files
[girocco.git] / taskd / clone.sh
blobc3d10aa05926da8445c25eb9dad878e81bd21804
1 #!/bin/sh
3 # Invoked from taskd/taskd.pl
5 . @basedir@/shlib.sh
7 set -e
9 umask 002
10 [ "$cfg_permission_control" != "Hooks" ] || umask 000
11 clean_git_env
13 # darcs fast-export | git fast-import with error handling
14 git_darcs_fetch() (
15 set_utf8_locale
16 _err1=
17 _err2=
18 exec 3>&1
19 { read -r _err1 || :; read -r _err2 || :; } <<-EOT
21 exec 4>&3 3>&1 1>&4 4>&-
23 _e1=0
24 "$cfg_basedir"/bin/darcs-fast-export \
25 --export-marks="$(pwd)/dfe-marks" "$1" 3>&- || _e1=$?
26 echo $_e1 >&3
27 } |
29 _e2=0
30 git fast-import \
31 --export-marks="$(pwd)/gfi-marks" \
32 --export-pack-edges="$(pwd)/gfi-packs" \
33 --force 3>&- || _e2=$?
34 echo $_e2 >&3
37 EOT
38 exec 3>&-
39 [ "$_err1" = 0 ] && [ "$_err2" = 0 ]
40 return $?
43 # bzr fast-export | git fast-import with error handling
44 git_bzr_fetch() (
45 set_utf8_locale
46 BZR_LOG=/dev/null
47 export BZR_LOG
48 _err1=
49 _err2=
50 exec 3>&1
51 { read -r _err1 || :; read -r _err2 || :; } <<-EOT
53 exec 4>&3 3>&1 1>&4 4>&-
55 _e1=0
56 bzr fast-export --plain \
57 --export-marks="$(pwd)/bfe-marks" "$1" 3>&- || _e1=$?
58 echo $_e1 >&3
59 } |
61 _e2=0
62 git fast-import \
63 --export-marks="$(pwd)/gfi-marks" \
64 --export-pack-edges="$(pwd)/gfi-packs" \
65 --force 3>&- || _e2=$?
66 echo $_e2 >&3
69 EOT
70 exec 3>&-
71 [ "$_err1" = 0 ] && [ "$_err2" = 0 ]
72 return $?
75 send_clone_failed() {
76 trap "" EXIT
77 # We must now close the .clonelog file that is open on stdout and stderr
78 exec >/dev/null 2>&1
79 ! [ -d htmlcache ] || { >htmlcache/changed; } 2>/dev/null || :
80 failaddrs="$(config_get owner)" || :
81 [ -z "$cfg_admincc" ] || [ "$cfg_admincc" = "0" ] || [ -z "$cfg_admin" ] ||
82 if [ -z "$failaddrs" ]; then failaddrs="$cfg_admin"; else failaddrs="$failaddrs,$cfg_admin"; fi
83 [ -z "$failaddrs" ] ||
85 cat <<EOT
86 Condolences. The clone of project $proj just failed.
88 * Source URL: $url
89 * Project settings: $cfg_webadmurl/editproj.cgi?name=$(echo "$proj" | LC_ALL=C sed -e 's/[+]/%2B/g')
91 The project settings link may be used to adjust the settings
92 and restart the clone in order to try the clone again.
93 EOT
94 if [ -f .clonelog ] && [ -r .clonelog ]; then
95 echo ""
96 echo "Log follows:"
97 echo ""
98 loglines=$(LC_ALL=C wc -l <.clonelog)
99 if [ $loglines -le 203 ]; then
100 cat .clonelog
101 else
102 head -n 100 .clonelog
103 echo ""
104 echo "[ ... elided $(( $loglines - 200 )) middle lines ... ]"
105 echo ""
106 tail -n 100 .clonelog
109 } | mailref "clone@$cfg_gitweburl/$proj.git" -s "[$cfg_name] $proj clone failed" "$failaddrs" || :
112 # removes any git-svn leftovers
113 cleanup_git_svn_leftovers() {
115 # Remove any stale git-svn temp files
116 # The git-svn process creates temp files with random 10 character names
117 # in the root of $GIT_DIR. Unfortunately they do not have a recognizable
118 # prefix, so we just have to kill any files with a 10-character name.
119 # All characters are chosen from
120 # [A-Za-z0-9_] so we can at least check that and fortunately the only
121 # collision is 'FETCH_HEAD' but that doesn't matter.
122 # There may also be temp files with a Git_ prefix as well.
123 _randchar='[A-Za-z0-9_]'
124 _randchar2="$_randchar$_randchar"
125 _randchar4="$_randchar2$_randchar2"
126 _randchar10="$_randchar4$_randchar4$_randchar2"
127 find -L . -maxdepth 1 -type f -name "$_randchar10" -exec rm -f '{}' + || :
128 find -L . -maxdepth 1 -type f -name "Git_*" -exec rm -f '{}' + || :
131 # removes all leftovers from a previous failed clone attempt
132 cleanup_failed_clone() {
134 # Remove any left-over svn-remote.svn or remote.origin config
135 git config --remove-section svn-remote.svn 2>/dev/null || :
136 git config --remove-section remote.origin 2>/dev/null || :
138 # If there is a remote-template.origin section, pre-seed the
139 # remote.origin section with its contents
140 git config --get-regexp '^remote-template\.origin\..' |
141 while read name value; do
142 if [ -n "$name" ] && [ -n "$value" ]; then
143 git config "remote${name#remote-template}" "$value"
145 done
147 # Any pre-existing FETCH_HEAD from a previous clone failed or not is
148 # now garbage to be removed
149 rm -f FETCH_HEAD
151 # Remove any left-over svn dir from a previous failed attempt
152 rm -rf svn
154 # Remove any left-over .darcs dirs from a previous failed attempt
155 rm -rf *.darcs
157 # Remove any left-over repo.hg dir from a previous failed attempt
158 rm -rf repo.hg
160 # Remove any left-over import/export/temp files from a previous failed attempt
161 rm -f bfe-marks dfe-marks hg2git-heads hg2git-mapping hg2git-marks* hg2git-state \
162 gfi-marks gfi-packs .pkts-temp .refs-temp
164 # Remove any git-svn junk
165 cleanup_git_svn_leftovers
167 # We want a gc right after the clone, so re-enable that just in case.
168 # There's a potential race where we could add it and gc.sh could remove
169 # it, but we'll reunset lastgc just before we remove .delaygc at the end.
170 [ -e .delaygc ] || >.delaygc
171 git config --unset gitweb.lastgc 2>/dev/null || :
173 # Remove all pre-existing refs
174 rm -f packed-refs
175 git for-each-ref --format='delete %(refname)' | git_updateref_stdin 2>/dev/null || :
177 # The initial state before a clone starts has HEAD as a symbolic-ref to master
178 git symbolic-ref HEAD refs/heads/master
180 # HEAD is no longer "ok"
181 git config --unset girocco.headok 2>/dev/null || :
183 # We, perhaps, ought to remove any packs/loose objects now, but the next gc
184 # will get rid of any extras. Also, if we're recloning the same thing, any
185 # preexisting packs/loose objects containing what we're recloning will only
186 # speed up the reclone by avoiding some disk writes. So we don't kill them.
188 # It's just remotely possible that a bunch of failures in a row could
189 # create a big mess that just keeps growing and growing...
190 # Trigger a .needsgc if that happens.
191 check_and_set_needsgc
194 proj="${1%.git}"
195 cd "$cfg_reporoot/$proj.git"
196 bang_reset
198 ! [ -e .delaygc ] || >.allowgc || :
200 trap "echo '@OVER@'; touch .clone_failed; send_clone_failed" EXIT
201 echo "Project: $proj"
202 echo " Date: $(TZ=UTC date '+%Y-%m-%d %T UTC')"
203 echo ""
204 [ -n "$cfg_mirror" ] || { echo "Mirroring is disabled" >&2; exit 1; }
205 url="$(config_get baseurl)" || :
206 case "$url" in *" "*|*" "*|"")
207 echo "Bad mirror URL (\"$url\")"
208 exit 1
209 esac
211 cleanup_failed_clone
213 # Record original mirror type for use by update.sh
214 mirror_type="$(get_url_mirror_type "$url")"
215 git config girocco.mirrortype "$mirror_type"
217 echo "Mirroring from URL \"$url\""
218 echo ""
220 if [ "$cfg_project_owners" = "source" ]; then
221 config set owner "$(ls -ldH "${url#file://}" 2>/dev/null | LC_ALL=C awk '{print $3}')"
224 mailaddrs="$(config_get owner)" || :
225 [ -z "$cfg_admin" ] ||
226 if [ -z "$mailaddrs" ]; then mailaddrs="$cfg_admin"; else mailaddrs="$mailaddrs,$cfg_admin"; fi
228 # Make sure we don't get any unwanted loose objects
229 # Starting with Git v2.10.0 fast-import can generate loose objects unless we
230 # tweak its configuration to prevent that
231 git_add_config 'fetch.unpackLimit=1'
232 # Note the git config documentation is wrong
233 # transfer.unpackLimit, if set, overrides fetch.unpackLimit
234 git_add_config 'transfer.unpackLimit=1'
235 # But not the Git v2.10.0 and later fastimport.unpackLimit which improperly uses <= instead of <
236 git_add_config 'fastimport.unpackLimit=0'
238 # Initial mirror
239 echo "Initiating mirroring..."
240 headref=
241 showheadwarn=
242 warnempty=
244 # remember the starting time so we can easily combine fetched loose objects
245 # we sleep for 1 second after creating .needspack to make sure all objects are newer
246 if ! [ -e .needspack ]; then
247 rm -f .needspack
248 >.needspack
249 sleep 1
252 case "$url" in
253 svn://* | svn+http://* | svn+https://* | svn+file://* | svn+ssh://*)
254 [ -n "$cfg_mirror_svn" ] || { echo "Mirroring svn is disabled" >&2; exit 1; }
255 # Allow the username to be specified in the "svn-credential.svn.username"
256 # property and the password in the "svn-credential.svn.password" property
257 # Use an 'anonsvn' username by default as is commonly used for anonymous svn
258 # Default the password to the same as the username
259 # The password property will be ignored unless a username has been specified
260 if svnuser="$(git config --get svn-credential.svn.username)" && [ -n "$svnuser" ]; then
261 if ! svnpass="$(git config --get svn-credential.svn.password)"; then
262 svnpass="$svnuser"
264 url1="${url#*://}"
265 url1="${url1%%/*}"
266 case "$url1" in ?*"@"?*)
267 urlsch="${url%%://*}"
268 url="$urlsch://${url#*@}"
269 esac
270 else
271 # As a fallback, check in the URL, just in case
272 url1="${url#*://}"
273 url1="${url1%%/*}"
274 svnuser=
275 case "$url1" in ?*"@"?*)
276 urlsch="${url%%://*}"
277 url="$urlsch://${url#*@}"
278 url1="${url1%%@*}"
279 svnuser="${url1%%:*}"
280 if [ -n "$svnuser" ]; then
281 svnpass="$svnuser"
282 case "$url1" in *":"*)
283 svnpass="${url1#*:}"
284 esac
286 esac
287 if [ -z "$svnuser" ]; then
288 svnuser="anonsvn"
289 svnpass="anonsvn"
292 GIT_ASKPASS_PASSWORD="$svnpass"
293 export GIT_ASKPASS_PASSWORD
294 # We just remove svn+ here, so svn+http://... becomes http://...
295 # We also remove a trailing '/' to match what git-svn will do
296 case "$url" in svn+ssh://*) svnurl="$url";; *) svnurl="${url#svn+}";; esac
297 svnurl="${svnurl%/}"
298 # We require svn info to succeed on the URL otherwise it's
299 # simply not a valid URL and without using -s on the init it
300 # will not otherwise be tested until the fetch
301 svn --non-interactive --username "$svnuser" --password "$svnpass" info "$svnurl" >/dev/null
302 # We initially use -s for the init which will possibly shorten
303 # the URL. However, the shortening can fail if a password is
304 # not required for the longer version but is for the shorter,
305 # so try again without -s if the -s version fails.
306 # We must use GIT_DIR=. here or ever so "helpful" git-svn will
307 # create a .git subdirectory!
308 GIT_DIR=. git svn init --username="$svnuser" --prefix "" -s "$svnurl" <"$mtlinesfile" ||
309 GIT_DIR=. git svn init --username="$svnuser" --prefix "" "$svnurl" <"$mtlinesfile"
310 # We need to remember this url so we can detect changes because
311 # ever so "helpful" git-svn may shorten it!
312 config_set svnurl "$svnurl"
313 # At this point, since we asked for a standard layout (-s) git-svn
314 # may have been "helpful" and adjusted our $svnurl to a prefix and
315 # then glued the removed suffix onto the front of any svn-remote.svn.*
316 # config items. We could avoid this by not using the '-s' option
317 # but then we might not get all the history. If, for example, we
318 # are cloning an http://svn.example.com/repos/public repository that
319 # early in its history moved trunk => public/trunk we would miss that
320 # earlier history without allowing the funky shorten+prefix behavior.
321 # So we read back the svn-remote.svn.fetch configuration and compute
322 # the prefix. This way we are sure to get the correct prefix.
323 gitsvnurl="$(git config --get svn-remote.svn.url)" || :
324 gitsvnfetch="$(git config --get-all svn-remote.svn.fetch | tail -1)" || :
325 gitsvnprefix="${gitsvnfetch%%:*}"
326 gitsvnsuffix="${gitsvnprefix##*/}"
327 gitsvnprefix="${gitsvnprefix%$gitsvnsuffix}"
328 # Ask git-svn to store everything in the normal non-remote
329 # locations being careful to use the correct prefix
330 git config --replace-all svn-remote.svn.fetch "${gitsvnprefix}trunk:refs/heads/master"
331 git config --replace-all svn-remote.svn.branches "${gitsvnprefix}branches/*:refs/heads/*"
332 git config --replace-all svn-remote.svn.tags "${gitsvnprefix}tags/*:refs/tags/*"
333 # look for additional non-standard directories to fetch
334 # check for standard layout at the same time
335 foundstd=
336 foundfile=
337 svn --non-interactive --username "$svnuser" --password "$svnpass" ls "$gitsvnurl/${gitsvnprefix}" 2>/dev/null |
338 { while read file; do case $file in
339 # skip the already-handled standard ones and any with a space or tab
340 *' '*|*' '*) :;;
341 trunk/|branches/|tags/) foundstd=1;;
342 # only fetch extra directories from the $svnurl root (not any files)
343 *?/) git config --add svn-remote.svn.fetch \
344 "${gitsvnprefix}${file%/}:refs/heads/${file%/}";;
345 *?) foundfile=1;;
346 esac; done
347 # if files found and no standard directories present use a simpler layout
348 if [ -z "$foundstd" ] && [ -n "$foundfile" ]; then
349 git config --unset svn-remote.svn.branches
350 git config --unset svn-remote.svn.tags
351 git config --replace-all svn-remote.svn.fetch ':refs/heads/master'
352 fi; }
353 test $? -eq 0
354 # git svn fetch on a very large repo can take some time and the
355 # remote server may interrupt the connection from time to time.
356 # keep retrying (after a brief pause) as long as we are making progress.
357 # however, we do limit the total number of retries to 1000
358 # we will, however, retry up to 5 times even if we're not making progress
359 v_get_svn_progress_fingerprint() {
360 eval "$1="'"$({ GIT_DIR=. git svn info <"$mtlinesfile" 2>&1; git show-ref --head 2>&1; } |
361 git hash-object -t blob --stdin )"' || :
363 svn_ret_err() { return "${1:-1}"; }
364 svn_retries=1000
365 svn_progress=
366 v_get_svn_progress_fingerprint svn_progress
367 svn_progress_retries="$svn_retries"
368 svn_err=0
369 while [ "$svn_retries" -gt 0 ]; do
370 svn_retries="$(( $svn_retries - 1 ))"
371 svn_err=0
372 # Again, be careful to use GIT_DIR=. here or else new .git subdirectory!
373 GIT_DIR=. git svn fetch --log-window-size=$var_log_window_size --username="$svnuser" --quiet <"$mtlinesfile" || svn_err="$?"
374 [ "${svn_err:-1}" -ne 0 ] || break # success!
375 # Check to see if we made any progress
376 v_get_svn_progress_fingerprint svn_progress_now
377 if [ "$svn_progress_now" != "$svn_progress" ]; then
378 # we made progress, continue the loop
379 svn_progress="$svn_progress_now"
380 svn_progress_retries="$svn_retries"
381 else
382 # no progress, but we only give up after
383 # 5 no-progress attempts in a row
384 [ "$(( $svn_progress_retries - $svn_retries ))" -lt 5 ] || break # failure
386 # Pause briefly before retrying to be friendly to the server
387 echo 'Pausing for 120 seconds before retrying'
388 sleep 120
389 cleanup_git_svn_leftovers
390 echo 'Retrying fetch'
391 done
392 [ "${svn_err:-1}" -eq 0 ] || svn_ret_err "$svn_err"
393 test ${svn_err:-1} -eq 0
394 # git svn does not preserve group permissions in the svn subdirectory
395 chmod -R ug+rw,o+r svn
396 # git svn also leaves behind ref turds that end with @nnn
397 # We get rid of them now
398 git for-each-ref --format='%(refname)' |
399 LC_ALL=C sed '/^..*@[1-9][0-9]*$/!d; s/^/delete /' |
400 git_updateref_stdin
401 unset GIT_ASKPASS_PASSWORD
403 darcs://* | darcs+http://* | darcs+https://*)
404 [ -n "$cfg_mirror_darcs" ] || { echo "Mirroring darcs is disabled" >&2; exit 1; }
405 case "$url" in
406 darcs://*) darcsurl="http://${url#darcs://}";;
407 *) darcsurl="${url#darcs+}";;
408 esac
409 git_darcs_fetch "$darcsurl"
411 bzr://*)
412 [ -n "$cfg_mirror_bzr" ] || { echo "Mirroring bzr is disabled" >&2; exit 1; }
413 # we just remove bzr:// here, a typical bzr url is just
414 # "lp:foo"
415 bzrurl="${url#bzr://}"
416 git_bzr_fetch "$bzrurl"
418 hg+http://* | hg+https://* | hg+file://* | hg+ssh://*)
419 [ -n "$cfg_mirror_hg" ] || { echo "Mirroring hg is disabled" >&2; exit 1; }
420 # We just remove hg+ here, so hg+http://... becomes http://...
421 hgurl="${url#hg+}"
422 # Perform the initial hg clone
423 hg clone -U "$hgurl" "$(pwd)/repo.hg"
424 # Do the fast-export | fast-import
425 git_hg_fetch
428 # We manually add remote.origin.url and remote.origin.fetch
429 # to simulate a `git remote add --mirror=fetch` since that's
430 # not available until Git 1.7.5 and this way we guarantee we
431 # always get exactly the intended configuration and nothing else.
432 git config remote.origin.url "$url"
433 if ! is_gfi_mirror_url "$url" && [ "$(git config --bool girocco.cleanmirror 2>/dev/null || :)" = "true" ]; then
434 git config --replace-all remote.origin.fetch "+refs/heads/*:refs/heads/*"
435 git config --add remote.origin.fetch "+refs/tags/*:refs/tags/*"
436 git config --add remote.origin.fetch "+refs/notes/*:refs/notes/*"
437 git config --add remote.origin.fetch "+refs/top-bases/*:refs/top-bases/*"
438 git config --bool girocco.lastupdateclean true
439 else
440 git config --replace-all remote.origin.fetch "+refs/*:refs/*"
441 git config --bool girocco.lastupdateclean false
443 # Set the correct HEAD symref by using ls-remote first
444 GIT_SSL_NO_VERIFY=1 GIT_TRACE_PACKET=1 git ls-remote origin >.refs-temp 2>.pkts-temp ||
446 # Since everything was redirected, on failure there'd be no output,
447 # so let's make some failure output
448 cat .pkts-temp
449 echo ""
450 echo "git ls-remote \"$url\" failed"
451 exit 1
453 # Compensate for git() {} side effects
454 unset GIT_TRACE_PACKET
455 # If the server is running at least Git 1.8.4.3 then it will send us the actual
456 # symref for HEAD. If we are running at least Git 1.7.5 then we can snarf that
457 # out of the packet trace data.
458 if [ -s .refs-temp ]; then
459 # Nothing to do unless the remote repository has at least 1 ref
460 # See if we got a HEAD ref
461 head="$(LC_ALL=C grep -E "^$octet20$hexdig*[ $tab]+HEAD\$" <.refs-temp | LC_ALL=C awk '{print $1}')"
462 # If the remote has HEAD set to a symbolic ref that does not exist
463 # then we will not receive a HEAD ref in the ls-remote output
464 headref=
465 showheadwarn=
466 symrefcap=
467 if [ -n "$head" ]; then
468 symrefcap="$(LC_ALL=C sed -ne <.pkts-temp \
469 "/packet:.*git<.*[ $tab]symref="'HEAD:refs\/heads\/'"[^ $tab]/\
470 {s/^.*[ $tab]symref="'HEAD:\(refs\/heads\/'"[^ $tab][^ $tab]*"'\).*$/\1/;p;}')"
471 # prefer $symrefcap (refs/heads/master if no $symrefcap) if it
472 # matches HEAD otherwise take the first refs/heads/... match
473 matchcnt=0
474 while read ref; do
475 [ -n "$ref" ] || continue
476 matchcnt=$(( $matchcnt + 1 ))
477 if [ -z "$headref" ] || [ "$ref" = "${symrefcap:-refs/heads/master}" ]; then
478 headref="$ref"
480 if [ "$headref" = "${symrefcap:-refs/heads/master}" ] && [ $matchcnt -gt 1 ]; then
481 break
483 done <<-EOT
484 $(LC_ALL=C grep -E "^$head[ $tab]+refs/heads/[^ $tab]+\$" <.refs-temp |
485 LC_ALL=C awk '{print $2}')
487 # Warn if there was more than one match and $symrefcap is empty
488 # or $symrefcap is not the same as $headref since our choice might
489 # differ from the source repository's HEAD
490 if [ $matchcnt -ge 1 ] && [ "$symrefcap" != "$headref" ] &&
491 { [ -n "$symrefcap" ] || [ $matchcnt -gt 1 ]; }; then
492 showheadwarn=1
495 if [ -z "$headref" ]; then
496 # If we still don't have a HEAD ref then prefer refs/heads/master
497 # if it exists otherwise take the first refs/heads/...
498 # We do not support having a detached HEAD.
499 # We always warn now because we will be setting HEAD differently
500 # than the source repository had HEAD set
501 showheadwarn=1
502 while read ref; do
503 [ -n "$ref" ] || continue
504 if [ -z "$headref" ] || [ "$ref" = "refs/heads/master" ]; then
505 headref="$ref"
507 [ "$headref" != "refs/heads/master" ] || break
508 done <<-EOT
509 $(LC_ALL=C grep -E "^$octet20$hexdig*[ $tab]+refs/heads/[^ $tab]+\$" <.refs-temp |
510 LC_ALL=C awk '{print $2}')
513 # If we STILL do not have a HEAD ref (perhaps the source repository
514 # contains only tags) then use refs/heads/master. It will be invalid
515 # but is no worse than we used to do by default and we'll warn about
516 # it. We do not support a HEAD symref to anything other than refs/heads/...
517 [ -n "$headref" ] || headref="refs/heads/master"
518 git symbolic-ref HEAD "$headref"
519 pruneopt=--prune
520 [ "$(git config --bool fetch.prune 2>/dev/null || :)" != "false" ] || pruneopt=
521 # remember the starting time so we can easily detect new packs for fast-import mirrors
522 # we sleep for 1 second after creating .gfipack to make sure all packs are newer
523 if is_gfi_mirror_url "$url" && ! [ -e .gfipack ]; then
524 rm -f .gfipack
525 >.gfipack
526 sleep 1
528 GIT_SSL_NO_VERIFY=1 git remote update $pruneopt
529 if [ -e .gfipack ] && is_gfi_mirror_url "$url"; then
530 find -L objects/pack -type f -newer .gfipack -name "pack-$octet20*.pack" -print >>gfi-packs
531 rm -f .gfipack
533 else
534 warnempty=1
535 git symbolic-ref HEAD "refs/heads/master"
537 rm -f .refs-temp .pkts-temp
539 esac
541 # The objects subdirectories permissions must be updated now.
542 # In the case of a dumb http clone, the permissions will not be correct
543 # (missing group write) despite the core.sharedrepository=1 setting!
544 # The objects themselves seem to have the correct permissions.
545 # This problem appears to have been fixed in the most recent git versions.
546 perms=g+w
547 [ "$cfg_permission_control" != "Hooks" ] || perms=go+w
548 chmod $perms $(find -L objects -maxdepth 1 -type d) 2>/dev/null || :
550 # We may have just cloned a lot of refs and they will all be
551 # individual files at this point. Let's pack them now so we
552 # can have better performance right from the start.
553 git pack-refs --all
555 # Initialize gitweb.lastreceive, gitweb.lastchange and info/lastactivity
556 git config gitweb.lastreceive "$(date '+%a, %d %b %Y %T %z')"
557 git config gitweb.lastchange "$(date '+%a, %d %b %Y %T %z')"
558 git for-each-ref --sort=-committerdate --format='%(committerdate:iso8601)' \
559 --count=1 refs/heads >info/lastactivity || :
560 ! [ -d htmlcache ] || { >htmlcache/changed; } 2>/dev/null || :
562 # Don't leave a multi-megabyte useless FETCH_HEAD behind
563 rm -f FETCH_HEAD
565 # Last ditch attempt to get a valid HEAD for a non-git source
566 check_and_set_head || :
568 # The rest
569 echo "Final touches..."
570 git update-server-info
571 trap "" EXIT
573 # run gc now unless the clone is empty
574 if [ -z "$warnempty" ]; then
575 git config --unset gitweb.lastgc 2>/dev/null || :
576 rm -f .delaygc .allowgc
579 emptynote=
580 [ -z "$warnempty" ] ||
581 emptynote="
582 WARNING: You have mirrored an empty repository.
584 headnote=
585 [ -z "$showheadwarn" ] || [ -z "$headref" ] ||
586 headnote="
587 NOTE: HEAD has been set to a symbolic ref to \"$headref\".
588 Use the \"Project settings\" link to choose a different HEAD symref.
590 sizenote=
591 ! is_gfi_mirror ||
592 sizenote="
593 NOTE: Since this is a mirror of a non-Git source, the initial repository
594 size may be somewhat larger than necessary. This will be corrected
595 shortly. If you intend to clone this repository you may want to
596 wait up to 1 hour before doing so in order to receive the more
597 compact final size.
599 [ -z "$mailaddrs" ] ||
600 mailref "clone@$cfg_gitweburl/$proj.git" -s "[$cfg_name] $proj clone completed" "$mailaddrs" <<EOT || :
601 Congratulations! The clone of project $proj just completed.
603 * Source URL: $url
604 * GitWeb interface: $cfg_gitweburl/$proj.git
605 * Project settings: $cfg_webadmurl/editproj.cgi?name=$(echo "$proj" | LC_ALL=C sed -e 's/[+]/%2B/g')
606 $emptynote$headnote$sizenote
607 Have a lot of fun.
610 echo "Mirroring finished successfuly!"
611 # In case this is a re-mirror, lastgc could have been set already so clear it now
612 git config --unset gitweb.lastgc || :
613 rm .clone_in_progress
614 echo "$sizenote@OVER@"