#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#use FileHandle; Can't do! Won't work for all perls... Y? Who knows?
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 file diff viewer
# View diff between two files or two revisions
#
#################################################################
# Get file spec argument
my @files = split /,/,P4CGI::cgi()->param("FSPC") ;
&P4CGI::bail("No file specified") unless @files > 0 ;
map { $_ = &P4CGI::htmlEncode($_) } @files ;
my @revs = split / /,P4CGI::cgi()->param("REV") if defined P4CGI::cgi()->param("REV") ;
$files[0] =~ s/^([^\#]+)\#(\d+)/$1/ and do { $revs[0] = $2 ; } ;
&P4CGI::bail("No revision specified") unless @revs > 0 ;
map { s/^(\d+).*/$1/ ; } @revs ;
my @modes ;
@modes = split / /,P4CGI::cgi()->param("ACT") if defined P4CGI::cgi()->param("ACT") ;
&P4CGI::bail("No mode specified") unless @modes > 0 ;
my @files2 ;
@files2 =
split /,/,P4CGI::cgi()->param("FSPC2") if defined P4CGI::cgi()->param("FSPC2") ;
map { $_ = &P4CGI::htmlEncode($_) } @files2 ;
my @revs2 ;
@revs2 =
split / /,P4CGI::cgi()->param("REV2") if defined P4CGI::cgi()->param("REV2") ;
map { s/^(\d+).*/$1/ ; } @revs2 ;
if(defined $files2[0]) {
$files2[0] =~ s/^([^\#]+)\#(\d+)/$1/ and do { $revs2[0] = $2 ; } ;
} ;
my $change = P4CGI::cgi()->param("CH") ;
$change =~ s/^(\d+).*/$1/ if defined $change ;
my $ignoreSpace = P4CGI::cgi()->param("IGNSP") ;
# Constants for the file diff display
# $NCONTEXT - number of lines context before and after a diff
my $NCONTEXT = P4CGI::cgi()->param("CONTEXT") ;
$NCONTEXT = 10 unless defined $NCONTEXT ;
# $MAXCONTEXT - max number of lines context between diffs
my $MAXCONTEXT = $NCONTEXT+20;
my $n ;
for($n = 0; $n < @files ; $n++) {
$files2[$n] = $files[$n] unless defined $files2[$n] ;
$revs2[$n] = $revs[$n]-1 unless defined $revs2[$n] ;
}
if((@files != @revs) ||
(@files != @files2) ||
(@files != @revs2)) {
&P4CGI::bail("Argument counts not correct") ;
} ;
my $title ;
if(@files == 1) {
if($files[0] eq $files2[0]) {
if($revs[0] < $revs2[0]) {
my $r = $revs2[0] ;
$revs2[0] = $revs[0] ;
$revs[0] = $r ;
}
$title = "Diff<br><code>$files[0]</code>\#$revs2[0] -> \#$revs[0] " ;
}
else {
$title = "Diff between<br><code>$files[0]\#$revs[0]</code><br>and<br><code>$files2[0]\#$revs2[0]" ;
}
}
else {
$title = "Diffs for change $change" ;
}
my $nextNCONTEXT= $NCONTEXT*2 ;
my @pstr ;
my $p ;
foreach $p (&P4CGI::cgi()->param) {
next if $p eq "CONTEXT" ;
push @pstr, $p . "=" . P4CGI::cgi()->param($p) ;
}
my @options ;
if($NCONTEXT < 9999999) {
push @options, &P4CGI::buttonCell($ENV{SCRIPT_NAME},
"Show $nextNCONTEXT context lines",
@pstr,
"CONTEXT=$nextNCONTEXT",
"Show more context") ;
push @options, &P4CGI::buttonCell($ENV{SCRIPT_NAME},
"Show all lines",
@pstr,
"CONTEXT=9999999",
"Show complete") ;
} ;
if(@files == 1 and $files[0] eq $files2[0]) {
push @options, ("<td> </td>",
&P4CGI::buttonCell("fileLogView.cgi",
"Show file log for $files[0]",
"FSPC=$files[0]",
"File log")) ;
}
if(defined $ignoreSpace and $ignoreSpace eq "Y") {
&P4CGI::cgi()->param("IGNSP","N") ;
push @options, &P4CGI::buttonCell( &P4CGI::cgi()->url(-query=>1),
"Show changes in whitespaces",
"Show whitespace") ;
$ignoreSpace = "-dw" ;
}
else {
&P4CGI::cgi()->param("IGNSP","Y") ;
push @options, &P4CGI::buttonCell( &P4CGI::cgi()->url(-query=>1),
"Ignore changes in whitespaces",
"Ignore whitespace") ;
$ignoreSpace = "" ;
}
print
&P4CGI::start_page("$title",@options) ;
my $currentFile ;
my $currentRev ;
local *P4 ;
my $P4lineNo ; # Line No of file
my $SameFile ; # Set to true of same files.
my $f1Mark ;
my $f2Mark ;
my $f1Class ;
my $f2Class ;
sub getLine()
{
$P4lineNo++ if defined $P4lineNo ;
return <P4> ;
}
my $NoFiles = scalar @files ;
while(@files>0) {
my $file1 = shift @files ;
my $file2 = shift @files2 ;
my $rev1 = shift @revs ;
my $rev2 = shift @revs2 ;
my $mode = shift @modes ;
next if ($mode eq "add") or ($mode eq "delete") or ($mode eq "branch") ; # Skip if diff not possible
$SameFile = ($file1 eq $file2) ;
if($SameFile) { # Make sure revisions is in correct order if it is the same file.
if($rev1 < $rev2) {
my $r = $rev2 ;
$rev2 = $rev1 ;
$rev1 = $r ;
}
} ;
my $f1Class = $SameFile ? "fileDiffAddedLines" : "fileDiffFirst" ;
my $f2Class = $SameFile ? "fileDiffDeletedLines" : "fileDiffSecond" ;
$f1Mark = $SameFile ? "+" : "<" ;
$f2Mark = $SameFile ? "-" : ">" ;
my @buttoncells ;
if(!$SameFile or $NoFiles > 1) {
push @buttoncells,&P4CGI::buttonLink("fileLogView.cgi",
"View log for file $file1",
"FSPC=$file1",
"File Log") ;
} ;
if(!$SameFile) {
push @buttoncells,&P4CGI::buttonLink("fileLogView.cgi",
"View log for file $file2",
"FSPC=$file2",
"File Log") ;
} ;
my $title = "<span class=\"fileDiffMark\">${f1Mark}</span> <span class=\"$f1Class\">$file1#$rev1</span> " ;
$title .= shift @buttoncells if @buttoncells ;
$title .= "<br>" ;
$title .= "<span class=\"fileDiffMark\">${f2Mark}</span> <span class=\"$f2Class\">$file2#$rev2</span> " ;
if(@buttoncells) {
$title .= shift @buttoncells ;
}
print "<br>\n" ;
print &P4CGI::start_framedTable($title) ;
print &P4CGI::start_table("class=\"fileDiff\"") ;
my $f1 = "$file1#$rev1";
my $f2 = "$file2#$rev2";
$currentFile = $file1 ;
$currentRev = $rev1 ;
##
## Use "p4 diff2" to get a list of modifications (diff chunks)
##
my $nchunk =0; # Counter for diff chunks
my @start ; # Start line for chunk in latest file
my @dels ; # No. of deleted lines in chunk
my @adds ; # No. of added lines in chunk
my @delLines ; # Memory for deleted lines
if ($mode ne 'add' && $mode ne 'delete' && $mode ne 'branch') {
&P4CGI::p4call(*P4, "diff2 $ignoreSpace \"$f2\" \"$f1\"");
$_ = <P4>;
while (<P4>) {
# Check if line matches start of a diff chunk
/(\d+),?(\d*)([acd])(\d+),?(\d*)/ or do { next ; } ;
# $la, $lb: start and end line in old (left) file
# $op: operation (one of a,d or c)
# $ra, $rb: start and end line in new (right) file
my ( $la, $lb, $op, $ra, $rb ) = ($1,$2,$3,$4,$5) ;
# End lines may have to be calculated
if( !$lb ) { $lb = $op ne 'a' ? $la : $la - 1; }
if( !$rb ) { $rb = $op ne 'd' ? $ra : $ra - 1; }
my ( $dels, $adds ); # Temporary vars for No of adds/deletes
# Calc. start position in new (right) file
$start[ $nchunk ] = $op ne 'd' ? $ra : $ra + 1;
# Calc. No. of deleted lines
$dels[ $nchunk ] = $dels = $lb - $la + 1;
# Calc. No. of added lines
$adds[ $nchunk ] = $adds = $rb - $ra + 1;
# Init deleted lines
$delLines[ $nchunk ] = "";
# Get the deleted lines from the old (left) file
while( $dels-- ) {
$_ = <P4>;
s/^. //;
$_ = &P4CGI::htmlEncode($_) ;
$delLines[ $nchunk ] .=
"$_";
}
# If it was a change, skip over separator
if ($op eq 'c') {
$_ = <P4>;
}
# Skip over added lines (we don't need to know them yet)
while( $adds-- ) {
$_ = <P4>;
}
# Next chunk.
$nchunk++;
}
close P4;
}
# Now walk through the diff chunks, reading the new (right) file and
# displaying it as necessary.
&P4CGI::p4call(*P4, "print -q \"$f1\"");
$P4lineNo = 0; # Zero current line
my $n ;
for( $n = 0; $n < $nchunk; $n++ )
{
# print up to this chunk.
&catchup($start[ $n ] - $P4lineNo - 1) ;
# display added lines -- these are in the file stream.
if( $adds[ $n ] )
{
&display($adds[ $n ],$f1Class,$f1Mark );
}
# display deleted lines -- we saved these from the diff
if( $dels[ $n ] )
{
my $line ;
foreach $line (split("\n",$delLines[ $n ])) {
print "<tr><td class=\"fileDiffLineNo\"></td><td class=\"fileDiffMark\">$f2Mark</td>" ;
$line =~ s/ / /g ;
print "<td class=\"$f2Class\">$line</td></tr>\n" ;
}
}
# $curlin = $start[ $n ] + $adds[ $n ];
}
&catchup(999999999 );
close P4;
print
&P4CGI::end_table(),
&P4CGI::end_framedTable();
}
print &P4CGI::end_page() ;
# Support for processing diff chunks.
#
# skip: skip lines in source file
# display: display lines in source file, handling funny chars
# catchup: display & skip as necessary
#
##
## skip(no of lines)
## Returns: 0 or No. of lines not skipped if file ends
sub skip {
my $to = shift @_;
while( $to > 0 && ( $_ = &getLine() ) ) {
$to--;
}
return $to;
}
##
## display(no of lines,class,mark)
## Displays a number of lines from handle
sub display {
my $to = shift @_;
my $class = shift @_;
my $mark = shift @_;
while( $to-- > 0 && ( $_ = &getLine() ) ) {
my $line = &P4CGI::htmlEncode($_) ;
$line =~ s/ / /g ;
my $ls ;
if($P4lineNo == 1 or ($P4lineNo % 5) == 0) {
$ls = "<td class=\"fileDiffLineNo\">" ;
$ls .= &P4CGI::ahref(-url=>"fileViewer.cgi",
-anchor => "L$P4lineNo",
"FSPC=$currentFile",
"REV=$currentRev",
"HELP=View file at line $P4lineNo",
$P4lineNo) ;
$ls .= "</td>" ;
}
else {
$ls = "<td></td>" ;
}
if($mark ne "") {
print "<tr>$ls<td class=\"fileDiffMark\">$mark</td><td class=\"$class\">$line</td></tr>\n" ;
}
else {
print "<tr>$ls<td></td><td class=\"$class\">$line</td></tr>\n" ;
}
}
}
##
## catchup(<handle>,no of lines)
## Print/skip lines to next diff chunk
sub catchup {
my $to = shift @_;
if( $to > $MAXCONTEXT )
{
my $skipped = $to - $NCONTEXT ;
if($P4lineNo > 0) {
&display($NCONTEXT,"fileDiffLine","");
$skipped -= $NCONTEXT ;
}
$skipped -= &skip($skipped );
print
"<tr><td></td><td></td><td class=\"fileDiffSkipped\">",
" $skipped lines skipped ",
"</td></tr>\n" if( $skipped );
&display($NCONTEXT,"fileDiffLine","");
}
else
{
&display($to,"fileDiffLine","");
}
}
#
# That's all folks
#
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #9 | 5412 | Fredric Fredricson | P4DB: Added button to ignore whitespace in file diff view | ||
| #8 | 4313 | Fredric Fredricson |
P4DB: - Removed some error messages (that clobbers the error log for the web server) - Added a CSS file that works for people with color vision deficiency - Fixed minor bug in the scripts that creates the tarball and zip-file |
||
| #7 | 4306 | Fredric Fredricson |
P4DB: Hardened P4DB against malicious parameters (cross site scripting), performed some cleanup and increased version to 3.1.1. |
||
| #6 | 4300 | Fredric Fredricson |
P4DB. Some cleanup of old html-code |
||
| #5 | 4237 | Fredric Fredricson | P4DB: Maybe the final submit for P4DB 3.1.0 | ||
| #4 | 4069 | Fredric Fredricson | P4DB: More changes on the way to 3.1 | ||
| #3 | 2875 | Fredric Fredricson | P4DB 3.0 first beta... | ||
| #2 | 1920 | Fredric Fredricson |
P4DB: Mainly some user interface fixes: * Added a small arrow that points to selection in list of options * Added tooltip help * Added user prefereces to turn the above off (or on) * Some other user interface fixes And fixed a bug in jobList.cgi and some minor bugs in label and branch viewers. |
||
| #1 | 1638 | Fredric Fredricson | P4DB: Added all (I think) files for P4DB |