#!/usr/bin/perl -w use strict ; # # p4b4.perl -- CGI browser for PERFORCE # # This script is based on the cgi script provided by Perforce. Most of the code # in that script is still in this script. # # * Added -w and "use strict" (my personal religion, sorry about that) # * Fixed all the consequences from -w and "use strict" # * Added some error handling # * Handles '<','>' and '&' in more places than before # * Changed the way parameters are passed to make it easier to use forms # * First parameter to "changes" can now handle labels as well as file name # * Smarter way to display files # * Added a lot of stuff...... # Fredric Fredricson, MYDATA automation AB, fredric@mydata.se # # Known bugs: # * A serious case of feature bloat # ################################################################# # BASIC CONFIGURATION INFORMATION # # How to configure: # # 1. Set first line of script to point to perl. Usually /usr/bin/perl # or /usr/bin/perl. Don't forget the -w switch # # 2. If You are not using the standard host/port, set it here #$ENV{P4PORT} = "p4:1666"; # 3. A user and a client must be specfied. The user must have write access (at least # if You want to view jobs (at least using p4 97.2.....) I have honstly no idea why # this is the case but the physical universe is pretty persuasive here......) $ENV{USER} = "trenoll"; $ENV{P4CLIENT} = "trenoll_slussen"; $ENV{USER} = "fredric"; $ENV{P4CLIENT} = "fredric_at_home"; # 4. Set up complete path to p4 program my $P4PGM = "/usr/local/bin/p4"; # 5. Set up path to standard configuration file $ENV{CODELINES} = "./CODELINES" ; # 6. Set up a path to temporary data files that might be used. # (NOTE! the cgi must have write access to this directory) $ENV{TMPDIR} = "/tmp" ; # # 7. Set up script name (leave commented out for apache) # #$ENV{SCRIPT_NAME} = $0 ; # # END OF BASIC CONFIGURATION (well, this is perl, the whole script could be # viewed as "basic configuration") ################################################################# # # Some more opportunities for configuration: # # Standard background color my $bgcolor = "#FFFFD0"; # Sort of bright yellow # A slightly darker background color my $bgcolor_dark = "#C0D0C0"; # Sort of dark # A slightly brighter background color my $bgcolor_bright = "white"; # Sort of bright # Some definitions for text colors my $BLUE_TXT = qq(); my $GREEN_TXT = qq(); my $RED_TXT = qq(); my $END = qq(); # Some more definitions for text colors/styles my $ADD = $BLUE_TXT; my $ADDEND = $END; my $DEL = "$RED_TXT"; my $DELEND = "$END"; # Constants for the file diff display my $MAXCONTEXT = 30; my $NCONTEXT = 10; # # OK, that was the configuration parts, the rest is not *intended* # as configuration part # ################################################################# my $myname = defined $ENV{SCRIPT_NAME} ? $ENV{SCRIPT_NAME} : $0 ; # Set up script name # File handle must be declared somwhere (use strict!) local *P4 ; # Variable to contain parameter values by names my %args ; # CMD -> current command name # CH -> change number # FSPC -> file specification (for changes and files) # CHK_FSPC -> check file spec to make sure file exists # REV -> file revision # ACT -> file action # FROMCH -> display only changes later than this change # EXLAB -> exclude changes that affects this label # VERBOSE -> if "YES" will be more verbose (for beginners) # # Get arguments from command line or browser (This works with apache version???, I # don't know if it will work with any other browser) # my $qstring = $ENV{QUERY_STRING} ; if(defined $qstring) { ### Convert %nn's in QUERY_STRING $qstring =~ s/%/\\x/g ; # (method: change to \xnn and eval) $qstring =~ s/@/\\@/g ; $qstring = eval("return \"$qstring\"") ; } else { $qstring = join('&',@ARGV) ; } # # Stuff arguments from browsed into args hash # my $arg ; foreach $arg (split(/&/, $qstring)) { my ($command,$value) = split /=/,$arg ; $args{$command}=$value ; } # # Set verbose variables # my $verbose = $args{"VERBOSE"} ; $verbose = "NO" unless defined $verbose ; $verbose = undef unless $verbose eq "YES" ; my $verbose_string = (defined $verbose) ? "YES" : "NO" ; my $verbose_arg = (defined $verbose) ? "&VERBOSE=YES" : "" ; # # Get help texts # my %helpTexts ; my $currHelpText ; if(defined $verbose) { while() { /HELPTEXT=(\S+)/ && do { $currHelpText = $1 ; $helpTexts{$currHelpText} = "" ; next ; } ; $helpTexts{$currHelpText} .= $_ ; } } # # Common part of header # $| = 1 ; # turn output buffering of (wonderful perl syntax, isn't it!) print "Content-type: text/html\n", "\n", "\n" ; # # Check that we have contact with p4 server # &p4open(*P4,"changes -m 1|") ; $_ = ; /Change (\d+)/ or &bail("No contact with P4 server") ; my $currentChangeLevel=$1 ; # # Parse arguments(s) # if(!defined $args{"CMD"}) { &introScreen() ; } else { my $command=$args{"CMD"} ; "changes" eq $command and do { my ($filespec, $exlab, $fromChange) = ($args{"FSPC"} or &bail("Argument error: Missing file specification"), $args{"EXLAB"}, $args{"FROMCH"}) ; &showChanges($filespec, $exlab, $fromChange) ; } ; "searchdepot" eq $command and do { my ($filespec) = ($args{"FSPC"} or &bail("Argument error: Missing file specification")) ; &searchDepot($filespec) ; } ; "describe" eq $command and do { my $change=$args{"CH"} or &bail("Argument error: Missing change number"); &describeChange($change) ; } ; "filelog" eq $command and do { my ($filespec) = ($args{"FSPC"} or &bail("Argument error: Missing file specification")) ; &filelog($filespec) ; } ; "print" eq $command and do { my $fname = $args{"FSPC"} or &bail("Argument error: Missing file spec") ; my $frev = $args{"REV"} or &bail("Argument error: Missing file revision") ; &printFile($fname,$frev) ; } ; "diff" eq $command and do { my $name = $args{"FSPC"} or &bail("Argument error: Missing file spec") ; my $rev = $args{"REV"} or &bail("Argument error: Missing file revision") ; my $mode = $args{"ACT"} or &bail("Argument error: Missing file action") ; my $rev2 = $args{"REV2"} ; my $name2 = $args{"FSPC2"} ; &printDiff($name,$rev,$mode,$rev2,$name2) ; } ; "jobs" eq $command and do { &listJobs($args{"JOBSTAT"}) ; } ; "job" eq $command and do { $args{"JOB"} or &bail("Argument error: Missing job spec") ; &descJob($args{"JOB"}) ; } ; "label" eq $command and do { $args{"LABEL"} or &bail("Argument error: Missing label spec") ; &descLabel($args{"LABEL"}) ; } ; "labeldiff" eq $command and do { $args{"LABEL"} or &bail("Argument error: Missing label spec") ; $args{"LABEL2"} or &bail("Argument error: Missing label spec") ; &labelDiff($args{"LABEL"},$args{"LABEL2"}, $args{"SHOWSAME"}, $args{"SHOWNOTSAME"}, $args{"SHOWDIFF"}) ; } ; } # Common trailer print "
Comments: fredric\@mydata.se", "\n"; ################################ # # Put up the introductory screen. # ################################ # "local" subroutine that creates an entry # on intro screen (made a subroutine to facilitate # modifications sub introScreenSection($$$@ ) { # arg 1 : title # arg 2 : an anchor name for anchor and help texts # arg 3 : Help text # arg 4..n : body of selection # print "---". join("\n---",@_)."\n" ; my $title = shift @_ or die("Internal error") ; my $anchor = shift @_ or die("Internal error") ; my $helpText = shift @_ ; #or die("Internal error for $anchor") ; my @body = @_ ; print "",&anchor($anchor),"\n", "

