1ca13eaa5SAndy Fiddaman#!@TOOLS_PYTHON@ 28bcea973SRichard Lowe# 38bcea973SRichard Lowe# This program is free software; you can redistribute it and/or modify 48bcea973SRichard Lowe# it under the terms of the GNU General Public License version 2 58bcea973SRichard Lowe# as published by the Free Software Foundation. 68bcea973SRichard Lowe# 78bcea973SRichard Lowe# This program is distributed in the hope that it will be useful, 88bcea973SRichard Lowe# but WITHOUT ANY WARRANTY; without even the implied warranty of 98bcea973SRichard Lowe# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 108bcea973SRichard Lowe# GNU General Public License for more details. 118bcea973SRichard Lowe# 128bcea973SRichard Lowe# You should have received a copy of the GNU General Public License 138bcea973SRichard Lowe# along with this program; if not, write to the Free Software 148bcea973SRichard Lowe# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 158bcea973SRichard Lowe# 168bcea973SRichard Lowe 178bcea973SRichard Lowe# 188bcea973SRichard Lowe# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 198bcea973SRichard Lowe# Copyright 2008, 2012 Richard Lowe 20*955eb5e1SGarrett D'Amore# Copyright 2019 Garrett D'Amore <garrett@damore.org> 2193d2a904SPaul Dagnelie# Copyright (c) 2015, 2016 by Delphix. All rights reserved. 2228e2b3adSHans Rosenfeld# Copyright 2016 Nexenta Systems, Inc. 23972282a0SJohn Levon# Copyright (c) 2019, Joyent, Inc. 24a90997d2SAndy Fiddaman# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. 258bcea973SRichard Lowe# 268bcea973SRichard Lowe 27ca13eaa5SAndy Fiddamanfrom __future__ import print_function 28ca13eaa5SAndy Fiddaman 298bcea973SRichard Loweimport getopt 30ca13eaa5SAndy Fiddamanimport io 318bcea973SRichard Loweimport os 328bcea973SRichard Loweimport re 338bcea973SRichard Loweimport subprocess 348bcea973SRichard Loweimport sys 35ff50e8e5SRichard Loweimport tempfile 368bcea973SRichard Lowe 37ca13eaa5SAndy Fiddamanif sys.version_info[0] < 3: 388bcea973SRichard Lowe from cStringIO import StringIO 39ca13eaa5SAndy Fiddamanelse: 40ca13eaa5SAndy Fiddaman from io import StringIO 418bcea973SRichard Lowe 428bcea973SRichard Lowe# 438bcea973SRichard Lowe# Adjust the load path based on our location and the version of python into 448bcea973SRichard Lowe# which it is being loaded. This assumes the normal onbld directory 458bcea973SRichard Lowe# structure, where we are in bin/ and the modules are in 468bcea973SRichard Lowe# lib/python(version)?/onbld/Scm/. If that changes so too must this. 478bcea973SRichard Lowe# 488bcea973SRichard Lowesys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "lib", 498bcea973SRichard Lowe "python%d.%d" % sys.version_info[:2])) 508bcea973SRichard Lowe 518bcea973SRichard Lowe# 528bcea973SRichard Lowe# Add the relative path to usr/src/tools to the load path, such that when run 538bcea973SRichard Lowe# from the source tree we use the modules also within the source tree. 548bcea973SRichard Lowe# 558bcea973SRichard Lowesys.path.insert(2, os.path.join(os.path.dirname(__file__), "..")) 568bcea973SRichard Lowe 57e5587435SJoshua M. Clulowfrom onbld.Scm import Ignore 584ff15898SGordon Rossfrom onbld.Checks import Comments, Copyright, CStyle, HdrChk, WsCheck 5971af3be3SCody Peter Mellofrom onbld.Checks import JStyle, Keywords, ManLint, Mapfile, SpellCheck 608bcea973SRichard Lowe 618bcea973SRichard Loweclass GitError(Exception): 628bcea973SRichard Lowe pass 638bcea973SRichard Lowe 648bcea973SRichard Lowedef git(command): 658bcea973SRichard Lowe """Run a command and return a stream containing its stdout (and write its 668bcea973SRichard Lowe stderr to its stdout)""" 678bcea973SRichard Lowe 688bcea973SRichard Lowe if type(command) != list: 698bcea973SRichard Lowe command = command.split() 708bcea973SRichard Lowe 718bcea973SRichard Lowe command = ["git"] + command 728bcea973SRichard Lowe 73ff50e8e5SRichard Lowe try: 74ca13eaa5SAndy Fiddaman tmpfile = tempfile.TemporaryFile(prefix="git-nits", mode="w+b") 75ca13eaa5SAndy Fiddaman except EnvironmentError as e: 76ff50e8e5SRichard Lowe raise GitError("Could not create temporary file: %s\n" % e) 77ff50e8e5SRichard Lowe 78ff50e8e5SRichard Lowe try: 798bcea973SRichard Lowe p = subprocess.Popen(command, 80ff50e8e5SRichard Lowe stdout=tmpfile, 81380fd671SMatthew Ahrens stderr=subprocess.PIPE) 82ca13eaa5SAndy Fiddaman except OSError as e: 83709afb1dSDillon Amburgey raise GitError("could not execute %s: %s\n" % (command, e)) 848bcea973SRichard Lowe 858bcea973SRichard Lowe err = p.wait() 868bcea973SRichard Lowe if err != 0: 87380fd671SMatthew Ahrens raise GitError(p.stderr.read()) 888bcea973SRichard Lowe 89ff50e8e5SRichard Lowe tmpfile.seek(0) 90ca13eaa5SAndy Fiddaman lines = [] 91ca13eaa5SAndy Fiddaman for l in tmpfile: 92ca13eaa5SAndy Fiddaman lines.append(l.decode('utf-8', 'replace')) 93ca13eaa5SAndy Fiddaman return lines 948bcea973SRichard Lowe 958bcea973SRichard Lowedef git_root(): 968bcea973SRichard Lowe """Return the root of the current git workspace""" 978bcea973SRichard Lowe 988bcea973SRichard Lowe p = git('rev-parse --git-dir') 99ca13eaa5SAndy Fiddaman dir = p[0] 1008bcea973SRichard Lowe 101ca13eaa5SAndy Fiddaman return os.path.abspath(os.path.join(dir, os.path.pardir)) 1028bcea973SRichard Lowe 1038bcea973SRichard Lowedef git_branch(): 1048bcea973SRichard Lowe """Return the current git branch""" 1058bcea973SRichard Lowe 1068bcea973SRichard Lowe p = git('branch') 1078bcea973SRichard Lowe 1088bcea973SRichard Lowe for elt in p: 1098bcea973SRichard Lowe if elt[0] == '*': 1108bcea973SRichard Lowe if elt.endswith('(no branch)'): 1118bcea973SRichard Lowe return None 1128bcea973SRichard Lowe return elt.split()[1] 1138bcea973SRichard Lowe 1148bcea973SRichard Lowedef git_parent_branch(branch): 1158bcea973SRichard Lowe """Return the parent of the current git branch. 1168bcea973SRichard Lowe 1178bcea973SRichard Lowe If this branch tracks a remote branch, return the remote branch which is 1188bcea973SRichard Lowe tracked. If not, default to origin/master.""" 1198bcea973SRichard Lowe 1208bcea973SRichard Lowe if not branch: 1218bcea973SRichard Lowe return None 1228bcea973SRichard Lowe 12328e2b3adSHans Rosenfeld p = git(["for-each-ref", "--format=%(refname:short) %(upstream:short)", 12428e2b3adSHans Rosenfeld "refs/heads/"]) 1258bcea973SRichard Lowe 1268bcea973SRichard Lowe if not p: 1278bcea973SRichard Lowe sys.stderr.write("Failed finding git parent branch\n") 128972282a0SJohn Levon sys.exit(1) 1298bcea973SRichard Lowe 1308bcea973SRichard Lowe for line in p: 1318bcea973SRichard Lowe # Git 1.7 will leave a ' ' trailing any non-tracking branch 1328bcea973SRichard Lowe if ' ' in line and not line.endswith(' \n'): 1338bcea973SRichard Lowe local, remote = line.split() 1348bcea973SRichard Lowe if local == branch: 1358bcea973SRichard Lowe return remote 1368bcea973SRichard Lowe return 'origin/master' 1378bcea973SRichard Lowe 1388bcea973SRichard Lowedef git_comments(parent): 1398bcea973SRichard Lowe """Return a list of any checkin comments on this git branch""" 1408bcea973SRichard Lowe 14127495383SRichard Lowe p = git('log --pretty=tformat:%%B:SEP: %s..' % parent) 1428bcea973SRichard Lowe 1438bcea973SRichard Lowe if not p: 144972282a0SJohn Levon sys.stderr.write("No outgoing changesets found - missing -p option?\n"); 145972282a0SJohn Levon sys.exit(1) 1468bcea973SRichard Lowe 147ca13eaa5SAndy Fiddaman return [x.strip() for x in p if x != ':SEP:\n'] 1488bcea973SRichard Lowe 1498bcea973SRichard Lowedef git_file_list(parent, paths=None): 1508bcea973SRichard Lowe """Return the set of files which have ever changed on this branch. 1518bcea973SRichard Lowe 1528bcea973SRichard Lowe NB: This includes files which no longer exist, or no longer actually 1538bcea973SRichard Lowe differ.""" 1548bcea973SRichard Lowe 1558bcea973SRichard Lowe p = git("log --name-only --pretty=format: %s.. %s" % 1568bcea973SRichard Lowe (parent, ' '.join(paths))) 1578bcea973SRichard Lowe 1588bcea973SRichard Lowe if not p: 1598bcea973SRichard Lowe sys.stderr.write("Failed building file-list from git\n") 160972282a0SJohn Levon sys.exit(1) 1618bcea973SRichard Lowe 1628bcea973SRichard Lowe ret = set() 1638bcea973SRichard Lowe for fname in p: 16493d2a904SPaul Dagnelie if fname and not fname.isspace() and fname not in ret: 1658bcea973SRichard Lowe ret.add(fname.strip()) 1668bcea973SRichard Lowe 1678bcea973SRichard Lowe return ret 1688bcea973SRichard Lowe 1698bcea973SRichard Lowedef not_check(root, cmd): 1708bcea973SRichard Lowe """Return a function which returns True if a file given as an argument 1718bcea973SRichard Lowe should be excluded from the check named by 'cmd'""" 1728bcea973SRichard Lowe 173ca13eaa5SAndy Fiddaman ignorefiles = list(filter(os.path.exists, 1748bcea973SRichard Lowe [os.path.join(root, ".git", "%s.NOT" % cmd), 175ca13eaa5SAndy Fiddaman os.path.join(root, "exception_lists", cmd)])) 176e5587435SJoshua M. Clulow return Ignore.ignore(root, ignorefiles) 1778bcea973SRichard Lowe 178*955eb5e1SGarrett D'Amoredef gen_files(root, parent, paths, exclude, filter=None): 1798bcea973SRichard Lowe """Return a function producing file names, relative to the current 1808bcea973SRichard Lowe directory, of any file changed on this branch (limited to 'paths' if 1818bcea973SRichard Lowe requested), and excluding files for which exclude returns a true value """ 1828bcea973SRichard Lowe 183*955eb5e1SGarrett D'Amore if filter is None: 184*955eb5e1SGarrett D'Amore filter = lambda x: os.path.isfile(x) 185*955eb5e1SGarrett D'Amore 1868bcea973SRichard Lowe # Taken entirely from Python 2.6's os.path.relpath which we would use if we 1878bcea973SRichard Lowe # could. 1888bcea973SRichard Lowe def relpath(path, here): 1898bcea973SRichard Lowe c = os.path.abspath(os.path.join(root, path)).split(os.path.sep) 1908bcea973SRichard Lowe s = os.path.abspath(here).split(os.path.sep) 1918bcea973SRichard Lowe l = len(os.path.commonprefix((s, c))) 1928bcea973SRichard Lowe return os.path.join(*[os.path.pardir] * (len(s)-l) + c[l:]) 1938bcea973SRichard Lowe 1948bcea973SRichard Lowe def ret(select=None): 1958bcea973SRichard Lowe if not select: 1968bcea973SRichard Lowe select = lambda x: True 1978bcea973SRichard Lowe 19838e36c53SJohn Levon for abspath in git_file_list(parent, paths): 19938e36c53SJohn Levon path = relpath(abspath, '.') 20093d2a904SPaul Dagnelie try: 20138e36c53SJohn Levon res = git("diff %s HEAD %s" % (parent, path)) 202ca13eaa5SAndy Fiddaman except GitError as e: 20338e36c53SJohn Levon # This ignores all the errors that can be thrown. Usually, this 20438e36c53SJohn Levon # means that git returned non-zero because the file doesn't 20538e36c53SJohn Levon # exist, but it could also fail if git can't create a new file 20638e36c53SJohn Levon # or it can't be executed. Such errors are 1) unlikely, and 2) 20738e36c53SJohn Levon # will be caught by other invocations of git(). 20893d2a904SPaul Dagnelie continue 209ca13eaa5SAndy Fiddaman empty = not res 210*955eb5e1SGarrett D'Amore if (filter(path) and not empty and 21138e36c53SJohn Levon select(path) and not exclude(abspath)): 21238e36c53SJohn Levon yield path 2138bcea973SRichard Lowe return ret 2148bcea973SRichard Lowe 215*955eb5e1SGarrett D'Amoredef gen_links(root, parent, paths, exclude): 216*955eb5e1SGarrett D'Amore """Return a function producing symbolic link names, relative to the current 217*955eb5e1SGarrett D'Amore directory, of any file changed on this branch (limited to 'paths' if 218*955eb5e1SGarrett D'Amore requested), and excluding files for which exclude returns a true value """ 219*955eb5e1SGarrett D'Amore 220*955eb5e1SGarrett D'Amore return gen_files(root, parent, paths, exclude, lambda x: os.path.islink(x)) 221*955eb5e1SGarrett D'Amore 2228bcea973SRichard Lowedef comchk(root, parent, flist, output): 2238bcea973SRichard Lowe output.write("Comments:\n") 2248bcea973SRichard Lowe 2258bcea973SRichard Lowe return Comments.comchk(git_comments(parent), check_db=True, 2268bcea973SRichard Lowe output=output) 2278bcea973SRichard Lowe 2288bcea973SRichard Lowe 2298bcea973SRichard Lowedef mapfilechk(root, parent, flist, output): 2308bcea973SRichard Lowe ret = 0 2318bcea973SRichard Lowe 2328bcea973SRichard Lowe # We are interested in examining any file that has the following 2338bcea973SRichard Lowe # in its final path segment: 2348bcea973SRichard Lowe # - Contains the word 'mapfile' 2358bcea973SRichard Lowe # - Begins with 'map.' 2368bcea973SRichard Lowe # - Ends with '.map' 2378bcea973SRichard Lowe # We don't want to match unless these things occur in final path segment 2388bcea973SRichard Lowe # because directory names with these strings don't indicate a mapfile. 2398bcea973SRichard Lowe # We also ignore files with suffixes that tell us that the files 2408bcea973SRichard Lowe # are not mapfiles. 2418bcea973SRichard Lowe MapfileRE = re.compile(r'.*((mapfile[^/]*)|(/map\.+[^/]*)|(\.map))$', 2428bcea973SRichard Lowe re.IGNORECASE) 2438bcea973SRichard Lowe NotMapSuffixRE = re.compile(r'.*\.[ch]$', re.IGNORECASE) 2448bcea973SRichard Lowe 2458bcea973SRichard Lowe output.write("Mapfile comments:\n") 2468bcea973SRichard Lowe 2478bcea973SRichard Lowe for f in flist(lambda x: MapfileRE.match(x) and not 2488bcea973SRichard Lowe NotMapSuffixRE.match(x)): 249ca13eaa5SAndy Fiddaman with io.open(f, encoding='utf-8', errors='replace') as fh: 2508bcea973SRichard Lowe ret |= Mapfile.mapfilechk(fh, output=output) 2518bcea973SRichard Lowe return ret 2528bcea973SRichard Lowe 2538bcea973SRichard Lowedef copyright(root, parent, flist, output): 2548bcea973SRichard Lowe ret = 0 2558bcea973SRichard Lowe output.write("Copyrights:\n") 2568bcea973SRichard Lowe for f in flist(): 257ca13eaa5SAndy Fiddaman with io.open(f, encoding='utf-8', errors='replace') as fh: 2588bcea973SRichard Lowe ret |= Copyright.copyright(fh, output=output) 2598bcea973SRichard Lowe return ret 2608bcea973SRichard Lowe 2618bcea973SRichard Lowedef hdrchk(root, parent, flist, output): 2628bcea973SRichard Lowe ret = 0 2638bcea973SRichard Lowe output.write("Header format:\n") 2648bcea973SRichard Lowe for f in flist(lambda x: x.endswith('.h')): 265ca13eaa5SAndy Fiddaman with io.open(f, encoding='utf-8', errors='replace') as fh: 2668bcea973SRichard Lowe ret |= HdrChk.hdrchk(fh, lenient=True, output=output) 2678bcea973SRichard Lowe return ret 2688bcea973SRichard Lowe 2698bcea973SRichard Lowedef cstyle(root, parent, flist, output): 2708bcea973SRichard Lowe ret = 0 2718bcea973SRichard Lowe output.write("C style:\n") 2728bcea973SRichard Lowe for f in flist(lambda x: x.endswith('.c') or x.endswith('.h')): 273a90997d2SAndy Fiddaman with io.open(f, mode='rb') as fh: 2748bcea973SRichard Lowe ret |= CStyle.cstyle(fh, output=output, picky=True, 2758bcea973SRichard Lowe check_posix_types=True, 2768bcea973SRichard Lowe check_continuation=True) 2778bcea973SRichard Lowe return ret 2788bcea973SRichard Lowe 2798bcea973SRichard Lowedef jstyle(root, parent, flist, output): 2808bcea973SRichard Lowe ret = 0 2818bcea973SRichard Lowe output.write("Java style:\n") 2828bcea973SRichard Lowe for f in flist(lambda x: x.endswith('.java')): 283ca13eaa5SAndy Fiddaman with io.open(f, encoding='utf-8', errors='replace') as fh: 2848bcea973SRichard Lowe ret |= JStyle.jstyle(fh, output=output, picky=True) 2858bcea973SRichard Lowe return ret 2868bcea973SRichard Lowe 28795c635efSGarrett D'Amoredef manlint(root, parent, flist, output): 28895c635efSGarrett D'Amore ret = 0 28971af3be3SCody Peter Mello output.write("Man page format/spelling:\n") 29095c635efSGarrett D'Amore ManfileRE = re.compile(r'.*\.[0-9][a-z]*$', re.IGNORECASE) 29195c635efSGarrett D'Amore for f in flist(lambda x: ManfileRE.match(x)): 292a90997d2SAndy Fiddaman with io.open(f, mode='rb') as fh: 29395c635efSGarrett D'Amore ret |= ManLint.manlint(fh, output=output, picky=True) 29471af3be3SCody Peter Mello ret |= SpellCheck.spellcheck(fh, output=output) 29595c635efSGarrett D'Amore return ret 29695c635efSGarrett D'Amore 2978bcea973SRichard Lowedef keywords(root, parent, flist, output): 2988bcea973SRichard Lowe ret = 0 2998bcea973SRichard Lowe output.write("SCCS Keywords:\n") 3008bcea973SRichard Lowe for f in flist(): 301ca13eaa5SAndy Fiddaman with io.open(f, encoding='utf-8', errors='replace') as fh: 3028bcea973SRichard Lowe ret |= Keywords.keywords(fh, output=output) 3038bcea973SRichard Lowe return ret 3048bcea973SRichard Lowe 3054ff15898SGordon Rossdef wscheck(root, parent, flist, output): 3064ff15898SGordon Ross ret = 0 3074ff15898SGordon Ross output.write("white space nits:\n") 3084ff15898SGordon Ross for f in flist(): 309ca13eaa5SAndy Fiddaman with io.open(f, encoding='utf-8', errors='replace') as fh: 3104ff15898SGordon Ross ret |= WsCheck.wscheck(fh, output=output) 3114ff15898SGordon Ross return ret 3128bcea973SRichard Lowe 313*955eb5e1SGarrett D'Amoredef symlinks(root, parent, flist, output): 314*955eb5e1SGarrett D'Amore ret = 0 315*955eb5e1SGarrett D'Amore output.write("Symbolic links:\n") 316*955eb5e1SGarrett D'Amore for f in flist(): 317*955eb5e1SGarrett D'Amore output.write(" "+f+"\n") 318*955eb5e1SGarrett D'Amore ret |= 1 319*955eb5e1SGarrett D'Amore return ret 320*955eb5e1SGarrett D'Amore 321*955eb5e1SGarrett D'Amoredef iswinreserved(name): 322*955eb5e1SGarrett D'Amore reserved = [ 323*955eb5e1SGarrett D'Amore 'con', 'prn', 'aux', 'nul', 324*955eb5e1SGarrett D'Amore 'com1', 'com2', 'com3', 'com4', 'com5', 325*955eb5e1SGarrett D'Amore 'com6', 'com7', 'com8', 'com9', 'com0', 326*955eb5e1SGarrett D'Amore 'lpt1', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 327*955eb5e1SGarrett D'Amore 'lpt6', 'lpt7', 'lpt8', 'lpt9', 'lpt0' ] 328*955eb5e1SGarrett D'Amore l = name.lower() 329*955eb5e1SGarrett D'Amore for r in reserved: 330*955eb5e1SGarrett D'Amore if l == r or l.startswith(r+"."): 331*955eb5e1SGarrett D'Amore return True 332*955eb5e1SGarrett D'Amore return False 333*955eb5e1SGarrett D'Amore 334*955eb5e1SGarrett D'Amoredef haswinspecial(name): 335*955eb5e1SGarrett D'Amore specials = '<>:"\\|?*' 336*955eb5e1SGarrett D'Amore for c in name: 337*955eb5e1SGarrett D'Amore if c in specials: 338*955eb5e1SGarrett D'Amore return True 339*955eb5e1SGarrett D'Amore return False 340*955eb5e1SGarrett D'Amore 341*955eb5e1SGarrett D'Amoredef winnames(root, parent, flist, output): 342*955eb5e1SGarrett D'Amore ret = 0 343*955eb5e1SGarrett D'Amore output.write("Illegal filenames (Windows):\n") 344*955eb5e1SGarrett D'Amore for f in flist(): 345*955eb5e1SGarrett D'Amore if haswinspecial(f): 346*955eb5e1SGarrett D'Amore output.write(" "+f+": invalid character in name\n") 347*955eb5e1SGarrett D'Amore ret |= 1 348*955eb5e1SGarrett D'Amore continue 349*955eb5e1SGarrett D'Amore 350*955eb5e1SGarrett D'Amore parts = f.split('/') 351*955eb5e1SGarrett D'Amore for p in parts: 352*955eb5e1SGarrett D'Amore if iswinreserved(p): 353*955eb5e1SGarrett D'Amore output.write(" "+f+": reserved file name\n") 354*955eb5e1SGarrett D'Amore ret |= 1 355*955eb5e1SGarrett D'Amore break 356*955eb5e1SGarrett D'Amore 357*955eb5e1SGarrett D'Amore return ret 358*955eb5e1SGarrett D'Amore 359*955eb5e1SGarrett D'Amoredef run_checks(root, parent, cmds, scmds, paths='', opts={}): 3608bcea973SRichard Lowe """Run the checks given in 'cmds', expected to have well-known signatures, 3618bcea973SRichard Lowe and report results for any which fail. 3628bcea973SRichard Lowe 3638bcea973SRichard Lowe Return failure if any of them did. 3648bcea973SRichard Lowe 3658bcea973SRichard Lowe NB: the function name of the commands passed in is used to name the NOT 3668bcea973SRichard Lowe file which excepts files from them.""" 3678bcea973SRichard Lowe 3688bcea973SRichard Lowe ret = 0 3698bcea973SRichard Lowe 3708bcea973SRichard Lowe for cmd in cmds: 3718bcea973SRichard Lowe s = StringIO() 3728bcea973SRichard Lowe 373ca13eaa5SAndy Fiddaman exclude = not_check(root, cmd.__name__) 3748bcea973SRichard Lowe result = cmd(root, parent, gen_files(root, parent, paths, exclude), 3758bcea973SRichard Lowe output=s) 3768bcea973SRichard Lowe ret |= result 3778bcea973SRichard Lowe 3788bcea973SRichard Lowe if result != 0: 379ca13eaa5SAndy Fiddaman print(s.getvalue()) 3808bcea973SRichard Lowe 381*955eb5e1SGarrett D'Amore for cmd in scmds: 382*955eb5e1SGarrett D'Amore s = StringIO() 383*955eb5e1SGarrett D'Amore 384*955eb5e1SGarrett D'Amore exclude = not_check(root, cmd.__name__) 385*955eb5e1SGarrett D'Amore result = cmd(root, parent, gen_links(root, parent, paths, exclude), 386*955eb5e1SGarrett D'Amore output=s) 387*955eb5e1SGarrett D'Amore ret |= result 388*955eb5e1SGarrett D'Amore 389*955eb5e1SGarrett D'Amore if result != 0: 390*955eb5e1SGarrett D'Amore print(s.getvalue()) 391*955eb5e1SGarrett D'Amore 3928bcea973SRichard Lowe return ret 3938bcea973SRichard Lowe 3948bcea973SRichard Lowedef nits(root, parent, paths): 3958bcea973SRichard Lowe cmds = [copyright, 3968bcea973SRichard Lowe cstyle, 3978bcea973SRichard Lowe hdrchk, 3988bcea973SRichard Lowe jstyle, 3998bcea973SRichard Lowe keywords, 40095c635efSGarrett D'Amore manlint, 4014ff15898SGordon Ross mapfilechk, 402*955eb5e1SGarrett D'Amore winnames, 4034ff15898SGordon Ross wscheck] 404*955eb5e1SGarrett D'Amore scmds = [symlinks] 405*955eb5e1SGarrett D'Amore run_checks(root, parent, cmds, scmds, paths) 4068bcea973SRichard Lowe 4078bcea973SRichard Lowedef pbchk(root, parent, paths): 4088bcea973SRichard Lowe cmds = [comchk, 4098bcea973SRichard Lowe copyright, 4108bcea973SRichard Lowe cstyle, 4118bcea973SRichard Lowe hdrchk, 4128bcea973SRichard Lowe jstyle, 4138bcea973SRichard Lowe keywords, 41495c635efSGarrett D'Amore manlint, 4154ff15898SGordon Ross mapfilechk, 416*955eb5e1SGarrett D'Amore winnames, 4174ff15898SGordon Ross wscheck] 418*955eb5e1SGarrett D'Amore scmds = [symlinks] 419*955eb5e1SGarrett D'Amore run_checks(root, parent, cmds, scmds) 4208bcea973SRichard Lowe 4218bcea973SRichard Lowedef main(cmd, args): 4228bcea973SRichard Lowe parent_branch = None 423eabe844aSJohn Levon checkname = None 4248bcea973SRichard Lowe 4258bcea973SRichard Lowe try: 42642a3762dSJoshua M. Clulow opts, args = getopt.getopt(args, 'b:c:p:') 427ca13eaa5SAndy Fiddaman except getopt.GetoptError as e: 4288bcea973SRichard Lowe sys.stderr.write(str(e) + '\n') 429eabe844aSJohn Levon sys.stderr.write("Usage: %s [-c check] [-p branch] [path...]\n" % cmd) 4308bcea973SRichard Lowe sys.exit(1) 4318bcea973SRichard Lowe 4328bcea973SRichard Lowe for opt, arg in opts: 43342a3762dSJoshua M. Clulow # We accept "-b" as an alias of "-p" for backwards compatibility. 43442a3762dSJoshua M. Clulow if opt == '-p' or opt == '-b': 4358bcea973SRichard Lowe parent_branch = arg 436eabe844aSJohn Levon elif opt == '-c': 437eabe844aSJohn Levon checkname = arg 4388bcea973SRichard Lowe 4398bcea973SRichard Lowe if not parent_branch: 4408bcea973SRichard Lowe parent_branch = git_parent_branch(git_branch()) 4418bcea973SRichard Lowe 442eabe844aSJohn Levon if checkname is None: 4438bcea973SRichard Lowe if cmd == 'git-pbchk': 444eabe844aSJohn Levon checkname = 'pbchk' 445eabe844aSJohn Levon else: 446eabe844aSJohn Levon checkname = 'nits' 447eabe844aSJohn Levon 448eabe844aSJohn Levon if checkname == 'pbchk': 4498bcea973SRichard Lowe if args: 4508bcea973SRichard Lowe sys.stderr.write("only complete workspaces may be pbchk'd\n"); 4518bcea973SRichard Lowe sys.exit(1) 452eabe844aSJohn Levon pbchk(git_root(), parent_branch, None) 453eabe844aSJohn Levon elif checkname == 'nits': 454eabe844aSJohn Levon nits(git_root(), parent_branch, args) 455eabe844aSJohn Levon else: 456eabe844aSJohn Levon run_checks(git_root(), parent_branch, [eval(checkname)], args) 4578bcea973SRichard Lowe 4588bcea973SRichard Loweif __name__ == '__main__': 4598bcea973SRichard Lowe try: 4608bcea973SRichard Lowe main(os.path.basename(sys.argv[0]), sys.argv[1:]) 461ca13eaa5SAndy Fiddaman except GitError as e: 4628bcea973SRichard Lowe sys.stderr.write("failed to run git:\n %s\n" % str(e)) 4638bcea973SRichard Lowe sys.exit(1) 464