aboutsummaryrefslogtreecommitdiffstats
path: root/CVSROOT/edithook
blob: 900093025dcc000655e2665407bd08d821bc9ab9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
#!/usr/bin/perl
#
#   $Id$
#

# Perl filter to handle cvs editinfo preparation of log messge

# This filter should be named in the $CVSROOT/CVSROOT/editinfo file
# for any modules you wish to add the gnats bug system bugid and
# header.
# A line like "DEFAULT      /path/to/this/perl/script"
# will do the trick.

# Some tracking information may be logged
$debugging = 0;         # used in sub debug   for tracking
$logging   = 0;         # used in sub log     for tracking

$debugging = 1 if (defined $ENV{'CVSDEBUGEDIT'});

#########################################################################
#
# derrived information needed below
#
#########################################################################

$login = (getpwuid($<))[0] || "Anonymous"; # get user's login name


#########################################################################
#
# Paths to utilities
#
#########################################################################

$defaultEditorCmd  = '/usr/bin/vi'; # use env $EDITOR to override
$editorCmd         = ((defined $ENV{'EDITOR'}) ?
                      $ENV{'EDITOR'} :
              ((defined $ENV{'EDITOR'}) ?
               $ENV{'EDITOR'} : $defaultEditorCmd));


#########################################################################
#
# Constants
#
#########################################################################
$BadTmpDir = "
It is a very bad idea for the environment variable TMPDIR
currently set to \'$ENV{'TMPDIR'}\' to be a relative pathname.
Please choose something with a leading slash (/tmp) for example
\n";

$MissingTmpDir = "
It is a very bad idea for the environment variable TMPDIR
currently set to \'$ENV{'TMPDIR'}\' to be directory which does not
exist. Please create this directory and give it read-write permissions
to group cisco.
\n";


#########################################################################
#
# Inter-filter communication file names
#
#########################################################################

# Do not change these constants without changing them in the other
# scripts as well.

$pgrp          = getpgrp();     # parent process id

if (defined $ENV{'TMPDIR'}) {
    # trivial sanity check, are we able to write into this directory?
    if ($ENV{'TMPDIR'} !~ /^\//) {
    &debug("Bad... TMPDIR is not a full pathname");
    &abort($BadTmpDir);
    }
    elsif ( -d $ENV{'TMPDIR'} && -w _ ) {
    &debug("Good.. TMPDIR references a directory we can use");
    $tmpDir = $ENV{'TMPDIR'};
    }
    else {
    &debug("Bad... TMPDIR is not a directory in which we can write files");
    &abort($MissingTmpDir);
    }
}
else {
    $tmpDir = '/tmp';
    if ( -d $tmpDir && -w _ ) {
    &debug("Good.. $tmpDir looks like we can use it");
    }
    else {
    &debug("Bad... $tmpDir is not a directory in which we can write files");
    &abort("This system is in real trouble $tmpDir is not writable");
    }
}

$gnatsReportFile   = $tmpDir . '/' . $login . '.cvsgnats'    . $pgrp;
$logFile       = $tmpDir . '/' . $login . '.cvslog'      . $pgrp;

#########################################################################
#
# main
#
#########################################################################

if (! @ARGV) {
    &abort( "No message filename was given. Usage: $0 cvs-log-file\n" );
}

$userLogMessageFile = $ARGV[0];

&create_timestamps();
$hostname = `hostname`;
chop($hostname);

if ($logging) {
    if (!open(LOGFILE, ">> $logFile")) {
    warn "Cannot open log file: $logFile\nturning logging off";
    $logging = 0;
    }

    &log("Start: sys_editinfo attempt by $login at $date");
    &log("Command: $0" . join(' ',@ARGV));
}

&debug("Command: $0 \'" . join('\' \'',@ARGV).'\'');

