source: OFFICIAL/FCM_V1.3/lib/Fcm/CmCommitMessage.pm

Last change on this file was 1, checked in by fcm, 15 years ago

creation de larborescence

File size: 8.4 KB
Line 
1#!/usr/bin/perl
2# ------------------------------------------------------------------------------
3# NAME
4#   Fcm::CmCommitMessage
5#
6# DESCRIPTION
7#   This class contains methods to read, write and edit the commit message file
8#   in a working copy.
9#
10# COPYRIGHT
11#   (C) Crown copyright Met Office. All rights reserved.
12#   For further details please refer to the file COPYRIGHT.txt
13#   which you should have received as part of this distribution.
14# ------------------------------------------------------------------------------
15
16package Fcm::CmCommitMessage;
17@ISA = qw(Fcm::Base);
18
19# Standard pragma
20use warnings;
21use strict;
22
23# Standard modules
24use Carp;
25use Cwd;
26use File::Spec;
27use File::Temp qw/tempfile/;
28
29# FCM component modules
30use Fcm::Base;
31use Fcm::Util qw/e_report run_command/;
32
33# List of property methods for this class
34my @scalar_properties = (
35  'auto_mesg',   # the automatically inserted part of a commit message
36  'base',        # the base name of the commit message file
37  'dir',         # the directory container of the commit message file
38  'ignore_mesg', # the ignored part of a commit message
39  'user_mesg',   # the user defined part of a commit message
40);
41
42# Commit log delimiter messages
43my $ignore_line = '--This line, and those below, will be ignored--';
44my $auto_line   = '--This line will be ignored and those below will be ' .
45                  'inserted automatically--';
46
47# ------------------------------------------------------------------------------
48# SYNOPSIS
49#   $obj = Fcm::CmCommitMessage->new ();
50#
51# DESCRIPTION
52#   This method constructs a new instance of the Fcm::CmCommitMessage class.
53# ------------------------------------------------------------------------------
54
55sub new {
56  my $this  = shift;
57  my %args  = @_;
58  my $class = ref $this || $this;
59
60  my $self = Fcm::Base->new (%args);
61
62  $self->{$_} = undef for (@scalar_properties);
63
64  bless $self, $class;
65  return $self;
66}
67
68# ------------------------------------------------------------------------------
69# SYNOPSIS
70#   $value = $obj->X;
71#   $obj->X ($value);
72#
73# DESCRIPTION
74#   Details of these properties are explained in @scalar_properties.
75# ------------------------------------------------------------------------------
76
77for my $name (@scalar_properties) {
78  no strict 'refs';
79
80  *$name = sub {
81    my $self = shift;
82
83    # Argument specified, set property to specified argument
84    if (@_) {
85      $self->{$name} = $_[0];
86    }
87
88    # Default value for property
89    if (not defined $self->{$name}) {
90      if ($name eq 'base') {
91        # Reference to an array
92        $self->{$name} = '#commit_message#';
93
94      } elsif ($name eq 'dir') {
95        # Current working directory
96        $self->{$name} = &cwd ();
97
98      } elsif ($name =~ /_mesg$/) {
99        # Reference to an array
100        $self->{$name} = [];
101      }
102    }
103
104    return $self->{$name};
105  }
106}
107
108# ------------------------------------------------------------------------------
109# SYNOPSIS
110#   $file = $obj->file;
111#   $obj->file ($file);
112#
113# DESCRIPTION
114#   This method returns the full name of the commit message file. If an
115#   argument is specified, the file is reset using the value of the argument.
116# ------------------------------------------------------------------------------
117
118sub file {
119  my ($self, $file) = @_;
120
121  if ($file) {
122    $self->dir  (dirname  ($file));
123    $self->base (basename ($file));
124  }
125
126  return File::Spec->catfile ($self->dir, $self->base);
127}
128
129# ------------------------------------------------------------------------------
130# SYNOPSIS
131#   ($user, $auto) = $obj->read_file ();
132#
133# DESCRIPTION
134#   This function reads from the commit log message file. It resets the user
135#   and the automatic messages after reading the file. It returns the message
136#   back in two array references.
137# ------------------------------------------------------------------------------
138
139sub read_file {
140  my $self = shift;
141
142  my @user = ();
143  my @auto = ();
144  my $file = $self->file;
145
146  if (-r $file) {
147    open FILE, '<', $file or croak 'Cannot open ', $file, '(', $!, '), abort';
148
149    my $in_auto = 0;
150    while (<FILE>) {
151      last if index ($_, $ignore_line) == 0; # ignore after the ignore delimiter
152
153      if (index ($_, $auto_line) == 0) {
154        # Beginning of the automatically inserted message delimiter
155        $in_auto = 1;
156        next;
157      }
158
159      if ($in_auto) {
160        push @auto, $_;
161
162      } else {
163        push @user, $_;
164      }
165    }
166
167    close FILE;
168
169    $self->user_mesg (\@user);
170    $self->auto_mesg (\@auto);
171  }
172
173  return (\@user, \@auto);
174}
175
176# ------------------------------------------------------------------------------
177# SYNOPSIS
178#   $obj->write_file ();
179#
180# DESCRIPTION
181#   This function writes to the commit log message file based on the content of
182#   the user defined message, and the automatically inserted message.
183# ------------------------------------------------------------------------------
184
185sub write_file {
186  my $self = shift;
187  my %args = @_;
188
189  my @user = @{ $self->user_mesg };
190  my @auto = @{ $self->auto_mesg };
191  my $file = $self->file;
192
193  open FILE, '>', $file or die 'Cannot open ', $file, '(', $!, '), abort';
194  print FILE @user;
195  print FILE $auto_line, "\n", @auto if @auto;
196  close FILE or croak 'Cannot close ', $file, '(', $!, '), abort';
197
198  return;
199}
200
201# ------------------------------------------------------------------------------
202# SYNOPSIS
203#   $file = $obj->edit_file ([TEMP => 1,] [BATCH => 1,]);
204#
205# DESCRIPTION
206#   This function normally triggers an editor for editing the commit message.
207#   If TEMP is set, it edits a temporary file. Otherwise, it edits the current
208#   commit message file. It resets the user defined message on success. Returns
209#   the name of the commit log file. Do not start the editor if BATCH is set.
210# ------------------------------------------------------------------------------
211
212sub edit_file {
213  my $self  = shift;
214  my %args  = @_;
215  my $temp  = exists $args{TEMP}  ? $args{TEMP}  : 0;
216  my $batch = exists $args{BATCH} ? $args{BATCH} : 0;
217
218  my @user   = @{ $self->user_mesg };
219  my @auto   = @{ $self->auto_mesg };
220  my @ignore = @{ $self->ignore_mesg };
221  my $file   = $self->file;
222
223  if ($temp) {
224    my $fh;
225    ($fh, $file) = tempfile (SUFFIX => ".fcm", UNLINK => 1);
226    close $fh;
227  }
228
229  # Add original or code driven message and status information to the file
230  my $select = select;
231  open FILE, '>', $file or croak 'Cannot open ', $file, ' (', $!, '), abort';
232  select FILE;
233
234  print @user;
235  print (@auto || @user ? '' : "\n");
236  print $auto_line, "\n", @auto, "\n" if @auto;
237  print $ignore_line, "\n\n";
238  print @ignore if @ignore;
239
240  close FILE or die 'Cannot close ', $file, ' (', $!, '), abort';
241  select $select;
242
243  if (not $batch) {
244    # Select editor
245    my $editor = 'nedit';
246   
247    if ($ENV{'SVN_EDITOR'}) {
248      $editor = $ENV{'SVN_EDITOR'};
249
250    } elsif ($ENV{'VISUAL'}) {
251      $editor = $ENV{'VISUAL'};
252
253    } elsif ($ENV{'EDITOR'}) {
254      $editor = $ENV{'EDITOR'};
255    }
256
257    # Execute command to start the editor
258    print 'Starting ', $editor, ' to edit commit message ...', "\n";
259    &run_command ([split (/\s+/, $editor), $file]);
260  }
261
262  # Read the edited file, and extract user log message from it
263  open FILE, '<', $file or croak 'Cannot open ', $file, ' (', $!, '), abort';
264  my (@log);
265  my $in_auto    = 0;
266  my $in_ignored = 0;
267
268  while (<FILE>) {
269    if (index ($_, $auto_line) == 0) {
270      $in_auto = 1;
271
272    } elsif (index ($_, $ignore_line) == 0) {
273      $in_ignored = 1;
274      last;
275
276    } else {
277      next if $in_auto;
278      push @log, $_;
279    }
280  }
281
282  close FILE;
283
284  # Ensure auto and ignored lines are not altered
285  e_report 'Error: the line "', $auto_line, '" has been altered, abort.'
286    if @auto and not $in_auto;
287
288  e_report 'Error: the line "', $ignore_line, '" has been altered, abort.'
289    if not $in_ignored;
290
291  # Check for empty commit log
292  e_report 'Error: log message unchanged or not specified, abort.'
293    if join (' ', (@log, @auto)) =~ /^\s*$/;
294
295  # Echo the commit message to standard output
296  my $separator = '-' x 80 . "\n";
297  print 'Commit message is as follows:', "\n";
298  print $separator, @log, @auto, $ignore_line, "\n", @ignore, $separator;
299
300  open FILE, '>', $file or croak 'Cannot open ', $file, ' (', $!, '), abort';
301  print FILE @log, @auto;
302  close FILE or croak 'Cannot close ', $file, ' (', $!, '), abort';
303
304  # Reset the array for the user specified log message
305  $self->user_mesg (\@log);
306
307  return $file;
308}
309
310# ------------------------------------------------------------------------------
311
3121;
313
314__END__
Note: See TracBrowser for help on using the repository browser.