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}) (.*)$') 40 41def isARC(comment): 42 return arcre.match(comment) 43 44def isBug(comment): 45 return bugre.match(comment) 46 47# 48# Translate any acceptable case number format into "<ARC> <YEAR>/<NUM>" 49# format. 50# 51def normalize_arc(caseid): 52 return re.sub(r'^([A-Z][A-Z]*ARC)[/ \t]', '\\1 ', caseid) 53 54def comchk(comments, check_db=True, output=sys.stderr): 55 '''Validate checkin comments against ON standards. 56 57 Comments must be a list of one-line comments, with no trailing 58 newline. 59 60 If check_db is True (the default), validate CR and ARC 61 synopses against the databases. 62 63 Error messages intended for the user are written to output, 64 which defaults to stderr 65 ''' 66 bugnospcre = re.compile(r'^(\d{7})([^ ].*)') 67 ignorere = re.compile(r'^(Portions contributed by |Contributed by |back[ -]?out )') 68 69 errors = { 'bugnospc': [], 70 'mutant': [], 71 'dup': [], 72 'nomatch': [], 73 'nonexistent': [] } 74 bugs = {} 75 arcs = {} 76 ret = 0 77 blanks = False 78 79 for com in comments: 80 # Our input must be newline-free, comments are line-wise. 81 if com.find('\n') != -1: 82 raise ValueError("newline in comment '%s'" % com) 83 84 # Ignore valid comments we can't check 85 if ignorere.search(com): 86 continue 87 88 if not com or com.isspace(): 89 blanks = True 90 continue 91 92 match = bugre.search(com) 93 if match: 94 if match.group(1) not in bugs: 95 bugs[match.group(1)] = [] 96 bugs[match.group(1)].append(match.group(2)) 97 continue 98 99 # 100 # Bugs missing a space after the ID are still bugs 101 # for the purposes of the duplicate ID and synopsis 102 # checks. 103 # 104 match = bugnospcre.search(com) 105 if match: 106 if match.group(1) not in bugs: 107 bugs[match.group(1)] = [] 108 bugs[match.group(1)].append(match.group(2)) 109 errors['bugnospc'].append(com) 110 continue 111 112 # ARC case 113 match = arcre.search(com) 114 if match: 115 case = normalize_arc(match.group(1)) 116 if case not in arcs: arcs[case] = [] 117 arcs[case].append(match.group(2)) 118 continue 119 120 # Anything else is bogus 121 errors['mutant'].append(com) 122 123 if len(bugs) > 0 and check_db: 124 bugdb = BugDB() 125 results = bugdb.lookup(bugs.keys()) 126 127 for crid, insts in bugs.iteritems(): 128 if len(insts) > 1: 129 errors['dup'].append(crid) 130 131 if not check_db: 132 continue 133 134 if crid not in results: 135 errors['nonexistent'].append(crid) 136 continue 137 138 # 139 # For each synopsis, compare the real synopsis with 140 # that in the comments, allowing for possible '(fix 141 # stuff)'-like trailing text 142 # 143 for entered in insts: 144 synopsis = results[crid]["synopsis"] 145 if not re.search(r'^' + re.escape(synopsis) + 146 r'( \([^)]+\))?$', entered): 147 errors['nomatch'].append([crid, synopsis, 148 entered]) 149 150 for case, insts in arcs.iteritems(): 151 if len(insts) > 1: 152 errors['dup'].append(case) 153 154 if not check_db: 155 continue 156 157 com, id = case.split(' ') 158 arc = ARC(com, id) 159 160 if not arc.valid(): 161 errors['nonexistent'].append(case) 162 continue 163 164 # 165 # The opensolaris.org ARC interfaces only give us the 166 # first 40 characters of the case name, so we must limit 167 # our checking similarly. 168 # 169 # We first try a direct match between the actual case name 170 # and the entered comment. If that fails we remove a possible 171 # trailing (fix nit)-type comment, and re-try. 172 # 173 for entered in insts: 174 if entered[0:40] == arc.name(): 175 continue 176 else: 177 # Try again with trailing (fix ...) removed. 178 dbcom = re.sub(r' \([^)]+\)$', '', entered) 179 if dbcom[0:40] != arc.name(): 180 errors['nomatch'].append([case, 181 arc.name(), 182 entered]) 183 184 if blanks: 185 output.write("WARNING: Blank line(s) in comments\n") 186 ret = 1 187 188 if errors['dup']: 189 ret = 1 190 output.write("These IDs appear more than once in your " 191 "comments:\n") 192 for err in errors['dup']: 193 output.write(" %s\n" % err) 194 195 if errors['bugnospc']: 196 ret = 1 197 output.write("These bugs are missing a single space following " 198 "the ID:\n") 199 for com in errors['bugnospc']: 200 output.write(" %s\n" % com) 201 202 if errors['mutant']: 203 ret = 1 204 output.write("These comments are neither bug nor ARC case:\n") 205 for com in errors['mutant']: 206 output.write(" %s\n" % com) 207 208 if errors['nonexistent']: 209 ret = 1 210 output.write("These bugs/ARC cases were not found in the " 211 "databases:\n") 212 for id in errors['nonexistent']: 213 output.write(" %s\n" % id) 214 215 if errors['nomatch']: 216 ret = 1 217 output.write("These bugs/ARC case synopsis/names don't match " 218 "the database entries:\n") 219 for err in errors['nomatch']: 220 output.write("Synopsis/name of %s is wrong:\n" % err[0]) 221 output.write(" should be: '%s'\n" % err[1]) 222 output.write(" is: '%s'\n" % err[2]) 223 224 return ret 225