mbonadei | 74973ed | 2017-05-09 07:58:05 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
| 3 | # |
| 4 | # Use of this source code is governed by a BSD-style license |
| 5 | # that can be found in the LICENSE file in the root of the source |
| 6 | # tree. An additional intellectual property rights grant can be found |
| 7 | # in the file PATENTS. All contributing project authors may |
| 8 | # be found in the AUTHORS file in the root of the source tree. |
| 9 | |
| 10 | import os |
| 11 | import re |
mbonadei | 26c2634 | 2017-05-12 02:06:16 -0700 | [diff] [blame] | 12 | import string |
mbonadei | 74973ed | 2017-05-09 07:58:05 -0700 | [diff] [blame] | 13 | |
| 14 | |
| 15 | # TARGET_RE matches a GN target, and extracts the target name and the contents. |
| 16 | TARGET_RE = re.compile(r'(?P<indent>\s*)\w+\("(?P<target_name>\w+)"\) {' |
| 17 | r'(?P<target_contents>.*?)' |
| 18 | r'(?P=indent)}', |
| 19 | re.MULTILINE | re.DOTALL) |
| 20 | |
| 21 | # SOURCES_RE matches a block of sources inside a GN target. |
mbonadei | 84ab581 | 2017-05-10 08:04:34 -0700 | [diff] [blame] | 22 | SOURCES_RE = re.compile( |
Patrik Höglund | ac086af | 2017-09-29 16:07:49 +0200 | [diff] [blame] | 23 | r'(sources|public|common_objc_headers) \+?= \[(?P<sources>.*?)\]', |
mbonadei | 84ab581 | 2017-05-10 08:04:34 -0700 | [diff] [blame] | 24 | re.MULTILINE | re.DOTALL) |
mbonadei | 74973ed | 2017-05-09 07:58:05 -0700 | [diff] [blame] | 25 | |
| 26 | SOURCE_FILE_RE = re.compile(r'.*\"(?P<source_file>.*)\"') |
| 27 | |
| 28 | |
| 29 | class NoBuildGnFoundError(Exception): |
| 30 | pass |
| 31 | |
| 32 | |
| 33 | class WrongFileTypeError(Exception): |
| 34 | pass |
| 35 | |
| 36 | |
| 37 | def _ReadFile(file_path): |
| 38 | """Returns the content of file_path in a string. |
| 39 | |
| 40 | Args: |
| 41 | file_path: the path of the file to read. |
| 42 | Returns: |
| 43 | A string with the content of the file. |
| 44 | """ |
| 45 | with open(file_path) as f: |
| 46 | return f.read() |
| 47 | |
| 48 | |
| 49 | def GetBuildGnPathFromFilePath(file_path, file_exists_check, root_dir_path): |
| 50 | """Returns the BUILD.gn file responsible for file_path. |
| 51 | |
| 52 | Args: |
| 53 | file_path: the absolute path to the .h file to check. |
| 54 | file_exists_check: a function that defines how to check if a file exists |
| 55 | on the file system. |
| 56 | root_dir_path: the absolute path of the root of project. |
| 57 | |
| 58 | Returns: |
| 59 | A string with the absolute path to the BUILD.gn file responsible to include |
| 60 | file_path in a target. |
| 61 | """ |
| 62 | if not file_path.endswith('.h'): |
| 63 | raise WrongFileTypeError( |
| 64 | 'File {} is not an header file (.h)'.format(file_path)) |
| 65 | candidate_dir = os.path.dirname(file_path) |
| 66 | while candidate_dir.startswith(root_dir_path): |
| 67 | candidate_build_gn_path = os.path.join(candidate_dir, 'BUILD.gn') |
| 68 | if file_exists_check(candidate_build_gn_path): |
| 69 | return candidate_build_gn_path |
| 70 | else: |
| 71 | candidate_dir = os.path.abspath(os.path.join(candidate_dir, |
| 72 | os.pardir)) |
| 73 | raise NoBuildGnFoundError( |
| 74 | 'No BUILD.gn file found for file: `{}`'.format(file_path)) |
| 75 | |
| 76 | |
| 77 | def IsHeaderInBuildGn(header_path, build_gn_path): |
| 78 | """Returns True if the header is listed in the BUILD.gn file. |
| 79 | |
| 80 | Args: |
| 81 | header_path: the absolute path to the header to check. |
| 82 | build_gn_path: the absolute path to the header to check. |
| 83 | |
| 84 | Returns: |
| 85 | bool: True if the header_path is an header that is listed in |
| 86 | at least one GN target in the BUILD.gn file specified by |
| 87 | the argument build_gn_path. |
| 88 | """ |
| 89 | target_abs_path = os.path.dirname(build_gn_path) |
| 90 | build_gn_content = _ReadFile(build_gn_path) |
| 91 | headers_in_build_gn = GetHeadersInBuildGnFileSources(build_gn_content, |
| 92 | target_abs_path) |
| 93 | return header_path in headers_in_build_gn |
| 94 | |
| 95 | |
| 96 | def GetHeadersInBuildGnFileSources(file_content, target_abs_path): |
| 97 | """Returns a set with all the .h files in the file_content. |
| 98 | |
| 99 | Args: |
| 100 | file_content: a string with the content of the BUILD.gn file. |
| 101 | target_abs_path: the absolute path to the directory where the |
| 102 | BUILD.gn file lives. |
| 103 | |
| 104 | Returns: |
| 105 | A set with all the headers (.h file) in the file_content. |
| 106 | The set contains absolute paths. |
| 107 | """ |
| 108 | headers_in_sources = set([]) |
| 109 | for target_match in TARGET_RE.finditer(file_content): |
| 110 | target_contents = target_match.group('target_contents') |
| 111 | for sources_match in SOURCES_RE.finditer(target_contents): |
| 112 | sources = sources_match.group('sources') |
| 113 | for source_file_match in SOURCE_FILE_RE.finditer(sources): |
| 114 | source_file = source_file_match.group('source_file') |
| 115 | if source_file.endswith('.h'): |
mbonadei | 26c2634 | 2017-05-12 02:06:16 -0700 | [diff] [blame] | 116 | source_file_tokens = string.split(source_file, '/') |
mbonadei | 26c2634 | 2017-05-12 02:06:16 -0700 | [diff] [blame] | 117 | headers_in_sources.add(os.path.join(target_abs_path, |
| 118 | *source_file_tokens)) |
mbonadei | 74973ed | 2017-05-09 07:58:05 -0700 | [diff] [blame] | 119 | return headers_in_sources |