Skip to content

Commit 7232188

Browse files
committed
Add verification scripts
1 parent c3fade7 commit 7232188

9 files changed

Lines changed: 484 additions & 0 deletions
File renamed without changes.

hack/boilerplate/boilerplate.py

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2015 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
from __future__ import print_function
18+
19+
import argparse
20+
import difflib
21+
import glob
22+
import json
23+
import mmap
24+
import os
25+
import re
26+
import sys
27+
from datetime import date
28+
29+
parser = argparse.ArgumentParser()
30+
parser.add_argument(
31+
"filenames",
32+
help="list of files to check, all files if unspecified",
33+
nargs='*')
34+
35+
rootdir = os.path.dirname(__file__) + "/../../"
36+
rootdir = os.path.abspath(rootdir)
37+
parser.add_argument(
38+
"--rootdir", default=rootdir, help="root directory to examine")
39+
40+
default_boilerplate_dir = os.path.join(rootdir, "hack/boilerplate")
41+
parser.add_argument(
42+
"--boilerplate-dir", default=default_boilerplate_dir)
43+
44+
parser.add_argument(
45+
"-v", "--verbose",
46+
help="give verbose output regarding why a file does not pass",
47+
action="store_true")
48+
49+
args = parser.parse_args()
50+
51+
verbose_out = sys.stderr if args.verbose else open("/dev/null", "w")
52+
53+
54+
def get_refs():
55+
refs = {}
56+
57+
for path in glob.glob(os.path.join(args.boilerplate_dir, "boilerplate.*.txt")):
58+
extension = os.path.basename(path).split(".")[1]
59+
60+
ref_file = open(path, 'r')
61+
ref = ref_file.read().splitlines()
62+
ref_file.close()
63+
refs[extension] = ref
64+
65+
return refs
66+
67+
68+
def file_passes(filename, refs, regexs):
69+
try:
70+
f = open(filename, 'r')
71+
except Exception as exc:
72+
print("Unable to open %s: %s" % (filename, exc), file=verbose_out)
73+
return False
74+
75+
data = f.read()
76+
f.close()
77+
78+
basename = os.path.basename(filename)
79+
extension = file_extension(filename)
80+
if extension != "":
81+
ref = refs[extension]
82+
else:
83+
ref = refs[basename]
84+
85+
# remove build tags from the top of Go files
86+
if extension == "go":
87+
p = regexs["go_build_constraints"]
88+
(data, found) = p.subn("", data, 1)
89+
90+
# remove shebang from the top of shell files
91+
if extension == "sh":
92+
p = regexs["shebang"]
93+
(data, found) = p.subn("", data, 1)
94+
95+
data = data.splitlines()
96+
97+
# if our test file is smaller than the reference it surely fails!
98+
if len(ref) > len(data):
99+
print('File %s smaller than reference (%d < %d)' %
100+
(filename, len(data), len(ref)),
101+
file=verbose_out)
102+
return False
103+
104+
# trim our file to the same number of lines as the reference file
105+
data = data[:len(ref)]
106+
107+
p = regexs["year"]
108+
for d in data:
109+
if p.search(d):
110+
print('File %s is missing the year' % filename, file=verbose_out)
111+
return False
112+
113+
# Replace all occurrences of the regex "CURRENT_YEAR|...|2016|2015|2014" with "YEAR"
114+
p = regexs["date"]
115+
for i, d in enumerate(data):
116+
(data[i], found) = p.subn('YEAR', d)
117+
if found != 0:
118+
break
119+
120+
# if we don't match the reference at this point, fail
121+
if ref != data:
122+
print("Header in %s does not match reference, diff:" %
123+
filename, file=verbose_out)
124+
if args.verbose:
125+
print(file=verbose_out)
126+
for line in difflib.unified_diff(ref, data, 'reference', filename, lineterm=''):
127+
print(line, file=verbose_out)
128+
print(file=verbose_out)
129+
return False
130+
131+
return True
132+
133+
134+
def file_extension(filename):
135+
return os.path.splitext(filename)[1].split(".")[-1].lower()
136+
137+
138+
skipped_dirs = [
139+
'.git',
140+
"vendor",
141+
"test/e2e/framework/framework.go",
142+
"images"
143+
]
144+
145+
146+
def normalize_files(files):
147+
newfiles = []
148+
for pathname in files:
149+
if any(x in pathname for x in skipped_dirs):
150+
continue
151+
newfiles.append(pathname)
152+
for i, pathname in enumerate(newfiles):
153+
if not os.path.isabs(pathname):
154+
newfiles[i] = os.path.join(args.rootdir, pathname)
155+
return newfiles
156+
157+
158+
def get_files(extensions):
159+
files = []
160+
if len(args.filenames) > 0:
161+
files = args.filenames
162+
else:
163+
for root, dirs, walkfiles in os.walk(args.rootdir):
164+
# don't visit certain dirs. This is just a performance improvement
165+
# as we would prune these later in normalize_files(). But doing it
166+
# cuts down the amount of filesystem walking we do and cuts down
167+
# the size of the file list
168+
for d in skipped_dirs:
169+
if d in dirs:
170+
dirs.remove(d)
171+
172+
for name in walkfiles:
173+
pathname = os.path.join(root, name)
174+
files.append(pathname)
175+
176+
files = normalize_files(files)
177+
outfiles = []
178+
for pathname in files:
179+
basename = os.path.basename(pathname)
180+
extension = file_extension(pathname)
181+
if extension in extensions or basename in extensions:
182+
outfiles.append(pathname)
183+
return outfiles
184+
185+
186+
def get_regexs():
187+
regexs = {}
188+
# Search for "YEAR" which exists in the boilerplate, but shouldn't in the real thing
189+
regexs["year"] = re.compile('YEAR')
190+
# dates can be 2014, 2015, 2016, ..., CURRENT_YEAR, company holder names can be anything
191+
years = range(2014, date.today().year + 1)
192+
regexs["date"] = re.compile(
193+
'(%s)' % "|".join(map(lambda l: str(l), years)))
194+
# strip // +build \n\n build constraints
195+
regexs["go_build_constraints"] = re.compile(
196+
r"^(// \+build.*\n)+\n", re.MULTILINE)
197+
# strip #!.* from shell scripts
198+
regexs["shebang"] = re.compile(r"^(#!.*\n)\n*", re.MULTILINE)
199+
return regexs
200+
201+
202+
def main():
203+
regexs = get_regexs()
204+
refs = get_refs()
205+
filenames = get_files(refs.keys())
206+
207+
for filename in filenames:
208+
if not file_passes(filename, refs, regexs):
209+
print(filename, file=sys.stdout)
210+
211+
return 0
212+
213+
214+
if __name__ == "__main__":
215+
sys.exit(main())
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright YEAR The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright YEAR The Kubernetes Authors.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+

