17078Smjnelson#! /usr/bin/python 27078Smjnelson# 37078Smjnelson# CDDL HEADER START 47078Smjnelson# 57078Smjnelson# The contents of this file are subject to the terms of the 67078Smjnelson# Common Development and Distribution License (the "License"). 77078Smjnelson# You may not use this file except in compliance with the License. 87078Smjnelson# 97078Smjnelson# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107078Smjnelson# or http://www.opensolaris.org/os/licensing. 117078Smjnelson# See the License for the specific language governing permissions 127078Smjnelson# and limitations under the License. 137078Smjnelson# 147078Smjnelson# When distributing Covered Code, include this CDDL HEADER in each 157078Smjnelson# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167078Smjnelson# If applicable, add the following below this CDDL HEADER, with the 177078Smjnelson# fields enclosed by brackets "[]" replaced with your own identifying 187078Smjnelson# information: Portions Copyright [yyyy] [name of copyright owner] 197078Smjnelson# 207078Smjnelson# CDDL HEADER END 217078Smjnelson# 227078Smjnelson 237078Smjnelson# 24*9920SMark.J.Nelson@Sun.COM# Copyright 2009 Sun Microsystems, Inc. All rights reserved. 257078Smjnelson# Use is subject to license terms. 267078Smjnelson# 277078Smjnelson 287078Smjnelson# 297078Smjnelson# Check delta comments: 307078Smjnelson# - Have the correct form. 317078Smjnelson# - Have a synopsis matching that of the CR or ARC case. 327078Smjnelson# - Appear only once. 337078Smjnelson# 347078Smjnelson 357078Smjnelsonimport re, sys 367078Smjnelsonfrom onbld.Checks.DbLookups import BugDB, ARC 377078Smjnelson 387078Smjnelsonarcre = re.compile(r'^([A-Z][A-Z]*ARC[/ \t][12]\d{3}/\d{3}) (.*)$') 397078Smjnelsonbugre = re.compile(r'^(\d{7}) (.*)$') 407711Srichlowe@richlowe.net 417078Smjnelsondef isARC(comment): 427078Smjnelson return arcre.match(comment) 437078Smjnelson 447078Smjnelsondef isBug(comment): 457078Smjnelson return bugre.match(comment) 467078Smjnelson 477078Smjnelson# 487078Smjnelson# Translate any acceptable case number format into "<ARC> <YEAR>/<NUM>" 497078Smjnelson# format. 507078Smjnelson# 517078Smjnelsondef normalize_arc(caseid): 527078Smjnelson return re.sub(r'^([A-Z][A-Z]*ARC)[/ \t]', '\\1 ', caseid) 537078Smjnelson 54*9920SMark.J.Nelson@Sun.COMdef comchk(comments, check_db=True, output=sys.stderr, arcPath=None): 558042SJohn.Sonnenschein@Sun.COM '''Validate checkin comments against ON standards. 567711Srichlowe@richlowe.net 578042SJohn.Sonnenschein@Sun.COM Comments must be a list of one-line comments, with no trailing 588042SJohn.Sonnenschein@Sun.COM newline. 598042SJohn.Sonnenschein@Sun.COM 608042SJohn.Sonnenschein@Sun.COM If check_db is True (the default), validate CR and ARC 618042SJohn.Sonnenschein@Sun.COM synopses against the databases. 627711Srichlowe@richlowe.net 638042SJohn.Sonnenschein@Sun.COM Error messages intended for the user are written to output, 648042SJohn.Sonnenschein@Sun.COM which defaults to stderr 658042SJohn.Sonnenschein@Sun.COM ''' 667078Smjnelson bugnospcre = re.compile(r'^(\d{7})([^ ].*)') 677321SJohn.Beck@Sun.COM ignorere = re.compile(r'^(Portions contributed by |Contributed by |back[ -]?out )') 687078Smjnelson 697078Smjnelson errors = { 'bugnospc': [], 707078Smjnelson 'mutant': [], 717078Smjnelson 'dup': [], 727078Smjnelson 'nomatch': [], 737078Smjnelson 'nonexistent': [] } 747078Smjnelson bugs = {} 757078Smjnelson arcs = {} 767711Srichlowe@richlowe.net ret = 0 777711Srichlowe@richlowe.net blanks = False 787078Smjnelson 797078Smjnelson for com in comments: 808042SJohn.Sonnenschein@Sun.COM # Our input must be newline-free, comments are line-wise. 818042SJohn.Sonnenschein@Sun.COM if com.find('\n') != -1: 828042SJohn.Sonnenschein@Sun.COM raise ValueError("newline in comment '%s'" % com) 838042SJohn.Sonnenschein@Sun.COM 847078Smjnelson # Ignore valid comments we can't check 857078Smjnelson if ignorere.search(com): 867078Smjnelson continue 877078Smjnelson 887078Smjnelson if not com or com.isspace(): 897711Srichlowe@richlowe.net blanks = True 907078Smjnelson continue 917078Smjnelson 927078Smjnelson match = bugre.search(com) 937078Smjnelson if match: 947078Smjnelson if match.group(1) not in bugs: 957078Smjnelson bugs[match.group(1)] = [] 967078Smjnelson bugs[match.group(1)].append(match.group(2)) 977078Smjnelson continue 987078Smjnelson 997078Smjnelson # 1007078Smjnelson # Bugs missing a space after the ID are still bugs 1017078Smjnelson # for the purposes of the duplicate ID and synopsis 1027078Smjnelson # checks. 1037078Smjnelson # 1047078Smjnelson match = bugnospcre.search(com) 1057078Smjnelson if match: 1067078Smjnelson if match.group(1) not in bugs: 1077078Smjnelson bugs[match.group(1)] = [] 1087078Smjnelson bugs[match.group(1)].append(match.group(2)) 1097078Smjnelson errors['bugnospc'].append(com) 1107078Smjnelson continue 1117078Smjnelson 1127078Smjnelson # ARC case 1137078Smjnelson match = arcre.search(com) 1147078Smjnelson if match: 1158042SJohn.Sonnenschein@Sun.COM arc, case = re.split('[/ \t]', match.group(1), 1) 1168042SJohn.Sonnenschein@Sun.COM arcs.setdefault((arc, case), []).append(match.group(2)) 1177078Smjnelson continue 1187078Smjnelson 1197078Smjnelson # Anything else is bogus 1207078Smjnelson errors['mutant'].append(com) 1217078Smjnelson 1227078Smjnelson if len(bugs) > 0 and check_db: 1237078Smjnelson bugdb = BugDB() 1247078Smjnelson results = bugdb.lookup(bugs.keys()) 1257078Smjnelson 1267078Smjnelson for crid, insts in bugs.iteritems(): 1277078Smjnelson if len(insts) > 1: 1287078Smjnelson errors['dup'].append(crid) 1297078Smjnelson 1307078Smjnelson if not check_db: 1317078Smjnelson continue 1327078Smjnelson 1337078Smjnelson if crid not in results: 1347078Smjnelson errors['nonexistent'].append(crid) 1357078Smjnelson continue 1367078Smjnelson 1377711Srichlowe@richlowe.net # 1387711Srichlowe@richlowe.net # For each synopsis, compare the real synopsis with 1397711Srichlowe@richlowe.net # that in the comments, allowing for possible '(fix 1407711Srichlowe@richlowe.net # stuff)'-like trailing text 1417711Srichlowe@richlowe.net # 1427078Smjnelson for entered in insts: 1437078Smjnelson synopsis = results[crid]["synopsis"] 1447711Srichlowe@richlowe.net if not re.search(r'^' + re.escape(synopsis) + 1458042SJohn.Sonnenschein@Sun.COM r'( \([^)]+\))?$', entered): 1467078Smjnelson errors['nomatch'].append([crid, synopsis, 1478042SJohn.Sonnenschein@Sun.COM entered]) 1488042SJohn.Sonnenschein@Sun.COM 1498042SJohn.Sonnenschein@Sun.COM if check_db: 150*9920SMark.J.Nelson@Sun.COM valid = ARC(arcs.keys(), arcPath) 1517078Smjnelson 1527078Smjnelson for case, insts in arcs.iteritems(): 1537078Smjnelson if len(insts) > 1: 1548042SJohn.Sonnenschein@Sun.COM errors['dup'].append(' '.join(case)) 1557078Smjnelson 1568042SJohn.Sonnenschein@Sun.COM if not check_db: 1577078Smjnelson continue 1588042SJohn.Sonnenschein@Sun.COM 1598042SJohn.Sonnenschein@Sun.COM if not case in valid: 1608042SJohn.Sonnenschein@Sun.COM errors['nonexistent'].append(' '.join(case)) 1618042SJohn.Sonnenschein@Sun.COM continue 162*9920SMark.J.Nelson@Sun.COM 1637078Smjnelson # 1647078Smjnelson # We first try a direct match between the actual case name 1657078Smjnelson # and the entered comment. If that fails we remove a possible 1667078Smjnelson # trailing (fix nit)-type comment, and re-try. 1677078Smjnelson # 1687078Smjnelson for entered in insts: 169*9920SMark.J.Nelson@Sun.COM if entered == valid[case]: 1708042SJohn.Sonnenschein@Sun.COM break 1717078Smjnelson else: 1727711Srichlowe@richlowe.net # Try again with trailing (fix ...) removed. 1737078Smjnelson dbcom = re.sub(r' \([^)]+\)$', '', entered) 174*9920SMark.J.Nelson@Sun.COM if dbcom != valid[case]: 1758042SJohn.Sonnenschein@Sun.COM errors['nomatch'].append( 1768042SJohn.Sonnenschein@Sun.COM [' '.join(case), valid[case], 1778042SJohn.Sonnenschein@Sun.COM entered]) 1787078Smjnelson 1797078Smjnelson if blanks: 1807078Smjnelson output.write("WARNING: Blank line(s) in comments\n") 1817078Smjnelson ret = 1 1827078Smjnelson 1837078Smjnelson if errors['dup']: 1847078Smjnelson ret = 1 1857078Smjnelson output.write("These IDs appear more than once in your " 1867078Smjnelson "comments:\n") 1877078Smjnelson for err in errors['dup']: 1887078Smjnelson output.write(" %s\n" % err) 1897078Smjnelson 1907078Smjnelson if errors['bugnospc']: 1917078Smjnelson ret = 1 1927078Smjnelson output.write("These bugs are missing a single space following " 1937078Smjnelson "the ID:\n") 1947078Smjnelson for com in errors['bugnospc']: 1957078Smjnelson output.write(" %s\n" % com) 1967078Smjnelson 1977078Smjnelson if errors['mutant']: 1987078Smjnelson ret = 1 1997078Smjnelson output.write("These comments are neither bug nor ARC case:\n") 2007078Smjnelson for com in errors['mutant']: 2017078Smjnelson output.write(" %s\n" % com) 2027078Smjnelson 2037078Smjnelson if errors['nonexistent']: 2047078Smjnelson ret = 1 2057078Smjnelson output.write("These bugs/ARC cases were not found in the " 2067078Smjnelson "databases:\n") 2077078Smjnelson for id in errors['nonexistent']: 2087078Smjnelson output.write(" %s\n" % id) 2097078Smjnelson 2107078Smjnelson if errors['nomatch']: 2117078Smjnelson ret = 1 2127078Smjnelson output.write("These bugs/ARC case synopsis/names don't match " 2137078Smjnelson "the database entries:\n") 2147078Smjnelson for err in errors['nomatch']: 2157078Smjnelson output.write("Synopsis/name of %s is wrong:\n" % err[0]) 2167078Smjnelson output.write(" should be: '%s'\n" % err[1]) 2177078Smjnelson output.write(" is: '%s'\n" % err[2]) 2187078Smjnelson 2197078Smjnelson return ret 220