New upstream version.
committer: mfx <mfx> 1052654076 +0000
This commit is contained in:
+286
-37
@@ -9,8 +9,8 @@ exec perl -w -x $0 ${1+"$@"} # -*- mode: perl; perl-indent-level: 2; -*-
|
|||||||
### ###
|
### ###
|
||||||
##############################################################
|
##############################################################
|
||||||
|
|
||||||
## $Revision: 2.47 $
|
## $Revision: 2.48 $
|
||||||
## $Date: 2003/03/10 16:08:30 $
|
## $Date: 2003/04/21 09:50:52 $
|
||||||
## $Author: fluffy $
|
## $Author: fluffy $
|
||||||
##
|
##
|
||||||
## (C) 2001,2002,2003 Martyn J. Pearce <fluffy@cpan.org>, under the GNU GPL.
|
## (C) 2001,2002,2003 Martyn J. Pearce <fluffy@cpan.org>, under the GNU GPL.
|
||||||
@@ -38,7 +38,7 @@ exec perl -w -x $0 ${1+"$@"} # -*- mode: perl; perl-indent-level: 2; -*-
|
|||||||
use strict;
|
use strict;
|
||||||
use Text::Wrap;
|
use Text::Wrap;
|
||||||
use Time::Local;
|
use Time::Local;
|
||||||
use File::Basename;
|
use File::Basename qw( fileparse );
|
||||||
use User::pwent;
|
use User::pwent;
|
||||||
|
|
||||||
|
|
||||||
@@ -76,11 +76,13 @@ use User::pwent;
|
|||||||
|
|
||||||
############### Globals ################
|
############### Globals ################
|
||||||
|
|
||||||
|
use constant MAILNAME => "/etc/mailname";
|
||||||
|
|
||||||
# What we run to generate it:
|
# What we run to generate it:
|
||||||
my $Log_Source_Command = "cvs log";
|
my $Log_Source_Command = "cvs log";
|
||||||
|
|
||||||
# In case we have to print it out:
|
# In case we have to print it out:
|
||||||
my $VERSION = '$Revision: 2.47 $';
|
my $VERSION = '$Revision: 2.48 $';
|
||||||
$VERSION =~ s/\S+\s+(\S+)\s+\S+/$1/;
|
$VERSION =~ s/\S+\s+(\S+)\s+\S+/$1/;
|
||||||
|
|
||||||
## Vars set by options:
|
## Vars set by options:
|
||||||
@@ -104,8 +106,16 @@ my $Log_File_Name = "ChangeLog";
|
|||||||
# to that ChangeLog.
|
# to that ChangeLog.
|
||||||
my $Cumulative = 0;
|
my $Cumulative = 0;
|
||||||
|
|
||||||
|
# `cvs log -d`, this will repeat the last entry in the old log. This is OK,
|
||||||
|
# as it guarantees at least one entry in the update changelog, which means
|
||||||
|
# that there will always be a date to extract for the next update. The repeat
|
||||||
|
# entry can be removed in postprocessing, if necessary.
|
||||||
|
my $Update = 0;
|
||||||
|
|
||||||
# Expand usernames to email addresses based on a map file?
|
# Expand usernames to email addresses based on a map file?
|
||||||
my $User_Map_File = "";
|
my $User_Map_File = "";
|
||||||
|
my $User_Passwd_File;
|
||||||
|
my $Mail_Domain;
|
||||||
|
|
||||||
# Output log in chronological order? [default is reverse chronological order]
|
# Output log in chronological order? [default is reverse chronological order]
|
||||||
my $Chronological_Order = 0;
|
my $Chronological_Order = 0;
|
||||||
@@ -131,6 +141,9 @@ my %show_tags;
|
|||||||
# Don't call Text::Wrap on the body of the message
|
# Don't call Text::Wrap on the body of the message
|
||||||
my $No_Wrap = 0;
|
my $No_Wrap = 0;
|
||||||
|
|
||||||
|
# Don't do any pretty print processing
|
||||||
|
my $Summary = 0;
|
||||||
|
|
||||||
# Separates header from log message. Code assumes it is either " " or
|
# Separates header from log message. Code assumes it is either " " or
|
||||||
# "\n\n", so if there's ever an option to set it to something else,
|
# "\n\n", so if there's ever an option to set it to something else,
|
||||||
# make sure to go through all conditionals that use this var.
|
# make sure to go through all conditionals that use this var.
|
||||||
@@ -158,6 +171,9 @@ my $Show_Day_Of_Week = 0;
|
|||||||
# Show revision numbers in output?
|
# Show revision numbers in output?
|
||||||
my $Show_Revisions = 0;
|
my $Show_Revisions = 0;
|
||||||
|
|
||||||
|
# Show dead files in output?
|
||||||
|
my $Show_Dead = 0;
|
||||||
|
|
||||||
# Show tags (symbolic names) in output?
|
# Show tags (symbolic names) in output?
|
||||||
my $Show_Tags = 0;
|
my $Show_Tags = 0;
|
||||||
|
|
||||||
@@ -210,6 +226,13 @@ my $Delta_Mode = 0;
|
|||||||
my $Delta_From = "";
|
my $Delta_From = "";
|
||||||
my $Delta_To = "";
|
my $Delta_To = "";
|
||||||
|
|
||||||
|
my $TestCode;
|
||||||
|
|
||||||
|
# Whether to parse filenames from the RCS filename, and if so what
|
||||||
|
# prefix to strip.
|
||||||
|
my $RCS_Mode = 0;
|
||||||
|
my $RCS_Root = "";
|
||||||
|
|
||||||
## end vars set by options.
|
## end vars set by options.
|
||||||
|
|
||||||
# latest observed times for the start/end tags in delta mode
|
# latest observed times for the start/end tags in delta mode
|
||||||
@@ -225,19 +248,39 @@ my $file_separator = "======================================="
|
|||||||
# within a file:
|
# within a file:
|
||||||
my $logmsg_separator = "----------------------------";
|
my $logmsg_separator = "----------------------------";
|
||||||
|
|
||||||
|
my $No_Ancestors = 0;
|
||||||
|
|
||||||
############### End globals ############
|
############### End globals ############
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
&parse_options ();
|
&parse_options ();
|
||||||
|
if ( defined $TestCode ) {
|
||||||
|
eval $TestCode;
|
||||||
|
die "Eval failed: '$@'\n"
|
||||||
|
if $@;
|
||||||
|
} else {
|
||||||
&derive_change_log ();
|
&derive_change_log ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
### Everything below is subroutine definitions. ###
|
### Everything below is subroutine definitions. ###
|
||||||
|
|
||||||
|
sub run_ext {
|
||||||
|
my ($cmd) = @_;
|
||||||
|
$cmd = [$cmd]
|
||||||
|
unless ref $cmd;
|
||||||
|
local $" = ' ';
|
||||||
|
my $out = qx"@$cmd 2>&1";
|
||||||
|
my $rv = $?;
|
||||||
|
my ($sig, $core, $exit) = ($? & 127, $? & 128, $? >> 8);
|
||||||
|
return $out, $exit, $sig, $core;
|
||||||
|
}
|
||||||
|
|
||||||
# If accumulating, grab the boundary date from pre-existing ChangeLog.
|
# If accumulating, grab the boundary date from pre-existing ChangeLog.
|
||||||
sub maybe_grab_accumulation_date ()
|
sub maybe_grab_accumulation_date ()
|
||||||
{
|
{
|
||||||
if (! $Cumulative) {
|
if (! $Cumulative || $Update) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,6 +314,9 @@ sub derive_change_log ()
|
|||||||
my $time;
|
my $time;
|
||||||
my $revision;
|
my $revision;
|
||||||
my $author;
|
my $author;
|
||||||
|
my $state;
|
||||||
|
my $lines;
|
||||||
|
my $cvsstate;
|
||||||
my $msg_txt;
|
my $msg_txt;
|
||||||
my $detected_file_separator;
|
my $detected_file_separator;
|
||||||
|
|
||||||
@@ -321,11 +367,22 @@ sub derive_change_log ()
|
|||||||
{
|
{
|
||||||
# Canonicalize line endings
|
# Canonicalize line endings
|
||||||
s/\r$//;
|
s/\r$//;
|
||||||
|
my $new_full_path;
|
||||||
|
|
||||||
# If on a new file and don't see filename, skip until we find it, and
|
# If on a new file and don't see filename, skip until we find it, and
|
||||||
# when we find it, grab it.
|
# when we find it, grab it.
|
||||||
if ((! (defined $file_full_path)) and /^Working file: (.*)/)
|
if (! (defined $file_full_path))
|
||||||
{
|
{
|
||||||
$file_full_path = $1;
|
if (/^Working file: (.*)/) {
|
||||||
|
$new_full_path = $1;
|
||||||
|
} elsif ($RCS_Mode && m|^RCS file: $RCS_Root/(.*),v$|) {
|
||||||
|
$new_full_path = $1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined $new_full_path)
|
||||||
|
{
|
||||||
|
$file_full_path = $new_full_path;
|
||||||
if (@Ignore_Files)
|
if (@Ignore_Files)
|
||||||
{
|
{
|
||||||
my $base;
|
my $base;
|
||||||
@@ -441,7 +498,9 @@ sub derive_change_log ()
|
|||||||
goto dengo;
|
goto dengo;
|
||||||
}
|
}
|
||||||
# Non-trivial case: check if rev is ancestral to branch
|
# Non-trivial case: check if rev is ancestral to branch
|
||||||
elsif ((length ($branch_number)) > (length ($revision)))
|
elsif ((length ($branch_number)) > (length ($revision))
|
||||||
|
and
|
||||||
|
$No_Ancestors)
|
||||||
{
|
{
|
||||||
$revision =~ /^((?:\d+\.)+)(\d+)$/;
|
$revision =~ /^((?:\d+\.)+)(\d+)$/;
|
||||||
my $r_left = $1; # still has the trailing "."
|
my $r_left = $1; # still has the trailing "."
|
||||||
@@ -491,7 +550,8 @@ sub derive_change_log ()
|
|||||||
{
|
{
|
||||||
if (/^date: .*/)
|
if (/^date: .*/)
|
||||||
{
|
{
|
||||||
($time, $author) = &parse_date_and_author ($_);
|
($time, $author, $state, $lines) =
|
||||||
|
&parse_date_author_and_state ($_);
|
||||||
if (defined ($usermap{$author}) and $usermap{$author}) {
|
if (defined ($usermap{$author}) and $usermap{$author}) {
|
||||||
$author = $usermap{$author};
|
$author = $usermap{$author};
|
||||||
} elsif($Domain ne "" or $Gecos == 1) {
|
} elsif($Domain ne "" or $Gecos == 1) {
|
||||||
@@ -653,6 +713,10 @@ sub derive_change_log ()
|
|||||||
# loop-end deals with organizing these in qunk.
|
# loop-end deals with organizing these in qunk.
|
||||||
|
|
||||||
$qunk{'revision'} = $revision;
|
$qunk{'revision'} = $revision;
|
||||||
|
$qunk{'state'} = $state;
|
||||||
|
if ( defined( $lines )) {
|
||||||
|
$qunk{'lines'} = $lines;
|
||||||
|
}
|
||||||
|
|
||||||
# Grab the branch, even though we may or may not need it:
|
# Grab the branch, even though we may or may not need it:
|
||||||
$qunk{'revision'} =~ /((?:\d+\.)+)\d+/;
|
$qunk{'revision'} =~ /((?:\d+\.)+)\d+/;
|
||||||
@@ -662,6 +726,9 @@ sub derive_change_log ()
|
|||||||
$qunk{'branch'} = $branch_names{$branch_prefix};
|
$qunk{'branch'} = $branch_names{$branch_prefix};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Keep a record of the file's cvs state.
|
||||||
|
$qunk{'cvsstate'} = $state;
|
||||||
|
|
||||||
# If there's anything in the @branch_roots array, then this
|
# If there's anything in the @branch_roots array, then this
|
||||||
# revision is the root of at least one branch. We'll display
|
# revision is the root of at least one branch. We'll display
|
||||||
# them as branch names instead of revision numbers, the
|
# them as branch names instead of revision numbers, the
|
||||||
@@ -926,7 +993,7 @@ sub derive_change_log ()
|
|||||||
$msg = &preprocess_msg_text ($msg);
|
$msg = &preprocess_msg_text ($msg);
|
||||||
$body = $files . $msg;
|
$body = $files . $msg;
|
||||||
}
|
}
|
||||||
elsif ($No_Wrap)
|
elsif ($No_Wrap && !$Summary)
|
||||||
{
|
{
|
||||||
$msg = &preprocess_msg_text ($msg);
|
$msg = &preprocess_msg_text ($msg);
|
||||||
$files = wrap ("\t", " ", "$files");
|
$files = wrap ("\t", " ", "$files");
|
||||||
@@ -936,6 +1003,83 @@ sub derive_change_log ()
|
|||||||
}
|
}
|
||||||
$body = $files . $After_Header . $msg;
|
$body = $files . $After_Header . $msg;
|
||||||
}
|
}
|
||||||
|
elsif ($Summary)
|
||||||
|
{
|
||||||
|
my( $filelist, $qunk );
|
||||||
|
my( @DeletedQunks, @AddedQunks, @ChangedQunks );
|
||||||
|
|
||||||
|
$msg = &preprocess_msg_text ($msg);
|
||||||
|
#
|
||||||
|
# Sort the files (qunks) according to the operation that was
|
||||||
|
# performed. Files which were added have no line change
|
||||||
|
# indicator, whereas deleted files have state dead.
|
||||||
|
#
|
||||||
|
foreach $qunk ( @$qunklist )
|
||||||
|
{
|
||||||
|
if ( "dead" eq $qunk->{'state'})
|
||||||
|
{
|
||||||
|
push( @DeletedQunks, $qunk );
|
||||||
|
}
|
||||||
|
elsif ( !exists( $qunk->{'lines'}))
|
||||||
|
{
|
||||||
|
push( @AddedQunks, $qunk );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
push( @ChangedQunks, $qunk );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#
|
||||||
|
# The qunks list was originally in tree search order. Let's
|
||||||
|
# get that back. The lists, if they exist, will be reversed upon
|
||||||
|
# processing.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Now write the three sections onto $filelist
|
||||||
|
#
|
||||||
|
if ( @DeletedQunks )
|
||||||
|
{
|
||||||
|
$filelist .= "\tDeleted:\n";
|
||||||
|
foreach $qunk ( @DeletedQunks )
|
||||||
|
{
|
||||||
|
$filelist .= "\t\t" . $qunk->{'filename'};
|
||||||
|
$filelist .= " (" . $qunk->{'revision'} . ")";
|
||||||
|
$filelist .= "\n";
|
||||||
|
}
|
||||||
|
undef( @DeletedQunks );
|
||||||
|
}
|
||||||
|
if ( @AddedQunks )
|
||||||
|
{
|
||||||
|
$filelist .= "\tAdded:\n";
|
||||||
|
foreach $qunk ( @AddedQunks )
|
||||||
|
{
|
||||||
|
$filelist .= "\t\t" . $qunk->{'filename'};
|
||||||
|
$filelist .= " (" . $qunk->{'revision'} . ")";
|
||||||
|
$filelist .= "\n";
|
||||||
|
}
|
||||||
|
undef( @AddedQunks );
|
||||||
|
}
|
||||||
|
if ( @ChangedQunks )
|
||||||
|
{
|
||||||
|
$filelist .= "\tChanged:\n";
|
||||||
|
foreach $qunk ( @ChangedQunks )
|
||||||
|
{
|
||||||
|
$filelist .= "\t\t" . $qunk->{'filename'};
|
||||||
|
$filelist .= " (" . $qunk->{'revision'} . ")";
|
||||||
|
$filelist .= ", \"" . $qunk->{'state'} . "\"";
|
||||||
|
$filelist .= ", lines: " . $qunk->{'lines'};
|
||||||
|
$filelist .= "\n";
|
||||||
|
}
|
||||||
|
undef( @ChangedQunks );
|
||||||
|
}
|
||||||
|
chomp( $filelist );
|
||||||
|
$msg =~ s/\n(.*)/\n\t$1/g;
|
||||||
|
unless ($After_Header eq " ") {
|
||||||
|
$msg =~ s/^(.*)/\t$1/g;
|
||||||
|
}
|
||||||
|
$body = $filelist . $After_Header . $msg;
|
||||||
|
}
|
||||||
else # do wrapping, either FSF-style or regular
|
else # do wrapping, either FSF-style or regular
|
||||||
{
|
{
|
||||||
if ($FSF_Style)
|
if ($FSF_Style)
|
||||||
@@ -1040,7 +1184,7 @@ sub derive_change_log ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub parse_date_and_author ()
|
sub parse_date_author_and_state ()
|
||||||
{
|
{
|
||||||
# Parses the date/time and author out of a line like:
|
# Parses the date/time and author out of a line like:
|
||||||
#
|
#
|
||||||
@@ -1048,14 +1192,19 @@ sub parse_date_and_author ()
|
|||||||
|
|
||||||
my $line = shift;
|
my $line = shift;
|
||||||
|
|
||||||
my ($year, $mon, $mday, $hours, $min, $secs, $author) = $line =~
|
my ($year, $mon, $mday, $hours, $min, $secs, $author, $state, $rest) =
|
||||||
m#(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+);\s+author:\s+([^;]+);#
|
$line =~
|
||||||
|
m#(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+);\s+author:\s+([^;]+);\s+state:\s+([^;]+);(.*)#
|
||||||
or die "Couldn't parse date ``$line''";
|
or die "Couldn't parse date ``$line''";
|
||||||
die "Bad date or Y2K issues" unless ($year > 1969 and $year < 2258);
|
die "Bad date or Y2K issues" unless ($year > 1969 and $year < 2258);
|
||||||
# Kinda arbitrary, but useful as a sanity check
|
# Kinda arbitrary, but useful as a sanity check
|
||||||
my $time = timegm($secs,$min,$hours,$mday,$mon-1,$year-1900);
|
my $time = timegm($secs,$min,$hours,$mday,$mon-1,$year-1900);
|
||||||
|
my $lines;
|
||||||
return ($time, $author);
|
if ( $rest =~ m#\s+lines:\s+(.*)# )
|
||||||
|
{
|
||||||
|
$lines =$1;
|
||||||
|
}
|
||||||
|
return ($time, $author, $state, $lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Here we take a bunch of qunks and convert them into printed
|
# Here we take a bunch of qunks and convert them into printed
|
||||||
@@ -1161,6 +1310,7 @@ sub pretty_file_list ()
|
|||||||
foreach my $qunkref (@qunkrefs)
|
foreach my $qunkref (@qunkrefs)
|
||||||
{
|
{
|
||||||
my $filename = $$qunkref{'filename'};
|
my $filename = $$qunkref{'filename'};
|
||||||
|
my $cvsstate = $$qunkref{'cvsstate'};
|
||||||
my $revision = $$qunkref{'revision'};
|
my $revision = $$qunkref{'revision'};
|
||||||
my $tags = $$qunkref{'tags'};
|
my $tags = $$qunkref{'tags'};
|
||||||
my $branch = $$qunkref{'branch'};
|
my $branch = $$qunkref{'branch'};
|
||||||
@@ -1171,6 +1321,7 @@ sub pretty_file_list ()
|
|||||||
|
|
||||||
$beauty .= "<file>\n";
|
$beauty .= "<file>\n";
|
||||||
$beauty .= "<name>${filename}</name>\n";
|
$beauty .= "<name>${filename}</name>\n";
|
||||||
|
$beauty .= "<cvsstate>${cvsstate}</cvsstate>\n";
|
||||||
$beauty .= "<revision>${revision}</revision>\n";
|
$beauty .= "<revision>${revision}</revision>\n";
|
||||||
if ($branch) {
|
if ($branch) {
|
||||||
$branch = &xml_escape ($branch); # more paranoia
|
$branch = &xml_escape ($branch); # more paranoia
|
||||||
@@ -1294,7 +1445,7 @@ sub pretty_file_list ()
|
|||||||
# (($common_dir eq "./") ? "" : length ($common_dir)));
|
# (($common_dir eq "./") ? "" : length ($common_dir)));
|
||||||
$$qunkref{'printed'} = 1; # Set a mark bit.
|
$$qunkref{'printed'} = 1; # Set a mark bit.
|
||||||
|
|
||||||
if ($Show_Revisions || $Show_Tags)
|
if ($Show_Revisions || $Show_Tags || $Show_Dead)
|
||||||
{
|
{
|
||||||
my $started_addendum = 0;
|
my $started_addendum = 0;
|
||||||
|
|
||||||
@@ -1303,6 +1454,11 @@ sub pretty_file_list ()
|
|||||||
$b .= " (";
|
$b .= " (";
|
||||||
$b .= "$$qunkref{'revision'}";
|
$b .= "$$qunkref{'revision'}";
|
||||||
}
|
}
|
||||||
|
if ($Show_Dead && $$qunkref{'cvsstate'} =~ /dead/)
|
||||||
|
{
|
||||||
|
# Deliberately not using $started_addendum. Keeping it simple.
|
||||||
|
$b .= "[DEAD]";
|
||||||
|
}
|
||||||
if ($Show_Tags && (defined $$qunkref{'tags'})) {
|
if ($Show_Tags && (defined $$qunkref{'tags'})) {
|
||||||
my @tags = grep ($non_unanimous_tags{$_}, @{$$qunkref{'tags'}});
|
my @tags = grep ($non_unanimous_tags{$_}, @{$$qunkref{'tags'}});
|
||||||
if ((scalar (@tags)) > 0) {
|
if ((scalar (@tags)) > 0) {
|
||||||
@@ -1346,37 +1502,44 @@ sub pretty_file_list ()
|
|||||||
return $beauty;
|
return $beauty;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub common_path_prefix ()
|
sub min ($$) { $_[0] < $_[1] ? $_[0] : $_[1] }
|
||||||
{
|
|
||||||
my $path1 = shift;
|
|
||||||
my $path2 = shift;
|
|
||||||
|
|
||||||
my ($dir1, $dir2);
|
sub common_path_prefix ($$)
|
||||||
(undef, $dir1, undef) = fileparse ($path1);
|
{
|
||||||
(undef, $dir2, undef) = fileparse ($path2);
|
my ($path1, $path2) = @_;
|
||||||
|
|
||||||
|
# For compatibility (with older versions of cvs2cl.pl), we think in UN*X
|
||||||
|
# terms, and mould windoze filenames to match. Is this really appropriate?
|
||||||
|
# If a file is checked in under UN*X, and cvs log run on windoze, which way
|
||||||
|
# do the path separators slope? Can we use fileparse as per the local
|
||||||
|
# conventions? If so, we should probably have a user option to specify an
|
||||||
|
# OS to emulate to handle stdin-fed logs. If we did this, we could avoid
|
||||||
|
# the nasty \-/ transmogrification below.
|
||||||
|
|
||||||
|
my ($dir1, $dir2) = map +(fileparse($_))[1], $path1, $path2;
|
||||||
|
|
||||||
# Transmogrify Windows filenames to look like Unix.
|
# Transmogrify Windows filenames to look like Unix.
|
||||||
# (It is far more likely that someone is running cvs2cl.pl under
|
# (It is far more likely that someone is running cvs2cl.pl under
|
||||||
# Windows than that they would genuinely have backslashes in their
|
# Windows than that they would genuinely have backslashes in their
|
||||||
# filenames.)
|
# filenames.)
|
||||||
$dir1 =~ tr#\\#/#;
|
tr!\\!/!
|
||||||
$dir2 =~ tr#\\#/#;
|
for $dir1, $dir2;
|
||||||
|
|
||||||
my $accum1 = "";
|
my ($accum1, $accum2, $last_common_prefix) = ('') x 3;
|
||||||
my $accum2 = "";
|
|
||||||
my $last_common_prefix = "";
|
|
||||||
|
|
||||||
while ($accum1 eq $accum2)
|
my @path1 = grep length($_), split qr!/!, $dir1;
|
||||||
{
|
my @path2 = grep length($_), split qr!/!, $dir2;
|
||||||
$last_common_prefix = $accum1;
|
|
||||||
last if ($accum1 eq $dir1);
|
my @common_path;
|
||||||
my ($tmp1) = split (/\//, (substr ($dir1, length ($accum1))));
|
for (0..min($#path1,$#path2)) {
|
||||||
my ($tmp2) = split (/\//, (substr ($dir2, length ($accum2))));
|
if ( $path1[$_] eq $path2[$_]) {
|
||||||
$accum1 .= "$tmp1/" if (defined $tmp1 and $tmp1 ne '');
|
push @common_path, $path1[$_];
|
||||||
$accum2 .= "$tmp2/" if (defined $tmp2 and $tmp2 ne '');
|
} else {
|
||||||
|
last;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $last_common_prefix;
|
return join '', map "$_/", @common_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub preprocess_msg_text ()
|
sub preprocess_msg_text ()
|
||||||
@@ -1651,6 +1814,44 @@ sub maybe_read_user_map_file ()
|
|||||||
close (MAPFILE);
|
close (MAPFILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (defined $User_Passwd_File)
|
||||||
|
{
|
||||||
|
if ( ! defined $Mail_Domain ) {
|
||||||
|
if ( -e MAILNAME ) {
|
||||||
|
chomp($Mail_Domain = slurp_file(MAILNAME));
|
||||||
|
} else {
|
||||||
|
MAILDOMAIN_CMD:
|
||||||
|
for ([qw(hostname -d)], 'dnsdomainname', 'domainname') {
|
||||||
|
my ($text, $exit, $sig, $core) = run_ext($_);
|
||||||
|
if ( $exit == 0 && $sig == 0 && $core == 0 ) {
|
||||||
|
chomp $text;
|
||||||
|
if ( length $text ) {
|
||||||
|
$Mail_Domain = $text;
|
||||||
|
last MAILDOMAIN_CMD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
die "No mail domain found\n"
|
||||||
|
unless defined $Mail_Domain;
|
||||||
|
|
||||||
|
open (MAPFILE, "<$User_Passwd_File")
|
||||||
|
or die ("Unable to open $User_Passwd_File ($!)");
|
||||||
|
while (<MAPFILE>)
|
||||||
|
{
|
||||||
|
# all lines are valid
|
||||||
|
my ($username, $pw, $uid, $gid, $gecos, $homedir, $shell) = split ':';
|
||||||
|
my $expansion = '';
|
||||||
|
($expansion) = split (',', $gecos)
|
||||||
|
if defined $gecos && length $gecos;
|
||||||
|
|
||||||
|
$expansions{$username} = "$expansion <$username\@$Mail_Domain>";
|
||||||
|
}
|
||||||
|
close (MAPFILE);
|
||||||
|
}
|
||||||
|
|
||||||
return %expansions;
|
return %expansions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1700,6 +1901,9 @@ sub parse_options ()
|
|||||||
elsif ($arg =~ /^--accum$/) {
|
elsif ($arg =~ /^--accum$/) {
|
||||||
$Cumulative = 1;
|
$Cumulative = 1;
|
||||||
}
|
}
|
||||||
|
elsif ($arg =~ /^--update$/) {
|
||||||
|
$Update = 1;
|
||||||
|
}
|
||||||
elsif ($arg =~ /^--fsf$/) {
|
elsif ($arg =~ /^--fsf$/) {
|
||||||
$FSF_Style = 1;
|
$FSF_Style = 1;
|
||||||
}
|
}
|
||||||
@@ -1707,6 +1911,11 @@ sub parse_options ()
|
|||||||
$Show_Times = 0;
|
$Show_Times = 0;
|
||||||
$Common_Dir = 0;
|
$Common_Dir = 0;
|
||||||
}
|
}
|
||||||
|
elsif ($arg =~ /^--rcs/) {
|
||||||
|
my $narg = shift (@ARGV) || die "$arg needs argument.\n";
|
||||||
|
$RCS_Root = $narg;
|
||||||
|
$RCS_Mode = 1;
|
||||||
|
}
|
||||||
elsif ($arg =~ /^-U$|^--usermap$/) {
|
elsif ($arg =~ /^-U$|^--usermap$/) {
|
||||||
my $narg = shift (@ARGV) || die "$arg needs argument.\n";
|
my $narg = shift (@ARGV) || die "$arg needs argument.\n";
|
||||||
$User_Map_File = $narg;
|
$User_Map_File = $narg;
|
||||||
@@ -1718,6 +1927,14 @@ sub parse_options ()
|
|||||||
my $narg = shift (@ARGV) || die "$arg needs argument.\n";
|
my $narg = shift (@ARGV) || die "$arg needs argument.\n";
|
||||||
$Domain = $narg;
|
$Domain = $narg;
|
||||||
}
|
}
|
||||||
|
elsif ($arg =~ /^--passwd$/) {
|
||||||
|
my $narg = shift (@ARGV) || die "$arg needs argument.\n";
|
||||||
|
$User_Passwd_File = $narg;
|
||||||
|
}
|
||||||
|
elsif ($arg =~ /^--mailname$/) {
|
||||||
|
my $narg = shift (@ARGV) || die "$arg needs argument.\n";
|
||||||
|
$Mail_Domain = $narg;
|
||||||
|
}
|
||||||
elsif ($arg =~ /^-W$|^--window$/) {
|
elsif ($arg =~ /^-W$|^--window$/) {
|
||||||
defined(my $narg = shift (@ARGV)) || die "$arg needs argument.\n";
|
defined(my $narg = shift (@ARGV)) || die "$arg needs argument.\n";
|
||||||
$Max_Checkin_Duration = $narg;
|
$Max_Checkin_Duration = $narg;
|
||||||
@@ -1754,6 +1971,10 @@ sub parse_options ()
|
|||||||
elsif ($arg =~ /^--no-wrap$/) {
|
elsif ($arg =~ /^--no-wrap$/) {
|
||||||
$No_Wrap = 1;
|
$No_Wrap = 1;
|
||||||
}
|
}
|
||||||
|
elsif ($arg =~ /^--summary$/) {
|
||||||
|
$Summary = 1;
|
||||||
|
$After_Header = "\n\n"; # Summary implies --separate-header
|
||||||
|
}
|
||||||
elsif ($arg =~ /^--gmt$|^--utc$/) {
|
elsif ($arg =~ /^--gmt$|^--utc$/) {
|
||||||
$UTC_Times = 1;
|
$UTC_Times = 1;
|
||||||
}
|
}
|
||||||
@@ -1766,6 +1987,9 @@ sub parse_options ()
|
|||||||
elsif ($arg =~ /^-r$|^--revisions$/) {
|
elsif ($arg =~ /^-r$|^--revisions$/) {
|
||||||
$Show_Revisions = 1;
|
$Show_Revisions = 1;
|
||||||
}
|
}
|
||||||
|
elsif ($arg =~ /^--show-dead$/) {
|
||||||
|
$Show_Dead = 1;
|
||||||
|
}
|
||||||
elsif ($arg =~ /^-t$|^--tags$/) {
|
elsif ($arg =~ /^-t$|^--tags$/) {
|
||||||
$Show_Tags = 1;
|
$Show_Tags = 1;
|
||||||
}
|
}
|
||||||
@@ -1813,6 +2037,16 @@ sub parse_options ()
|
|||||||
unless @ARGV;
|
unless @ARGV;
|
||||||
$show_tags{shift @ARGV} = 1;
|
$show_tags{shift @ARGV} = 1;
|
||||||
}
|
}
|
||||||
|
elsif ( lc ($arg) eq '--test-code' ) {
|
||||||
|
# Deliberately undocumented. This is not a public interface,
|
||||||
|
# and may change/disappear at any time.
|
||||||
|
die "$arg needs argument.\n"
|
||||||
|
unless @ARGV;
|
||||||
|
$TestCode = shift @ARGV;
|
||||||
|
}
|
||||||
|
elsif ($arg =~ /^--no-ancestors$/) {
|
||||||
|
$No_Ancestors = 1;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
# Just add a filename as argument to the log command
|
# Just add a filename as argument to the log command
|
||||||
$Log_Source_Command .= " '$arg'";
|
$Log_Source_Command .= " '$arg'";
|
||||||
@@ -1936,6 +2170,7 @@ Options/Arguments:
|
|||||||
-b, --branches Show branch names in revisions when possible
|
-b, --branches Show branch names in revisions when possible
|
||||||
-t, --tags Show tags (symbolic names) in output
|
-t, --tags Show tags (symbolic names) in output
|
||||||
-T, --tagdates Show tags in output on their first occurance
|
-T, --tagdates Show tags in output on their first occurance
|
||||||
|
--show-dead Show dead files
|
||||||
--stdin Read from stdin, don't run cvs log
|
--stdin Read from stdin, don't run cvs log
|
||||||
--stdout Output to stdout not to ChangeLog
|
--stdout Output to stdout not to ChangeLog
|
||||||
-d, --distributed Put ChangeLogs in subdirs
|
-d, --distributed Put ChangeLogs in subdirs
|
||||||
@@ -1944,16 +2179,27 @@ Options/Arguments:
|
|||||||
--FSF Attempt strict FSF-standard compatible output
|
--FSF Attempt strict FSF-standard compatible output
|
||||||
-W SECS, --window SECS Window of time within which log entries unify
|
-W SECS, --window SECS Window of time within which log entries unify
|
||||||
-U UFILE, --usermap UFILE Expand usernames to email addresses from UFILE
|
-U UFILE, --usermap UFILE Expand usernames to email addresses from UFILE
|
||||||
|
--passwd PASSWORDFILE Use system passwd file for user name expansion
|
||||||
|
--mailname MAILDOMAIN Mail domainname to attach to user names for
|
||||||
|
email addresses. Only used with --passwd.
|
||||||
|
Defaults to contents, of /etc/mailname else
|
||||||
|
output of hostname -d / dnsdomainname /
|
||||||
|
domainname
|
||||||
--domain DOMAIN Domain to build email addresses from
|
--domain DOMAIN Domain to build email addresses from
|
||||||
--gecos Get user information from GECOS data
|
--gecos Get user information from GECOS data
|
||||||
-R REGEXP, --regexp REGEXP Include only entries that match REGEXP
|
-R REGEXP, --regexp REGEXP Include only entries that match REGEXP
|
||||||
-I REGEXP, --ignore REGEXP Ignore files whose names match REGEXP
|
-I REGEXP, --ignore REGEXP Ignore files whose names match REGEXP
|
||||||
-C, --case-insensitive Any regexp matching is done case-insensitively
|
-C, --case-insensitive Any regexp matching is done case-insensitively
|
||||||
-F BRANCH, --follow BRANCH Show only revisions on or ancestral to BRANCH
|
-F BRANCH, --follow BRANCH Show only revisions on or ancestral to BRANCH
|
||||||
|
--no-ancestors When using -F, only track changes since the
|
||||||
|
BRANCH started
|
||||||
-S, --separate-header Blank line between each header and log message
|
-S, --separate-header Blank line between each header and log message
|
||||||
|
--summary Add CVS change summary information
|
||||||
--no-wrap Don't auto-wrap log message (recommend -S also)
|
--no-wrap Don't auto-wrap log message (recommend -S also)
|
||||||
--gmt, --utc Show times in GMT/UTC instead of local time
|
--gmt, --utc Show times in GMT/UTC instead of local time
|
||||||
--accum Add to an existing ChangeLog (incompat w/ --xml)
|
--accum Add to an existing ChangeLog (incompat w/ --xml)
|
||||||
|
--update As --accum, but lists only files changed since
|
||||||
|
last run
|
||||||
-w, --day-of-week Show day of week
|
-w, --day-of-week Show day of week
|
||||||
--no-times Don't show times in output
|
--no-times Don't show times in output
|
||||||
--header FILE Get ChangeLog header from FILE ("-" means stdin)
|
--header FILE Get ChangeLog header from FILE ("-" means stdin)
|
||||||
@@ -1961,6 +2207,9 @@ Options/Arguments:
|
|||||||
--xml-encoding ENCODING Insert encoding clause in XML header
|
--xml-encoding ENCODING Insert encoding clause in XML header
|
||||||
--hide-filenames Don't show filenames (ignored for XML output)
|
--hide-filenames Don't show filenames (ignored for XML output)
|
||||||
--no-common-dir Don't shorten directory names from filenames.
|
--no-common-dir Don't shorten directory names from filenames.
|
||||||
|
--rcs CVSROOT Handle filenames from raw RCS, for instance
|
||||||
|
those produced by "cvs rlog" output, stripping
|
||||||
|
the prefix CVSROOT.
|
||||||
-P, --prune Don't show empty log messages
|
-P, --prune Don't show empty log messages
|
||||||
--ignore-tag TAG Ignore individual changes that are associated
|
--ignore-tag TAG Ignore individual changes that are associated
|
||||||
with a given tag. May be repeated, if so,
|
with a given tag. May be repeated, if so,
|
||||||
|
|||||||
Reference in New Issue
Block a user