43 development tools should be adjusted to understand the brave new world
[illumos-gate.git] / usr / src / tools / onbld / Checks / Comments.py
blobdaf6aa47d90a56224c511c981deb1d65e55463e9
1 #! /usr/bin/python
3 # CDDL HEADER START
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
20 # CDDL HEADER END
24 # Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 # Use is subject to license terms.
28 # Copyright 2007, 2010 Richard Lowe
31 # Check delta comments:
32 # - Have the correct form.
33 # - Have a synopsis matching that of the bug
34 # - Appear only once.
37 import re, sys
38 from onbld.Checks.DbLookups import BugDB
41 bugre = re.compile(r'^(\d{2,7}) (.*)$')
44 def isBug(comment):
45 return bugre.match(comment)
48 def comchk(comments, check_db=True, output=sys.stderr):
49 '''Validate checkin comments against ON standards.
51 Comments must be a list of one-line comments, with no trailing
52 newline.
54 If check_db is True (the default), validate bug synopses against the
55 databases.
57 Error messages intended for the user are written to output,
58 which defaults to stderr
59 '''
60 bugnospcre = re.compile(r'^(\d{2,7})([^ ].*)')
61 ignorere = re.compile(r'^(' +
62 r'Portions contributed by|' +
63 r'Contributed by|' +
64 r'Reviewed[ -]by|' +
65 r'Approved[ -]by|' +
66 r'back[ -]?out)' +
67 r'[: ]')
69 errors = { 'bugnospc': [],
70 'mutant': [],
71 'dup': [],
72 'nomatch': [],
73 'nonexistent': [] }
74 bugs = {}
75 ret = 0
76 blanks = False
78 for com in comments:
79 # Our input must be newline-free, comments are line-wise.
80 if com.find('\n') != -1:
81 raise ValueError("newline in comment '%s'" % com)
83 # Ignore valid comments we can't check
84 if ignorere.search(com):
85 continue
87 if not com or com.isspace():
88 blanks = True
89 continue
91 match = bugre.search(com)
92 if match:
93 if match.group(1) not in bugs:
94 bugs[match.group(1)] = []
95 bugs[match.group(1)].append(match.group(2))
96 continue
99 # Bugs missing a space after the ID are still bugs
100 # for the purposes of the duplicate ID and synopsis
101 # checks.
103 match = bugnospcre.search(com)
104 if match:
105 if match.group(1) not in bugs:
106 bugs[match.group(1)] = []
107 bugs[match.group(1)].append(match.group(2))
108 errors['bugnospc'].append(com)
109 continue
111 # Anything else is bogus
112 errors['mutant'].append(com)
114 if len(bugs) > 0 and check_db:
115 bugdb = BugDB()
116 results = bugdb.lookup(bugs.keys())
118 for crid, insts in bugs.iteritems():
119 if len(insts) > 1:
120 errors['dup'].append(crid)
122 if not check_db:
123 continue
125 if crid not in results:
126 errors['nonexistent'].append(crid)
127 continue
130 # For each synopsis, compare the real synopsis with
131 # that in the comments, allowing for possible '(fix
132 # stuff)'-like trailing text
134 for entered in insts:
135 synopsis = results[crid]["synopsis"]
136 if not re.search(r'^' + re.escape(synopsis) +
137 r'( \([^)]+\))?$', entered):
138 errors['nomatch'].append([crid, synopsis,
139 entered])
142 if blanks:
143 output.write("WARNING: Blank line(s) in comments\n")
144 ret = 1
146 if errors['dup']:
147 ret = 1
148 output.write("These IDs appear more than once in your "
149 "comments:\n")
150 for err in errors['dup']:
151 output.write(" %s\n" % err)
153 if errors['bugnospc']:
154 ret = 1
155 output.write("These bugs are missing a single space following "
156 "the ID:\n")
157 for com in errors['bugnospc']:
158 output.write(" %s\n" % com)
160 if errors['mutant']:
161 ret = 1
162 output.write("These comments are not valid bugs:\n")
163 for com in errors['mutant']:
164 output.write(" %s\n" % com)
166 if errors['nonexistent']:
167 ret = 1
168 output.write("These bugs were not found in the databases:\n")
169 for id in errors['nonexistent']:
170 output.write(" %s\n" % id)
172 if errors['nomatch']:
173 ret = 1
174 output.write("These bug synopses don't match "
175 "the database entries:\n")
176 for err in errors['nomatch']:
177 output.write("Synopsis of %s is wrong:\n" % err[0])
178 output.write(" should be: '%s'\n" % err[1])
179 output.write(" is: '%s'\n" % err[2])
181 return ret