hgforest.sh revision 2281:4353c659dfde
1210284Sjmallett#!/bin/sh
2232812Sjmallett#
3215990Sjmallett# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
4210284Sjmallett# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5210284Sjmallett#
6215990Sjmallett# This code is free software; you can redistribute it and/or modify it
7215990Sjmallett# under the terms of the GNU General Public License version 2 only, as
8215990Sjmallett# published by the Free Software Foundation.
9210284Sjmallett#
10215990Sjmallett# This code is distributed in the hope that it will be useful, but WITHOUT
11215990Sjmallett# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12210284Sjmallett# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13215990Sjmallett# version 2 for more details (a copy is included in the LICENSE file that
14215990Sjmallett# accompanied this code).
15215990Sjmallett#
16215990Sjmallett# You should have received a copy of the GNU General Public License version
17215990Sjmallett# 2 along with this work; if not, write to the Free Software Foundation,
18232812Sjmallett# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19215990Sjmallett#
20215990Sjmallett# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21215990Sjmallett# or visit www.oracle.com if you need additional information or have any
22215990Sjmallett# questions.
23215990Sjmallett#
24215990Sjmallett
25215990Sjmallett# Shell script for a fast parallel forest/trees command
26215990Sjmallett
27215990Sjmallettusage() {
28215990Sjmallett      echo "usage: $0 [-h|--help] [-q|--quiet] [-v|--verbose] [-s|--sequential] [--] <command> [commands...]" > ${status_output}
29232812Sjmallett      echo "command format : mercurial-command [ "jdk" ] [ extra-url ]"
30215990Sjmallett      echo "command option: jdk : used only with clone command to request just the extra repos for JDK-only builds"
31215990Sjmallett      echo "command option : extra-url : server hosting the extra repositories"
32215990Sjmallett      echo "Environment variables which modify behaviour:"
33215990Sjmallett      echo "   HGFOREST_QUIET      : (boolean) If 'true' then standard output is redirected to /dev/null"
34215990Sjmallett      echo "   HGFOREST_VERBOSE    : (boolean) If 'true' then Mercurial asked to produce verbose output"
35215990Sjmallett      echo "   HGFOREST_SEQUENTIAL : (boolean) If 'true' then repos are processed sequentially. Disables concurrency"
36215990Sjmallett      echo "   HGFOREST_GLOBALOPTS : (string, must begin with space) Additional Mercurial global options"
37215990Sjmallett      echo "   HGFOREST_REDIRECT   : (file path) Redirect standard output to specified file"
38210284Sjmallett      echo "   HGFOREST_FIFOS      : (boolean) Default behaviour for FIFO detection. Does not override FIFOs disabled"
39210284Sjmallett      echo "   HGFOREST_CONCURRENCY: (positive integer) Number of repos to process concurrently"
40210284Sjmallett      echo "   HGFOREST_DEBUG      : (boolean) If 'true' then temp files are retained"
41210284Sjmallett      exit 1
42210284Sjmallett}
43210284Sjmallett
44210284Sjmallettglobal_opts="${HGFOREST_GLOBALOPTS:-}"
45215990Sjmallettstatus_output="${HGFOREST_REDIRECT:-/dev/stdout}"
46210284Sjmallettqflag="${HGFOREST_QUIET:-false}"
47210284Sjmallettvflag="${HGFOREST_VERBOSE:-false}"
48210284Sjmallettsflag="${HGFOREST_SEQUENTIAL:-false}"
49210284Sjmallettwhile [ $# -gt 0 ]
50210284Sjmallettdo
51232812Sjmallett  case $1 in
52210284Sjmallett    -h | --help )
53215990Sjmallett      usage
54215990Sjmallett      ;;
55215990Sjmallett
56215990Sjmallett    -q | --quiet )
57215990Sjmallett      qflag="true"
58215990Sjmallett      ;;
59215990Sjmallett
60232812Sjmallett    -v | --verbose )
61215990Sjmallett      vflag="true"
62215990Sjmallett      ;;
63215990Sjmallett
64215990Sjmallett    -s | --sequential )
65215990Sjmallett      sflag="true"
66215990Sjmallett      ;;
67232812Sjmallett
68215990Sjmallett    '--' ) # no more options
69215990Sjmallett      shift; break
70215990Sjmallett      ;;
71215990Sjmallett
72215990Sjmallett    -*)  # bad option
73215990Sjmallett      usage
74215990Sjmallett      ;;
75215990Sjmallett
76215990Sjmallett     * )  # non option
77215990Sjmallett      break
78215990Sjmallett      ;;
79232812Sjmallett  esac
80215990Sjmallett  shift
81215990Sjmallettdone
82215990Sjmallett
83215990Sjmallett# debug mode
84210284Sjmallettif [ "${HGFOREST_DEBUG:-false}" = "true" ] ; then
85215990Sjmallett  global_opts="${global_opts} --debug"
86210284Sjmallettfi
87215990Sjmallett
88215990Sjmallett# silence standard output?
89215990Sjmallettif [ ${qflag} = "true" ] ; then
90232816Sjmallett  global_opts="${global_opts} -q"
91215990Sjmallett  status_output="/dev/null"
92215990Sjmallettfi
93215990Sjmallett
94215990Sjmallett# verbose output?
95210284Sjmallettif [ ${vflag} = "true" ] ; then
96210284Sjmallett  global_opts="${global_opts} -v"
97210284Sjmallettfi
98210284Sjmallett
99210284Sjmallett# Make sure we have a command.
100210284Sjmallettif [ ${#} -lt 1 -o -z "${1:-}" ] ; then
101210284Sjmallett  echo "ERROR: No command to hg supplied!" > ${status_output}
102210284Sjmallett  usage > ${status_output}
103232812Sjmallettfi
104215990Sjmallett
105210284Sjmallett# grab command
106215990Sjmallettcommand="${1}"; shift
107210284Sjmallett
108210284Sjmallettif [ ${vflag} = "true" ] ; then
109210284Sjmallett  echo "# Mercurial command: ${command}" > ${status_output}
110232812Sjmallettfi
111210284Sjmallett
112210284Sjmallett# At this point all command options and args are in "$@".
113210284Sjmallett# Always use "$@" (within double quotes) to avoid breaking
114210284Sjmallett# args with spaces into separate args.
115210284Sjmallett
116232812Sjmallettif [ ${vflag} = "true" ] ; then
117232812Sjmallett  echo "# Mercurial command argument count: $#" > ${status_output}
118215990Sjmallett  for cmdarg in "$@" ; do
119215990Sjmallett    echo "# Mercurial command argument: ${cmdarg}" > ${status_output}
120215990Sjmallett  done
121210284Sjmallettfi
122210284Sjmallett
123210284Sjmallett# Clean out the temporary directory that stores the pid files.
124232812Sjmalletttmp=/tmp/forest.$$
125232812Sjmallettrm -f -r ${tmp}
126232812Sjmallettmkdir -p ${tmp}
127232812Sjmallett
128210284Sjmallett
129210284Sjmallettif [ "${HGFOREST_DEBUG:-false}" = "true" ] ; then
130210284Sjmallett  # ignores redirection.
131210284Sjmallett  echo "DEBUG: temp files are in: ${tmp}" >&2
132210284Sjmallettfi
133210284Sjmallett
134210284Sjmallett# Check if we can use fifos for monitoring sub-process completion.
135210284Sjmallettecho "1" > ${tmp}/read
136210284Sjmallettwhile_subshell=1
137210284Sjmallettwhile read line; do
138210284Sjmallett  while_subshell=0
139210284Sjmallett  break;
140210284Sjmallettdone < ${tmp}/read
141210284Sjmallettrm ${tmp}/read
142212844Sjmallett
143212844Sjmalletton_windows=`uname -s | egrep -ic -e 'cygwin|msys'`
144212844Sjmallett
145212844Sjmallettif [ ${while_subshell} = "1" -o ${on_windows} = "1" ]; then
146215014Sjmallett  # cygwin has (2014-04-18) broken (single writer only) FIFOs
147215014Sjmallett  # msys has (2014-04-18) no FIFOs.
148212844Sjmallett  # older shells create a sub-shell for redirect to while
149242104Sjmallett  have_fifos="false"
150242104Sjmallettelse
151242104Sjmallett  have_fifos="${HGFOREST_FIFOS:-true}"
152242104Sjmallettfi
153212844Sjmallett
154212844Sjmallettsafe_interrupt () {
155212844Sjmallett  if [ -d ${tmp} ]; then
156212844Sjmallett    if [ "`ls ${tmp}/*.pid`" != "" ]; then
157232812Sjmallett      echo "Waiting for processes ( `cat ${tmp}/.*.pid ${tmp}/*.pid 2> /dev/null | tr '\n' ' '`) to terminate nicely!" > ${status_output}
158232812Sjmallett      sleep 1
159232812Sjmallett      # Pipe stderr to dev/null to silence kill, that complains when trying to kill
160232812Sjmallett      # a subprocess that has already exited.
161232812Sjmallett      kill -TERM `cat ${tmp}/*.pid | tr '\n' ' '` 2> /dev/null
162232812Sjmallett      wait
163232812Sjmallett      echo "Interrupt complete!" > ${status_output}
164232812Sjmallett    fi
165232812Sjmallett    rm -f -r ${tmp}
166232812Sjmallett  fi
167210284Sjmallett  exit 130
168210284Sjmallett}
169210284Sjmallett
170210284Sjmallettnice_exit () {
171215990Sjmallett  if [ -d ${tmp} ]; then
172215990Sjmallett    if [ "`ls -A ${tmp} 2> /dev/null`" != "" ]; then
173215990Sjmallett      wait
174210284Sjmallett    fi
175210284Sjmallett    if [ "${HGFOREST_DEBUG:-false}" != "true" ] ; then
176210284Sjmallett      rm -f -r ${tmp}
177210284Sjmallett    fi
178210284Sjmallett  fi
179210284Sjmallett}
180210284Sjmallett
181210284Sjmalletttrap 'safe_interrupt' INT QUIT
182210284Sjmalletttrap 'nice_exit' EXIT
183210284Sjmallett
184210284Sjmallettsubrepos="corba jaxp jaxws langtools jdk hotspot nashorn"
185210284Sjmallettjdk_subrepos_extra="closed jdk/src/closed jdk/make/closed jdk/test/closed hotspot/make/closed hotspot/src/closed hotspot/test/closed"
186210284Sjmallettsubrepos_extra="$jdk_subrepos_extra deploy install sponsors pubs"
187232812Sjmallett
188232812Sjmallett# Only look in specific locations for possible forests (avoids long searches)
189232812Sjmallettpull_default=""
190232812Sjmallettrepos=""
191210284Sjmallettrepos_extra=""
192215990Sjmallettif [ "${command}" = "clone" -o "${command}" = "fclone" -o "${command}" = "tclone" ] ; then
193215990Sjmallett  # we must be a clone
194215990Sjmallett  if [ ! -f .hg/hgrc ] ; then
195210284Sjmallett    echo "ERROR: Need initial repository to use this script" > ${status_output}
196210284Sjmallett    exit 1
197210284Sjmallett  fi
198210284Sjmallett
199210284Sjmallett  # the clone must know where it came from (have a default pull path).
200210284Sjmallett  pull_default=`hg paths default`
201210284Sjmallett  if [ "${pull_default}" = "" ] ; then
202210284Sjmallett    echo "ERROR: Need initial clone with 'hg paths default' defined" > ${status_output}
203210284Sjmallett    exit 1
204210284Sjmallett  fi
205210284Sjmallett
206210284Sjmallett  # determine which sub repos need to be cloned.
207210284Sjmallett  for i in ${subrepos} ; do
208210284Sjmallett    if [ ! -f ${i}/.hg/hgrc ] ; then
209210284Sjmallett      repos="${repos} ${i}"
210232812Sjmallett    fi
211232812Sjmallett  done
212232812Sjmallett
213232812Sjmallett  pull_default_tail=`echo ${pull_default} | sed -e 's@^.*://[^/]*/\(.*\)@\1@'`
214232812Sjmallett
215232812Sjmallett  if [ $# -gt 0 ] ; then
216232812Sjmallett    if [ "x${1}" = "xjdk" ] ; then
217232812Sjmallett       subrepos_extra=$jdk_subrepos_extra
218232812Sjmallett       echo "subrepos being cloned are $subrepos_extra"
219232812Sjmallett       shift
220232812Sjmallett    fi
221232812Sjmallett    # if there is an "extra sources" path then reparent "extra" repos to that path
222232812Sjmallett    if [ "x${pull_default}" = "x${pull_default_tail}" ] ; then
223232812Sjmallett      echo "ERROR: Need initial clone from non-local source" > ${status_output}
224232812Sjmallett      exit 1
225232812Sjmallett    fi
226232812Sjmallett    # assume that "extra sources" path is the first arg
227232812Sjmallett    pull_extra="${1}/${pull_default_tail}"
228232812Sjmallett
229232812Sjmallett    # determine which extra subrepos need to be cloned.
230232812Sjmallett    for i in ${subrepos_extra} ; do
231232812Sjmallett      if [ ! -f ${i}/.hg/hgrc ] ; then
232232812Sjmallett        repos_extra="${repos_extra} ${i}"
233232812Sjmallett      fi
234232812Sjmallett    done
235232812Sjmallett  else
236232812Sjmallett    if [ "x${pull_default}" = "x${pull_default_tail}" ] ; then
237232812Sjmallett      # local source repo. Clone the "extra" subrepos that exist there.
238232812Sjmallett      for i in ${subrepos_extra} ; do
239232812Sjmallett        if [ -f ${pull_default}/${i}/.hg/hgrc -a ! -f ${i}/.hg/hgrc ] ; then
240232812Sjmallett          # sub-repo there in source but not here
241232812Sjmallett          repos_extra="${repos_extra} ${i}"
242232812Sjmallett        fi
243232812Sjmallett      done
244232812Sjmallett    fi
245232812Sjmallett  fi
246232812Sjmallett
247232812Sjmallett  # Any repos to deal with?
248232812Sjmallett  if [ "${repos}" = "" -a "${repos_extra}" = "" ] ; then
249232812Sjmallett    echo "No repositories to process." > ${status_output}
250232812Sjmallett    exit
251232812Sjmallett  fi
252232812Sjmallett
253232812Sjmallett  # Repos to process concurrently. Clone does better with low concurrency.
254232812Sjmallett  at_a_time="${HGFOREST_CONCURRENCY:-2}"
255232812Sjmallettelse
256232812Sjmallett  # Process command for all of the present repos
257232812Sjmallett  for i in . ${subrepos} ${subrepos_extra} ; do
258232812Sjmallett    if [ -d ${i}/.hg ] ; then
259232812Sjmallett      repos="${repos} ${i}"
260232812Sjmallett    fi
261232812Sjmallett  done
262232812Sjmallett
263232812Sjmallett  # Any repos to deal with?
264232812Sjmallett  if [ "${repos}" = "" ] ; then
265232812Sjmallett    echo "No repositories to process." > ${status_output}
266232812Sjmallett    exit
267232812Sjmallett  fi
268232812Sjmallett
269232812Sjmallett  # any of the repos locked?
270232812Sjmallett  locked=""
271232812Sjmallett  for i in ${repos} ; do
272232812Sjmallett    if [ -h ${i}/.hg/store/lock -o -f ${i}/.hg/store/lock ] ; then
273232812Sjmallett      locked="${i} ${locked}"
274232812Sjmallett    fi
275232812Sjmallett  done
276232812Sjmallett  if [ "${locked}" != "" ] ; then
277232812Sjmallett    echo "ERROR: These repositories are locked: ${locked}" > ${status_output}
278232812Sjmallett    exit 1
279232812Sjmallett  fi
280232812Sjmallett
281232812Sjmallett  # Repos to process concurrently.
282232812Sjmallett  at_a_time="${HGFOREST_CONCURRENCY:-8}"
283232812Sjmallettfi
284232812Sjmallett
285232812Sjmallett# Echo out what repositories we do a command on.
286232812Sjmallettecho "# Repositories: ${repos} ${repos_extra}" > ${status_output}
287232812Sjmallett
288232812Sjmallettif [ "${command}" = "serve" ] ; then
289232812Sjmallett  # "serve" is run for all the repos as one command.
290232812Sjmallett  (
291232812Sjmallett    (
292232812Sjmallett      cwd=`pwd`
293210284Sjmallett      serving=`basename ${cwd}`
294210284Sjmallett      (
295210284Sjmallett        echo "[web]"
296210284Sjmallett        echo "description = ${serving}"
297210284Sjmallett        echo "allow_push = *"
298232812Sjmallett        echo "push_ssl = False"
299232812Sjmallett
300232812Sjmallett        echo "[paths]"
301232812Sjmallett        for i in ${repos} ; do
302210284Sjmallett          if [ "${i}" != "." ] ; then
303210284Sjmallett            echo "/${serving}/${i} = ${i}"
304210284Sjmallett          else
305210284Sjmallett            echo "/${serving} = ${cwd}"
306210284Sjmallett          fi
307232812Sjmallett        done
308232812Sjmallett      ) > ${tmp}/serve.web-conf
309232812Sjmallett
310215990Sjmallett      echo "serving root repo ${serving}" > ${status_output}
311215990Sjmallett
312232812Sjmallett      echo "hg${global_opts} serve" > ${status_output}
313232812Sjmallett      (PYTHONUNBUFFERED=true hg${global_opts} serve -A ${status_output} -E ${status_output} --pid-file ${tmp}/serve.pid --web-conf ${tmp}/serve.web-conf; echo "$?" > ${tmp}/serve.pid.rc ) 2>&1 &
314232812Sjmallett    ) 2>&1 | sed -e "s@^@serve:   @" > ${status_output}
315232812Sjmallett  ) &
316232812Sjmallettelse
317215990Sjmallett  # Run the supplied command on all repos in parallel.
318215990Sjmallett
319215990Sjmallett  # n is the number of subprocess started or which might still be running.
320215990Sjmallett  n=0
321215990Sjmallett  if [ ${have_fifos} = "true" ]; then
322215990Sjmallett    # if we have fifos use them to detect command completion.
323215990Sjmallett    mkfifo ${tmp}/fifo
324232812Sjmallett    exec 3<>${tmp}/fifo
325232812Sjmallett  fi
326232812Sjmallett
327232812Sjmallett  # iterate over all of the subrepos.
328232812Sjmallett  for i in ${repos} ${repos_extra} ; do
329232812Sjmallett    n=`expr ${n} '+' 1`
330232812Sjmallett    repopidfile=`echo ${i} | sed -e 's@./@@' -e 's@/@_@g'`
331232812Sjmallett    reponame=`echo ${i} | sed -e :a -e 's/^.\{1,20\}$/ &/;ta'`
332232812Sjmallett    pull_base="${pull_default}"
333232812Sjmallett
334232812Sjmallett    # regular repo or "extra" repo?
335232812Sjmallett    for j in ${repos_extra} ; do
336232812Sjmallett      if [ "${i}" = "${j}" ] ; then
337232812Sjmallett        # it's an "extra"
338232812Sjmallett        if [ -n "${pull_extra}" ]; then
339232812Sjmallett          # if no pull_extra is defined, assume that pull_default is valid
340232812Sjmallett          pull_base="${pull_extra}"
341232812Sjmallett        fi
342232812Sjmallett      fi
343232812Sjmallett    done
344232812Sjmallett
345232812Sjmallett    # remove trailing slash
346232812Sjmallett    pull_base="`echo ${pull_base} | sed -e 's@[/]*$@@'`"
347232812Sjmallett
348232812Sjmallett    # execute the command on the subrepo
349232812Sjmallett    (
350232812Sjmallett      (
351232812Sjmallett        if [ "${command}" = "clone" -o "${command}" = "fclone" -o "${command}" = "tclone" ] ; then
352232812Sjmallett          # some form of clone
353232812Sjmallett          clone_newrepo="${pull_base}/${i}"
354232812Sjmallett          parent_path="`dirname ${i}`"
355232812Sjmallett          if [ "${parent_path}" != "." ] ; then
356232812Sjmallett            times=0
357232812Sjmallett            while [ ! -d "${parent_path}" ] ; do  ## nested repo, ensure containing dir exists
358232812Sjmallett              if [ "${sflag}" = "true" ] ; then
359232812Sjmallett                # Missing parent is fatal during sequential operation.
360232812Sjmallett                echo "ERROR: Missing parent path: ${parent_path}" > ${status_output}
361232812Sjmallett                exit 1
362232812Sjmallett              fi
363232812Sjmallett              times=`expr ${times} '+' 1`
364232812Sjmallett              if [ `expr ${times} '%' 10` -eq 0 ] ; then
365232812Sjmallett                echo "${parent_path} still not created, waiting..." > ${status_output}
366232812Sjmallett              fi
367232812Sjmallett              sleep 5
368232812Sjmallett            done
369232812Sjmallett          fi
370232812Sjmallett          # run the clone command.
371232812Sjmallett          echo "hg${global_opts} clone ${clone_newrepo} ${i}" > ${status_output}
372232812Sjmallett          (PYTHONUNBUFFERED=true hg${global_opts} clone ${clone_newrepo} ${i}; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 &
373232812Sjmallett        else
374232812Sjmallett          # run the command.
375232812Sjmallett          echo "cd ${i} && hg${global_opts} ${command} ${@}" > ${status_output}
376232812Sjmallett          cd ${i} && (PYTHONUNBUFFERED=true hg${global_opts} ${command} "${@}"; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 &
377232812Sjmallett        fi
378210284Sjmallett
379210284Sjmallett        echo $! > ${tmp}/${repopidfile}.pid
380210284Sjmallett      ) 2>&1 | sed -e "s@^@${reponame}:   @" > ${status_output}
381210284Sjmallett      # tell the fifo waiter that this subprocess is done.
382210284Sjmallett      if [ ${have_fifos} = "true" ]; then
383210284Sjmallett        echo "${i}" >&3
384210284Sjmallett      fi
385210284Sjmallett    ) &
386210284Sjmallett
387210284Sjmallett    if [ "${sflag}" = "true" ] ; then
388210284Sjmallett      # complete this task before starting another.
389232812Sjmallett      wait
390232812Sjmallett    else
391232812Sjmallett      if [ "${have_fifos}" = "true" ]; then
392232812Sjmallett        # check on count of running subprocesses and possibly wait for completion
393232812Sjmallett        if [ ${n} -ge ${at_a_time} ] ; then
394232812Sjmallett          # read will block until there are completed subprocesses
395232812Sjmallett          while read repo_done; do
396210284Sjmallett            n=`expr ${n} '-' 1`
397210284Sjmallett            if [ ${n} -lt ${at_a_time} ] ; then
398210284Sjmallett              # we should start more subprocesses
399210284Sjmallett              break;
400210284Sjmallett            fi
401210284Sjmallett          done <&3
402210284Sjmallett        fi
403210284Sjmallett      else
404210284Sjmallett        # Compare completions to starts
405210284Sjmallett        completed="`(ls -a1 ${tmp}/*.pid.rc 2> /dev/null | wc -l) || echo 0`"
406210284Sjmallett        while [ `expr ${n} '-' ${completed}` -ge ${at_a_time} ] ; do
407210284Sjmallett          # sleep a short time to give time for something to complete
408210284Sjmallett          sleep 1
409210284Sjmallett          completed="`(ls -a1 ${tmp}/*.pid.rc 2> /dev/null | wc -l) || echo 0`"
410210284Sjmallett        done
411232812Sjmallett      fi
412215990Sjmallett    fi
413232812Sjmallett  done
414232812Sjmallett
415232812Sjmallett  if [ ${have_fifos} = "true" ]; then
416232812Sjmallett    # done with the fifo
417232812Sjmallett    exec 3>&-
418232812Sjmallett  fi
419215990Sjmallettfi
420210284Sjmallett
421210284Sjmallett# Wait for all subprocesses to complete
422210284Sjmallettwait
423210284Sjmallett
424210284Sjmallett# Terminate with exit 0 only if all subprocesses were successful
425210284Sjmallett# Terminate with highest exit code of subprocesses
426210284Sjmallettec=0
427210284Sjmallettif [ -d ${tmp} ]; then
428210284Sjmallett  rcfiles="`(ls -a ${tmp}/*.pid.rc 2> /dev/null) || echo ''`"
429210284Sjmallett  for rc in ${rcfiles} ; do
430210284Sjmallett    exit_code=`cat ${rc} | tr -d ' \n\r'`
431210284Sjmallett    if [ "${exit_code}" != "0" ] ; then
432210284Sjmallett      if [ ${exit_code} -gt 1 ]; then
433210284Sjmallett        # mercurial exit codes greater than "1" signal errors.
434210284Sjmallett      repo="`echo ${rc} | sed -e 's@^'${tmp}'@@' -e 's@/*\([^/]*\)\.pid\.rc$@\1@' -e 's@_@/@g'`"
435210284Sjmallett      echo "WARNING: ${repo} exited abnormally (${exit_code})" > ${status_output}
436215990Sjmallett      fi
437215990Sjmallett      if [ ${exit_code} -gt ${ec} ]; then
438215990Sjmallett        # assume that larger exit codes are more significant
439210284Sjmallett        ec=${exit_code}
440210284Sjmallett      fi
441210284Sjmallett    fi
442210284Sjmallett  done
443210284Sjmallettfi
444210284Sjmallettexit ${ec}
445210284Sjmallett