Print this page
3810 remove support for teamware from webrev


   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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  25 #
  26 
  27 # Copyright 2008, 2010, Richard Lowe
  28 # Copyright 2012 Marcel Telka <marcel@telka.sk>

  29 
  30 #
  31 # This script takes a file list and a workspace and builds a set of html files
  32 # suitable for doing a code review of source changes via a web page.
  33 # Documentation is available via the manual page, webrev.1, or just
  34 # type 'webrev -h'.
  35 #
  36 # Acknowledgements to contributors to webrev are listed in the webrev(1)
  37 # man page.
  38 #
  39 
  40 REMOVED_COLOR=brown
  41 CHANGED_COLOR=blue
  42 NEW_COLOR=blue
  43 
  44 HTML='<?xml version="1.0"?>
  45 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  46     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  47 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
  48 


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 


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


2616         print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
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>"




   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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  25 #
  26 
  27 # Copyright 2008, 2010, Richard Lowe
  28 # Copyright 2012 Marcel Telka <marcel@telka.sk>
  29 # Copyright 2014 Bart Coddens <bart.coddens@gmail.com>
  30 
  31 #
  32 # This script takes a file list and a workspace and builds a set of html files
  33 # suitable for doing a code review of source changes via a web page.
  34 # Documentation is available via the manual page, webrev.1, or just
  35 # type 'webrev -h'.
  36 #
  37 # Acknowledgements to contributors to webrev are listed in the webrev(1)
  38 # man page.
  39 #
  40 
  41 REMOVED_COLOR=brown
  42 CHANGED_COLOR=blue
  43 NEW_COLOR=blue
  44 
  45 HTML='<?xml version="1.0"?>
  46 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  47     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  48 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
  49 


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

















































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


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




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


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






































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


1809                 export CODEMGR_WS
1810         fi
1811 
1812         #
1813         # Check to see if CODEMGR_PARENT is set in the flist file.
1814         #
1815         if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1816                 codemgr_parent=$CODEMGR_PARENT
1817                 export CODEMGR_PARENT
1818         fi
1819 }
1820 
1821 function look_for_prog
1822 {
1823         typeset path
1824         typeset ppath
1825         typeset progname=$1
1826 
1827         ppath=$PATH
1828         ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
1829         ppath=$ppath:/opt/onbld/bin
1830         ppath=$ppath:/opt/onbld/bin/`uname -p`
1831 
1832         PATH=$ppath prog=`whence $progname`
1833         if [[ -n $prog ]]; then
1834                 print $prog
1835         fi
1836 }
1837 
1838 function get_file_mode
1839 {
1840         $PERL -e '
1841                 if (@stat = stat($ARGV[0])) {
1842                         $mode = $stat[2] & 0777;
1843                         printf "%03o\n", $mode;
1844                         exit 0;
1845                 } else {
1846                         exit 1;
1847                 }
1848             ' $1
1849 }
1850 








































































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


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


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


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



2085 SCM Environment:
2086         CODEMGR_WS: Workspace location.
2087         CODEMGR_PARENT: Parent workspace location.
2088 '
2089 
2090         exit 2
2091 }
2092 
2093 #
2094 #
2095 # Main program starts here
2096 #
2097 #
2098 
2099 trap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
2100 
2101 set +o noclobber
2102 
2103 PATH=$(/bin/dirname "$(whence $0)"):$PATH
2104 


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















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


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















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


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






































































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


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

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