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