#!/usr/bin/perl -w # -*- perl -*- use P4CGI ; use strict ; # ################################################################# # CONFIGURATION INFORMATION # All config info should be in P4CGI.pm # ################################################################# # # P4 depot tree browser # ################################################################# ### ### Handle file spec argument ### # * Get path from argument my $fspc = &P4CGI::cgi()->param("FSPC") ; $fspc =~ s/\.\.\.$// if defined $fspc ; $fspc = &P4CGI::htmlEncode($fspc) ; # Find out if we have multiple depots my @depots ; my $err2null = &P4CGI::REDIRECT_ERROR_TO_NULL_DEVICE() ; &P4CGI::p4call(\@depots,"dirs \"//*\" $err2null") ; my $moreThanOneDepot = (@depots > 1) ; # Set server ROOT my $ROOT ; if($moreThanOneDepot) { $ROOT = "/" ; } else { $ROOT = "$depots[0]/" ; $ROOT =~ s|//|/|g ; } ; # canonicalize to either "/.../" or "/" $fspc = $ROOT unless defined $fspc ; $fspc = "/$fspc/" ; while($fspc =~ s|//|/|) {} ; # Find out if we are at root my $weAreAtROOT = ($fspc eq $ROOT) ; if($weAreAtROOT) { &P4CGI::cgi()->delete("FSPC") ; } ; ### ### handle "Hide deleted files" argument ### # * Get HIDEDEL argument (Hide deleted files) my $hidedel = P4CGI::cgi()->param("HIDEDEL") ; if(&P4CGI::HIDE_DELETED() == 0) { $hidedel = "NO" unless defined $hidedel and $hidedel eq "YES" ; } else { $hidedel = "YES" unless defined $hidedel and $hidedel eq "NO" ; } my $p4DirsDOption = "" ; # Set -D option for "p4 dirs" if hide deleted $p4DirsDOption = " -D" if $hidedel eq "NO" ; ### ### Figure out "back" buttons ### my @back ; my $tmp = "$fspc" ; # Copy arg my $lastd ; if($tmp =~ /([^\/]+\/)$/) { $lastd = $1 ; } ; $tmp =~ s|[^/]+/$|| ; # Remove last subdir my $upTarget = $tmp ; # while($tmp ne $ROOT) { $tmp =~ s|([^/]+)/$|| or last ; my $f = $1 ; unshift @back,&P4CGI::ahref("FSPC=$tmp$f", "HIDEDEL=$hidedel", "HELP=Up to /$tmp$f", "/$f") ; } ; unless($weAreAtROOT) { unshift @back,&P4CGI::ahref("FSPC=$ROOT", "HIDEDEL=$hidedel", "HELP=Up to depot root", "[ROOT]") ; } if(defined $lastd) { push @back,"/$lastd" ; } my @options ; ### ### Create link to changes for all files below ### push @options,&P4CGI::buttonLink("changeList.cgi", "View changes for /$fspc...", "CMD=changes", "FSPC=/$fspc...", "Changes") ; ### ### Create link to changes for all files below ### push @options,&P4CGI::buttonLink("changeList.cgi", "View pending changes for /$fspc...", "CMD=changes", "STATUS=pending", "FSPC=/$fspc...", "Pending") ; ### ### Create link to open files for all files below ### push @options,&P4CGI::buttonLink("fileOpen.cgi", "View currently open files for /$fspc...", "FSPC=/$fspc...", "Open files") ; ### ### Create link to view changes for a specific user below this point ### push @options,&P4CGI::buttonLink("searchPattern.cgi", "Find changes by user, description etc.", "FSPC=/$fspc...", "Find changes") ; ### ### Create link to recently modified files ### push @options,&P4CGI::buttonLink("findFiles.cgi", "Find files by name and date in /$fspc...", "FSPC=/$fspc...", "Find Files") ; ### ### Create link to depot statistics ### push @options,&P4CGI::buttonLink("depotStats.cgi", "View depot statistics for /$fspc...", "FSPC=/$fspc...", "Statistics") ; ### ### Create link to recently modified files ### push @options,&P4CGI::buttonLink("jobList.cgi", "View jobs related to files /$fspc...", "FSPC=/$fspc...", "LIST=Y", "Jobs") ; ### ### Get subdirs ### my @allSubDirsWithFiles ; &P4CGI::p4call(\@allSubDirsWithFiles,"dirs \"/$fspc*\" $err2null") ; my %nonDeleted = map { ($_,$_) ; } @allSubDirsWithFiles ; my @subdirs ; &P4CGI::p4call(\@subdirs,"dirs $p4DirsDOption \"/$fspc*\" $err2null") ; map { my $dir = $_ ; my $dirname ; ($dirname = $dir) =~ s|^.*/|/| ; my $divstart = "" ; my $divend = "" ; unless(defined $nonDeleted{$dir}) { $divstart = "" ; $divend = "" ; } ; $_ = $divstart. P4CGI::ahref("FSPC=$dir", "HIDEDEL=$hidedel", "HELP=Descend to subdir", $dirname) . $divend ; } @subdirs ; unless($weAreAtROOT) { unshift @subdirs,&P4CGI::ahref("FSPC=$upTarget", "HIDEDEL=$hidedel", "HELP=Up", "/..") ; } ### ### Get files ### my @files ; my $totalFiles = 0 ; my @tmp ; &P4CGI::p4call(\@tmp,"files \"/$fspc*\" $err2null") ; @files = map { /([^\#]+)\#(.*)/ ; $totalFiles++ ; my $file=$1 ; my $info=$2 ; $file =~ s/^.*\/// ; my ($rev,$inf) = split / - /,$info ; my $pfile = "$file" ; my $prev ; my $spanStart = "" ; my $spanEnd = "" ; if($inf =~ /^delete/) { $prev = "\#$rev"; $spanStart = "" ; $spanEnd = "" ; if($hidedel eq "YES") { $pfile = undef ; } else { $pfile= "$file"; } } else { $prev = &P4CGI::ahref(-url => "fileViewer.cgi", "FSPC=/$fspc$file", "REV=$rev", "HELP=View head revision of file", "\#$rev") ; }; if($pfile) { $pfile = join("", ($spanStart, &P4CGI::ahref(-url => "fileLogView.cgi", "FSPC=/$fspc$file", "HELP=View file log", "$pfile") , " $prev" , $spanEnd )) ; } ; defined $pfile?$pfile:() ; } @tmp ; ### ### Create link for "hide/view deleted files" ### my $toggleHide ; if($hidedel eq "YES") { $toggleHide = &P4CGI::buttonCell($ENV{SCRIPT_NAME}, "Click to show deleted files", "FSPC=/$fspc", "HIDEDEL=NO", "Show deleted") ; } else { $toggleHide = &P4CGI::buttonCell($ENV{SCRIPT_NAME}, "Click to hide deleted files", "FSPC=/$fspc", "HIDEDEL=YES", "Hide deleted") ; } ### ### Set help target ### &P4CGI::SET_HELP_TARGET("depotTreeBrowser") ; ### ### Start page printout ### print &P4CGI::start_page("Depot Tree Browser", $toggleHide) ; my $sarg=$weAreAtROOT?"[ROOT]":"/$fspc" ; # replace // with [ROOT] my $currpath ; print &P4CGI::start_framedTable("Location") ; if(@back > 0) { $currpath = join('',@back) ; } else { $currpath = "[ROOT]" ; } print " \n". " $currpath\n". " \n". " \n". " \n" . join(" ",@options) . " \n" . " \n" . &P4CGI::end_framedTable() ; ### # Make table with three columns # sub makeThreeColumns(@) { my $l = @_ ; my $len = int((@_+2)/3) ; if($l < 10) { $len = int($l/2) ; } ; if($l < 6) { $len = $l ; } ; while(@_ < ($len*3)) { push @_,"" ;} ; # To avoid error messages return join("\n",(&P4CGI::start_table(" COLS=3 class=\"TreeBrowser\""), &P4CGI::table_row({-class => "TreeBrowser", -text => join("
\n",@_[0..$len-1])}, {-class => ($len<$l)?"TreeBrowser":"Empty", -text => join("
\n",@_[$len..(2*$len)-1])}, {-class => ($len*2<$l)?"TreeBrowser":"Empty", -text => join("
\n",@_[(2*$len)..(3*$len)-1])}), &P4CGI::end_table())) ; } if($weAreAtROOT and $moreThanOneDepot) { print "
" , &P4CGI::start_framedTable("Depots") ; if(@subdirs>0) { print makeThreeColumns(@subdirs) ; } print &P4CGI::end_framedTable() ; } else { print "
", &P4CGI::start_framedTable("Directories") ; if(@subdirs>0) { print makeThreeColumns(@subdirs) ; } else { print "
[No more subdirectories]
" ; } ; print &P4CGI::end_framedTable() ; print "
", &P4CGI::start_framedTable("Files") ; print " (deleted files hidden)" if ($hidedel eq "YES" and $totalFiles > @files); print "\n"; if(@files>0) { print makeThreeColumns(@files) ; } else { print "
[No files in this directory]
" ; } print &P4CGI::end_framedTable() ; } ; print &P4CGI::end_page() ; # # That's all folks #