libv8 8.4.255.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.gitmodules +3 -0
- data/.rspec +3 -0
- data/.travis.yml +45 -0
- data/CHANGELOG.md +111 -0
- data/Gemfile +4 -0
- data/README.md +152 -0
- data/Rakefile +125 -0
- data/appveyor.yml.disabled +36 -0
- data/ext/libv8/arch.rb +20 -0
- data/ext/libv8/builder.rb +106 -0
- data/ext/libv8/extconf.rb +7 -0
- data/ext/libv8/location.rb +89 -0
- data/ext/libv8/paths.rb +28 -0
- data/lib/libv8.rb +9 -0
- data/lib/libv8/version.rb +3 -0
- data/libv8.gemspec +30 -0
- data/scaleway.png +0 -0
- data/spec/location_spec.rb +69 -0
- data/spec/spec_helper.rb +4 -0
- data/thefrontside.png +0 -0
- data/vendor/depot_tools/.cipd_impl.ps1 +129 -0
- data/vendor/depot_tools/.gitattributes +55 -0
- data/vendor/depot_tools/.gitignore +92 -0
- data/vendor/depot_tools/.style.yapf +4 -0
- data/vendor/depot_tools/.vpython +55 -0
- data/vendor/depot_tools/.vpython3 +23 -0
- data/vendor/depot_tools/CROS_OWNERS +7 -0
- data/vendor/depot_tools/GOMA_OWNERS +9 -0
- data/vendor/depot_tools/LICENSE +27 -0
- data/vendor/depot_tools/LUCI_OWNERS +5 -0
- data/vendor/depot_tools/OWNERS +39 -0
- data/vendor/depot_tools/PRESUBMIT.py +150 -0
- data/vendor/depot_tools/README.gclient.md +67 -0
- data/vendor/depot_tools/README.git-cl.md +99 -0
- data/vendor/depot_tools/README.md +78 -0
- data/vendor/depot_tools/WATCHLISTS +26 -0
- data/vendor/depot_tools/auth.py +163 -0
- data/vendor/depot_tools/autoninja +36 -0
- data/vendor/depot_tools/autoninja.bat +33 -0
- data/vendor/depot_tools/autoninja.py +148 -0
- data/vendor/depot_tools/bb +12 -0
- data/vendor/depot_tools/bb.bat +7 -0
- data/vendor/depot_tools/bootstrap/README.md +155 -0
- data/vendor/depot_tools/bootstrap/bootstrap.py +356 -0
- data/vendor/depot_tools/bootstrap/git-bash.template.sh +12 -0
- data/vendor/depot_tools/bootstrap/git.template.bat +5 -0
- data/vendor/depot_tools/bootstrap/manifest.txt +27 -0
- data/vendor/depot_tools/bootstrap/manifest_bleeding_edge.txt +27 -0
- data/vendor/depot_tools/bootstrap/profile.d.python.sh +20 -0
- data/vendor/depot_tools/bootstrap/python27.bat +46 -0
- data/vendor/depot_tools/bootstrap/python3.bat +46 -0
- data/vendor/depot_tools/bootstrap/win_tools.bat +79 -0
- data/vendor/depot_tools/bootstrap_python3 +35 -0
- data/vendor/depot_tools/breakpad.py +12 -0
- data/vendor/depot_tools/cbuildbot +1 -0
- data/vendor/depot_tools/chrome_set_ver +1 -0
- data/vendor/depot_tools/cipd +247 -0
- data/vendor/depot_tools/cipd.bat +67 -0
- data/vendor/depot_tools/cipd_bin_setup.bat +6 -0
- data/vendor/depot_tools/cipd_bin_setup.sh +22 -0
- data/vendor/depot_tools/cipd_client_version +1 -0
- data/vendor/depot_tools/cipd_client_version.digests +22 -0
- data/vendor/depot_tools/cipd_manifest.txt +63 -0
- data/vendor/depot_tools/cipd_manifest.versions +438 -0
- data/vendor/depot_tools/cit +8 -0
- data/vendor/depot_tools/cit.bat +12 -0
- data/vendor/depot_tools/cit.py +167 -0
- data/vendor/depot_tools/clang-format +8 -0
- data/vendor/depot_tools/clang-format.bat +12 -0
- data/vendor/depot_tools/clang_format.py +79 -0
- data/vendor/depot_tools/clang_format_merge_driver +8 -0
- data/vendor/depot_tools/clang_format_merge_driver.bat +12 -0
- data/vendor/depot_tools/clang_format_merge_driver.py +69 -0
- data/vendor/depot_tools/codereview.settings +6 -0
- data/vendor/depot_tools/compile_single_file +8 -0
- data/vendor/depot_tools/compile_single_file.bat +11 -0
- data/vendor/depot_tools/compile_single_file.py +79 -0
- data/vendor/depot_tools/cpplint.bat +11 -0
- data/vendor/depot_tools/cpplint.py +6097 -0
- data/vendor/depot_tools/cpplint_chromium.py +50 -0
- data/vendor/depot_tools/cros +87 -0
- data/vendor/depot_tools/cros_sdk +1 -0
- data/vendor/depot_tools/crosjobs +13 -0
- data/vendor/depot_tools/detect_host_arch.py +55 -0
- data/vendor/depot_tools/dirmd +12 -0
- data/vendor/depot_tools/dirmd.bat +7 -0
- data/vendor/depot_tools/download_from_google_storage +8 -0
- data/vendor/depot_tools/download_from_google_storage.bat +12 -0
- data/vendor/depot_tools/download_from_google_storage.py +634 -0
- data/vendor/depot_tools/ensure_bootstrap +53 -0
- data/vendor/depot_tools/fetch +21 -0
- data/vendor/depot_tools/fetch.bat +28 -0
- data/vendor/depot_tools/fetch.py +319 -0
- data/vendor/depot_tools/fetch_configs/android.py +34 -0
- data/vendor/depot_tools/fetch_configs/android_internal.py +34 -0
- data/vendor/depot_tools/fetch_configs/breakpad.py +44 -0
- data/vendor/depot_tools/fetch_configs/chromium.py +66 -0
- data/vendor/depot_tools/fetch_configs/config_util.py +52 -0
- data/vendor/depot_tools/fetch_configs/crashpad.py +41 -0
- data/vendor/depot_tools/fetch_configs/dart.py +45 -0
- data/vendor/depot_tools/fetch_configs/depot_tools.py +44 -0
- data/vendor/depot_tools/fetch_configs/devtools-frontend.py +44 -0
- data/vendor/depot_tools/fetch_configs/goma_client.py +41 -0
- data/vendor/depot_tools/fetch_configs/gyp.py +41 -0
- data/vendor/depot_tools/fetch_configs/infra.py +40 -0
- data/vendor/depot_tools/fetch_configs/infra_internal.py +45 -0
- data/vendor/depot_tools/fetch_configs/inspector_protocol.py +40 -0
- data/vendor/depot_tools/fetch_configs/ios.py +34 -0
- data/vendor/depot_tools/fetch_configs/ios_internal.py +39 -0
- data/vendor/depot_tools/fetch_configs/nacl.py +48 -0
- data/vendor/depot_tools/fetch_configs/naclports.py +47 -0
- data/vendor/depot_tools/fetch_configs/node-ci.py +41 -0
- data/vendor/depot_tools/fetch_configs/pdfium.py +40 -0
- data/vendor/depot_tools/fetch_configs/skia.py +41 -0
- data/vendor/depot_tools/fetch_configs/skia_buildbot.py +41 -0
- data/vendor/depot_tools/fetch_configs/syzygy.py +41 -0
- data/vendor/depot_tools/fetch_configs/v8.py +44 -0
- data/vendor/depot_tools/fetch_configs/webrtc.py +52 -0
- data/vendor/depot_tools/fetch_configs/webrtc_android.py +34 -0
- data/vendor/depot_tools/fetch_configs/webrtc_ios.py +34 -0
- data/vendor/depot_tools/fix_encoding.py +385 -0
- data/vendor/depot_tools/gclient +38 -0
- data/vendor/depot_tools/gclient-new-workdir.py +124 -0
- data/vendor/depot_tools/gclient.bat +32 -0
- data/vendor/depot_tools/gclient.py +3198 -0
- data/vendor/depot_tools/gclient_completion.sh +76 -0
- data/vendor/depot_tools/gclient_eval.py +891 -0
- data/vendor/depot_tools/gclient_paths.py +152 -0
- data/vendor/depot_tools/gclient_scm.py +1615 -0
- data/vendor/depot_tools/gclient_utils.py +1280 -0
- data/vendor/depot_tools/gerrit_client.py +151 -0
- data/vendor/depot_tools/gerrit_util.py +996 -0
- data/vendor/depot_tools/git-cache +6 -0
- data/vendor/depot_tools/git-cl +6 -0
- data/vendor/depot_tools/git-crrev-parse +53 -0
- data/vendor/depot_tools/git-drover +6 -0
- data/vendor/depot_tools/git-find-releases +6 -0
- data/vendor/depot_tools/git-footers +6 -0
- data/vendor/depot_tools/git-freeze +8 -0
- data/vendor/depot_tools/git-gs +9 -0
- data/vendor/depot_tools/git-hyper-blame +6 -0
- data/vendor/depot_tools/git-map +6 -0
- data/vendor/depot_tools/git-map-branches +6 -0
- data/vendor/depot_tools/git-mark-merge-base +6 -0
- data/vendor/depot_tools/git-nav-downstream +6 -0
- data/vendor/depot_tools/git-nav-upstream +6 -0
- data/vendor/depot_tools/git-new-branch +6 -0
- data/vendor/depot_tools/git-number +6 -0
- data/vendor/depot_tools/git-rebase-update +6 -0
- data/vendor/depot_tools/git-rename-branch +6 -0
- data/vendor/depot_tools/git-reparent-branch +6 -0
- data/vendor/depot_tools/git-retry +8 -0
- data/vendor/depot_tools/git-runhooks +23 -0
- data/vendor/depot_tools/git-squash-branch +6 -0
- data/vendor/depot_tools/git-templates/description +3 -0
- data/vendor/depot_tools/git-templates/hooks/applypatch-msg +4 -0
- data/vendor/depot_tools/git-templates/hooks/post-applypatch +4 -0
- data/vendor/depot_tools/git-templates/hooks/post-checkout +4 -0
- data/vendor/depot_tools/git-templates/hooks/post-commit +4 -0
- data/vendor/depot_tools/git-templates/hooks/post-merge +4 -0
- data/vendor/depot_tools/git-templates/hooks/post-update +4 -0
- data/vendor/depot_tools/git-templates/hooks/pre-applypatch +4 -0
- data/vendor/depot_tools/git-templates/hooks/pre-auto-gc +4 -0
- data/vendor/depot_tools/git-templates/hooks/pre-commit +4 -0
- data/vendor/depot_tools/git-templates/hooks/pre-rebase +4 -0
- data/vendor/depot_tools/git-templates/hooks/prepare-commit-msg +4 -0
- data/vendor/depot_tools/git-templates/info/exclude +6 -0
- data/vendor/depot_tools/git-thaw +13 -0
- data/vendor/depot_tools/git-upstream-diff +9 -0
- data/vendor/depot_tools/git_cache.py +786 -0
- data/vendor/depot_tools/git_cl.py +5158 -0
- data/vendor/depot_tools/git_cl_completion.sh +48 -0
- data/vendor/depot_tools/git_common.py +1101 -0
- data/vendor/depot_tools/git_dates.py +62 -0
- data/vendor/depot_tools/git_drover.py +469 -0
- data/vendor/depot_tools/git_find_releases.py +67 -0
- data/vendor/depot_tools/git_footers.py +261 -0
- data/vendor/depot_tools/git_freezer.py +40 -0
- data/vendor/depot_tools/git_hyper_blame.py +391 -0
- data/vendor/depot_tools/git_map.py +166 -0
- data/vendor/depot_tools/git_map_branches.py +354 -0
- data/vendor/depot_tools/git_mark_merge_base.py +73 -0
- data/vendor/depot_tools/git_nav_downstream.py +69 -0
- data/vendor/depot_tools/git_new_branch.py +82 -0
- data/vendor/depot_tools/git_number.py +301 -0
- data/vendor/depot_tools/git_rebase_update.py +351 -0
- data/vendor/depot_tools/git_rename_branch.py +55 -0
- data/vendor/depot_tools/git_reparent_branch.py +101 -0
- data/vendor/depot_tools/git_retry.py +181 -0
- data/vendor/depot_tools/git_squash_branch.py +28 -0
- data/vendor/depot_tools/git_upstream_diff.py +64 -0
- data/vendor/depot_tools/gn +8 -0
- data/vendor/depot_tools/gn.bat +12 -0
- data/vendor/depot_tools/gn.py +78 -0
- data/vendor/depot_tools/goma_auth +12 -0
- data/vendor/depot_tools/goma_auth.bat +8 -0
- data/vendor/depot_tools/goma_ctl +12 -0
- data/vendor/depot_tools/goma_ctl.bat +8 -0
- data/vendor/depot_tools/gsutil.py +190 -0
- data/vendor/depot_tools/gsutil.py.bat +23 -0
- data/vendor/depot_tools/gsutil.vpython +120 -0
- data/vendor/depot_tools/infra/README.md +1 -0
- data/vendor/depot_tools/infra/config/OWNERS +7 -0
- data/vendor/depot_tools/infra/config/README.md +1 -0
- data/vendor/depot_tools/infra/config/recipes.cfg +26 -0
- data/vendor/depot_tools/led +12 -0
- data/vendor/depot_tools/led.bat +7 -0
- data/vendor/depot_tools/lockfile.py +116 -0
- data/vendor/depot_tools/luci-auth +13 -0
- data/vendor/depot_tools/luci-auth.bat +8 -0
- data/vendor/depot_tools/lucicfg +12 -0
- data/vendor/depot_tools/lucicfg.bat +7 -0
- data/vendor/depot_tools/mac_toolchain +12 -0
- data/vendor/depot_tools/man/html/depot_tools.html +934 -0
- data/vendor/depot_tools/man/html/depot_tools_tutorial.html +1593 -0
- data/vendor/depot_tools/man/html/git-cl.html +1033 -0
- data/vendor/depot_tools/man/html/git-drover.html +1048 -0
- data/vendor/depot_tools/man/html/git-footers.html +878 -0
- data/vendor/depot_tools/man/html/git-freeze.html +859 -0
- data/vendor/depot_tools/man/html/git-hyper-blame.html +878 -0
- data/vendor/depot_tools/man/html/git-map-branches.html +904 -0
- data/vendor/depot_tools/man/html/git-map.html +887 -0
- data/vendor/depot_tools/man/html/git-mark-merge-base.html +826 -0
- data/vendor/depot_tools/man/html/git-nav-downstream.html +844 -0
- data/vendor/depot_tools/man/html/git-nav-upstream.html +853 -0
- data/vendor/depot_tools/man/html/git-new-branch.html +932 -0
- data/vendor/depot_tools/man/html/git-rebase-update.html +961 -0
- data/vendor/depot_tools/man/html/git-rename-branch.html +794 -0
- data/vendor/depot_tools/man/html/git-reparent-branch.html +847 -0
- data/vendor/depot_tools/man/html/git-retry.html +858 -0
- data/vendor/depot_tools/man/html/git-squash-branch.html +881 -0
- data/vendor/depot_tools/man/html/git-thaw.html +794 -0
- data/vendor/depot_tools/man/html/git-upstream-diff.html +923 -0
- data/vendor/depot_tools/man/man1/git-cl.1 +198 -0
- data/vendor/depot_tools/man/man1/git-drover.1 +330 -0
- data/vendor/depot_tools/man/man1/git-footers.1 +144 -0
- data/vendor/depot_tools/man/man1/git-freeze.1 +113 -0
- data/vendor/depot_tools/man/man1/git-hyper-blame.1 +128 -0
- data/vendor/depot_tools/man/man1/git-map-branches.1 +210 -0
- data/vendor/depot_tools/man/man1/git-map.1 +179 -0
- data/vendor/depot_tools/man/man1/git-mark-merge-base.1 +69 -0
- data/vendor/depot_tools/man/man1/git-nav-downstream.1 +112 -0
- data/vendor/depot_tools/man/man1/git-nav-upstream.1 +122 -0
- data/vendor/depot_tools/man/man1/git-new-branch.1 +176 -0
- data/vendor/depot_tools/man/man1/git-rebase-update.1 +177 -0
- data/vendor/depot_tools/man/man1/git-rename-branch.1 +53 -0
- data/vendor/depot_tools/man/man1/git-reparent-branch.1 +93 -0
- data/vendor/depot_tools/man/man1/git-retry.1 +108 -0
- data/vendor/depot_tools/man/man1/git-squash-branch.1 +129 -0
- data/vendor/depot_tools/man/man1/git-thaw.1 +54 -0
- data/vendor/depot_tools/man/man1/git-upstream-diff.1 +153 -0
- data/vendor/depot_tools/man/man7/depot_tools.7 +139 -0
- data/vendor/depot_tools/man/man7/depot_tools_tutorial.7 +1061 -0
- data/vendor/depot_tools/man/push_to_gs.sh +4 -0
- data/vendor/depot_tools/man/src/.gitignore +5 -0
- data/vendor/depot_tools/man/src/_aliases.txt +5 -0
- data/vendor/depot_tools/man/src/_footer.txt +8 -0
- data/vendor/depot_tools/man/src/_git-cl_desc.helper.txt +1 -0
- data/vendor/depot_tools/man/src/_git-drover_desc.helper.txt +2 -0
- data/vendor/depot_tools/man/src/_git-footers_desc.helper.txt +1 -0
- data/vendor/depot_tools/man/src/_git-freeze_desc.helper.txt +1 -0
- data/vendor/depot_tools/man/src/_git-hyper-blame_desc.helper.txt +1 -0
- data/vendor/depot_tools/man/src/_git-map-branches_desc.helper.txt +4 -0
- data/vendor/depot_tools/man/src/_git-map_desc.helper.txt +3 -0
- data/vendor/depot_tools/man/src/_git-mark-merge-base_desc.helper.txt +1 -0
- data/vendor/depot_tools/man/src/_git-nav-downstream_desc.helper.txt +1 -0
- data/vendor/depot_tools/man/src/_git-nav-upstream_desc.helper.txt +1 -0
- data/vendor/depot_tools/man/src/_git-new-branch_desc.helper.txt +1 -0
- data/vendor/depot_tools/man/src/_git-rebase-update_desc.helper.txt +1 -0
- data/vendor/depot_tools/man/src/_git-rename-branch_desc.helper.txt +1 -0
- data/vendor/depot_tools/man/src/_git-reparent-branch_desc.helper.txt +1 -0
- data/vendor/depot_tools/man/src/_git-retry_desc.helper.txt +2 -0
- data/vendor/depot_tools/man/src/_git-squash-branch_desc.helper.txt +1 -0
- data/vendor/depot_tools/man/src/_git-thaw_desc.helper.txt +2 -0
- data/vendor/depot_tools/man/src/_git-upstream-diff_desc.helper.txt +1 -0
- data/vendor/depot_tools/man/src/_helper_prefix.txt +1 -0
- data/vendor/depot_tools/man/src/asciidoc-override.css +7 -0
- data/vendor/depot_tools/man/src/common_demo_functions.sh +84 -0
- data/vendor/depot_tools/man/src/demo_repo.sh +43 -0
- data/vendor/depot_tools/man/src/depot_tools.txt +28 -0
- data/vendor/depot_tools/man/src/depot_tools_tutorial.demo.walkthrough.sh +155 -0
- data/vendor/depot_tools/man/src/depot_tools_tutorial.txt +432 -0
- data/vendor/depot_tools/man/src/filter_demo_output.py +141 -0
- data/vendor/depot_tools/man/src/git-cl.txt +119 -0
- data/vendor/depot_tools/man/src/git-drover.demo.1.sh +22 -0
- data/vendor/depot_tools/man/src/git-drover.demo.2.sh +23 -0
- data/vendor/depot_tools/man/src/git-drover.demo.3.sh +27 -0
- data/vendor/depot_tools/man/src/git-drover.demo.4.sh +39 -0
- data/vendor/depot_tools/man/src/git-drover.demo.common.sh +19 -0
- data/vendor/depot_tools/man/src/git-drover.txt +102 -0
- data/vendor/depot_tools/man/src/git-footers.demo.1.sh +17 -0
- data/vendor/depot_tools/man/src/git-footers.txt +71 -0
- data/vendor/depot_tools/man/src/git-freeze.demo.1.sh +23 -0
- data/vendor/depot_tools/man/src/git-freeze.txt +54 -0
- data/vendor/depot_tools/man/src/git-hyper-blame.demo.1.sh +3 -0
- data/vendor/depot_tools/man/src/git-hyper-blame.demo.2.sh +4 -0
- data/vendor/depot_tools/man/src/git-hyper-blame.demo.common.sh +57 -0
- data/vendor/depot_tools/man/src/git-hyper-blame.txt +85 -0
- data/vendor/depot_tools/man/src/git-map-branches.demo.1.sh +8 -0
- data/vendor/depot_tools/man/src/git-map-branches.txt +64 -0
- data/vendor/depot_tools/man/src/git-map.demo.1.sh +3 -0
- data/vendor/depot_tools/man/src/git-map.txt +67 -0
- data/vendor/depot_tools/man/src/git-mark-merge-base.txt +46 -0
- data/vendor/depot_tools/man/src/git-nav-downstream.demo.1.sh +12 -0
- data/vendor/depot_tools/man/src/git-nav-downstream.txt +40 -0
- data/vendor/depot_tools/man/src/git-nav-upstream.demo.1.sh +12 -0
- data/vendor/depot_tools/man/src/git-nav-upstream.txt +39 -0
- data/vendor/depot_tools/man/src/git-new-branch.demo.1.sh +17 -0
- data/vendor/depot_tools/man/src/git-new-branch.txt +82 -0
- data/vendor/depot_tools/man/src/git-rebase-update.txt +141 -0
- data/vendor/depot_tools/man/src/git-rename-branch.txt +28 -0
- data/vendor/depot_tools/man/src/git-reparent-branch.txt +61 -0
- data/vendor/depot_tools/man/src/git-retry.txt +67 -0
- data/vendor/depot_tools/man/src/git-squash-branch.demo.1.sh +12 -0
- data/vendor/depot_tools/man/src/git-squash-branch.txt +59 -0
- data/vendor/depot_tools/man/src/git-thaw.txt +29 -0
- data/vendor/depot_tools/man/src/git-upstream-diff.txt +107 -0
- data/vendor/depot_tools/man/src/make_docs.sh +260 -0
- data/vendor/depot_tools/man/src/prep_demo_repo.sh +103 -0
- data/vendor/depot_tools/metrics.README.md +101 -0
- data/vendor/depot_tools/metrics.py +297 -0
- data/vendor/depot_tools/metrics_utils.py +293 -0
- data/vendor/depot_tools/my_activity.py +971 -0
- data/vendor/depot_tools/ninja +44 -0
- data/vendor/depot_tools/ninja-linux32 +0 -0
- data/vendor/depot_tools/ninja-linux64 +0 -0
- data/vendor/depot_tools/ninja-mac +0 -0
- data/vendor/depot_tools/ninja.exe +0 -0
- data/vendor/depot_tools/ninjalog.README.md +64 -0
- data/vendor/depot_tools/ninjalog_uploader.py +233 -0
- data/vendor/depot_tools/ninjalog_uploader_wrapper.py +125 -0
- data/vendor/depot_tools/owners.py +641 -0
- data/vendor/depot_tools/owners_finder.py +385 -0
- data/vendor/depot_tools/post_build_ninja_summary.py +350 -0
- data/vendor/depot_tools/presubmit_canned_checks.py +1655 -0
- data/vendor/depot_tools/presubmit_support.py +1923 -0
- data/vendor/depot_tools/profile.xml +8 -0
- data/vendor/depot_tools/prpc +13 -0
- data/vendor/depot_tools/prpc.bat +8 -0
- data/vendor/depot_tools/pylint +9 -0
- data/vendor/depot_tools/pylint-1.5 +78 -0
- data/vendor/depot_tools/pylint-1.6 +78 -0
- data/vendor/depot_tools/pylint-1.7 +78 -0
- data/vendor/depot_tools/pylint-1.8 +78 -0
- data/vendor/depot_tools/pylint-1.9 +78 -0
- data/vendor/depot_tools/pylint.bat +12 -0
- data/vendor/depot_tools/pylint_main.py +45 -0
- data/vendor/depot_tools/pylintrc +349 -0
- data/vendor/depot_tools/python-bin/python3 +7 -0
- data/vendor/depot_tools/python_runner.sh +60 -0
- data/vendor/depot_tools/rdb +12 -0
- data/vendor/depot_tools/rdb.bat +7 -0
- data/vendor/depot_tools/recipes/OWNERS +4 -0
- data/vendor/depot_tools/recipes/README.recipes.md +1079 -0
- data/vendor/depot_tools/recipes/recipe_modules/OWNERS +1 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/OWNERS +2 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/__init__.py +38 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/api.py +516 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/basic.json +117 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/basic_luci.json +117 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/basic_with_branch_heads.json +118 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/clobber.json +211 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/deprecated_got_revision_mapping.json +194 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/gerrit_no_rebase_patch_ref.json +211 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/gerrit_no_reset.json +211 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/input_commit_with_id_without_repo.json +210 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/multiple_patch_refs.json +214 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/no_apply_patch_on_gclient.json +265 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/no_cp_checkout_HEAD.json +65 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/no_cp_checkout_a_branch_head.json +65 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/no_cp_checkout_a_specific_commit.json +65 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/no_cp_checkout_master.json +65 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/refs.json +212 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/reset_root_solution_revision.json +210 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/resolve_chromium_fixed_version.json +117 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail.json +95 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch.json +209 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch_download.json +193 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_angle.json +265 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_branch_heads.json +261 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_feature_branch.json +261 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_v8_feature_branch.json +265 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_webrtc.json +265 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8.json +265 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8_head_by_default.json +265 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/unrecognized_commit_repo.json +8 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/with_tags.json +211 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.py +308 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/resources/__init__.py +0 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/resources/bot_update.py +1258 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/test_api.py +93 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/tests/do_not_retry_patch_failures_in_cq.py +42 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/tests/ensure_checkout.py +35 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/__init__.py +9 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/api.py +455 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/basic.json +403 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/basic_pkg.json +403 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/describe-failed.json +82 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/describe-many-instances.json +411 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/mac64.json +403 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/pkg_bad_file.json +315 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/pkg_bad_mode.json +313 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/pkg_bad_verfile.json +313 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/win64.json +403 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.py +187 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/junk arch.json +5 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/junk bits.json +5 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_arm_32.json +12 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_arm_64.json +12 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_intel_32.json +12 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_intel_64.json +12 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_mips_64.json +12 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/mac_intel_64.json +12 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/win_intel_32.json +12 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/win_intel_64.json +12 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.py +59 -0
- data/vendor/depot_tools/recipes/recipe_modules/cipd/test_api.py +93 -0
- data/vendor/depot_tools/recipes/recipe_modules/depot_tools/__init__.py +9 -0
- data/vendor/depot_tools/recipes/recipe_modules/depot_tools/api.py +75 -0
- data/vendor/depot_tools/recipes/recipe_modules/depot_tools/examples/full.expected/basic.json +83 -0
- data/vendor/depot_tools/recipes/recipe_modules/depot_tools/examples/full.expected/basic_luci.json +83 -0
- data/vendor/depot_tools/recipes/recipe_modules/depot_tools/examples/full.expected/win.json +83 -0
- data/vendor/depot_tools/recipes/recipe_modules/depot_tools/examples/full.py +55 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/__init__.py +13 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/api.py +428 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/config.py +462 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/basic.json +238 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/revision.json +240 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/tryserver.json +238 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.py +95 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/resources/diff_deps.py +16 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/test_api.py +36 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/diff_deps.expected/basic.json +55 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/diff_deps.expected/dont have revision yet.json +84 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/diff_deps.expected/no change, exception.json +83 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/diff_deps.expected/windows.json +55 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/diff_deps.py +88 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/patch_project.py +92 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/sync_failure.py +24 -0
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/__init__.py +8 -0
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/api.py +178 -0
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/examples/full.expected/basic.json +284 -0
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/examples/full.py +73 -0
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/test_api.py +53 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/__init__.py +11 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/api.py +405 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic.json +217 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_branch.json +217 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_file_name.json +219 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_hash.json +216 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_ref.json +217 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_submodule_update_force.json +218 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_tags.json +218 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/can_fail_build.json +164 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/cannot_fail_build.json +220 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/cat-file_test.json +239 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/count-objects_delta.json +290 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/count-objects_failed.json +220 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/count-objects_with_bad_output.json +222 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/count-objects_with_bad_output_fails_build.json +111 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/curl_trace_file.json +218 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/git-cache-checkout.json +265 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/platform_win.json +217 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/rebase_failed.json +221 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/remote_not_origin.json +219 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/set_got_revision.json +218 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.py +170 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/resources/git_setup.py +52 -0
- data/vendor/depot_tools/recipes/recipe_modules/git/test_api.py +18 -0
- data/vendor/depot_tools/recipes/recipe_modules/git_cl/__init__.py +5 -0
- data/vendor/depot_tools/recipes/recipe_modules/git_cl/api.py +50 -0
- data/vendor/depot_tools/recipes/recipe_modules/git_cl/config.py +22 -0
- data/vendor/depot_tools/recipes/recipe_modules/git_cl/examples/full.expected/basic.json +105 -0
- data/vendor/depot_tools/recipes/recipe_modules/git_cl/examples/full.py +47 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/OWNERS +2 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/__init__.py +12 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/api.py +257 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/examples/full.expected/basic.json +596 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/examples/full.py +93 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/resources/gerrit_client.py +251 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/test_api.py +95 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/tests/parse_repo_url.expected/basic.json +5 -0
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/tests/parse_repo_url.py +49 -0
- data/vendor/depot_tools/recipes/recipe_modules/gsutil/__init__.py +4 -0
- data/vendor/depot_tools/recipes/recipe_modules/gsutil/api.py +222 -0
- data/vendor/depot_tools/recipes/recipe_modules/gsutil/examples/full.expected/basic.json +247 -0
- data/vendor/depot_tools/recipes/recipe_modules/gsutil/examples/full.py +92 -0
- data/vendor/depot_tools/recipes/recipe_modules/gsutil/resources/gsutil_smart_retry.py +69 -0
- data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/__init__.py +36 -0
- data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/api.py +140 -0
- data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/ancient_version.json +83 -0
- data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/automatic_version.json +83 -0
- data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/explicit_version.json +83 -0
- data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/linux.json +21 -0
- data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/mac.json +83 -0
- data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/win.json +21 -0
- data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.py +42 -0
- data/vendor/depot_tools/recipes/recipe_modules/presubmit/__init__.py +27 -0
- data/vendor/depot_tools/recipes/recipe_modules/presubmit/api.py +251 -0
- data/vendor/depot_tools/recipes/recipe_modules/presubmit/examples/full.expected/basic.json +27 -0
- data/vendor/depot_tools/recipes/recipe_modules/presubmit/examples/full.py +19 -0
- data/vendor/depot_tools/recipes/recipe_modules/presubmit/properties.proto +14 -0
- data/vendor/depot_tools/recipes/recipe_modules/presubmit/test_api.py +19 -0
- data/vendor/depot_tools/recipes/recipe_modules/presubmit/tests/execute.py +247 -0
- data/vendor/depot_tools/recipes/recipe_modules/presubmit/tests/prepare.py +49 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/__init__.py +18 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/api.py +264 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/basic_tags.json +57 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch.json +190 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch_and_target_ref.json +190 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_wrong_patch.json +21 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_wrong_patch_new.json +22 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.py +95 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/test_api.py +14 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/tests/gerrit_change_fetch_ref_timeout.py +29 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/tests/gerrit_change_owner.expected/basic.json +5 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/tests/gerrit_change_owner.py +22 -0
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/tests/gerrit_change_target_ref.py +32 -0
- data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/__init__.py +25 -0
- data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/api.py +137 -0
- data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/examples/full.expected/linux.json +21 -0
- data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/examples/full.expected/mac.json +21 -0
- data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/examples/full.expected/win.json +108 -0
- data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/examples/full.py +21 -0
- data/vendor/depot_tools/recipes/recipes.py +249 -0
- data/vendor/depot_tools/recipes/recipes/fetch_end_to_end_test.expected/basic.json +175 -0
- data/vendor/depot_tools/recipes/recipes/fetch_end_to_end_test.py +56 -0
- data/vendor/depot_tools/recipes/trigger_recipe_roller.txt +13 -0
- data/vendor/depot_tools/repo +1194 -0
- data/vendor/depot_tools/roll-dep +21 -0
- data/vendor/depot_tools/roll-dep.bat +21 -0
- data/vendor/depot_tools/roll_dep.py +282 -0
- data/vendor/depot_tools/scm.py +415 -0
- data/vendor/depot_tools/setup_color.py +130 -0
- data/vendor/depot_tools/split_cl.py +263 -0
- data/vendor/depot_tools/subcommand.py +261 -0
- data/vendor/depot_tools/subprocess2.py +258 -0
- data/vendor/depot_tools/third_party/__init__.py +5 -0
- data/vendor/depot_tools/third_party/colorama/LICENSE.txt +27 -0
- data/vendor/depot_tools/third_party/colorama/README.chromium +12 -0
- data/vendor/depot_tools/third_party/colorama/README.rst +346 -0
- data/vendor/depot_tools/third_party/colorama/__init__.py +6 -0
- data/vendor/depot_tools/third_party/colorama/ansi.py +102 -0
- data/vendor/depot_tools/third_party/colorama/ansitowin32.py +257 -0
- data/vendor/depot_tools/third_party/colorama/initialise.py +80 -0
- data/vendor/depot_tools/third_party/colorama/win32.py +152 -0
- data/vendor/depot_tools/third_party/colorama/winterm.py +169 -0
- data/vendor/depot_tools/third_party/coverage/AUTHORS.txt +43 -0
- data/vendor/depot_tools/third_party/coverage/PKG-INFO +41 -0
- data/vendor/depot_tools/third_party/coverage/README.chromium +13 -0
- data/vendor/depot_tools/third_party/coverage/__init__.py +120 -0
- data/vendor/depot_tools/third_party/coverage/__main__.py +4 -0
- data/vendor/depot_tools/third_party/coverage/annotate.py +101 -0
- data/vendor/depot_tools/third_party/coverage/backward.py +184 -0
- data/vendor/depot_tools/third_party/coverage/bytecode.py +75 -0
- data/vendor/depot_tools/third_party/coverage/cmdline.py +740 -0
- data/vendor/depot_tools/third_party/coverage/codeunit.py +145 -0
- data/vendor/depot_tools/third_party/coverage/collector.py +353 -0
- data/vendor/depot_tools/third_party/coverage/config.py +213 -0
- data/vendor/depot_tools/third_party/coverage/control.py +776 -0
- data/vendor/depot_tools/third_party/coverage/data.py +278 -0
- data/vendor/depot_tools/third_party/coverage/debug.py +54 -0
- data/vendor/depot_tools/third_party/coverage/execfile.py +171 -0
- data/vendor/depot_tools/third_party/coverage/files.py +309 -0
- data/vendor/depot_tools/third_party/coverage/fullcoverage/encodings.py +57 -0
- data/vendor/depot_tools/third_party/coverage/html.py +387 -0
- data/vendor/depot_tools/third_party/coverage/htmlfiles/coverage_html.js +376 -0
- data/vendor/depot_tools/third_party/coverage/htmlfiles/index.html +104 -0
- data/vendor/depot_tools/third_party/coverage/htmlfiles/jquery-1.4.3.min.js +166 -0
- data/vendor/depot_tools/third_party/coverage/htmlfiles/jquery.hotkeys.js +99 -0
- data/vendor/depot_tools/third_party/coverage/htmlfiles/jquery.isonscreen.js +53 -0
- data/vendor/depot_tools/third_party/coverage/htmlfiles/jquery.min.js +166 -0
- data/vendor/depot_tools/third_party/coverage/htmlfiles/jquery.tablesorter.min.js +2 -0
- data/vendor/depot_tools/third_party/coverage/htmlfiles/keybd_closed.png +0 -0
- data/vendor/depot_tools/third_party/coverage/htmlfiles/keybd_open.png +0 -0
- data/vendor/depot_tools/third_party/coverage/htmlfiles/pyfile.html +90 -0
- data/vendor/depot_tools/third_party/coverage/htmlfiles/style.css +300 -0
- data/vendor/depot_tools/third_party/coverage/misc.py +163 -0
- data/vendor/depot_tools/third_party/coverage/parser.py +666 -0
- data/vendor/depot_tools/third_party/coverage/phystokens.py +208 -0
- data/vendor/depot_tools/third_party/coverage/report.py +92 -0
- data/vendor/depot_tools/third_party/coverage/results.py +286 -0
- data/vendor/depot_tools/third_party/coverage/summary.py +86 -0
- data/vendor/depot_tools/third_party/coverage/templite.py +166 -0
- data/vendor/depot_tools/third_party/coverage/version.py +9 -0
- data/vendor/depot_tools/third_party/coverage/xmlreport.py +155 -0
- data/vendor/depot_tools/third_party/httplib2/LICENSE +1339 -0
- data/vendor/depot_tools/third_party/httplib2/README.chromium +15 -0
- data/vendor/depot_tools/third_party/httplib2/__init__.py +1780 -0
- data/vendor/depot_tools/third_party/httplib2/cacerts.txt +2196 -0
- data/vendor/depot_tools/third_party/httplib2/iri2uri.py +110 -0
- data/vendor/depot_tools/third_party/httplib2/socks.py +448 -0
- data/vendor/depot_tools/third_party/repo/COPYING +202 -0
- data/vendor/depot_tools/third_party/repo/README.chromium +4 -0
- data/vendor/depot_tools/third_party/repo/__init__.py +0 -0
- data/vendor/depot_tools/third_party/repo/progress.py +117 -0
- data/vendor/depot_tools/third_party/retry_decorator/LICENSE.google +30 -0
- data/vendor/depot_tools/third_party/retry_decorator/__init__.py +0 -0
- data/vendor/depot_tools/third_party/retry_decorator/decorators.py +45 -0
- data/vendor/depot_tools/third_party/schema/.editorconfig +15 -0
- data/vendor/depot_tools/third_party/schema/.gitignore +174 -0
- data/vendor/depot_tools/third_party/schema/.travis.yml +37 -0
- data/vendor/depot_tools/third_party/schema/LICENSE-MIT +19 -0
- data/vendor/depot_tools/third_party/schema/MANIFEST.in +1 -0
- data/vendor/depot_tools/third_party/schema/README.chromium +12 -0
- data/vendor/depot_tools/third_party/schema/README.rst +382 -0
- data/vendor/depot_tools/third_party/schema/__init__.py +1 -0
- data/vendor/depot_tools/third_party/schema/schema.py +338 -0
- data/vendor/depot_tools/third_party/schema/setup.cfg +5 -0
- data/vendor/depot_tools/third_party/schema/setup.py +30 -0
- data/vendor/depot_tools/third_party/schema/test_schema.py +556 -0
- data/vendor/depot_tools/third_party/schema/tox.ini +33 -0
- data/vendor/depot_tools/third_party/six/LICENSE.txt +18 -0
- data/vendor/depot_tools/third_party/six/README.chromium +10 -0
- data/vendor/depot_tools/third_party/six/__init__.py +762 -0
- data/vendor/depot_tools/update_depot_tools +138 -0
- data/vendor/depot_tools/update_depot_tools.bat +65 -0
- data/vendor/depot_tools/update_depot_tools_toggle.py +38 -0
- data/vendor/depot_tools/upload_metrics.py +26 -0
- data/vendor/depot_tools/upload_to_google_storage.py +306 -0
- data/vendor/depot_tools/vpython +42 -0
- data/vendor/depot_tools/vpython.bat +7 -0
- data/vendor/depot_tools/vpython3 +55 -0
- data/vendor/depot_tools/vpython3.bat +12 -0
- data/vendor/depot_tools/watchlists.py +141 -0
- data/vendor/depot_tools/weekly +54 -0
- data/vendor/depot_tools/win32imports.py +61 -0
- data/vendor/depot_tools/win_toolchain/OWNERS +2 -0
- data/vendor/depot_tools/win_toolchain/README.md +74 -0
- data/vendor/depot_tools/win_toolchain/get_toolchain_if_necessary.py +599 -0
- data/vendor/depot_tools/win_toolchain/package_from_installed.py +524 -0
- data/vendor/depot_tools/wtf +81 -0
- data/vendor/depot_tools/yapf +21 -0
- data/vendor/depot_tools/yapf.bat +12 -0
- data/vendor/depot_tools/zsh-goodies/README +6 -0
- data/vendor/depot_tools/zsh-goodies/_gclient +14 -0
- metadata +729 -0
@@ -0,0 +1,1655 @@
|
|
1
|
+
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
2
|
+
# Use of this source code is governed by a BSD-style license that can be
|
3
|
+
# found in the LICENSE file.
|
4
|
+
|
5
|
+
"""Generic presubmit checks that can be reused by other presubmit checks."""
|
6
|
+
|
7
|
+
from __future__ import print_function
|
8
|
+
|
9
|
+
import os as _os
|
10
|
+
_HERE = _os.path.dirname(_os.path.abspath(__file__))
|
11
|
+
|
12
|
+
# These filters will be disabled if callers do not explicitly supply a
|
13
|
+
# (possibly-empty) list. Ideally over time this list could be driven to zero.
|
14
|
+
# TODO(pkasting): If some of these look like "should never enable", move them
|
15
|
+
# to OFF_UNLESS_MANUALLY_ENABLED_LINT_FILTERS.
|
16
|
+
#
|
17
|
+
# Justifications for each filter:
|
18
|
+
#
|
19
|
+
# - build/include : Too many; fix in the future
|
20
|
+
# TODO(pkasting): Try enabling subcategories
|
21
|
+
# - build/include_order : Not happening; #ifdefed includes
|
22
|
+
# - build/namespaces : TODO(pkasting): Try re-enabling
|
23
|
+
# - readability/casting : Mistakes a whole bunch of function pointers
|
24
|
+
# - runtime/int : Can be fixed long term; volume of errors too high
|
25
|
+
# - whitespace/braces : We have a lot of explicit scoping in chrome code
|
26
|
+
OFF_BY_DEFAULT_LINT_FILTERS = [
|
27
|
+
'-build/include',
|
28
|
+
'-build/include_order',
|
29
|
+
'-build/namespaces',
|
30
|
+
'-readability/casting',
|
31
|
+
'-runtime/int',
|
32
|
+
'-whitespace/braces',
|
33
|
+
]
|
34
|
+
|
35
|
+
# These filters will be disabled unless callers explicitly enable them, because
|
36
|
+
# they are undesirable in some way.
|
37
|
+
#
|
38
|
+
# Justifications for each filter:
|
39
|
+
# - build/c++11 : Include file and feature blocklists are
|
40
|
+
# google3-specific
|
41
|
+
# - runtime/references : No longer banned by Google style guide
|
42
|
+
OFF_UNLESS_MANUALLY_ENABLED_LINT_FILTERS = [
|
43
|
+
'-build/c++11',
|
44
|
+
'-runtime/references',
|
45
|
+
]
|
46
|
+
|
47
|
+
### Description checks
|
48
|
+
|
49
|
+
def CheckChangeHasBugField(input_api, output_api):
|
50
|
+
"""Requires that the changelist have a Bug: field."""
|
51
|
+
if input_api.change.BugsFromDescription():
|
52
|
+
return []
|
53
|
+
else:
|
54
|
+
return [output_api.PresubmitNotifyResult(
|
55
|
+
'If this change has an associated bug, add Bug: [bug number].')]
|
56
|
+
|
57
|
+
def CheckChangeHasNoUnwantedTags(input_api, output_api):
|
58
|
+
UNWANTED_TAGS = {
|
59
|
+
'FIXED': {
|
60
|
+
'why': 'is not supported',
|
61
|
+
'instead': 'Use "Fixed:" instead.'
|
62
|
+
},
|
63
|
+
# TODO: BUG, ISSUE
|
64
|
+
}
|
65
|
+
|
66
|
+
errors = []
|
67
|
+
for tag, desc in UNWANTED_TAGS.items():
|
68
|
+
if tag in input_api.change.tags:
|
69
|
+
subs = tag, desc['why'], desc.get('instead', '')
|
70
|
+
errors.append(('%s= %s. %s' % subs).rstrip())
|
71
|
+
|
72
|
+
return [output_api.PresubmitError('\n'.join(errors))] if errors else []
|
73
|
+
|
74
|
+
def CheckDoNotSubmitInDescription(input_api, output_api):
|
75
|
+
"""Checks that the user didn't add 'DO NOT ''SUBMIT' to the CL description.
|
76
|
+
"""
|
77
|
+
keyword = 'DO NOT ''SUBMIT'
|
78
|
+
if keyword in input_api.change.DescriptionText():
|
79
|
+
return [output_api.PresubmitError(
|
80
|
+
keyword + ' is present in the changelist description.')]
|
81
|
+
else:
|
82
|
+
return []
|
83
|
+
|
84
|
+
|
85
|
+
def CheckChangeHasDescription(input_api, output_api):
|
86
|
+
"""Checks the CL description is not empty."""
|
87
|
+
text = input_api.change.DescriptionText()
|
88
|
+
if text.strip() == '':
|
89
|
+
if input_api.is_committing:
|
90
|
+
return [output_api.PresubmitError('Add a description to the CL.')]
|
91
|
+
else:
|
92
|
+
return [output_api.PresubmitNotifyResult('Add a description to the CL.')]
|
93
|
+
return []
|
94
|
+
|
95
|
+
|
96
|
+
def CheckChangeWasUploaded(input_api, output_api):
|
97
|
+
"""Checks that the issue was uploaded before committing."""
|
98
|
+
if input_api.is_committing and not input_api.change.issue:
|
99
|
+
return [output_api.PresubmitError(
|
100
|
+
'Issue wasn\'t uploaded. Please upload first.')]
|
101
|
+
return []
|
102
|
+
|
103
|
+
|
104
|
+
### Content checks
|
105
|
+
|
106
|
+
def CheckAuthorizedAuthor(input_api, output_api, bot_whitelist=None):
|
107
|
+
"""For non-googler/chromites committers, verify the author's email address is
|
108
|
+
in AUTHORS.
|
109
|
+
"""
|
110
|
+
if input_api.is_committing:
|
111
|
+
error_type = output_api.PresubmitError
|
112
|
+
else:
|
113
|
+
error_type = output_api.PresubmitPromptWarning
|
114
|
+
|
115
|
+
author = input_api.change.author_email
|
116
|
+
if not author:
|
117
|
+
input_api.logging.info('No author, skipping AUTHOR check')
|
118
|
+
return []
|
119
|
+
|
120
|
+
# This is used for CLs created by trusted robot accounts.
|
121
|
+
if bot_whitelist and author in bot_whitelist:
|
122
|
+
return []
|
123
|
+
|
124
|
+
authors_path = input_api.os_path.join(
|
125
|
+
input_api.PresubmitLocalPath(), 'AUTHORS')
|
126
|
+
valid_authors = (
|
127
|
+
input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
|
128
|
+
for line in open(authors_path))
|
129
|
+
valid_authors = [item.group(1).lower() for item in valid_authors if item]
|
130
|
+
if not any(input_api.fnmatch.fnmatch(author.lower(), valid)
|
131
|
+
for valid in valid_authors):
|
132
|
+
input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
|
133
|
+
return [error_type(
|
134
|
+
('%s is not in AUTHORS file. If you are a new contributor, please visit'
|
135
|
+
'\n'
|
136
|
+
'https://www.chromium.org/developers/contributing-code and read the '
|
137
|
+
'"Legal" section\n'
|
138
|
+
'If you are a chromite, verify the contributor signed the CLA.') %
|
139
|
+
author)]
|
140
|
+
return []
|
141
|
+
|
142
|
+
|
143
|
+
def CheckDoNotSubmitInFiles(input_api, output_api):
|
144
|
+
"""Checks that the user didn't add 'DO NOT ''SUBMIT' to any files."""
|
145
|
+
# We want to check every text file, not just source files.
|
146
|
+
file_filter = lambda x : x
|
147
|
+
keyword = 'DO NOT ''SUBMIT'
|
148
|
+
def DoNotSubmitRule(extension, line):
|
149
|
+
try:
|
150
|
+
return keyword not in line
|
151
|
+
# Fallback to True for non-text content
|
152
|
+
except UnicodeDecodeError:
|
153
|
+
return True
|
154
|
+
|
155
|
+
errors = _FindNewViolationsOfRule(DoNotSubmitRule, input_api, file_filter)
|
156
|
+
text = '\n'.join('Found %s in %s' % (keyword, loc) for loc in errors)
|
157
|
+
if text:
|
158
|
+
return [output_api.PresubmitError(text)]
|
159
|
+
return []
|
160
|
+
|
161
|
+
|
162
|
+
def CheckChangeLintsClean(input_api, output_api, source_file_filter=None,
|
163
|
+
lint_filters=None, verbose_level=None):
|
164
|
+
"""Checks that all '.cc' and '.h' files pass cpplint.py."""
|
165
|
+
_RE_IS_TEST = input_api.re.compile(r'.*tests?.(cc|h)$')
|
166
|
+
result = []
|
167
|
+
|
168
|
+
cpplint = input_api.cpplint
|
169
|
+
# Access to a protected member _XX of a client class
|
170
|
+
# pylint: disable=protected-access
|
171
|
+
cpplint._cpplint_state.ResetErrorCounts()
|
172
|
+
|
173
|
+
filters = OFF_UNLESS_MANUALLY_ENABLED_LINT_FILTERS[:]
|
174
|
+
if lint_filters is None:
|
175
|
+
lint_filters = OFF_BY_DEFAULT_LINT_FILTERS
|
176
|
+
filters.extend(lint_filters)
|
177
|
+
cpplint._SetFilters(','.join(filters))
|
178
|
+
|
179
|
+
# We currently are more strict with normal code than unit tests; 4 and 5 are
|
180
|
+
# the verbosity level that would normally be passed to cpplint.py through
|
181
|
+
# --verbose=#. Hopefully, in the future, we can be more verbose.
|
182
|
+
files = [f.AbsoluteLocalPath() for f in
|
183
|
+
input_api.AffectedSourceFiles(source_file_filter)]
|
184
|
+
for file_name in files:
|
185
|
+
if _RE_IS_TEST.match(file_name):
|
186
|
+
level = 5
|
187
|
+
else:
|
188
|
+
level = 4
|
189
|
+
|
190
|
+
verbose_level = verbose_level or level
|
191
|
+
cpplint.ProcessFile(file_name, verbose_level)
|
192
|
+
|
193
|
+
if cpplint._cpplint_state.error_count > 0:
|
194
|
+
if input_api.is_committing:
|
195
|
+
res_type = output_api.PresubmitError
|
196
|
+
else:
|
197
|
+
res_type = output_api.PresubmitPromptWarning
|
198
|
+
result = [res_type('Changelist failed cpplint.py check.')]
|
199
|
+
|
200
|
+
return result
|
201
|
+
|
202
|
+
|
203
|
+
def CheckChangeHasNoCR(input_api, output_api, source_file_filter=None):
|
204
|
+
"""Checks no '\r' (CR) character is in any source files."""
|
205
|
+
cr_files = []
|
206
|
+
for f in input_api.AffectedSourceFiles(source_file_filter):
|
207
|
+
if '\r' in input_api.ReadFile(f, 'rb'):
|
208
|
+
cr_files.append(f.LocalPath())
|
209
|
+
if cr_files:
|
210
|
+
return [output_api.PresubmitPromptWarning(
|
211
|
+
'Found a CR character in these files:', items=cr_files)]
|
212
|
+
return []
|
213
|
+
|
214
|
+
|
215
|
+
def CheckChangeHasOnlyOneEol(input_api, output_api, source_file_filter=None):
|
216
|
+
"""Checks the files ends with one and only one \n (LF)."""
|
217
|
+
eof_files = []
|
218
|
+
for f in input_api.AffectedSourceFiles(source_file_filter):
|
219
|
+
contents = input_api.ReadFile(f, 'rb')
|
220
|
+
# Check that the file ends in one and only one newline character.
|
221
|
+
if len(contents) > 1 and (contents[-1:] != '\n' or contents[-2:-1] == '\n'):
|
222
|
+
eof_files.append(f.LocalPath())
|
223
|
+
|
224
|
+
if eof_files:
|
225
|
+
return [output_api.PresubmitPromptWarning(
|
226
|
+
'These files should end in one (and only one) newline character:',
|
227
|
+
items=eof_files)]
|
228
|
+
return []
|
229
|
+
|
230
|
+
|
231
|
+
def CheckChangeHasNoCrAndHasOnlyOneEol(input_api, output_api,
|
232
|
+
source_file_filter=None):
|
233
|
+
"""Runs both CheckChangeHasNoCR and CheckChangeHasOnlyOneEOL in one pass.
|
234
|
+
|
235
|
+
It is faster because it is reading the file only once.
|
236
|
+
"""
|
237
|
+
cr_files = []
|
238
|
+
eof_files = []
|
239
|
+
for f in input_api.AffectedSourceFiles(source_file_filter):
|
240
|
+
contents = input_api.ReadFile(f, 'rb')
|
241
|
+
if '\r' in contents:
|
242
|
+
cr_files.append(f.LocalPath())
|
243
|
+
# Check that the file ends in one and only one newline character.
|
244
|
+
if len(contents) > 1 and (contents[-1:] != '\n' or contents[-2:-1] == '\n'):
|
245
|
+
eof_files.append(f.LocalPath())
|
246
|
+
outputs = []
|
247
|
+
if cr_files:
|
248
|
+
outputs.append(output_api.PresubmitPromptWarning(
|
249
|
+
'Found a CR character in these files:', items=cr_files))
|
250
|
+
if eof_files:
|
251
|
+
outputs.append(output_api.PresubmitPromptWarning(
|
252
|
+
'These files should end in one (and only one) newline character:',
|
253
|
+
items=eof_files))
|
254
|
+
return outputs
|
255
|
+
|
256
|
+
def CheckGenderNeutral(input_api, output_api, source_file_filter=None):
|
257
|
+
"""Checks that there are no gendered pronouns in any of the text files to be
|
258
|
+
submitted.
|
259
|
+
"""
|
260
|
+
gendered_re = input_api.re.compile(
|
261
|
+
r'(^|\s|\(|\[)([Hh]e|[Hh]is|[Hh]ers?|[Hh]im|[Ss]he|[Gg]uys?)\\b')
|
262
|
+
|
263
|
+
errors = []
|
264
|
+
for f in input_api.AffectedFiles(include_deletes=False,
|
265
|
+
file_filter=source_file_filter):
|
266
|
+
for line_num, line in f.ChangedContents():
|
267
|
+
if gendered_re.search(line):
|
268
|
+
errors.append('%s (%d): %s' % (f.LocalPath(), line_num, line))
|
269
|
+
|
270
|
+
if len(errors):
|
271
|
+
return [output_api.PresubmitPromptWarning('Found a gendered pronoun in:',
|
272
|
+
long_text='\n'.join(errors))]
|
273
|
+
return []
|
274
|
+
|
275
|
+
|
276
|
+
|
277
|
+
def _ReportErrorFileAndLine(filename, line_num, dummy_line):
|
278
|
+
"""Default error formatter for _FindNewViolationsOfRule."""
|
279
|
+
return '%s:%s' % (filename, line_num)
|
280
|
+
|
281
|
+
|
282
|
+
def _GenerateAffectedFileExtList(input_api, source_file_filter):
|
283
|
+
"""Generate a list of (file, extension) tuples from affected files.
|
284
|
+
|
285
|
+
The result can be fed to _FindNewViolationsOfRule() directly, or
|
286
|
+
could be filtered before doing that.
|
287
|
+
|
288
|
+
Args:
|
289
|
+
input_api: object to enumerate the affected files.
|
290
|
+
source_file_filter: a filter to be passed to the input api.
|
291
|
+
Yields:
|
292
|
+
A list of (file, extension) tuples, where |file| is an affected
|
293
|
+
file, and |extension| its file path extension.
|
294
|
+
"""
|
295
|
+
for f in input_api.AffectedFiles(
|
296
|
+
include_deletes=False, file_filter=source_file_filter):
|
297
|
+
extension = str(f.LocalPath()).rsplit('.', 1)[-1]
|
298
|
+
yield (f, extension)
|
299
|
+
|
300
|
+
|
301
|
+
def _FindNewViolationsOfRuleForList(callable_rule,
|
302
|
+
file_ext_list,
|
303
|
+
error_formatter=_ReportErrorFileAndLine):
|
304
|
+
"""Find all newly introduced violations of a per-line rule (a callable).
|
305
|
+
|
306
|
+
Prefer calling _FindNewViolationsOfRule() instead of this function, unless
|
307
|
+
the list of affected files need to be filtered in a special way.
|
308
|
+
|
309
|
+
Arguments:
|
310
|
+
callable_rule: a callable taking a file extension and line of input and
|
311
|
+
returning True if the rule is satisfied and False if there was a problem.
|
312
|
+
file_ext_list: a list of input (file, extension) tuples, as returned by
|
313
|
+
_GenerateAffectedFileExtList().
|
314
|
+
error_formatter: a callable taking (filename, line_number, line) and
|
315
|
+
returning a formatted error string.
|
316
|
+
|
317
|
+
Returns:
|
318
|
+
A list of the newly-introduced violations reported by the rule.
|
319
|
+
"""
|
320
|
+
errors = []
|
321
|
+
for f, extension in file_ext_list:
|
322
|
+
# For speed, we do two passes, checking first the full file. Shelling out
|
323
|
+
# to the SCM to determine the changed region can be quite expensive on
|
324
|
+
# Win32. Assuming that most files will be kept problem-free, we can
|
325
|
+
# skip the SCM operations most of the time.
|
326
|
+
if all(callable_rule(extension, line) for line in f.NewContents()):
|
327
|
+
continue # No violation found in full text: can skip considering diff.
|
328
|
+
|
329
|
+
for line_num, line in f.ChangedContents():
|
330
|
+
if not callable_rule(extension, line):
|
331
|
+
errors.append(error_formatter(f.LocalPath(), line_num, line))
|
332
|
+
|
333
|
+
return errors
|
334
|
+
|
335
|
+
|
336
|
+
def _FindNewViolationsOfRule(callable_rule,
|
337
|
+
input_api,
|
338
|
+
source_file_filter=None,
|
339
|
+
error_formatter=_ReportErrorFileAndLine):
|
340
|
+
"""Find all newly introduced violations of a per-line rule (a callable).
|
341
|
+
|
342
|
+
Arguments:
|
343
|
+
callable_rule: a callable taking a file extension and line of input and
|
344
|
+
returning True if the rule is satisfied and False if there was a problem.
|
345
|
+
input_api: object to enumerate the affected files.
|
346
|
+
source_file_filter: a filter to be passed to the input api.
|
347
|
+
error_formatter: a callable taking (filename, line_number, line) and
|
348
|
+
returning a formatted error string.
|
349
|
+
|
350
|
+
Returns:
|
351
|
+
A list of the newly-introduced violations reported by the rule.
|
352
|
+
"""
|
353
|
+
return _FindNewViolationsOfRuleForList(
|
354
|
+
callable_rule, _GenerateAffectedFileExtList(
|
355
|
+
input_api, source_file_filter), error_formatter)
|
356
|
+
|
357
|
+
|
358
|
+
def CheckChangeHasNoTabs(input_api, output_api, source_file_filter=None):
|
359
|
+
"""Checks that there are no tab characters in any of the text files to be
|
360
|
+
submitted.
|
361
|
+
"""
|
362
|
+
# In addition to the filter, make sure that makefiles are skipped.
|
363
|
+
if not source_file_filter:
|
364
|
+
# It's the default filter.
|
365
|
+
source_file_filter = input_api.FilterSourceFile
|
366
|
+
def filter_more(affected_file):
|
367
|
+
basename = input_api.os_path.basename(affected_file.LocalPath())
|
368
|
+
return (not (basename in ('Makefile', 'makefile') or
|
369
|
+
basename.endswith('.mk')) and
|
370
|
+
source_file_filter(affected_file))
|
371
|
+
|
372
|
+
tabs = _FindNewViolationsOfRule(lambda _, line : '\t' not in line,
|
373
|
+
input_api, filter_more)
|
374
|
+
|
375
|
+
if tabs:
|
376
|
+
return [output_api.PresubmitPromptWarning('Found a tab character in:',
|
377
|
+
long_text='\n'.join(tabs))]
|
378
|
+
return []
|
379
|
+
|
380
|
+
|
381
|
+
def CheckChangeTodoHasOwner(input_api, output_api, source_file_filter=None):
|
382
|
+
"""Checks that the user didn't add TODO(name) without an owner."""
|
383
|
+
|
384
|
+
unowned_todo = input_api.re.compile('TO''DO[^(]')
|
385
|
+
errors = _FindNewViolationsOfRule(lambda _, x : not unowned_todo.search(x),
|
386
|
+
input_api, source_file_filter)
|
387
|
+
errors = ['Found TO''DO with no owner in ' + x for x in errors]
|
388
|
+
if errors:
|
389
|
+
return [output_api.PresubmitPromptWarning('\n'.join(errors))]
|
390
|
+
return []
|
391
|
+
|
392
|
+
|
393
|
+
def CheckChangeHasNoStrayWhitespace(input_api, output_api,
|
394
|
+
source_file_filter=None):
|
395
|
+
"""Checks that there is no stray whitespace at source lines end."""
|
396
|
+
errors = _FindNewViolationsOfRule(lambda _, line : line.rstrip() == line,
|
397
|
+
input_api, source_file_filter)
|
398
|
+
if errors:
|
399
|
+
return [output_api.PresubmitPromptWarning(
|
400
|
+
'Found line ending with white spaces in:',
|
401
|
+
long_text='\n'.join(errors))]
|
402
|
+
return []
|
403
|
+
|
404
|
+
|
405
|
+
def CheckLongLines(input_api, output_api, maxlen, source_file_filter=None):
|
406
|
+
"""Checks that there aren't any lines longer than maxlen characters in any of
|
407
|
+
the text files to be submitted.
|
408
|
+
"""
|
409
|
+
maxlens = {
|
410
|
+
'java': 100,
|
411
|
+
# This is specifically for Android's handwritten makefiles (Android.mk).
|
412
|
+
'mk': 200,
|
413
|
+
'': maxlen,
|
414
|
+
}
|
415
|
+
|
416
|
+
# Language specific exceptions to max line length.
|
417
|
+
# '.h' is considered an obj-c file extension, since OBJC_EXCEPTIONS are a
|
418
|
+
# superset of CPP_EXCEPTIONS.
|
419
|
+
CPP_FILE_EXTS = ('c', 'cc')
|
420
|
+
CPP_EXCEPTIONS = ('#define', '#endif', '#if', '#include', '#pragma')
|
421
|
+
HTML_FILE_EXTS = ('html',)
|
422
|
+
HTML_EXCEPTIONS = ('<g ', '<link ', '<path ',)
|
423
|
+
JAVA_FILE_EXTS = ('java',)
|
424
|
+
JAVA_EXCEPTIONS = ('import ', 'package ')
|
425
|
+
JS_FILE_EXTS = ('js',)
|
426
|
+
JS_EXCEPTIONS = ("GEN('#include", 'import ')
|
427
|
+
TS_FILE_EXTS = ('ts',)
|
428
|
+
TS_EXCEPTIONS = ('import ')
|
429
|
+
OBJC_FILE_EXTS = ('h', 'm', 'mm')
|
430
|
+
OBJC_EXCEPTIONS = ('#define', '#endif', '#if', '#import', '#include',
|
431
|
+
'#pragma')
|
432
|
+
PY_FILE_EXTS = ('py',)
|
433
|
+
PY_EXCEPTIONS = ('import', 'from')
|
434
|
+
|
435
|
+
LANGUAGE_EXCEPTIONS = [
|
436
|
+
(CPP_FILE_EXTS, CPP_EXCEPTIONS),
|
437
|
+
(HTML_FILE_EXTS, HTML_EXCEPTIONS),
|
438
|
+
(JAVA_FILE_EXTS, JAVA_EXCEPTIONS),
|
439
|
+
(JS_FILE_EXTS, JS_EXCEPTIONS),
|
440
|
+
(TS_FILE_EXTS, TS_EXCEPTIONS),
|
441
|
+
(OBJC_FILE_EXTS, OBJC_EXCEPTIONS),
|
442
|
+
(PY_FILE_EXTS, PY_EXCEPTIONS),
|
443
|
+
]
|
444
|
+
|
445
|
+
def no_long_lines(file_extension, line):
|
446
|
+
# Check for language specific exceptions.
|
447
|
+
if any(file_extension in exts and line.lstrip().startswith(exceptions)
|
448
|
+
for exts, exceptions in LANGUAGE_EXCEPTIONS):
|
449
|
+
return True
|
450
|
+
|
451
|
+
file_maxlen = maxlens.get(file_extension, maxlens[''])
|
452
|
+
# Stupidly long symbols that needs to be worked around if takes 66% of line.
|
453
|
+
long_symbol = file_maxlen * 2 / 3
|
454
|
+
# Hard line length limit at 50% more.
|
455
|
+
extra_maxlen = file_maxlen * 3 / 2
|
456
|
+
|
457
|
+
line_len = len(line)
|
458
|
+
if line_len <= file_maxlen:
|
459
|
+
return True
|
460
|
+
|
461
|
+
# Allow long URLs of any length.
|
462
|
+
if any((url in line) for url in ('file://', 'http://', 'https://')):
|
463
|
+
return True
|
464
|
+
|
465
|
+
if line_len > extra_maxlen:
|
466
|
+
return False
|
467
|
+
|
468
|
+
if 'url(' in line and file_extension == 'css':
|
469
|
+
return True
|
470
|
+
|
471
|
+
if '<include' in line and file_extension in ('css', 'html', 'js'):
|
472
|
+
return True
|
473
|
+
|
474
|
+
return input_api.re.match(
|
475
|
+
r'.*[A-Za-z][A-Za-z_0-9]{%d,}.*' % long_symbol, line)
|
476
|
+
|
477
|
+
def is_global_pylint_directive(line, pos):
|
478
|
+
"""True iff the pylint directive starting at line[pos] is global."""
|
479
|
+
# Any character before |pos| that is not whitespace or '#' indidcates
|
480
|
+
# this is a local directive.
|
481
|
+
return not any([c not in " \t#" for c in line[:pos]])
|
482
|
+
|
483
|
+
def check_python_long_lines(affected_files, error_formatter):
|
484
|
+
errors = []
|
485
|
+
global_check_enabled = True
|
486
|
+
|
487
|
+
for f in affected_files:
|
488
|
+
file_path = f.LocalPath()
|
489
|
+
for idx, line in enumerate(f.NewContents()):
|
490
|
+
line_num = idx + 1
|
491
|
+
line_is_short = no_long_lines(PY_FILE_EXTS[0], line)
|
492
|
+
|
493
|
+
pos = line.find('pylint: disable=line-too-long')
|
494
|
+
if pos >= 0:
|
495
|
+
if is_global_pylint_directive(line, pos):
|
496
|
+
global_check_enabled = False # Global disable
|
497
|
+
else:
|
498
|
+
continue # Local disable.
|
499
|
+
|
500
|
+
do_check = global_check_enabled
|
501
|
+
|
502
|
+
pos = line.find('pylint: enable=line-too-long')
|
503
|
+
if pos >= 0:
|
504
|
+
if is_global_pylint_directive(line, pos):
|
505
|
+
global_check_enabled = True # Global enable
|
506
|
+
do_check = True # Ensure it applies to current line as well.
|
507
|
+
else:
|
508
|
+
do_check = True # Local enable
|
509
|
+
|
510
|
+
if do_check and not line_is_short:
|
511
|
+
errors.append(error_formatter(file_path, line_num, line))
|
512
|
+
|
513
|
+
return errors
|
514
|
+
|
515
|
+
def format_error(filename, line_num, line):
|
516
|
+
return '%s, line %s, %s chars' % (filename, line_num, len(line))
|
517
|
+
|
518
|
+
file_ext_list = list(
|
519
|
+
_GenerateAffectedFileExtList(input_api, source_file_filter))
|
520
|
+
|
521
|
+
errors = []
|
522
|
+
|
523
|
+
# For non-Python files, a simple line-based rule check is enough.
|
524
|
+
non_py_file_ext_list = [x for x in file_ext_list if x[1] not in PY_FILE_EXTS]
|
525
|
+
if non_py_file_ext_list:
|
526
|
+
errors += _FindNewViolationsOfRuleForList(
|
527
|
+
no_long_lines, non_py_file_ext_list, error_formatter=format_error)
|
528
|
+
|
529
|
+
# However, Python files need more sophisticated checks that need parsing
|
530
|
+
# the whole source file.
|
531
|
+
py_file_list = [x[0] for x in file_ext_list if x[1] in PY_FILE_EXTS]
|
532
|
+
if py_file_list:
|
533
|
+
errors += check_python_long_lines(
|
534
|
+
py_file_list, error_formatter=format_error)
|
535
|
+
if errors:
|
536
|
+
msg = 'Found lines longer than %s characters (first 5 shown).' % maxlen
|
537
|
+
return [output_api.PresubmitPromptWarning(msg, items=errors[:5])]
|
538
|
+
else:
|
539
|
+
return []
|
540
|
+
|
541
|
+
|
542
|
+
def CheckLicense(input_api, output_api, license_re, source_file_filter=None,
|
543
|
+
accept_empty_files=True):
|
544
|
+
"""Verifies the license header.
|
545
|
+
"""
|
546
|
+
license_re = input_api.re.compile(license_re, input_api.re.MULTILINE)
|
547
|
+
bad_files = []
|
548
|
+
for f in input_api.AffectedSourceFiles(source_file_filter):
|
549
|
+
contents = input_api.ReadFile(f, 'rb')
|
550
|
+
if accept_empty_files and not contents:
|
551
|
+
continue
|
552
|
+
if not license_re.search(contents):
|
553
|
+
bad_files.append(f.LocalPath())
|
554
|
+
if bad_files:
|
555
|
+
return [output_api.PresubmitPromptWarning(
|
556
|
+
'License must match:\n%s\n' % license_re.pattern +
|
557
|
+
'Found a bad license header in these files:', items=bad_files)]
|
558
|
+
return []
|
559
|
+
|
560
|
+
|
561
|
+
### Other checks
|
562
|
+
|
563
|
+
def CheckDoNotSubmit(input_api, output_api):
|
564
|
+
return (
|
565
|
+
CheckDoNotSubmitInDescription(input_api, output_api) +
|
566
|
+
CheckDoNotSubmitInFiles(input_api, output_api)
|
567
|
+
)
|
568
|
+
|
569
|
+
|
570
|
+
def CheckTreeIsOpen(input_api, output_api,
|
571
|
+
url=None, closed=None, json_url=None):
|
572
|
+
"""Check whether to allow commit without prompt.
|
573
|
+
|
574
|
+
Supports two styles:
|
575
|
+
1. Checks that an url's content doesn't match a regexp that would mean that
|
576
|
+
the tree is closed. (old)
|
577
|
+
2. Check the json_url to decide whether to allow commit without prompt.
|
578
|
+
Args:
|
579
|
+
input_api: input related apis.
|
580
|
+
output_api: output related apis.
|
581
|
+
url: url to use for regex based tree status.
|
582
|
+
closed: regex to match for closed status.
|
583
|
+
json_url: url to download json style status.
|
584
|
+
"""
|
585
|
+
if not input_api.is_committing:
|
586
|
+
return []
|
587
|
+
try:
|
588
|
+
if json_url:
|
589
|
+
connection = input_api.urllib_request.urlopen(json_url)
|
590
|
+
status = input_api.json.loads(connection.read())
|
591
|
+
connection.close()
|
592
|
+
if not status['can_commit_freely']:
|
593
|
+
short_text = 'Tree state is: ' + status['general_state']
|
594
|
+
long_text = status['message'] + '\n' + json_url
|
595
|
+
return [output_api.PresubmitError(short_text, long_text=long_text)]
|
596
|
+
else:
|
597
|
+
# TODO(bradnelson): drop this once all users are gone.
|
598
|
+
connection = input_api.urllib_request.urlopen(url)
|
599
|
+
status = connection.read()
|
600
|
+
connection.close()
|
601
|
+
if input_api.re.match(closed, status):
|
602
|
+
long_text = status + '\n' + url
|
603
|
+
return [output_api.PresubmitError('The tree is closed.',
|
604
|
+
long_text=long_text)]
|
605
|
+
except IOError as e:
|
606
|
+
return [output_api.PresubmitError('Error fetching tree status.',
|
607
|
+
long_text=str(e))]
|
608
|
+
return []
|
609
|
+
|
610
|
+
def GetUnitTestsInDirectory(
|
611
|
+
input_api, output_api, directory, files_to_check=None, files_to_skip=None,
|
612
|
+
env=None, run_on_python2=True, run_on_python3=True, whitelist=None,
|
613
|
+
blacklist=None, allowlist=None, blocklist=None):
|
614
|
+
"""Lists all files in a directory and runs them. Doesn't recurse.
|
615
|
+
|
616
|
+
It's mainly a wrapper for RunUnitTests. Use allowlist and blocklist to filter
|
617
|
+
tests accordingly.
|
618
|
+
"""
|
619
|
+
# TODO(https://crbug.com/1098560): Add warnings before removing bc.
|
620
|
+
files_to_check = files_to_check or allowlist or whitelist
|
621
|
+
files_to_skip = files_to_skip or blocklist or blacklist
|
622
|
+
unit_tests = []
|
623
|
+
test_path = input_api.os_path.abspath(
|
624
|
+
input_api.os_path.join(input_api.PresubmitLocalPath(), directory))
|
625
|
+
|
626
|
+
def check(filename, filters):
|
627
|
+
return any(True for i in filters if input_api.re.match(i, filename))
|
628
|
+
|
629
|
+
to_run = found = 0
|
630
|
+
for filename in input_api.os_listdir(test_path):
|
631
|
+
found += 1
|
632
|
+
fullpath = input_api.os_path.join(test_path, filename)
|
633
|
+
if not input_api.os_path.isfile(fullpath):
|
634
|
+
continue
|
635
|
+
if files_to_check and not check(filename, files_to_check):
|
636
|
+
continue
|
637
|
+
if files_to_skip and check(filename, files_to_skip):
|
638
|
+
continue
|
639
|
+
unit_tests.append(input_api.os_path.join(directory, filename))
|
640
|
+
to_run += 1
|
641
|
+
input_api.logging.debug('Found %d files, running %d unit tests'
|
642
|
+
% (found, to_run))
|
643
|
+
if not to_run:
|
644
|
+
return [
|
645
|
+
output_api.PresubmitPromptWarning(
|
646
|
+
'Out of %d files, found none that matched c=%r, s=%r in directory %s'
|
647
|
+
% (found, files_to_check, files_to_skip, directory))
|
648
|
+
]
|
649
|
+
return GetUnitTests(
|
650
|
+
input_api, output_api, unit_tests, env, run_on_python2, run_on_python3)
|
651
|
+
|
652
|
+
|
653
|
+
def GetUnitTests(
|
654
|
+
input_api, output_api, unit_tests, env=None, run_on_python2=True,
|
655
|
+
run_on_python3=True):
|
656
|
+
"""Runs all unit tests in a directory.
|
657
|
+
|
658
|
+
On Windows, sys.executable is used for unit tests ending with ".py".
|
659
|
+
"""
|
660
|
+
assert run_on_python3 or run_on_python2, (
|
661
|
+
'At least one of "run_on_python2" or "run_on_python3" must be set.')
|
662
|
+
def has_py3_shebang(test):
|
663
|
+
with open(test) as f:
|
664
|
+
maybe_shebang = f.readline()
|
665
|
+
return maybe_shebang.startswith('#!') and 'python3' in maybe_shebang
|
666
|
+
|
667
|
+
# We don't want to hinder users from uploading incomplete patches.
|
668
|
+
if input_api.is_committing:
|
669
|
+
message_type = output_api.PresubmitError
|
670
|
+
else:
|
671
|
+
message_type = output_api.PresubmitPromptWarning
|
672
|
+
|
673
|
+
results = []
|
674
|
+
for unit_test in unit_tests:
|
675
|
+
cmd = [unit_test]
|
676
|
+
if input_api.verbose:
|
677
|
+
cmd.append('--verbose')
|
678
|
+
kwargs = {'cwd': input_api.PresubmitLocalPath()}
|
679
|
+
if env:
|
680
|
+
kwargs['env'] = env
|
681
|
+
if not unit_test.endswith('.py'):
|
682
|
+
results.append(input_api.Command(
|
683
|
+
name=unit_test,
|
684
|
+
cmd=cmd,
|
685
|
+
kwargs=kwargs,
|
686
|
+
message=message_type))
|
687
|
+
else:
|
688
|
+
if has_py3_shebang(unit_test) and run_on_python3:
|
689
|
+
results.append(input_api.Command(
|
690
|
+
name=unit_test,
|
691
|
+
cmd=cmd,
|
692
|
+
kwargs=kwargs,
|
693
|
+
message=message_type,
|
694
|
+
python3=True))
|
695
|
+
if run_on_python2:
|
696
|
+
results.append(input_api.Command(
|
697
|
+
name=unit_test,
|
698
|
+
cmd=cmd,
|
699
|
+
kwargs=kwargs,
|
700
|
+
message=message_type))
|
701
|
+
return results
|
702
|
+
|
703
|
+
|
704
|
+
def GetUnitTestsRecursively(input_api, output_api, directory,
|
705
|
+
files_to_check=None, files_to_skip=None,
|
706
|
+
run_on_python2=True, run_on_python3=True,
|
707
|
+
whitelist=None, blacklist=None, allowlist=None,
|
708
|
+
blocklist=None):
|
709
|
+
"""Gets all files in the directory tree (git repo) that match the whitelist.
|
710
|
+
|
711
|
+
Restricts itself to only find files within the Change's source repo, not
|
712
|
+
dependencies.
|
713
|
+
"""
|
714
|
+
files_to_check = files_to_check or allowlist or whitelist
|
715
|
+
files_to_skip = files_to_skip or blocklist or blacklist
|
716
|
+
assert files_to_check is not None
|
717
|
+
assert files_to_skip is not None
|
718
|
+
|
719
|
+
def check(filename):
|
720
|
+
return (any(input_api.re.match(f, filename) for f in files_to_check) and
|
721
|
+
not any(input_api.re.match(f, filename) for f in files_to_skip))
|
722
|
+
|
723
|
+
tests = []
|
724
|
+
|
725
|
+
to_run = found = 0
|
726
|
+
for filepath in input_api.change.AllFiles(directory):
|
727
|
+
found += 1
|
728
|
+
if check(filepath):
|
729
|
+
to_run += 1
|
730
|
+
tests.append(filepath)
|
731
|
+
input_api.logging.debug('Found %d files, running %d' % (found, to_run))
|
732
|
+
if not to_run:
|
733
|
+
return [
|
734
|
+
output_api.PresubmitPromptWarning(
|
735
|
+
'Out of %d files, found none that matched c=%r, s=%r in directory %s'
|
736
|
+
% (found, files_to_check, files_to_skip, directory))
|
737
|
+
]
|
738
|
+
|
739
|
+
return GetUnitTests(input_api, output_api, tests,
|
740
|
+
run_on_python2=run_on_python2,
|
741
|
+
run_on_python3=run_on_python3)
|
742
|
+
|
743
|
+
|
744
|
+
def GetPythonUnitTests(input_api, output_api, unit_tests):
|
745
|
+
"""Run the unit tests out of process, capture the output and use the result
|
746
|
+
code to determine success.
|
747
|
+
|
748
|
+
DEPRECATED.
|
749
|
+
"""
|
750
|
+
# We don't want to hinder users from uploading incomplete patches.
|
751
|
+
if input_api.is_committing:
|
752
|
+
message_type = output_api.PresubmitError
|
753
|
+
else:
|
754
|
+
message_type = output_api.PresubmitNotifyResult
|
755
|
+
results = []
|
756
|
+
for unit_test in unit_tests:
|
757
|
+
# Run the unit tests out of process. This is because some unit tests
|
758
|
+
# stub out base libraries and don't clean up their mess. It's too easy to
|
759
|
+
# get subtle bugs.
|
760
|
+
cwd = None
|
761
|
+
env = None
|
762
|
+
unit_test_name = unit_test
|
763
|
+
# 'python -m test.unit_test' doesn't work. We need to change to the right
|
764
|
+
# directory instead.
|
765
|
+
if '.' in unit_test:
|
766
|
+
# Tests imported in submodules (subdirectories) assume that the current
|
767
|
+
# directory is in the PYTHONPATH. Manually fix that.
|
768
|
+
unit_test = unit_test.replace('.', '/')
|
769
|
+
cwd = input_api.os_path.dirname(unit_test)
|
770
|
+
unit_test = input_api.os_path.basename(unit_test)
|
771
|
+
env = input_api.environ.copy()
|
772
|
+
# At least on Windows, it seems '.' must explicitly be in PYTHONPATH
|
773
|
+
backpath = [
|
774
|
+
'.', input_api.os_path.pathsep.join(['..'] * (cwd.count('/') + 1))
|
775
|
+
]
|
776
|
+
# We convert to str, since on Windows on Python 2 only strings are allowed
|
777
|
+
# as environment variables, but literals are unicode since we're importing
|
778
|
+
# unicode_literals from __future__.
|
779
|
+
if env.get('PYTHONPATH'):
|
780
|
+
backpath.append(env.get('PYTHONPATH'))
|
781
|
+
env['PYTHONPATH'] = input_api.os_path.pathsep.join((backpath))
|
782
|
+
env.pop('VPYTHON_CLEAR_PYTHONPATH', None)
|
783
|
+
cmd = [input_api.python_executable, '-m', '%s' % unit_test]
|
784
|
+
results.append(input_api.Command(
|
785
|
+
name=unit_test_name,
|
786
|
+
cmd=cmd,
|
787
|
+
kwargs={'env': env, 'cwd': cwd},
|
788
|
+
message=message_type))
|
789
|
+
return results
|
790
|
+
|
791
|
+
|
792
|
+
def RunUnitTestsInDirectory(input_api, *args, **kwargs):
|
793
|
+
"""Run tests in a directory serially.
|
794
|
+
|
795
|
+
For better performance, use GetUnitTestsInDirectory and then
|
796
|
+
pass to input_api.RunTests.
|
797
|
+
"""
|
798
|
+
return input_api.RunTests(
|
799
|
+
GetUnitTestsInDirectory(input_api, *args, **kwargs), False)
|
800
|
+
|
801
|
+
|
802
|
+
def RunUnitTests(input_api, *args, **kwargs):
|
803
|
+
"""Run tests serially.
|
804
|
+
|
805
|
+
For better performance, use GetUnitTests and then pass to
|
806
|
+
input_api.RunTests.
|
807
|
+
"""
|
808
|
+
return input_api.RunTests(GetUnitTests(input_api, *args, **kwargs), False)
|
809
|
+
|
810
|
+
|
811
|
+
def RunPythonUnitTests(input_api, *args, **kwargs):
|
812
|
+
"""Run python tests in a directory serially.
|
813
|
+
|
814
|
+
DEPRECATED
|
815
|
+
"""
|
816
|
+
return input_api.RunTests(
|
817
|
+
GetPythonUnitTests(input_api, *args, **kwargs), False)
|
818
|
+
|
819
|
+
|
820
|
+
def _FetchAllFiles(input_api, files_to_check, files_to_skip):
|
821
|
+
"""Hack to fetch all files."""
|
822
|
+
# We cannot use AffectedFiles here because we want to test every python
|
823
|
+
# file on each single python change. It's because a change in a python file
|
824
|
+
# can break another unmodified file.
|
825
|
+
# Use code similar to InputApi.FilterSourceFile()
|
826
|
+
def Find(filepath, filters):
|
827
|
+
if input_api.platform == 'win32':
|
828
|
+
filepath = filepath.replace('\\', '/')
|
829
|
+
|
830
|
+
for item in filters:
|
831
|
+
if input_api.re.match(item, filepath):
|
832
|
+
return True
|
833
|
+
return False
|
834
|
+
|
835
|
+
files = []
|
836
|
+
path_len = len(input_api.PresubmitLocalPath())
|
837
|
+
for dirpath, dirnames, filenames in input_api.os_walk(
|
838
|
+
input_api.PresubmitLocalPath()):
|
839
|
+
# Passes dirnames in block list to speed up search.
|
840
|
+
for item in dirnames[:]:
|
841
|
+
filepath = input_api.os_path.join(dirpath, item)[path_len + 1:]
|
842
|
+
if Find(filepath, files_to_skip):
|
843
|
+
dirnames.remove(item)
|
844
|
+
for item in filenames:
|
845
|
+
filepath = input_api.os_path.join(dirpath, item)[path_len + 1:]
|
846
|
+
if Find(filepath, files_to_check) and not Find(filepath, files_to_skip):
|
847
|
+
files.append(filepath)
|
848
|
+
return files
|
849
|
+
|
850
|
+
|
851
|
+
def GetPylint(input_api, output_api, files_to_check=None, files_to_skip=None,
|
852
|
+
disabled_warnings=None, extra_paths_list=None, pylintrc=None,
|
853
|
+
white_list=None, black_list=None, allow_list=None,
|
854
|
+
block_list=None):
|
855
|
+
"""Run pylint on python files.
|
856
|
+
|
857
|
+
The default files_to_check enforces looking only at *.py files.
|
858
|
+
"""
|
859
|
+
files_to_check = tuple(files_to_check or allow_list or white_list or
|
860
|
+
(r'.*\.py$',))
|
861
|
+
files_to_skip = tuple(files_to_skip or block_list or black_list or
|
862
|
+
input_api.DEFAULT_FILES_TO_SKIP)
|
863
|
+
extra_paths_list = extra_paths_list or []
|
864
|
+
|
865
|
+
if input_api.is_committing:
|
866
|
+
error_type = output_api.PresubmitError
|
867
|
+
else:
|
868
|
+
error_type = output_api.PresubmitPromptWarning
|
869
|
+
|
870
|
+
# Only trigger if there is at least one python file affected.
|
871
|
+
def rel_path(regex):
|
872
|
+
"""Modifies a regex for a subject to accept paths relative to root."""
|
873
|
+
def samefile(a, b):
|
874
|
+
# Default implementation for platforms lacking os.path.samefile
|
875
|
+
# (like Windows).
|
876
|
+
return input_api.os_path.abspath(a) == input_api.os_path.abspath(b)
|
877
|
+
samefile = getattr(input_api.os_path, 'samefile', samefile)
|
878
|
+
if samefile(input_api.PresubmitLocalPath(),
|
879
|
+
input_api.change.RepositoryRoot()):
|
880
|
+
return regex
|
881
|
+
|
882
|
+
prefix = input_api.os_path.join(input_api.os_path.relpath(
|
883
|
+
input_api.PresubmitLocalPath(), input_api.change.RepositoryRoot()), '')
|
884
|
+
return input_api.re.escape(prefix) + regex
|
885
|
+
src_filter = lambda x: input_api.FilterSourceFile(
|
886
|
+
x, map(rel_path, files_to_check), map(rel_path, files_to_skip))
|
887
|
+
if not input_api.AffectedSourceFiles(src_filter):
|
888
|
+
input_api.logging.info('Skipping pylint: no matching changes.')
|
889
|
+
return []
|
890
|
+
|
891
|
+
if pylintrc is not None:
|
892
|
+
pylintrc = input_api.os_path.join(input_api.PresubmitLocalPath(), pylintrc)
|
893
|
+
else:
|
894
|
+
pylintrc = input_api.os_path.join(_HERE, 'pylintrc')
|
895
|
+
extra_args = ['--rcfile=%s' % pylintrc]
|
896
|
+
if disabled_warnings:
|
897
|
+
extra_args.extend(['-d', ','.join(disabled_warnings)])
|
898
|
+
|
899
|
+
files = _FetchAllFiles(input_api, files_to_check, files_to_skip)
|
900
|
+
if not files:
|
901
|
+
return []
|
902
|
+
files.sort()
|
903
|
+
|
904
|
+
input_api.logging.info('Running pylint on %d files', len(files))
|
905
|
+
input_api.logging.debug('Running pylint on: %s', files)
|
906
|
+
env = input_api.environ.copy()
|
907
|
+
env['PYTHONPATH'] = input_api.os_path.pathsep.join(extra_paths_list)
|
908
|
+
env.pop('VPYTHON_CLEAR_PYTHONPATH', None)
|
909
|
+
input_api.logging.debug(' with extra PYTHONPATH: %r', extra_paths_list)
|
910
|
+
|
911
|
+
def GetPylintCmd(flist, extra, parallel):
|
912
|
+
# Windows needs help running python files so we explicitly specify
|
913
|
+
# the interpreter to use. It also has limitations on the size of
|
914
|
+
# the command-line, so we pass arguments via a pipe.
|
915
|
+
tool = input_api.os_path.join(_HERE, 'pylint')
|
916
|
+
kwargs = {'env': env}
|
917
|
+
if input_api.platform == 'win32':
|
918
|
+
# On Windows, scripts on the current directory take precedence over PATH.
|
919
|
+
# When `pylint.bat` calls `vpython`, it will execute the `vpython` of the
|
920
|
+
# depot_tools under test instead of the one in the bot.
|
921
|
+
# As a workaround, we run the tests from the parent directory instead.
|
922
|
+
cwd = input_api.change.RepositoryRoot()
|
923
|
+
if input_api.os_path.basename(cwd) == 'depot_tools':
|
924
|
+
kwargs['cwd'] = input_api.os_path.dirname(cwd)
|
925
|
+
flist = [input_api.os_path.join('depot_tools', f) for f in flist]
|
926
|
+
tool += '.bat'
|
927
|
+
|
928
|
+
cmd = [tool, '--args-on-stdin']
|
929
|
+
if len(flist) == 1:
|
930
|
+
description = flist[0]
|
931
|
+
else:
|
932
|
+
description = '%s files' % len(flist)
|
933
|
+
|
934
|
+
args = extra_args[:]
|
935
|
+
if extra:
|
936
|
+
args.extend(extra)
|
937
|
+
description += ' using %s' % (extra,)
|
938
|
+
if parallel:
|
939
|
+
args.append('--jobs=%s' % input_api.cpu_count)
|
940
|
+
description += ' on %d cores' % input_api.cpu_count
|
941
|
+
|
942
|
+
kwargs['stdin'] = '\n'.join(args + flist)
|
943
|
+
|
944
|
+
return input_api.Command(
|
945
|
+
name='Pylint (%s)' % description,
|
946
|
+
cmd=cmd,
|
947
|
+
kwargs=kwargs,
|
948
|
+
message=error_type)
|
949
|
+
|
950
|
+
# Always run pylint and pass it all the py files at once.
|
951
|
+
# Passing py files one at time is slower and can produce
|
952
|
+
# different results. input_api.verbose used to be used
|
953
|
+
# to enable this behaviour but differing behaviour in
|
954
|
+
# verbose mode is not desirable.
|
955
|
+
# Leave this unreachable code in here so users can make
|
956
|
+
# a quick local edit to diagnose pylint issues more
|
957
|
+
# easily.
|
958
|
+
if True:
|
959
|
+
# pylint's cycle detection doesn't work in parallel, so spawn a second,
|
960
|
+
# single-threaded job for just that check.
|
961
|
+
|
962
|
+
# Some PRESUBMITs explicitly mention cycle detection.
|
963
|
+
if not any('R0401' in a or 'cyclic-import' in a for a in extra_args):
|
964
|
+
return [
|
965
|
+
GetPylintCmd(files, ["--disable=cyclic-import"], True),
|
966
|
+
GetPylintCmd(files, ["--disable=all", "--enable=cyclic-import"], False)
|
967
|
+
]
|
968
|
+
else:
|
969
|
+
return [ GetPylintCmd(files, [], True) ]
|
970
|
+
|
971
|
+
else:
|
972
|
+
return map(lambda x: GetPylintCmd([x], [], 1), files)
|
973
|
+
|
974
|
+
|
975
|
+
def RunPylint(input_api, *args, **kwargs):
|
976
|
+
"""Legacy presubmit function.
|
977
|
+
|
978
|
+
For better performance, get all tests and then pass to
|
979
|
+
input_api.RunTests.
|
980
|
+
"""
|
981
|
+
return input_api.RunTests(GetPylint(input_api, *args, **kwargs), False)
|
982
|
+
|
983
|
+
|
984
|
+
def CheckBuildbotPendingBuilds(input_api, output_api, url, max_pendings,
|
985
|
+
ignored):
|
986
|
+
try:
|
987
|
+
connection = input_api.urllib_request.urlopen(url)
|
988
|
+
raw_data = connection.read()
|
989
|
+
connection.close()
|
990
|
+
except IOError:
|
991
|
+
return [output_api.PresubmitNotifyResult('%s is not accessible' % url)]
|
992
|
+
|
993
|
+
try:
|
994
|
+
data = input_api.json.loads(raw_data)
|
995
|
+
except ValueError:
|
996
|
+
return [output_api.PresubmitNotifyResult('Received malformed json while '
|
997
|
+
'looking up buildbot status')]
|
998
|
+
|
999
|
+
out = []
|
1000
|
+
for (builder_name, builder) in data.items():
|
1001
|
+
if builder_name in ignored:
|
1002
|
+
continue
|
1003
|
+
if builder.get('state', '') == 'offline':
|
1004
|
+
continue
|
1005
|
+
pending_builds_len = len(builder.get('pending_builds', []))
|
1006
|
+
if pending_builds_len > max_pendings:
|
1007
|
+
out.append('%s has %d build(s) pending' %
|
1008
|
+
(builder_name, pending_builds_len))
|
1009
|
+
if out:
|
1010
|
+
return [output_api.PresubmitPromptWarning(
|
1011
|
+
'Build(s) pending. It is suggested to wait that no more than %d '
|
1012
|
+
'builds are pending.' % max_pendings,
|
1013
|
+
long_text='\n'.join(out))]
|
1014
|
+
return []
|
1015
|
+
|
1016
|
+
|
1017
|
+
def CheckOwnersFormat(input_api, output_api):
|
1018
|
+
affected_files = set([
|
1019
|
+
f.LocalPath()
|
1020
|
+
for f in input_api.change.AffectedFiles()
|
1021
|
+
if 'OWNERS' in f.LocalPath() and f.Action() != 'D'
|
1022
|
+
])
|
1023
|
+
if not affected_files:
|
1024
|
+
return []
|
1025
|
+
try:
|
1026
|
+
owners_db = input_api.owners_db
|
1027
|
+
owners_db.override_files = {}
|
1028
|
+
owners_db.load_data_needed_for(affected_files)
|
1029
|
+
return []
|
1030
|
+
except Exception as e:
|
1031
|
+
return [output_api.PresubmitError(
|
1032
|
+
'Error parsing OWNERS files:\n%s' % e)]
|
1033
|
+
|
1034
|
+
|
1035
|
+
def CheckOwners(input_api, output_api, source_file_filter=None):
|
1036
|
+
affected_files = set([f.LocalPath() for f in
|
1037
|
+
input_api.change.AffectedFiles(file_filter=source_file_filter)])
|
1038
|
+
owners_db = input_api.owners_db
|
1039
|
+
owners_db.override_files = input_api.change.OriginalOwnersFiles()
|
1040
|
+
owner_email, reviewers = GetCodereviewOwnerAndReviewers(
|
1041
|
+
input_api,
|
1042
|
+
owners_db.email_regexp,
|
1043
|
+
approval_needed=input_api.is_committing)
|
1044
|
+
|
1045
|
+
owner_email = owner_email or input_api.change.author_email
|
1046
|
+
|
1047
|
+
finder = input_api.owners_finder(
|
1048
|
+
affected_files,
|
1049
|
+
input_api.change.RepositoryRoot(),
|
1050
|
+
owner_email,
|
1051
|
+
reviewers,
|
1052
|
+
fopen=open,
|
1053
|
+
os_path=input_api.os_path,
|
1054
|
+
email_postfix='',
|
1055
|
+
disable_color=True,
|
1056
|
+
override_files=input_api.change.OriginalOwnersFiles())
|
1057
|
+
missing_files = finder.unreviewed_files
|
1058
|
+
affects_owners = any('OWNERS' in name for name in missing_files)
|
1059
|
+
|
1060
|
+
if input_api.is_committing:
|
1061
|
+
if input_api.tbr and not affects_owners:
|
1062
|
+
return [output_api.PresubmitNotifyResult(
|
1063
|
+
'--tbr was specified, skipping OWNERS check')]
|
1064
|
+
needed = 'LGTM from an OWNER'
|
1065
|
+
output_fn = output_api.PresubmitError
|
1066
|
+
if input_api.change.issue:
|
1067
|
+
if input_api.dry_run:
|
1068
|
+
output_fn = lambda text: output_api.PresubmitNotifyResult(
|
1069
|
+
'This is a dry run, but these failures would be reported on ' +
|
1070
|
+
'commit:\n' + text)
|
1071
|
+
else:
|
1072
|
+
return [output_api.PresubmitError(
|
1073
|
+
'OWNERS check failed: this CL has no Gerrit change number, '
|
1074
|
+
'so we can\'t check it for approvals.')]
|
1075
|
+
else:
|
1076
|
+
needed = 'OWNER reviewers'
|
1077
|
+
output_fn = output_api.PresubmitNotifyResult
|
1078
|
+
|
1079
|
+
if missing_files:
|
1080
|
+
output_list = [
|
1081
|
+
output_fn('Missing %s for these files:\n %s' %
|
1082
|
+
(needed, '\n '.join(sorted(missing_files))))]
|
1083
|
+
if input_api.tbr and affects_owners:
|
1084
|
+
output_list.append(output_fn('TBR for OWNERS files are ignored.'))
|
1085
|
+
if not input_api.is_committing:
|
1086
|
+
suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
|
1087
|
+
owners_with_comments = []
|
1088
|
+
def RecordComments(text):
|
1089
|
+
owners_with_comments.append(finder.print_indent() + text)
|
1090
|
+
finder.writeln = RecordComments
|
1091
|
+
for owner in suggested_owners:
|
1092
|
+
finder.print_comments(owner)
|
1093
|
+
output_list.append(output_fn('Suggested OWNERS: ' +
|
1094
|
+
'(Use "git-cl owners" to interactively select owners.)\n %s' %
|
1095
|
+
('\n '.join(owners_with_comments))))
|
1096
|
+
return output_list
|
1097
|
+
|
1098
|
+
if input_api.is_committing and not reviewers:
|
1099
|
+
return [output_fn('Missing LGTM from someone other than %s' % owner_email)]
|
1100
|
+
return []
|
1101
|
+
|
1102
|
+
|
1103
|
+
def GetCodereviewOwnerAndReviewers(input_api, email_regexp, approval_needed):
|
1104
|
+
"""Return the owner and reviewers of a change, if any.
|
1105
|
+
|
1106
|
+
If approval_needed is True, only reviewers who have approved the change
|
1107
|
+
will be returned.
|
1108
|
+
"""
|
1109
|
+
issue = input_api.change.issue
|
1110
|
+
if not issue:
|
1111
|
+
return None, (set() if approval_needed else
|
1112
|
+
_ReviewersFromChange(input_api.change))
|
1113
|
+
|
1114
|
+
owner_email = input_api.gerrit.GetChangeOwner(issue)
|
1115
|
+
reviewers = set(
|
1116
|
+
r for r in input_api.gerrit.GetChangeReviewers(issue, approval_needed)
|
1117
|
+
if _match_reviewer_email(r, owner_email, email_regexp))
|
1118
|
+
input_api.logging.debug('owner: %s; approvals given by: %s',
|
1119
|
+
owner_email, ', '.join(sorted(reviewers)))
|
1120
|
+
return owner_email, reviewers
|
1121
|
+
|
1122
|
+
|
1123
|
+
def _ReviewersFromChange(change):
|
1124
|
+
"""Return the reviewers specified in the |change|, if any."""
|
1125
|
+
reviewers = set()
|
1126
|
+
reviewers.update(change.ReviewersFromDescription())
|
1127
|
+
reviewers.update(change.TBRsFromDescription())
|
1128
|
+
|
1129
|
+
# Drop reviewers that aren't specified in email address format.
|
1130
|
+
return set(reviewer for reviewer in reviewers if '@' in reviewer)
|
1131
|
+
|
1132
|
+
|
1133
|
+
def _match_reviewer_email(r, owner_email, email_regexp):
|
1134
|
+
return email_regexp.match(r) and r != owner_email
|
1135
|
+
|
1136
|
+
|
1137
|
+
def CheckSingletonInHeaders(input_api, output_api, source_file_filter=None):
|
1138
|
+
"""Deprecated, must be removed."""
|
1139
|
+
return [
|
1140
|
+
output_api.PresubmitNotifyResult(
|
1141
|
+
'CheckSingletonInHeaders is deprecated, please remove it.')
|
1142
|
+
]
|
1143
|
+
|
1144
|
+
|
1145
|
+
def PanProjectChecks(input_api, output_api,
|
1146
|
+
excluded_paths=None, text_files=None,
|
1147
|
+
license_header=None, project_name=None,
|
1148
|
+
owners_check=True, maxlen=80):
|
1149
|
+
"""Checks that ALL chromium orbit projects should use.
|
1150
|
+
|
1151
|
+
These are checks to be run on all Chromium orbit project, including:
|
1152
|
+
Chromium
|
1153
|
+
Native Client
|
1154
|
+
V8
|
1155
|
+
When you update this function, please take this broad scope into account.
|
1156
|
+
Args:
|
1157
|
+
input_api: Bag of input related interfaces.
|
1158
|
+
output_api: Bag of output related interfaces.
|
1159
|
+
excluded_paths: Don't include these paths in common checks.
|
1160
|
+
text_files: Which file are to be treated as documentation text files.
|
1161
|
+
license_header: What license header should be on files.
|
1162
|
+
project_name: What is the name of the project as it appears in the license.
|
1163
|
+
Returns:
|
1164
|
+
A list of warning or error objects.
|
1165
|
+
"""
|
1166
|
+
excluded_paths = tuple(excluded_paths or [])
|
1167
|
+
text_files = tuple(text_files or (
|
1168
|
+
r'.+\.txt$',
|
1169
|
+
r'.+\.json$',
|
1170
|
+
))
|
1171
|
+
project_name = project_name or 'Chromium'
|
1172
|
+
|
1173
|
+
# Accept any year number from 2006 to the current year, or the special
|
1174
|
+
# 2006-20xx string used on the oldest files. 2006-20xx is deprecated, but
|
1175
|
+
# tolerated on old files.
|
1176
|
+
current_year = int(input_api.time.strftime('%Y'))
|
1177
|
+
allowed_years = (str(s) for s in reversed(range(2006, current_year + 1)))
|
1178
|
+
years_re = '(' + '|'.join(allowed_years) + '|2006-2008|2006-2009|2006-2010)'
|
1179
|
+
|
1180
|
+
# The (c) is deprecated, but tolerate it until it's removed from all files.
|
1181
|
+
license_header = license_header or (
|
1182
|
+
r'.*? Copyright (\(c\) )?%(year)s The %(project)s Authors\. '
|
1183
|
+
r'All rights reserved\.\n'
|
1184
|
+
r'.*? Use of this source code is governed by a BSD-style license that '
|
1185
|
+
r'can be\n'
|
1186
|
+
r'.*? found in the LICENSE file\.(?: \*/)?\n'
|
1187
|
+
) % {
|
1188
|
+
'year': years_re,
|
1189
|
+
'project': project_name,
|
1190
|
+
}
|
1191
|
+
|
1192
|
+
results = []
|
1193
|
+
# This code loads the default skip list (e.g. third_party, experimental, etc)
|
1194
|
+
# and add our skip list (breakpad, skia and v8 are still not following
|
1195
|
+
# google style and are not really living this repository).
|
1196
|
+
# See presubmit_support.py InputApi.FilterSourceFile for the (simple) usage.
|
1197
|
+
files_to_skip = input_api.DEFAULT_FILES_TO_SKIP + excluded_paths
|
1198
|
+
files_to_check = input_api.DEFAULT_FILES_TO_CHECK + text_files
|
1199
|
+
sources = lambda x: input_api.FilterSourceFile(x, files_to_skip=files_to_skip)
|
1200
|
+
text_files = lambda x: input_api.FilterSourceFile(
|
1201
|
+
x, files_to_skip=files_to_skip, files_to_check=files_to_check)
|
1202
|
+
|
1203
|
+
snapshot_memory = []
|
1204
|
+
def snapshot(msg):
|
1205
|
+
"""Measures & prints performance warning if a rule is running slow."""
|
1206
|
+
if input_api.sys.version_info.major == 2:
|
1207
|
+
dt2 = input_api.time.clock()
|
1208
|
+
else:
|
1209
|
+
dt2 = input_api.time.process_time()
|
1210
|
+
if snapshot_memory:
|
1211
|
+
delta_ms = int(1000*(dt2 - snapshot_memory[0]))
|
1212
|
+
if delta_ms > 500:
|
1213
|
+
print(" %s took a long time: %dms" % (snapshot_memory[1], delta_ms))
|
1214
|
+
snapshot_memory[:] = (dt2, msg)
|
1215
|
+
|
1216
|
+
snapshot("checking owners files format")
|
1217
|
+
results.extend(input_api.canned_checks.CheckOwnersFormat(
|
1218
|
+
input_api, output_api))
|
1219
|
+
|
1220
|
+
if owners_check:
|
1221
|
+
snapshot("checking owners")
|
1222
|
+
results.extend(input_api.canned_checks.CheckOwners(
|
1223
|
+
input_api, output_api, source_file_filter=None))
|
1224
|
+
|
1225
|
+
snapshot("checking long lines")
|
1226
|
+
results.extend(input_api.canned_checks.CheckLongLines(
|
1227
|
+
input_api, output_api, maxlen, source_file_filter=sources))
|
1228
|
+
snapshot( "checking tabs")
|
1229
|
+
results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
|
1230
|
+
input_api, output_api, source_file_filter=sources))
|
1231
|
+
snapshot( "checking stray whitespace")
|
1232
|
+
results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
|
1233
|
+
input_api, output_api, source_file_filter=sources))
|
1234
|
+
snapshot("checking license")
|
1235
|
+
results.extend(input_api.canned_checks.CheckLicense(
|
1236
|
+
input_api, output_api, license_header, source_file_filter=sources))
|
1237
|
+
|
1238
|
+
if input_api.is_committing:
|
1239
|
+
snapshot("checking was uploaded")
|
1240
|
+
results.extend(input_api.canned_checks.CheckChangeWasUploaded(
|
1241
|
+
input_api, output_api))
|
1242
|
+
snapshot("checking description")
|
1243
|
+
results.extend(input_api.canned_checks.CheckChangeHasDescription(
|
1244
|
+
input_api, output_api))
|
1245
|
+
results.extend(input_api.canned_checks.CheckDoNotSubmitInDescription(
|
1246
|
+
input_api, output_api))
|
1247
|
+
snapshot("checking do not submit in files")
|
1248
|
+
results.extend(input_api.canned_checks.CheckDoNotSubmitInFiles(
|
1249
|
+
input_api, output_api))
|
1250
|
+
if input_api.change.scm == 'git':
|
1251
|
+
snapshot("checking for commit objects in tree")
|
1252
|
+
results.extend(input_api.canned_checks.CheckForCommitObjects(
|
1253
|
+
input_api, output_api))
|
1254
|
+
snapshot("done")
|
1255
|
+
return results
|
1256
|
+
|
1257
|
+
|
1258
|
+
def CheckPatchFormatted(input_api,
|
1259
|
+
output_api,
|
1260
|
+
bypass_warnings=True,
|
1261
|
+
check_clang_format=True,
|
1262
|
+
check_js=False,
|
1263
|
+
check_python=None,
|
1264
|
+
result_factory=None):
|
1265
|
+
result_factory = result_factory or output_api.PresubmitPromptWarning
|
1266
|
+
import git_cl
|
1267
|
+
|
1268
|
+
display_args = []
|
1269
|
+
if not check_clang_format:
|
1270
|
+
display_args.append('--no-clang-format')
|
1271
|
+
|
1272
|
+
if check_js:
|
1273
|
+
display_args.append('--js')
|
1274
|
+
|
1275
|
+
# Explicitly setting check_python to will enable/disable python formatting
|
1276
|
+
# on all files. Leaving it as None will enable checking patch formatting
|
1277
|
+
# on files that have a .style.yapf file in a parent directory.
|
1278
|
+
if check_python is not None:
|
1279
|
+
if check_python:
|
1280
|
+
display_args.append('--python')
|
1281
|
+
else:
|
1282
|
+
display_args.append('--no-python')
|
1283
|
+
|
1284
|
+
cmd = ['-C', input_api.change.RepositoryRoot(),
|
1285
|
+
'cl', 'format', '--dry-run', '--presubmit'] + display_args
|
1286
|
+
presubmit_subdir = input_api.os_path.relpath(
|
1287
|
+
input_api.PresubmitLocalPath(), input_api.change.RepositoryRoot())
|
1288
|
+
if presubmit_subdir.startswith('..') or presubmit_subdir == '.':
|
1289
|
+
presubmit_subdir = ''
|
1290
|
+
# If the PRESUBMIT.py is in a parent repository, then format the entire
|
1291
|
+
# subrepository. Otherwise, format only the code in the directory that
|
1292
|
+
# contains the PRESUBMIT.py.
|
1293
|
+
if presubmit_subdir:
|
1294
|
+
cmd.append(input_api.PresubmitLocalPath())
|
1295
|
+
code, _ = git_cl.RunGitWithCode(cmd, suppress_stderr=bypass_warnings)
|
1296
|
+
# bypass_warnings? Only fail with code 2.
|
1297
|
+
# As this is just a warning, ignore all other errors if the user
|
1298
|
+
# happens to have a broken clang-format, doesn't use git, etc etc.
|
1299
|
+
if code == 2 or (code and not bypass_warnings):
|
1300
|
+
if presubmit_subdir:
|
1301
|
+
short_path = presubmit_subdir
|
1302
|
+
else:
|
1303
|
+
short_path = input_api.basename(input_api.change.RepositoryRoot())
|
1304
|
+
display_args.append(presubmit_subdir)
|
1305
|
+
return [result_factory(
|
1306
|
+
'The %s directory requires source formatting. '
|
1307
|
+
'Please run: git cl format %s' %
|
1308
|
+
(short_path, ' '.join(display_args)))]
|
1309
|
+
return []
|
1310
|
+
|
1311
|
+
|
1312
|
+
def CheckGNFormatted(input_api, output_api):
|
1313
|
+
import gn
|
1314
|
+
affected_files = input_api.AffectedFiles(
|
1315
|
+
include_deletes=False,
|
1316
|
+
file_filter=lambda x: x.LocalPath().endswith('.gn') or
|
1317
|
+
x.LocalPath().endswith('.gni') or
|
1318
|
+
x.LocalPath().endswith('.typemap'))
|
1319
|
+
warnings = []
|
1320
|
+
for f in affected_files:
|
1321
|
+
cmd = ['gn', 'format', '--dry-run', f.AbsoluteLocalPath()]
|
1322
|
+
rc = gn.main(cmd)
|
1323
|
+
if rc == 2:
|
1324
|
+
warnings.append(output_api.PresubmitPromptWarning(
|
1325
|
+
'%s requires formatting. Please run:\n gn format %s' % (
|
1326
|
+
f.AbsoluteLocalPath(), f.LocalPath())))
|
1327
|
+
# It's just a warning, so ignore other types of failures assuming they'll be
|
1328
|
+
# caught elsewhere.
|
1329
|
+
return warnings
|
1330
|
+
|
1331
|
+
|
1332
|
+
def CheckCIPDManifest(input_api, output_api, path=None, content=None):
|
1333
|
+
"""Verifies that a CIPD ensure file manifest is valid against all platforms.
|
1334
|
+
|
1335
|
+
Exactly one of "path" or "content" must be provided. An assertion will occur
|
1336
|
+
if neither or both are provided.
|
1337
|
+
|
1338
|
+
Args:
|
1339
|
+
path (str): If provided, the filesystem path to the manifest to verify.
|
1340
|
+
content (str): If provided, the raw content of the manifest to veirfy.
|
1341
|
+
"""
|
1342
|
+
cipd_bin = 'cipd' if not input_api.is_windows else 'cipd.bat'
|
1343
|
+
cmd = [cipd_bin, 'ensure-file-verify']
|
1344
|
+
kwargs = {}
|
1345
|
+
|
1346
|
+
if input_api.is_windows:
|
1347
|
+
# Needs to be able to resolve "cipd.bat".
|
1348
|
+
kwargs['shell'] = True
|
1349
|
+
|
1350
|
+
if input_api.verbose:
|
1351
|
+
cmd += ['-log-level', 'debug']
|
1352
|
+
|
1353
|
+
if path:
|
1354
|
+
assert content is None, 'Cannot provide both "path" and "content".'
|
1355
|
+
cmd += ['-ensure-file', path]
|
1356
|
+
name = 'Check CIPD manifest %r' % path
|
1357
|
+
elif content:
|
1358
|
+
assert path is None, 'Cannot provide both "path" and "content".'
|
1359
|
+
cmd += ['-ensure-file=-']
|
1360
|
+
kwargs['stdin'] = content
|
1361
|
+
# quick and dirty parser to extract checked packages.
|
1362
|
+
packages = [
|
1363
|
+
l.split()[0] for l in (ll.strip() for ll in content.splitlines())
|
1364
|
+
if ' ' in l and not l.startswith('$')
|
1365
|
+
]
|
1366
|
+
name = 'Check CIPD packages from string: %r' % (packages,)
|
1367
|
+
else:
|
1368
|
+
raise Exception('Exactly one of "path" or "content" must be provided.')
|
1369
|
+
|
1370
|
+
return input_api.Command(
|
1371
|
+
name,
|
1372
|
+
cmd,
|
1373
|
+
kwargs,
|
1374
|
+
output_api.PresubmitError)
|
1375
|
+
|
1376
|
+
|
1377
|
+
def CheckCIPDPackages(input_api, output_api, platforms, packages):
|
1378
|
+
"""Verifies that all named CIPD packages can be resolved against all supplied
|
1379
|
+
platforms.
|
1380
|
+
|
1381
|
+
Args:
|
1382
|
+
platforms (list): List of CIPD platforms to verify.
|
1383
|
+
packages (dict): Mapping of package name to version.
|
1384
|
+
"""
|
1385
|
+
manifest = []
|
1386
|
+
for p in platforms:
|
1387
|
+
manifest.append('$VerifiedPlatform %s' % (p,))
|
1388
|
+
for k, v in packages.items():
|
1389
|
+
manifest.append('%s %s' % (k, v))
|
1390
|
+
return CheckCIPDManifest(input_api, output_api, content='\n'.join(manifest))
|
1391
|
+
|
1392
|
+
|
1393
|
+
def CheckCIPDClientDigests(input_api, output_api, client_version_file):
|
1394
|
+
"""Verifies that *.digests file was correctly regenerated.
|
1395
|
+
|
1396
|
+
<client_version_file>.digests file contains pinned hashes of the CIPD client.
|
1397
|
+
It is consulted during CIPD client bootstrap and self-update. It should be
|
1398
|
+
regenerated each time CIPD client version file changes.
|
1399
|
+
|
1400
|
+
Args:
|
1401
|
+
client_version_file (str): Path to a text file with CIPD client version.
|
1402
|
+
"""
|
1403
|
+
cmd = [
|
1404
|
+
'cipd' if not input_api.is_windows else 'cipd.bat',
|
1405
|
+
'selfupdate-roll', '-check', '-version-file', client_version_file,
|
1406
|
+
]
|
1407
|
+
if input_api.verbose:
|
1408
|
+
cmd += ['-log-level', 'debug']
|
1409
|
+
return input_api.Command(
|
1410
|
+
'Check CIPD client_version_file.digests file',
|
1411
|
+
cmd,
|
1412
|
+
{'shell': True} if input_api.is_windows else {}, # to resolve cipd.bat
|
1413
|
+
output_api.PresubmitError)
|
1414
|
+
|
1415
|
+
|
1416
|
+
def CheckForCommitObjects(input_api, output_api):
|
1417
|
+
"""Validates that there are no commit objects in the repository.
|
1418
|
+
|
1419
|
+
Commit objects are put into the git tree typically by submodule tooling.
|
1420
|
+
Because we use gclient to handle external repository references instead,
|
1421
|
+
we want to avoid this. Having commit objects in the tree can confuse git
|
1422
|
+
tooling in some scenarios into thinking that the tree is dirty (e.g. the
|
1423
|
+
presence of a DEPS subrepo at a location where a commit object is stored
|
1424
|
+
in the tree).
|
1425
|
+
|
1426
|
+
Args:
|
1427
|
+
input_api: Bag of input related interfaces.
|
1428
|
+
output_api: Bag of output related interfaces.
|
1429
|
+
|
1430
|
+
Returns:
|
1431
|
+
A presubmit error if a commit object is present in the tree.
|
1432
|
+
"""
|
1433
|
+
|
1434
|
+
def parse_tree_entry(ent):
|
1435
|
+
"""Splits a tree entry into components
|
1436
|
+
|
1437
|
+
Args:
|
1438
|
+
ent: a tree entry in the form "filemode type hash\tname"
|
1439
|
+
|
1440
|
+
Returns:
|
1441
|
+
The tree entry split into component parts
|
1442
|
+
"""
|
1443
|
+
tabparts = ent.split('\t', 1)
|
1444
|
+
spaceparts = tabparts[0].split(' ', 2)
|
1445
|
+
return (spaceparts[0], spaceparts[1], spaceparts[2], tabparts[1])
|
1446
|
+
|
1447
|
+
full_tree = input_api.subprocess.check_output(
|
1448
|
+
['git', 'ls-tree', '-r', '--full-tree', 'HEAD'],
|
1449
|
+
cwd=input_api.PresubmitLocalPath()
|
1450
|
+
)
|
1451
|
+
tree_entries = full_tree.split('\n')
|
1452
|
+
tree_entries = filter(lambda x: len(x) > 0, tree_entries)
|
1453
|
+
tree_entries = map(parse_tree_entry, tree_entries)
|
1454
|
+
bad_tree_entries = filter(lambda x: x[1] == 'commit', tree_entries)
|
1455
|
+
bad_tree_entries = map(lambda x: x[3], bad_tree_entries)
|
1456
|
+
if len(bad_tree_entries) > 0:
|
1457
|
+
return [output_api.PresubmitError(
|
1458
|
+
'Commit objects present within tree.\n'
|
1459
|
+
'This may be due to submodule-related interactions; the presence of a\n'
|
1460
|
+
'commit object in the tree may lead to odd situations where files are\n'
|
1461
|
+
'inconsistently checked-out. Remove these commit entries and validate\n'
|
1462
|
+
'your changeset again:\n',
|
1463
|
+
bad_tree_entries)]
|
1464
|
+
return []
|
1465
|
+
|
1466
|
+
|
1467
|
+
def CheckVPythonSpec(input_api, output_api, file_filter=None):
|
1468
|
+
"""Validates any changed .vpython files with vpython verification tool.
|
1469
|
+
|
1470
|
+
Args:
|
1471
|
+
input_api: Bag of input related interfaces.
|
1472
|
+
output_api: Bag of output related interfaces.
|
1473
|
+
file_filter: Custom function that takes a path (relative to client root) and
|
1474
|
+
returns boolean, which is used to filter files for which to apply the
|
1475
|
+
verification to. Defaults to any path ending with .vpython, which captures
|
1476
|
+
both global .vpython and <script>.vpython files.
|
1477
|
+
|
1478
|
+
Returns:
|
1479
|
+
A list of input_api.Command objects containing verification commands.
|
1480
|
+
"""
|
1481
|
+
file_filter = file_filter or (lambda f: f.LocalPath().endswith('.vpython'))
|
1482
|
+
affected_files = input_api.AffectedTestableFiles(file_filter=file_filter)
|
1483
|
+
affected_files = map(lambda f: f.AbsoluteLocalPath(), affected_files)
|
1484
|
+
|
1485
|
+
commands = []
|
1486
|
+
for f in affected_files:
|
1487
|
+
commands.append(input_api.Command(
|
1488
|
+
'Verify %s' % f,
|
1489
|
+
['vpython', '-vpython-spec', f, '-vpython-tool', 'verify'],
|
1490
|
+
{'stderr': input_api.subprocess.STDOUT},
|
1491
|
+
output_api.PresubmitError))
|
1492
|
+
|
1493
|
+
return commands
|
1494
|
+
|
1495
|
+
|
1496
|
+
def CheckChangedLUCIConfigs(input_api, output_api):
|
1497
|
+
import collections
|
1498
|
+
import base64
|
1499
|
+
import json
|
1500
|
+
import logging
|
1501
|
+
|
1502
|
+
import auth
|
1503
|
+
import git_cl
|
1504
|
+
|
1505
|
+
LUCI_CONFIG_HOST_NAME = 'luci-config.appspot.com'
|
1506
|
+
|
1507
|
+
cl = git_cl.Changelist()
|
1508
|
+
if input_api.change.issue and input_api.gerrit:
|
1509
|
+
remote_branch = input_api.gerrit.GetDestRef(input_api.change.issue)
|
1510
|
+
else:
|
1511
|
+
remote, remote_branch = cl.GetRemoteBranch()
|
1512
|
+
if remote_branch.startswith('refs/remotes/%s/' % remote):
|
1513
|
+
remote_branch = remote_branch.replace(
|
1514
|
+
'refs/remotes/%s/' % remote, 'refs/heads/', 1)
|
1515
|
+
if remote_branch.startswith('refs/remotes/branch-heads/'):
|
1516
|
+
remote_branch = remote_branch.replace(
|
1517
|
+
'refs/remotes/branch-heads/', 'refs/branch-heads/', 1)
|
1518
|
+
|
1519
|
+
remote_host_url = cl.GetRemoteUrl()
|
1520
|
+
if not remote_host_url:
|
1521
|
+
return [output_api.PresubmitError(
|
1522
|
+
'Remote host url for git has not been defined')]
|
1523
|
+
remote_host_url = remote_host_url.rstrip('/')
|
1524
|
+
if remote_host_url.endswith('.git'):
|
1525
|
+
remote_host_url = remote_host_url[:-len('.git')]
|
1526
|
+
|
1527
|
+
# authentication
|
1528
|
+
try:
|
1529
|
+
acc_tkn = auth.Authenticator().get_access_token()
|
1530
|
+
except auth.LoginRequiredError as e:
|
1531
|
+
return [output_api.PresubmitError(
|
1532
|
+
'Error in authenticating user.', long_text=str(e))]
|
1533
|
+
|
1534
|
+
def request(endpoint, body=None):
|
1535
|
+
api_url = ('https://%s/_ah/api/config/v1/%s'
|
1536
|
+
% (LUCI_CONFIG_HOST_NAME, endpoint))
|
1537
|
+
req = input_api.urllib_request.Request(api_url)
|
1538
|
+
req.add_header('Authorization', 'Bearer %s' % acc_tkn.token)
|
1539
|
+
if body is not None:
|
1540
|
+
req.add_header('Content-Type', 'application/json')
|
1541
|
+
req.data = json.dumps(body).encode('utf-8')
|
1542
|
+
return json.load(input_api.urllib_request.urlopen(req))
|
1543
|
+
|
1544
|
+
try:
|
1545
|
+
config_sets = request('config-sets').get('config_sets')
|
1546
|
+
except input_api.urllib_error.HTTPError as e:
|
1547
|
+
return [output_api.PresubmitError(
|
1548
|
+
'Config set request to luci-config failed', long_text=str(e))]
|
1549
|
+
if not config_sets:
|
1550
|
+
return [output_api.PresubmitPromptWarning('No config_sets were returned')]
|
1551
|
+
loc_pref = '%s/+/%s/' % (remote_host_url, remote_branch)
|
1552
|
+
logging.debug('Derived location prefix: %s', loc_pref)
|
1553
|
+
dir_to_config_set = {
|
1554
|
+
'%s/' % cs['location'][len(loc_pref):].rstrip('/'): cs['config_set']
|
1555
|
+
for cs in config_sets
|
1556
|
+
if cs['location'].startswith(loc_pref) or
|
1557
|
+
('%s/' % cs['location']) == loc_pref
|
1558
|
+
}
|
1559
|
+
if not dir_to_config_set:
|
1560
|
+
warning_long_text_lines = [
|
1561
|
+
'No config_set found for %s.' % loc_pref,
|
1562
|
+
'Found the following:',
|
1563
|
+
]
|
1564
|
+
for loc in sorted(cs['location'] for cs in config_sets):
|
1565
|
+
warning_long_text_lines.append(' %s' % loc)
|
1566
|
+
warning_long_text_lines.append('')
|
1567
|
+
warning_long_text_lines.append(
|
1568
|
+
'If the requested location is internal,'
|
1569
|
+
' the requester may not have access.')
|
1570
|
+
|
1571
|
+
return [output_api.PresubmitPromptWarning(
|
1572
|
+
warning_long_text_lines[0],
|
1573
|
+
long_text='\n'.join(warning_long_text_lines))]
|
1574
|
+
cs_to_files = collections.defaultdict(list)
|
1575
|
+
for f in input_api.AffectedFiles(include_deletes=False):
|
1576
|
+
# windows
|
1577
|
+
file_path = f.LocalPath().replace(_os.sep, '/')
|
1578
|
+
logging.debug('Affected file path: %s', file_path)
|
1579
|
+
for dr, cs in dir_to_config_set.items():
|
1580
|
+
if dr == '/' or file_path.startswith(dr):
|
1581
|
+
cs_to_files[cs].append({
|
1582
|
+
'path': file_path[len(dr):] if dr != '/' else file_path,
|
1583
|
+
'content': base64.b64encode(
|
1584
|
+
'\n'.join(f.NewContents()).encode('utf-8')).decode('utf-8')
|
1585
|
+
})
|
1586
|
+
outputs = []
|
1587
|
+
for cs, f in cs_to_files.items():
|
1588
|
+
try:
|
1589
|
+
# TODO(myjang): parallelize
|
1590
|
+
res = request(
|
1591
|
+
'validate-config', body={'config_set': cs, 'files': f})
|
1592
|
+
except input_api.urllib_error.HTTPError as e:
|
1593
|
+
return [output_api.PresubmitError(
|
1594
|
+
'Validation request to luci-config failed', long_text=str(e))]
|
1595
|
+
for msg in res.get('messages', []):
|
1596
|
+
sev = msg['severity']
|
1597
|
+
if sev == 'WARNING':
|
1598
|
+
out_f = output_api.PresubmitPromptWarning
|
1599
|
+
elif sev == 'ERROR' or sev == 'CRITICAL':
|
1600
|
+
out_f = output_api.PresubmitError
|
1601
|
+
else:
|
1602
|
+
out_f = output_api.PresubmitNotifyResult
|
1603
|
+
outputs.append(out_f('Config validation: %s' % msg['text']))
|
1604
|
+
return outputs
|
1605
|
+
|
1606
|
+
|
1607
|
+
def CheckLucicfgGenOutput(input_api, output_api, entry_script):
|
1608
|
+
"""Verifies configs produced by `lucicfg` are up-to-date and pass validation.
|
1609
|
+
|
1610
|
+
Runs the check unconditionally, regardless of what files are modified. Examine
|
1611
|
+
input_api.AffectedFiles() yourself before using CheckLucicfgGenOutput if this
|
1612
|
+
is a concern.
|
1613
|
+
|
1614
|
+
Assumes `lucicfg` binary is in PATH and the user is logged in.
|
1615
|
+
|
1616
|
+
Args:
|
1617
|
+
entry_script: path to the entry-point *.star script responsible for
|
1618
|
+
generating a single config set. Either absolute or relative to the
|
1619
|
+
currently running PRESUBMIT.py script.
|
1620
|
+
|
1621
|
+
Returns:
|
1622
|
+
A list of input_api.Command objects containing verification commands.
|
1623
|
+
"""
|
1624
|
+
return [
|
1625
|
+
input_api.Command(
|
1626
|
+
'lucicfg validate "%s"' % entry_script,
|
1627
|
+
[
|
1628
|
+
'lucicfg' if not input_api.is_windows else 'lucicfg.bat',
|
1629
|
+
'validate', entry_script,
|
1630
|
+
'-log-level', 'debug' if input_api.verbose else 'warning',
|
1631
|
+
],
|
1632
|
+
{
|
1633
|
+
'stderr': input_api.subprocess.STDOUT,
|
1634
|
+
'shell': input_api.is_windows, # to resolve *.bat
|
1635
|
+
'cwd': input_api.PresubmitLocalPath(),
|
1636
|
+
},
|
1637
|
+
output_api.PresubmitError)
|
1638
|
+
]
|
1639
|
+
|
1640
|
+
def CheckJsonParses(input_api, output_api):
|
1641
|
+
"""Verifies that all JSON files at least parse as valid JSON."""
|
1642
|
+
import json
|
1643
|
+
affected_files = input_api.AffectedFiles(
|
1644
|
+
include_deletes=False,
|
1645
|
+
file_filter=lambda x: x.LocalPath().endswith('.json'))
|
1646
|
+
warnings = []
|
1647
|
+
for f in affected_files:
|
1648
|
+
with open(f.AbsoluteLocalPath()) as j:
|
1649
|
+
try:
|
1650
|
+
json.load(j)
|
1651
|
+
except ValueError:
|
1652
|
+
# Just a warning for now, in case people are using JSON5 somewhere.
|
1653
|
+
warnings.append(output_api.PresubmitPromptWarning(
|
1654
|
+
'%s does not appear to be valid JSON.' % f.LocalPath()))
|
1655
|
+
return warnings
|