1552 {
1553 WHICH=$1
1554 TNAME=$2
1555
1556 print "$HTML<head>$STDHEAD"
1557 print "<title>$WNAME $WHICH $TNAME</title>"
1558 print "<body id=\"SUNWwebrev\">"
1559 print "<pre>"
1560 html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1561 print "</pre></body></html>"
1562 }
1563
1564 #
1565 # comments_from_wx {text|html} filepath
1566 #
1567 # Given the pathname of a file, find its location in a "wx" active
1568 # file list and print the following comment. Output is either text or
1569 # HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1570 # are turned into URLs.
1571 #
1572 # This is also used with Mercurial and the file list provided by hg-active.
1573 #
1574 comments_from_wx()
1575 {
1576 typeset fmt=$1
1577 typeset p=$2
1578
1579 comm=`$AWK '
1580 $1 == "'$p'" {
1581 do getline ; while (NF > 0)
1582 getline
1583 while (NF > 0) { print ; getline }
1584 exit
1585 }' < $wxfile`
1586
1587 if [[ -z $comm ]]; then
1588 comm="*** NO COMMENTS ***"
1589 fi
1590
1591 if [[ $fmt == "text" ]]; then
1592 print -- "$comm"
1593 return
1594 fi
1595
1596 print -- "$comm" | html_quote | its2url
1597
1598 }
1599
1600 #
1601 # getcomments {text|html} filepath parentpath
1602 #
1603 # Fetch the comments depending on what SCM mode we're in.
1604 #
1605 getcomments()
1606 {
1607 typeset fmt=$1
1608 typeset p=$2
1609 typeset pp=$3
1610
1611 if [[ -n $Nflag ]]; then
1612 return
1613 fi
1614 #
1615 # Mercurial support uses a file list in wx format, so this
1616 # will be used there, too
1617 #
1618 if [[ -n $wxfile ]]; then
1619 comments_from_wx $fmt $p
1620 fi
1621 }
1622
1623 #
1624 # printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1625 #
1626 # Print out Code Inspection figures similar to sccs-prt(1) format.
1627 #
1628 function printCI
1629 {
1630 integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1631 typeset str
1632 if (( tot == 1 )); then
1633 str="line"
1634 else
1635 str="lines"
1636 fi
1637 printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1778 #
1779 # If the wx file pathname is relative then make it absolute
1780 # because the webrev does a "cd" later on.
1781 #
1782 wxfile=$PWD/$argfile
1783 else
1784 wxfile=$argfile
1785 fi
1786
1787 $AWK '{ c = 1; print;
1788 while (getline) {
1789 if (NF == 0) { c = -c; continue }
1790 if (c > 0) print
1791 }
1792 }' $wxfile > $FLIST
1793
1794 print " Done."
1795 }
1796
1797 #
1798 # Call hg-active to get the active list output in the wx active list format
1799 #
1800 function hg_active_wxfile
1801 {
1802 typeset child=$1
1803 typeset parent=$2
1804
1805 TMPFLIST=/tmp/$$.active
1806 $HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1807 wxfile=$TMPFLIST
1808 }
1809
1810 #
1811 # flist_from_mercurial
1812 # Call hg-active to get a wx-style active list, and hand it off to
1813 # flist_from_wx
1814 #
1815 function flist_from_mercurial
1816 {
1817 typeset child=$1
1818 typeset parent=$2
1819
1820 print " File list from: hg-active -p $parent ...\c"
1821 if [[ ! -x $HG_ACTIVE ]]; then
1822 print # Blank line for the \c above
1823 print -u2 "Error: hg-active tool not found. Exiting"
1824 exit 1
1825 fi
1826 hg_active_wxfile $child $parent
1827
1828 # flist_from_wx prints the Done, so we don't have to.
1829 flist_from_wx $TMPFLIST
1830 }
1831
1832 #
1833 # Transform a specified 'git log' output format into a wx-like active list.
1834 #
1835 function git_wxfile
1836 {
1837 typeset child="$1"
1838 typeset parent="$2"
1839
1840 TMPFLIST=/tmp/$$.active
1841 $PERL -e 'my (%files, %realfiles, $msg);
1842 my $parent = $ARGV[0];
1843 my $child = $ARGV[1];
1844
1845 open(F, "git diff -M --name-status $parent..$child |");
1846 while (<F>) {
1847 chomp;
1848 if (/^R(\d+)\s+([^ ]+)\s+([^ ]+)/) { # rename
1849 if ($1 >= 75) { # Probably worth treating as a rename
1850 $realfiles{$3} = $2;
1851 } else {
1852 $realfiles{$3} = $3;
1962
1963 PATH=$ppath prog=`whence $progname`
1964 if [[ -n $prog ]]; then
1965 print $prog
1966 fi
1967 }
1968
1969 function get_file_mode
1970 {
1971 $PERL -e '
1972 if (@stat = stat($ARGV[0])) {
1973 $mode = $stat[2] & 0777;
1974 printf "%03o\n", $mode;
1975 exit 0;
1976 } else {
1977 exit 1;
1978 }
1979 ' $1
1980 }
1981
1982 function build_old_new_mercurial
1983 {
1984 typeset olddir="$1"
1985 typeset newdir="$2"
1986 typeset old_mode=
1987 typeset new_mode=
1988 typeset file
1989
1990 #
1991 # Get old file mode, from the parent revision manifest entry.
1992 # Mercurial only stores a "file is executable" flag, but the
1993 # manifest will display an octal mode "644" or "755".
1994 #
1995 if [[ "$PDIR" == "." ]]; then
1996 file="$PF"
1997 else
1998 file="$PDIR/$PF"
1999 fi
2000 file=`echo $file | $SED 's#/#\\\/#g'`
2001 # match the exact filename, and return only the permission digits
2002 old_mode=`$SED -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
2003 < $HG_PARENT_MANIFEST`
2004
2005 #
2006 # Get new file mode, directly from the filesystem.
2007 # Normalize the mode to match Mercurial's behavior.
2008 #
2009 new_mode=`get_file_mode $CWS/$DIR/$F`
2010 if [[ -n "$new_mode" ]]; then
2011 if [[ "$new_mode" = *[1357]* ]]; then
2012 new_mode=755
2013 else
2014 new_mode=644
2015 fi
2016 fi
2017
2018 #
2019 # new version of the file.
2020 #
2021 rm -rf $newdir/$DIR/$F
2022 if [[ -e $CWS/$DIR/$F ]]; then
2023 cp $CWS/$DIR/$F $newdir/$DIR/$F
2024 if [[ -n $new_mode ]]; then
2025 chmod $new_mode $newdir/$DIR/$F
2026 else
2027 # should never happen
2028 print -u2 "ERROR: set mode of $newdir/$DIR/$F"
2029 fi
2030 fi
2031
2032 #
2033 # parent's version of the file
2034 #
2035 # Note that we get this from the last version common to both
2036 # ourselves and the parent. References are via $CWS since we have no
2037 # guarantee that the parent workspace is reachable via the filesystem.
2038 #
2039 if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
2040 cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2041 elif [[ -n $HG_PARENT ]]; then
2042 hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
2043 $olddir/$PDIR/$PF 2>/dev/null
2044
2045 if (( $? != 0 )); then
2046 rm -f $olddir/$PDIR/$PF
2047 else
2048 if [[ -n $old_mode ]]; then
2049 chmod $old_mode $olddir/$PDIR/$PF
2050 else
2051 # should never happen
2052 print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
2053 fi
2054 fi
2055 fi
2056 }
2057
2058 function build_old_new_git
2059 {
2060 typeset olddir="$1"
2061 typeset newdir="$2"
2062 typeset o_mode=
2063 typeset n_mode=
2064 typeset o_object=
2065 typeset n_object=
2066 typeset OWD=$PWD
2067 typeset file
2068 typeset type
2069
2070 cd $CWS
2071
2072 #
2073 # Get old file and its mode from the git object tree
2074 #
2075 if [[ "$PDIR" == "." ]]; then
2076 file="$PF"
2077 else
2152 cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2153 fi
2154 }
2155
2156 function build_old_new
2157 {
2158 typeset WDIR=$1
2159 typeset PWS=$2
2160 typeset PDIR=$3
2161 typeset PF=$4
2162 typeset CWS=$5
2163 typeset DIR=$6
2164 typeset F=$7
2165
2166 typeset olddir="$WDIR/raw_files/old"
2167 typeset newdir="$WDIR/raw_files/new"
2168
2169 mkdir -p $olddir/$PDIR
2170 mkdir -p $newdir/$DIR
2171
2172 if [[ $SCM_MODE == "mercurial" ]]; then
2173 build_old_new_mercurial "$olddir" "$newdir"
2174 elif [[ $SCM_MODE == "git" ]]; then
2175 build_old_new_git "$olddir" "$newdir"
2176 elif [[ $SCM_MODE == "subversion" ]]; then
2177 build_old_new_subversion "$olddir" "$newdir"
2178 elif [[ $SCM_MODE == "unknown" ]]; then
2179 build_old_new_unknown "$olddir" "$newdir"
2180 fi
2181
2182 if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
2183 print "*** Error: file not in parent or child"
2184 return 1
2185 fi
2186 return 0
2187 }
2188
2189
2190 #
2191 # Usage message.
2192 #
2193 function usage
2194 {
2220 CODEMGR_PARENT: Parent workspace location.
2221 '
2222
2223 exit 2
2224 }
2225
2226 #
2227 #
2228 # Main program starts here
2229 #
2230 #
2231
2232 trap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
2233
2234 set +o noclobber
2235
2236 PATH=$(/bin/dirname "$(whence $0)"):$PATH
2237
2238 [[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
2239 [[ -z $WX ]] && WX=`look_for_prog wx`
2240 [[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
2241 [[ -z $GIT ]] && GIT=`look_for_prog git`
2242 [[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
2243 [[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
2244 [[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
2245 [[ -z $PERL ]] && PERL=`look_for_prog perl`
2246 [[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
2247 [[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
2248 [[ -z $AWK ]] && AWK=`look_for_prog nawk`
2249 [[ -z $AWK ]] && AWK=`look_for_prog gawk`
2250 [[ -z $AWK ]] && AWK=`look_for_prog awk`
2251 [[ -z $SCP ]] && SCP=`look_for_prog scp`
2252 [[ -z $SED ]] && SED=`look_for_prog sed`
2253 [[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
2254 [[ -z $SORT ]] && SORT=`look_for_prog sort`
2255 [[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
2256 [[ -z $GREP ]] && GREP=`look_for_prog grep`
2257 [[ -z $FIND ]] && FIND=`look_for_prog find`
2258 [[ -z $MANDOC ]] && MANDOC=`look_for_prog mandoc`
2259 [[ -z $COL ]] && COL=`look_for_prog col`
2260
2293 cflag=
2294 Cflag=
2295 Dflag=
2296 flist_mode=
2297 flist_file=
2298 hflag=
2299 iflag=
2300 Iflag=
2301 lflag=
2302 Nflag=
2303 nflag=
2304 Oflag=
2305 oflag=
2306 pflag=
2307 tflag=
2308 uflag=
2309 Uflag=
2310 wflag=
2311 remote_target=
2312
2313 #
2314 # NOTE: when adding/removing options it is necessary to sync the list
2315 # with usr/src/tools/onbld/hgext/cdm.py
2316 #
2317 while getopts "c:C:Dh:i:I:lnNo:Op:t:Uw" opt
2318 do
2319 case $opt in
2320 c) cflag=1
2321 codemgr_head=$OPTARG
2322 codemgr_parent=$OPTARG~1;;
2323
2324 C) Cflag=1
2325 ITSCONF=$OPTARG;;
2326
2327 D) Dflag=1;;
2328
2329 h) hflag=1
2330 codemgr_head=$OPTARG;;
2331
2332 i) iflag=1
2333 INCLUDE_FILE=$OPTARG;;
2334
2335 I) Iflag=1
2336 ITSREG=$OPTARG;;
2367
2368 # more sanity checking
2369 if [[ -n $nflag && -z $Uflag ]]; then
2370 print "it does not make sense to skip webrev generation" \
2371 "without -U"
2372 exit 1
2373 fi
2374
2375 if [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2376 echo "remote target has to be used only for upload or delete"
2377 exit 1
2378 fi
2379
2380 #
2381 # For the invocation "webrev -n -U" with no other options, webrev will assume
2382 # that the webrev exists in ${CWS}/webrev, but will upload it using the name
2383 # $(basename ${CWS}). So we need to get CWS set before we skip any remaining
2384 # logic.
2385 #
2386 $WHICH_SCM | read SCM_MODE junk || exit 1
2387 if [[ $SCM_MODE == "mercurial" ]]; then
2388 #
2389 # Mercurial priorities:
2390 # 1. hg root from CODEMGR_WS environment variable
2391 # 1a. hg root from CODEMGR_WS/usr/closed if we're somewhere under
2392 # usr/closed when we run webrev
2393 # 2. hg root from directory of invocation
2394 #
2395 if [[ ${PWD} =~ "usr/closed" ]]; then
2396 testparent=${CODEMGR_WS}/usr/closed
2397 # If we're in OpenSolaris mode, we enforce a minor policy:
2398 # help to make sure the reviewer doesn't accidentally publish
2399 # source which is under usr/closed
2400 if [[ -n "$Oflag" ]]; then
2401 print -u2 "OpenSolaris output not permitted with" \
2402 "usr/closed changes"
2403 exit 1
2404 fi
2405 else
2406 testparent=${CODEMGR_WS}
2407 fi
2408 [[ -z $codemgr_ws && -n $testparent ]] && \
2409 codemgr_ws=$(hg root -R $testparent 2>/dev/null)
2410 [[ -z $codemgr_ws ]] && codemgr_ws=$(hg root 2>/dev/null)
2411 CWS=$codemgr_ws
2412 elif [[ $SCM_MODE == "git" ]]; then
2413 #
2414 # Git priorities:
2415 # 1. git rev-parse --git-dir from CODEMGR_WS environment variable
2416 # 2. git rev-parse --git-dir from directory of invocation
2417 #
2418 [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
2419 codemgr_ws=$($GIT --git-dir=$CODEMGR_WS/.git rev-parse --git-dir \
2420 2>/dev/null)
2421 [[ -z $codemgr_ws ]] && \
2422 codemgr_ws=$($GIT rev-parse --git-dir 2>/dev/null)
2423
2424 if [[ "$codemgr_ws" == ".git" ]]; then
2425 codemgr_ws="${PWD}/${codemgr_ws}"
2426 fi
2427
2428 if [[ "$codemgr_ws" = *"/.git" ]]; then
2429 codemgr_ws=$(dirname $codemgr_ws) # Lose the '/.git'
2430 fi
2431 CWS="$codemgr_ws"
2432 elif [[ $SCM_MODE == "subversion" ]]; then
2495 elif [[ -n $1 ]]; then
2496 if [[ ! -r $1 ]]; then
2497 print -u2 "$1: no such file or not readable"
2498 usage
2499 fi
2500 cat $1 > $FLIST
2501 flist_mode="file"
2502 flist_file=$1
2503 flist_done=1
2504 shift
2505 else
2506 flist_mode="auto"
2507 fi
2508 fi
2509
2510 #
2511 # Before we go on to further consider -l and -w, work out which SCM we think
2512 # is in use.
2513 #
2514 case "$SCM_MODE" in
2515 mercurial|git|subversion)
2516 ;;
2517 unknown)
2518 if [[ $flist_mode == "auto" ]]; then
2519 print -u2 "Unable to determine SCM in use and file list not specified"
2520 print -u2 "See which_scm(1) for SCM detection information."
2521 exit 1
2522 fi
2523 ;;
2524 *)
2525 if [[ $flist_mode == "auto" ]]; then
2526 print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2527 exit 1
2528 fi
2529 ;;
2530 esac
2531
2532 print -u2 " SCM detected: $SCM_MODE"
2533
2534 if [[ -n $wflag ]]; then
2535 #
2553 print -u2 "$wxfile: no such file or not readable"
2554 usage
2555 fi
2556
2557 print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
2558 flist_from_wx $wxfile
2559 flist_done=1
2560 if [[ -n "$*" ]]; then
2561 shift
2562 fi
2563 elif [[ $flist_mode == "stdin" ]]; then
2564 print -u2 " File list from: standard input"
2565 elif [[ $flist_mode == "file" ]]; then
2566 print -u2 " File list from: $flist_file"
2567 fi
2568
2569 if [[ $# -gt 0 ]]; then
2570 print -u2 "WARNING: unused arguments: $*"
2571 fi
2572
2573 #
2574 # Before we entered the DO_EVERYTHING loop, we should have already set CWS
2575 # and CODEMGR_WS as needed. Here, we set the parent workspace.
2576 #
2577 if [[ $SCM_MODE == "mercurial" ]]; then
2578 #
2579 # Parent can either be specified with -p
2580 # Specified with CODEMGR_PARENT in the environment
2581 # or taken from hg's default path.
2582 #
2583
2584 if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2585 codemgr_parent=$CODEMGR_PARENT
2586 fi
2587
2588 if [[ -z $codemgr_parent ]]; then
2589 codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2590 fi
2591
2592 PWS=$codemgr_parent
2593
2594 #
2595 # If the parent is a webrev, we want to do some things against
2596 # the natural workspace parent (file list, comments, etc)
2597 #
2598 if [[ -n $parent_webrev ]]; then
2599 real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2600 else
2601 real_parent=$PWS
2602 fi
2603
2604 #
2605 # If hg-active exists, then we run it. In the case of no explicit
2606 # flist given, we'll use it for our comments. In the case of an
2607 # explicit flist given we'll try to use it for comments for any
2608 # files mentioned in the flist.
2609 #
2610 if [[ -z $flist_done ]]; then
2611 flist_from_mercurial $CWS $real_parent
2612 flist_done=1
2613 fi
2614
2615 #
2616 # If we have a file list now, pull out any variables set
2617 # therein. We do this now (rather than when we possibly use
2618 # hg-active to find comments) to avoid stomping specifications
2619 # in the user-specified flist.
2620 #
2621 if [[ -n $flist_done ]]; then
2622 env_from_flist
2623 fi
2624
2625 #
2626 # Only call hg-active if we don't have a wx formatted file already
2627 #
2628 if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2629 print " Comments from: hg-active -p $real_parent ...\c"
2630 hg_active_wxfile $CWS $real_parent
2631 print " Done."
2632 fi
2633
2634 #
2635 # At this point we must have a wx flist either from hg-active,
2636 # or in general. Use it to try and find our parent revision,
2637 # if we don't have one.
2638 #
2639 if [[ -z $HG_PARENT ]]; then
2640 eval `$SED -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
2641 fi
2642
2643 #
2644 # If we still don't have a parent, we must have been given a
2645 # wx-style active list with no HG_PARENT specification, run
2646 # hg-active and pull an HG_PARENT out of it, ignore the rest.
2647 #
2648 if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2649 $HG_ACTIVE -w $codemgr_ws -p $real_parent | \
2650 eval `$SED -e "s/#.*$//" | $GREP HG_PARENT=`
2651 elif [[ -z $HG_PARENT ]]; then
2652 print -u2 "Error: Cannot discover parent revision"
2653 exit 1
2654 fi
2655
2656 pnode=$(trim_digest $HG_PARENT)
2657 PRETTY_PWS="${PWS} (at ${pnode})"
2658 cnode=$(hg parent -R $codemgr_ws --template '{node|short}' \
2659 2>/dev/null)
2660 PRETTY_CWS="${CWS} (at ${cnode})"}
2661 elif [[ $SCM_MODE == "git" ]]; then
2662 # Check that "head" revision specified with -c or -h is sane
2663 if [[ -n $cflag || -n $hflag ]]; then
2664 head_rev=$($GIT rev-parse --verify --quiet "$codemgr_head")
2665 if [[ -z $head_rev ]]; then
2666 print -u2 "Error: bad revision ${codemgr_head}"
2667 exit 1
2668 fi
2669 fi
2670
2671 if [[ -z $codemgr_head ]]; then
2672 codemgr_head="HEAD";
2673 fi
2674
2675 # Parent can either be specified with -p, or specified with
2676 # CODEMGR_PARENT in the environment.
2677 if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2678 codemgr_parent=$CODEMGR_PARENT
2679 fi
2680
2681 # Try to figure out the parent based on the branch the current
3058 #
3059 # Save the file list in the webrev dir
3060 #
3061 [[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
3062
3063 rm -f $WDIR/$WNAME.patch
3064 rm -f $WDIR/$WNAME.ps
3065 rm -f $WDIR/$WNAME.pdf
3066
3067 touch $WDIR/$WNAME.patch
3068
3069 print " Output Files:"
3070
3071 #
3072 # Clean up the file list: Remove comments, blank lines and env variables.
3073 #
3074 $SED -e "s/#.*$//" -e "/=/d" -e "/^[ ]*$/d" $FLIST > /tmp/$$.flist.clean
3075 FLIST=/tmp/$$.flist.clean
3076
3077 #
3078 # For Mercurial, create a cache of manifest entries.
3079 #
3080 if [[ $SCM_MODE == "mercurial" ]]; then
3081 #
3082 # Transform the FLIST into a temporary sed script that matches
3083 # relevant entries in the Mercurial manifest as follows:
3084 # 1) The script will be used against the parent revision manifest,
3085 # so for FLIST lines that have two filenames (a renamed file)
3086 # keep only the old name.
3087 # 2) Escape all forward slashes the filename.
3088 # 3) Change the filename into another sed command that matches
3089 # that file in "hg manifest -v" output: start of line, three
3090 # octal digits for file permissions, space, a file type flag
3091 # character, space, the filename, end of line.
3092 # 4) Eliminate any duplicate entries. (This can occur if a
3093 # file has been used as the source of an hg cp and it's
3094 # also been modified in the same changeset.)
3095 #
3096 SEDFILE=/tmp/$$.manifest.sed
3097 $SED '
3098 s#^[^ ]* ##
3099 s#/#\\\/#g
3100 s#^.*$#/^... . &$/p#
3101 ' < $FLIST | $SORT -u > $SEDFILE
3102
3103 #
3104 # Apply the generated script to the output of "hg manifest -v"
3105 # to get the relevant subset for this webrev.
3106 #
3107 HG_PARENT_MANIFEST=/tmp/$$.manifest
3108 hg -R $CWS manifest -v -r $HG_PARENT |
3109 $SED -n -f $SEDFILE > $HG_PARENT_MANIFEST
3110 fi
3111
3112 #
3113 # First pass through the files: generate the per-file webrev HTML-files.
3114 #
3115 cat $FLIST | while read LINE
3116 do
3117 set - $LINE
3118 P=$1
3119
3120 #
3121 # Normally, each line in the file list is just a pathname of a
3122 # file that has been modified or created in the child. A file
3123 # that is renamed in the child workspace has two names on the
3124 # line: new name followed by the old name.
3125 #
3126 oldname=""
3127 oldpath=""
3128 rename=
3129 if [[ $# -eq 2 ]]; then
3130 PP=$2 # old filename
3131 if [[ -f $PP ]]; then
3132 oldname=" (copied from $PP)"
3406 print "$TOTL" > $WDIR/TotalChangedLines
3407
3408 print " index.html: \c"
3409 INDEXFILE=$WDIR/index.html
3410 exec 3<&1 # duplicate stdout to FD3.
3411 exec 1<&- # Close stdout.
3412 exec > $INDEXFILE # Open stdout to index file.
3413
3414 print "$HTML<head>$STDHEAD"
3415 print "<title>$WNAME</title>"
3416 print "</head>"
3417 print "<body id=\"SUNWwebrev\">"
3418 print "<div class=\"summary\">"
3419 print "<h2>Code Review for $WNAME</h2>"
3420
3421 print "<table>"
3422
3423 #
3424 # Get the preparer's name:
3425 #
3426 # If the SCM detected is Mercurial, and the configuration property
3427 # ui.username is available, use that, but be careful to properly escape
3428 # angle brackets (HTML syntax characters) in the email address.
3429 #
3430 # Otherwise, use the current userid in the form "John Doe (jdoe)", but
3431 # to maintain compatibility with passwd(4), we must support '&' substitutions.
3432 #
3433 preparer=
3434 if [[ "$SCM_MODE" == mercurial ]]; then
3435 preparer=`hg showconfig ui.username 2>/dev/null`
3436 if [[ -n "$preparer" ]]; then
3437 preparer="$(echo "$preparer" | html_quote)"
3438 fi
3439 fi
3440 if [[ -z "$preparer" ]]; then
3441 preparer=$(
3442 $PERL -e '
3443 ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
3444 if ($login) {
3445 $gcos =~ s/\&/ucfirst($login)/e;
3446 printf "%s (%s)\n", $gcos, $login;
3447 } else {
3448 printf "(unknown)\n";
3449 }
3450 ')
3451 fi
3452
3453 PREPDATE=$(LC_ALL=C /usr/bin/date +%Y-%b-%d\ %R\ %z\ %Z)
3454 print "<tr><th>Prepared by:</th><td>$preparer on $PREPDATE</td></tr>"
3455 print "<tr><th>Workspace:</th><td>${PRETTY_CWS:-$CWS}"
3643 elif [[ -n $manpage ]]; then
3644 print " --- ---- ---"
3645 fi
3646
3647 print "</p>"
3648
3649 # Insert delta comments
3650 print "<blockquote><pre>"
3651 getcomments html $P $PP
3652 print "</pre>"
3653
3654 # Add additional comments comment
3655 print "<!-- Add comments to explain changes in $P here -->"
3656
3657 # Add count of changes.
3658 if [[ -f $F.count ]]; then
3659 cat $F.count
3660 rm $F.count
3661 fi
3662
3663 if [[ $SCM_MODE == "mercurial" ||
3664 $SCM_MODE == "unknown" ]]; then
3665 # Include warnings for important file mode situations:
3666 # 1) New executable files
3667 # 2) Permission changes of any kind
3668 # 3) Existing executable files
3669 old_mode=
3670 if [[ -f $WDIR/raw_files/old/$PP ]]; then
3671 old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3672 fi
3673
3674 new_mode=
3675 if [[ -f $WDIR/raw_files/new/$P ]]; then
3676 new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3677 fi
3678
3679 if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3680 print "<span class=\"chmod\">"
3681 print "<p>new executable file: mode $new_mode</p>"
3682 print "</span>"
3683 elif [[ -n "$old_mode" && -n "$new_mode" &&
3684 "$old_mode" != "$new_mode" ]]; then
|
1552 {
1553 WHICH=$1
1554 TNAME=$2
1555
1556 print "$HTML<head>$STDHEAD"
1557 print "<title>$WNAME $WHICH $TNAME</title>"
1558 print "<body id=\"SUNWwebrev\">"
1559 print "<pre>"
1560 html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1561 print "</pre></body></html>"
1562 }
1563
1564 #
1565 # comments_from_wx {text|html} filepath
1566 #
1567 # Given the pathname of a file, find its location in a "wx" active
1568 # file list and print the following comment. Output is either text or
1569 # HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1570 # are turned into URLs.
1571 #
1572 comments_from_wx()
1573 {
1574 typeset fmt=$1
1575 typeset p=$2
1576
1577 comm=`$AWK '
1578 $1 == "'$p'" {
1579 do getline ; while (NF > 0)
1580 getline
1581 while (NF > 0) { print ; getline }
1582 exit
1583 }' < $wxfile`
1584
1585 if [[ -z $comm ]]; then
1586 comm="*** NO COMMENTS ***"
1587 fi
1588
1589 if [[ $fmt == "text" ]]; then
1590 print -- "$comm"
1591 return
1592 fi
1593
1594 print -- "$comm" | html_quote | its2url
1595
1596 }
1597
1598 #
1599 # getcomments {text|html} filepath parentpath
1600 #
1601 # Fetch the comments depending on what SCM mode we're in.
1602 #
1603 getcomments()
1604 {
1605 typeset fmt=$1
1606 typeset p=$2
1607 typeset pp=$3
1608
1609 if [[ -n $Nflag ]]; then
1610 return
1611 fi
1612
1613 if [[ -n $wxfile ]]; then
1614 comments_from_wx $fmt $p
1615 fi
1616 }
1617
1618 #
1619 # printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1620 #
1621 # Print out Code Inspection figures similar to sccs-prt(1) format.
1622 #
1623 function printCI
1624 {
1625 integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1626 typeset str
1627 if (( tot == 1 )); then
1628 str="line"
1629 else
1630 str="lines"
1631 fi
1632 printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1773 #
1774 # If the wx file pathname is relative then make it absolute
1775 # because the webrev does a "cd" later on.
1776 #
1777 wxfile=$PWD/$argfile
1778 else
1779 wxfile=$argfile
1780 fi
1781
1782 $AWK '{ c = 1; print;
1783 while (getline) {
1784 if (NF == 0) { c = -c; continue }
1785 if (c > 0) print
1786 }
1787 }' $wxfile > $FLIST
1788
1789 print " Done."
1790 }
1791
1792 #
1793 # Transform a specified 'git log' output format into a wx-like active list.
1794 #
1795 function git_wxfile
1796 {
1797 typeset child="$1"
1798 typeset parent="$2"
1799
1800 TMPFLIST=/tmp/$$.active
1801 $PERL -e 'my (%files, %realfiles, $msg);
1802 my $parent = $ARGV[0];
1803 my $child = $ARGV[1];
1804
1805 open(F, "git diff -M --name-status $parent..$child |");
1806 while (<F>) {
1807 chomp;
1808 if (/^R(\d+)\s+([^ ]+)\s+([^ ]+)/) { # rename
1809 if ($1 >= 75) { # Probably worth treating as a rename
1810 $realfiles{$3} = $2;
1811 } else {
1812 $realfiles{$3} = $3;
1922
1923 PATH=$ppath prog=`whence $progname`
1924 if [[ -n $prog ]]; then
1925 print $prog
1926 fi
1927 }
1928
1929 function get_file_mode
1930 {
1931 $PERL -e '
1932 if (@stat = stat($ARGV[0])) {
1933 $mode = $stat[2] & 0777;
1934 printf "%03o\n", $mode;
1935 exit 0;
1936 } else {
1937 exit 1;
1938 }
1939 ' $1
1940 }
1941
1942 function build_old_new_git
1943 {
1944 typeset olddir="$1"
1945 typeset newdir="$2"
1946 typeset o_mode=
1947 typeset n_mode=
1948 typeset o_object=
1949 typeset n_object=
1950 typeset OWD=$PWD
1951 typeset file
1952 typeset type
1953
1954 cd $CWS
1955
1956 #
1957 # Get old file and its mode from the git object tree
1958 #
1959 if [[ "$PDIR" == "." ]]; then
1960 file="$PF"
1961 else
2036 cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2037 fi
2038 }
2039
2040 function build_old_new
2041 {
2042 typeset WDIR=$1
2043 typeset PWS=$2
2044 typeset PDIR=$3
2045 typeset PF=$4
2046 typeset CWS=$5
2047 typeset DIR=$6
2048 typeset F=$7
2049
2050 typeset olddir="$WDIR/raw_files/old"
2051 typeset newdir="$WDIR/raw_files/new"
2052
2053 mkdir -p $olddir/$PDIR
2054 mkdir -p $newdir/$DIR
2055
2056 if [[ $SCM_MODE == "git" ]]; then
2057 build_old_new_git "$olddir" "$newdir"
2058 elif [[ $SCM_MODE == "subversion" ]]; then
2059 build_old_new_subversion "$olddir" "$newdir"
2060 elif [[ $SCM_MODE == "unknown" ]]; then
2061 build_old_new_unknown "$olddir" "$newdir"
2062 fi
2063
2064 if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
2065 print "*** Error: file not in parent or child"
2066 return 1
2067 fi
2068 return 0
2069 }
2070
2071
2072 #
2073 # Usage message.
2074 #
2075 function usage
2076 {
2102 CODEMGR_PARENT: Parent workspace location.
2103 '
2104
2105 exit 2
2106 }
2107
2108 #
2109 #
2110 # Main program starts here
2111 #
2112 #
2113
2114 trap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
2115
2116 set +o noclobber
2117
2118 PATH=$(/bin/dirname "$(whence $0)"):$PATH
2119
2120 [[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
2121 [[ -z $WX ]] && WX=`look_for_prog wx`
2122 [[ -z $GIT ]] && GIT=`look_for_prog git`
2123 [[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
2124 [[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
2125 [[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
2126 [[ -z $PERL ]] && PERL=`look_for_prog perl`
2127 [[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
2128 [[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
2129 [[ -z $AWK ]] && AWK=`look_for_prog nawk`
2130 [[ -z $AWK ]] && AWK=`look_for_prog gawk`
2131 [[ -z $AWK ]] && AWK=`look_for_prog awk`
2132 [[ -z $SCP ]] && SCP=`look_for_prog scp`
2133 [[ -z $SED ]] && SED=`look_for_prog sed`
2134 [[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
2135 [[ -z $SORT ]] && SORT=`look_for_prog sort`
2136 [[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
2137 [[ -z $GREP ]] && GREP=`look_for_prog grep`
2138 [[ -z $FIND ]] && FIND=`look_for_prog find`
2139 [[ -z $MANDOC ]] && MANDOC=`look_for_prog mandoc`
2140 [[ -z $COL ]] && COL=`look_for_prog col`
2141
2174 cflag=
2175 Cflag=
2176 Dflag=
2177 flist_mode=
2178 flist_file=
2179 hflag=
2180 iflag=
2181 Iflag=
2182 lflag=
2183 Nflag=
2184 nflag=
2185 Oflag=
2186 oflag=
2187 pflag=
2188 tflag=
2189 uflag=
2190 Uflag=
2191 wflag=
2192 remote_target=
2193
2194 while getopts "c:C:Dh:i:I:lnNo:Op:t:Uw" opt
2195 do
2196 case $opt in
2197 c) cflag=1
2198 codemgr_head=$OPTARG
2199 codemgr_parent=$OPTARG~1;;
2200
2201 C) Cflag=1
2202 ITSCONF=$OPTARG;;
2203
2204 D) Dflag=1;;
2205
2206 h) hflag=1
2207 codemgr_head=$OPTARG;;
2208
2209 i) iflag=1
2210 INCLUDE_FILE=$OPTARG;;
2211
2212 I) Iflag=1
2213 ITSREG=$OPTARG;;
2244
2245 # more sanity checking
2246 if [[ -n $nflag && -z $Uflag ]]; then
2247 print "it does not make sense to skip webrev generation" \
2248 "without -U"
2249 exit 1
2250 fi
2251
2252 if [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2253 echo "remote target has to be used only for upload or delete"
2254 exit 1
2255 fi
2256
2257 #
2258 # For the invocation "webrev -n -U" with no other options, webrev will assume
2259 # that the webrev exists in ${CWS}/webrev, but will upload it using the name
2260 # $(basename ${CWS}). So we need to get CWS set before we skip any remaining
2261 # logic.
2262 #
2263 $WHICH_SCM | read SCM_MODE junk || exit 1
2264
2265 if [[ $SCM_MODE == "git" ]]; then
2266 #
2267 # Git priorities:
2268 # 1. git rev-parse --git-dir from CODEMGR_WS environment variable
2269 # 2. git rev-parse --git-dir from directory of invocation
2270 #
2271 [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
2272 codemgr_ws=$($GIT --git-dir=$CODEMGR_WS/.git rev-parse --git-dir \
2273 2>/dev/null)
2274 [[ -z $codemgr_ws ]] && \
2275 codemgr_ws=$($GIT rev-parse --git-dir 2>/dev/null)
2276
2277 if [[ "$codemgr_ws" == ".git" ]]; then
2278 codemgr_ws="${PWD}/${codemgr_ws}"
2279 fi
2280
2281 if [[ "$codemgr_ws" = *"/.git" ]]; then
2282 codemgr_ws=$(dirname $codemgr_ws) # Lose the '/.git'
2283 fi
2284 CWS="$codemgr_ws"
2285 elif [[ $SCM_MODE == "subversion" ]]; then
2348 elif [[ -n $1 ]]; then
2349 if [[ ! -r $1 ]]; then
2350 print -u2 "$1: no such file or not readable"
2351 usage
2352 fi
2353 cat $1 > $FLIST
2354 flist_mode="file"
2355 flist_file=$1
2356 flist_done=1
2357 shift
2358 else
2359 flist_mode="auto"
2360 fi
2361 fi
2362
2363 #
2364 # Before we go on to further consider -l and -w, work out which SCM we think
2365 # is in use.
2366 #
2367 case "$SCM_MODE" in
2368 git|subversion)
2369 ;;
2370 unknown)
2371 if [[ $flist_mode == "auto" ]]; then
2372 print -u2 "Unable to determine SCM in use and file list not specified"
2373 print -u2 "See which_scm(1) for SCM detection information."
2374 exit 1
2375 fi
2376 ;;
2377 *)
2378 if [[ $flist_mode == "auto" ]]; then
2379 print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2380 exit 1
2381 fi
2382 ;;
2383 esac
2384
2385 print -u2 " SCM detected: $SCM_MODE"
2386
2387 if [[ -n $wflag ]]; then
2388 #
2406 print -u2 "$wxfile: no such file or not readable"
2407 usage
2408 fi
2409
2410 print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
2411 flist_from_wx $wxfile
2412 flist_done=1
2413 if [[ -n "$*" ]]; then
2414 shift
2415 fi
2416 elif [[ $flist_mode == "stdin" ]]; then
2417 print -u2 " File list from: standard input"
2418 elif [[ $flist_mode == "file" ]]; then
2419 print -u2 " File list from: $flist_file"
2420 fi
2421
2422 if [[ $# -gt 0 ]]; then
2423 print -u2 "WARNING: unused arguments: $*"
2424 fi
2425
2426
2427 if [[ $SCM_MODE == "git" ]]; then
2428 # Check that "head" revision specified with -c or -h is sane
2429 if [[ -n $cflag || -n $hflag ]]; then
2430 head_rev=$($GIT rev-parse --verify --quiet "$codemgr_head")
2431 if [[ -z $head_rev ]]; then
2432 print -u2 "Error: bad revision ${codemgr_head}"
2433 exit 1
2434 fi
2435 fi
2436
2437 if [[ -z $codemgr_head ]]; then
2438 codemgr_head="HEAD";
2439 fi
2440
2441 # Parent can either be specified with -p, or specified with
2442 # CODEMGR_PARENT in the environment.
2443 if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2444 codemgr_parent=$CODEMGR_PARENT
2445 fi
2446
2447 # Try to figure out the parent based on the branch the current
2824 #
2825 # Save the file list in the webrev dir
2826 #
2827 [[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
2828
2829 rm -f $WDIR/$WNAME.patch
2830 rm -f $WDIR/$WNAME.ps
2831 rm -f $WDIR/$WNAME.pdf
2832
2833 touch $WDIR/$WNAME.patch
2834
2835 print " Output Files:"
2836
2837 #
2838 # Clean up the file list: Remove comments, blank lines and env variables.
2839 #
2840 $SED -e "s/#.*$//" -e "/=/d" -e "/^[ ]*$/d" $FLIST > /tmp/$$.flist.clean
2841 FLIST=/tmp/$$.flist.clean
2842
2843 #
2844 # First pass through the files: generate the per-file webrev HTML-files.
2845 #
2846 cat $FLIST | while read LINE
2847 do
2848 set - $LINE
2849 P=$1
2850
2851 #
2852 # Normally, each line in the file list is just a pathname of a
2853 # file that has been modified or created in the child. A file
2854 # that is renamed in the child workspace has two names on the
2855 # line: new name followed by the old name.
2856 #
2857 oldname=""
2858 oldpath=""
2859 rename=
2860 if [[ $# -eq 2 ]]; then
2861 PP=$2 # old filename
2862 if [[ -f $PP ]]; then
2863 oldname=" (copied from $PP)"
3137 print "$TOTL" > $WDIR/TotalChangedLines
3138
3139 print " index.html: \c"
3140 INDEXFILE=$WDIR/index.html
3141 exec 3<&1 # duplicate stdout to FD3.
3142 exec 1<&- # Close stdout.
3143 exec > $INDEXFILE # Open stdout to index file.
3144
3145 print "$HTML<head>$STDHEAD"
3146 print "<title>$WNAME</title>"
3147 print "</head>"
3148 print "<body id=\"SUNWwebrev\">"
3149 print "<div class=\"summary\">"
3150 print "<h2>Code Review for $WNAME</h2>"
3151
3152 print "<table>"
3153
3154 #
3155 # Get the preparer's name:
3156 #
3157 # If the SCM detected is Git, and the configuration property user.name is
3158 # available, use that, but be careful to properly escape angle brackets (HTML
3159 # syntax characters) in the email address.
3160 #
3161 # Otherwise, use the current userid in the form "John Doe (jdoe)", but
3162 # to maintain compatibility with passwd(4), we must support '&' substitutions.
3163 #
3164 preparer=
3165 if [[ "$SCM_MODE" == git ]]; then
3166 preparer=$(git config user.name 2>/dev/null)
3167 if [[ -n "$preparer" ]]; then
3168 preparer="$(echo "$preparer" | html_quote)"
3169 fi
3170 fi
3171 if [[ -z "$preparer" ]]; then
3172 preparer=$(
3173 $PERL -e '
3174 ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
3175 if ($login) {
3176 $gcos =~ s/\&/ucfirst($login)/e;
3177 printf "%s (%s)\n", $gcos, $login;
3178 } else {
3179 printf "(unknown)\n";
3180 }
3181 ')
3182 fi
3183
3184 PREPDATE=$(LC_ALL=C /usr/bin/date +%Y-%b-%d\ %R\ %z\ %Z)
3185 print "<tr><th>Prepared by:</th><td>$preparer on $PREPDATE</td></tr>"
3186 print "<tr><th>Workspace:</th><td>${PRETTY_CWS:-$CWS}"
3374 elif [[ -n $manpage ]]; then
3375 print " --- ---- ---"
3376 fi
3377
3378 print "</p>"
3379
3380 # Insert delta comments
3381 print "<blockquote><pre>"
3382 getcomments html $P $PP
3383 print "</pre>"
3384
3385 # Add additional comments comment
3386 print "<!-- Add comments to explain changes in $P here -->"
3387
3388 # Add count of changes.
3389 if [[ -f $F.count ]]; then
3390 cat $F.count
3391 rm $F.count
3392 fi
3393
3394 if [[ $SCM_MODE == "unknown" ]]; then
3395 # Include warnings for important file mode situations:
3396 # 1) New executable files
3397 # 2) Permission changes of any kind
3398 # 3) Existing executable files
3399 old_mode=
3400 if [[ -f $WDIR/raw_files/old/$PP ]]; then
3401 old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3402 fi
3403
3404 new_mode=
3405 if [[ -f $WDIR/raw_files/new/$P ]]; then
3406 new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3407 fi
3408
3409 if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3410 print "<span class=\"chmod\">"
3411 print "<p>new executable file: mode $new_mode</p>"
3412 print "</span>"
3413 elif [[ -n "$old_mode" && -n "$new_mode" &&
3414 "$old_mode" != "$new_mode" ]]; then
|