xref: /titanic_51/usr/src/tools/onbld/Checks/Comments.py (revision 93be19b94b8b631e9abb3b71f9415817c441c051)
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
282f54b716SRichard Lowe# Copyright 2007, 2010 Richard Lowe
29*93be19b9SAndy Fiddaman# Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
302f54b716SRichard Lowe
31cdf0c1d5Smjnelson#
32cdf0c1d5Smjnelson# Check delta comments:
33cdf0c1d5Smjnelson#	- Have the correct form.
342f54b716SRichard Lowe#	- Have a synopsis matching that of the bug
35cdf0c1d5Smjnelson#	- Appear only once.
36cdf0c1d5Smjnelson#
37cdf0c1d5Smjnelson
38cdf0c1d5Smjnelsonimport re, sys
392f54b716SRichard Lowefrom onbld.Checks.DbLookups import BugDB
40cdf0c1d5Smjnelson
41ef62fef3SRichard Lowe
422f54b716SRichard Lowebugre = re.compile(r'^(\d{2,7}) (.*)$')
432f54b716SRichard Lowe
44cdf0c1d5Smjnelson
45cdf0c1d5Smjnelsondef isBug(comment):
46cdf0c1d5Smjnelson	return bugre.match(comment)
47cdf0c1d5Smjnelson
48cdf0c1d5Smjnelson
492f54b716SRichard Lowedef comchk(comments, check_db=True, output=sys.stderr):
50ef62fef3SRichard Lowe	'''Validate checkin comments against ON standards.
51ef62fef3SRichard Lowe
52ef62fef3SRichard Lowe	Comments must be a list of one-line comments, with no trailing
53ef62fef3SRichard Lowe	newline.
54ef62fef3SRichard Lowe
552f54b716SRichard Lowe	If check_db is True (the default), validate bug synopses against the
562f54b716SRichard Lowe	databases.
57ef62fef3SRichard Lowe
58ef62fef3SRichard Lowe	Error messages intended for the user are written to output,
59ef62fef3SRichard Lowe	which defaults to stderr
60ef62fef3SRichard Lowe	'''
612f54b716SRichard Lowe	bugnospcre = re.compile(r'^(\d{2,7})([^ ].*)')
622f54b716SRichard Lowe	ignorere = re.compile(r'^(' +
632f54b716SRichard Lowe                              r'Portions contributed by|' +
642f54b716SRichard Lowe                              r'Contributed by|' +
652f54b716SRichard Lowe                              r'Reviewed[ -]by|' +
662f54b716SRichard Lowe                              r'Approved[ -]by|' +
672f54b716SRichard Lowe                              r'back[ -]?out)' +
682f54b716SRichard Lowe                              r'[: ]')
69cdf0c1d5Smjnelson
70cdf0c1d5Smjnelson	errors = { 'bugnospc': [],
71cdf0c1d5Smjnelson		   'mutant': [],
72cdf0c1d5Smjnelson		   'dup': [],
73cdf0c1d5Smjnelson		   'nomatch': [],
74cdf0c1d5Smjnelson		   'nonexistent': [] }
75cdf0c1d5Smjnelson	bugs = {}
76ef62fef3SRichard Lowe	ret = 0
77ef62fef3SRichard Lowe	blanks = False
78cdf0c1d5Smjnelson
79cdf0c1d5Smjnelson	for com in comments:
80ef62fef3SRichard Lowe		# Our input must be newline-free, comments are line-wise.
81ef62fef3SRichard Lowe		if com.find('\n') != -1:
82ef62fef3SRichard Lowe			raise ValueError("newline in comment '%s'" % com)
83ef62fef3SRichard Lowe
84cdf0c1d5Smjnelson		# Ignore valid comments we can't check
85cdf0c1d5Smjnelson		if ignorere.search(com):
86cdf0c1d5Smjnelson			continue
87cdf0c1d5Smjnelson
88cdf0c1d5Smjnelson		if not com or com.isspace():
89ef62fef3SRichard Lowe			blanks = True
90cdf0c1d5Smjnelson			continue
91cdf0c1d5Smjnelson
92cdf0c1d5Smjnelson		match = bugre.search(com)
93cdf0c1d5Smjnelson		if match:
94cdf0c1d5Smjnelson			if match.group(1) not in bugs:
95cdf0c1d5Smjnelson				bugs[match.group(1)] = []
96cdf0c1d5Smjnelson			bugs[match.group(1)].append(match.group(2))
97cdf0c1d5Smjnelson			continue
98cdf0c1d5Smjnelson
99cdf0c1d5Smjnelson		#
100cdf0c1d5Smjnelson		# Bugs missing a space after the ID are still bugs
101cdf0c1d5Smjnelson		# for the purposes of the duplicate ID and synopsis
102cdf0c1d5Smjnelson		# checks.
103cdf0c1d5Smjnelson		#
104cdf0c1d5Smjnelson		match = bugnospcre.search(com)
105cdf0c1d5Smjnelson		if match:
106cdf0c1d5Smjnelson			if match.group(1) not in bugs:
107cdf0c1d5Smjnelson				bugs[match.group(1)] = []
108cdf0c1d5Smjnelson			bugs[match.group(1)].append(match.group(2))
109cdf0c1d5Smjnelson			errors['bugnospc'].append(com)
110cdf0c1d5Smjnelson			continue
111cdf0c1d5Smjnelson
112cdf0c1d5Smjnelson		# Anything else is bogus
113cdf0c1d5Smjnelson		errors['mutant'].append(com)
114cdf0c1d5Smjnelson
115cdf0c1d5Smjnelson	if len(bugs) > 0 and check_db:
116cdf0c1d5Smjnelson		bugdb = BugDB()
117*93be19b9SAndy Fiddaman		results = bugdb.lookup(list(bugs.keys()))
118cdf0c1d5Smjnelson
119*93be19b9SAndy Fiddaman	for crid, insts in bugs.items():
120cdf0c1d5Smjnelson		if len(insts) > 1:
121cdf0c1d5Smjnelson			errors['dup'].append(crid)
122cdf0c1d5Smjnelson
123cdf0c1d5Smjnelson		if not check_db:
124cdf0c1d5Smjnelson			continue
125cdf0c1d5Smjnelson
126cdf0c1d5Smjnelson		if crid not in results:
127cdf0c1d5Smjnelson			errors['nonexistent'].append(crid)
128cdf0c1d5Smjnelson			continue
129cdf0c1d5Smjnelson
130ef62fef3SRichard Lowe		#
131ef62fef3SRichard Lowe		# For each synopsis, compare the real synopsis with
132ef62fef3SRichard Lowe		# that in the comments, allowing for possible '(fix
133ef62fef3SRichard Lowe		# stuff)'-like trailing text
134ef62fef3SRichard Lowe		#
135cdf0c1d5Smjnelson		for entered in insts:
136cdf0c1d5Smjnelson			synopsis = results[crid]["synopsis"]
137ef62fef3SRichard Lowe			if not re.search(r'^' + re.escape(synopsis) +
138cdf0c1d5Smjnelson					r'( \([^)]+\))?$', entered):
139cdf0c1d5Smjnelson				errors['nomatch'].append([crid, synopsis,
140cdf0c1d5Smjnelson							entered])
141cdf0c1d5Smjnelson
142cdf0c1d5Smjnelson
143cdf0c1d5Smjnelson	if blanks:
144cdf0c1d5Smjnelson		output.write("WARNING: Blank line(s) in comments\n")
145cdf0c1d5Smjnelson		ret = 1
146cdf0c1d5Smjnelson
147cdf0c1d5Smjnelson	if errors['dup']:
148cdf0c1d5Smjnelson		ret = 1
149cdf0c1d5Smjnelson		output.write("These IDs appear more than once in your "
150cdf0c1d5Smjnelson			     "comments:\n")
151cdf0c1d5Smjnelson		for err in errors['dup']:
152cdf0c1d5Smjnelson			output.write("  %s\n" % err)
153cdf0c1d5Smjnelson
154cdf0c1d5Smjnelson	if errors['bugnospc']:
155cdf0c1d5Smjnelson		ret = 1
156cdf0c1d5Smjnelson		output.write("These bugs are missing a single space following "
157cdf0c1d5Smjnelson			     "the ID:\n")
158cdf0c1d5Smjnelson		for com in errors['bugnospc']:
159cdf0c1d5Smjnelson			output.write("  %s\n" % com)
160cdf0c1d5Smjnelson
161cdf0c1d5Smjnelson	if errors['mutant']:
162cdf0c1d5Smjnelson		ret = 1
1632f54b716SRichard Lowe		output.write("These comments are not valid bugs:\n")
164cdf0c1d5Smjnelson		for com in errors['mutant']:
165cdf0c1d5Smjnelson			output.write("  %s\n" % com)
166cdf0c1d5Smjnelson
167cdf0c1d5Smjnelson	if errors['nonexistent']:
168cdf0c1d5Smjnelson		ret = 1
1692f54b716SRichard Lowe		output.write("These bugs were not found in the databases:\n")
170cdf0c1d5Smjnelson		for id in errors['nonexistent']:
171cdf0c1d5Smjnelson			output.write("  %s\n" % id)
172cdf0c1d5Smjnelson
173cdf0c1d5Smjnelson	if errors['nomatch']:
174cdf0c1d5Smjnelson		ret = 1
1752f54b716SRichard Lowe		output.write("These bug synopses don't match "
176cdf0c1d5Smjnelson			     "the database entries:\n")
177cdf0c1d5Smjnelson		for err in errors['nomatch']:
1782f54b716SRichard Lowe			output.write("Synopsis of %s is wrong:\n" % err[0])
179cdf0c1d5Smjnelson			output.write("  should be: '%s'\n" % err[1])
180cdf0c1d5Smjnelson			output.write("         is: '%s'\n" % err[2])
181cdf0c1d5Smjnelson
182cdf0c1d5Smjnelson	return ret
183