#!/usr/bonsaitools/bin/perl -- # -*- Mode: perl; indent-tabs-mode: nil -*- # # The contents of this file are subject to the Netscape Public License # Version 1.0 (the "License"); you may not use this file except in # compliance with the License. You may obtain a copy of the License at # http://www.mozilla.org/NPL/ # # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the # License for the specific language governing rights and limitations # under the License. # # The Original Code is the Bonsai CVS tool. # # The Initial Developer of the Original Code is Netscape Communications # Corporation. Portions created by Netscape are Copyright (C) 1998 # Netscape Communications Corporation. All Rights Reserved. require 'lloydcgi.pl'; require 'utils.pl'; use Date::Parse; loadConfigData(); $CVS_ROOT = $form{"cvsroot"}; require 'timelocal.pl'; require 'cvsquery.pl'; $| = 1; $sm_font_tag = ""; my $generateBackoutCVSCommands = 0; if (defined $form{'generateBackoutCVSCommands'}) { $generateBackoutCVSCommands = 1; } if (!$generateBackoutCVSCommands) { print "Content-type: text/html "; $script_str=''; &setup_script; print "$script_str"; } #print "
";


$CVS_REPOS_SUFIX = $CVS_ROOT;
$CVS_REPOS_SUFIX =~ s/\//_/g;

$CHECKIN_DATA_FILE = "data/checkinlog${CVS_REPOS_SUFIX}";
$CHECKIN_INDEX_FILE = "data/index${CVS_REPOS_SUFIX}";


$SORT_HEAD="bgcolor=\"#DDDDDD\"";

#
# Log the query
open( LOG, ">>data/querylog.txt");
$t = time;
print LOG "$ENV{'REMOTE_ADDR'} $t $ENV{'QUERY_STRING'}\n";
close(LOG);

#
# build a module map
#
$query_module = $form{'module'};

#
# allow ?file=/a/b/c/foo.c to be synonymous with ?dir=/a/b/c&file=foo.c
#
if ( $form{'dir'} eq '' ) {
    if ($form{'file'} =~ m@(.*?/)([^/]*)$@) {
        $form{'dir'} = $1;
        $form{'file'} = $2;
    }
}

#
# build a directory map
#
@query_dirs = split(/[;, \t]+/, $form{'dir'});

$query_file = $form{'file'};
$query_filetype = $form{'filetype'};
$query_logexpr = $form{'logexpr'};

#
# date
#
$query_date_type = $form{'date'};
if( $query_date_type eq 'hours' ){
    $query_date_min = time - $form{'hours'}*60*60;
} 
elsif( $query_date_type eq 'day' ){
    $query_date_min = time - 24*60*60;
}
elsif( $query_date_type eq 'week' ){
    $query_date_min = time - 7*24*60*60;
}
elsif( $query_date_type eq 'month' ){
    $query_date_min = time - 30*24*60*60;
}
elsif( $query_date_type eq 'all' ){
    $query_date_min = 0;
}
elsif( $query_date_type eq 'explicit' ){
    if ($form{'mindate'} ne "") {
        $query_date_min = parse_date($form{'mindate'});
    }

    if ($form{'maxdate'} ne "") {
        $query_date_max = parse_date($form{'maxdate'});
    }
}
else {
    $query_date_min = time-60*60*2;
}

#
# who
#
$query_who = $form{'who'};
$query_whotype = $form{'whotype'};


$show_raw = $form{'raw'} ne '';

#
# branch
#
$query_branch = $form{'branch'};
$query_branchtype = $form{'branchtype'};


#
# tags
#
$query_begin_tag = $form{'begin_tag'};
$query_end_tag = $form{'end_tag'};


#
# Get the query in english and print it.
#
$t = $e = &query_to_english;
$t =~ s/<[^>]*>//g;

$query_debug = $form{'debug'};

$result= &query_checkins( $mod_map );

for $i (@{$result}) {
    $w{"$i->[$CI_WHO]\@netscape.com"} = 1;
}

