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