320 lines
8.8 KiB
Perl
Executable File
320 lines
8.8 KiB
Perl
Executable File
# ------------------------------------------------------------------------------
|
|
# NAME
|
|
# Fcm::CmCommitMessage
|
|
#
|
|
# DESCRIPTION
|
|
# This class contains methods to read, write and edit the commit message file
|
|
# in a working copy.
|
|
#
|
|
# COPYRIGHT
|
|
# (C) Crown copyright Met Office. All rights reserved.
|
|
# For further details please refer to the file COPYRIGHT.txt
|
|
# which you should have received as part of this distribution.
|
|
# ------------------------------------------------------------------------------
|
|
|
|
package Fcm::CmCommitMessage;
|
|
@ISA = qw(Fcm::Base);
|
|
|
|
# Standard pragma
|
|
use warnings;
|
|
use strict;
|
|
|
|
# Standard modules
|
|
use Carp;
|
|
use Cwd;
|
|
use File::Spec;
|
|
use File::Temp qw/tempfile/;
|
|
|
|
# FCM component modules
|
|
use Fcm::Base;
|
|
use Fcm::Util qw/e_report run_command/;
|
|
|
|
# List of property methods for this class
|
|
my @scalar_properties = (
|
|
'auto_mesg', # the automatically inserted part of a commit message
|
|
'base', # the base name of the commit message file
|
|
'dir', # the directory container of the commit message file
|
|
'ignore_mesg', # the ignored part of a commit message
|
|
'user_mesg', # the user defined part of a commit message
|
|
);
|
|
|
|
# Commit log delimiter messages
|
|
my $log_delimiter = '--Add your commit message ABOVE - ' .
|
|
'do not alter this line or those below--';
|
|
my $auto_delimiter = '--FCM message (will be inserted automatically)--';
|
|
my $auto_delimiter_old = '--This line will be ignored and those below ' .
|
|
'will be inserted automatically--';
|
|
my $status_delimiter = '--Change summary ' .
|
|
'(not part of commit message)--';
|
|
my $status_delimiter_old = '--This line, and those below, will be ignored--';
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# SYNOPSIS
|
|
# $obj = Fcm::CmCommitMessage->new ();
|
|
#
|
|
# DESCRIPTION
|
|
# This method constructs a new instance of the Fcm::CmCommitMessage class.
|
|
# ------------------------------------------------------------------------------
|
|
|
|
sub new {
|
|
my $this = shift;
|
|
my %args = @_;
|
|
my $class = ref $this || $this;
|
|
|
|
my $self = Fcm::Base->new (%args);
|
|
|
|
$self->{$_} = undef for (@scalar_properties);
|
|
|
|
bless $self, $class;
|
|
return $self;
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# SYNOPSIS
|
|
# $value = $obj->X;
|
|
# $obj->X ($value);
|
|
#
|
|
# DESCRIPTION
|
|
# Details of these properties are explained in @scalar_properties.
|
|
# ------------------------------------------------------------------------------
|
|
|
|
for my $name (@scalar_properties) {
|
|
no strict 'refs';
|
|
|
|
*$name = sub {
|
|
my $self = shift;
|
|
|
|
# Argument specified, set property to specified argument
|
|
if (@_) {
|
|
$self->{$name} = $_[0];
|
|
}
|
|
|
|
# Default value for property
|
|
if (not defined $self->{$name}) {
|
|
if ($name eq 'base') {
|
|
# Reference to an array
|
|
$self->{$name} = '#commit_message#';
|
|
|
|
} elsif ($name eq 'dir') {
|
|
# Current working directory
|
|
$self->{$name} = &cwd ();
|
|
|
|
} elsif ($name =~ /_mesg$/) {
|
|
# Reference to an array
|
|
$self->{$name} = [];
|
|
}
|
|
}
|
|
|
|
return $self->{$name};
|
|
}
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# SYNOPSIS
|
|
# $file = $obj->file;
|
|
# $obj->file ($file);
|
|
#
|
|
# DESCRIPTION
|
|
# This method returns the full name of the commit message file. If an
|
|
# argument is specified, the file is reset using the value of the argument.
|
|
# ------------------------------------------------------------------------------
|
|
|
|
sub file {
|
|
my ($self, $file) = @_;
|
|
|
|
if ($file) {
|
|
$self->dir (dirname ($file));
|
|
$self->base (basename ($file));
|
|
}
|
|
|
|
return File::Spec->catfile ($self->dir, $self->base);
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# SYNOPSIS
|
|
# ($user, $auto) = $obj->read_file ();
|
|
#
|
|
# DESCRIPTION
|
|
# This function reads from the commit log message file. It resets the user
|
|
# and the automatic messages after reading the file. It returns the message
|
|
# back in two array references.
|
|
# ------------------------------------------------------------------------------
|
|
|
|
sub read_file {
|
|
my $self = shift;
|
|
|
|
my @user = ();
|
|
my @auto = ();
|
|
my $file = $self->file;
|
|
|
|
if (-r $file) {
|
|
open FILE, '<', $file or croak 'Cannot open ', $file, '(', $!, '), abort';
|
|
|
|
my $in_auto = 0;
|
|
while (<FILE>) {
|
|
|
|
next if (index ($_, $log_delimiter) == 0);
|
|
|
|
if (index ($_, $status_delimiter) == 0 ||
|
|
index ($_, $status_delimiter_old) == 0) {
|
|
# Ignore after the ignore delimiter
|
|
last;
|
|
}
|
|
|
|
if (index ($_, $auto_delimiter) == 0 ||
|
|
index ($_, $auto_delimiter_old) == 0) {
|
|
# Beginning of the automatically inserted message
|
|
$in_auto = 1;
|
|
next;
|
|
}
|
|
|
|
if ($in_auto) {
|
|
push @auto, $_;
|
|
|
|
} else {
|
|
push @user, $_;
|
|
}
|
|
}
|
|
|
|
close FILE;
|
|
|
|
$self->user_mesg (\@user);
|
|
$self->auto_mesg (\@auto);
|
|
}
|
|
|
|
return (\@user, \@auto);
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# SYNOPSIS
|
|
# $obj->write_file ();
|
|
#
|
|
# DESCRIPTION
|
|
# This function writes to the commit log message file based on the content of
|
|
# the user defined message, and the automatically inserted message.
|
|
# ------------------------------------------------------------------------------
|
|
|
|
sub write_file {
|
|
my $self = shift;
|
|
my %args = @_;
|
|
|
|
my @user = @{ $self->user_mesg };
|
|
my @auto = @{ $self->auto_mesg };
|
|
my $file = $self->file;
|
|
|
|
open FILE, '>', $file or die 'Cannot open ', $file, '(', $!, '), abort';
|
|
print FILE @user;
|
|
print FILE $log_delimiter, "\n", $auto_delimiter, "\n", @auto if @auto;
|
|
close FILE or croak 'Cannot close ', $file, '(', $!, '), abort';
|
|
|
|
return;
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# SYNOPSIS
|
|
# $file = $obj->edit_file ([TEMP => 1,] [BATCH => 1,]);
|
|
#
|
|
# DESCRIPTION
|
|
# This function normally triggers an editor for editing the commit message.
|
|
# If TEMP is set, it edits a temporary file. Otherwise, it edits the current
|
|
# commit message file. It resets the user defined message on success. Returns
|
|
# the name of the commit log file. Do not start the editor if BATCH is set.
|
|
# ------------------------------------------------------------------------------
|
|
|
|
sub edit_file {
|
|
my $self = shift;
|
|
my %args = @_;
|
|
my $temp = exists $args{TEMP} ? $args{TEMP} : 0;
|
|
my $batch = exists $args{BATCH} ? $args{BATCH} : 0;
|
|
|
|
my @user = @{ $self->user_mesg };
|
|
my @auto = @{ $self->auto_mesg };
|
|
my @ignore = @{ $self->ignore_mesg };
|
|
my $file = $self->file;
|
|
|
|
if ($temp) {
|
|
my $fh;
|
|
($fh, $file) = tempfile (SUFFIX => ".fcm", UNLINK => 1);
|
|
close $fh;
|
|
}
|
|
|
|
# Add original or code driven message and status information to the file
|
|
my $select = select;
|
|
open FILE, '>', $file or croak 'Cannot open ', $file, ' (', $!, '), abort';
|
|
select FILE;
|
|
|
|
print @user;
|
|
print (@auto || @user ? '' : "\n");
|
|
print $log_delimiter, "\n";
|
|
print $auto_delimiter, "\n", @auto, "\n" if @auto;
|
|
print $status_delimiter, "\n\n";
|
|
print @ignore if @ignore;
|
|
|
|
close FILE or die 'Cannot close ', $file, ' (', $!, '), abort';
|
|
select $select;
|
|
|
|
if (not $batch) {
|
|
# Select editor
|
|
my $editor = 'nedit';
|
|
|
|
if ($ENV{'SVN_EDITOR'}) {
|
|
$editor = $ENV{'SVN_EDITOR'};
|
|
|
|
} elsif ($ENV{'VISUAL'}) {
|
|
$editor = $ENV{'VISUAL'};
|
|
|
|
} elsif ($ENV{'EDITOR'}) {
|
|
$editor = $ENV{'EDITOR'};
|
|
}
|
|
|
|
# Execute command to start the editor
|
|
print 'Starting ', $editor, ' to edit commit message ...', "\n";
|
|
&run_command ([split (/\s+/, $editor), $file]);
|
|
}
|
|
|
|
# Read the edited file, and extract user log message from it
|
|
open FILE, '<', $file or croak 'Cannot open ', $file, ' (', $!, '), abort';
|
|
my (@log);
|
|
my $delimiter_found = 0;
|
|
|
|
while (<FILE>) {
|
|
if (index ($_, $log_delimiter) == 0) {
|
|
$delimiter_found = 1;
|
|
last;
|
|
}
|
|
push @log, $_;
|
|
}
|
|
|
|
close FILE;
|
|
|
|
# Ensure log delimiter line was not altered
|
|
e_report 'Error: the line "', $log_delimiter, '" has been altered, abort.'
|
|
if not $delimiter_found;
|
|
|
|
# Check for empty commit log
|
|
e_report 'Error: log message unchanged or not specified, abort.'
|
|
if join (' ', (@log, @auto)) =~ /^\s*$/;
|
|
|
|
# Echo the commit message to standard output
|
|
my $separator = '-' x 80 . "\n";
|
|
print 'Change summary:', "\n";
|
|
print $separator, @ignore, $separator;
|
|
print 'Commit message is as follows:', "\n";
|
|
print $separator, @log, @auto, $separator;
|
|
|
|
open FILE, '>', $file or croak 'Cannot open ', $file, ' (', $!, '), abort';
|
|
print FILE @log, @auto;
|
|
close FILE or croak 'Cannot close ', $file, ' (', $!, '), abort';
|
|
|
|
# Reset the array for the user specified log message
|
|
$self->user_mesg (\@log);
|
|
|
|
return $file;
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
1;
|
|
|
|
__END__
|