xref: /titanic_50/usr/src/tools/onbld/Checks/Comments.py (revision 41a5f560d7437bb41abade5dce25dc6875da156a)
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#
24*41a5f560SMark J. Nelson# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25cdf0c1d5Smjnelson# Use is subject to license terms.
26cdf0c1d5Smjnelson#
27cdf0c1d5Smjnelson
28cdf0c1d5Smjnelson#
29cdf0c1d5Smjnelson# Check delta comments:
30cdf0c1d5Smjnelson# 	- Have the correct form.
31cdf0c1d5Smjnelson# 	- Have a synopsis matching that of the CR or ARC case.
32cdf0c1d5Smjnelson# 	- Appear only once.
33cdf0c1d5Smjnelson#
34cdf0c1d5Smjnelson
35cdf0c1d5Smjnelsonimport re, sys
36cdf0c1d5Smjnelsonfrom onbld.Checks.DbLookups import BugDB, ARC
37cdf0c1d5Smjnelson
38cdf0c1d5Smjnelsonarcre = re.compile(r'^([A-Z][A-Z]*ARC[/ \t][12]\d{3}/\d{3}) (.*)$')
39cdf0c1d5Smjnelsonbugre = re.compile(r'^(\d{7}) (.*)$')
40ef62fef3SRichard Lowe
41cdf0c1d5Smjnelsondef isARC(comment):
42cdf0c1d5Smjnelson	return arcre.match(comment)
43cdf0c1d5Smjnelson
44cdf0c1d5Smjnelsondef isBug(comment):
45cdf0c1d5Smjnelson	return bugre.match(comment)
46cdf0c1d5Smjnelson
47cdf0c1d5Smjnelson#
48cdf0c1d5Smjnelson# Translate any acceptable case number format into "<ARC> <YEAR>/<NUM>"
49cdf0c1d5Smjnelson# format.
50cdf0c1d5Smjnelson#
51cdf0c1d5Smjnelsondef normalize_arc(caseid):
52cdf0c1d5Smjnelson	return re.sub(r'^([A-Z][A-Z]*ARC)[/ \t]', '\\1 ', caseid)
53cdf0c1d5Smjnelson
54*41a5f560SMark J. Nelsondef comchk(comments, check_db=True, output=sys.stderr, arcPath=None):
55ef62fef3SRichard Lowe	'''Validate checkin comments against ON standards.
56ef62fef3SRichard Lowe
57ef62fef3SRichard Lowe	Comments must be a list of one-line comments, with no trailing
58ef62fef3SRichard Lowe	newline.
59ef62fef3SRichard Lowe
60ef62fef3SRichard Lowe	If check_db is True (the default), validate CR and ARC
61ef62fef3SRichard Lowe	synopses against the databases.
62ef62fef3SRichard Lowe
63ef62fef3SRichard Lowe	Error messages intended for the user are written to output,
64ef62fef3SRichard Lowe	which defaults to stderr
65ef62fef3SRichard Lowe	'''
66cdf0c1d5Smjnelson	bugnospcre = re.compile(r'^(\d{7})([^ ].*)')
67aa46c263SJohn Beck	ignorere = re.compile(r'^(Portions contributed by |Contributed by |back[ -]?out )')
68cdf0c1d5Smjnelson
69cdf0c1d5Smjnelson	errors = { 'bugnospc': [],
70cdf0c1d5Smjnelson		   'mutant': [],
71cdf0c1d5Smjnelson		   'dup': [],
72cdf0c1d5Smjnelson		   'nomatch': [],
73cdf0c1d5Smjnelson		   'nonexistent': [] }
74cdf0c1d5Smjnelson	bugs = {}
75cdf0c1d5Smjnelson	arcs = {}
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		# ARC case
113cdf0c1d5Smjnelson		match = arcre.search(com)
114cdf0c1d5Smjnelson		if match:
115c08a253cSJohn Sonnenschein			arc, case = re.split('[/ \t]', match.group(1), 1)
116c08a253cSJohn Sonnenschein			arcs.setdefault((arc, case), []).append(match.group(2))
117cdf0c1d5Smjnelson			continue
118cdf0c1d5Smjnelson
119cdf0c1d5Smjnelson		# Anything else is bogus
120cdf0c1d5Smjnelson		errors['mutant'].append(com)
121cdf0c1d5Smjnelson
122cdf0c1d5Smjnelson	if len(bugs) > 0 and check_db:
123cdf0c1d5Smjnelson		bugdb = BugDB()
124cdf0c1d5Smjnelson		results = bugdb.lookup(bugs.keys())
125cdf0c1d5Smjnelson
126cdf0c1d5Smjnelson	for crid, insts in bugs.iteritems():
127cdf0c1d5Smjnelson		if len(insts) > 1:
128cdf0c1d5Smjnelson			errors['dup'].append(crid)
129cdf0c1d5Smjnelson
130cdf0c1d5Smjnelson		if not check_db:
131cdf0c1d5Smjnelson			continue
132cdf0c1d5Smjnelson
133cdf0c1d5Smjnelson		if crid not in results:
134cdf0c1d5Smjnelson			errors['nonexistent'].append(crid)
135cdf0c1d5Smjnelson			continue
136cdf0c1d5Smjnelson
137ef62fef3SRichard Lowe		#
138ef62fef3SRichard Lowe		# For each synopsis, compare the real synopsis with
139ef62fef3SRichard Lowe		# that in the comments, allowing for possible '(fix
140ef62fef3SRichard Lowe		# stuff)'-like trailing text
141ef62fef3SRichard Lowe		#
142cdf0c1d5Smjnelson		for entered in insts:
143cdf0c1d5Smjnelson			synopsis = results[crid]["synopsis"]
144ef62fef3SRichard Lowe			if not re.search(r'^' + re.escape(synopsis) +
145cdf0c1d5Smjnelson					r'( \([^)]+\))?$', entered):
146cdf0c1d5Smjnelson				errors['nomatch'].append([crid, synopsis,
147cdf0c1d5Smjnelson							entered])
148cdf0c1d5Smjnelson
149c08a253cSJohn Sonnenschein	if check_db:
150*41a5f560SMark J. Nelson		valid = ARC(arcs.keys(), arcPath)
151c08a253cSJohn Sonnenschein
152cdf0c1d5Smjnelson	for case, insts in arcs.iteritems():
153cdf0c1d5Smjnelson		if len(insts) > 1:
154c08a253cSJohn Sonnenschein			errors['dup'].append(' '.join(case))
155cdf0c1d5Smjnelson
156cdf0c1d5Smjnelson 		if not check_db:
157cdf0c1d5Smjnelson			continue
158cdf0c1d5Smjnelson
159c08a253cSJohn Sonnenschein		if not case in valid:
160c08a253cSJohn Sonnenschein			errors['nonexistent'].append(' '.join(case))
161cdf0c1d5Smjnelson			continue
162*41a5f560SMark J. Nelson
163cdf0c1d5Smjnelson		#
164cdf0c1d5Smjnelson		# We first try a direct match between the actual case name
165cdf0c1d5Smjnelson		# and the entered comment.  If that fails we remove a possible
166cdf0c1d5Smjnelson		# trailing (fix nit)-type comment, and re-try.
167cdf0c1d5Smjnelson		#
168cdf0c1d5Smjnelson		for entered in insts:
169*41a5f560SMark J. Nelson			if entered == valid[case]:
170c08a253cSJohn Sonnenschein				break
171cdf0c1d5Smjnelson			else:
172ef62fef3SRichard Lowe				# Try again with trailing (fix ...) removed.
173cdf0c1d5Smjnelson				dbcom = re.sub(r' \([^)]+\)$', '', entered)
174*41a5f560SMark J. Nelson				if dbcom != valid[case]:
175c08a253cSJohn Sonnenschein					errors['nomatch'].append(
176c08a253cSJohn Sonnenschein						[' '.join(case), valid[case],
177cdf0c1d5Smjnelson						 entered])
178cdf0c1d5Smjnelson
179cdf0c1d5Smjnelson	if blanks:
180cdf0c1d5Smjnelson		output.write("WARNING: Blank line(s) in comments\n")
181cdf0c1d5Smjnelson		ret = 1
182cdf0c1d5Smjnelson
183cdf0c1d5Smjnelson	if errors['dup']:
184cdf0c1d5Smjnelson		ret = 1
185cdf0c1d5Smjnelson		output.write("These IDs appear more than once in your "
186cdf0c1d5Smjnelson			     "comments:\n")
187cdf0c1d5Smjnelson		for err in errors['dup']:
188cdf0c1d5Smjnelson			output.write("  %s\n" % err)
189cdf0c1d5Smjnelson
190cdf0c1d5Smjnelson	if errors['bugnospc']:
191cdf0c1d5Smjnelson		ret = 1
192cdf0c1d5Smjnelson		output.write("These bugs are missing a single space following "
193cdf0c1d5Smjnelson			     "the ID:\n")
194cdf0c1d5Smjnelson		for com in errors['bugnospc']:
195cdf0c1d5Smjnelson			output.write("  %s\n" % com)
196cdf0c1d5Smjnelson
197cdf0c1d5Smjnelson	if errors['mutant']:
198cdf0c1d5Smjnelson		ret = 1
199cdf0c1d5Smjnelson		output.write("These comments are neither bug nor ARC case:\n")
200cdf0c1d5Smjnelson		for com in errors['mutant']:
201cdf0c1d5Smjnelson			output.write("  %s\n" % com)
202cdf0c1d5Smjnelson
203cdf0c1d5Smjnelson	if errors['nonexistent']:
204cdf0c1d5Smjnelson		ret = 1
205cdf0c1d5Smjnelson		output.write("These bugs/ARC cases were not found in the "
206cdf0c1d5Smjnelson			     "databases:\n")
207cdf0c1d5Smjnelson		for id in errors['nonexistent']:
208cdf0c1d5Smjnelson			output.write("  %s\n" % id)
209cdf0c1d5Smjnelson
210cdf0c1d5Smjnelson	if errors['nomatch']:
211cdf0c1d5Smjnelson		ret = 1
212cdf0c1d5Smjnelson		output.write("These bugs/ARC case synopsis/names don't match "
213cdf0c1d5Smjnelson			     "the database entries:\n")
214cdf0c1d5Smjnelson		for err in errors['nomatch']:
215cdf0c1d5Smjnelson			output.write("Synopsis/name of %s is wrong:\n" % err[0])
216cdf0c1d5Smjnelson			output.write("  should be: '%s'\n" % err[1])
217cdf0c1d5Smjnelson			output.write("         is: '%s'\n" % err[2])
218cdf0c1d5Smjnelson
219cdf0c1d5Smjnelson	return ret
220