@p = sort keys %w;
$pCount = @p;
$s = join(",%20", @p);

$e =~ s/Checkins in/In/;

my $menu = "

$e

Modify Query
Mail everyone on this page ($pCount people)
I want to back out these changes "; if (defined $form{'generateBackoutCVSCommands'}) { print "Content-type: text/plain # This page can be saved as a shell script and executed. It should be # run at the top of your CVS work area. It will update your workarea to # backout the changes selected by your query. "; foreach my $ci (@{$result}) { if ($ci->[$CI_REV] eq "") { print "echo 'Changes made to $ci->[$CI_DIR]/$ci->[$CI_FILE] need to be backed out by hand'\n"; next; } my $prev_revision = PrevRev($ci->[$CI_REV]); print "cvs update -j$ci->[$CI_REV] -j$prev_revision $ci->[$CI_DIR]/$ci->[$CI_FILE]\n"; } exit; } EmitHtmlTitleAndHeader($t, "CVS Checkins", "$menu"); # # Test code to print the results # $|=1; if( !$show_raw ) { if( $form{"sortby"} eq "Who" ){ $result = [sort { $a->[$CI_WHO] cmp $b->[$CI_WHO] || $b->[$CI_DATE] <=> $a->[$CI_DATE] } @{$result}] ; $head_who = $SORT_HEAD; } elsif( $form{"sortby"} eq "File" ){ $result = [sort { $a->[$CI_FILE] cmp $b->[$CI_FILE] || $b->[$CI_DATE] <=> $a->[$CI_DATE] || $a->[$CI_DIRECTORY] cmp $b->[$CI_DIRECTORY] } @{$result}] ; $head_file = $SORT_HEAD; } elsif( $form{"sortby"} eq "Directory" ){ $result = [sort { $a->[$CI_DIRECTORY] cmp $b->[$CI_DIRECTORY] || $a->[$CI_FILE] cmp $b->[$CI_FILE] || $b->[$CI_DATE] <=> $a->[$CI_DATE] } @{$result}] ; $head_directory = $SORT_HEAD; } elsif( $form{"sortby"} eq "Change Size" ){ $result = [sort { ($b->[$CI_LINES_ADDED]- $b->[$CI_LINES_REMOVED]) <=> ($a->[$CI_LINES_ADDED]- $a->[$CI_LINES_REMOVED]) #|| $b->[$CI_DATE] <=> $a->[$CI_DATE] } @{$result}] ; $head_delta = $SORT_HEAD; } else{ $result = [sort {$b->[$CI_DATE] <=> $a->[$CI_DATE]} @{$result}] ; $head_date = $SORT_HEAD; } &print_result($result); } else { print "

";
    for $ci (@$result) {
        $ci->[$CI_LOG] = '';
        $s = join("|",@$ci);
        print "$s\n";
    }
}


#
# code to debug the modules_map
#
#print "
\n";
#while( ($k,$v) = each(%{$mod_map})) {
#    print "$k=$v\n";
#}

#
#
#
sub print_tcl {
    local($result) = @_;
    local($t, $count,$first,$i, $k, $files);

    $t = time;
    print TCLOUT "set treeopen 0\n" .
                 "set lastgoodtimestamp $t\n" .
                 "set closetimestamp $t\n";
    $count = 0;
    $first = 0;
    $i = 1;


    $max = @{$result}+1;

    while( $i < $max ){
        $c1 = $result->[$first];
        $c2 = $result->[$i];
        if( $i == $max-1
                || $c1->[$CI_DATE] != $c2->[$CI_DATE]
                || $c1->[$CI_DIR] ne $c2->[$CI_DIR]
                || $c1->[$CI_WHO] ne $c2->[$CI_WHO]
        ) {
            $files = '{';
            $fu = '{';
            $k = $first;
            while( $k < $i ){
                $files .= $result->[$k][$CI_FILE] . " ";
                $fu .= &make_fullinfo( $result->[$k] );
                $k++;
            }
            $files .= '}';
            $fu .= '}';
            print TCLOUT "set ci-${count}(date) $c1->[$CI_DATE]\n" .
                      "set ci-${count}(dir) $c1->[$CI_DIR]\n" .
                      "set ci-${count}(person) $c1->[$CI_WHO]\n" .
                      "set ci-${count}(files) $files\n" .
                      "set ci-${count}(fullinfo) $fu\n" .
                      "set ci-${count}(log) \{$c1->[$CI_LOG]\}\n" .
                      "set ci-${count}(treeopen) 1\n";
            $count++;
            $first = $i;
        }
        $i++;
    }
}