$title

" , (defined $verbose) ? $helpText : "", join("\n", &table("", row("", (cell("bgcolor=\"$bgcolor_dark\"", @body), (!defined $verbose) ? (cell("", (&url("VERBOSE=YES", "$GREEN_TXT Click for help $END",$anchor)))) : ("") ) ) ) ) ; } ; sub introScreen( ) { &printHeader("Perforce Depot Browser") ; print "
", &gotoAnchor("SELECT_PREDEF","Changes for predefined pattern"),"|", &gotoAnchor("SELECT_PATTERN","Changes for file"),"|", &gotoAnchor("SELECT_SEARCH","Search for file"),"|", &gotoAnchor("SELECT_LABEL","View label"),"|", &gotoAnchor("SELECT_LABEL_CHANGES","View changes for label"),"|", &gotoAnchor("SELECT_LABEL_DIFF","View diff between labels"),"|", &gotoAnchor("SELECT_JOBS","View jobs"), "
" ; print "", (defined $verbose) ? &helpText("GENERAL") : &url("VERBOSE=YES", "

Click here for". " help"), "


\n"; # Default codelines data is just a simple list of everything. # If $CODELINES is set in the environment, the codelines comes # from that. The format is: # # description1 # //path1[+//path2...] # description2 # //path2 my @CODELINES = ("Full Depot Source\n", "//...\n" ); if (defined $ENV{CODELINES} and -r $ENV{CODELINES}) { open(P4, "$ENV{CODELINES}" ) || &bail("Can not open codelines file". " \"$ENV{CODELINES}\"" ); @CODELINES = ; close P4 ; } my $tmp="" ; foreach ( @CODELINES ) { chop; if( m:^/: ) { my $t ; ($t = $_) =~ s/\+/ AND /g ; $tmp .= "
  • ". &url( "CMD=changes&FSPC=$_", $t ). "\n"; } elsif( !/^\s*$/ ) { $tmp .= "
    $_\n"; } } &introScreenSection ("View changes for predeined view", "SELECT_PREDEF", &helpText("SELECT_PREDEF"), $tmp) ; &introScreenSection ("View changes for selected patterm", "SELECT_PATTERN", &helpText("SELECT_PATTERN"), "
    \n" , " \n" , " \n" , "
    \n") ; &introScreenSection ("Search for file pattern", "SELECT_SEARCH", &helpText("SELECT_SEARCH"), "
    \n" . " \n" . " \n". "
    \n") ; # Get labels &p4open( *P4, "labels |" ); my @labels ; while() { /^Label (\S+)/ ; $1 =~ /^test/i && do { next ; } ; push @labels,$1 ; } close P4 ; # Create label \n" ; } $labelSelectOptions .= "