xref: /illumos-gate/usr/src/tools/onbld/Checks/Comments.py (revision 051aabe6136ff13e81542a427e9693ffe1503525)
1#! /usr/bin/python
2#
3# CDDL HEADER START
4#
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.
8#
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.
13#
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]
19#
20# CDDL HEADER END
21#
22
23#
24# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
25# Use is subject to license terms.
26#
27# ident	"%Z%%M%	%I%	%E% SMI"
28#
29
30#
31# Check delta comments:
32# 	- Have the correct form.
33# 	- Have a synopsis matching that of the CR or ARC case.
34# 	- Appear only once.
35#
36
37import re, sys
38from onbld.Checks.DbLookups import BugDB, ARC
39
40arcre = re.compile(r'^([A-Z][A-Z]*ARC[/ \t][12]\d{3}/\d{3}) (.*)$')
41bugre = re.compile(r'^(\d{7}) (.*)$')
42def isARC(comment):
43	return arcre.match(comment)
44
45def isBug(comment):
46	return bugre.match(comment)
47
48#
49# Translate any acceptable case number format into "<ARC> <YEAR>/<NUM>"
50# format.
51#
52def normalize_arc(caseid):
53	return re.sub(r'^([A-Z][A-Z]*ARC)[/ \t]', '\\1 ', caseid)
54
55def comchk(comments, check_db=True, output=sys.stderr):
56	bugnospcre = re.compile(r'^(\d{7})([^ ].*)')
57	ignorere = re.compile(r'^(Contributed by .*|backout \d{7})')
58
59	errors = { 'bugnospc': [],
60		   'mutant': [],
61		   'dup': [],
62		   'nomatch': [],
63		   'nonexistent': [] }
64	bugs = {}
65	arcs = {}
66	ret = blanks = 0
67
68	for com in comments:
69		# Ignore valid comments we can't check
70		if ignorere.search(com):
71			continue
72
73		if not com or com.isspace():
74			blanks += 1
75			continue
76
77		match = bugre.search(com)
78		if match:
79			if match.group(1) not in bugs:
80				bugs[match.group(1)] = []
81			bugs[match.group(1)].append(match.group(2))
82			continue
83
84		#
85		# Bugs missing a space after the ID are still bugs
86		# for the purposes of the duplicate ID and synopsis
87		# checks.
88		#
89		match = bugnospcre.search(com)
90		if match:
91			if match.group(1) not in bugs:
92				bugs[match.group(1)] = []
93			bugs[match.group(1)].append(match.group(2))
94			errors['bugnospc'].append(com)
95			continue
96
97		# ARC case
98		match = arcre.search(com)
99		if match:
100			case = normalize_arc(match.group(1))
101			if case not in arcs: arcs[case] = []
102			arcs[case].append(match.group(2))
103			continue
104
105		# Anything else is bogus
106		errors['mutant'].append(com)
107
108	if len(bugs) > 0 and check_db:
109		bugdb = BugDB()
110		results = bugdb.lookup(bugs.keys())
111
112	for crid, insts in bugs.iteritems():
113		if len(insts) > 1:
114			errors['dup'].append(crid)
115
116		if not check_db:
117			continue
118
119		if crid not in results:
120			errors['nonexistent'].append(crid)
121			continue
122
123		for entered in insts:
124			synopsis = results[crid]["synopsis"]
125			if not re.search(re.escape(synopsis) +
126					 r'( \([^)]+\))?$', entered):
127				errors['nomatch'].append([crid, synopsis,
128							  entered])
129
130	for case, insts in arcs.iteritems():
131		if len(insts) > 1:
132			errors['dup'].append(case)
133
134		if not check_db:
135			continue
136
137		com, id = case.split(' ')
138		arc = ARC(com, id)
139
140		if not arc.valid():
141			errors['nonexistent'].append(case)
142			continue
143
144		#
145		# The opensolaris.org ARC interfaces only give us the
146		# first 40 characters of the case name, so we must limit
147		# our checking similarly.
148		#
149		# We first try a direct match between the actual case name
150		# and the entered comment.  If that fails we remove a possible
151		# trailing (fix nit)-type comment, and re-try.
152		#
153		for entered in insts:
154			if entered[0:40] == arc.name():
155				continue
156			else:
157				dbcom = re.sub(r' \([^)]+\)$', '', entered)
158				if dbcom[0:40] != arc.name():
159					errors['nomatch'].append([case,
160								  arc.name(),
161								  entered])
162
163	if blanks:
164		output.write("WARNING: Blank line(s) in comments\n")
165		ret = 1
166
167	if errors['dup']:
168		ret = 1
169		output.write("These IDs appear more than once in your "
170			     "comments:\n")
171		for err in errors['dup']:
172			output.write("  %s\n" % err)
173
174	if errors['bugnospc']:
175		ret = 1
176		output.write("These bugs are missing a single space following "
177			     "the ID:\n")
178		for com in errors['bugnospc']:
179			output.write("  %s\n" % com)
180
181	if errors['mutant']:
182		ret = 1
183		output.write("These comments are neither bug nor ARC case:\n")
184		for com in errors['mutant']:
185			output.write("  %s\n" % com)
186
187	if errors['nonexistent']:
188		ret = 1
189		output.write("These bugs/ARC cases were not found in the "
190			     "databases:\n")
191		for id in errors['nonexistent']:
192			output.write("  %s\n" % id)
193
194	if errors['nomatch']:
195		ret = 1
196		output.write("These bugs/ARC case synopsis/names don't match "
197			     "the database entries:\n")
198		for err in errors['nomatch']:
199			output.write("Synopsis/name of %s is wrong:\n" % err[0])
200			output.write("  should be: '%s'\n" % err[1])
201			output.write("         is: '%s'\n" % err[2])
202
203	return ret
204