summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/tools_webrtc/presubmit_checks_lib')
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/__init__.py0
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/build_helpers.py134
-rwxr-xr-xthird_party/libwebrtc/tools_webrtc/presubmit_checks_lib/build_helpers_test.py32
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_orphan_headers.py116
-rwxr-xr-xthird_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_orphan_headers_test.py113
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_package_boundaries.py133
-rwxr-xr-xthird_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_package_boundaries_test.py71
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/BUILD.gn14
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/expected.pyl16
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage1/BUILD.gn15
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage1/subsubpackage1/BUILD.gn0
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage2/BUILD.gn15
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage2/subsubpackage2/BUILD.gn0
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/circular_dependency/.gn1
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/circular_dependency/BUILD.gn10
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/circular_dependency/BUILDCONFIG.gn1
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/common_prefix/BUILD.gn15
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/common_prefix/call/BUILD.gn0
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/common_prefix/expected.pyl1
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/dangerous_filename/BUILD.gn13
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/dangerous_filename/expected.pyl4
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/dangerous_filename/libc++/BUILD.gn11
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/BUILD.gn28
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/expected.pyl16
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/subpackage1/BUILD.gn0
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/subpackage2/BUILD.gn0
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_single_target/BUILD.gn14
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_single_target/expected.pyl8
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_single_target/subpackage/BUILD.gn14
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/no_errors/BUILD.gn16
-rw-r--r--third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/no_errors/expected.pyl1
31 files changed, 812 insertions, 0 deletions
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/__init__.py b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/__init__.py
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/build_helpers.py b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/build_helpers.py
new file mode 100644
index 0000000000..3386d6d40c
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/build_helpers.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env vpython3
+
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+"""This script helps to invoke gn and ninja
+which lie in depot_tools repository."""
+
+import json
+import os
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+
+
+def FindSrcDirPath():
+ """Returns the abs path to the src/ dir of the project."""
+ src_dir = os.path.dirname(os.path.abspath(__file__))
+ while os.path.basename(src_dir) != 'src':
+ src_dir = os.path.normpath(os.path.join(src_dir, os.pardir))
+ return src_dir
+
+
+SRC_DIR = FindSrcDirPath()
+sys.path.append(os.path.join(SRC_DIR, 'build'))
+import find_depot_tools
+
+
+def RunGnCommand(args, root_dir=None):
+ """Runs `gn` with provided args and return error if any."""
+ try:
+ command = [
+ sys.executable,
+ os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'gn.py')
+ ] + args
+ subprocess.check_output(command, cwd=root_dir)
+ except subprocess.CalledProcessError as err:
+ return err.output
+ return None
+
+
+# GN_ERROR_RE matches the summary of an error output by `gn check`.
+# Matches "ERROR" and following lines until it sees an empty line or a line
+# containing just underscores.
+GN_ERROR_RE = re.compile(r'^ERROR .+(?:\n.*[^_\n].*$)+', re.MULTILINE)
+
+
+def RunGnCheck(root_dir=None):
+ """Runs `gn gen --check` with default args to detect mismatches between
+ #includes and dependencies in the BUILD.gn files, as well as general build
+ errors.
+
+ Returns a list of error summary strings.
+ """
+ out_dir = tempfile.mkdtemp('gn')
+ try:
+ error = RunGnCommand(['gen', '--check', out_dir], root_dir)
+ finally:
+ shutil.rmtree(out_dir, ignore_errors=True)
+ return GN_ERROR_RE.findall(error.decode('utf-8')) if error else []
+
+
+def RunNinjaCommand(args, root_dir=None):
+ """Runs ninja quietly. Any failure (e.g. clang not found) is
+ silently discarded, since this is unlikely an error in submitted CL."""
+ command = [os.path.join(SRC_DIR, 'third_party', 'ninja', 'ninja')] + args
+ p = subprocess.Popen(command,
+ cwd=root_dir,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out, _ = p.communicate()
+ return out
+
+
+def GetClangTidyPath():
+ """POC/WIP! Use the one we have, even it doesn't match clang's version."""
+ tidy = ('third_party/android_ndk/toolchains/'
+ 'llvm/prebuilt/linux-x86_64/bin/clang-tidy')
+ return os.path.join(SRC_DIR, tidy)
+
+
+def GetCompilationDb(root_dir=None):
+ """Run ninja compdb tool to get proper flags, defines and include paths."""
+ # The compdb tool expect a rule.
+ commands = json.loads(RunNinjaCommand(['-t', 'compdb', 'cxx'], root_dir))
+ # Turns 'file' field into a key.
+ return {v['file']: v for v in commands}
+
+
+def GetCompilationCommand(filepath, gn_args, work_dir):
+ """Get the whole command used to compile one cc file.
+ Typically, clang++ with flags, defines and include paths.
+
+ Args:
+ filepath: path to .cc file.
+ gen_args: build configuration for gn.
+ work_dir: build dir.
+
+ Returns:
+ Command as a list, ready to be consumed by subprocess.Popen.
+ """
+ gn_errors = RunGnCommand(['gen'] + gn_args + [work_dir])
+ if gn_errors:
+ raise RuntimeError('FYI, cannot complete check due to gn error:\n%s\n'
+ 'Please open a bug.' % gn_errors)
+
+ # Needed for single file compilation.
+ commands = GetCompilationDb(work_dir)
+
+ # Path as referenced by ninja.
+ rel_path = os.path.relpath(os.path.abspath(filepath), work_dir)
+
+ # Gather defines, include path and flags (such as -std=c++11).
+ try:
+ compilation_entry = commands[rel_path]
+ except KeyError as not_found:
+ raise ValueError('%s: Not found in compilation database.\n'
+ 'Please check the path.' % filepath) from not_found
+ command = compilation_entry['command'].split()
+
+ # Remove troublesome flags. May trigger an error otherwise.
+ if '-MMD' in command:
+ command.remove('-MMD')
+ if '-MF' in command:
+ index = command.index('-MF')
+ del command[index:index + 2] # Remove filename as well.
+
+ return command
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/build_helpers_test.py b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/build_helpers_test.py
new file mode 100755
index 0000000000..42b94d6c29
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/build_helpers_test.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env vpython3
+
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import re
+import os
+import unittest
+
+import build_helpers
+
+TESTDATA_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+ 'testdata')
+
+
+class GnCheckTest(unittest.TestCase):
+
+ def testCircularDependencyError(self):
+ test_dir = os.path.join(TESTDATA_DIR, 'circular_dependency')
+ expected_error = re.compile('ERROR Dependency cycle')
+ gn_output = build_helpers.RunGnCheck(test_dir)
+ self.assertEqual(1, len(gn_output))
+ self.assertRegex(gn_output[0], expected_error)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_orphan_headers.py b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_orphan_headers.py
new file mode 100644
index 0000000000..ae5b5baf2f
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_orphan_headers.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env vpython3
+
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import os
+import re
+
+# TARGET_RE matches a GN target, and extracts the target name and the contents.
+TARGET_RE = re.compile(
+ r'(?P<indent>\s*)\w+\("(?P<target_name>\w+)"\) {'
+ r'(?P<target_contents>.*?)'
+ r'(?P=indent)}', re.MULTILINE | re.DOTALL)
+
+# SOURCES_RE matches a block of sources inside a GN target.
+SOURCES_RE = re.compile(
+ r'(sources|public|common_objc_headers) \+?= \[(?P<sources>.*?)\]',
+ re.MULTILINE | re.DOTALL)
+
+SOURCE_FILE_RE = re.compile(r'.*\"(?P<source_file>.*)\"')
+
+
+class NoBuildGnFoundError(Exception):
+ pass
+
+
+class WrongFileTypeError(Exception):
+ pass
+
+
+def _ReadFile(file_path):
+ """Returns the content of file_path in a string.
+
+ Args:
+ file_path: the path of the file to read.
+ Returns:
+ A string with the content of the file.
+ """
+ with open(file_path) as f:
+ return f.read()
+
+
+def GetBuildGnPathFromFilePath(file_path, file_exists_check, root_dir_path):
+ """Returns the BUILD.gn file responsible for file_path.
+
+ Args:
+ file_path: the absolute path to the .h file to check.
+ file_exists_check: a function that defines how to check if a file exists
+ on the file system.
+ root_dir_path: the absolute path of the root of project.
+
+ Returns:
+ A string with the absolute path to the BUILD.gn file responsible to include
+ file_path in a target.
+ """
+ if not file_path.endswith('.h'):
+ raise WrongFileTypeError(
+ 'File {} is not an header file (.h)'.format(file_path))
+ candidate_dir = os.path.dirname(file_path)
+ while candidate_dir.startswith(root_dir_path):
+ candidate_build_gn_path = os.path.join(candidate_dir, 'BUILD.gn')
+ if file_exists_check(candidate_build_gn_path):
+ return candidate_build_gn_path
+ candidate_dir = os.path.abspath(os.path.join(candidate_dir, os.pardir))
+ raise NoBuildGnFoundError(
+ 'No BUILD.gn file found for file: `{}`'.format(file_path))
+
+
+def IsHeaderInBuildGn(header_path, build_gn_path):
+ """Returns True if the header is listed in the BUILD.gn file.
+
+ Args:
+ header_path: the absolute path to the header to check.
+ build_gn_path: the absolute path to the header to check.
+
+ Returns:
+ bool: True if the header_path is an header that is listed in
+ at least one GN target in the BUILD.gn file specified by
+ the argument build_gn_path.
+ """
+ target_abs_path = os.path.dirname(build_gn_path)
+ build_gn_content = _ReadFile(build_gn_path)
+ headers_in_build_gn = GetHeadersInBuildGnFileSources(build_gn_content,
+ target_abs_path)
+ return header_path in headers_in_build_gn
+
+
+def GetHeadersInBuildGnFileSources(file_content, target_abs_path):
+ """Returns a set with all the .h files in the file_content.
+
+ Args:
+ file_content: a string with the content of the BUILD.gn file.
+ target_abs_path: the absolute path to the directory where the
+ BUILD.gn file lives.
+
+ Returns:
+ A set with all the headers (.h file) in the file_content.
+ The set contains absolute paths.
+ """
+ headers_in_sources = set([])
+ for target_match in TARGET_RE.finditer(file_content):
+ target_contents = target_match.group('target_contents')
+ for sources_match in SOURCES_RE.finditer(target_contents):
+ sources = sources_match.group('sources')
+ for source_file_match in SOURCE_FILE_RE.finditer(sources):
+ source_file = source_file_match.group('source_file')
+ if source_file.endswith('.h'):
+ source_file_tokens = source_file.split('/')
+ headers_in_sources.add(
+ os.path.join(target_abs_path, *source_file_tokens))
+ return headers_in_sources
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_orphan_headers_test.py b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_orphan_headers_test.py
new file mode 100755
index 0000000000..957d7b814a
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_orphan_headers_test.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env vpython3
+
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import os
+import sys
+import unittest
+
+import check_orphan_headers
+
+def _GetRootBasedOnPlatform():
+ if sys.platform.startswith('win'):
+ return 'C:\\'
+ return '/'
+
+
+def _GetPath(*path_chunks):
+ return os.path.join(_GetRootBasedOnPlatform(), *path_chunks)
+
+
+class GetBuildGnPathFromFilePathTest(unittest.TestCase):
+ def testGetBuildGnFromSameDirectory(self):
+ file_path = _GetPath('home', 'projects', 'webrtc', 'base', 'foo.h')
+ expected_build_path = _GetPath('home', 'projects', 'webrtc', 'base',
+ 'BUILD.gn')
+ file_exists = lambda p: p == _GetPath('home', 'projects', 'webrtc', 'base',
+ 'BUILD.gn')
+ src_dir_path = _GetPath('home', 'projects', 'webrtc')
+ self.assertEqual(
+ expected_build_path,
+ check_orphan_headers.GetBuildGnPathFromFilePath(file_path, file_exists,
+ src_dir_path))
+
+ def testGetBuildPathFromParentDirectory(self):
+ file_path = _GetPath('home', 'projects', 'webrtc', 'base', 'foo.h')
+ expected_build_path = _GetPath('home', 'projects', 'webrtc', 'BUILD.gn')
+ file_exists = lambda p: p == _GetPath('home', 'projects', 'webrtc',
+ 'BUILD.gn')
+ src_dir_path = _GetPath('home', 'projects', 'webrtc')
+ self.assertEqual(
+ expected_build_path,
+ check_orphan_headers.GetBuildGnPathFromFilePath(file_path, file_exists,
+ src_dir_path))
+
+ def testExceptionIfNoBuildGnFilesAreFound(self):
+ with self.assertRaises(check_orphan_headers.NoBuildGnFoundError):
+ file_path = _GetPath('home', 'projects', 'webrtc', 'base', 'foo.h')
+ file_exists = lambda p: False
+ src_dir_path = _GetPath('home', 'projects', 'webrtc')
+ check_orphan_headers.GetBuildGnPathFromFilePath(file_path, file_exists,
+ src_dir_path)
+
+ def testExceptionIfFilePathIsNotAnHeader(self):
+ with self.assertRaises(check_orphan_headers.WrongFileTypeError):
+ file_path = _GetPath('home', 'projects', 'webrtc', 'base', 'foo.cc')
+ file_exists = lambda p: False
+ src_dir_path = _GetPath('home', 'projects', 'webrtc')
+ check_orphan_headers.GetBuildGnPathFromFilePath(file_path, file_exists,
+ src_dir_path)
+
+
+class GetHeadersInBuildGnFileSourcesTest(unittest.TestCase):
+ def testEmptyFileReturnsEmptySet(self):
+ self.assertEqual(
+ set([]),
+ check_orphan_headers.GetHeadersInBuildGnFileSources('', '/a/b'))
+
+ def testReturnsSetOfHeadersFromFileContent(self):
+ file_content = """
+ # Some comments
+ if (is_android) {
+ import("//a/b/c.gni")
+ import("//d/e/f.gni")
+ }
+ source_set("foo") {
+ sources = ["foo.h"]
+ deps = [":bar"]
+ }
+ rtc_static_library("bar") {
+ # Public headers should also be included.
+ public = [
+ "public_foo.h",
+ ]
+ sources = [
+ "bar.h",
+ "bar.cc",
+ ]
+ deps = [":bar"]
+ }
+ source_set("baz_foo") {
+ sources = ["baz/foo.h"]
+ }
+ """
+ target_abs_path = _GetPath('a', 'b')
+ self.assertEqual(
+ set([
+ _GetPath('a', 'b', 'foo.h'),
+ _GetPath('a', 'b', 'bar.h'),
+ _GetPath('a', 'b', 'public_foo.h'),
+ _GetPath('a', 'b', 'baz', 'foo.h'),
+ ]),
+ check_orphan_headers.GetHeadersInBuildGnFileSources(
+ file_content, target_abs_path))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_package_boundaries.py b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_package_boundaries.py
new file mode 100644
index 0000000000..6477a17c39
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_package_boundaries.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env vpython3
+
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import argparse
+import collections
+import os
+import re
+import sys
+
+# TARGET_RE matches a GN target, and extracts the target name and the contents.
+TARGET_RE = re.compile(
+ r'(?P<indent>\s*)\w+\("(?P<target_name>\w+)"\) {'
+ r'(?P<target_contents>.*?)'
+ r'(?P=indent)}', re.MULTILINE | re.DOTALL)
+
+# SOURCES_RE matches a block of sources inside a GN target.
+SOURCES_RE = re.compile(r'sources \+?= \[(?P<sources>.*?)\]',
+ re.MULTILINE | re.DOTALL)
+
+ERROR_MESSAGE = ("{build_file_path} in target '{target_name}':\n"
+ " Source file '{source_file}'\n"
+ " crosses boundary of package '{subpackage}'.")
+
+
+class PackageBoundaryViolation(
+ collections.namedtuple(
+ 'PackageBoundaryViolation',
+ 'build_file_path target_name source_file subpackage')):
+ def __str__(self):
+ return ERROR_MESSAGE.format(**self._asdict())
+
+
+def _BuildSubpackagesPattern(packages, query):
+ """Returns a regular expression that matches source files inside subpackages
+ of the given query."""
+ query += os.path.sep
+ length = len(query)
+ pattern = r'\s*"(?P<source_file>(?P<subpackage>'
+ pattern += '|'.join(
+ re.escape(package[length:].replace(os.path.sep, '/'))
+ for package in packages if package.startswith(query))
+ pattern += r')/[\w\./]*)"'
+ return re.compile(pattern)
+
+
+def _ReadFileAndPrependLines(file_path):
+ """Reads the contents of a file."""
+ with open(file_path) as f:
+ return "".join(f.readlines())
+
+
+def _CheckBuildFile(build_file_path, packages):
+ """Iterates over all the targets of the given BUILD.gn file, and verifies that
+ the source files referenced by it don't belong to any of it's subpackages.
+ Returns an iterator over PackageBoundaryViolations for this package.
+ """
+ package = os.path.dirname(build_file_path)
+ subpackages_re = _BuildSubpackagesPattern(packages, package)
+
+ build_file_contents = _ReadFileAndPrependLines(build_file_path)
+ for target_match in TARGET_RE.finditer(build_file_contents):
+ target_name = target_match.group('target_name')
+ target_contents = target_match.group('target_contents')
+ for sources_match in SOURCES_RE.finditer(target_contents):
+ sources = sources_match.group('sources')
+ for subpackages_match in subpackages_re.finditer(sources):
+ subpackage = subpackages_match.group('subpackage')
+ source_file = subpackages_match.group('source_file')
+ if subpackage:
+ yield PackageBoundaryViolation(build_file_path, target_name,
+ source_file, subpackage)
+
+
+def CheckPackageBoundaries(root_dir, build_files=None):
+ packages = [
+ root for root, _, files in os.walk(root_dir) if 'BUILD.gn' in files
+ ]
+
+ if build_files is not None:
+ for build_file_path in build_files:
+ assert build_file_path.startswith(root_dir)
+ else:
+ build_files = [os.path.join(package, 'BUILD.gn') for package in packages]
+
+ messages = []
+ for build_file_path in build_files:
+ messages.extend(_CheckBuildFile(build_file_path, packages))
+ return messages
+
+
+def main(argv):
+ parser = argparse.ArgumentParser(
+ description='Script that checks package boundary violations in GN '
+ 'build files.')
+
+ parser.add_argument('root_dir',
+ metavar='ROOT_DIR',
+ help='The root directory that contains all BUILD.gn '
+ 'files to be processed.')
+ parser.add_argument('build_files',
+ metavar='BUILD_FILE',
+ nargs='*',
+ help='A list of BUILD.gn files to be processed. If no '
+ 'files are given, all BUILD.gn files under ROOT_DIR '
+ 'will be processed.')
+ parser.add_argument('--max_messages',
+ type=int,
+ default=None,
+ help='If set, the maximum number of violations to be '
+ 'displayed.')
+
+ args = parser.parse_args(argv)
+
+ messages = CheckPackageBoundaries(args.root_dir, args.build_files)
+ messages = messages[:args.max_messages]
+
+ for i, message in enumerate(messages):
+ if i > 0:
+ print()
+ print(message)
+
+ return bool(messages)
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_package_boundaries_test.py b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_package_boundaries_test.py
new file mode 100755
index 0000000000..611af3a236
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/check_package_boundaries_test.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env vpython3
+
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import ast
+import os
+import unittest
+
+import check_package_boundaries
+
+MSG_FORMAT = 'ERROR:check_package_boundaries.py: Unexpected %s.'
+TESTDATA_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+ 'testdata')
+
+
+def ReadPylFile(file_path):
+ with open(file_path) as f:
+ return ast.literal_eval(f.read())
+
+
+class UnitTest(unittest.TestCase):
+ def _RunTest(self, test_dir, check_all_build_files=False):
+ build_files = [os.path.join(test_dir, 'BUILD.gn')]
+ if check_all_build_files:
+ build_files = None
+
+ messages = []
+ for violation in check_package_boundaries.CheckPackageBoundaries(
+ test_dir, build_files):
+ build_file_path = os.path.relpath(violation.build_file_path, test_dir)
+ build_file_path = build_file_path.replace(os.path.sep, '/')
+ messages.append(violation._replace(build_file_path=build_file_path))
+
+ expected_messages = ReadPylFile(os.path.join(test_dir, 'expected.pyl'))
+ self.assertListEqual(sorted(expected_messages), sorted(messages))
+
+ def testNoErrors(self):
+ self._RunTest(os.path.join(TESTDATA_DIR, 'no_errors'))
+
+ def testMultipleErrorsSingleTarget(self):
+ self._RunTest(os.path.join(TESTDATA_DIR, 'multiple_errors_single_target'))
+
+ def testMultipleErrorsMultipleTargets(self):
+ self._RunTest(os.path.join(TESTDATA_DIR,
+ 'multiple_errors_multiple_targets'))
+
+ def testCommonPrefix(self):
+ self._RunTest(os.path.join(TESTDATA_DIR, 'common_prefix'))
+
+ def testAllBuildFiles(self):
+ self._RunTest(os.path.join(TESTDATA_DIR, 'all_build_files'), True)
+
+ def testSanitizeFilename(self):
+ # The `dangerous_filename` test case contains a directory with '++' in its
+ # name. If it's not properly escaped, a regex error would be raised.
+ self._RunTest(os.path.join(TESTDATA_DIR, 'dangerous_filename'), True)
+
+ def testRelativeFilename(self):
+ test_dir = os.path.join(TESTDATA_DIR, 'all_build_files')
+ with self.assertRaises(AssertionError):
+ check_package_boundaries.CheckPackageBoundaries(test_dir, ["BUILD.gn"])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/BUILD.gn
new file mode 100644
index 0000000000..46bd2bec8f
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+target("dummy_target_ok") {
+ sources = [
+ "dummy_source.cc",
+ "dummy_source.h",
+ ]
+}
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/expected.pyl b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/expected.pyl
new file mode 100644
index 0000000000..07f98e9a6e
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/expected.pyl
@@ -0,0 +1,16 @@
+[('subpackage2/BUILD.gn',
+ 'error_2',
+ 'subsubpackage2/dummy_subsubpackage2.cc',
+ 'subsubpackage2'),
+ ('subpackage2/BUILD.gn',
+ 'error_2',
+ 'subsubpackage2/dummy_subsubpackage2.h',
+ 'subsubpackage2'),
+ ('subpackage1/BUILD.gn',
+ 'error_1',
+ 'subsubpackage1/dummy_subsubpackage1.cc',
+ 'subsubpackage1'),
+ ('subpackage1/BUILD.gn',
+ 'error_1',
+ 'subsubpackage1/dummy_subsubpackage1.h',
+ 'subsubpackage1')]
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage1/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage1/BUILD.gn
new file mode 100644
index 0000000000..2653a2b607
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage1/BUILD.gn
@@ -0,0 +1,15 @@
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+target("error_1") {
+ sources = [
+ "subpackage1.h",
+ "subsubpackage1/dummy_subsubpackage1.cc",
+ "subsubpackage1/dummy_subsubpackage1.h",
+ ]
+}
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage1/subsubpackage1/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage1/subsubpackage1/BUILD.gn
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage1/subsubpackage1/BUILD.gn
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage2/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage2/BUILD.gn
new file mode 100644
index 0000000000..290036145d
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage2/BUILD.gn
@@ -0,0 +1,15 @@
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+target("error_2") {
+ sources = [
+ "subpackage2.h",
+ "subsubpackage2/dummy_subsubpackage2.cc",
+ "subsubpackage2/dummy_subsubpackage2.h",
+ ]
+}
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage2/subsubpackage2/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage2/subsubpackage2/BUILD.gn
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/all_build_files/subpackage2/subsubpackage2/BUILD.gn
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/circular_dependency/.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/circular_dependency/.gn
new file mode 100644
index 0000000000..9fe0b4226c
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/circular_dependency/.gn
@@ -0,0 +1 @@
+buildconfig = "//BUILDCONFIG.gn"
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/circular_dependency/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/circular_dependency/BUILD.gn
new file mode 100644
index 0000000000..86095b2f79
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/circular_dependency/BUILD.gn
@@ -0,0 +1,10 @@
+toolchain("toolchain") {
+}
+
+static_library("foo") {
+ deps = [ ":bar" ]
+}
+
+static_library("bar") {
+ deps = [ ":foo" ]
+}
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/circular_dependency/BUILDCONFIG.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/circular_dependency/BUILDCONFIG.gn
new file mode 100644
index 0000000000..48c2a464b2
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/circular_dependency/BUILDCONFIG.gn
@@ -0,0 +1 @@
+set_default_toolchain(":toolchain")
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/common_prefix/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/common_prefix/BUILD.gn
new file mode 100644
index 0000000000..dd5145bc68
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/common_prefix/BUILD.gn
@@ -0,0 +1,15 @@
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+rtc_library("webrtc") {
+ sources = [
+ "call.h",
+ "dummy_source.h",
+ ]
+ deps = [ "call" ]
+}
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/common_prefix/call/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/common_prefix/call/BUILD.gn
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/common_prefix/call/BUILD.gn
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/common_prefix/expected.pyl b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/common_prefix/expected.pyl
new file mode 100644
index 0000000000..fe51488c70
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/common_prefix/expected.pyl
@@ -0,0 +1 @@
+[]
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/dangerous_filename/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/dangerous_filename/BUILD.gn
new file mode 100644
index 0000000000..d4e728431b
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/dangerous_filename/BUILD.gn
@@ -0,0 +1,13 @@
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+# "libc++" is considered a "dangerous filename" because it's an invalid regex.
+
+target("dummy_target") {
+ sources = [ "libc++/dummy_subpackage_file.h" ]
+}
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/dangerous_filename/expected.pyl b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/dangerous_filename/expected.pyl
new file mode 100644
index 0000000000..34f23f8a01
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/dangerous_filename/expected.pyl
@@ -0,0 +1,4 @@
+[("BUILD.gn",
+ "dummy_target",
+ "libc++/dummy_subpackage_file.h",
+ "libc++")]
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/dangerous_filename/libc++/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/dangerous_filename/libc++/BUILD.gn
new file mode 100644
index 0000000000..b7c1f8aac2
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/dangerous_filename/libc++/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+group("dummy_subpackage") {
+ sources = [ "dummy_subpackage.h" ]
+}
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/BUILD.gn
new file mode 100644
index 0000000000..db8c426588
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+target("dummy_target_ok") {
+ sources = [
+ "dummy_source.cc",
+ "dummy_source.h",
+ ]
+}
+
+target("error_1") {
+ sources = [
+ "subpackage1/dummy_subpackage1.cc",
+ "subpackage1/dummy_subpackage1.h",
+ ]
+}
+
+target("error_2") {
+ sources = [
+ "subpackage1/dummy_subpackage2.cc",
+ "subpackage1/dummy_subpackage2.h",
+ ]
+}
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/expected.pyl b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/expected.pyl
new file mode 100644
index 0000000000..9b9ad01c6c
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/expected.pyl
@@ -0,0 +1,16 @@
+[('BUILD.gn',
+ 'error_1',
+ 'subpackage1/dummy_subpackage1.cc',
+ 'subpackage1'),
+ ('BUILD.gn',
+ 'error_1',
+ 'subpackage1/dummy_subpackage1.h',
+ 'subpackage1'),
+ ('BUILD.gn',
+ 'error_2',
+ 'subpackage1/dummy_subpackage2.cc',
+ 'subpackage1'),
+ ('BUILD.gn',
+ 'error_2',
+ 'subpackage1/dummy_subpackage2.h',
+ 'subpackage1')]
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/subpackage1/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/subpackage1/BUILD.gn
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/subpackage1/BUILD.gn
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/subpackage2/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/subpackage2/BUILD.gn
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_multiple_targets/subpackage2/BUILD.gn
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_single_target/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_single_target/BUILD.gn
new file mode 100644
index 0000000000..eb5ee40846
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_single_target/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+target("dummy_target") {
+ sources = [
+ "subpackage/dummy_subpackage_file.cc",
+ "subpackage/dummy_subpackage_file.h",
+ ]
+}
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_single_target/expected.pyl b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_single_target/expected.pyl
new file mode 100644
index 0000000000..012d3bd1c2
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_single_target/expected.pyl
@@ -0,0 +1,8 @@
+[("BUILD.gn",
+ "dummy_target",
+ "subpackage/dummy_subpackage_file.cc",
+ "subpackage"),
+ ("BUILD.gn",
+ "dummy_target",
+ "subpackage/dummy_subpackage_file.h",
+ "subpackage")]
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_single_target/subpackage/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_single_target/subpackage/BUILD.gn
new file mode 100644
index 0000000000..700508155b
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/multiple_errors_single_target/subpackage/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+group("dummy_supbackage") {
+ sources = [
+ "dummy_subpackage.cc",
+ "dummy_subpackage.h",
+ ]
+}
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/no_errors/BUILD.gn b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/no_errors/BUILD.gn
new file mode 100644
index 0000000000..559d333cb2
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/no_errors/BUILD.gn
@@ -0,0 +1,16 @@
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+group("testdata") {
+ deps = [ ":dummy_target" ]
+}
+
+static_library("dummy_target") {
+ sources = [ "dummy.cc" ]
+ deps = [ "subdir" ]
+}
diff --git a/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/no_errors/expected.pyl b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/no_errors/expected.pyl
new file mode 100644
index 0000000000..fe51488c70
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/presubmit_checks_lib/testdata/no_errors/expected.pyl
@@ -0,0 +1 @@
+[]