6731044 wx2hg should deal better with nested repositories

   1 #! /usr/bin/ksh
   2 #
   3 # CDDL HEADER START
   4 #
   5 # The contents of this file are subject to the terms of the
   6 # Common Development and Distribution License (the "License").
   7 # You may not use this file except in compliance with the License.
   8 #
   9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10 # or http://www.opensolaris.org/os/licensing.
  11 # See the License for the specific language governing permissions
  12 # and limitations under the License.
  13 #
  14 # When distributing Covered Code, include this CDDL HEADER in each
  15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16 # If applicable, add the following below this CDDL HEADER, with the
  17 # fields enclosed by brackets "[]" replaced with your own identifying
  18 # information: Portions Copyright [yyyy] [name of copyright owner]
  19 #
  20 # CDDL HEADER END
  21 #
  22 
  23 #
  24 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  25 # Use is subject to license terms.
  26 #
  27 # ident "@(#)wx2hg.sh   1.2     08/07/18 SMI"
  28 #
  29 
  30 #
  31 # Convert a wx-based workspace to Mercurial.
  32 #
  33 
  34 usage="wx2hg [-u] [-r hg_rev] [-t hg_ws] codemgr_ws"
  35 
  36 #
  37 # If "yes", then give some hints about cleanup and rerunning after a
  38 # failure.
  39 #
  40 can_retry=no
  41 tail=/usr/xpg4/bin/tail
  42 
  43 function has_hg_twin {
  44         [[ -f "$1"/Codemgr_wsdata/hg_twin ]]
  45 }
  46 
  47 function clone_twin {
  48         twinfile="$1"/Codemgr_wsdata/hg_twin
  49         twin=$(head -1 "$twinfile")
  50         ws="$2"
  51         rev="$3"
  52 
  53         echo "Teamware parent $1 has an hg twin"
  54 
  55         clonedirs=$($tail -n +2 "$twinfile")
  56         echo "Cloning $twin"
  57         echo "to $ws"
  58         set -x
  59         hg clone -r $rev "$twin" "$ws"
  60         set +x
  61         for dir in $clonedirs; do
  62                 echo "Cloning from $twin/$dir"
  63                 echo "to $ws/$dir"
  64                 hg clone -r $rev "$twin"/$dir "$ws"/$dir
  65         done
  66 }
  67 
  68 
  69 function fail {
  70         print -u2 wx2hg: "$@"
  71         if [[ "$can_retry" = yes ]]; then
  72                 print -u2 "Please run"
  73                 print -u2 "  hg --cwd $hg_ws update -C"
  74                 print -u2 "before retrying."
  75         fi
  76         exit 1
  77 }
  78 
  79 function warn {
  80         print -u2 wx2hg: warning: "$@"
  81 }
  82 
  83 function note {
  84         print -u2 wx2hg: note: "$@"
























  85 }
  86 
  87 #
  88 # Command-line processing, sanity checks, and setup.
  89 #
  90 
  91 [[ -n $(whence workspace) ]] || 
  92     fail "workspace command not found; please check PATH."
  93 
  94 # do a wx update?
  95 do_update=yes
  96 
  97 #
  98 # Mercurial workspace to populate.  Default is to create, in the same
  99 # directory as the Teamware workspace, a new Mercurial workspace cloned
 100 # from the hg_twin of the Teamware parent.
 101 #
 102 hg_ws=""
 103 
 104 #
 105 # Revision in the Mercurial workspace to apply the changes to.
 106 # Default is to get the most recent revision (tip), thus avoiding
 107 # the need for a merge unless overridden by the caller using -r.
 108 #
 109 hg_rev="tip"
 110 
 111 while getopts r:t:u opt; do
 112         case $opt in
 113         r)      hg_rev="$OPTARG";;
 114         t)      hg_ws="$OPTARG";;
 115         u)      do_update=no;;
 116         ?)      print -u2 "usage: $usage"; exit 1;;
 117         esac
 118 done
 119 shift $(($OPTIND - 1))
 120 
 121 if [[ $# -ne 1 ]]; then
 122         print -u2 "usage: $usage"
 123         exit 1
 124 fi
 125 
 126 CODEMGR_WS="$1"
 127 [[ "$CODEMGR_WS" = /* ]] || CODEMGR_WS="$(pwd)/$CODEMGR_WS"
 128 export CODEMGR_WS
 129 
 130 if [[ -n "$hg_ws" ]]; then
 131         if [[ ! -d "$hg_ws" || ! -d "$hg_ws/.hg" ]]; then
 132                 fail "$hg_ws is not a Mercurial workspace."
 133         fi
 134         [[ "$hg_ws" = /* ]] || hg_ws="$(pwd)/$hg_ws"
 135 fi
 136 
 137 [[ -d "$CODEMGR_WS" ]] || fail "$CODEMGR_WS does not exist."
 138 cd "$CODEMGR_WS"
 139 
 140 codemgr_parent=$(workspace parent)
 141 [[ -n "$codemgr_parent" ]] || \
 142     fail "$CODEMGR_WS is not a Teamware workspace or does not have a parent."
 143 [[ -d "$codemgr_parent" ]] || fail "parent ($codemgr_parent) doesn't exist."
 144 














 145 #
 146 # Do this check before time-consuming operations like creating
 147 # the target repo.
 148 #
 149 his=$(find Codemgr_wsdata -name history -mtime -1)
 150 if [[ -z "$his" ]]; then
 151         warn "history file is more than one day old; do you need to" \
 152             "bringover from $codemgr_parent?"
 153 fi
 154 
 155 # Less time-consuming than cloning
 156 
 157 if [[ ! -d wx ]]; then
 158         print "Initializing wx..."
 159         wx init -ft
 160 else
 161         if [[ "$do_update" = yes ]]; then
 162                 print "Updating wx state..."
 163                 wx update
 164         fi
 165 fi
 166 
 167 wx outchk
 168 
 169 out_files=$(wx out)
 170 active_files=$(wx list)
 171 
 172 if [[ ! -z "$out_files" ]]; then
 173         fail "wx2hg will only migrate checked-in files;" \
 174             "please check in these files with wx ci and try again"
 175 fi
 176 
 177 # more time-consuming than wx update and wx outchk
 178 
 179 if [[ -z "$hg_ws" ]]; then
 180         ws=$(basename $(pwd))
 181         hg_ws=$(dirname $(pwd))/"$ws-hg"
 182 fi
 183 
 184 if [[ -d "$hg_ws" ]]; then
 185         echo "Updating preexisting Mercurial workspace $hg_ws to $hg_rev\n"
 186         (cd "$hg_ws"; hg update -C $hg_rev) ||
 187             fail "hg update $hg_rev failed for $hg_ws"
























 188 else
 189         if has_hg_twin "$codemgr_parent"; then
 190                 clone_twin "$codemgr_parent" "$hg_ws" $hg_rev
 191         else
 192                 fail "$codemgr_parent is not recognized as a gate;" \
 193                     "please provide a Mercurial workspace (-t hg_ws)" \
 194                     "that matches it."
 195         fi
 196 fi
 197 
 198 can_retry=yes
 199 
 200 # Make sure hg_ws is an absolute path
 201 [[ "$hg_ws" = /* ]] || hg_ws="$(pwd)/$hg_ws"
 202 















 203 #
 204 # Do renames first, because they'll be listed with the new name by "wx
 205 # list".  There's a conflict if the new name already exists or if the
 206 # old name does not exist.  We can theoretically recover from the
 207 # former (move the existing file out of the way, or pick a different
 208 # new name), but not the latter.  For now, just error out and let the
 209 # user fix up the workspace so that there isn't a conflict.
 210 #
 211 
 212 renamelist=/tmp/wxrename$$
 213 wx renamed > "$renamelist"
 214 
 215 # usage: do_rename oldname newname
 216 function do_rename {
 217         typeset old=$1
 218         typeset new=$2
 219 
 220         print "rename $old -> $new"





 221         [[ -f "$old" ]] || fail "can't rename: $old doesn't exist."
 222         [[ ! -f "$new" ]] || fail "can't rename: $new already exists."







 223         set -x
 224         hg mv $old $new || fail "rename failed."

 225         set +x









 226 }
 227 
 228 if [[ -s "$renamelist" ]]; then
 229         cat "$renamelist" | (
 230                 cd "$hg_ws"
 231                 while :; do
 232                         read newname oldname
 233                         [[ -n "$newname" ]] || break
 234                         do_rename "$oldname" "$newname"
 235                 done
 236         ) || exit 1
 237 fi
 238 
 239 #
 240 # usage: name_in_parent fname
 241 # If fname had been renamed, echo the old name.  Otherwise echo the
 242 # given name.
 243 #
 244 function name_in_parent {
 245         typeset new old
 246 
 247         if [[ -s "$renamelist" ]]; then
 248                 cat "$renamelist" | while :; do
 249                         read new old
 250                         [[ -n "$new" ]] || break
 251                         if [[ "$1" = "$new" ]]; then
 252                                 print "$old"
 253                                 return
 254                         fi
 255                 done
 256         fi
 257         print "$1"
 258 }
 259 
 260 #
 261 # Now do content changes.  There's a likely conflict if the file in
 262 # Mercurial is different from the file in the Teamware parent.
 263 #
 264 
 265 parentfile=/tmp/parent$$
 266 patchfile=/tmp/patch$$
 267 childfile=/tmp/child$$
 268 
 269 [[ -n "$active_files" ]] || warn "no files in active list."
 270 
 271 for f in $active_files; do
 272         #
 273         # Get the name that the file appears in the parent as.
 274         #
 275         oldname=$(name_in_parent "$f")
 276 
 277         # We need unexpanded SCCS keywords for both parent and child
 278         sccs get -skp "$f" > "$childfile"
 279 
 280         if [[ -f "$codemgr_parent/$oldname" ]]; then
 281                 (cd $codemgr_parent; sccs get -skp "$oldname" > "$parentfile")
 282         else
 283                 rm -f $parentfile
 284         fi
 285 
 286         if [[ ! -r "$parentfile" ]]; then
 287                 print "new file: $f"
 288                 [[ ! -f "$hg_ws/$f" ]] || fail "$f already exists in $hg_ws."
 289                 dir=$(dirname "$hg_ws/$f")
 290                 base=$(basename "$hg_ws/$f")
 291                 [[ -d "$dir" ]] || mkdir -p "$dir" || fail "mkdir failed"
 292                 cp "$childfile" "$hg_ws/$f" || fail "copy failed"
 293                 set -x
 294                 (cd "$dir" && hg add "$base") || fail "hg add failed."
 295                 set +x
 296         elif diff "$parentfile" "$hg_ws/$f" > /dev/null 2>&1; then
 297                 if diff -u "$parentfile" "$childfile" > "$patchfile"; then
 298                         print "skipping $f (unchanged)."
 299                         continue
 300                 fi
 301                 (cd "$hg_ws"; gpatch -F0 $f < "$patchfile")
 302                 [[ $? -eq 0 ]] || fail "$f: patch failed."
 303         else
 304                 diff -u "$parentfile" "$hg_ws/$f"
 305                 echo ""
 306 
 307                 fail "For file:\n\n\t$f\n\nthe teamware parent:" \
 308                     "\n\n\t$codemgr_parent" \
 309                     "\n\ndoesn't match its mercurial twin;" \
 310                         "specify the matching revision in mercurial\nwith" \
 311                         "-r hg_rev, or resynchronize them.\n"
 312         fi
 313 done
 314 
 315 note "remember to commit your changes in $hg_ws"






 316 
 317 if [[ "$hg_rev" != "tip" ]]; then
 318         note "before you integrate your changes, $hg_ws must be merged to tip"
 319 fi
 320 
 321 rm -f "$parentfile" "$patchfile" "$renamelist" "$childfile"
 322 
 323 exit 0
--- EOF ---