Print this page
teamware must die


 629 #      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
 630 #      NR==8           {wl("#7A7ADD");next}
 631 #      NR==54          {wl("#7A7ADD");sp(3);next}
 632 #      NR==56          {wl("#7A7ADD");next}
 633 #      NR==57          {wl("black");printf "\n"; next}
 634 #        :               :
 635 #
 636 #  This script is then run on the original source file to generate the
 637 #  HTML that corresponds to the source file.
 638 #
 639 #  The two HTML files are then combined into a single piece of HTML that
 640 #  uses an HTML table construct to present the files side by side.  You'll
 641 #  notice that the changes are color-coded:
 642 #
 643 #   black     - unchanged lines
 644 #   blue      - changed lines
 645 #   bold blue - new lines
 646 #   brown     - deleted lines
 647 #
 648 #  Blank lines are inserted in each file to keep unchanged lines in sync
 649 #  (side-by-side).  This format is familiar to users of sdiff(1) or
 650 #  Teamware's filemerge tool.
 651 #
 652 sdiff_to_html()
 653 {
 654         diff -b $1 $2 > /tmp/$$.diffs
 655 
 656         TNAME=$3
 657         TPATH=$4
 658         COMMENT=$5
 659 
 660         #
 661         #  Now we have the diffs, generate the HTML for the old file.
 662         #
 663         $AWK '
 664         BEGIN   {
 665                 printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
 666                 printf "function removed() "
 667                 printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
 668                 printf "function changed() "
 669                 printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
 670                 printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"


1415 
1416 #
1417 # source_to_html { new | old } <filename>
1418 #
1419 # Process a plain vanilla source file to transform it into an HTML file.
1420 #
1421 source_to_html()
1422 {
1423         WHICH=$1
1424         TNAME=$2
1425 
1426         print "$HTML<head>$STDHEAD"
1427         print "<title>$WNAME $WHICH $TNAME</title>"
1428         print "<body id=\"SUNWwebrev\">"
1429         print "<pre>"
1430         html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1431         print "</pre></body></html>"
1432 }
1433 
1434 #
1435 # comments_from_teamware {text|html} parent-file child-file
1436 #
1437 # Find the first delta in the child that's not in the parent.  Get the
1438 # newest delta from the parent, get all deltas from the child starting
1439 # with that delta, and then get all info starting with the second oldest
1440 # delta in that list (the first delta unique to the child).
1441 #
1442 # This code adapted from Bill Shannon's "spc" script
1443 #
1444 comments_from_teamware()
1445 {
1446         fmt=$1
1447         pfile=$PWS/$2
1448         cfile=$CWS/$3
1449 
1450         if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
1451                 pfile=$RWS/$2
1452         fi
1453 
1454         if [[ -f $pfile ]]; then
1455                 psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
1456         else
1457                 psid=1.1
1458         fi
1459 
1460         set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
1461         N=${#sids[@]}
1462 
1463         nawkprg='
1464                 /^COMMENTS:/    {p=1; continue}
1465                 /^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
1466                 NF == 0u        { continue }
1467                 {if (p==0) continue; print $0 }'
1468 
1469         if [[ $N -ge 2 ]]; then
1470                 sid1=${sids[$((N-2))]}  # Gets 2nd to last sid
1471 
1472                 if [[ $fmt == "text" ]]; then
1473                         $SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1474                             $AWK "$nawkprg"
1475                         return
1476                 fi
1477 
1478                 $SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1479                     html_quote | its2url | $AWK "$nawkprg"
1480         fi
1481 }
1482 
1483 #
1484 # comments_from_wx {text|html} filepath
1485 #
1486 # Given the pathname of a file, find its location in a "wx" active
1487 # file list and print the following comment.  Output is either text or
1488 # HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1489 # are turned into URLs.
1490 #
1491 # This is also used with Mercurial and the file list provided by hg-active.
1492 #
1493 comments_from_wx()
1494 {
1495         typeset fmt=$1
1496         typeset p=$2
1497 
1498         comm=`$AWK '
1499         $1 == "'$p'" {
1500                 do getline ; while (NF > 0)
1501                 getline
1502                 while (NF > 0) { print ; getline }
1503                 exit


1519 #
1520 # getcomments {text|html} filepath parentpath
1521 #
1522 # Fetch the comments depending on what SCM mode we're in.
1523 #
1524 getcomments()
1525 {
1526         typeset fmt=$1
1527         typeset p=$2
1528         typeset pp=$3
1529 
1530         if [[ -n $Nflag ]]; then
1531                 return
1532         fi
1533         #
1534         # Mercurial support uses a file list in wx format, so this
1535         # will be used there, too
1536         #
1537         if [[ -n $wxfile ]]; then
1538                 comments_from_wx $fmt $p
1539         else
1540                 if [[ $SCM_MODE == "teamware" ]]; then
1541                         comments_from_teamware $fmt $pp $p
1542                 fi
1543         fi
1544 }
1545 
1546 #
1547 # printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1548 #
1549 # Print out Code Inspection figures similar to sccs-prt(1) format.
1550 #
1551 function printCI
1552 {
1553         integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1554         typeset str
1555         if (( tot == 1 )); then
1556                 str="line"
1557         else
1558                 str="lines"
1559         fi
1560         printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1561             $tot $str $ins $del $mod $unc
1562 }


1701                 #
1702                 # If the wx file pathname is relative then make it absolute
1703                 # because the webrev does a "cd" later on.
1704                 #
1705                 wxfile=$PWD/$argfile
1706         else
1707                 wxfile=$argfile
1708         fi
1709 
1710         $AWK '{ c = 1; print;
1711           while (getline) {
1712                 if (NF == 0) { c = -c; continue }
1713                 if (c > 0) print
1714           }
1715         }' $wxfile > $FLIST
1716 
1717         print " Done."
1718 }
1719 
1720 #
1721 # flist_from_teamware [ <args-to-putback-n> ]
1722 #
1723 # Generate the file list by extracting file names from a putback -n.  Some
1724 # names may come from the "update/create" messages and others from the
1725 # "currently checked out" warning.  Renames are detected here too.  Extract
1726 # values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
1727 # -n as well, but remove them if they are already defined.
1728 #
1729 function flist_from_teamware
1730 {
1731         if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
1732                 if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
1733                         print -u2 "parent $codemgr_parent doesn't look like a" \
1734                             "valid teamware workspace"
1735                         exit 1
1736                 fi
1737                 parent_args="-p $codemgr_parent"
1738         fi
1739 
1740         print " File list from: 'putback -n $parent_args $*' ... \c"
1741 
1742         putback -n $parent_args $* 2>&1 |
1743             $AWK '
1744                 /^update:|^create:/     {print $2}
1745                 /^Parent workspace:/    {printf("CODEMGR_PARENT=%s\n",$3)}
1746                 /^Child workspace:/     {printf("CODEMGR_WS=%s\n",$3)}
1747                 /^The following files are currently checked out/ {p = 1; continue}
1748                 NF == 0                 {p=0 ; continue}
1749                 /^rename/               {old=$3}
1750                 $1 == "to:"             {print $2, old}
1751                 /^"/                    {continue}
1752                 p == 1                  {print $1}' |
1753             sort -r -k 1,1 -u | sort > $FLIST
1754 
1755         print " Done."
1756 }
1757 
1758 #
1759 # Call hg-active to get the active list output in the wx active list format
1760 #
1761 function hg_active_wxfile
1762 {
1763         typeset child=$1
1764         typeset parent=$2
1765 
1766         TMPFLIST=/tmp/$$.active
1767         $HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1768         wxfile=$TMPFLIST
1769 }
1770 
1771 #
1772 # flist_from_mercurial
1773 # Call hg-active to get a wx-style active list, and hand it off to
1774 # flist_from_wx
1775 #
1776 function flist_from_mercurial
1777 {
1778         typeset child=$1


1899                 export CODEMGR_WS
1900         fi
1901 
1902         #
1903         # Check to see if CODEMGR_PARENT is set in the flist file.
1904         #
1905         if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1906                 codemgr_parent=$CODEMGR_PARENT
1907                 export CODEMGR_PARENT
1908         fi
1909 }
1910 
1911 function look_for_prog
1912 {
1913         typeset path
1914         typeset ppath
1915         typeset progname=$1
1916 
1917         ppath=$PATH
1918         ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
1919         ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
1920         ppath=$ppath:/opt/onbld/bin/`uname -p`
1921 
1922         PATH=$ppath prog=`whence $progname`
1923         if [[ -n $prog ]]; then
1924                 print $prog
1925         fi
1926 }
1927 
1928 function get_file_mode
1929 {
1930         $PERL -e '
1931                 if (@stat = stat($ARGV[0])) {
1932                         $mode = $stat[2] & 0777;
1933                         printf "%03o\n", $mode;
1934                         exit 0;
1935                 } else {
1936                         exit 1;
1937                 }
1938             ' $1
1939 }
1940 
1941 function build_old_new_teamware
1942 {
1943         typeset olddir="$1"
1944         typeset newdir="$2"
1945 
1946         # If the child's version doesn't exist then
1947         # get a readonly copy.
1948 
1949         if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
1950                 $SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
1951         fi
1952 
1953         # The following two sections propagate file permissions the
1954         # same way SCCS does.  If the file is already under version
1955         # control, always use permissions from the SCCS/s.file.  If
1956         # the file is not under SCCS control, use permissions from the
1957         # working copy.  In all cases, the file copied to the webrev
1958         # is set to read only, and group/other permissions are set to
1959         # match those of the file owner.  This way, even if the file
1960         # is currently checked out, the webrev will display the final
1961         # permissions that would result after check in.
1962 
1963         #
1964         # Snag new version of file.
1965         #
1966         rm -f $newdir/$DIR/$F
1967         cp $CWS/$DIR/$F $newdir/$DIR/$F
1968         if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
1969                 chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
1970                     $newdir/$DIR/$F
1971         fi
1972         chmod u-w,go=u $newdir/$DIR/$F
1973 
1974         #
1975         # Get the parent's version of the file. First see whether the
1976         # child's version is checked out and get the parent's version
1977         # with keywords expanded or unexpanded as appropriate.
1978         #
1979         if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
1980             ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
1981                 # Parent is not a real workspace, but just a raw
1982                 # directory tree - use the file that's there as
1983                 # the old file.
1984 
1985                 rm -f $olddir/$PDIR/$PF
1986                 cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1987         else
1988                 if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
1989                         real_parent=$PWS
1990                 else
1991                         real_parent=$RWS
1992                 fi
1993 
1994                 rm -f $olddir/$PDIR/$PF
1995 
1996                 if [[ -f $real_parent/$PDIR/$PF ]]; then
1997                         if [ -f $CWS/$DIR/SCCS/p.$F ]; then
1998                                 $SCCS get -s -p -k $real_parent/$PDIR/$PF > \
1999                                     $olddir/$PDIR/$PF
2000                         else
2001                                 $SCCS get -s -p    $real_parent/$PDIR/$PF > \
2002                                     $olddir/$PDIR/$PF
2003                         fi
2004                         chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
2005                             $olddir/$PDIR/$PF
2006                 fi
2007         fi
2008         if [[ -f $olddir/$PDIR/$PF ]]; then
2009                 chmod u-w,go=u $olddir/$PDIR/$PF
2010         fi
2011 }
2012 
2013 function build_old_new_mercurial
2014 {
2015         typeset olddir="$1"
2016         typeset newdir="$2"
2017         typeset old_mode=
2018         typeset new_mode=
2019         typeset file
2020 
2021         #
2022         # Get old file mode, from the parent revision manifest entry.
2023         # Mercurial only stores a "file is executable" flag, but the
2024         # manifest will display an octal mode "644" or "755".
2025         #
2026         if [[ "$PDIR" == "." ]]; then
2027                 file="$PF"
2028         else
2029                 file="$PDIR/$PF"
2030         fi
2031         file=`echo $file | $SED 's#/#\\\/#g'`
2032         # match the exact filename, and return only the permission digits


2183                 cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2184         fi
2185 }
2186 
2187 function build_old_new
2188 {
2189         typeset WDIR=$1
2190         typeset PWS=$2
2191         typeset PDIR=$3
2192         typeset PF=$4
2193         typeset CWS=$5
2194         typeset DIR=$6
2195         typeset F=$7
2196 
2197         typeset olddir="$WDIR/raw_files/old"
2198         typeset newdir="$WDIR/raw_files/new"
2199 
2200         mkdir -p $olddir/$PDIR
2201         mkdir -p $newdir/$DIR
2202 
2203         if [[ $SCM_MODE == "teamware" ]]; then
2204                 build_old_new_teamware "$olddir" "$newdir"
2205         elif [[ $SCM_MODE == "mercurial" ]]; then
2206                 build_old_new_mercurial "$olddir" "$newdir"
2207         elif [[ $SCM_MODE == "git" ]]; then
2208                 build_old_new_git "$olddir" "$newdir"
2209         elif [[ $SCM_MODE == "subversion" ]]; then
2210                 build_old_new_subversion "$olddir" "$newdir"
2211         elif [[ $SCM_MODE == "unknown" ]]; then
2212                 build_old_new_unknown "$olddir" "$newdir"
2213         fi
2214 
2215         if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
2216                 print "*** Error: file not in parent or child"
2217                 return 1
2218         fi
2219         return 0
2220 }
2221 
2222 
2223 #
2224 # Usage message.
2225 #


2229         webrev [common-options] ( <file> | - )
2230         webrev [common-options] -w <wx file>
2231 
2232 Options:
2233         -C <filename>: Use <filename> for the information tracking configuration.
2234         -D: delete remote webrev
2235         -i <filename>: Include <filename> in the index.html file.
2236         -I <filename>: Use <filename> for the information tracking registry.
2237         -n: do not generate the webrev (useful with -U)
2238         -O: Print bugids/arc cases suitable for OpenSolaris.
2239         -o <outdir>: Output webrev to specified directory.
2240         -p <compare-against>: Use specified parent wkspc or basis for comparison
2241         -t <remote_target>: Specify remote destination for webrev upload
2242         -U: upload the webrev to remote destination
2243         -w <wxfile>: Use specified wx active file.
2244 
2245 Environment:
2246         WDIR: Control the output directory.
2247         WEBREV_TRASH_DIR: Set directory for webrev delete.
2248 
2249 SCM Specific Options:
2250         TeamWare: webrev [common-options] -l [arguments to 'putback']
2251 
2252 SCM Environment:
2253         CODEMGR_WS: Workspace location.
2254         CODEMGR_PARENT: Parent workspace location.
2255 '
2256 
2257         exit 2
2258 }
2259 
2260 #
2261 #
2262 # Main program starts here
2263 #
2264 #
2265 
2266 trap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
2267 
2268 set +o noclobber
2269 
2270 PATH=$(/bin/dirname "$(whence $0)"):$PATH
2271 
2272 [[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
2273 [[ -z $WX ]] && WX=`look_for_prog wx`
2274 [[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
2275 [[ -z $GIT ]] && GIT=`look_for_prog git`
2276 [[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`


2398 
2399 # more sanity checking
2400 if [[ -n $nflag && -z $Uflag ]]; then
2401         print "it does not make sense to skip webrev generation" \
2402             "without -U"
2403         exit 1
2404 fi
2405 
2406 if [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2407         echo "remote target has to be used only for upload or delete"
2408         exit 1
2409 fi
2410 
2411 #
2412 # For the invocation "webrev -n -U" with no other options, webrev will assume
2413 # that the webrev exists in ${CWS}/webrev, but will upload it using the name
2414 # $(basename ${CWS}).  So we need to get CWS set before we skip any remaining
2415 # logic.
2416 #
2417 $WHICH_SCM | read SCM_MODE junk || exit 1
2418 if [[ $SCM_MODE == "teamware" ]]; then
2419         #
2420         # Teamware priorities:
2421         # 1. CODEMGR_WS from the environment
2422         # 2. workspace name
2423         #
2424         [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
2425         if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
2426                 print -u2 "$codemgr_ws: no such workspace"
2427                 exit 1
2428         fi
2429         [[ -z $codemgr_ws ]] && codemgr_ws=$(workspace name)
2430         codemgr_ws=$(cd $codemgr_ws;print $PWD)
2431         CODEMGR_WS=$codemgr_ws
2432         CWS=$codemgr_ws
2433 elif [[ $SCM_MODE == "mercurial" ]]; then
2434         #
2435         # Mercurial priorities:
2436         # 1. hg root from CODEMGR_WS environment variable
2437         # 1a. hg root from CODEMGR_WS/usr/closed if we're somewhere under
2438         #    usr/closed when we run webrev
2439         # 2. hg root from directory of invocation
2440         #
2441         if [[ ${PWD} =~ "usr/closed" ]]; then
2442                 testparent=${CODEMGR_WS}/usr/closed
2443                 # If we're in OpenSolaris mode, we enforce a minor policy:
2444                 # help to make sure the reviewer doesn't accidentally publish
2445                 # source which is under usr/closed
2446                 if [[ -n "$Oflag" ]]; then
2447                         print -u2 "OpenSolaris output not permitted with" \
2448                             "usr/closed changes"
2449                         exit 1
2450                 fi
2451         else
2452                 testparent=${CODEMGR_WS}
2453         fi


2539         elif [[ -n $1 ]]; then
2540                 if [[ ! -r $1 ]]; then
2541                         print -u2 "$1: no such file or not readable"
2542                         usage
2543                 fi
2544                 cat $1 > $FLIST
2545                 flist_mode="file"
2546                 flist_file=$1
2547                 flist_done=1
2548                 shift
2549         else
2550                 flist_mode="auto"
2551         fi
2552 fi
2553 
2554 #
2555 # Before we go on to further consider -l and -w, work out which SCM we think
2556 # is in use.
2557 #
2558 case "$SCM_MODE" in
2559 teamware|mercurial|git|subversion)
2560         ;;
2561 unknown)
2562         if [[ $flist_mode == "auto" ]]; then
2563                 print -u2 "Unable to determine SCM in use and file list not specified"
2564                 print -u2 "See which_scm(1) for SCM detection information."
2565                 exit 1
2566         fi
2567         ;;
2568 *)
2569         if [[ $flist_mode == "auto" ]]; then
2570                 print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2571                 exit 1
2572         fi
2573         ;;
2574 esac
2575 
2576 print -u2 "   SCM detected: $SCM_MODE"
2577 
2578 if [[ -n $lflag ]]; then
2579         #
2580         # If the -l flag is given instead of the name of a file list,
2581         # then generate the file list by extracting file names from a
2582         # putback -n.
2583         #
2584         shift $(($OPTIND - 1))
2585         if [[ $SCM_MODE == "teamware" ]]; then
2586                 flist_from_teamware "$*"
2587         else
2588                 print -u2 -- "Error: -l option only applies to TeamWare"
2589                 exit 1
2590         fi
2591         flist_done=1
2592         shift $#
2593 elif [[ -n $wflag ]]; then
2594         #
2595         # If the -w is given then assume the file list is in Bonwick's "wx"
2596         # command format, i.e.  pathname lines alternating with SCCS comment
2597         # lines with blank lines as separators.  Use the SCCS comments later
2598         # in building the index.html file.
2599         #
2600         shift $(($OPTIND - 1))
2601         wxfile=$1
2602         if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
2603                 if [[ -r $CODEMGR_WS/wx/active ]]; then
2604                         wxfile=$CODEMGR_WS/wx/active
2605                 fi
2606         fi
2607 
2608         [[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
2609             "be auto-detected (check \$CODEMGR_WS)" && exit 1
2610 
2611         if [[ ! -r $wxfile ]]; then
2612                 print -u2 "$wxfile: no such file or not readable"
2613                 usage


2617         flist_from_wx $wxfile
2618         flist_done=1
2619         if [[ -n "$*" ]]; then
2620                 shift
2621         fi
2622 elif [[ $flist_mode == "stdin" ]]; then
2623         print -u2 " File list from: standard input"
2624 elif [[ $flist_mode == "file" ]]; then
2625         print -u2 " File list from: $flist_file"
2626 fi
2627 
2628 if [[ $# -gt 0 ]]; then
2629         print -u2 "WARNING: unused arguments: $*"
2630 fi
2631 
2632 #
2633 # Before we entered the DO_EVERYTHING loop, we should have already set CWS
2634 # and CODEMGR_WS as needed.  Here, we set the parent workspace.
2635 #
2636 
2637 if [[ $SCM_MODE == "teamware" ]]; then
2638 
2639         #
2640         # Teamware priorities:
2641         #
2642         #      1) via -p command line option
2643         #      2) in the user environment
2644         #      3) in the flist
2645         #      4) automatically based on the workspace
2646         #
2647 
2648         #
2649         # For 1, codemgr_parent will already be set.  Here's 2:
2650         #
2651         [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
2652             codemgr_parent=$CODEMGR_PARENT
2653         if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
2654                 print -u2 "$codemgr_parent: no such directory"
2655                 exit 1
2656         fi
2657 
2658         #
2659         # If we're in auto-detect mode and we haven't already gotten the file
2660         # list, then see if we can get it by probing for wx.
2661         #
2662         if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
2663                 if [[ ! -x $WX ]]; then
2664                         print -u2 "WARNING: wx not found!"
2665                 fi
2666 
2667                 #
2668                 # We need to use wx list -w so that we get renamed files, etc.
2669                 # but only if a wx active file exists-- otherwise wx will
2670                 # hang asking us to initialize our wx information.
2671                 #
2672                 if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
2673                         print -u2 " File list from: 'wx list -w' ... \c"
2674                         $WX list -w > $FLIST
2675                         $WX comments > /tmp/$$.wx_comments
2676                         wxfile=/tmp/$$.wx_comments
2677                         print -u2 "done"
2678                         flist_done=1
2679                 fi
2680         fi
2681 
2682         #
2683         # If by hook or by crook we've gotten a file list by now (perhaps
2684         # from the command line), eval it to extract environment variables from
2685         # it: This is method 3 for finding the parent.
2686         #
2687         if [[ -z $flist_done ]]; then
2688                 flist_from_teamware
2689         fi
2690         env_from_flist
2691 
2692         #
2693         # (4) If we still don't have a value for codemgr_parent, get it
2694         # from workspace.
2695         #
2696         [[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
2697         if [[ ! -d $codemgr_parent ]]; then
2698                 print -u2 "$CODEMGR_PARENT: no such parent workspace"
2699                 exit 1
2700         fi
2701 
2702         PWS=$codemgr_parent
2703 
2704         [[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
2705 
2706 elif [[ $SCM_MODE == "mercurial" ]]; then
2707         #
2708         # Parent can either be specified with -p
2709         # Specified with CODEMGR_PARENT in the environment
2710         # or taken from hg's default path.
2711         #
2712 
2713         if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2714                 codemgr_parent=$CODEMGR_PARENT
2715         fi
2716 
2717         if [[ -z $codemgr_parent ]]; then
2718                 codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2719         fi
2720 
2721         PWS=$codemgr_parent
2722 
2723         #
2724         # If the parent is a webrev, we want to do some things against
2725         # the natural workspace parent (file list, comments, etc)
2726         #


3666         fi
3667 
3668         print "</p>"
3669         # Insert delta comments
3670 
3671         print "<blockquote><pre>"
3672         getcomments html $P $PP
3673         print "</pre>"
3674 
3675         # Add additional comments comment
3676 
3677         print "<!-- Add comments to explain changes in $P here -->"
3678 
3679         # Add count of changes.
3680 
3681         if [[ -f $F.count ]]; then
3682             cat $F.count
3683             rm $F.count
3684         fi
3685 
3686         if [[ $SCM_MODE == "teamware" ||
3687             $SCM_MODE == "mercurial" ||
3688             $SCM_MODE == "unknown" ]]; then
3689 
3690                 # Include warnings for important file mode situations:
3691                 # 1) New executable files
3692                 # 2) Permission changes of any kind
3693                 # 3) Existing executable files
3694 
3695                 old_mode=
3696                 if [[ -f $WDIR/raw_files/old/$PP ]]; then
3697                         old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3698                 fi
3699 
3700                 new_mode=
3701                 if [[ -f $WDIR/raw_files/new/$P ]]; then
3702                         new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3703                 fi
3704 
3705                 if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3706                         print "<span class=\"chmod\">"
3707                         print "<p>new executable file: mode $new_mode</p>"




 629 #      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
 630 #      NR==8           {wl("#7A7ADD");next}
 631 #      NR==54          {wl("#7A7ADD");sp(3);next}
 632 #      NR==56          {wl("#7A7ADD");next}
 633 #      NR==57          {wl("black");printf "\n"; next}
 634 #        :               :
 635 #
 636 #  This script is then run on the original source file to generate the
 637 #  HTML that corresponds to the source file.
 638 #
 639 #  The two HTML files are then combined into a single piece of HTML that
 640 #  uses an HTML table construct to present the files side by side.  You'll
 641 #  notice that the changes are color-coded:
 642 #
 643 #   black     - unchanged lines
 644 #   blue      - changed lines
 645 #   bold blue - new lines
 646 #   brown     - deleted lines
 647 #
 648 #  Blank lines are inserted in each file to keep unchanged lines in sync
 649 #  (side-by-side).  This format is familiar to users of sdiff(1).

 650 #
 651 sdiff_to_html()
 652 {
 653         diff -b $1 $2 > /tmp/$$.diffs
 654 
 655         TNAME=$3
 656         TPATH=$4
 657         COMMENT=$5
 658 
 659         #
 660         #  Now we have the diffs, generate the HTML for the old file.
 661         #
 662         $AWK '
 663         BEGIN   {
 664                 printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
 665                 printf "function removed() "
 666                 printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
 667                 printf "function changed() "
 668                 printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
 669                 printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"


1414 
1415 #
1416 # source_to_html { new | old } <filename>
1417 #
1418 # Process a plain vanilla source file to transform it into an HTML file.
1419 #
1420 source_to_html()
1421 {
1422         WHICH=$1
1423         TNAME=$2
1424 
1425         print "$HTML<head>$STDHEAD"
1426         print "<title>$WNAME $WHICH $TNAME</title>"
1427         print "<body id=\"SUNWwebrev\">"
1428         print "<pre>"
1429         html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1430         print "</pre></body></html>"
1431 }
1432 
1433 #

















































1434 # comments_from_wx {text|html} filepath
1435 #
1436 # Given the pathname of a file, find its location in a "wx" active
1437 # file list and print the following comment.  Output is either text or
1438 # HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1439 # are turned into URLs.
1440 #
1441 # This is also used with Mercurial and the file list provided by hg-active.
1442 #
1443 comments_from_wx()
1444 {
1445         typeset fmt=$1
1446         typeset p=$2
1447 
1448         comm=`$AWK '
1449         $1 == "'$p'" {
1450                 do getline ; while (NF > 0)
1451                 getline
1452                 while (NF > 0) { print ; getline }
1453                 exit


1469 #
1470 # getcomments {text|html} filepath parentpath
1471 #
1472 # Fetch the comments depending on what SCM mode we're in.
1473 #
1474 getcomments()
1475 {
1476         typeset fmt=$1
1477         typeset p=$2
1478         typeset pp=$3
1479 
1480         if [[ -n $Nflag ]]; then
1481                 return
1482         fi
1483         #
1484         # Mercurial support uses a file list in wx format, so this
1485         # will be used there, too
1486         #
1487         if [[ -n $wxfile ]]; then
1488                 comments_from_wx $fmt $p




1489         fi
1490 }
1491 
1492 #
1493 # printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1494 #
1495 # Print out Code Inspection figures similar to sccs-prt(1) format.
1496 #
1497 function printCI
1498 {
1499         integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1500         typeset str
1501         if (( tot == 1 )); then
1502                 str="line"
1503         else
1504                 str="lines"
1505         fi
1506         printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1507             $tot $str $ins $del $mod $unc
1508 }


1647                 #
1648                 # If the wx file pathname is relative then make it absolute
1649                 # because the webrev does a "cd" later on.
1650                 #
1651                 wxfile=$PWD/$argfile
1652         else
1653                 wxfile=$argfile
1654         fi
1655 
1656         $AWK '{ c = 1; print;
1657           while (getline) {
1658                 if (NF == 0) { c = -c; continue }
1659                 if (c > 0) print
1660           }
1661         }' $wxfile > $FLIST
1662 
1663         print " Done."
1664 }
1665 
1666 #






































1667 # Call hg-active to get the active list output in the wx active list format
1668 #
1669 function hg_active_wxfile
1670 {
1671         typeset child=$1
1672         typeset parent=$2
1673 
1674         TMPFLIST=/tmp/$$.active
1675         $HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1676         wxfile=$TMPFLIST
1677 }
1678 
1679 #
1680 # flist_from_mercurial
1681 # Call hg-active to get a wx-style active list, and hand it off to
1682 # flist_from_wx
1683 #
1684 function flist_from_mercurial
1685 {
1686         typeset child=$1


1807                 export CODEMGR_WS
1808         fi
1809 
1810         #
1811         # Check to see if CODEMGR_PARENT is set in the flist file.
1812         #
1813         if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1814                 codemgr_parent=$CODEMGR_PARENT
1815                 export CODEMGR_PARENT
1816         fi
1817 }
1818 
1819 function look_for_prog
1820 {
1821         typeset path
1822         typeset ppath
1823         typeset progname=$1
1824 
1825         ppath=$PATH
1826         ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
1827         ppath=$ppath:/opt/onbld/bin:/opt/onbld/bin/`uname -p`

1828 
1829         PATH=$ppath prog=`whence $progname`
1830         if [[ -n $prog ]]; then
1831                 print $prog
1832         fi
1833 }
1834 
1835 function get_file_mode
1836 {
1837         $PERL -e '
1838                 if (@stat = stat($ARGV[0])) {
1839                         $mode = $stat[2] & 0777;
1840                         printf "%03o\n", $mode;
1841                         exit 0;
1842                 } else {
1843                         exit 1;
1844                 }
1845             ' $1
1846 }
1847 








































































1848 function build_old_new_mercurial
1849 {
1850         typeset olddir="$1"
1851         typeset newdir="$2"
1852         typeset old_mode=
1853         typeset new_mode=
1854         typeset file
1855 
1856         #
1857         # Get old file mode, from the parent revision manifest entry.
1858         # Mercurial only stores a "file is executable" flag, but the
1859         # manifest will display an octal mode "644" or "755".
1860         #
1861         if [[ "$PDIR" == "." ]]; then
1862                 file="$PF"
1863         else
1864                 file="$PDIR/$PF"
1865         fi
1866         file=`echo $file | $SED 's#/#\\\/#g'`
1867         # match the exact filename, and return only the permission digits


2018                 cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2019         fi
2020 }
2021 
2022 function build_old_new
2023 {
2024         typeset WDIR=$1
2025         typeset PWS=$2
2026         typeset PDIR=$3
2027         typeset PF=$4
2028         typeset CWS=$5
2029         typeset DIR=$6
2030         typeset F=$7
2031 
2032         typeset olddir="$WDIR/raw_files/old"
2033         typeset newdir="$WDIR/raw_files/new"
2034 
2035         mkdir -p $olddir/$PDIR
2036         mkdir -p $newdir/$DIR
2037 
2038         if [[ $SCM_MODE == "mercurial" ]]; then


2039                 build_old_new_mercurial "$olddir" "$newdir"
2040         elif [[ $SCM_MODE == "git" ]]; then
2041                 build_old_new_git "$olddir" "$newdir"
2042         elif [[ $SCM_MODE == "subversion" ]]; then
2043                 build_old_new_subversion "$olddir" "$newdir"
2044         elif [[ $SCM_MODE == "unknown" ]]; then
2045                 build_old_new_unknown "$olddir" "$newdir"
2046         fi
2047 
2048         if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
2049                 print "*** Error: file not in parent or child"
2050                 return 1
2051         fi
2052         return 0
2053 }
2054 
2055 
2056 #
2057 # Usage message.
2058 #


2062         webrev [common-options] ( <file> | - )
2063         webrev [common-options] -w <wx file>
2064 
2065 Options:
2066         -C <filename>: Use <filename> for the information tracking configuration.
2067         -D: delete remote webrev
2068         -i <filename>: Include <filename> in the index.html file.
2069         -I <filename>: Use <filename> for the information tracking registry.
2070         -n: do not generate the webrev (useful with -U)
2071         -O: Print bugids/arc cases suitable for OpenSolaris.
2072         -o <outdir>: Output webrev to specified directory.
2073         -p <compare-against>: Use specified parent wkspc or basis for comparison
2074         -t <remote_target>: Specify remote destination for webrev upload
2075         -U: upload the webrev to remote destination
2076         -w <wxfile>: Use specified wx active file.
2077 
2078 Environment:
2079         WDIR: Control the output directory.
2080         WEBREV_TRASH_DIR: Set directory for webrev delete.
2081 



2082 SCM Environment:
2083         CODEMGR_WS: Workspace location.
2084         CODEMGR_PARENT: Parent workspace location.
2085 '

2086         exit 2
2087 }
2088 
2089 #
2090 #
2091 # Main program starts here
2092 #
2093 #
2094 
2095 trap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
2096 
2097 set +o noclobber
2098 
2099 PATH=$(/bin/dirname "$(whence $0)"):$PATH
2100 
2101 [[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
2102 [[ -z $WX ]] && WX=`look_for_prog wx`
2103 [[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
2104 [[ -z $GIT ]] && GIT=`look_for_prog git`
2105 [[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`


2227 
2228 # more sanity checking
2229 if [[ -n $nflag && -z $Uflag ]]; then
2230         print "it does not make sense to skip webrev generation" \
2231             "without -U"
2232         exit 1
2233 fi
2234 
2235 if [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2236         echo "remote target has to be used only for upload or delete"
2237         exit 1
2238 fi
2239 
2240 #
2241 # For the invocation "webrev -n -U" with no other options, webrev will assume
2242 # that the webrev exists in ${CWS}/webrev, but will upload it using the name
2243 # $(basename ${CWS}).  So we need to get CWS set before we skip any remaining
2244 # logic.
2245 #
2246 $WHICH_SCM | read SCM_MODE junk || exit 1
2247 if [[ $SCM_MODE == "mercurial" ]]; then















2248         #
2249         # Mercurial priorities:
2250         # 1. hg root from CODEMGR_WS environment variable
2251         # 1a. hg root from CODEMGR_WS/usr/closed if we're somewhere under
2252         #    usr/closed when we run webrev
2253         # 2. hg root from directory of invocation
2254         #
2255         if [[ ${PWD} =~ "usr/closed" ]]; then
2256                 testparent=${CODEMGR_WS}/usr/closed
2257                 # If we're in OpenSolaris mode, we enforce a minor policy:
2258                 # help to make sure the reviewer doesn't accidentally publish
2259                 # source which is under usr/closed
2260                 if [[ -n "$Oflag" ]]; then
2261                         print -u2 "OpenSolaris output not permitted with" \
2262                             "usr/closed changes"
2263                         exit 1
2264                 fi
2265         else
2266                 testparent=${CODEMGR_WS}
2267         fi


2353         elif [[ -n $1 ]]; then
2354                 if [[ ! -r $1 ]]; then
2355                         print -u2 "$1: no such file or not readable"
2356                         usage
2357                 fi
2358                 cat $1 > $FLIST
2359                 flist_mode="file"
2360                 flist_file=$1
2361                 flist_done=1
2362                 shift
2363         else
2364                 flist_mode="auto"
2365         fi
2366 fi
2367 
2368 #
2369 # Before we go on to further consider -l and -w, work out which SCM we think
2370 # is in use.
2371 #
2372 case "$SCM_MODE" in
2373 mercurial|git|subversion)
2374         ;;
2375 unknown)
2376         if [[ $flist_mode == "auto" ]]; then
2377                 print -u2 "Unable to determine SCM in use and file list not specified"
2378                 print -u2 "See which_scm(1) for SCM detection information."
2379                 exit 1
2380         fi
2381         ;;
2382 *)
2383         if [[ $flist_mode == "auto" ]]; then
2384                 print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2385                 exit 1
2386         fi
2387         ;;
2388 esac
2389 
2390 print -u2 "   SCM detected: $SCM_MODE"
2391 
2392 if [[ -n $wflag ]]; then















2393         #
2394         # If the -w is given then assume the file list is in Bonwick's "wx"
2395         # command format, i.e.  pathname lines alternating with SCCS comment
2396         # lines with blank lines as separators.  Use the SCCS comments later
2397         # in building the index.html file.
2398         #
2399         shift $(($OPTIND - 1))
2400         wxfile=$1
2401         if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
2402                 if [[ -r $CODEMGR_WS/wx/active ]]; then
2403                         wxfile=$CODEMGR_WS/wx/active
2404                 fi
2405         fi
2406 
2407         [[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
2408             "be auto-detected (check \$CODEMGR_WS)" && exit 1
2409 
2410         if [[ ! -r $wxfile ]]; then
2411                 print -u2 "$wxfile: no such file or not readable"
2412                 usage


2416         flist_from_wx $wxfile
2417         flist_done=1
2418         if [[ -n "$*" ]]; then
2419                 shift
2420         fi
2421 elif [[ $flist_mode == "stdin" ]]; then
2422         print -u2 " File list from: standard input"
2423 elif [[ $flist_mode == "file" ]]; then
2424         print -u2 " File list from: $flist_file"
2425 fi
2426 
2427 if [[ $# -gt 0 ]]; then
2428         print -u2 "WARNING: unused arguments: $*"
2429 fi
2430 
2431 #
2432 # Before we entered the DO_EVERYTHING loop, we should have already set CWS
2433 # and CODEMGR_WS as needed.  Here, we set the parent workspace.
2434 #
2435 
2436 if [[ $SCM_MODE == "mercurial" ]]; then





































































2437         #
2438         # Parent can either be specified with -p
2439         # Specified with CODEMGR_PARENT in the environment
2440         # or taken from hg's default path.
2441         #
2442 
2443         if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2444                 codemgr_parent=$CODEMGR_PARENT
2445         fi
2446 
2447         if [[ -z $codemgr_parent ]]; then
2448                 codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2449         fi
2450 
2451         PWS=$codemgr_parent
2452 
2453         #
2454         # If the parent is a webrev, we want to do some things against
2455         # the natural workspace parent (file list, comments, etc)
2456         #


3396         fi
3397 
3398         print "</p>"
3399         # Insert delta comments
3400 
3401         print "<blockquote><pre>"
3402         getcomments html $P $PP
3403         print "</pre>"
3404 
3405         # Add additional comments comment
3406 
3407         print "<!-- Add comments to explain changes in $P here -->"
3408 
3409         # Add count of changes.
3410 
3411         if [[ -f $F.count ]]; then
3412             cat $F.count
3413             rm $F.count
3414         fi
3415 
3416         if [[ $SCM_MODE == "mercurial" ||

3417             $SCM_MODE == "unknown" ]]; then
3418 
3419                 # Include warnings for important file mode situations:
3420                 # 1) New executable files
3421                 # 2) Permission changes of any kind
3422                 # 3) Existing executable files
3423 
3424                 old_mode=
3425                 if [[ -f $WDIR/raw_files/old/$PP ]]; then
3426                         old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3427                 fi
3428 
3429                 new_mode=
3430                 if [[ -f $WDIR/raw_files/new/$P ]]; then
3431                         new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3432                 fi
3433 
3434                 if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3435                         print "<span class=\"chmod\">"
3436                         print "<p>new executable file: mode $new_mode</p>"