From 79e2b47bf194733c48491bfb2b1bacb597d2df0c Mon Sep 17 00:00:00 2001
From: murgatroid99 <mlumish@google.com>
Date: Tue, 9 Feb 2016 09:38:29 -0800
Subject: [PATCH 1/4] Add sanitize script

---
 tools/distrib/sanitize.sh | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)
 create mode 100644 tools/distrib/sanitize.sh

diff --git a/tools/distrib/sanitize.sh b/tools/distrib/sanitize.sh
new file mode 100644
index 00000000000..56644b1d65b
--- /dev/null
+++ b/tools/distrib/sanitize.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -ex
+
+cd $(dirname $0)/../..
+
+./tools/buildgen/generate_projects.sh
+./tools/distrib/clang_format_code.sh
+./tools/distrib/check_copyright.py --fix
+./tools/distrib/check_trailing_newlines.sh

From a72a49044beed3e7bb0b7943fdd47afe5d2e9cd3 Mon Sep 17 00:00:00 2001
From: murgatroid99 <mlumish@google.com>
Date: Tue, 9 Feb 2016 09:41:21 -0800
Subject: [PATCH 2/4] Set sanitize script executable

---
 tools/distrib/sanitize.sh | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 mode change 100644 => 100755 tools/distrib/sanitize.sh

diff --git a/tools/distrib/sanitize.sh b/tools/distrib/sanitize.sh
old mode 100644
new mode 100755

From f656f189e453c87370caa1cdffa6eed6e71b0f04 Mon Sep 17 00:00:00 2001
From: murgatroid99 <mlumish@google.com>
Date: Tue, 9 Feb 2016 10:56:25 -0800
Subject: [PATCH 3/4] Make sanitize script a suitable pre-commit hook

---
 tools/distrib/check_copyright.py              |  9 ++++++-
 tools/distrib/clang_format_code.sh            |  2 +-
 tools/distrib/sanitize.sh                     | 24 +++++++++++++++----
 .../clang_format_all_the_things.sh            |  6 +++++
 4 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/tools/distrib/check_copyright.py b/tools/distrib/check_copyright.py
index a7efdc85cc1..ef836d6e2da 100755
--- a/tools/distrib/check_copyright.py
+++ b/tools/distrib/check_copyright.py
@@ -57,6 +57,9 @@ argp.add_argument('-a', '--ancient',
 argp.add_argument('-f', '--fix',
                   default=False,
                   action='store_true');
+argp.add_argument('--precommit',
+                  default=False,
+                  action='store_true')
 args = argp.parse_args()
 
 # open the license text
@@ -101,6 +104,10 @@ RE_LICENSE = dict(
         for line in LICENSE))
      for k, v in LICENSE_PREFIX.iteritems())
 
+if args.precommit:
+  FILE_LIST_COMMAND = 'git diff --name-only HEAD | grep -v ^third_party/'
+else:
+  FILE_LIST_COMMAND = 'git ls-tree -r --name-only -r HEAD | grep -v ^third_party/'
 
 def load(name):
   with open(name) as f:
@@ -124,7 +131,7 @@ def log(cond, why, filename):
 
 # scan files, validate the text
 ok = True
