PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/hack/boilerplate/boilerplate.py

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