aboutsummaryrefslogtreecommitdiffstats
path: root/CVSROOT/logcheck
blob: b3e235969ba6e05857481756255ff68959473158 (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
#! /usr/bin/perl -w
#
# $FreeBSD$
# 
# This hack is to sanitise the results of what the user may have
# "done" while editing the commit log message.. :-)   Peter Wemm.
#
# Note: this uses an enhancement to cvs's verifymsg functionality.
# Normally, the check is advisory only, the FreeBSD version reads
# back the file after the verifymsg file so that this script can
# make changes.
#

use strict;


############################################################
#
# Configurable options
#
############################################################

# These are the optional headers that can be filled at the end of
# each commit message.  The associated value is a regular-expression
# that is used to type-check the entered value.  If the match failed
# then the commit is rejected.  (See rcstemplate).
my %HEADERS = (
    "Reviewed by"       => '.*',
    "Submitted by"      => '.*',
    "Obtained from"     => '.*',
    "Approved by"       => '.*',
    "PR"            => '.*',
    "MFC after"     => '\d+(?:\s+(?:days?|weeks?|months?))?'
);



#############################################################
#
# Main Body
#
############################################################

my $filename = shift;
die "Usage: logcheck filename\n" unless $filename;




# Read the log file in, stripping 'CVS:' lines and removing trailing
# white spaces.
open IN, "< $filename" or
    die "logcheck: Cannot open for reading: $filename: $!\n";
my @log_in = map { s/^(.*?)\s*$/$1/; $1 } grep { !/^CVS:/ } <IN>;
close IN;

# Remove duplicate blank lines.
my $i = 0;
while ($i < scalar(@log_in) - 1) {
    if ($log_in[$i] eq "" && $log_in[$i + 1] eq "") {
        splice(@log_in, $i, 1);
        next;
        }
        ++$i;
}

# Remove leading and trailing blank lines.  (There will be at most
# one because of the duplicate removal above).
shift @log_in if $log_in[0] eq "";
pop @log_in if $log_in[-1] eq "";

# Scan through the commit message looking for templated headers
# as defined in the configuration file, and rcstemplate.
# Assume that these only exist in the last paragraph.
# Filter out blank entries, and type check if necessary.
my $j = $#log_in;   # The index of the last entry in the commit msg.
my $error = 0;
while ($j >= 0) {
    my $logline = $log_in[$j];

    --$j;

    # Hitting a blank line means that we've seen all of the last paragraph.
    last if $logline eq "";

    unless ($logline =~ /^(.*?):\s*(.*)$/) {
        ### XXX
        # We're here because we saw a line that didn't match
        # a template header (no ':').  This could be a continuation
        # line from the previous header, or the log message proper.
        # We don't know, so run the risk of checking the last paragraph
        # of the log message for headers.
        next;
    }

    my $header = $1;
    my $value = $2;
    my $pattern = $HEADERS{$header};

    # Ignore unrecognised headers.
    unless (defined($pattern)) {
    ###     print "Warning: unknown template header: $header\n";
        next;
    }

    # Filter out the template header if it's blank.
    if ($value eq "") {
        splice(@log_in, $j + 1, 1);
        next;
    }

    # Type check the header
    unless ($value =~ /^$pattern$/) {
        print "Error: $header: should match '$pattern'.\n";
        ++$error;
        next;
    }
}


# Write the modified log file back out.
my $tmpfile = $filename . "tmp";
open OUT, "> $tmpfile" or
    die "logcheck: Cannot open for writing: $tmpfile: $!\n";
print OUT map { "$_\n" } @log_in;
close OUT;


# Stop the commit if there was a problem with the template headers.
if ($error) {
    print "There were $error errors in the template headers.\n";
    print "Please fix the log message and commit again.\n";
    print "A copy of your log message was saved in $tmpfile.\n";
    exit 1;
}



# Nuke likely editor backups.
unlink "$filename.~";
unlink "$filename.bak";


# Overwrite the log message with our sanitised one.  (See the comment
# block at the top of this script for an explaination of why.)
rename($tmpfile, $filename) or
    die "logcheck: Could not rename $tmpfile to $filename: $!";

exit 0;