boilerplate.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #!/usr/bin/env python3
  2. # Copyright 2014 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """Create files with copyright boilerplate and header include guards.
  6. Usage: tools/boilerplate.py path/to/file.{h,cc}
  7. """
  8. from __future__ import print_function, unicode_literals
  9. from datetime import date
  10. import io
  11. import os
  12. import os.path
  13. import sys
  14. LINES = [
  15. f'Copyright {date.today().year} The Chromium Authors.',
  16. 'Use of this source code is governed by a BSD-style license that can be',
  17. 'found in the LICENSE file.'
  18. ]
  19. NO_COMPILE_LINES = [
  20. 'This is a "No Compile Test" suite.',
  21. 'https://dev.chromium.org/developers/testing/no-compile-tests'
  22. ]
  23. EXTENSIONS_TO_COMMENTS = {
  24. 'h': '//',
  25. 'cc': '//',
  26. 'nc': '//',
  27. 'mm': '//',
  28. 'js': '//',
  29. 'py': '#',
  30. 'gn': '#',
  31. 'gni': '#',
  32. 'mojom': '//',
  33. 'ts': '//',
  34. 'typemap': '#',
  35. "swift": "//",
  36. }
  37. def _GetHeaderImpl(filename, lines):
  38. _, ext = os.path.splitext(filename)
  39. ext = ext[1:]
  40. comment = EXTENSIONS_TO_COMMENTS[ext] + ' '
  41. return '\n'.join([comment + line for line in lines])
  42. def _GetHeader(filename):
  43. return _GetHeaderImpl(filename, LINES)
  44. def _GetNoCompileHeader(filename):
  45. assert (filename.endswith(".nc"))
  46. return '\n' + _GetHeaderImpl(filename, NO_COMPILE_LINES)
  47. def _CppHeader(filename):
  48. guard = filename.upper() + '_'
  49. for char in '/\\.+':
  50. guard = guard.replace(char, '_')
  51. return '\n'.join([
  52. '',
  53. '#ifndef ' + guard,
  54. '#define ' + guard,
  55. '',
  56. '#endif // ' + guard,
  57. ''
  58. ])
  59. def _RemoveCurrentDirectoryPrefix(filename):
  60. current_dir_prefixes = [os.curdir + os.sep]
  61. if os.altsep is not None:
  62. current_dir_prefixes.append(os.curdir + os.altsep)
  63. for prefix in current_dir_prefixes:
  64. if filename.startswith(prefix):
  65. return filename[len(prefix):]
  66. return filename
  67. def _RemoveTestSuffix(filename):
  68. base, _ = os.path.splitext(filename)
  69. suffixes = [ '_test', '_unittest', '_browsertest' ]
  70. for suffix in suffixes:
  71. l = len(suffix)
  72. if base[-l:] == suffix:
  73. return base[:-l]
  74. return base
  75. def _IsIOSFile(filename):
  76. if os.path.splitext(os.path.basename(filename))[0].endswith('_ios'):
  77. return True
  78. if 'ios' in filename.split(os.path.sep):
  79. return True
  80. return False
  81. def _FilePathSlashesToCpp(filename):
  82. return filename.replace('\\', '/')
  83. def _CppImplementation(filename):
  84. return '\n#include "' + _FilePathSlashesToCpp(_RemoveTestSuffix(filename)) \
  85. + '.h"\n'
  86. def _ObjCppImplementation(filename):
  87. implementation = '\n#import "' + _RemoveTestSuffix(filename) + '.h"\n'
  88. if not _IsIOSFile(filename):
  89. return implementation
  90. implementation += '\n'
  91. implementation += '#if !defined(__has_feature) || !__has_feature(objc_arc)\n'
  92. implementation += '#error "This file requires ARC support."\n'
  93. implementation += '#endif\n'
  94. return implementation
  95. def _CreateFile(filename):
  96. filename = _RemoveCurrentDirectoryPrefix(filename)
  97. contents = _GetHeader(filename) + '\n'
  98. if filename.endswith('.h'):
  99. contents += _CppHeader(filename)
  100. elif filename.endswith('.cc'):
  101. contents += _CppImplementation(filename)
  102. elif filename.endswith('.nc'):
  103. contents += _GetNoCompileHeader(filename) + '\n'
  104. contents += _CppImplementation(filename)
  105. elif filename.endswith('.mm'):
  106. contents += _ObjCppImplementation(filename)
  107. with io.open(filename, mode='w', newline='\n') as fd:
  108. fd.write(contents)
  109. def Main():
  110. files = sys.argv[1:]
  111. if len(files) < 1:
  112. print(
  113. 'Usage: boilerplate.py path/to/file.h path/to/file.cc', file=sys.stderr)
  114. return 1
  115. # Perform checks first so that the entire operation is atomic.
  116. for f in files:
  117. _, ext = os.path.splitext(f)
  118. if not ext[1:] in EXTENSIONS_TO_COMMENTS:
  119. print('Unknown file type for %s' % f, file=sys.stderr)
  120. return 2
  121. if os.path.exists(f):
  122. print('A file at path %s already exists' % f, file=sys.stderr)
  123. return 2
  124. for f in files:
  125. _CreateFile(f)
  126. if __name__ == '__main__':
  127. sys.exit(Main())