hack/kube-env.sh

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/bin/bash
2+
3+
# Copyright 2014 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
# Some useful colors.
18+
if [[ -z "${color_start-}" ]]; then
19+
declare -r color_start="\033["
20+
declare -r color_red="${color_start}0;31m"
21+
declare -r color_yellow="${color_start}0;33m"
22+
declare -r color_green="${color_start}0;32m"
23+
declare -r color_norm="${color_start}0m"
24+
fi
25+
26+
# Returns the server version as MMmmpp, with MM as the major
27+
# component, mm the minor component, and pp as the patch
28+
# revision. e.g. 0.7.1 is echoed as 701, and 1.0.11 would be
29+
# 10011. (This makes for easy integer comparison in bash.)
30+
function kube_server_version() {
31+
local server_version
32+
local major
33+
local minor
34+
local patch
35+
36+
# This sed expression is the POSIX BRE to match strings like:
37+
# Server Version: &version.Info{Major:"0", Minor:"7+", GitVersion:"v0.7.0-dirty", GitCommit:"ad44234f7152e9c66bc2853575445c7071335e57", GitTreeState:"dirty"}
38+
# and capture the GitVersion portion (which has the patch level)
39+
server_version=$(${KUBECTL} --match-server-version=false version | grep "Server Version:")
40+
read major minor patch < <(
41+
echo ${server_version} | \
42+
sed "s/.*GitVersion:\"v\([0-9]\{1,\}\)\.\([0-9]\{1,\}\)\.\([0-9]\{1,\}\).*/\1 \2 \3/")
43+
printf "%02d%02d%02d" ${major} ${minor} ${patch} | sed 's/^0*//'
44+
}

hack/verify-all.sh

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#!/bin/bash
2+
3+
# Copyright 2014 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
set -o errexit
18+
set -o nounset
19+
set -o pipefail
20+
21+
SCRIPT_ROOT=$(dirname "${BASH_SOURCE}")/..
22+
source "${SCRIPT_ROOT}/hack/kube-env.sh"
23+
24+
SILENT=true
25+
26+
function is-excluded {
27+
for e in $EXCLUDE; do
28+
if [[ $1 -ef ${BASH_SOURCE} ]]; then
29+
return
30+
fi
31+
if [[ $1 -ef "$SCRIPT_ROOT/hack/$e" ]]; then
32+
return
33+
fi
34+
done
35+
return 1
36+
}
37+
38+
while getopts ":v" opt; do
39+
case $opt in
40+
v)
41+
SILENT=false
42+
;;
43+
\?)
44+
echo "Invalid flag: -$OPTARG" >&2
45+
exit 1
46+
;;
47+
esac
48+
done
49+
50+
if $SILENT ; then
51+
echo "Running in the silent mode, run with -v if you want to see script logs."
52+
fi
53+
54+
EXCLUDE="verify-all.sh"
55+
56+
ret=0
57+
for t in `ls $SCRIPT_ROOT/hack/verify-*.sh`
58+
do
59+
if is-excluded $t ; then
60+
echo "Skipping $t"
61+
continue
62+
fi
63+
if $SILENT ; then
64+
echo -e "Verifying $t"
65+
if bash "$t" &> /dev/null; then
66+
echo -e "${color_green}SUCCESS${color_norm}"
67+
else
68+
echo -e "${color_red}FAILED${color_norm}"
69+
ret=1
70+
fi
71+
else
72+
bash "$t" || ret=1
73+
fi
74+
done
75+
76+
exit $ret
77+
78+
# ex: ts=2 sw=2 et filetype=sh

0 commit comments

Comments
 (0)