diff --git a/hack/verify-boilerplate.sh b/hack/verify-boilerplate.sh index 21cd75c848d..007f23a87f5 100755 --- a/hack/verify-boilerplate.sh +++ b/hack/verify-boilerplate.sh @@ -19,40 +19,37 @@ set -o nounset set -o pipefail KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. +boiler="${KUBE_ROOT}/hooks/boilerplate.py" cd ${KUBE_ROOT} -result=0 find_files() { + local ext=$1 find . -not \( \ \( \ -wholename './output' \ -o -wholename './_output' \ -o -wholename './release' \ -o -wholename './target' \ + -o -wholename './.git' \ -o -wholename '*/third_party/*' \ -o -wholename '*/Godeps/*' \ \) -prune \ - \) -name '*.go' + \) -name "*.${ext}" } -for file in $(find_files); do - if [[ "$("${KUBE_ROOT}/hooks/boilerplate.sh" "${file}")" -eq "0" ]]; then +files_need_boilerplate=() + +files=($(find_files "go")) +files_need_boilerplate+=($(${boiler} "go" "${files[@]}")) + +files=($(find_files "sh")) +files_need_boilerplate+=($(${boiler} "sh" "${files[@]}")) + +if [[ ${#files_need_boilerplate[@]} -gt 0 ]]; then + for file in "${files_need_boilerplate[@]}"; do echo "Boilerplate header is wrong for: ${file}" - result=1 - fi -done - -dirs=("cluster" "hack" "hooks" "build") - -for dir in ${dirs[@]}; do - for file in $(find "$dir" -name '*.sh'); do - if [[ "$("${KUBE_ROOT}/hooks/boilerplate.sh" "${file}")" -eq "0" ]]; then - echo "Boilerplate header is wrong for: ${file}" - result=1 - fi done -done - -exit ${result} + exit 1 +fi diff --git a/hooks/boilerplate.py b/hooks/boilerplate.py new file mode 100755 index 00000000000..3b04c78420f --- /dev/null +++ b/hooks/boilerplate.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python + +# Copyright 2015 The Kubernetes Authors All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function + +import json +import mmap +import os +import re +import sys + +def PrintError(*err): + print(*err, file=sys.stderr) + +def file_passes(filename, extention, ref, regex): + try: + f = open(filename, 'r') + except: + return False + + data = f.readlines() + + # remove build tags from the top of Go file + if extention == "go": + while data[0] != "/*\n": + data = data[1:] + + # if our test file is smaller than the reference it surely fails! + if len(ref) > len(data): + return False + + # trim our file to the same number of lines as the reference file + data = data[:len(ref)] + + # Replace all occurances of the regex "2015" with "2014" + for i, d in enumerate(data): + (data[i], found) = regex.subn( '2014', d) + if found != 0: + break + + # if we don't match the reference at this point, fail + if ref != data: + return False + + return True + +def main(): + if len(sys.argv) < 3: + PrintError("usage: %s extension FILENAME [FILENAMES]" % sys.argv[0]) + return False + + basedir = os.path.dirname(os.path.abspath(__file__)) + + extention = sys.argv[1] + # argv[0] is the binary, argv[1] is the extension (go, sh, py, whatever) + filenames = sys.argv[2:] + + ref_filename = basedir + "/boilerplate." + extention + ".txt" + try: + ref_file = open(ref_filename, 'r') + except: + # No boilerplate template is success + return True + ref = ref_file.readlines() + + # dates can be 2014 or 2015, company holder names can be anything + p = re.compile( '(2014|2015)' ) + + for filename in filenames: + if not file_passes(filename, extention, ref, p): + print(filename, file=sys.stdout) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/hooks/boilerplate.sh b/hooks/boilerplate.sh deleted file mode 100755 index 34b6cbf3928..00000000000 --- a/hooks/boilerplate.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -# Copyright 2014 The Kubernetes Authors All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Print 1 if the file in $1 has the correct boilerplate header, 0 otherwise. -FILE=$1 -EXT=${FILE##*.} - -REF_FILE="$(dirname $0)/boilerplate.${EXT}.txt" - -if [ ! -e $REF_FILE ]; then - echo "1" - exit 0 -fi - -LINES=$(cat "${REF_FILE}" | wc -l | tr -d ' ') -if [[ "${EXT}" == "go" ]]; then - # remove build tags from the top of Go file - DIFFER=$(cat "${FILE}" | sed '/\/\*/,$!d' | sed 's/2015/2014/g' | head "-${LINES}" | diff -q - "${REF_FILE}") -else - DIFFER=$(head "-${LINES}" "${FILE}" | sed 's/2015/2014/g' | diff -q - "${REF_FILE}") -fi - -if [[ -z "${DIFFER}" ]]; then - echo "1" - exit 0 -fi - -echo "0" diff --git a/hooks/prepare-commit-msg b/hooks/prepare-commit-msg index ee66b600139..80a29ab934f 100755 --- a/hooks/prepare-commit-msg +++ b/hooks/prepare-commit-msg @@ -5,28 +5,27 @@ KUBE_HOOKS_DIR="$(dirname "$(test -L "$0" && echo "$(dirname $0)/$(readlink "$0" files_need_gofmt=() files_need_boilerplate=() files_need_description=() -for file in $(git diff --cached --name-only --diff-filter ACM | grep "\.go" | grep -v -e "third_party" -e "Godeps"); do + +files=($(git diff --cached --name-only --diff-filter ACM | grep "\.go" | grep -v -e "third_party" -e "Godeps")) +for file in "${files[@]}"; do # Check for files that fail gofmt. diff="$(git show ":${file}" | gofmt -s -d)" if [[ -n "$diff" ]]; then files_need_gofmt+=("${file}") fi - - # Check for files without the required boilerplate. - boilerplate=$("${KUBE_HOOKS_DIR}/boilerplate.sh" "${file}") - if [[ "$boilerplate" -eq "0" ]]; then - files_need_boilerplate+=("${file}") - fi done -# Check sh files for boilerplate -for file in $(git diff --cached --name-only --diff-filter ACM | grep "\.sh" | grep -v -e "third_party" -e "Godeps"); do - # Check for files without the required boilerplate. - boilerplate=$("${KUBE_HOOKS_DIR}/boilerplate.sh" "${file}") - if [[ "$boilerplate" -eq "0" ]]; then - files_need_boilerplate+=("${file}") - fi -done +boiler="${KUBE_HOOKS_DIR}/boilerplate.py" +# Check for go files without the required boilerplate. +if [[ ${#files[@]} -gt 0 ]]; then + files_need_boilerplate+=($("${boiler}" "go" "${files[@]}")) +fi + +# Check for sh files without the required boilerplate. +files=($(git diff --cached --name-only --diff-filter ACM | grep "\.sh" | grep -v -e "third_party" -e "Godeps")) +if [[ ${#files[@]} -gt 0 ]]; then + files_need_boilerplate+=($("${boiler}" "sh" "${files[@]}")) +fi # Check API schema definitions for field descriptions for file in $(git diff --cached --name-only --diff-filter ACM | egrep "pkg/api/v.[^/]*/types\.go" | grep -v "third_party"); do