# $gnatsReportFile will already have built by commitinfo
if ( -e $gnatsReportFile ) {
    &debug("using existing gnats report: $gnatsReportFile");

    # Get bug Id from gnats report
    $bugId = '';
    $bugBranch = '';
    ($bugId, $bugBranch, $headline) =
    &getBugId_from_gnatsreport( $gnatsReportFile );
    $bugBranch =~ s/^-//;   # remove leading dash

    &log("Bug Id $bugId extracted from $gnatsReportFile");
    &log("Headline $headline extracted from $gnatsReportFile");
    &log("Branch \'$bugBranch\' extracted from $gnatsReportFile");

    # If we have a valid bug id, complete bug file names
    if ( $bugId eq '' ) {
    warn "Bug Id not found in GNATS report $gnatsReportFile";
    }
}

@loglines = &read_file( $userLogMessageFile );
if (($bugId ne '') && ($bugId ne 'sync') && ($bugId ne 'new') &&
    ($bugId ne 'placeholder')) {
    if (! grep(/$bugId/, @loglines)) {
    &debug("adding bugid and headline to $userLogMessageFile");
    &debug(">>>$bugId: $headline");
    push(@loglines, $bugId.': '.$headline);
    &write_file( $userLogMessageFile, @loglines );
    }
}
if ($bugBranch ne '') {
    if (! grep(/^Branch:/, @loglines)) {
    &debug("adding Branch information to $userLogMessageFile");
    &debug(">>>Branch: $bugBranch");
    push(@loglines, 'Branch: '.$bugBranch);
    &write_file( $userLogMessageFile, @loglines );
    }
}

$doedit = 1;
while ($doedit) {
    $doedit = 0;
    $diff = 0;

    while (&editFile( $editorCmd, $userLogMessageFile )) {
    print "A non-zero return code usually means that either something\n";
    print "went wrong with your edit session, or you were using vi\n";
    print "and executed a bad command. You may wish to edit $userLogMessageFile\n";
    print "from some other window before answering this next query.\n";
    print "a \'y\' will try the edit command once more and a \'n\'\n";
    print "will fall through and proces the log message at once\n";
    print "Do you wish me to run the command\n";
    $ans = &yes_no("$editorCmd $userLogMessageFile ?", 'n');
    last if ($ans eq 'n');
    }

    @statlines = grep(/^Reviewed by:\s*\S+|^Submitted by:\s*\S+|Obtained from:\s*\S+/, &read_file ( $userLogMessageFile ));

    @loglines = grep(!/^CVS:|^Reviewed by:|^Submitted by:|^Obtained from:/, &read_file( $userLogMessageFile ));

    $orig = join("\n", @loglines);
    $maxlen = 0;
    foreach (@loglines) {
    $save = $_;
    s/[ \t\n]+$//;      # delete trailing space
    1 while s/\t+/' 'x (length($&) * 8 - length($`) % 8)/e; # expand tabs
    s,/\*,/ *,g;        # defuse C Comment start
    s,\*/,* /,g;        # defuse C Comment end
    $diff = 1 if ($save ne $_);
    $maxlen = length($_) if (length($_) > $maxlen);
    }

    if ($maxlen > 72) {
    &write_file( $userLogMessageFile, @loglines );
    open(FMT, "fmt -s $userLogMessageFile |")
        || die "unable to use fmt: $!";
    @loglines = <FMT>;
    close(FMT);

    foreach (@loglines) {
        chop;
        1 while s/\t+/' 'x (length($&) * 8 - length($`) % 8)/e; # expand tabs
    }
    }

    $leading = 200;
    foreach (@loglines) {
    next if /^$/;
    # notice leading whitespace
    ($tmp = $_) =~ s/^(\s*).*$/$1/;
    $leading = length($tmp) if (length($tmp) < $leading);
    }

    # nuke $leading blanks
    if ($leading > 0) {
    &debug("removing $leading leading spaces");
    $tmp = ' ' x $leading;
    foreach (@loglines) {
        s/^$tmp//;
    }
    }
    
    $new = join("\n",@loglines);
    if ($orig ne $new) {
    @loglines = ( @statlines, @loglines );
    &write_file( $userLogMessageFile, @loglines );

    print STDERR "=============== New log text ===============\n";
    print STDERR join("\n", @loglines);
    print STDERR "\n=============== end log text ===============\n\n";
    $ans = &yes_no("Formated log differs from original text. Use it?", 'y');
    exit(0) if ($ans eq 'y');
    $ans = &yes_no("Do you wish to edit the text?", 'y');
    if ($ans eq 'n') {
        $ans = &yes_no("Ok to abort?", 'n');
        &abort("terminated by user request") if ($ans eq 'y');
    }
    $doedit = 1;
    }
}

