#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
use CGI::Carp ;
#
#################################################################
# CONFIGURATION INFORMATION
# All config info should be in P4CGI.pm
#
#################################################################
#
# P4 file log viewer
#
#################################################################
## Check if we have GD (required for branchGraph.cgi).
my $GD_AVAILABLE=undef ;
{
my $tmpDie = $SIG{'__DIE__'} ;
$SIG{'__DIE__'} = "" ;
eval ' use GD ; ' ;
if(length($@) == 0) {
$GD_AVAILABLE= "Y" ;
}
$SIG{'__DIE__'} = $tmpDie ;
}
sub offsetOf($@ ) {
my $v = shift @_ ;
my $pos = 0 ;
while(@_ > 0) {
if($v eq (shift @_)) {
return $pos ;
}
$pos++ ;
}
return -1 ;
}
my $err2null = &P4CGI::REDIRECT_ERROR_TO_NULL_DEVICE() ;
my $err2stdout = &P4CGI::REDIRECT_ERROR_TO_STDOUT() ;
#my ($serverYear,$serverNo,$serverQ) = &P4CGI::SERVER_VERSION() ;
# File argument
my $file = P4CGI::cgi()->param("FSPC") ;
&P4CGI::bail("No file spec") unless defined $file ;
# Get file data
my @filelogdata ;
my %relatedFiles ;
local *F ;
&P4CGI::p4call(*F,"filelog -l \"$file\"") ;
my $curr ;
while(<F>) {
chomp ;
next if /^\s*$/ ;
/^\.\.\. \#(\d+) change (\d+) (\S+) on (\S+) by (\S+)\@(\S+) \((\S+)\)/ and do {
my %data ;
my $rev ;
($rev,
$data{"change"},
$data{"action"},
$data{"date"},
$data{"user"},
$data{"client"},
$data{"type"}) =($1,$2,$3,$4,$5,$6,$7);
$data{"description"} = "" ;
$data{"labels"} = [] ;
$data{"open"} = [] ;
$curr = \%data ;
unshift @filelogdata,$curr ;
next ;
} ;
/^\t(.+)/ and do {
${$curr}{"description"} .= $1 . "\n" ;
next ;
} ;
/^\.\.\. \.\.\. (\S+) (\S+) (.+)$/ and do {
my ($act,$dir,$filespec) = ($1,$2,$3) ;
$filespec =~ /([^\#]+)(\#\d+.*)/ and do {
my ($file,$r) = ($1,$2) ;
$filespec = &P4CGI::ahref(-url=>"fileLogView.cgi",
"FSPC=$file",
"HELP=View file log",
"$file$r") ;
$relatedFiles{$file} = 1 ;
} ;
if(!exists ${$curr}{$dir}) {
my @arr ;
${$curr}{$dir} = \@arr ;
}
push @{${$curr}{$dir}},"$act $filespec" ;
} ;
}
close *F ;
&P4CGI::bail("No data for file \"$file\"") if @filelogdata == 0 ;
my @opendata ;
# Get info about opened status
&P4CGI::p4call(\@opendata,"opened -a \"$file\" $err2null") ;
my $openedText = "" ;
while(@opendata) {
$_ = shift @opendata ;
$openedText = "Opened by" ;
/^.*\#(\d+) - .* by (\S+)\@(\S+)/ or
&P4CGI::bail("Can not read info from \"p4 opened\"") ;
my ($rev,$user,$client) = ($1,$2,$3) ;
$user = &P4CGI::ahref(-url => "userView.cgi",
"USER=$user",
"HELP=View user info",
"$user") ;
$client = &P4CGI::ahref(-url => "clientView.cgi",
"CLIENT=$client",
"HELP=View client info",
"$client") ;
push @{${$filelogdata[$rev-1]}{"open"}},"$user\@${client}" ;
} ;
##
## Get Label cross reference
##
my %fileToLabels ; # Hash containing labels by file name and version
{
my @labels ; # Labels containing file
&P4CGI::p4call(\@labels,"labels $file") ;
map { s/^Label (\S+) .*/$1/ ; } @labels ;
if(@labels > 0) {
my $filelabels = "" ;
foreach (@labels) {
$filelabels .= " \"$file\@$_\"" ;
}
my @filesInLabels ;
&P4CGI::p4call(\@filesInLabels,"files $filelabels $err2null") ;
foreach (@filesInLabels) {
my $labt = shift @labels ;
my $lab = &P4CGI::ahref(-url => "labelView.cgi",
"LABEL=$labt",
"HELP=View label",
"$labt") ;
/^.*\#(\d+)/ and do {
my $v = $1 ;
push @{${$filelogdata[$v-1]}{"labels"}},"$lab" ;
} ;
/^(\S+)/ ;
if(defined $fileToLabels{$1}) {
$fileToLabels{$1} .= "<br>$lab" ;
}
else {
$fileToLabels{$1} = "$lab" ;
}
}
} ;
} ;
###
### Get jobs fixed by changes to file
###
my %jobDataByChangeNo ;
{
my @fixes ;
&P4CGI::p4call(\@fixes,"fixes -i \"$file\"") ;
foreach (@fixes) {
/^(.*) fixed by change (\d+)/ and
do {
my ($job,$change)=($1,$2) ;
my %jobData ;
&P4CGI::p4readform("job -o \"$job\"",\%jobData) ;
$jobData{"Job"} =
&P4CGI::ahref(-url=>"jobView.cgi",
"JOB=$jobData{Job}",
"HELP=View job",
"$jobData{Job}") ;
$jobData{"Description"} =
&P4CGI::formatDescription($jobData{"Description"}) ;
$jobDataByChangeNo{$change} = \%jobData ;
} ;
} ;
} ;
my @legendList ;
push @legendList,
&P4CGI::buttonCell("changeList.cgi",
"List all changes for this file",
"FSPC=$file",
"Changes") ;
my @parsListLab ;
my $p ;
foreach $p (&P4CGI::cgi()->param()) {
push @parsListLab, "$p=" . &P4CGI::cgi()->param($p) unless $p eq "LISTLAB" ;
}
# Get file directory part
my $fileDir=$file ;
$fileDir =~ s#/[^/]+$## ;
push @legendList,
&P4CGI::buttonCell("depotTreeBrowser.cgi",
"Browse depot tree at $fileDir",
"FSPC=$fileDir",
"Browse file dir.") ;
my %vars ;
{
my $par ;
foreach $par (&P4CGI::cgi()->param()) {
$vars{$par} = &P4CGI::cgi()->param($par);
} ;
} ;
if($GD_AVAILABLE) {
push @legendList,
&P4CGI::buttonCell("branchGraph.cgi",
"Show graph over branches and merges to/from this file",
"FSPC=$file",
"View Branch Graph") ;
}
print &P4CGI::start_page("",@legendList) ;
my $labelHead ="";
$labelHead="In label(s)" ;
print &P4CGI::start_framedTable("File log for $file") ;
print &P4CGI::start_table("class=\"ListX\"") ;
print &P4CGI::table_header("Rev",
"Action",
"Date",
"User",
"Change",
"Type",
$labelHead,
$openedText) ;
my $first = "yes" ;
my @revs ;
while(@filelogdata) {
my $rev = scalar @filelogdata ;
push @revs,$rev ;
my $tmpr = pop @filelogdata ;
my %data = %{$tmpr} ;
if($first ne "yes") {
print &P4CGI::table_row(-valign => "top",
-class=>"Delimiter",
undef,
undef,
undef,
undef,
undef,
undef,
undef,
undef,
{-class=>"Delimiter",
-text=>" "}) ;
};
$first = "no" ;
my $revLink ;
my $actionLink ;
if(exists $data{"into"}) {
foreach (@{$data{"into"}}) {
/^(\w+) (.*)/ ;
my ($act,$file) = ($1,$2) ;
print &P4CGI::table_row(-valign => "top",
# -class=>"Delimiter",
"",
undef,
undef,
undef,
undef,
undef,
undef,
undef,
{-class=>"kalle",
-text=>"$act into $file"}) ;
} ;
} ;
if( $data{"action"} eq "delete") {
$revLink = {-rowspan=>"2",
-class=>"ListHeadColumn",
-text=>"\#$rev"} ;
$actionLink = {-class=>"ListC",
-text=>$data{"action"}} ;
}
else {
$revLink = {-rowspan=>"2",
-class=>"ListHeadColumn",
-text=>
&P4CGI::ahref(-url=>"fileViewer.cgi",
"FSPC=$file",
"REV=$rev",
"HELP=View file",
"\#$rev")} ;
$actionLink = {-class=>"ListC",
-text=>&P4CGI::ahref(-url=>"fileDiffView.cgi",
"FSPC=$file",
"REV=$rev",
"ACT=$data{action}",
"HELP=View diff",
$data{"action"})} ;
} ;
print &P4CGI::table_row(-valign => "top",
-class => "\"Top\"",
$revLink,
$actionLink,
{-class=>"List",
-text =>$data{"date"}},
{-class=>"List",
-text =>&P4CGI::ahref(-url=>"userView.cgi",
"USER=$data{user}",
"HELP=View user info",
$data{"user"})},
{-class=>"List",
-text =>&P4CGI::ahref(-url=>"changeView.cgi",
"CH=$data{change}",
"HELP=View change",
$data{"change"})},
{-class=>"ListC",
-text =>"$data{type}"},
{-class=>"List",
-text =>join("<br>",@{$data{"labels"}})},
join("<br>",@{$data{"open"}})) ;
my %desc = ( -text => &P4CGI::formatDescription($data{"description"}),
-class=> "Description" ) ;
print &P4CGI::table_row(-valign => "top",
undef,
undef,
undef,
undef,
undef,
undef,
undef,
\%desc) ;
if(exists $data{"from"}) {
foreach (@{$data{"from"}}) {
/^(\w+) (.*)/ ;
my ($act,$file) = ($1,$2) ;
print &P4CGI::table_row(-valign => "top",
# -class=>"Delimiter",
"",
undef,
undef,
undef,
undef,
undef,
undef,
undef,
{-class=>"kalle",
-text=>"$act from $file"}) ;
} ;
} ;
if(exists $jobDataByChangeNo{$data{"change"}}) {
my %jobData = %{$jobDataByChangeNo{$data{"change"}}} ;
print &P4CGI::table_row(-valign => "top",
"",
"Fixes job:<br>$jobData{Job}",
undef,
undef,
undef,
undef,
undef,
undef,
{-class=>"Description",
-text =>$jobData{"Description"}}) ;
} ;
} ;
print &P4CGI::end_table("") ;
if(@revs > 2) {
print
"<hr>",
&P4CGI::cgi()->startform("-action","fileDiffView.cgi",
"-method","GET"),
&P4CGI::cgi()->hidden("-name","FSPC",
"-value",&P4CGI::urlEncode("$file")),
&P4CGI::cgi()->hidden("-name","ACT",
"-value","edit"),
&P4CGI::start_framedTable("Show diff between revisions"),
&P4CGI::cgi()->popup_menu(-name =>"REV",
"-values" =>\@revs);
shift @revs ;
print
" and ",
&P4CGI::cgi()->popup_menu(-name =>"REV2",
"-values" =>\@revs),
" ",
&P4CGI::cgi()->submit(-name =>"Go",
-value =>"Go"),
&P4CGI::end_framedTable(),
&P4CGI::cgi()->endform() ;
} ;
# my @fixes ;
# &P4CGI::p4call(\@fixes,"fixes \"$file\"") ;
# if(@fixes) {
# my @jobs ;
# &P4CGI::p4call(\@jobs,"jobs -i \"$file\"") ;
# my %job2desc ;
# %job2desc = map { /(\S+) on .* \'(.*)\'/ ;
# my ($job,$desc) = ($1,$2) ;
# $desc .= "..." if length($desc) > 30 ;
# ($job,$desc) ; } @jobs ;
# my $j ;
# foreach $j (keys %job2desc) {
# my %jobData ;
# &P4CGI::p4readform("job -o \"$j\"",\%jobData) ;
# if(exists $jobData{"Description"}) {
# my $d = $jobData{"Description"} ;
# $job2desc{$j} = $d ;
# }
# }
# print "<hr><b><font size=+1>Fixes</font></b>",
# &P4CGI::start_table(""),
# &P4CGI::table_header("Job/view job",
# "Change/view change",
# "Date",
# "User/view user",
# "Description") ;
# my $fix ;
# foreach $fix (sort { my $ach = $a ;
# my $bch = $b ;
# $ach =~ s/.* by change (\d+) .*/$1/ ;
# $bch =~ s/.* by change (\d+) .*/$1/ ;
# $bch <=> $ach } @fixes)
# {
# $fix =~ /(.*) fixed by change (\d+) on (\S+) by (\S+)@(\S+)/ ;
# my ($job,$change,$date,$user,$client) = ($1,$2,$3,$4,$5) ;
# print
# &P4CGI::table_row(-valign => "top",
# &P4CGI::ahref("-url","jobView.cgi",
# "JOB=$job",
# "HELP=View job",
# "$job"),
# &P4CGI::ahref("-url","changeView.cgi",
# "CH=$change",
# "HELP=View change",
# "$change"),
# "$date",
# &P4CGI::ahref(-url => "userView.cgi" ,
# "USER=$user",
# "HELP=View user info",
# "$user"),
# {-type=> "td",
# -class=> "Description",
# -text=>$job2desc{$job}}) ;
# }
# print
# &P4CGI::end_table("") ;
# }
sub getRelatedFiles($ )
{
my $file = shift @_ ;
my @data ;
&P4CGI::p4call(\@data,"filelog \"$file\"") ;
my %res ;
map { if(/^\.\.\. \.\.\. \w+ \w+ (\S+?)\#/) { $res{$1} = 1 ; } ; } @data ;
return ( sort keys %res ) ;
} ;
if((keys %relatedFiles) > 0) {
my @rel = sort keys %relatedFiles ;
my @fileLinks = map { &P4CGI::ahref("-url","fileLogView.cgi",
"FSPC=$_",
"HELP=View file log",
"$_") ; } @rel ;
my %indrel ;
$relatedFiles{$file} = 1 ;
while(@rel > 0) {
my $r ;
foreach $r (map { exists $relatedFiles{$_} ? () : $_ } getRelatedFiles(shift @rel)) {
&P4CGI::ERRLOG("found: $r") ;
$indrel{$r} = 1;
push @rel, $r ;
$relatedFiles{$r} = 1 ;
}
}
my @indFileLinks = map { &P4CGI::ahref("-url","fileLogView.cgi",
"FSPC=$_",
"HELP=View file log",
"$_") ; } sort keys %indrel ;
print
"<hr>",
&P4CGI::start_framedTable("Related files"),
&P4CGI::start_table(""),
&P4CGI::table_row({-class => "Prompt",
-text => "Direct related:" },
{ -text => join("<br>",@fileLinks) }) ;
if(@indFileLinks > 0) {
print "", &P4CGI::table_row({ -class => "Prompt",
-text => "Indirect related:" },
{ -text => join("<br>",@indFileLinks) }) ;
} ;
print
&P4CGI::end_table(),
&P4CGI::end_framedTable() ;
} ;
print
&P4CGI::end_framedTable(),
&P4CGI::end_page() ;
#
# That's all folks
#
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #14 | 4990 | Fredric Fredricson | P4DB: Improved error handling: | ||
| #13 | 4306 | Fredric Fredricson |
P4DB: Hardened P4DB against malicious parameters (cross site scripting), performed some cleanup and increased version to 3.1.1. |
||
| #12 | 4216 | Fredric Fredricson | P4DB: Another partial submit on my way to P4DB 3.1... | ||
| #11 | 4152 | Fredric Fredricson | P4DB: Some more work on tha way to version 3.1.... | ||
| #10 | 4069 | Fredric Fredricson | P4DB: More changes on the way to 3.1 | ||
| #9 | 2875 | Fredric Fredricson | P4DB 3.0 first beta... | ||
| #8 | 1927 | Fredric Fredricson | P4DB: Removed some prints to the httpd error log | ||
| #7 | 1926 | Fredric Fredricson |
P4DB: Replaced call to CGI::Vars() with code that works for older CGI.pm versions as well. (Will make upgrades so much easier). |
||
| #6 | 1924 | Fredric Fredricson |
P4DB: Fixed a bug in fileLogView.cgi and also made the code take advantage of the -l flag for the filelog command. |
||
| #5 | 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. |
||
| #4 | 1913 | Fredric Fredricson |
P4DB: Updated file log view with a link to branch graph and the README with information about the branchGraph cgi |
||
| #3 | 1870 | Fredric Fredricson |
P4DB: Fixed problem when description in file log view contained special characters such as <, > and & |
||
| #2 | 1646 | Fredric Fredricson |
P4DB: file log can now show full descriptions. Added a new "preference" that makes the full descriptions default or not. |
||
| #1 | 1638 | Fredric Fredricson | P4DB: Added all (I think) files for P4DB |