sub make_fullinfo{
    local( $ci ) = @_;
    local( $s );

    $a = &tcl_value( $ci->[$CI_FILE] );
    $b = &tcl_value( $ci->[$CI_REV] );
    $c = &tcl_value( $ci->[$CI_LINES_ADDED] );
    $d = &tcl_value( $ci->[$CI_LINES_REMOVED] );
    $e = &tcl_value( $ci->[$CI_STICKY] );

    return "{$a $b $c $d $e}";
}

sub tcl_value {
    local( $a ) = @_;

    if( $a eq '' ){
        return '{}';
    }
    else {
        return $a;
    }
}

#
#
#
sub print_result {
    local($result) = @_;
    local($ci,$i,$k,$j,$max, $l, $span);

    &print_head;

    $i = 20;
    $k = 0;
    $max = @{$result};

    while( $k < $max ){
        $ci = $result->[$k];
        $span = 1;
        if( ($l = $ci->[$CI_LOG]) ne '' ){
            # 
            # Calculate the number of consequitive logs that are 
            #  the same and nuke them
            #
            $j = $k+1;
            while( $j < $max && $result->[$j]->[$CI_LOG] eq $l ){
                $result->[$j]->[$CI_LOG] = '';
                $j++;
            }

            # 
            # Make sure we don't break over a description block
            #
            $span = $j-$k;
            if( $span-1 > $i ){
                $i = $j-$k;
            }
        }

        &print_ci( $ci, $span );
        

        if( $i <= 0 ){
            $i = 20;
            print "\n";
        }
        else {
            $i--;
        }
        $k++;
    }

    &print_foot;
}

sub print_ci {
    local($ci, $span) = @_;
    local($sec,$minute,$hour,$mday,$mon,$year,$t);
    local($log);
    
    ($sec,$minute,$hour,$mday,$mon,$year) = localtime( $ci->[$CI_DATE] );
    $t = sprintf("%02d/%02d/%02d %02d:%02d",$mon+1,$mday,$year,$hour,$minute);

    $log = &html_log($ci->[$CI_LOG]);
    $rev = $ci->[$CI_REV];

    print "\n";

    print "\n";
}

sub print_head {

if ($versioninfo ne "") {
    print "";
    print "";
    print "";
    print "";
    print "";
    print "(+$lines_added/$lines_removed) Lines changed.";
}

$anchor = $ENV{QUERY_STRING};
$anchor =~ s/\&sortby\=[A-Za-z\ \+]*//g;
$anchor = "

";
}


sub print_foot {
    print "
${sm_font_tag}$t"; print "[$CI_WHO]','',event);\" >" . "$ci->[$CI_WHO]\n"; print "[$CI_DIR]','$ci->[$CI_FILE]','$ci->[$CI_REV]','$query_branch',event)\">\n"; # if( (length $ci->[$CI_FILE]) + (length $ci->[$CI_DIR]) > 30 ){ # $d = $ci->[$CI_DIR]; # if( (length $ci->[$CI_DIR]) > 30 ){ # $d =~ s/([^\n]*\/)(classes\/)/$1classes\/
  /; # # Insert a
before any directory named # # 'classes.' # } # print " $d/
  $ci->[$CI_FILE]
