blob: deb445cd8caaa060a2b2760074cd481fcd5efbb9 [file] [log] [blame]
mbonadei74973ed2017-05-09 07:58:05 -07001#!/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
10import os
11import re
mbonadei26c26342017-05-12 02:06:16 -070012import string
mbonadei74973ed2017-05-09 07:58:05 -070013
14
15# TARGET_RE matches a GN target, and extracts the target name and the contents.
16TARGET_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.
mbonadei84ab5812017-05-10 08:04:34 -070022SOURCES_RE = re.compile(
Patrik Höglundac086af2017-09-29 16:07:49 +020023 r'(sources|public|common_objc_headers) \+?= \[(?P<sources>.*?)\]',
mbonadei84ab5812017-05-10 08:04:34 -070024 re.MULTILINE | re.DOTALL)
mbonadei74973ed2017-05-09 07:58:05 -070025
26SOURCE_FILE_RE = re.compile(r'.*\"(?P<source_file>.*)\"')
27
28
29class NoBuildGnFoundError(Exception):
30 pass
31
32
33class WrongFileTypeError(Exception):
34 pass
35
36
37def _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
49def 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
77def 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
96def 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'):
mbonadei26c26342017-05-12 02:06:16 -0700116 source_file_tokens = string.split(source_file, '/')
mbonadei26c26342017-05-12 02:06:16 -0700117 headers_in_sources.add(os.path.join(target_abs_path,
118 *source_file_tokens))
mbonadei74973ed2017-05-09 07:58:05 -0700119 return headers_in_sources