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 ---