\n"; # } # else{ # print " $ci->[$CI_DIR]/$ci->[$CI_FILE]\n"; # } $d = "$ci->[$CI_DIR]/$ci->[$CI_FILE]"; if( $query_module eq 'allrepositories' ){ $d = "$ci->[$CI_REPOSITORY]/$d"; } $d =~ s:/:/ :g; # Insert a whitespace after any slash, so that # we'll break long names at a reasonable place. print "$d\n"; if( $rev ne '' ){ $prevrev = &PrevRev( $rev ); print "
${sm_font_tag}$rev\n"; } else { print "\ \n"; } if( !$query_branch_head ){ print "$ci->[$CI_BRANCH] \n"; } print "${sm_font_tag}$ci->[$CI_LINES_ADDED]/$ci->[$CI_LINES_REMOVED] \n"; if( $log ne '' ){ eval ('$log =~ s@\d{4,6}@' . $BUGSYSTEMEXPR . '@g;'); $log =~ s/([ #\t])([0-9][0-9][0-9][0-9][0-9])([^0-9])/$1$2<\/a>$3/g; # Makes numbers into links to bugsplat. $log =~ s/\n/
/g; # Makes newlines into
's if( $span > 1 ){ print "
$log\n"; } else { print "$log\n"; } } print "
$anchor>When ${anchor}&sortby=Who>Who ${anchor}&sortby=File>File Rev "; $descwidth = 47; if( !$query_branch_head ){ print "Branch\n"; $descwidth -= 2; } print " ${anchor}&sortby=Change+Size>+/- Description
"; print "

"; } sub html_log { local( $log ) = @_; $log =~ s/&/&/g; $log =~ s/ 7000000) { return $d; } return 0; } sub setup_script { $script_str =<<'ENDJS'; ENDJS } # # Actually do the query # sub query_to_english { my $english = 'Checkins '; if( $query_module eq 'allrepositories' ){ $english .= "to All Repositories "; } elsif( $query_module ne 'all' && @query_dirs == 0 ){ $english .= "to module $query_module "; } elsif( $form{dir} ne "" ) { my $word = "directory"; if (@query_dirs > 1) { $word = "directories"; } $english .= "to $word $form{dir} "; } if ($query_file ne "") { if ($english ne 'Checkins ') { $english .= "and "; } $english .= "to file $query_file "; } if( ! ($query_branch =~ /^[ ]*HEAD[ ]*$/i) ){ if($query_branch eq '' ){ $english .= "on all branches "; } else { $english .= "on branch $query_branch "; } } if( $query_who ne '' ){ $english .= "by $query_who "; } $query_date_type = $form{'date'}; if( $query_date_type eq 'hours' ){ $english .="in the last $form{hours} hours"; } elsif( $query_date_type eq 'day' ){ $english .="in the last day"; } elsif( $query_date_type eq 'week' ){ $english .="in the last week"; } elsif( $query_date_type eq 'month' ){ $english .="in the last month"; } elsif( $query_date_type eq 'all' ){ $english .="since the beginning of time"; } elsif( $query_date_type eq 'explicit' ){ if ( $form{mindate} ne "" && $form{maxdate} ne "" ) { $w1 = "between"; $w2 = "and" ; } else { $w1 = "since"; $w2 = "before"; } if( $form{'mindate'} ne "" ){ $dd = &parse_date($form{'mindate'}); ($sec,$minute,$hour,$mday,$mon,$year) = localtime( $dd ); $t = sprintf("%02d/%02d/%02d %02d:%02d",$mon+1,$mday,$year,$hour,$minute); $english .= "$w1 $t "; } if( $form{'maxdate'} ne "" ){ $dd = &parse_date($form{'maxdate'}); ($sec,$minute,$hour,$mday,$mon,$year) = localtime( $dd ); $t = sprintf("%02d/%02d/%02d %02d:%02d",$mon+1,$mday,$year,$hour,$minute); $english .= "$w2 $t "; } } return $english . ":"; }