source: codes/icosagcm/trunk/tools/FCM/lib/Fcm/CmCommitMessage.pm @ 10

Last change on this file since 10 was 10, checked in by ymipsl, 12 years ago

dynamico tree creation

YM

File size: 10.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
18# Standard pragma
19use warnings;
20use strict;
21
22# Standard modules
23use Carp;
24use Cwd;
25use File::Spec;
26use File::Temp qw/tempfile/;
27
28# FCM component modules
29use Fcm::Util qw/e_report run_command/;
30
31# Commit log delimiter messages
32my $ignore_line = '--This line, and those below, will be ignored--';
33my $auto_line   = '--This line will be ignored and those below will be ' .
34                  'inserted automatically--';
35
36# ------------------------------------------------------------------------------
37# SYNOPSIS
38#   $ci_mesg = Fcm::CmCommitMessage->new (
39#     CONFIG  => $config,
40#     DIR     => $dir,
41#     BASE    => $base,
42#   );
43#
44# DESCRIPTION
45#   This method constructs a new instance of the Fcm::CmCommitMessageFile class.
46#
47# ARGUMENTS
48#   CONFIG - reference to a Fcm::Config instance
49#   DIR    - directory containing the commit message file
50#   BASE   - base name of the commit message file
51# ------------------------------------------------------------------------------
52
53sub new {
54  my $this  = shift;
55  my %args  = @_;
56  my $class = ref $this || $this;
57
58  my $self = {
59    CONFIG => (exists $args{CONFIG} ? $args{CONFIG} : &main::cfg),
60    DIR    => (exists $args{DIR}    ? $args{DIR}    : cwd),
61    BASE   => (exists $args{BASE}   ? $args{BASE}   : '#commit_message#'),
62    USER_M => [],
63    AUTO_M => [],
64    IGNORE => [],
65  };
66
67  bless $self, $class;
68  return $self;
69}
70
71# ------------------------------------------------------------------------------
72# SYNOPSIS
73#   $config = $ci_mesg->config;
74#
75# DESCRIPTION
76#   This method returns a reference to the Fcm::Config instance.
77# ------------------------------------------------------------------------------
78
79sub config {
80  my $self = shift;
81
82  return $self->{CONFIG};
83}
84
85# ------------------------------------------------------------------------------
86# SYNOPSIS
87#   $dir = $ci_mesg->dir;
88#   $ci_mesg->dir ($dir);
89#
90# DESCRIPTION
91#   This method returns the directory container of the commit message file. If
92#   an argument is specified, the directory is reset using the value of the
93#   argument. (It does nothing is the directory does not already exist.)
94# ------------------------------------------------------------------------------
95
96sub dir {
97  my $self = shift;
98
99  if (@_) {
100    my $dir = shift;
101    $self->{DIR} = $dir if -d $dir;
102  }
103
104  return $self->{DIR};
105}
106
107# ------------------------------------------------------------------------------
108# SYNOPSIS
109#   $base = $ci_mesg->base;
110#   $ci_mesg->base ($base);
111#
112# DESCRIPTION
113#   This method returns the base name of the commit message file. If an
114#   argument is specified, the file is reset using the value of the argument.
115# ------------------------------------------------------------------------------
116
117sub base {
118  my $self = shift;
119
120  if (@_) {
121    $self->{BASE} = shift;
122  }
123
124  return $self->{BASE};
125}
126
127# ------------------------------------------------------------------------------
128# SYNOPSIS
129#   $file = $ci_mesg->file;
130#   $ci_mesg->file ($file);
131#
132# DESCRIPTION
133#   This method returns the full name of the commit message file. If an
134#   argument is specified, the file is reset using the value of the argument.
135# ------------------------------------------------------------------------------
136
137sub file {
138  my $self = shift;
139
140  if (@_) {
141    my $file      = shift;
142    $self->{DIR}  = dirname  ($file);
143    $self->{BASE} = basename ($file);
144  }
145
146  return File::Spec->catfile ($self->{DIR}, $self->{BASE});
147}
148
149# ------------------------------------------------------------------------------
150# SYNOPSIS
151#   @mesg = $ci_mesg->user_mesg;
152#   $ci_mesg->user_mesg (@mesg);
153#
154# DESCRIPTION
155#   This method returns the user defined commit message. If an argument is
156#   specified, the message is reset using the value of the argument.
157# ------------------------------------------------------------------------------
158
159sub user_mesg {
160  my $self = shift;
161
162  if (@_) {
163    @{ $self->{USER_M} } = @_;
164  }
165
166  return @{ $self->{USER_M} };
167}
168
169# ------------------------------------------------------------------------------
170# SYNOPSIS
171#   @mesg = $ci_mesg->auto_mesg;
172#   $ci_mesg->auto_mesg (@mesg);
173#
174# DESCRIPTION
175#   This method returns the automatically inserted commit message. If an
176#   argument is specified, the message is reset using the value of the
177#   argument.
178# ------------------------------------------------------------------------------
179
180sub auto_mesg {
181  my $self = shift;
182
183  if (@_) {
184    @{ $self->{AUTO_M} } = @_;
185  }
186
187  return @{ $self->{AUTO_M} };
188}
189
190# ------------------------------------------------------------------------------
191# SYNOPSIS
192#   @mesg = $ci_mesg->ignore_mesg;
193#   $ci_mesg->ignore_mesg (@mesg);
194#
195# DESCRIPTION
196#   This method returns the ignored part of a commit message. If an argument is
197#   specified, the message is reset using the value of the argument.
198# ------------------------------------------------------------------------------
199
200sub ignore_mesg {
201  my $self = shift;
202
203  if (@_) {
204    @{ $self->{IGNORE} } = @_;
205  }
206
207  return @{ $self->{IGNORE} };
208}
209
210# ------------------------------------------------------------------------------
211# SYNOPSIS
212#   ($user, $auto) = $ci_mesg->read_file ();
213#
214# DESCRIPTION
215#   This function reads from the commit log message file. It resets the user
216#   and the automatic messages after reading the file. It returns the message
217#   back in two array references.
218# ------------------------------------------------------------------------------
219
220sub read_file {
221  my $self = shift;
222
223  my @user = ();
224  my @auto = ();
225  my $file = $self->file;
226
227  if (-r $file) {
228    open FILE, '<', $file or croak 'Cannot open ', $file, '(', $!, '), abort';
229
230    my $in_auto = 0;
231    while (<FILE>) {
232      last if index ($_, $ignore_line) == 0; # ignore after the ignore delimiter
233
234      if (index ($_, $auto_line) == 0) {
235        # Beginning of the automatically inserted message delimiter
236        $in_auto = 1;
237        next;
238      }
239
240      if ($in_auto) {
241        push @auto, $_;
242
243      } else {
244        push @user, $_;
245      }
246    }
247
248    close FILE;
249
250    $self->user_mesg (@user);
251    $self->auto_mesg (@auto);
252  }
253
254  return (\@user, \@auto);
255}
256
257# ------------------------------------------------------------------------------
258# SYNOPSIS
259#   $ci_mesg->write_file ();
260#
261# DESCRIPTION
262#   This function writes to the commit log message file based on the content of
263#   the user defined message, and the automatically inserted message.
264# ------------------------------------------------------------------------------
265
266sub write_file {
267  my $self = shift;
268  my %args = @_;
269
270  my @user = $self->user_mesg;
271  my @auto = $self->auto_mesg;
272  my $file = $self->file;
273
274  open FILE, '>', $file or die 'Cannot open ', $file, '(', $!, '), abort';
275  print FILE @user;
276  print FILE $auto_line, "\n", @auto if @auto;
277  close FILE or croak 'Cannot close ', $file, '(', $!, '), abort';
278
279  return;
280}
281
282# ------------------------------------------------------------------------------
283# SYNOPSIS
284#   $file = $ci_mesg->edit_file ([TEMP => 1,] [BATCH => 1,]);
285#
286# DESCRIPTION
287#   This function normally triggers an editor for editing the commit message.
288#   If TEMP is set, it edits a temporary file. Otherwise, it edits the current
289#   commit message file. It resets the user defined message on success. Returns
290#   the name of the commit log file. Do not start the editor if BATCH is set.
291# ------------------------------------------------------------------------------
292
293sub edit_file {
294  my $self  = shift;
295  my %args  = @_;
296  my $temp  = exists $args{TEMP}  ? $args{TEMP}  : 0;
297  my $batch = exists $args{BATCH} ? $args{BATCH} : 0;
298
299  my @user   = $self->user_mesg;
300  my @auto   = $self->auto_mesg;
301  my @ignore = $self->ignore_mesg;
302  my $file   = $self->file;
303
304  if ($temp) {
305    my $fh;
306    ($fh, $file) = tempfile (SUFFIX => ".fcm", UNLINK => 1);
307    close $fh;
308  }
309
310  # Add original or code driven message and status information to the file
311  my $select = select;
312  open FILE, '>', $file or croak 'Cannot open ', $file, ' (', $!, '), abort';
313  select FILE;
314
315  print @user;
316  print (@auto || @user ? '' : "\n");
317  print $auto_line, "\n", @auto, "\n" if @auto;
318  print $ignore_line, "\n\n";
319  print @ignore if @ignore;
320
321  close FILE or die 'Cannot close ', $file, ' (', $!, '), abort';
322  select $select;
323
324  if (not $batch) {
325    # Select editor
326    my $editor = 'nedit';
327   
328    if ($ENV{'SVN_EDITOR'}) {
329      $editor = $ENV{'SVN_EDITOR'};
330
331    } elsif ($ENV{'VISUAL'}) {
332      $editor = $ENV{'VISUAL'};
333
334    } elsif ($ENV{'EDITOR'}) {
335      $editor = $ENV{'EDITOR'};
336    }
337
338    # Execute command to start the editor
339    print 'Starting ', $editor, ' to edit commit message ...', "\n";
340    &run_command ([split (/\s+/, $editor), $file]);
341  }
342
343  # Read the edited file, and extract user log message from it
344  open FILE, '<', $file or croak 'Cannot open ', $file, ' (', $!, '), abort';
345  my (@log);
346  my $in_auto    = 0;
347  my $in_ignored = 0;
348
349  while (<FILE>) {
350    if (index ($_, $auto_line) == 0) {
351      $in_auto = 1;
352
353    } elsif (index ($_, $ignore_line) == 0) {
354      $in_ignored = 1;
355      last;
356
357    } else {
358      next if $in_auto;
359      push @log, $_;
360    }
361  }
362
363  close FILE;
364
365  # Ensure auto and ignored lines are not altered
366  e_report 'Error: the line "', $auto_line, '" has been altered, abort.'
367    if @auto and not $in_auto;
368
369  e_report 'Error: the line "', $ignore_line, '" has been altered, abort.'
370    if not $in_ignored;
371
372  # Check for empty commit log
373  e_report 'Error: log message unchanged or not specified, abort.'
374    if join (' ', (@log, @auto)) =~ /^\s*$/;
375
376  # Echo the commit message to standard output
377  my $separator = '-' x 80 . "\n";
378  print 'Commit message is as follows:', "\n";
379  print $separator, @log, @auto, $ignore_line, "\n", @ignore, $separator;
380
381  open FILE, '>', $file or croak 'Cannot open ', $file, ' (', $!, '), abort';
382  print FILE @log, @auto;
383  close FILE or croak 'Cannot close ', $file, ' (', $!, '), abort';
384
385  # Reset the array for the user specified log message
386  $self->user_mesg (@log);
387
388  return $file;
389}
390
391# ------------------------------------------------------------------------------
392
3931;
394
395__END__
Note: See TracBrowser for help on using the repository browser.