diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000000..6fdf1dc888cb6 --- /dev/null +++ b/.clang-format @@ -0,0 +1,8 @@ +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium +# This defaults to 'Auto'. Explicitly set it for a while, so that +# 'vector >' in existing files gets formatted to +# 'vector>'. ('Auto' means that clang-format will only use +# 'int>>' if the file already contains at least one such instance.) +Standard: Cpp11 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000..21a13a6c6e189 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +## This page intentionally left blank. ## +# +# Workaround for VS2013 automatically creating .gitattributes files with +# default settings that we don't want. +# See also: +# http://connect.microsoft.com/VisualStudio/feedback/details/804948/inappropriately-creates-gitattributes-file +# http://crbug.com/342064 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000..f7bff5626da85 --- /dev/null +++ b/.gitignore @@ -0,0 +1,97 @@ +# commonly generated files +*.pyc +*~ +.*.sw? +.DS_Store +.classpath +.cproject +.gdb_history +.gdbinit +.landmines +.project +.pub +.pydevproject +.checkstyle +cscope.* +Session.vim +tags +Thumbs.db +v8.log +/build/util/LASTCHANGE* + +# directories pulled in via deps or hooks +/build/linux/bin/eu-strip +/buildtools/ +/dart/ +/dart-pub-cache/ +/native_client/ +/out/ +/out_*/ +/sdch/open-vcdiff/ +/testing/gmock/ +/testing/gtest/ +/third_party/android_tools/ +/third_party/angle/ +/third_party/appurify-python/ +/third_party/boringssl/src/ +/third_party/brotli/src/ +/third_party/colorama/src/ +/third_party/dart-sdk/ +/third_party/dart-pkg/archive +/third_party/dart-pkg/args +/third_party/dart-pkg/box2d +/third_party/dart-pkg/cassowary +/third_party/dart-pkg/collection +/third_party/dart-pkg/crypto +/third_party/dart-pkg/newton +/third_party/dart-pkg/path +/third_party/dart-pkg/quiver +/third_party/dart-pkg/source_span +/third_party/dart-pkg/string_scanner +/third_party/dart-pkg/vector_math +/third_party/dart-pkg/vector_math +/third_party/dart-pkg/yaml +/third_party/dejavu-fonts-ttf-2.34/ttf/*.ttf +/third_party/freetype-android/src +/third_party/go/tool/ +/third_party/icu/ +/third_party/jsr-305/src/ +/third_party/libc++/trunk/ +/third_party/libc++abi/trunk/ +/third_party/libjpeg_turbo/ +/third_party/llvm/ +/third_party/llvm-build/ +/third_party/junit/src/ +/third_party/mesa/src/ +/third_party/mockito/src/ +/third_party/pdfium/ +/third_party/pywebsocket/src/ +/third_party/requests/src/ +/third_party/robolectric/src/ +/third_party/skia/ +/third_party/smhasher/src/ +/third_party/yasm/binaries/ +/third_party/yasm/source/patched-yasm/ +/tools/grit/ +/v8/ + +# dart packages directories and related. +/mojo/dart/apptest/packages +/mojo/dart/mojo_services/packages +/mojo/dart/mojo_services/pubspec.lock +/mojo/dart/mojom/bin/packages +/mojo/dart/mojom/packages +/mojo/dart/mojom/test/packages +/sky/examples/hello_world/packages +/sky/examples/stocks/packages +/sky/sdk/packages/mojo/packages +/sky/sdk/packages/mojo/pubspec.lock +/sky/sdk/packages/sky/packages +/sky/sdk/packages/sky/pubspec.lock + +# sky tools +/sky/tools/skygo/linux64/sky_server +/sky/tools/skygo/mac/sky_server + +# downloaded keyboard_native resources. +/services/keyboard_native/res/*.png diff --git a/.gn b/.gn new file mode 100644 index 0000000000000..6dcc94ecc75e1 --- /dev/null +++ b/.gn @@ -0,0 +1,23 @@ +# This file is used by the experimental meta-buildsystem in src/tools/gn to +# find the root of the source tree and to set startup options. + +# The location of the build configuration file. +buildconfig = "//build/config/BUILDCONFIG.gn" + +# The secondary source root is a parallel directory tree where +# GN build files are placed when they can not be placed directly +# in the source tree, e.g. for third party source trees. +secondary_source = "//build/secondary/" + +# The set of targets known to pass 'gn check'. When all targets pass, remove +# this. +check_targets = [ + "//crypto/*", + "//dart/*", + "//mojo/*", + "//mojom/*", + "//skia/*", + "//sky/*", + "//ui/*", + "//url/*", +] diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 0000000000000..9190fb8c9be7c --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,13 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This target will be built if no target is specified when invoking ninja. +group("default") { + testonly = true + + deps = [ + "//sky", + "//services/sky", + ] +} diff --git a/DEPS b/DEPS new file mode 100644 index 0000000000000..68fd41e1631fd --- /dev/null +++ b/DEPS @@ -0,0 +1,350 @@ +# This file is automatically processed to create .DEPS.git which is the file +# that gclient uses under git. +# +# See http://code.google.com/p/chromium/wiki/UsingGit +# +# To test manually, run: +# python tools/deps2git/deps2git.py -o .DEPS.git -w +# where is the absolute path to the directory containing the +# .gclient file (the parent of 'src'). +# +# Then commit .DEPS.git locally (gclient doesn't like dirty trees) and run +# gclient sync +# Verify the thing happened you wanted. Then revert your .DEPS.git change +# DO NOT CHECK IN CHANGES TO .DEPS.git upstream. It will be automatically +# updated by a bot when you modify this one. +# +# When adding a new dependency, please update the top-level .gitignore file +# to list the dependency's destination directory. + +vars = { + 'chromium_git': 'https://chromium.googlesource.com', + 'dart_svn': 'https://dart.googlecode.com', + 'skia_revision': '2ced78866fcadd98895777c8dffe92e229775181', + 'angle_revision': 'bdd419f9f5b006e913606e7363125942c8ae06bc', + 'dart_revision': 'e5e3d161e70d862608e6597facdf5ac8ae9ab2c3', + 'dart_observatory_packages_revision': '45565', + 'boringssl_revision': '642f1498d056dbba3e50ed5a232ab2f482626dec', + + 'buildtools_revision': 'fa660d47fa1a6c649d5c29e001348447c55709e6', + + 'archive_dart_revision': '07ffd98c5403b7f9ae067b57dc9487611be420f5', + 'args_dart_revision': 'e0e8377412ee6cd6a5a4a8632848181c1db91f44', + 'box2d_dart_revision': 'c5e65d9546275e78ad2a1d51b459e7638f6e4323', + 'cassowary_dart_revision': '7e5afc5b3956a18636d5b37b1dcba1705865564b', + 'collection_dart_revision': '79ebc6fc2dae581cb23ad50a5c600c1b7dd132f8', + 'crypto_dart_revision': 'd4558dea1639e5ad2a41d045265b8ece270c2d90', + 'newton_dart_revision': '26da04f0c441d005a6ecbf62ae047cd02ec9abc5', + 'path_dart_revision': '2f3dcdec32011f1bc41194ae3640d6d9292a7096', + 'quiver_dart_revision': '6bab7dec34189eee579178eb16d3063c8ae69031', + 'source_span_dart_revision': '5c6c13f62fc111adaace3aeb4a38853d64481d06', + 'string_scanner_dart_revision': '9f00056b32f41efc376adecfb696a01bc7c593d7', + 'vector_math_dart_revision': '65915583f7aa606cb47ed265f853c18c60102b81', + 'yaml_dart_revision': 'd8c1ce75edf051ea1d5583b24474f8656abb4920', +} + +# Only these hosts are allowed for dependencies in this DEPS file. +# If you need to add a new host, contact chrome infrastructure team. +allowed_hosts = [ + 'chromium.googlesource.com', + 'dart.googlecode.com', +] + +deps = { + 'src/buildtools': + Var('chromium_git') + '/chromium/buildtools.git' + '@' + Var('buildtools_revision'), + + 'src/testing/gtest': + Var('chromium_git') + '/external/googletest.git' + '@' + 'be1868139ffe0ccd0e8e3b37292b84c821d9c8ad', # from svn revision 704 + + 'src/testing/gmock': + Var('chromium_git') + '/external/googlemock.git' + '@' + '29763965ab52f24565299976b936d1265cb6a271', # from svn revision 501 + + 'src/third_party/angle': + Var('chromium_git') + '/angle/angle.git' + '@' + Var('angle_revision'), + + 'src/third_party/icu': + Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'c3f79166089e5360c09e3053fce50e6e296c3204', + + 'src/dart': + Var('chromium_git') + '/external/github.com/dart-lang/sdk.git' + '@' + Var('dart_revision'), + + 'src/dart/third_party/observatory_pub_packages': + Var('dart_svn') + '/svn/third_party/observatory_pub_packages' + '@' + + Var('dart_observatory_packages_revision'), + + 'src/third_party/skia': + Var('chromium_git') + '/skia.git' + '@' + Var('skia_revision'), + + 'src/third_party/yasm/source/patched-yasm': + Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + '4671120cd8558ce62ee8672ebf3eb6f5216f909b', + + 'src/third_party/libjpeg_turbo': + Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '034e9a9747e0983bc19808ea70e469bc8342081f', + + 'src/third_party/smhasher/src': + Var('chromium_git') + '/external/smhasher.git' + '@' + 'e87738e57558e0ec472b2fc3a643b838e5b6e88f', + + 'src/third_party/mesa/src': + Var('chromium_git') + '/chromium/deps/mesa.git' + '@' + '071d25db04c23821a12a8b260ab9d96a097402f0', + + 'src/third_party/boringssl/src': + 'https://boringssl.googlesource.com/boringssl.git' + '@' + Var('boringssl_revision'), + + 'src/third_party/requests/src': + Var('chromium_git') + '/external/github.com/kennethreitz/requests.git' + '@' + 'f172b30356d821d180fa4ecfa3e71c7274a32de4', + + 'src/third_party/dart-pkg/archive': + Var('chromium_git') + '/external/github.com/brendan-duncan/archive.git' + '@' + Var('archive_dart_revision'), + + 'src/third_party/dart-pkg/args': + Var('chromium_git') + '/external/github.com/dart-lang/args.git' + '@' + Var('args_dart_revision'), + + 'src/third_party/dart-pkg/box2d': + Var('chromium_git') + '/external/github.com/google/box2d.dart.git' + '@' + Var('box2d_dart_revision'), + + 'src/third_party/dart-pkg/cassowary': + Var('chromium_git') + '/external/github.com/domokit/cassowary.git' + '@' + Var('cassowary_dart_revision'), + + 'src/third_party/dart-pkg/collection': + Var('chromium_git') + '/external/github.com/dart-lang/collection.git' + '@' + Var('collection_dart_revision'), + + 'src/third_party/dart-pkg/crypto': + Var('chromium_git') + '/external/github.com/dart-lang/crypto.git' + '@' + Var('crypto_dart_revision'), + + 'src/third_party/dart-pkg/newton': + Var('chromium_git') + '/external/github.com/domokit/newton.git' + '@' + Var('newton_dart_revision'), + + 'src/third_party/dart-pkg/path': + Var('chromium_git') + '/external/github.com/dart-lang/path.git' + '@' + Var('path_dart_revision'), + + 'src/third_party/dart-pkg/quiver': + Var('chromium_git') + '/external/github.com/google/quiver-dart.git' + '@' + Var('quiver_dart_revision'), + + 'src/third_party/dart-pkg/source_span': + Var('chromium_git') + '/external/github.com/dart-lang/source_span.git' + '@' + Var('source_span_dart_revision'), + + 'src/third_party/dart-pkg/string_scanner': + Var('chromium_git') + '/external/github.com/dart-lang/string_scanner.git' + '@' + Var('string_scanner_dart_revision'), + + 'src/third_party/dart-pkg/vector_math': + Var('chromium_git') + '/external/github.com/google/vector_math.dart.git' + '@' + Var('vector_math_dart_revision'), + + 'src/third_party/dart-pkg/yaml': + Var('chromium_git') + '/external/github.com/dart-lang/yaml.git' + '@' + Var('yaml_dart_revision'), +} + +deps_os = { + 'android': { + 'src/third_party/colorama/src': + Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8', + + 'src/third_party/jsr-305/src': + Var('chromium_git') + '/external/jsr-305.git' + '@' + '642c508235471f7220af6d5df2d3210e3bfc0919', + + 'src/third_party/junit/src': + Var('chromium_git') + '/external/junit.git' + '@' + '45a44647e7306262162e1346b750c3209019f2e1', + + 'src/third_party/mockito/src': + Var('chromium_git') + '/external/mockito/mockito.git' + '@' + 'ed99a52e94a84bd7c467f2443b475a22fcc6ba8e', + + 'src/third_party/robolectric/lib': + Var('chromium_git') + '/chromium/third_party/robolectric.git' + '@' + '6b63c99a8b6967acdb42cbed0adb067c80efc810', + + 'src/third_party/appurify-python/src': + Var('chromium_git') + '/external/github.com/appurify/appurify-python.git' + '@' + 'ee7abd5c5ae3106f72b2a0b9d2cb55094688e867', + + 'src/third_party/freetype-android/src': + Var('chromium_git') + '/chromium/src/third_party/freetype.git' + '@' + 'd1028db70bea988d1022e4d463de66581c696160', + + 'src/third_party/requests/src': + Var('chromium_git') + '/external/github.com/kennethreitz/requests.git' + '@' + 'f172b30356d821d180fa4ecfa3e71c7274a32de4', + }, +} + + +hooks = [ + { + # This clobbers when necessary (based on get_landmines.py). It must be the + # first hook so that other things that get/generate into the output + # directory will not subsequently be clobbered. + 'name': 'landmines', + 'pattern': '.', + 'action': [ + 'python', + 'src/build/landmines.py', + ], + }, + { + # Pull clang if needed or requested via GYP_DEFINES. + 'name': 'clang', + 'pattern': '.', + 'action': ['python', 'src/tools/clang/scripts/update.py', '--if-needed'], + }, + { + # Pull dart sdk if needed + 'name': 'dart', + 'pattern': '.', + 'action': ['python', 'src/tools/dart/update.py'], + }, + { + # This downloads android_tools according to tools/android/VERSION_*. + 'name': 'android_tools', + 'pattern': '.', + 'action': ['python', 'src/tools/android/download_android_tools.py'], + }, + { + # This downloads SDK extras and puts them in the + # third_party/android_tools/sdk/extras directory on the bots. Developers + # need to manually install these packages and accept the ToS. + 'name': 'sdkextras', + 'pattern': '.', + # When adding a new sdk extras package to download, add the package + # directory and zip file to .gitignore in third_party/android_tools. + 'action': ['python', 'src/build/download_sdk_extras.py'], + }, + { + # Update LASTCHANGE. This is also run by export_tarball.py in + # src/tools/export_tarball - please keep them in sync. + 'name': 'lastchange', + 'pattern': '.', + 'action': ['python', 'src/build/util/lastchange.py', + '-o', 'src/build/util/LASTCHANGE'], + }, + # Pull GN binaries. This needs to be before running GYP below. + { + 'name': 'gn_linux64', + 'pattern': '.', + 'action': [ 'download_from_google_storage', + '--no_resume', + '--platform=linux*', + '--no_auth', + '--bucket', 'chromium-gn', + '-s', 'src/buildtools/linux64/gn.sha1', + ], + }, + { + 'name': 'gn_mac', + 'pattern': '.', + 'action': [ 'download_from_google_storage', + '--no_resume', + '--platform=darwin', + '--no_auth', + '--bucket', 'chromium-gn', + '-s', 'src/buildtools/mac/gn.sha1', + ], + }, + { + 'name': 'gn_win', + 'pattern': '.', + 'action': [ 'download_from_google_storage', + '--no_resume', + '--platform=win*', + '--no_auth', + '--bucket', 'chromium-gn', + '-s', 'src/buildtools/win/gn.exe.sha1', + ], + }, + # Pull clang-format binaries using checked-in hashes. + { + 'name': 'clang_format_linux', + 'pattern': '.', + 'action': [ 'download_from_google_storage', + '--no_resume', + '--platform=linux*', + '--no_auth', + '--bucket', 'chromium-clang-format', + '-s', 'src/buildtools/linux64/clang-format.sha1', + ], + }, + { + 'name': 'clang_format_mac', + 'pattern': '.', + 'action': [ 'download_from_google_storage', + '--no_resume', + '--platform=darwin', + '--no_auth', + '--bucket', 'chromium-clang-format', + '-s', 'src/buildtools/mac/clang-format.sha1', + ], + }, + # Pull sky_server binaries using checked-in hashes. + { + 'name': 'sky_server_linux', + 'pattern': '.', + 'action': [ 'download_from_google_storage', + '--no_resume', + '--platform=linux*', + '--no_auth', + '--bucket', 'mojo', + '-s', 'src/sky/tools/skygo/linux64/sky_server.sha1', + ], + }, + { + 'name': 'sky_server_mac', + 'pattern': '.', + 'action': [ 'download_from_google_storage', + '--no_resume', + '--platform=darwin', + '--no_auth', + '--bucket', 'mojo', + '-s', 'src/sky/tools/skygo/mac/sky_server.sha1', + ], + }, + { + 'name': 'material_design_icons', + 'pattern': '.', + 'action': [ + 'python', + 'src/sky/sdk/lib/download_material_design_icons', + ], + }, + # Pull binutils for linux, enabled debug fission for faster linking / + # debugging when used with clang on Ubuntu Precise. + # https://code.google.com/p/chromium/issues/detail?id=352046 + { + 'name': 'binutils', + 'pattern': 'src/third_party/binutils', + 'action': [ + 'python', + 'src/third_party/binutils/download.py', + ], + }, + # Pull eu-strip binaries using checked-in hashes. + { + 'name': 'eu-strip', + 'pattern': '.', + 'action': [ 'download_from_google_storage', + '--no_resume', + '--platform=linux*', + '--no_auth', + '--bucket', 'chromium-eu-strip', + '-s', 'src/build/linux/bin/eu-strip.sha1', + ], + }, + # Run "pub get" on any directories with checked-in pubspec.yaml files + # (excluding sky/, whose pubspec.yaml files are not intended for supporting + # building in-place in the repo). + { + 'name': 'run_dart_pub_get', + 'pattern': '', + 'action': [ 'python', + 'src/mojo/public/tools/git/dart_pub_get.py', + '--repository-root', '../../../..', + '--dart-sdk-directory', + '../../../../third_party/dart-sdk/dart-sdk', + '--dirs-to-ignore', 'sky/', + ], + }, + { + # Ensure that we don't accidentally reference any .pyc files whose + # corresponding .py files have already been deleted. + 'name': 'remove_stale_pyc_files', + 'pattern': 'src/tools/.*\\.py', + 'action': [ + 'python', + 'src/tools/remove_stale_pyc_files.py', + 'src/tools', + ], + }, +] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000..972bb2edb099e --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000000000..72e8ffc0db8aa --- /dev/null +++ b/OWNERS @@ -0,0 +1 @@ +* diff --git a/PRESUBMIT.py b/PRESUBMIT.py new file mode 100644 index 0000000000000..7b3b26cf3fcd5 --- /dev/null +++ b/PRESUBMIT.py @@ -0,0 +1,1134 @@ +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Top-level presubmit script for Chromium. + +See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts +for more details about the presubmit API built into gcl. +""" + + +_EXCLUDED_PATHS = ( + r"^native_client_sdk/src/build_tools/make_rules.py", + r"^native_client_sdk/src/build_tools/make_simple.py", + r"^native_client_sdk/src/tools/.*.mk", + r"^skia/.*", + r"^v8/.*", + r".*MakeFile$", + r".+_autogen\.h$", + r".+/pnacl_shim\.c$", + r"^gpu/config/.*_list_json\.cc$", + r"^tools/android_stack_parser/.*" +) + +_SKY_PATHS = ( + r"^sky/.*", +) + +# Fragment of a regular expression that matches C++ and Objective-C++ +# implementation files. +_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$' + +# Regular expression that matches code only used for test binaries +# (best effort). +_TEST_CODE_EXCLUDED_PATHS = ( + r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS, + r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS, + r'.+_(app|browser|perf|pixel|unit)?test(_[a-z]+)?%s' % + _IMPLEMENTATION_EXTENSIONS, + r'.*/(test|tool(s)?)/.*', + # Non-production example code. + r'mojo/examples/.*', + # Launcher for running iOS tests on the simulator. + r'testing/iossim/iossim\.mm$', +) + +_TEST_ONLY_WARNING = ( + 'You might be calling functions intended only for testing from\n' + 'production code. It is OK to ignore this warning if you know what\n' + 'you are doing, as the heuristics used to detect the situation are\n' + 'not perfect. The commit queue will not block on this warning.') + + +_INCLUDE_ORDER_WARNING = ( + 'Your #include order seems to be broken. Send mail to\n' + 'marja@chromium.org if this is not the case.') + + +_BANNED_CPP_FUNCTIONS = ( + # Make sure that gtest's FRIEND_TEST() macro is not used; the + # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be + # used instead since that allows for FLAKY_ and DISABLED_ prefixes. + ( + 'FRIEND_TEST(', + ( + 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include', + 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.', + ), + False, + (), + ), + ( + 'ScopedAllowIO', + ( + 'New code should not use ScopedAllowIO. Post a task to the blocking', + 'pool or the FILE thread instead.', + ), + True, + ( + r"^base/process/process_metrics_linux\.cc$", + r"^mojo/edk/embedder/simple_platform_shared_buffer_posix\.cc$", + ), + ), + ( + 'SkRefPtr', + ( + 'The use of SkRefPtr is prohibited. ', + 'Please use skia::RefPtr instead.' + ), + True, + (), + ), + ( + 'SkAutoRef', + ( + 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ', + 'Please use skia::RefPtr instead.' + ), + True, + (), + ), + ( + 'SkAutoTUnref', + ( + 'The use of SkAutoTUnref is dangerous because it implicitly ', + 'converts to a raw pointer. Please use skia::RefPtr instead.' + ), + True, + (), + ), + ( + 'SkAutoUnref', + ( + 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ', + 'because it implicitly converts to a raw pointer. ', + 'Please use skia::RefPtr instead.' + ), + True, + (), + ), + ( + r'/HANDLE_EINTR\(.*close', + ( + 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file', + 'descriptor will be closed, and it is incorrect to retry the close.', + 'Either call close directly and ignore its return value, or wrap close', + 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623' + ), + True, + (), + ), + ( + r'/IGNORE_EINTR\((?!.*close)', + ( + 'IGNORE_EINTR is only valid when wrapping close. To wrap other system', + 'calls, use HANDLE_EINTR. See http://crbug.com/269623', + ), + True, + ( + # Files that #define IGNORE_EINTR. + r'^base/posix/eintr_wrapper\.h$', + ), + ), + ( + r'/v8::Extension\(', + ( + 'Do not introduce new v8::Extensions into the code base, use', + 'gin::Wrappable instead. See http://crbug.com/334679', + ), + True, + (), + ), +) + + +_VALID_OS_MACROS = ( + # Please keep sorted. + 'OS_ANDROID', + 'OS_ANDROID_HOST', + 'OS_BSD', + 'OS_CAT', # For testing. + 'OS_CHROMEOS', + 'OS_FREEBSD', + 'OS_IOS', + 'OS_LINUX', + 'OS_MACOSX', + 'OS_NACL', + 'OS_OPENBSD', + 'OS_POSIX', + 'OS_QNX', + 'OS_SOLARIS', + 'OS_WIN', +) + + +def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api): + """Attempts to prevent use of functions intended only for testing in + non-testing code. For now this is just a best-effort implementation + that ignores header files and may have some false positives. A + better implementation would probably need a proper C++ parser. + """ + # We only scan .cc files and the like, as the declaration of + # for-testing functions in header files are hard to distinguish from + # calls to such functions without a proper C++ parser. + file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS + + base_function_pattern = r'[ :]test::[^\s]+|ForTest(ing)?|for_test(ing)?' + inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern) + comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern) + exclusion_pattern = input_api.re.compile( + r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % ( + base_function_pattern, base_function_pattern)) + + def FilterFile(affected_file): + black_list = (_EXCLUDED_PATHS + + _TEST_CODE_EXCLUDED_PATHS + + input_api.DEFAULT_BLACK_LIST) + return input_api.FilterSourceFile( + affected_file, + white_list=(file_inclusion_pattern, ), + black_list=black_list) + + problems = [] + for f in input_api.AffectedSourceFiles(FilterFile): + local_path = f.LocalPath() + for line_number, line in f.ChangedContents(): + if (inclusion_pattern.search(line) and + not comment_pattern.search(line) and + not exclusion_pattern.search(line)): + problems.append( + '%s:%d\n %s' % (local_path, line_number, line.strip())) + + if problems: + return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)] + else: + return [] + + +def _CheckNoIOStreamInHeaders(input_api, output_api): + """Checks to make sure no .h files include .""" + files = [] + pattern = input_api.re.compile(r'^#include\s*', + input_api.re.MULTILINE) + for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile): + if not f.LocalPath().endswith('.h'): + continue + contents = input_api.ReadFile(f) + if pattern.search(contents): + files.append(f) + + if len(files): + return [ output_api.PresubmitError( + 'Do not #include in header files, since it inserts static ' + 'initialization into every file including the header. Instead, ' + '#include . See http://crbug.com/94794', + files) ] + return [] + + +def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api): + """Checks to make sure no source files use UNIT_TEST""" + problems = [] + for f in input_api.AffectedFiles(): + if (not f.LocalPath().endswith(('.cc', '.mm'))): + continue + + for line_num, line in f.ChangedContents(): + if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'): + problems.append(' %s:%d' % (f.LocalPath(), line_num)) + + if not problems: + return [] + return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' + + '\n'.join(problems))] + + +def _CheckNoNewWStrings(input_api, output_api): + """Checks to make sure we don't introduce use of wstrings.""" + problems = [] + for f in input_api.AffectedFiles(): + if (not f.LocalPath().endswith(('.cc', '.h')) or + f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h'))): + continue + + allowWString = False + for line_num, line in f.ChangedContents(): + if 'presubmit: allow wstring' in line: + allowWString = True + elif not allowWString and 'wstring' in line: + problems.append(' %s:%d' % (f.LocalPath(), line_num)) + allowWString = False + else: + allowWString = False + + if not problems: + return [] + return [output_api.PresubmitPromptWarning('New code should not use wstrings.' + ' If you are calling a cross-platform API that accepts a wstring, ' + 'fix the API.\n' + + '\n'.join(problems))] + + +def _CheckNoDEPSGIT(input_api, output_api): + """Make sure .DEPS.git is never modified manually.""" + if any(f.LocalPath().endswith('.DEPS.git') for f in + input_api.AffectedFiles()): + return [output_api.PresubmitError( + 'Never commit changes to .DEPS.git. This file is maintained by an\n' + 'automated system based on what\'s in DEPS and your changes will be\n' + 'overwritten.\n' + 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/get-the-code#Rolling_DEPS\n' + 'for more information')] + return [] + + +def _CheckValidHostsInDEPS(input_api, output_api): + """Checks that DEPS file deps are from allowed_hosts.""" + # Run only if DEPS file has been modified to annoy fewer bystanders. + if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()): + return [] + # Outsource work to gclient verify + try: + input_api.subprocess.check_output(['gclient', 'verify']) + return [] + except input_api.subprocess.CalledProcessError, error: + return [output_api.PresubmitError( + 'DEPS file must have only git dependencies.', + long_text=error.output)] + + +def _CheckNoBannedFunctions(input_api, output_api): + """Make sure that banned functions are not used.""" + warnings = [] + errors = [] + + file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h')) + for f in input_api.AffectedFiles(file_filter=file_filter): + for line_num, line in f.ChangedContents(): + for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS: + def IsBlacklisted(affected_file, blacklist): + local_path = affected_file.LocalPath() + for item in blacklist: + if input_api.re.match(item, local_path): + return True + return False + if IsBlacklisted(f, excluded_paths): + continue + matched = False + if func_name[0:1] == '/': + regex = func_name[1:] + if input_api.re.search(regex, line): + matched = True + elif func_name in line: + matched = True + if matched: + problems = warnings; + if error: + problems = errors; + problems.append(' %s:%d:' % (f.LocalPath(), line_num)) + for message_line in message: + problems.append(' %s' % message_line) + + result = [] + if (warnings): + result.append(output_api.PresubmitPromptWarning( + 'Banned functions were used.\n' + '\n'.join(warnings))) + if (errors): + result.append(output_api.PresubmitError( + 'Banned functions were used.\n' + '\n'.join(errors))) + return result + + +def _CheckNoPragmaOnce(input_api, output_api): + """Make sure that banned functions are not used.""" + files = [] + pattern = input_api.re.compile(r'^#pragma\s+once', + input_api.re.MULTILINE) + for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile): + if not f.LocalPath().endswith('.h'): + continue + contents = input_api.ReadFile(f) + if pattern.search(contents): + files.append(f) + + if files: + return [output_api.PresubmitError( + 'Do not use #pragma once in header files.\n' + 'See http://www.chromium.org/developers/coding-style#TOC-File-headers', + files)] + return [] + + +def _CheckNoTrinaryTrueFalse(input_api, output_api): + """Checks to make sure we don't introduce use of foo ? true : false.""" + problems = [] + pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)') + for f in input_api.AffectedFiles(): + if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')): + continue + + for line_num, line in f.ChangedContents(): + if pattern.match(line): + problems.append(' %s:%d' % (f.LocalPath(), line_num)) + + if not problems: + return [] + return [output_api.PresubmitPromptWarning( + 'Please consider avoiding the "? true : false" pattern if possible.\n' + + '\n'.join(problems))] + + +def _CheckFilePermissions(input_api, output_api): + """Check that all files have their permissions properly set.""" + if input_api.platform == 'win32': + return [] + args = [input_api.python_executable, 'tools/checkperms/checkperms.py', + '--root', input_api.change.RepositoryRoot()] + for f in input_api.AffectedFiles(): + args += ['--file', f.LocalPath()] + checkperms = input_api.subprocess.Popen(args, + stdout=input_api.subprocess.PIPE) + errors = checkperms.communicate()[0].strip() + if errors: + return [output_api.PresubmitError('checkperms.py failed.', + errors.splitlines())] + return [] + + +def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums): + """Checks that the lines in scope occur in the right order. + + 1. C system files in alphabetical order + 2. C++ system files in alphabetical order + 3. Project's .h files + """ + + c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>') + cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>') + custom_include_pattern = input_api.re.compile(r'\s*#include ".*') + + C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3) + + state = C_SYSTEM_INCLUDES + + previous_line = '' + previous_line_num = 0 + problem_linenums = [] + for line_num, line in scope: + if c_system_include_pattern.match(line): + if state != C_SYSTEM_INCLUDES: + problem_linenums.append((line_num, previous_line_num)) + elif previous_line and previous_line > line: + problem_linenums.append((line_num, previous_line_num)) + elif cpp_system_include_pattern.match(line): + if state == C_SYSTEM_INCLUDES: + state = CPP_SYSTEM_INCLUDES + elif state == CUSTOM_INCLUDES: + problem_linenums.append((line_num, previous_line_num)) + elif previous_line and previous_line > line: + problem_linenums.append((line_num, previous_line_num)) + elif custom_include_pattern.match(line): + if state != CUSTOM_INCLUDES: + state = CUSTOM_INCLUDES + elif previous_line and previous_line > line: + problem_linenums.append((line_num, previous_line_num)) + else: + problem_linenums.append(line_num) + previous_line = line + previous_line_num = line_num + + warnings = [] + for (line_num, previous_line_num) in problem_linenums: + if line_num in changed_linenums or previous_line_num in changed_linenums: + warnings.append(' %s:%d' % (file_path, line_num)) + return warnings + + +def _CheckIncludeOrderInFile(input_api, f, changed_linenums): + """Checks the #include order for the given file f.""" + + system_include_pattern = input_api.re.compile(r'\s*#include \<.*') + # Exclude the following includes from the check: + # 1) #include <.../...>, e.g., includes often need to appear in a + # specific order. + # 2) , "build/build_config.h" + excluded_include_pattern = input_api.re.compile( + r'\s*#include (\<.*/.*|\|"build/build_config.h")') + custom_include_pattern = input_api.re.compile(r'\s*#include "(?P.*)"') + # Match the final or penultimate token if it is xxxtest so we can ignore it + # when considering the special first include. + test_file_tag_pattern = input_api.re.compile( + r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)') + if_pattern = input_api.re.compile( + r'\s*#\s*(if|elif|else|endif|define|undef).*') + # Some files need specialized order of includes; exclude such files from this + # check. + uncheckable_includes_pattern = input_api.re.compile( + r'\s*#include ' + '("ipc/.*macros\.h"||".*gl.*autogen.h")\s*') + + contents = f.NewContents() + warnings = [] + line_num = 0 + + # Handle the special first include. If the first include file is + # some/path/file.h, the corresponding including file can be some/path/file.cc, + # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h + # etc. It's also possible that no special first include exists. + # If the included file is some/path/file_platform.h the including file could + # also be some/path/file_xxxtest_platform.h. + including_file_base_name = test_file_tag_pattern.sub( + '', input_api.os_path.basename(f.LocalPath())) + + for line in contents: + line_num += 1 + if system_include_pattern.match(line): + # No special first include -> process the line again along with normal + # includes. + line_num -= 1 + break + match = custom_include_pattern.match(line) + if match: + match_dict = match.groupdict() + header_basename = test_file_tag_pattern.sub( + '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '') + + if header_basename not in including_file_base_name: + # No special first include -> process the line again along with normal + # includes. + line_num -= 1 + break + + # Split into scopes: Each region between #if and #endif is its own scope. + scopes = [] + current_scope = [] + for line in contents[line_num:]: + line_num += 1 + if uncheckable_includes_pattern.match(line): + continue + if if_pattern.match(line): + scopes.append(current_scope) + current_scope = [] + elif ((system_include_pattern.match(line) or + custom_include_pattern.match(line)) and + not excluded_include_pattern.match(line)): + current_scope.append((line_num, line)) + scopes.append(current_scope) + + for scope in scopes: + warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(), + changed_linenums)) + return warnings + + +def _CheckIncludeOrder(input_api, output_api): + """Checks that the #include order is correct. + + 1. The corresponding header for source files. + 2. C system files in alphabetical order + 3. C++ system files in alphabetical order + 4. Project's .h files in alphabetical order + + Each region separated by #if, #elif, #else, #endif, #define and #undef follows + these rules separately. + """ + def FileFilterIncludeOrder(affected_file): + black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST) + return input_api.FilterSourceFile(affected_file, black_list=black_list) + + warnings = [] + for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder): + if f.LocalPath().endswith(('.cc', '.h')): + changed_linenums = set(line_num for line_num, _ in f.ChangedContents()) + warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums)) + + results = [] + if warnings: + results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING, + warnings)) + return results + + +def _CheckForVersionControlConflictsInFile(input_api, f): + pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$') + errors = [] + for line_num, line in f.ChangedContents(): + if pattern.match(line): + errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line)) + return errors + + +def _CheckForVersionControlConflicts(input_api, output_api): + """Usually this is not intentional and will cause a compile failure.""" + errors = [] + for f in input_api.AffectedFiles(): + errors.extend(_CheckForVersionControlConflictsInFile(input_api, f)) + + results = [] + if errors: + results.append(output_api.PresubmitError( + 'Version control conflict markers found, please resolve.', errors)) + return results + + +def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api): + def FilterFile(affected_file): + """Filter function for use with input_api.AffectedSourceFiles, + below. This filters out everything except non-test files from + top-level directories that generally speaking should not hard-code + service URLs (e.g. src/android_webview/, src/content/ and others). + """ + return input_api.FilterSourceFile( + affected_file, + white_list=(r'^base/.*', ), + black_list=(_EXCLUDED_PATHS + + _TEST_CODE_EXCLUDED_PATHS + + input_api.DEFAULT_BLACK_LIST)) + + base_pattern = '"[^"]*google\.com[^"]*"' + comment_pattern = input_api.re.compile('//.*%s' % base_pattern) + pattern = input_api.re.compile(base_pattern) + problems = [] # items are (filename, line_number, line) + for f in input_api.AffectedSourceFiles(FilterFile): + for line_num, line in f.ChangedContents(): + if not comment_pattern.search(line) and pattern.search(line): + problems.append((f.LocalPath(), line_num, line)) + + if problems: + return [output_api.PresubmitPromptOrNotify( + 'Most layers below src/chrome/ should not hardcode service URLs.\n' + 'Are you sure this is correct?', + [' %s:%d: %s' % ( + problem[0], problem[1], problem[2]) for problem in problems])] + else: + return [] + + +def _CheckNoAbbreviationInPngFileName(input_api, output_api): + """Makes sure there are no abbreviations in the name of PNG files. + """ + pattern = input_api.re.compile(r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$') + errors = [] + for f in input_api.AffectedFiles(include_deletes=False): + if pattern.match(f.LocalPath()): + errors.append(' %s' % f.LocalPath()) + + results = [] + if errors: + results.append(output_api.PresubmitError( + 'The name of PNG files should not have abbreviations. \n' + 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n' + 'Contact oshima@chromium.org if you have questions.', errors)) + return results + + +def _CheckSpamLogging(input_api, output_api): + file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS + black_list = (_EXCLUDED_PATHS + + _TEST_CODE_EXCLUDED_PATHS + + input_api.DEFAULT_BLACK_LIST + + (r"^base/logging\.h$", + r"^base/logging\.cc$", + r"^examples/wget/wget\.cc$", + r"^shell/application_manager/network_fetcher\.cc$", + r"^shell/tracer\.cc$", + r"^sandbox/linux/.*", + r"^tools/.*")) + source_file_filter = lambda x: input_api.FilterSourceFile( + x, white_list=(file_inclusion_pattern,), black_list=black_list) + + log_macro = input_api.re.compile(r"\bD?LOG\s*\(\s*INFO\s*\)") + log_if_macro = input_api.re.compile(r"\bD?LOG_IF\s*\(\s*INFO\s*,") + printf_macro = input_api.re.compile(r"\bprintf\(") + fprintf_macro = input_api.re.compile(r"\bfprintf\((stdout|stderr)") + + log_info = [] + printf = [] + + for f in input_api.AffectedSourceFiles(source_file_filter): + for linenum, line in f.ChangedContents(): + if log_macro.search(line) or log_if_macro.search(line): + log_info.append(f.LocalPath()) + if printf_macro.search(line) or fprintf_macro.search(line): + printf.append(f.LocalPath()) + + if log_info: + return [output_api.PresubmitError( + 'These files spam the console log with LOG(INFO):', + items=log_info)] + if printf: + return [output_api.PresubmitError( + 'These files spam the console log with printf/fprintf:', + items=printf)] + return [] + + +def _CheckForAnonymousVariables(input_api, output_api): + """These types are all expected to hold locks while in scope and + so should never be anonymous (which causes them to be immediately + destroyed).""" + they_who_must_be_named = [ + 'base::AutoLock', + 'base::AutoReset', + 'base::AutoUnlock', + 'SkAutoAlphaRestore', + 'SkAutoBitmapShaderInstall', + 'SkAutoBlitterChoose', + 'SkAutoBounderCommit', + 'SkAutoCallProc', + 'SkAutoCanvasRestore', + 'SkAutoCommentBlock', + 'SkAutoDescriptor', + 'SkAutoDisableDirectionCheck', + 'SkAutoDisableOvalCheck', + 'SkAutoFree', + 'SkAutoGlyphCache', + 'SkAutoHDC', + 'SkAutoLockColors', + 'SkAutoLockPixels', + 'SkAutoMalloc', + 'SkAutoMaskFreeImage', + 'SkAutoMutexAcquire', + 'SkAutoPathBoundsUpdate', + 'SkAutoPDFRelease', + 'SkAutoRasterClipValidate', + 'SkAutoRef', + 'SkAutoTime', + 'SkAutoTrace', + 'SkAutoUnref', + ] + anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named) + # bad: base::AutoLock(lock.get()); + # not bad: base::AutoLock lock(lock.get()); + bad_pattern = input_api.re.compile(anonymous) + # good: new base::AutoLock(lock.get()) + good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous) + errors = [] + + for f in input_api.AffectedFiles(): + if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')): + continue + for linenum, line in f.ChangedContents(): + if bad_pattern.search(line) and not good_pattern.search(line): + errors.append('%s:%d' % (f.LocalPath(), linenum)) + + if errors: + return [output_api.PresubmitError( + 'These lines create anonymous variables that need to be named:', + items=errors)] + return [] + + +def _GetJSONParseError(input_api, filename): + try: + contents = input_api.ReadFile(filename) + input_api.json.loads(contents) + except ValueError as e: + return e + return None + + +def _CheckParseErrors(input_api, output_api): + """Check that JSON files do not contain syntax errors.""" + actions = { + '.json': _GetJSONParseError, + } + # These paths contain test data and other known invalid JSON files. + excluded_patterns = [ + r'test/data/', + ] + # Most JSON files are preprocessed and support comments, but these do not. + json_no_comments_patterns = [ + r'^testing/', + ] + + def get_action(affected_file): + filename = affected_file.LocalPath() + return actions.get(input_api.os_path.splitext(filename)[1]) + + def MatchesFile(patterns, path): + for pattern in patterns: + if input_api.re.search(pattern, path): + return True + return False + + def FilterFile(affected_file): + action = get_action(affected_file) + if not action: + return False + path = affected_file.LocalPath() + + if MatchesFile(excluded_patterns, path): + return False + return True + + results = [] + for affected_file in input_api.AffectedFiles( + file_filter=FilterFile, include_deletes=False): + action = get_action(affected_file) + parse_error = action(input_api, affected_file.AbsoluteLocalPath()) + if parse_error: + results.append(output_api.PresubmitError('%s could not be parsed: %s' % + (affected_file.LocalPath(), parse_error))) + return results + + +def _CheckJavaStyle(input_api, output_api): + """Runs checkstyle on changed java files and returns errors if any exist.""" + import sys + original_sys_path = sys.path + try: + sys.path = sys.path + [input_api.os_path.join( + input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')] + import checkstyle + finally: + # Restore sys.path to what it was before. + sys.path = original_sys_path + + return checkstyle.RunCheckstyle( + input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml') + + +_DEPRECATED_CSS = [ + # Values + ( "-webkit-box", "flex" ), + ( "-webkit-inline-box", "inline-flex" ), + ( "-webkit-flex", "flex" ), + ( "-webkit-inline-flex", "inline-flex" ), + ( "-webkit-min-content", "min-content" ), + ( "-webkit-max-content", "max-content" ), + + # Properties + ( "-webkit-background-clip", "background-clip" ), + ( "-webkit-background-origin", "background-origin" ), + ( "-webkit-background-size", "background-size" ), + ( "-webkit-box-shadow", "box-shadow" ), + + # Functions + ( "-webkit-gradient", "gradient" ), + ( "-webkit-repeating-gradient", "repeating-gradient" ), + ( "-webkit-linear-gradient", "linear-gradient" ), + ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ), + ( "-webkit-radial-gradient", "radial-gradient" ), + ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ), +] + +def _CheckNoDeprecatedCSS(input_api, output_api): + """ Make sure that we don't use deprecated CSS + properties, functions or values. Our external + documentation is ignored by the hooks as it + needs to be consumed by WebKit. """ + results = [] + file_inclusion_pattern = (r".+\.css$") + black_list = (_EXCLUDED_PATHS + + _TEST_CODE_EXCLUDED_PATHS + + input_api.DEFAULT_BLACK_LIST + + (r"^chrome/common/extensions/docs", + r"^chrome/docs", + r"^native_client_sdk")) + file_filter = lambda f: input_api.FilterSourceFile( + f, white_list=file_inclusion_pattern, black_list=black_list) + for fpath in input_api.AffectedFiles(file_filter=file_filter): + for line_num, line in fpath.ChangedContents(): + for (deprecated_value, value) in _DEPRECATED_CSS: + if input_api.re.search(deprecated_value, line): + results.append(output_api.PresubmitError( + "%s:%d: Use of deprecated CSS %s, use %s instead" % + (fpath.LocalPath(), line_num, deprecated_value, value))) + return results + + +def _CheckForOverrideAndFinalRules(input_api, output_api): + """Checks for final and override used as per C++11""" + problems = [] + for f in input_api.AffectedFiles(): + if (f.LocalPath().endswith(('.cc', '.cpp', '.h', '.mm'))): + for line_num, line in f.ChangedContents(): + if (input_api.re.search(r'\b(FINAL|OVERRIDE)\b', line)): + problems.append(' %s:%d' % (f.LocalPath(), line_num)) + + if not problems: + return [] + return [output_api.PresubmitError('Use C++11\'s |final| and |override| ' + 'rather than FINAL and OVERRIDE.', + problems)] + + +def _CommonChecks(input_api, output_api): + """Checks common to both upload and commit.""" + results = [] + results.extend(input_api.canned_checks.PanProjectChecks( + input_api, output_api, excluded_paths=_EXCLUDED_PATHS + _SKY_PATHS)) + results.extend(_CheckAuthorizedAuthor(input_api, output_api)) + results.extend( + _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api)) + results.extend(_CheckNoIOStreamInHeaders(input_api, output_api)) + results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api)) + results.extend(_CheckNoNewWStrings(input_api, output_api)) + results.extend(_CheckNoDEPSGIT(input_api, output_api)) + results.extend(_CheckNoBannedFunctions(input_api, output_api)) + results.extend(_CheckNoPragmaOnce(input_api, output_api)) + results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api)) + results.extend(_CheckFilePermissions(input_api, output_api)) + results.extend(_CheckIncludeOrder(input_api, output_api)) + results.extend(_CheckForVersionControlConflicts(input_api, output_api)) + results.extend(_CheckPatchFiles(input_api, output_api)) + results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api)) + results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api)) + results.extend(_CheckForInvalidOSMacros(input_api, output_api)) + results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api)) + # TODO(danakj): Remove this when base/move.h is removed. + results.extend(_CheckForUsingSideEffectsOfPass(input_api, output_api)) + results.extend( + input_api.canned_checks.CheckChangeHasNoTabs( + input_api, + output_api, + source_file_filter=lambda x: x.LocalPath().endswith('.grd'))) + results.extend(_CheckSpamLogging(input_api, output_api)) + results.extend(_CheckForAnonymousVariables(input_api, output_api)) + results.extend(_CheckNoDeprecatedCSS(input_api, output_api)) + results.extend(_CheckParseErrors(input_api, output_api)) + results.extend(_CheckForOverrideAndFinalRules(input_api, output_api)) + + if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()): + results.extend(input_api.canned_checks.RunUnitTestsInDirectory( + input_api, output_api, + input_api.PresubmitLocalPath(), + whitelist=[r'^PRESUBMIT_test\.py$'])) + return results + + +def _CheckAuthorizedAuthor(input_api, output_api): + """For non-googler/chromites committers, verify the author's email address is + in AUTHORS. + """ + # TODO(maruel): Add it to input_api? + import fnmatch + + author = input_api.change.author_email + if not author: + input_api.logging.info('No author, skipping AUTHOR check') + return [] + authors_path = input_api.os_path.join( + input_api.PresubmitLocalPath(), 'AUTHORS') + valid_authors = ( + input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line) + for line in open(authors_path)) + valid_authors = [item.group(1).lower() for item in valid_authors if item] + if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors): + input_api.logging.info('Valid authors are %s', ', '.join(valid_authors)) + return [output_api.PresubmitPromptWarning( + ('%s is not in AUTHORS file. If you are a new contributor, please visit' + '\n' + 'http://www.chromium.org/developers/contributing-code and read the ' + '"Legal" section\n' + 'If you are a chromite, verify the contributor signed the CLA.') % + author)] + return [] + + +def _CheckPatchFiles(input_api, output_api): + problems = [f.LocalPath() for f in input_api.AffectedFiles() + if f.LocalPath().endswith(('.orig', '.rej'))] + if problems: + return [output_api.PresubmitError( + "Don't commit .rej and .orig files.", problems)] + else: + return [] + + +def _DidYouMeanOSMacro(bad_macro): + try: + return {'A': 'OS_ANDROID', + 'B': 'OS_BSD', + 'C': 'OS_CHROMEOS', + 'F': 'OS_FREEBSD', + 'L': 'OS_LINUX', + 'M': 'OS_MACOSX', + 'N': 'OS_NACL', + 'O': 'OS_OPENBSD', + 'P': 'OS_POSIX', + 'S': 'OS_SOLARIS', + 'W': 'OS_WIN'}[bad_macro[3].upper()] + except KeyError: + return '' + + +def _CheckForInvalidOSMacrosInFile(input_api, f): + """Check for sensible looking, totally invalid OS macros.""" + preprocessor_statement = input_api.re.compile(r'^\s*#') + os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)') + results = [] + for lnum, line in f.ChangedContents(): + if preprocessor_statement.search(line): + for match in os_macro.finditer(line): + if not match.group(1) in _VALID_OS_MACROS: + good = _DidYouMeanOSMacro(match.group(1)) + did_you_mean = ' (did you mean %s?)' % good if good else '' + results.append(' %s:%d %s%s' % (f.LocalPath(), + lnum, + match.group(1), + did_you_mean)) + return results + + +def _CheckForInvalidOSMacros(input_api, output_api): + """Check all affected files for invalid OS macros.""" + bad_macros = [] + for f in input_api.AffectedFiles(): + if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')): + bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f)) + + if not bad_macros: + return [] + + return [output_api.PresubmitError( + 'Possibly invalid OS macro[s] found. Please fix your code\n' + 'or add your macro to src/PRESUBMIT.py.', bad_macros)] + + +def _CheckForInvalidIfDefinedMacrosInFile(input_api, f): + """Check all affected files for invalid "if defined" macros.""" + ALWAYS_DEFINED_MACROS = ( + "TARGET_CPU_PPC", + "TARGET_CPU_PPC64", + "TARGET_CPU_68K", + "TARGET_CPU_X86", + "TARGET_CPU_ARM", + "TARGET_CPU_MIPS", + "TARGET_CPU_SPARC", + "TARGET_CPU_ALPHA", + "TARGET_IPHONE_SIMULATOR", + "TARGET_OS_EMBEDDED", + "TARGET_OS_IPHONE", + "TARGET_OS_MAC", + "TARGET_OS_UNIX", + "TARGET_OS_WIN32", + ) + ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)') + results = [] + for lnum, line in f.ChangedContents(): + for match in ifdef_macro.finditer(line): + if match.group(1) in ALWAYS_DEFINED_MACROS: + always_defined = ' %s is always defined. ' % match.group(1) + did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1) + results.append(' %s:%d %s\n\t%s' % (f.LocalPath(), + lnum, + always_defined, + did_you_mean)) + return results + + +def _CheckForInvalidIfDefinedMacros(input_api, output_api): + """Check all affected files for invalid "if defined" macros.""" + bad_macros = [] + for f in input_api.AffectedFiles(): + if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')): + bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f)) + + if not bad_macros: + return [] + + return [output_api.PresubmitError( + 'Found ifdef check on always-defined macro[s]. Please fix your code\n' + 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.', + bad_macros)] + + +def _CheckForUsingSideEffectsOfPass(input_api, output_api): + """Check all affected files for using side effects of Pass.""" + errors = [] + for f in input_api.AffectedFiles(): + if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')): + for lnum, line in f.ChangedContents(): + # Disallow Foo(*my_scoped_thing.Pass()); See crbug.com/418297. + if input_api.re.search(r'\*[a-zA-Z0-9_]+\.Pass\(\)', line): + errors.append(output_api.PresubmitError( + ('%s:%d uses *foo.Pass() to delete the contents of scoped_ptr. ' + + 'See crbug.com/418297.') % (f.LocalPath(), lnum))) + return errors + + +def CheckChangeOnUpload(input_api, output_api): + results = [] + results.extend(_CommonChecks(input_api, output_api)) + results.extend(_CheckValidHostsInDEPS(input_api, output_api)) + results.extend(_CheckJavaStyle(input_api, output_api)) + results.extend( + input_api.canned_checks.CheckGNFormatted(input_api, output_api)) + return results + + +def GetDefaultTryConfigs(bots=None): + """Returns a list of ('bot', set(['tests']), optionally filtered by [bots]. + + If 'bots' is specified, will only return configurations for bots in that list. + """ + + builders_and_tests = { + 'Mojo Android Builder (dbg) Try': ['defaulttests'], + 'Mojo Android Builder Try': ['defaulttests'], + 'Mojo Android Builder Tests (dbg) Try': ['defaulttests'], + 'Mojo Linux (dbg) Try': ['defaulttests'], + 'Mojo Linux ASan Try': ['defaulttests'], + 'Mojo Linux Try': ['defaulttests'], + } + + if bots: + filtered_builders_and_tests = dict((bot, set(builders_and_tests[bot])) + for bot in bots) + else: + filtered_builders_and_tests = dict( + (bot, set(tests)) + for bot, tests in builders_and_tests.iteritems()) + + # Build up the mapping from tryserver master to bot/test. + out = dict() + for bot, tests in filtered_builders_and_tests.iteritems(): + out.setdefault("tryserver.client.mojo", {})[bot] = tests + return out + + +def CheckChangeOnCommit(input_api, output_api): + results = [] + results.extend(_CommonChecks(input_api, output_api)) + results.extend(input_api.canned_checks.CheckChangeHasBugField( + input_api, output_api)) + results.extend(input_api.canned_checks.CheckChangeHasDescription( + input_api, output_api)) + return results + + +def GetPreferredTryMasters(project, change): + import re + files = change.LocalPaths() + + if not files: + return {} + + builders = [ + 'Mojo Android Builder (dbg) Try', + 'Mojo Android Builder Try', + 'Mojo Android Builder Tests (dbg) Try', + 'Mojo Linux (dbg) Try', + 'Mojo Linux ASan Try', + 'Mojo Linux Try', + ] + + return GetDefaultTryConfigs(builders) + +def PostUploadHook(cl, change, output_api): + import subprocess + subprocess.check_call(["git", "cl", "try"]) + return [] diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py new file mode 100644 index 0000000000000..9db52e79be59f --- /dev/null +++ b/PRESUBMIT_test.py @@ -0,0 +1,357 @@ +#!/usr/bin/env python +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import re +import unittest + +import PRESUBMIT +from PRESUBMIT_test_mocks import MockChange, MockFile +from PRESUBMIT_test_mocks import MockInputApi, MockOutputApi + + +_TEST_DATA_DIR = 'base/test/data/presubmit' + + +class IncludeOrderTest(unittest.TestCase): + def testSystemHeaderOrder(self): + scope = [(1, '#include '), + (2, '#include '), + (3, '#include "acustom.h"')] + all_linenums = [linenum for (linenum, _) in scope] + mock_input_api = MockInputApi() + warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api, + '', all_linenums) + self.assertEqual(0, len(warnings)) + + def testSystemHeaderOrderMismatch1(self): + scope = [(10, '#include '), + (20, '#include '), + (30, '#include "acustom.h"')] + all_linenums = [linenum for (linenum, _) in scope] + mock_input_api = MockInputApi() + warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api, + '', all_linenums) + self.assertEqual(1, len(warnings)) + self.assertTrue('20' in warnings[0]) + + def testSystemHeaderOrderMismatch2(self): + scope = [(10, '#include '), + (20, '#include "acustom.h"'), + (30, '#include ')] + all_linenums = [linenum for (linenum, _) in scope] + mock_input_api = MockInputApi() + warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api, + '', all_linenums) + self.assertEqual(1, len(warnings)) + self.assertTrue('30' in warnings[0]) + + def testSystemHeaderOrderMismatch3(self): + scope = [(10, '#include "acustom.h"'), + (20, '#include '), + (30, '#include ')] + all_linenums = [linenum for (linenum, _) in scope] + mock_input_api = MockInputApi() + warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api, + '', all_linenums) + self.assertEqual(2, len(warnings)) + self.assertTrue('20' in warnings[0]) + self.assertTrue('30' in warnings[1]) + + def testAlphabeticalOrderMismatch(self): + scope = [(10, '#include '), + (15, '#include '), + (20, '#include '), + (25, '#include '), + (30, '#include "bcustom.h"'), + (35, '#include "acustom.h"')] + all_linenums = [linenum for (linenum, _) in scope] + mock_input_api = MockInputApi() + warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api, + '', all_linenums) + self.assertEqual(3, len(warnings)) + self.assertTrue('15' in warnings[0]) + self.assertTrue('25' in warnings[1]) + self.assertTrue('35' in warnings[2]) + + def testSpecialFirstInclude1(self): + mock_input_api = MockInputApi() + contents = ['#include "some/path/foo.h"', + '#include "a/header.h"'] + mock_file = MockFile('some/path/foo.cc', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(0, len(warnings)) + + def testSpecialFirstInclude2(self): + mock_input_api = MockInputApi() + contents = ['#include "some/other/path/foo.h"', + '#include "a/header.h"'] + mock_file = MockFile('some/path/foo.cc', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(0, len(warnings)) + + def testSpecialFirstInclude3(self): + mock_input_api = MockInputApi() + contents = ['#include "some/path/foo.h"', + '#include "a/header.h"'] + mock_file = MockFile('some/path/foo_platform.cc', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(0, len(warnings)) + + def testSpecialFirstInclude4(self): + mock_input_api = MockInputApi() + contents = ['#include "some/path/bar.h"', + '#include "a/header.h"'] + mock_file = MockFile('some/path/foo_platform.cc', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(1, len(warnings)) + self.assertTrue('2' in warnings[0]) + + def testSpecialFirstInclude5(self): + mock_input_api = MockInputApi() + contents = ['#include "some/other/path/foo.h"', + '#include "a/header.h"'] + mock_file = MockFile('some/path/foo-suffix.h', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(0, len(warnings)) + + def testSpecialFirstInclude6(self): + mock_input_api = MockInputApi() + contents = ['#include "some/other/path/foo_win.h"', + '#include ', + '#include "a/header.h"'] + mock_file = MockFile('some/path/foo_unittest_win.h', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(0, len(warnings)) + + def testOrderAlreadyWrong(self): + scope = [(1, '#include "b.h"'), + (2, '#include "a.h"'), + (3, '#include "c.h"')] + mock_input_api = MockInputApi() + warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api, + '', [3]) + self.assertEqual(0, len(warnings)) + + def testConflictAdded1(self): + scope = [(1, '#include "a.h"'), + (2, '#include "c.h"'), + (3, '#include "b.h"')] + mock_input_api = MockInputApi() + warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api, + '', [2]) + self.assertEqual(1, len(warnings)) + self.assertTrue('3' in warnings[0]) + + def testConflictAdded2(self): + scope = [(1, '#include "c.h"'), + (2, '#include "b.h"'), + (3, '#include "d.h"')] + mock_input_api = MockInputApi() + warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api, + '', [2]) + self.assertEqual(1, len(warnings)) + self.assertTrue('2' in warnings[0]) + + def testIfElifElseEndif(self): + mock_input_api = MockInputApi() + contents = ['#include "e.h"', + '#define foo', + '#include "f.h"', + '#undef foo', + '#include "e.h"', + '#if foo', + '#include "d.h"', + '#elif bar', + '#include "c.h"', + '#else', + '#include "b.h"', + '#endif', + '#include "a.h"'] + mock_file = MockFile('', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(0, len(warnings)) + + def testExcludedIncludes(self): + # #include 's can appear in any order. + mock_input_api = MockInputApi() + contents = ['#include ', + '#include '] + mock_file = MockFile('', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(0, len(warnings)) + + contents = ['#include ', + '#include '] + mock_file = MockFile('', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(0, len(warnings)) + + contents = ['#include "build/build_config.h"', + '#include "aaa.h"'] + mock_file = MockFile('', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(0, len(warnings)) + + def testCheckOnlyCFiles(self): + mock_input_api = MockInputApi() + mock_output_api = MockOutputApi() + contents = ['#include ', + '#include '] + mock_file_cc = MockFile('something.cc', contents) + mock_file_h = MockFile('something.h', contents) + mock_file_other = MockFile('something.py', contents) + mock_input_api.files = [mock_file_cc, mock_file_h, mock_file_other] + warnings = PRESUBMIT._CheckIncludeOrder(mock_input_api, mock_output_api) + self.assertEqual(1, len(warnings)) + self.assertEqual(2, len(warnings[0].items)) + self.assertEqual('promptOrNotify', warnings[0].type) + + def testUncheckableIncludes(self): + mock_input_api = MockInputApi() + contents = ['#include ', + '#include "b.h"', + '#include "a.h"'] + mock_file = MockFile('', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(1, len(warnings)) + + contents = ['#include "gpu/command_buffer/gles_autogen.h"', + '#include "b.h"', + '#include "a.h"'] + mock_file = MockFile('', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(1, len(warnings)) + + contents = ['#include "gl_mock_autogen.h"', + '#include "b.h"', + '#include "a.h"'] + mock_file = MockFile('', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(1, len(warnings)) + + contents = ['#include "ipc/some_macros.h"', + '#include "b.h"', + '#include "a.h"'] + mock_file = MockFile('', contents) + warnings = PRESUBMIT._CheckIncludeOrderInFile( + mock_input_api, mock_file, range(1, len(contents) + 1)) + self.assertEqual(1, len(warnings)) + + +class VersionControlConflictsTest(unittest.TestCase): + def testTypicalConflict(self): + lines = ['<<<<<<< HEAD', + ' base::ScopedTempDir temp_dir_;', + '=======', + ' ScopedTempDir temp_dir_;', + '>>>>>>> master'] + errors = PRESUBMIT._CheckForVersionControlConflictsInFile( + MockInputApi(), MockFile('some/path/foo_platform.cc', lines)) + self.assertEqual(3, len(errors)) + self.assertTrue('1' in errors[0]) + self.assertTrue('3' in errors[1]) + self.assertTrue('5' in errors[2]) + + +class BadExtensionsTest(unittest.TestCase): + def testBadRejFile(self): + mock_input_api = MockInputApi() + mock_input_api.files = [ + MockFile('some/path/foo.cc', ''), + MockFile('some/path/foo.cc.rej', ''), + MockFile('some/path2/bar.h.rej', ''), + ] + + results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi()) + self.assertEqual(1, len(results)) + self.assertEqual(2, len(results[0].items)) + self.assertTrue('foo.cc.rej' in results[0].items[0]) + self.assertTrue('bar.h.rej' in results[0].items[1]) + + def testBadOrigFile(self): + mock_input_api = MockInputApi() + mock_input_api.files = [ + MockFile('other/path/qux.h.orig', ''), + MockFile('other/path/qux.h', ''), + MockFile('other/path/qux.cc', ''), + ] + + results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi()) + self.assertEqual(1, len(results)) + self.assertEqual(1, len(results[0].items)) + self.assertTrue('qux.h.orig' in results[0].items[0]) + + def testGoodFiles(self): + mock_input_api = MockInputApi() + mock_input_api.files = [ + MockFile('other/path/qux.h', ''), + MockFile('other/path/qux.cc', ''), + ] + results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi()) + self.assertEqual(0, len(results)) + + def testNoFiles(self): + mock_change = MockChange([]) + results = PRESUBMIT.GetPreferredTryMasters(None, mock_change) + self.assertEqual({}, results) + + +class InvalidOSMacroNamesTest(unittest.TestCase): + def testInvalidOSMacroNames(self): + lines = ['#if defined(OS_WINDOWS)', + ' #elif defined(OS_WINDOW)', + ' # if defined(OS_MACOSX) || defined(OS_CHROME)', + '# else // defined(OS_MAC)', + '#endif // defined(OS_MACOS)'] + errors = PRESUBMIT._CheckForInvalidOSMacrosInFile( + MockInputApi(), MockFile('some/path/foo_platform.cc', lines)) + self.assertEqual(len(lines), len(errors)) + self.assertTrue(':1 OS_WINDOWS' in errors[0]) + self.assertTrue('(did you mean OS_WIN?)' in errors[0]) + + def testValidOSMacroNames(self): + lines = ['#if defined(%s)' % m for m in PRESUBMIT._VALID_OS_MACROS] + errors = PRESUBMIT._CheckForInvalidOSMacrosInFile( + MockInputApi(), MockFile('some/path/foo_platform.cc', lines)) + self.assertEqual(0, len(errors)) + + +class InvalidIfDefinedMacroNamesTest(unittest.TestCase): + def testInvalidIfDefinedMacroNames(self): + lines = ['#if defined(TARGET_IPHONE_SIMULATOR)', + '#if !defined(TARGET_IPHONE_SIMULATOR)', + '#elif defined(TARGET_IPHONE_SIMULATOR)', + '#ifdef TARGET_IPHONE_SIMULATOR', + ' # ifdef TARGET_IPHONE_SIMULATOR', + '# if defined(VALID) || defined(TARGET_IPHONE_SIMULATOR)', + '# else // defined(TARGET_IPHONE_SIMULATOR)', + '#endif // defined(TARGET_IPHONE_SIMULATOR)',] + errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile( + MockInputApi(), MockFile('some/path/source.mm', lines)) + self.assertEqual(len(lines), len(errors)) + + def testValidIfDefinedMacroNames(self): + lines = ['#if defined(FOO)', + '#ifdef BAR',] + errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile( + MockInputApi(), MockFile('some/path/source.cc', lines)) + self.assertEqual(0, len(errors)) + + +if __name__ == '__main__': + unittest.main() diff --git a/PRESUBMIT_test_mocks.py b/PRESUBMIT_test_mocks.py new file mode 100644 index 0000000000000..f99671dafda83 --- /dev/null +++ b/PRESUBMIT_test_mocks.py @@ -0,0 +1,109 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import json +import os +import re +import subprocess +import sys + + +class MockInputApi(object): + """Mock class for the InputApi class. + + This class can be used for unittests for presubmit by initializing the files + attribute as the list of changed files. + """ + + def __init__(self): + self.json = json + self.re = re + self.os_path = os.path + self.python_executable = sys.executable + self.subprocess = subprocess + self.files = [] + self.is_committing = False + + def AffectedFiles(self, file_filter=None): + return self.files + + def PresubmitLocalPath(self): + return os.path.dirname(__file__) + + def ReadFile(self, filename, mode='rU'): + for file_ in self.files: + if file_.LocalPath() == filename: + return '\n'.join(file_.NewContents()) + # Otherwise, file is not in our mock API. + raise IOError, "No such file or directory: '%s'" % filename + + +class MockOutputApi(object): + """Mock class for the OutputApi class. + + An instance of this class can be passed to presubmit unittests for outputing + various types of results. + """ + + class PresubmitResult(object): + def __init__(self, message, items=None, long_text=''): + self.message = message + self.items = items + self.long_text = long_text + + class PresubmitError(PresubmitResult): + def __init__(self, message, items, long_text=''): + MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) + self.type = 'error' + + class PresubmitPromptWarning(PresubmitResult): + def __init__(self, message, items, long_text=''): + MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) + self.type = 'warning' + + class PresubmitNotifyResult(PresubmitResult): + def __init__(self, message, items, long_text=''): + MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) + self.type = 'notify' + + class PresubmitPromptOrNotify(PresubmitResult): + def __init__(self, message, items, long_text=''): + MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) + self.type = 'promptOrNotify' + + +class MockFile(object): + """Mock class for the File class. + + This class can be used to form the mock list of changed files in + MockInputApi for presubmit unittests. + """ + + def __init__(self, local_path, new_contents): + self._local_path = local_path + self._new_contents = new_contents + self._changed_contents = [(i + 1, l) for i, l in enumerate(new_contents)] + + def ChangedContents(self): + return self._changed_contents + + def NewContents(self): + return self._new_contents + + def LocalPath(self): + return self._local_path + + +class MockChange(object): + """Mock class for Change class. + + This class can be used in presubmit unittests to mock the query of the + current change. + """ + + def __init__(self, changed_files): + self._changed_files = changed_files + + def LocalPaths(self): + return self._changed_files diff --git a/WATCHLISTS b/WATCHLISTS new file mode 100644 index 0000000000000..7230b062c3d4c --- /dev/null +++ b/WATCHLISTS @@ -0,0 +1,45 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Watchlist Rules +# Refer: http://dev.chromium.org/developers/contributing-code/watchlists + +# IMPORTANT: The regular expression filepath is tested against each path using +# re.search, so it is not usually necessary to add .*. + +{ + 'WATCHLIST_DEFINITIONS': { + 'mojo': { + 'filepath': 'mojo', + }, + 'services': { + 'filepath': 'services', + }, + 'shell': { + 'filepath': 'shell', + }, + 'sky': { + 'filepath': 'sky', + }, + }, + + 'WATCHLISTS': { + 'mojo': ['aa@chromium.org', + 'abarth@chromium.org', + 'ben+mojo@chromium.org', + 'darin@chromium.org', + 'qsr+mojo@chromium.org', + 'viettrungluu+watch@chromium.org', + 'gregsimon@chromium.org', + 'yzshen+watch@chromium.org'], + 'services': ['qsr+mojo@chromium.org', + 'yzshen+watch@chromium.org'], + 'shell': ['qsr+mojo@chromium.org', + 'yzshen+watch@chromium.org'], + 'sky': ['abarth@chromium.org', + 'gregsimon@chromium.org', + 'jackson@chromium.org', + 'qsr+mojo@chromium.org'], + }, +} diff --git a/codereview.settings b/codereview.settings new file mode 100644 index 0000000000000..1dc1b2a04a8fe --- /dev/null +++ b/codereview.settings @@ -0,0 +1,6 @@ +# This file is used by gcl to get repository specific information. +CODE_REVIEW_SERVER: codereview.chromium.org +CC_LIST: mojo-reviews@chromium.org +VIEW_VC: https://chromium.googlesource.com/external/mojo/+/ +PROJECT: mojo +RUN_POST_UPLOAD_HOOK: True diff --git a/third_party/BUILD.gn b/third_party/BUILD.gn new file mode 100644 index 0000000000000..261cb1fecec8b --- /dev/null +++ b/third_party/BUILD.gn @@ -0,0 +1,43 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +if (is_android) { + import("//build/config/android/config.gni") +} + +declare_args() { + # Uses system libjpeg. If true, overrides use_libjpeg_turbo. + use_system_libjpeg = false + + # Uses libjpeg_turbo as the jpeg implementation. Has no effect if + # use_system_libjpeg is set. + use_libjpeg_turbo = true +} + +config("system_libjpeg_config") { + defines = [ "USE_SYSTEM_LIBJPEG" ] +} + +config("libjpeg_turbo_config") { + defines = [ "USE_LIBJPEG_TURBO" ] +} + +# This is a meta target that forwards to the system's libjpeg, +# third_party/libjpeg, or third_party/libjpeg_turbo depending on the build args +# declared in this file. +group("jpeg") { + if (use_system_libjpeg) { + libs = [ "jpeg" ] + public_configs = [ ":system_libjpeg_config" ] + } else if (use_libjpeg_turbo) { + deps = [ + "//third_party/libjpeg_turbo:libjpeg", + ] + public_configs = [ ":libjpeg_turbo_config" ] + } else { + deps = [ + "//third_party/libjpeg:libjpeg", + ] + } +}