8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# This program is free software; you can redistribute it and/or modify
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# it under the terms of the GNU General Public License version 2
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# as published by the Free Software Foundation.
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# This program is distributed in the hope that it will be useful,
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# but WITHOUT ANY WARRANTY; without even the implied warranty of
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# GNU General Public License for more details.
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# You should have received a copy of the GNU General Public License
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# along with this program; if not, write to the Free Software
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# Copyright 2008, 2012 Richard Lowe
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore# Copyright 2014 Garrett D'Amore <garrett@damore.org>
e55874358132a4aa6132178335bf567ca79c87c3Joshua M. Clulow# Copyright (c) 2014, Joyent, Inc.
93d2a904d17ac0073fa98bf62f89294d980c8b3dPaul Dagnelie# Copyright (c) 2015, 2016 by Delphix. All rights reserved.
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# Adjust the load path based on our location and the version of python into
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# which it is being loaded. This assumes the normal onbld directory
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# structure, where we are in bin/ and the modules are in
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# lib/python(version)?/onbld/Scm/. If that changes so too must this.
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowesys.path.insert(1, os.path.join(os.path.dirname(__file__), "..", "lib",
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# Add the relative path to usr/src/tools to the load path, such that when run
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe# from the source tree we use the modules also within the source tree.
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowesys.path.insert(2, os.path.join(os.path.dirname(__file__), ".."))
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowefrom onbld.Checks import Comments, Copyright, CStyle, HdrChk
71af3be340c57171837478555e2eb0d496318cfcCody Peter Mellofrom onbld.Checks import JStyle, Keywords, ManLint, Mapfile, SpellCheck
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe """Run a command and return a stream containing its stdout (and write its
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe stderr to its stdout)"""
ff50e8e5ae1af23788a33c5296dd2009f3b8baf7Richard Lowe tmpfile = tempfile.TemporaryFile(prefix="git-nits")
ff50e8e5ae1af23788a33c5296dd2009f3b8baf7Richard Lowe raise GitError("Could not create temporary file: %s\n" % e)
ff50e8e5ae1af23788a33c5296dd2009f3b8baf7Richard Lowe raise GitError("could not execute %s: %s\n" (command, e))
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe """Return the root of the current git workspace"""
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe sys.stderr.write("Failed finding git workspace\n")
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe return os.path.abspath(os.path.join(p.readlines()[0],
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe """Return the current git branch"""
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe sys.stderr.write("Failed finding git branch\n")
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe """Return the parent of the current git branch.
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe If this branch tracks a remote branch, return the remote branch which is
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe tracked. If not, default to origin/master."""
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe p = git("for-each-ref --format=%(refname:short) %(upstream:short) " +
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe sys.stderr.write("Failed finding git parent branch\n")
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe # Git 1.7 will leave a ' ' trailing any non-tracking branch
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe """Return a list of any checkin comments on this git branch"""
27495383ee5e81658b2c3bbd8f51f5b0dddeb3d8Richard Lowe p = git('log --pretty=tformat:%%B:SEP: %s..' % parent)
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe sys.stderr.write("Failed getting git comments\n")
27495383ee5e81658b2c3bbd8f51f5b0dddeb3d8Richard Lowe return [x.strip() for x in p.readlines() if x != ':SEP:\n']
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe """Return the set of files which have ever changed on this branch.
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe NB: This includes files which no longer exist, or no longer actually
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe p = git("log --name-only --pretty=format: %s.. %s" %
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe sys.stderr.write("Failed building file-list from git\n")
93d2a904d17ac0073fa98bf62f89294d980c8b3dPaul Dagnelie if fname and not fname.isspace() and fname not in ret:
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe """Return a function which returns True if a file given as an argument
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe should be excluded from the check named by 'cmd'"""
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe """Return a function producing file names, relative to the current
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe directory, of any file changed on this branch (limited to 'paths' if
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe requested), and excluding files for which exclude returns a true value """
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe # Taken entirely from Python 2.6's os.path.relpath which we would use if we
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe c = os.path.abspath(os.path.join(root, path)).split(os.path.sep)
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe return os.path.join(*[os.path.pardir] * (len(s)-l) + c[l:])
93d2a904d17ac0073fa98bf62f89294d980c8b3dPaul Dagnelie # This ignores all the errors that can be thrown. Usually, this means
93d2a904d17ac0073fa98bf62f89294d980c8b3dPaul Dagnelie # that git returned non-zero because the file doesn't exist, but it
93d2a904d17ac0073fa98bf62f89294d980c8b3dPaul Dagnelie # could also fail if git can't create a new file or it can't be
93d2a904d17ac0073fa98bf62f89294d980c8b3dPaul Dagnelie # executed. Such errors are 1) unlikely, and 2) will be caught by other
93d2a904d17ac0073fa98bf62f89294d980c8b3dPaul Dagnelie # invocations of git().
93d2a904d17ac0073fa98bf62f89294d980c8b3dPaul Dagnelie if (os.path.exists(f) and not empty and select(f) and not exclude(f)):
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe return Comments.comchk(git_comments(parent), check_db=True,
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe # We are interested in examining any file that has the following
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe # in its final path segment:
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe # - Contains the word 'mapfile'
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe # - Begins with 'map.'
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe # - Ends with '.map'
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe # We don't want to match unless these things occur in final path segment
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe # because directory names with these strings don't indicate a mapfile.
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe # We also ignore files with suffixes that tell us that the files
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe # are not mapfiles.
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe MapfileRE = re.compile(r'.*((mapfile[^/]*)|(/map\.+[^/]*)|(\.map))$',
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe NotMapSuffixRE = re.compile(r'.*\.[ch]$', re.IGNORECASE)
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe for f in flist(lambda x: MapfileRE.match(x) and not
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe ret |= HdrChk.hdrchk(fh, lenient=True, output=output)
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe for f in flist(lambda x: x.endswith('.c') or x.endswith('.h')):
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe ret |= CStyle.cstyle(fh, output=output, picky=True,
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe ret |= JStyle.jstyle(fh, output=output, picky=True)
71af3be340c57171837478555e2eb0d496318cfcCody Peter Mello output.write("Man page format/spelling:\n")
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ManfileRE = re.compile(r'.*\.[0-9][a-z]*$', re.IGNORECASE)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for f in flist(lambda x: ManfileRE.match(x)):
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ret |= ManLint.manlint(fh, output=output, picky=True)
71af3be340c57171837478555e2eb0d496318cfcCody Peter Mello ret |= SpellCheck.spellcheck(fh, output=output)
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowedef run_checks(root, parent, cmds, paths='', opts={}):
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe """Run the checks given in 'cmds', expected to have well-known signatures,
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe and report results for any which fail.
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe Return failure if any of them did.
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe NB: the function name of the commands passed in is used to name the NOT
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe file which excepts files from them."""
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe result = cmd(root, parent, gen_files(root, parent, paths, exclude),
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe sys.stderr.write("Usage: %s [-b branch] [path...]\n" % cmd)
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe parent_branch = git_parent_branch(git_branch())
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe sys.stderr.write("only complete workspaces may be pbchk'd\n");
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe main(os.path.basename(sys.argv[0]), sys.argv[1:])
8bcea973790ad3e762bf78b7c6ad5776e463fd51Richard Lowe sys.stderr.write("failed to run git:\n %s\n" % str(e))