-for filename in subprocess.check_output('git ls-tree -r --name-only -r HEAD | grep -v ^third_party/',
+for filename in subprocess.check_output(FILE_LIST_COMMAND,
                                         shell=True).splitlines():
   if filename in KNOWN_BAD: continue
   ext = os.path.splitext(filename)[1]
diff --git a/tools/distrib/clang_format_code.sh b/tools/distrib/clang_format_code.sh
index 6bfa278cae6..d904a841d4e 100755
--- a/tools/distrib/clang_format_code.sh
+++ b/tools/distrib/clang_format_code.sh
@@ -37,4 +37,4 @@ cd $(dirname $0)/../..
 docker build -t grpc_clang_format tools/dockerfile/grpc_clang_format
 
 # run clang-format against the checked out codebase
-docker run -e TEST=$TEST --rm=true -v ${HOST_GIT_ROOT:-`pwd`}:/local-code -t grpc_clang_format /clang_format_all_the_things.sh
+docker run -e TEST=$TEST -e CHANGED_FILES="$CHANGED_FILES" --rm=true -v ${HOST_GIT_ROOT:-`pwd`}:/local-code -t grpc_clang_format /clang_format_all_the_things.sh
diff --git a/tools/distrib/sanitize.sh b/tools/distrib/sanitize.sh
index 56644b1d65b..3b7ca6fd88d 100755
--- a/tools/distrib/sanitize.sh
+++ b/tools/distrib/sanitize.sh
@@ -32,7 +32,23 @@ set -ex
 
 cd $(dirname $0)/../..
 
-./tools/buildgen/generate_projects.sh
-./tools/distrib/clang_format_code.sh
-./tools/distrib/check_copyright.py --fix
-./tools/distrib/check_trailing_newlines.sh
+DIFF_COMMAND="git diff --name-only HEAD | grep -v ^third_party/"
+
+if [ "x$1" == 'x--pre-commit' ]; then
+  if eval $DIFF_COMMAND | grep '^build.yaml$'; then
+    ./tools/buildgen/generate_projects.sh
+  else
+    templates=$(eval $DIFF_COMMAND | grep '\.template$' || true)
+    if [ -n "$templates" ]; then
+      ./tools/buildgen/generate_projects.sh --templates $templates
+    fi
+  fi
+  CHANGED_FILES=$(eval $DIFF_COMMAND) ./tools/distrib/clang_format_code.sh
+  ./tools/distrib/check_copyright.py --fix --precommit
+  ./tools/distrib/check_trailing_newlines.sh
+else
+  ./tools/buildgen/generate_projects.sh
+  ./tools/distrib/clang_format_code.sh
+  ./tools/distrib/check_copyright.py --fix
+  ./tools/distrib/check_trailing_newlines.sh
+fi
diff --git a/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh b/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
index 86ba8b2e90b..dd8ea1ac305 100755
--- a/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
+++ b/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
@@ -48,6 +48,12 @@ do
   done
 done
 
+# The CHANGED_FILES variable is used to restrict the set of files to check.
+# Here we set files to the intersection of files and CHANGED_FILES
+if [ -n "$CHANGED_FILES" ]; then
+  files=$(comm -12 <(echo $files | tr ' ' '\n' | sort -u) <(echo $CHANGED_FILES | tr ' ' '\n' | sort -u))
+fi
+
 if [ "x$TEST" = "x" ]
 then
   echo $files | xargs $CLANG_FORMAT -i

From c58a781ba2c923d379d1650ead40e5368e8a828a Mon Sep 17 00:00:00 2001
From: murgatroid99 <mlumish@google.com>
Date: Tue, 9 Feb 2016 16:33:17 -0800
Subject: [PATCH 4/4] Handle failing git command in check_copyright.py

---
 tools/distrib/check_copyright.py | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/tools/distrib/check_copyright.py b/tools/distrib/check_copyright.py
index ef836d6e2da..d1a34a920dc 100755
--- a/tools/distrib/check_copyright.py
+++ b/tools/distrib/check_copyright.py
@@ -131,8 +131,14 @@ def log(cond, why, filename):
 
 # scan files, validate the text
 ok = True
-for filename in subprocess.check_output(FILE_LIST_COMMAND,
-                                        shell=True).splitlines():
+filename_list = []
+try:
+  filename_list = subprocess.check_output(FILE_LIST_COMMAND,
+                                          shell=True).splitlines()
+except subprocess.CalledProcessError:
+  sys.exit(0)
+
+for filename in filename_list:
   if filename in KNOWN_BAD: continue
   ext = os.path.splitext(filename)[1]
   base = os.path.basename(filename)