@loglines = &read_file( $userLogMessageFile );
if (($bugId ne '') && ($bugId ne 'sync') && ($bugId ne 'new') &&
    ($bugId ne 'placeholder')) {
    if (! grep(/$bugId/, @loglines)) {
    print STDERR "\n  Please note that removing $bugId\n";
    print STDERR "  from the log message is not good.\n\n";
    }
}

close(LOGFILE) if ($logging);

exit(0);


#########################################################################
#
# Subroutines
#
#########################################################################


sub abort {
    local( $abortMsg ) = @_;
    die ( "[ERROR] ", "$abortMsg\n" );
}

sub create_timestamps {
    ($sec,$min,$hour,$mday,$mon,$year) = localtime;
    $today  = sprintf("%02d/%02d/%02d", $mon+1, $mday, $year);
    $nowtime    = sprintf("%02d:%02d:%02d", $hour, $min, $sec);
    $date   = $today . ' ' . $nowtime;
}

sub debug {
    print @_, "\n" if ( $debugging );
}

sub editFile {
    local( $editor, $filename ) = @_;
    local( $return_code );

    &debug("editing file: $filename");
    print "invoking editor...\n$editor $filename\n";
    $return_code = system("$editor $filename");
    $return_code = $return_code / 256;
    if ($return_code) {
    print "$editor returned with an error code of $return_code\n";
    }
    $return_code;
}

sub log {
    print LOGFILE @_, "\n" if ($logging);
}

sub read_file {
    local($filename) = @_;
    local(@text);

    &debug("read file $filename");
    open(FILE, "<$filename") || return ();
    while (<FILE>) {
    chop;
    push(@text, $_);
    }
    close(FILE);
    @text;
}

sub write_file {
    local($filename, @lines) = @_;

    &debug("Writing file $filename");
    open(FILE, ">$filename") || die ("Cannot open log file $filename.\n");
    foreach (@lines) {
    print FILE $_, "\n";
    }
    close(FILE);
}

sub getBugId_from_gnatsreport {
    local( $diffsFile ) = @_;
    local( $bug_id, $branch, $headline );

    &debug( "Opening file $diffsFile to get Bug Id");
    open ( GNATSREPORT, $diffsFile ) ||
    &abort( "Can't open gnats report $diffsFile" );

    $bug_id = 'NULL';
    $branch = 'NULL';
    $headline = '';
    # Find the Bug Id
    while ( <GNATSREPORT> ) {
    chop;
    if ( /^Start: / ) {
        ($bug_id = $_) =~ s/[^:]*: //;
        &debug( "Bug Id = $bug_id" );
        $headline = 'syncronization commit' if ($bug_id eq 'sync');
    }
    elsif ( /^Headline:/) {
        ($headline = $_) =~ s/[^:]*://;
        &debug( "Headline = $headline" );
    }
    elsif ( /^Branch: / ) {
        ($branch = $_) =~ s/[^:]*: //;
        if ( $branch eq '' ) {
        &debug( "Branch = \'\' (main trunk)" );
        }
        else {
        &debug( "Branch = $branch" );
        }
    }
    last if (($bug_id ne 'NULL') && ($branch ne 'NULL') &&
         ($headline ne ''));
    }
    close ( GNATSREPORT );
    return ($bug_id, $branch, $headline);
}

# yes_no - ask the user the specified question - repeatedly, until
#      they answer with a valid answer (i.e. yes or no).  Returns
#      "n" or "y".
sub yes_no {
    local($ques, $default) = @_;

    for (;;) {
    print "$ques [$default] ";
    $_ = <STDIN>;
    chop;
    /^[yY]$/ && return "y";
    /^[nN]$/ && return "n";
    return $default if (!$_ && $default);
    }
}