|  | #!/usr/bin/env python | 
|  |  | 
|  | # Copyright 2017 Google Inc. | 
|  | # | 
|  | # Use of this source code is governed by a BSD-style license that can be | 
|  | # found in the LICENSE file. | 
|  |  | 
|  | import multiprocessing | 
|  | import os | 
|  | import re | 
|  | import subprocess | 
|  | import sys | 
|  |  | 
|  | ''' | 
|  | If called with arguments, this script will verify that those headers are | 
|  | self-sufficient and idempotent. | 
|  |  | 
|  | Otherwise, test all checked-in headers except for those in the ignore list. | 
|  | ''' | 
|  |  | 
|  | ignore = re.compile('|'.join([ | 
|  | r'debugger/QT/.*', | 
|  | r'example/.*', | 
|  | r'experimental/.*', | 
|  | r'include/config/.*', | 
|  | r'include/gpu/mtl/.*', | 
|  | r'include/gpu/vk/.*', | 
|  | r'include/ports/SkFontMgr_android\.h', | 
|  | r'include/ports/SkFontMgr_fontconfig\.h', | 
|  | r'include/ports/SkFontMgr_fuchsia\.h', | 
|  | r'include/ports/SkTypeface_win\.h', | 
|  | r'include/private/.*_impl\.h', | 
|  | r'include/private/.*_neon\.h', | 
|  | r'include/private/.*_sse\.h', | 
|  | r'include/third_party/vulkan/.*', | 
|  | r'include/utils/mac/SkCGUtils\.h', | 
|  | r'include/views/SkOSWindow_.*\.h', | 
|  | r'modules/.*', | 
|  | r'platform_tools/.*', | 
|  | r'src/c/sk_c_from_to\.h', | 
|  | r'src/core/.*Template\.h', | 
|  | r'src/core/SkBitmapProcState_.*\.h', | 
|  | r'src/core/SkLinearBitmapPipeline\.h', | 
|  | r'src/core/SkLinearBitmapPipeline_.*\.h', | 
|  | r'src/gpu/mtl/.*', | 
|  | r'src/gpu/vk/.*', | 
|  | r'src/opts/.*_SSE2\.h', | 
|  | r'src/opts/.*_SSSE3\.h', | 
|  | r'src/opts/.*_neon\.h', | 
|  | r'src/opts/.*_sse\.h', | 
|  | r'src/ports/.*', | 
|  | r'src/utils/.*_win\.h', | 
|  | r'src/utils/win/.*', | 
|  | r'src/views/.*', | 
|  | r'third_party/.*', | 
|  | r'tools/fiddle/.*', | 
|  | r'tools/gpu/vk/.*', | 
|  | r'tools/ganesh/vk/.*', | 
|  | r'tools/sk_app/.*', | 
|  | r'tools/viewer/.*', | 
|  | ])) | 
|  |  | 
|  |  | 
|  | # test header for self-sufficiency and idempotency. | 
|  | # Returns a string containing errors, or None iff there are no errors. | 
|  | def compile_header(header): | 
|  | cmd = ['c++', '--std=c++14', '-I.', '-o', '/dev/null', '-c', '-x', 'c++', '-'] | 
|  | proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, | 
|  | stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | 
|  | proc.stdin.write('#include "%s"\n#include "%s"\n' % (header, header)) | 
|  | proc.stdin.close() | 
|  | errors = proc.stdout.read().strip() | 
|  | if proc.wait() != 0 or len(errors) > 0: | 
|  | return '\n\033[7m ERROR: %s \033[0m\n%s\n\n' % (header, errors) | 
|  | return None | 
|  |  | 
|  |  | 
|  | #     for h in headers: | 
|  | #         compile_header(h) | 
|  | # ...Except use a multiprocessing pool. | 
|  | # Exit at first error. | 
|  | def compile_headers(headers): | 
|  | class N: good = True | 
|  | # N.good is a global scoped to this function to make a print_and_exit_if() a closure | 
|  | pool = multiprocessing.Pool() | 
|  | def print_and_exit_if(r): | 
|  | if r is not None: | 
|  | sys.stdout.write(r) | 
|  | N.good = False | 
|  | pool.terminate() | 
|  | for path in headers: | 
|  | assert os.path.exists(path) | 
|  | pool.apply_async(compile_header, args=(path, ), callback=print_and_exit_if) | 
|  | pool.close() | 
|  | pool.join() | 
|  | if N.good: | 
|  | sys.stdout.write('all good :)\n') | 
|  | else: | 
|  | exit(1) | 
|  |  | 
|  |  | 
|  | def main(argv): | 
|  | skia_dir = os.path.join(os.path.dirname(__file__), os.pardir) | 
|  | if len(argv) > 1: | 
|  | paths = [os.path.relpath(os.path.abspath(arg), skia_dir) for arg in argv[1:]] | 
|  | os.chdir(skia_dir) | 
|  | else: | 
|  | os.chdir(skia_dir) | 
|  | paths = [path for path in subprocess.check_output(['git', 'ls-files']).splitlines() | 
|  | if path.endswith('.h') and not ignore.match(path)] | 
|  | compile_headers(paths) | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | main(sys.argv) |