#!/usr/bin/perl -w # -*- perl -*- use P4CGI ; use strict ; # ################################################################# # CONFIGURATION INFORMATION # All config info should be in P4CGI.pm # ################################################################# # # P4 change browser # View list of changes for selected part of depot # ################################################################# ##### # This was the most complicated and insane script in P4DB. # The reason for this is that features where added and added and added until # the script became impossible to maintain and no more features could # be added. Despite this I still wanted MORE FEATURES and finally I # decided to start all over again and see if it is possible to add the # new features if I rewrote it all. And maybe, just maybe, I will # manage to make it maintainable this time. We will see...... # Jan 7 - 2000/Fredric #### ####### # Arguments: # # FSPC # File specification. Should start with //. Can be more than one file spec # in which case they are concatenated (no space, but start each file spec # with //). # The file specification should not contain any label or revision numbers. # # LABEL # Label specification. Label for which changes should be listed. # There can be only one label. # # NOTE! FSPC or LABEL must be specified. # # STATUS # Status of changes. Allowed values are "submitted" and "pending". # If not supplied "submitted" is assumed. # # EXLABEL (optional) # Specify a label to exclude. Same format as LABEL. The changes made for # this label are excluded from list. # # MAXCH (optional) # Max changes to display. To avoid very large html pages this argument # limits the number of changes displayed at one page. # If not specified there is a default value used (from config file) # # FIRSTCH (optional) # When MAXCH is specified this specifies change to start at (for second # and subsequent pages) # # CHOFFSET (optional) # Number of changes already displayed. # # SEARCHDESC (optional) # View only changes with pattern in description # # SEARCH_INVERT (optional) # If specified, invert pattern search # # USER (optional) # View only changes for users specified in comma-separated list # # GROUP (optional) # View only changes for users in comma-separated list of groups # # CLIENT (optional) # View only changes for clients specified in comma-separated list # # SHOWREFERENCED (optional) # If present and set to "Y" will try to display description for changes # referred to in change description # ###### my $MAGIC_RED=":::RED:::~~~" ; ## get server version my ($serverY,$serverN,$serverX) = &P4CGI::SERVER_VERSION() ; ### ### ### Get command arguments ### ### ### # # Get file spec argument # my $filespec = &P4CGI::cgi()->param("FSPC") ; $filespec = &P4CGI::htmlEncode($filespec) if defined $filespec ; my $FSPC_WasSpecified = $filespec ; $filespec = "//..." unless defined $filespec ; $filespec =~ s/\s*\+?\s*\/\//\/\//g ; # replace <space>+<space>// with // # where <space> is 0 or more whitespace charcaters my @FSPC = map { if($_) { "//".$_ ; } else { () ; } ; } split("//", $filespec ) if defined $filespec ; # # Get label argument # my $LABEL = &P4CGI::cgi()->param("LABEL") ; $LABEL = &P4CGI::htmlEncode($LABEL) if defined $LABEL ; if(defined $LABEL and $LABEL eq "-") { $LABEL = undef ; } ; # # Check that FSPC or LABEL is specified # unless(defined $LABEL or defined $FSPC_WasSpecified) { &P4CGI::bail("File spec OR label must be specified") ; } # # Get label to exclude # my $EXLABEL = &P4CGI::cgi()->param("EXLABEL") ; $EXLABEL = &P4CGI::htmlEncode($EXLABEL) if defined $EXLABEL ; if(defined $EXLABEL and $EXLABEL eq "-") { $EXLABEL = undef ; } ; # # Get status # my $STATUS = &P4CGI::cgi()->param("STATUS") ; unless(defined $STATUS) { $STATUS = "submitted" ; } ; # # Get max changes to display # my $MAXCH = P4CGI::cgi()->param("MAXCH") ; $MAXCH = &P4CGI::MAX_CHANGES() unless(defined $MAXCH) ; # # Get first change No. to display and offset from start # my $FIRSTCH ; my $CHOFFSET=0 ; if(defined $MAXCH) { $FIRSTCH = P4CGI::cgi()->param("FIRSTCH") ; $CHOFFSET = P4CGI::cgi()->param("CHOFFSETDISP") ; } my $SHOWREFERENCED = P4CGI::cgi()->param("SHOWREFERENCED") ; $SHOWREFERENCED = undef if defined $SHOWREFERENCED and $SHOWREFERENCED ne "Y" ; # # Get search data, user and client parameters # my $SEARCHDESC = &P4CGI::cgi()->param("SEARCHDESC") ; $SEARCHDESC=undef if defined $SEARCHDESC and $SEARCHDESC eq "" ; my $SEARCH_INVERT = &P4CGI::cgi()->param("SEARCH_INVERT") ; my $USER = &P4CGI::cgi()->param("USER") ; { my @tmp = &P4CGI::cgi()->param("USERS") ; if(@tmp) { if(defined $USER) { $USER .= "," . join(',',@tmp) ; } else { $USER = join(',',@tmp) ; } } } $USER=undef if defined $USER and $USER eq "" ; my $GROUP = &P4CGI::cgi()->param("GROUP") ; { my @tmp = &P4CGI::cgi()->param("GROUPS") ; if(@tmp) { if(defined $GROUP) { $GROUP .= "," . join(',',@tmp) ; } else { $GROUP = join(',',@tmp) ; } } } $GROUP=undef if defined $GROUP and $GROUP eq "" ; my $CLIENT = &P4CGI::cgi()->param("CLIENT") ; $CLIENT=undef if defined $CLIENT and $CLIENT eq "" ; ### ### Sub getChanges ### # This subroutine is used to get a set of changes from depot. The parameter is a hash containing # a set of switches: # -long If set, get changes in "long" format (i.e. full description, # not only the first 27 chars) # -file File spec for changes # -firstch First change to look for (or "offset") # -maxch Max changes to get # -status Status ("submitted" or "pending") # -user For specified user only # -client For specified client only # -label Label for file spec # -lastch Reference to scalar to receive last change parsed # -lastrch Reference to scalar to receive last change parsed and returned in result # -resultto A reference to a hash to receive result # -select A reference to a subroutine to call that determine if a change should be included # in list. The subroutine gets parameters: (<change>,<date>,<user>,<client>,<description>) # The <description> parameter is passed as a reference and can be modified # The subroutine should return true if the change should be included. # NOTE! The -select parameter is very important to understand if you plan to # understand more of this code. # # Another important thing to understand is that this subroutine getChanges is frequently called # more than once. # sub getChanges(%) { my %pars = @_ ; my $long ; # defined if -l flag my $filespec = "" ; # file spec my $firstch = &P4CGI::CURRENT_CHANGE_LEVEL() ; # first change to look for my $maxch = 0 ; # max no changes my $status="submitted" ; # status my $label ; # label my $rhash ; # result my $select ; # selection funtion my $lastch ; # Last change parsed my $lastrch ; # Last change parsed and returned my $linkedch ; # linked ch ref my $userOpt = "" ; # -u option to "changes" my $clientOpt = "" ; # -c option to "changes" my $k ; foreach $k (keys %pars) { $k = lc($k) ; $k eq "-long" and do { $long = $pars{$k} ; next } ; $k eq "-file" and do { $filespec = $pars{$k} ; next } ; $k eq "-firstch" and do { $firstch = $pars{$k} ; next } ; $k eq "-maxch" and do { $maxch = $pars{$k} ; next } ; $k eq "-status" and do { $status = $pars{$k} ; next } ; $k eq "-label" and do { $label = $pars{$k} ; next } ; $k eq "-resultto" and do { $rhash = $pars{$k} ; next } ; $k eq "-select" and do { $select = $pars{$k} ; next } ; $k eq "-lastch" and do { $lastch = $pars{$k} ; next } ; $k eq "-lastrch" and do { $lastrch = $pars{$k} ; next } ; $k eq "-magiclinked" and do { $linkedch = $pars{$k} ; next } ; $k eq "-user" and do { $userOpt = "-u $pars{$k} " ; next } ; $k eq "-client" and do { $clientOpt = "-c $pars{$k} " ; next } ; } ; my $tmpLastch ; $lastch = \$tmpLastch unless defined $lastch ; $lastrch = \$tmpLastch unless defined $lastrch ; if($long) { $long = " -l " ; } else { $long = "" } ; if($label) { $filespec .= "\@$label" ; if ($firstch and ($firstch != &P4CGI::CURRENT_CHANGE_LEVEL())) { $maxch += $firstch ; } ; } else { if ($firstch) { $filespec .= "\@$firstch" ; } ; } ; if($maxch) { $maxch = " -m $maxch " ;} else { $maxch = "" ; } ; if($status eq "pending") { $filespec = "" ; } ; if($filespec =~ /\s/) { $filespec = "\"$filespec\"" ; } ; my $command = "changes ${clientOpt}${userOpt}$long -t -s $status $maxch $filespec" ; $command = "changes ${clientOpt}${userOpt}$long -s $status $maxch $filespec" if $serverY < 2003 ; my $chpattern = "Change (\\d+) on (\\S+ \\S+) by (\\w+)\\@(\\S+)" ; $chpattern = "Change (\\d+) on (\\S+) by (\\w+)\\@(\\S+)" if $serverY < 2003 ; # &P4CGI::ERRLOG("Patterm: $chpattern\n") ; local *P4 ; my $n = 0 ; &P4CGI::p4call(*P4,$command) ; $$lastrch = 0 ; while(<P4>) { chomp ; if(/$chpattern/) { $n++ ; my ($change,$date,$user,$client) = ($1,$2,$3,$4) ; $$lastch = $change ; my $desc = "" ; if($long) { <P4> ; while(<P4>) { chomp ; last if length($_) == 0 ; s/^\t// ; if(length($desc) > 0) { $desc .="\n" ; } ; $desc .= $_ ; } # &P4CGI::ERRLOG("select: $select") ; if(defined $select) { next unless &$select($change,$date,$user,$client,\$desc) ; } my @ch; $desc = &P4CGI::formatDescription($desc,\@ch) ; $desc =~ s/$MAGIC_RED(.*?)$MAGIC_RED/<font color=red>$1<\/font>/gis ; if(defined $linkedch and @ch > 0) { $$linkedch{$change} = \@ch ; } ; } ; $$lastrch = $change ; $$rhash{$change} = [$date,$user,$client,$desc] ; } } close P4 ; return $n ; } ; ### get target ### my %extraUrlOptions ; if(&P4CGI::CHANGES_IN_SEPARATE_WIN()) { $extraUrlOptions{"-target"}="CHANGES" ; } ### ### ### Fix page title ### ### ### my $title = "List changes for" ; if($STATUS eq "pending") { $title = "Pending changes for " ; } ; $title = "<table><tr><td class=\"PageTitle\">$title</td><td> </td><td class=\"PageTitle\"> " ; if($FSPC_WasSpecified) { $title .= join(" and <br>",@FSPC) ; if(defined $LABEL) { $title .= "<br>and label $LABEL" ; } } else { $title .= "label $LABEL" ; } ; if(defined $EXLABEL) { $title .= "<br>excluding changes for label $EXLABEL" ; } if(defined $CHOFFSET and $CHOFFSET > 0) { $title .= "<br><small>(offset $CHOFFSET from top)</small>" ; } ; if(defined $USER) { $title .= " <br>where user is: $USER" ; } ; if(defined $GROUP) { $title .= " <br>where group is: $GROUP" ; # } ; if(defined $CLIENT) { $title .= "<br>where client is: $CLIENT" ; # } ; if(defined $SEARCHDESC) { my $not="" ; if(defined $SEARCH_INVERT) { $not = " does not" } $title .= "<br>where description$not match: $SEARCHDESC" ; } ; $title .=" </td></tr></table>" ; ### ### ### Get changes to exclude (if any) ### ### ### local *P4 ; my %excludeChanges ; my $f ; my $lastChangeInLabel = 0 ; if(defined $EXLABEL ) { getChanges(-label=>$EXLABEL, -resultto=> \%excludeChanges) ; my $n = scalar keys(%excludeChanges) ; my @tmp = sort { $b <=> $a } keys %excludeChanges ; $lastChangeInLabel = $tmp[0] ; &P4CGI::ERRLOG("Exclude from label \"$EXLABEL\":$n lastCh:$lastChangeInLabel") ; } ; ### ### ### Start page ### ### ### my @buttons ; unless(defined $SHOWREFERENCED || ($STATUS eq "pending")) { push @buttons,("<td> </td>", &P4CGI::buttonCell(&P4CGI::cgi()->self_url . "&SHOWREFERENCED=Y", "Append description of changes mentioned in a change description", "Show related desc.")) ; } push @buttons,"<td> </td>" ; if($STATUS eq "pending") { &P4CGI::cgi()->delete("STATUS") ; push @buttons, &P4CGI::buttonCell(&P4CGI::cgi()->url(-relative => 1, -query => 1), "Show submitted changes", "Show submitted") ; &P4CGI::cgi()->param("STATUS","pending") ; } else { &P4CGI::cgi()->param("STATUS","pending") ; push @buttons, &P4CGI::buttonCell(&P4CGI::cgi()->url(-relative => 1, -query => 1), "Show pending changes", "Show pending") ; &P4CGI::cgi()->delete("STATUS") ; } ; push @buttons,&P4CGI::buttonCell("searchPattern.cgi", "Search for submitted changes", "FSPC=$filespec", "Find changes") ; ### ### ### Get changes ### ### ### my %changes ; my $cchange = "0" ; my $oldestSafeCh = 0 ; # The last change in %changes that is "safe" (after this change changes # may be missing) my $gotAll="No" ; # Set to "Yes" if there are no more changes to display my %magicLinks ; my @filespecdata ; if(@FSPC) { push @filespecdata, "FSPC=".join(" ",@FSPC) ; } ; my %existingClients = &P4CGI::p4clients() ; my %existingUsers = &P4CGI::p4users() ; ### ### If "pending" get all pending changes ### if($STATUS eq "pending") { # Pending. All file and label specifications ignored... $title = "Pending changes" ; my $choffstr = "" ; my %chs ; getChanges(-status => "pending", -long => 1, -resultto => \%chs) ; my $ch ; foreach $ch (sort { $b <=> $a } keys %chs) { my ($date,$user,$client,$desc) = @{$chs{$ch}} ; my $dispUser = $user ; my $dispClient = $client ; if(length($dispUser)>25) { $dispUser =~ s/(.{23}).*/$1\.\.\./ ; } if(length($dispClient)>25) { $dispClient =~ s/(.{23}).*/$1\.\.\./ ; } $changes{$ch} = # "<tr><td colspan=5><hr class=\"Delimiter\"></td></tr>\n". "<tr>\n". " <td class=\"ListHeadColumn\" rowspan=\"1\"> ". &P4CGI::ahref("-url" => "changeView.cgi", %extraUrlOptions, "CH=$ch", @filespecdata, "HELP=View change", "$ch") . "</td>\n" ; $changes{$ch} .= " <td class=\"List\">$date</td>\n" ; if(exists $existingUsers{$user}) { $changes{$ch} .= " <td class=\"List\">". &P4CGI::ahref("-url" => "userView.cgi", "USER=$user", "HELP=View user info", $user) . "</td>\n" ; } else { $changes{$ch} .= " <td class=\"List\">$user</td>\n" ; } ; if(exists $existingClients{$client}) { $changes{$ch} .= " <td class=\"List\">". &P4CGI::ahref("-url" => "clientView.cgi", "CLIENT=$client", "HELP=View client info", $client) . "</td>\n" ; } else { $changes{$ch} .= " <td class=\"List\">$client</td>\n" ; } ; $changes{$ch} .= " <td></td>\n" . "</tr>\n" . "<tr><td></td>\n" . " <td class=\"Description\" colspan=4>". $desc . "</td>\n</tr>\n" ; } } ### ### If not "pending" get all changes ### else { my $max = $MAXCH ; # max ## ## Create subroutines for selection ## my @selectFuncs ; # Variable to hold subroutines if(defined $SEARCHDESC) { # Search description $max = (1+$max)*10 ; my $s = "($SEARCHDESC)" ; # $s =~ s/\s*\+\s*/|/g ; $s =~ s/\./\\\./g ; $s =~ s/\*/.\*/g ; $s =~ s/\?/./g ; $s =~ s/\s+/((\\s+)|(\n))+/g ; my $sq = $s ; $sq =~ s/\n/\\n/g ; &P4CGI::ERRLOG("select: ".$sq) ; if(defined $SEARCH_INVERT) { push @selectFuncs , sub { my ($ch,$date,$user,$client,$desc) = @_ ; return $$desc !~ /$s/gi ; } ; } else { push @selectFuncs , sub { my ($ch,$date,$user,$client,$desc) = @_ ; return $$desc =~ s/$s/$MAGIC_RED$1$MAGIC_RED/gi ; } ; } } ; if(defined $GROUP) { # Group(s) specified my @grps = split(',',$GROUP) ; while(@grps) { my $grp = shift @grps ; &P4CGI::ERRLOG("group: $grp") ; my %data ; &P4CGI::p4readform("group -o '$grp'",\%data) ; if(exists $data{"Subgroups"}) { push @grps,split("\n",$data{"Subgroups"}) ; } my $u ; foreach $u (split("\n",$data{"Users"})) { if(defined $USER) { $USER .= ",$u"; } else { $USER = "$u" ; } } } } my $onlyUser ; if(defined $USER) { # User(s) specified my %users ; my $usersToCheck = 0 ; foreach (split(',',$USER)) { $users{$_} = 1 ; $usersToCheck++ ; } &P4CGI::ERRLOG("users: ".join(",",(keys %users))." to check:".$usersToCheck) ; push @selectFuncs , sub { my ($ch,$date,$user,$client,$desc) = @_ ; return exists $users{$user} ; } ; $onlyUser = $USER if $usersToCheck == 1 ; my %users = &P4CGI::p4users() ; my @users = keys %users ; $max *= 3+int(@users/(5*$usersToCheck)) ; } ; my $onlyClient ; if(defined $CLIENT) { # Client specified my %clients ; my $clientsToCheck = 0 ; foreach (split(',',$CLIENT)) { $clients{$_} = 1 ; $clientsToCheck++ ; } &P4CGI::ERRLOG("client: $CLIENT") ; push @selectFuncs , sub { my ($ch,$date,$user,$client,$desc) = @_ ; return exists $clients{$client} ; } ; $onlyClient = $CLIENT if $clientsToCheck == 1 ; my %clients = &P4CGI::p4clients() ; my @clients = keys %clients ; $max *= 3+int(@clients/(5*$clientsToCheck)) ; } ; if((keys %excludeChanges) > 0) { # Exclude changes from a list push @selectFuncs , sub { my ($ch,$date,$user,$client,$desc) = @_ ; return ! exists $excludeChanges{$ch} ; } ; } ## ## Create a select subroutine for selection functions defined (if any) ## my $selectFunc ; if(@selectFuncs > 0) { $selectFunc = sub { my @params = @_ ; foreach (@selectFuncs) { return undef unless &$_(@params) ; } return 1 ; } } ## ## Set max changes to return for each search ## $max = 200 if $max < 200 ; # There is no point searching less than 200 at the time. # For a fast LAN this can be increased to 2000 my %chLevel ; # Store how far back we have traced by file spec my %ended ; # Set to true for a file spec where we have hit the end # HINT: We can merge changes from more than one file spec my $noFSPCsNotEnded = 0 ; # Store number of file speces that has not ended (so we know # when there is no point to keep trying) ## ## Initialize variable above ## my $firstch = &P4CGI::CURRENT_CHANGE_LEVEL() ; # First change we are interested in $firstch = $FIRSTCH if defined $FIRSTCH ; # Set if parameter FIRSTCH given my $fspc ; foreach $fspc (@FSPC) { $chLevel{$fspc} = $firstch ; # Set level to current for all filespec's $ended{$fspc} = 0 ; # Not ready with flespec yet... $noFSPCsNotEnded++ ; # Increment filespecs not ready } my %chs ; # result hash while(1) { # Loop until ready ## ## Loop over each file spec ## $oldestSafeCh = 0 ; my $filespec ; foreach $filespec (@FSPC) { # for each filespec..... next if $ended{$filespec} ; # Skip if all changes read for file spec my $lastIncludedCh ; # Store last change included in selection # # Set up parameters for getChanges() # my %params = (-file => $filespec , -resultto => \%chs, -long => 1, -maxch => $max+1, -select => $selectFunc, -lastch => \$chLevel{$filespec}, -lastrch => \$lastIncludedCh, -firstch => $chLevel{$filespec}, -magiclinked => \%magicLinks ) ; if($serverY >= 2001 and $serverN >= 2) { $params{"-user"} = $onlyUser if defined $onlyUser ; $params{"-client"} = $onlyClient if defined $onlyClient ; } ; if(defined $LABEL) { $params{"-label"} = $LABEL ; } # # Call getChanges # my $gotCh = getChanges(%params) ; # # Evaluate returned data # if($gotCh != ($max+1)) { # Did we get all changes we asked for? If no.... $ended{$filespec} = 1 ; # ... there is no more data for this file spec $noFSPCsNotEnded-- ; &P4CGI::ERRLOG("file spec \"$filespec\" ended") ; } else { if($lastIncludedCh > $oldestSafeCh) { # Update oldes safe ch. $oldestSafeCh = $lastIncludedCh ; } } } # End loop over each filespec if($noFSPCsNotEnded == 0) { # Did we get all changes there are for the filespecs? # No more changes for these filespecs $gotAll = "Yes" ; last ; } # Count number of changes that we can "trust" (for more than # one file spec we reach different number of changes back in time) my $okchs = 0 ; my $c ; foreach $c (keys %chs) { $okchs++ if $c >= $oldestSafeCh ; } &P4CGI::ERRLOG("okchs: $okchs, max: $max") ; last if $okchs >= $MAXCH ; # Did we get enough changes... } ## ## Build data for changes to display ## my $changesDisplayed=0 ; my $ch ; my @sorted = sort { $b <=> $a } keys %chs ; while($ch = shift(@sorted)) { if((exists $changes{$ch}) or (defined $FIRSTCH and ($ch > $FIRSTCH))) { &P4CGI::ERRLOG("skip ch $ch") ; } else { my ($date,$user,$client,$desc) = @{$chs{$ch}} ; my $dispUser = $user ; my $dispClient = $client ; if(length($dispUser)>25) { $dispUser =~ s/(.{23}).*/$1\.\.\./ ; } if(length($dispClient)>25) { $dispClient =~ s/(.{23}).*/$1\.\.\./ ; } $changes{$ch} = # "<tr><td colspan=5><hr class=\"Delimiter\"></td></tr>\n". "<tr>\n". " <td class=\"ListHeadColumn\" rowspan=\"1\"> ". &P4CGI::ahref("-url" => "changeView.cgi", %extraUrlOptions, "CH=$ch", @filespecdata, "HELP=View change $ch", "$ch:") . "</td>\n" ; $changes{$ch} .= " <td class=\"List\">$date</td>\n" ; if(exists $existingUsers{$user}) { $changes{$ch} .= " <td class=\"List\">". &P4CGI::ahref("-url" => "userView.cgi", "USER=$user", "HELP=View user $user", $dispUser) . "</td>\n" ; } else { $changes{$ch} .= " <td class=\"List\">$user</td>\n" ; } ; if(exists $existingClients{$client}) { $changes{$ch} .= " <td class=\"List\">". &P4CGI::ahref("-url" => "clientView.cgi", "CLIENT=$client", "HELP=View client $client", $dispClient) . "</td>\n" ; } else { $changes{$ch} .= " <td class=\"List\">$dispClient</td>\n" ; } ; $changes{$ch} .= " <td></td>\n" . "</tr>\n" . "<tr><td></td>\n" . " <td class=\"Description\" colspan=4>$desc</td>\n</tr>\n" ; $changesDisplayed++ ; if(defined $SHOWREFERENCED and exists $magicLinks{$ch}) { my $refch = "" ; my $n = 0 ; my $c ; foreach $c (@{$magicLinks{$ch}}) { my %data ; &P4CGI::p4readform("change -o '$c'",\%data) ; if(exists $data{"Description"}) { $n++ ; my $d =&P4CGI::formatDescription($data{"Description"}); $c = &P4CGI::ahref("-url" => "changeView.cgi", %extraUrlOptions, "CH=$c", @filespecdata, "HELP=View change $c", "$c") ; $refch .= " <td class=\"List\">$c:</td>\n" . " <td class=\"Description\">$d</td>\n" . " </tr>\n" ; } } if($n > 0) { $changes{$ch} .= "<tr>\n" . " <td></td>\n" . " <td colspan=4>\n". " <table class=\"SubChange\">\n". ## FIX! " <tr>\n". "$refch" . " </table>\n". "</tr>\n" ; } } } if($changesDisplayed == $MAXCH) { if(@sorted > 0) { $gotAll = "No" ; } last ; } } } ; ### ### ### Start print ### ### ### print &P4CGI::start_page($title,@buttons) ; my $debug_size = scalar keys %changes ; &P4CGI::ERRLOG("$debug_size changes to display") ; my $ch ; my $maxch = $MAXCH ; my $lastch = 1 ; #my $skipped = 0 ; { my $chs = keys %changes ; if($chs >= $maxch) { if(defined $CHOFFSET and $CHOFFSET > 0) { $chs = "$maxch next" ; } else { $chs = "$maxch most recent" ; } } my $changes = "changes" ; #$changes = "change" if $chs == 1 ; print &P4CGI::start_framedTable("$chs $changes:") ; } ; print "<table class=\"ListX\">\n" ; print P4CGI::table_header("#", "Date and time", "User", "Client") ; foreach $ch (sort { $b <=> $a } keys %changes) { last if ($maxch == 0) ; if($ch < $oldestSafeCh) { # Can not happend??? &P4CGI::ERRLOG("ch:$ch oldestSafeCh:$oldestSafeCh") ; # DEBUG $maxch = 0 ; last ; } ; $maxch-- ; $lastch=$ch-1 ; $CHOFFSET++ ; if(defined $EXLABEL and $ch < $lastChangeInLabel) { print "<tr>" , " <td colspan=5>" , " <table width=90% align=center cols=3>\n" , " <tr>\n" , " <th><hr>Last change in Label $EXLABEL is $lastChangeInLabel<hr>", " </th>" , " </tr>" , " </table>", "</tr>\n" ; $lastChangeInLabel = 0 ; } print $changes{$ch} ; } print "</table>\n" ; print &P4CGI::end_framedTable() ; &P4CGI::ERRLOG("gotAll:$gotAll maxch:$maxch") ; if(($maxch == 0) and ($gotAll ne "Yes")) { my @params = ("STATUS=$STATUS", "FIRSTCH=$lastch", "CHOFFSETDISP=$CHOFFSET", "MAXCH=$MAXCH") ; if(defined $EXLABEL) { push @params,"EXLABEL=$EXLABEL" ; } ; if(defined $LABEL) { push @params,"LABEL=$LABEL" ; } ; if(defined $USER) { push @params,"USER=$USER" ; } ; if(defined $GROUP) { push @params,"GROUP=$GROUP" ; } ; if(defined $SEARCHDESC) { push @params,"SEARCHDESC=$SEARCHDESC" ; } ; if(defined $SEARCH_INVERT) { push @params,"SEARCH_INVERT=1" ; } ; if(defined $SHOWREFERENCED) { push @params,"SHOWREFERENCED=$SHOWREFERENCED" ; } ; if($FSPC_WasSpecified) { push @params,"FSPC=".P4CGI::cgi()->param("FSPC") ; } print &P4CGI::buttonHMenuTable(&P4CGI::buttonCell("changeList.cgi", "Show next set of changes", @params, "More....")) ; } print "",&P4CGI::end_page(); # # That's all folks #
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#11 | 4998 | Fredric Fredricson |
P4DB: cleaned up some code. Added p4users(), p4client() and p4user2name() to P4CGI.pm and modified all cgi:s to use these, |
||
#10 | 4988 | Fredric Fredricson |
P4DB: Fixed (I think) bug in change list. The bug sometimes caused an enless loop when changes in a label with changes in another label excluded. |
||
#9 | 4306 | Fredric Fredricson |
P4DB: Hardened P4DB against malicious parameters (cross site scripting), performed some cleanup and increased version to 3.1.1. |
||
#8 | 4237 | Fredric Fredricson | P4DB: Maybe the final submit for P4DB 3.1.0 | ||
#7 | 4216 | Fredric Fredricson | P4DB: Another partial submit on my way to P4DB 3.1... | ||
#6 | 4152 | Fredric Fredricson | P4DB: Some more work on tha way to version 3.1.... | ||
#5 | 4046 | Fredric Fredricson |
P4DB: First submit for 3.1. * Removed frame-stuff and some related files * Added new page header * Started update of documentation * Changed a lot of CGI:s to conform to new "look and feel" Still a lot to do: - clean up stuff (especially the javascript) - Fix the file list to use new annotate-command - Clean up and document css-file - and more....... |
||
#4 | 2942 | Fredric Fredricson | P4DB: Fixed bug: Can now handle spaces in label names etc.... | ||
#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 |