#!/usr/bonsaitools/bin/perl -w # -*- 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. use diagnostics; use strict; # Shut up misguided -w warnings about "used only once". "use vars" just # doesn't work for me. sub sillyness { my $zz; $zz = $::CI_BRANCH; $zz = $::CI_REPOSITORY; $zz = $::lines_added; $zz = $::lines_removed; $zz = $::query_begin_tag; $zz = $::query_branchtype; $zz = $::query_date_max; $zz = $::query_debug; $zz = $::query_end_tag; $zz = $::query_filetype; $zz = $::query_logexpr; $zz = $::query_whotype; } require 'CGI.pl'; require 'cvsquery.pl'; $::CVS_ROOT = $::FORM{'cvsroot'}; $::CVS_ROOT = pickDefaultRepository() unless $::CVS_ROOT; $::TreeID = $::FORM{'module'} if (!exists($::FORM{'treeid'}) && exists($::FORM{'module'}) && exists($::TreeInfo{$::FORM{'module'}}{'repository'})); $::TreeID = 'default' if (!exists($::TreeInfo{$::TreeID}{'repository'}) || exists($::TreeInfo{$::TreeID}{'nobonsai'})); LoadTreeConfig(); my $userdomain = Param('userdomain'); $| = 1; my $sm_font_tag = ""; my $generateBackoutCVSCommands = 0; if (defined $::FORM{'generateBackoutCVSCommands'}) { $generateBackoutCVSCommands = 1; } if (!$generateBackoutCVSCommands) { print "Content-type: text/html "; print setup_script(); } #print "
";


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

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


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

#
# Log the query
Log("Query [$ENV{'REMOTE_ADDR'}]: $ENV{'QUERY_STRING'}");

#
# 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
#
$::FORM{'file'} = "" unless defined $::FORM{'file'};
unless ($::FORM{'dir'}) {
    $::FORM{'file'} = Fix_BonsaiLink($::FORM{'file'});
    if ($::FORM{'file'} =~ m@(.*?/)([^/]*)$@) {
        $::FORM{'dir'} = $1;
        $::FORM{'file'} = $2;
    } else {
        $::FORM{'dir'} = "";
    }
}

#
# 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'}) {
        $::query_date_min = parse_date($::FORM{'mindate'});
    }

    if ($::FORM{'maxdate'}) {
        $::query_date_max = parse_date($::FORM{'maxdate'});
    }
}
else {
    $::query_date_min = time-60*60*2;
}

#
# who
#
$::query_who = $::FORM{'who'};
$::query_whotype = $::FORM{'whotype'};


my $show_raw = 0;
if ($::FORM{'raw'}) {
    $show_raw = 1;
}

#
# branch
#
$::query_branch = $::FORM{'branch'};
if (!defined $::query_branch) {
    $::query_branch = 'HEAD';
}
$::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.
#
my ($t, $e);
$t = $e = &query_to_english;
$t =~ s/<[^>]*>//g;

$::query_debug = $::FORM{'debug'};

my %mod_map = ();
my $result= &query_checkins( %mod_map );

my %w;

for my $i (@{$result}) {
    $w{"$i->[$::CI_WHO]\@$userdomain"} = 1;
}

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

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

my $menu = "

$e

Modify Query
Mail everyone on this page ($pCount people)
Show commands which could be used 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; } PutsHeader($t, "CVS Checkins", "$menu"); # # Test code to print the results # $|=1; my $head_who = ''; my $head_file = ''; my $head_directory = ''; my $head_delta = ''; my $head_date = ''; if( !$show_raw ) { $::FORM{"sortby"} ||= ""; 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 my $ci (@$result) {
        $ci->[$::CI_LOG] = '';
        $s = join("|",@$ci);
        print "$s\n";
    }
}

#
#
#
sub print_result {
    my ($result) = @_;
    my ($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;
}

my $descwidth;

sub print_ci {
    my ($ci, $span) = @_;

    my ($sec,$minute,$hour,$mday,$mon,$year) = localtime( $ci->[$::CI_DATE] );
    my $t = sprintf("%02d/%02d/%04d %02d:%02d",$mon+1,$mday,$year+1900,$hour,$minute);

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

    print "\n";
    print "\n";
}

sub print_head {

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

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


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"; # } my $d = "$ci->[$::CI_DIR]/$ci->[$::CI_FILE]"; if (defined $::query_module && $::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 '' ){ my $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 '' ){ $log = MarkUpText($log); # 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\n"; print "${anchor}&sortby=Who>Who\n"; print "${anchor}&sortby=File>File\n"; print "Rev\n"; $descwidth = 47; if( !$::query_branch_head ){ print "Branch\n"; $descwidth -= 2; } print "${anchor}&sortby=Change+Size>+/-\n"; print "Description\n"; print "
"; print "

"; } sub html_log { my ( $log ) = @_; $log =~ s/&/&/g; $log =~ s/ 7000000) { return $d; } return 0; } sub setup_script { my $script_str =<<'ENDJS'; ENDJS return $script_str; } # # Actually do the query # sub query_to_english { my $english = 'Checkins '; $::query_module = 'all' unless defined $::query_module; 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) { $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' ){ my ($w1, $w2); if ( $::FORM{mindate} && $::FORM{maxdate}) { $w1 = "between"; $w2 = "and" ; } else { $w1 = "since"; $w2 = "before"; } if( $::FORM{'mindate'}){ my $dd = &parse_date($::FORM{'mindate'}); my ($sec,$minute,$hour,$mday,$mon,$year) = localtime( $dd ); my $t = sprintf("%02d/%02d/%04d %02d:%02d",$mon+1,$mday,$year+1900,$hour,$minute); $english .= "$w1 $t "; } if( $::FORM{'maxdate'}){ my $dd = &parse_date($::FORM{'maxdate'}); my ($sec,$minute,$hour,$mday,$mon,$year) = localtime( $dd ); my $t = sprintf("%02d/%02d/%04d %02d:%02d",$mon+1,$mday,$year+1900,$hour,$minute); $english .= "$w2 $t "; } } return $english . ":"; } PutsTrailer();