#!/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 |