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