libv8 6.3.292.48.1 → 6.7.288.46.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +10 -34
- data/CHANGELOG.md +16 -0
- data/README.md +9 -63
- data/Rakefile +2 -2
- data/ext/libv8/builder.rb +22 -87
- data/ext/libv8/extconf.rb +1 -1
- data/ext/libv8/paths.rb +5 -18
- data/lib/libv8/version.rb +1 -1
- data/spec/location_spec.rb +1 -2
- data/spec/spec_helper.rb +0 -1
- data/vendor/depot_tools/.gitattributes +1 -2
- data/vendor/depot_tools/OWNERS +0 -1
- data/vendor/depot_tools/PRESUBMIT.py +11 -6
- data/vendor/depot_tools/README.md +0 -1
- data/vendor/depot_tools/WATCHLISTS +0 -6
- data/vendor/depot_tools/auth.py +129 -87
- data/vendor/depot_tools/autoninja +11 -1
- data/vendor/depot_tools/autoninja.bat +7 -1
- data/vendor/depot_tools/autoninja.py +14 -6
- data/vendor/depot_tools/bootstrap/win/manifest.txt +1 -1
- data/vendor/depot_tools/bootstrap/win/manifest_bleeding_edge.txt +1 -1
- data/vendor/depot_tools/cipd +23 -2
- data/vendor/depot_tools/cipd.bat +2 -2
- data/vendor/depot_tools/cipd_client_version +1 -1
- data/vendor/depot_tools/cipd_manifest.txt +17 -7
- data/vendor/depot_tools/cit.py +7 -6
- data/vendor/depot_tools/cpplint.py +195 -35
- data/vendor/depot_tools/detect_host_arch.py +51 -0
- data/vendor/depot_tools/download_from_google_storage.py +85 -26
- data/vendor/depot_tools/fetch.py +11 -6
- data/vendor/depot_tools/fetch_configs/chromium.py +0 -1
- data/vendor/depot_tools/fetch_configs/goma_client.py +41 -0
- data/vendor/depot_tools/fetch_configs/infra.py +0 -1
- data/vendor/depot_tools/fetch_configs/infra_internal.py +0 -1
- data/vendor/depot_tools/gclient-new-workdir.py +4 -0
- data/vendor/depot_tools/gclient.py +732 -476
- data/vendor/depot_tools/gclient_eval.py +569 -58
- data/vendor/depot_tools/gclient_scm.py +258 -46
- data/vendor/depot_tools/gclient_utils.py +17 -1
- data/vendor/depot_tools/gerrit_util.py +46 -13
- data/vendor/depot_tools/git_cache.py +0 -2
- data/vendor/depot_tools/git_cl.py +176 -335
- data/vendor/depot_tools/git_common.py +19 -16
- data/vendor/depot_tools/git_footers.py +19 -5
- data/vendor/depot_tools/git_hyper_blame.py +9 -3
- data/vendor/depot_tools/git_new_branch.py +15 -3
- data/vendor/depot_tools/git_upstream_diff.py +7 -2
- data/vendor/depot_tools/gsutil.py +1 -1
- data/vendor/depot_tools/infra/config/cq.cfg +1 -2
- data/vendor/depot_tools/infra/config/recipes.cfg +1 -1
- data/vendor/depot_tools/luci-auth +13 -0
- data/vendor/depot_tools/luci-auth.bat +8 -0
- data/vendor/depot_tools/man/html/depot_tools.html +0 -8
- data/vendor/depot_tools/man/html/git-upstream-diff.html +20 -3
- data/vendor/depot_tools/man/man1/git-upstream-diff.1 +27 -6
- data/vendor/depot_tools/man/man7/depot_tools.7 +0 -5
- data/vendor/depot_tools/man/man7/depot_tools_tutorial.7 +2 -2
- data/vendor/depot_tools/man/src/git-upstream-diff.txt +21 -3
- data/vendor/depot_tools/man/src/make_docs.sh +6 -0
- data/vendor/depot_tools/my_activity.py +283 -93
- data/vendor/depot_tools/owners.py +9 -4
- data/vendor/depot_tools/owners_finder.py +7 -3
- data/vendor/depot_tools/post_build_ninja_summary.py +322 -0
- data/vendor/depot_tools/presubmit_canned_checks.py +91 -106
- data/vendor/depot_tools/presubmit_support.py +219 -157
- data/vendor/depot_tools/prpc +13 -0
- data/vendor/depot_tools/prpc.bat +8 -0
- data/vendor/depot_tools/recipes/OWNERS +3 -1
- data/vendor/depot_tools/recipes/README.recipes.md +70 -111
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/__init__.py +12 -5
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/api.py +36 -68
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/deprecated_got_revision_mapping.json +0 -8
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/{trychange_oauth2_json.json → no_apply_patch_on_gclient.json} +64 -10
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/{no_shallow.json → shallow.json} +1 -1
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob.json +0 -8
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_empty_revision.json +0 -8
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail.json +0 -6
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch.json +0 -7
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch_download.json +0 -6
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_angle_deprecated.json +44 -0
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/{trychange_oauth2_buildbot.json → tryjob_gerrit_branch_heads.json} +51 -5
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8.json +0 -8
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8_head_by_default.json +48 -8
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.py +19 -26
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/resources/bot_update.py +193 -155
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/test_api.py +9 -0
- data/vendor/depot_tools/recipes/recipe_modules/gclient/api.py +2 -7
- data/vendor/depot_tools/recipes/recipe_modules/gclient/config.py +31 -5
- data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/basic.json +37 -19
- data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/buildbot.json +37 -19
- data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/revision.json +37 -19
- data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/tryserver.json +37 -23
- data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.py +4 -0
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/api.py +40 -8
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/examples/full.expected/basic.json +3 -3
- data/vendor/depot_tools/recipes/recipe_modules/gerrit/examples/full.py +6 -3
- data/vendor/depot_tools/recipes/recipe_modules/gitiles/OWNERS +0 -1
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/__init__.py +0 -1
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/api.py +7 -56
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_wrong_patch.json +0 -1
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.py +15 -16
- data/vendor/depot_tools/recipes/recipes.py +4 -2
- data/vendor/depot_tools/recipes/trigger_recipe_roller.txt +12 -0
- data/vendor/depot_tools/roll_dep.py +35 -37
- data/vendor/depot_tools/support/chromite_wrapper +1 -1
- data/vendor/depot_tools/third_party/logilab/astroid/README.chromium +3 -3
- data/vendor/depot_tools/third_party/logilab/astroid/__pkginfo__.py +2 -2
- data/vendor/depot_tools/third_party/logilab/astroid/astpeephole.py +86 -0
- data/vendor/depot_tools/third_party/logilab/astroid/bases.py +53 -66
- data/vendor/depot_tools/third_party/logilab/astroid/brain/py2pytest.py +31 -31
- data/vendor/depot_tools/third_party/logilab/astroid/brain/pynose.py +39 -16
- data/vendor/depot_tools/third_party/logilab/astroid/brain/pysix_moves.py +225 -189
- data/vendor/depot_tools/third_party/logilab/astroid/inference.py +45 -41
- data/vendor/depot_tools/third_party/logilab/astroid/manager.py +1 -0
- data/vendor/depot_tools/third_party/logilab/astroid/modutils.py +2 -2
- data/vendor/depot_tools/third_party/logilab/astroid/node_classes.py +3 -2
- data/vendor/depot_tools/third_party/logilab/astroid/nodes.py +1 -0
- data/vendor/depot_tools/third_party/logilab/astroid/protocols.py +57 -3
- data/vendor/depot_tools/third_party/logilab/astroid/raw_building.py +1 -1
- data/vendor/depot_tools/third_party/logilab/astroid/rebuilder.py +21 -1
- data/vendor/depot_tools/third_party/logilab/astroid/scoped_nodes.py +58 -33
- data/vendor/depot_tools/third_party/pylint/README.chromium +2 -2
- data/vendor/depot_tools/third_party/pylint/__pkginfo__.py +3 -3
- data/vendor/depot_tools/third_party/pylint/checkers/base.py +6 -18
- data/vendor/depot_tools/third_party/pylint/checkers/classes.py +64 -63
- data/vendor/depot_tools/third_party/pylint/checkers/design_analysis.py +25 -57
- data/vendor/depot_tools/third_party/pylint/checkers/format.py +14 -10
- data/vendor/depot_tools/third_party/pylint/checkers/python3.py +142 -37
- data/vendor/depot_tools/third_party/pylint/checkers/spelling.py +10 -1
- data/vendor/depot_tools/third_party/pylint/checkers/stdlib.py +50 -7
- data/vendor/depot_tools/third_party/pylint/checkers/strings.py +1 -1
- data/vendor/depot_tools/third_party/pylint/epylint.py +2 -1
- data/vendor/depot_tools/third_party/pylint/gui.py +1 -1
- data/vendor/depot_tools/third_party/pylint/lint.py +88 -23
- data/vendor/depot_tools/third_party/pylint/reporters/html.py +37 -5
- data/vendor/depot_tools/third_party/pylint/testutils.py +1 -1
- data/vendor/depot_tools/third_party/pylint/utils.py +5 -0
- data/vendor/depot_tools/vpython +31 -1
- data/vendor/depot_tools/win_toolchain/get_toolchain_if_necessary.py +35 -2
- data/vendor/depot_tools/win_toolchain/package_from_installed.py +0 -15
- data/vendor/depot_tools/yapf +17 -0
- data/vendor/depot_tools/{apply_issue.bat → yapf.bat} +2 -2
- metadata +16 -58
- data/ext/libv8/compiler.rb +0 -39
- data/ext/libv8/compiler/apple_llvm.rb +0 -22
- data/ext/libv8/compiler/clang.rb +0 -22
- data/ext/libv8/compiler/gcc.rb +0 -22
- data/ext/libv8/compiler/generic_compiler.rb +0 -66
- data/ext/libv8/make.rb +0 -13
- data/ext/libv8/patcher.rb +0 -21
- data/patches/0001-Build-a-standalone-static-library.patch +0 -26
- data/patches/0002-Don-t-compile-unnecessary-stuff.patch +0 -85
- data/patches/0003-Use-the-fPIC-flag-for-the-static-library.patch +0 -25
- data/patches/0004-Do-not-embed-debug-symbols-in-macOS-libraries.patch +0 -25
- data/patches/0005-Remove-TryInstallOptimizedCode.patch +0 -321
- data/patches/mingw-generate-makefiles.sh +0 -97
- data/spec/compiler/apple_llvm_spec.rb +0 -37
- data/spec/compiler/clang_spec.rb +0 -37
- data/spec/compiler/gcc_spec.rb +0 -37
- data/spec/compiler/generic_compiler_spec.rb +0 -50
- data/spec/compiler_spec.rb +0 -45
- data/spec/support/compiler_helpers.rb +0 -47
- data/vendor/depot_tools/apply_issue +0 -8
- data/vendor/depot_tools/apply_issue.py +0 -315
- data/vendor/depot_tools/man/html/git-cherry-pick-upload.html +0 -815
- data/vendor/depot_tools/man/man1/git-cherry-pick-upload.1 +0 -80
- data/vendor/depot_tools/man/src/_git-cherry-pick-upload_desc.helper.txt +0 -1
- data/vendor/depot_tools/man/src/git-cherry-pick-upload.demo.1.sh +0 -17
- data/vendor/depot_tools/man/src/git-cherry-pick-upload.txt +0 -35
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/trychange_oauth2.json +0 -8
- data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/trychange_oauth2_json_win.json +0 -196
- data/vendor/depot_tools/recipes/recipe_modules/rietveld/__init__.py +0 -6
- data/vendor/depot_tools/recipes/recipe_modules/rietveld/api.py +0 -97
- data/vendor/depot_tools/recipes/recipe_modules/rietveld/examples/full.expected/basic.json +0 -8
- data/vendor/depot_tools/recipes/recipe_modules/rietveld/examples/full.expected/buildbot.json +0 -30
- data/vendor/depot_tools/recipes/recipe_modules/rietveld/examples/full.expected/no_auth.json +0 -27
- data/vendor/depot_tools/recipes/recipe_modules/rietveld/examples/full.py +0 -38
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_rietveld_patch.json +0 -69
- data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_rietveld_patch_new.json +0 -69
- data/vendor/depot_tools/third_party/cq_client/OWNERS +0 -2
- data/vendor/depot_tools/third_party/cq_client/README.depot_tools.md +0 -2
- data/vendor/depot_tools/third_party/cq_client/README.md +0 -59
- data/vendor/depot_tools/third_party/cq_client/__init__.py +0 -3
- data/vendor/depot_tools/third_party/cq_client/v1/__init__.py +0 -3
- data/vendor/depot_tools/third_party/cq_client/v1/cq.pb.go +0 -810
- data/vendor/depot_tools/third_party/cq_client/v1/cq.proto +0 -281
- data/vendor/depot_tools/third_party/cq_client/v1/cq_pb2.py +0 -794
- data/vendor/depot_tools/third_party/cq_client/v1/testdata/cq_both.cfg +0 -71
- data/vendor/depot_tools/third_party/cq_client/v1/testdata/cq_gerrit.cfg +0 -58
- data/vendor/depot_tools/third_party/cq_client/v1/testdata/cq_rietveld.cfg +0 -60
- data/vendor/depot_tools/third_party/cq_client/v2/__init__.py +0 -3
- data/vendor/depot_tools/third_party/cq_client/v2/cq.pb.go +0 -792
- data/vendor/depot_tools/third_party/cq_client/v2/cq.proto +0 -270
- data/vendor/depot_tools/third_party/cq_client/v2/cq_pb2.py +0 -841
@@ -11,11 +11,10 @@ so you may need approval from both an OWNER and a reviewer in many cases.
|
|
11
11
|
|
12
12
|
The syntax of the OWNERS file is, roughly:
|
13
13
|
|
14
|
-
lines := (\s* line? \s* "\n")*
|
14
|
+
lines := (\s* line? \s* comment? \s* "\n")*
|
15
15
|
|
16
16
|
line := directive
|
17
17
|
| "per-file" \s+ glob \s* "=" \s* directive
|
18
|
-
| comment
|
19
18
|
|
20
19
|
directive := "set noparent"
|
21
20
|
| "file:" glob
|
@@ -276,6 +275,12 @@ class Database(object):
|
|
276
275
|
previous_line_was_blank = True
|
277
276
|
continue
|
278
277
|
|
278
|
+
# If the line ends with a comment, strip the comment and store it for this
|
279
|
+
# line only.
|
280
|
+
line, _, line_comment = line.partition('#')
|
281
|
+
line = line.strip()
|
282
|
+
line_comment = [line_comment.strip()] if line_comment else []
|
283
|
+
|
279
284
|
previous_line_was_blank = False
|
280
285
|
if line == 'set noparent':
|
281
286
|
self._stop_looking.add(dirpath)
|
@@ -292,7 +297,7 @@ class Database(object):
|
|
292
297
|
line)
|
293
298
|
relative_glob_string = self.os_path.relpath(full_glob_string, self.root)
|
294
299
|
self._add_entry(relative_glob_string, directive, owners_path,
|
295
|
-
lineno, '\n'.join(comment))
|
300
|
+
lineno, '\n'.join(comment + line_comment))
|
296
301
|
if reset_comment_after_use:
|
297
302
|
comment = []
|
298
303
|
continue
|
@@ -302,7 +307,7 @@ class Database(object):
|
|
302
307
|
'unknown option: "%s"' % line[4:].strip())
|
303
308
|
|
304
309
|
self._add_entry(dirpath, line, owners_path, lineno,
|
305
|
-
' '.join(comment))
|
310
|
+
' '.join(comment + line_comment))
|
306
311
|
if reset_comment_after_use:
|
307
312
|
comment = []
|
308
313
|
|
@@ -22,7 +22,7 @@ class OwnersFinder(object):
|
|
22
22
|
|
23
23
|
indentation = 0
|
24
24
|
|
25
|
-
def __init__(self, files, local_root, author,
|
25
|
+
def __init__(self, files, local_root, author, reviewers,
|
26
26
|
fopen, os_path,
|
27
27
|
email_postfix='@chromium.org',
|
28
28
|
disable_color=False,
|
@@ -45,9 +45,13 @@ class OwnersFinder(object):
|
|
45
45
|
|
46
46
|
filtered_files = files
|
47
47
|
|
48
|
-
|
48
|
+
reviewers = list(reviewers)
|
49
|
+
if author:
|
50
|
+
reviewers.append(author)
|
51
|
+
|
52
|
+
# Eliminate files that existing reviewers can review.
|
49
53
|
filtered_files = list(self.db.files_not_covered_by(
|
50
|
-
|
54
|
+
filtered_files, reviewers))
|
51
55
|
|
52
56
|
# If some files are eliminated.
|
53
57
|
if len(filtered_files) != len(files):
|
@@ -0,0 +1,322 @@
|
|
1
|
+
# Copyright (c) 2018 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
|
+
"""Summarize the last ninja build, invoked with ninja's -C syntax.
|
6
|
+
|
7
|
+
This script is designed to be automatically run after each ninja build in
|
8
|
+
order to summarize the build's performance. Making build performance information
|
9
|
+
more visible should make it easier to notice anomalies and opportunities. To use
|
10
|
+
this script on Windows just set NINJA_SUMMARIZE_BUILD=1 and run autoninja.bat.
|
11
|
+
|
12
|
+
On Linux you can get autoninja to invoke this script using this syntax:
|
13
|
+
|
14
|
+
$ NINJA_SUMMARIZE_BUILD=1 autoninja -C out/Default/ chrome
|
15
|
+
|
16
|
+
You can also call this script directly using ninja's syntax to specify the
|
17
|
+
output directory of interest:
|
18
|
+
|
19
|
+
> python post_build_ninja_summary.py -C out/Default
|
20
|
+
|
21
|
+
Typical output looks like this:
|
22
|
+
|
23
|
+
>ninja -C out\debug_component base
|
24
|
+
ninja.exe -C out\debug_component base -j 960 -l 48 -d keeprsp
|
25
|
+
ninja: Entering directory `out\debug_component'
|
26
|
+
[1 processes, 1/1 @ 0.3/s : 3.092s ] Regenerating ninja files
|
27
|
+
[1 processes, 23/23 @ 0.9/s : 26.280s ] LINK(DLL) base.dll base.dll.lib
|
28
|
+
Longest build steps:
|
29
|
+
0.9 weighted s to build obj/base/base_jumbo_17.obj (5.0 s CPU time)
|
30
|
+
1.0 weighted s to build obj/base/base_jumbo_31.obj (13.1 s CPU time)
|
31
|
+
1.2 weighted s to build obj/base/base_jumbo_4.obj (14.7 s CPU time)
|
32
|
+
1.3 weighted s to build obj/base/base_jumbo_32.obj (15.0 s CPU time)
|
33
|
+
1.6 weighted s to build obj/base/base_jumbo_26.obj (17.1 s CPU time)
|
34
|
+
1.7 weighted s to build base.dll, base.dll.lib (1.7 s CPU time)
|
35
|
+
1.7 weighted s to build obj/base/base_jumbo_11.obj (15.9 s CPU time)
|
36
|
+
1.9 weighted s to build obj/base/base_jumbo_12.obj (18.5 s CPU time)
|
37
|
+
3.6 weighted s to build obj/base/base_jumbo_34.obj (20.1 s CPU time)
|
38
|
+
4.3 weighted s to build obj/base/base_jumbo_33.obj (22.3 s CPU time)
|
39
|
+
Time by build-step type:
|
40
|
+
0.1 s weighted time to generate 1 .c files (0.1 s CPU time)
|
41
|
+
0.1 s weighted time to generate 1 .stamp files (0.1 s CPU time)
|
42
|
+
0.2 s weighted time to generate 1 .h files (0.2 s CPU time)
|
43
|
+
1.7 s weighted time to generate 1 PEFile files (1.7 s CPU time)
|
44
|
+
24.3 s weighted time to generate 19 .obj files (233.4 s CPU time)
|
45
|
+
26.3 s weighted time (235.5 s CPU time, 9.0x parallelism)
|
46
|
+
23 build steps completed, average of 0.88/s
|
47
|
+
|
48
|
+
If no gn clean has been done then results will be for the last non-NULL
|
49
|
+
invocation of ninja. Ideas for future statistics, and implementations are
|
50
|
+
appreciated.
|
51
|
+
|
52
|
+
The "weighted" time is the elapsed time of each build step divided by the number
|
53
|
+
of tasks that were running in parallel. This makes it an excellent approximation
|
54
|
+
of how "important" a slow step was. A link that is entirely or mostly serialized
|
55
|
+
will have a weighted time that is the same or similar to its elapsed time. A
|
56
|
+
compile that runs in parallel with 999 other compiles will have a weighted time
|
57
|
+
that is tiny."""
|
58
|
+
|
59
|
+
import argparse
|
60
|
+
import errno
|
61
|
+
import os
|
62
|
+
import sys
|
63
|
+
|
64
|
+
|
65
|
+
# The number of long build times to report:
|
66
|
+
long_count = 10
|
67
|
+
# The number of long times by extension to report
|
68
|
+
long_ext_count = 5
|
69
|
+
|
70
|
+
|
71
|
+
class Target:
|
72
|
+
"""Represents a single line read for a .ninja_log file."""
|
73
|
+
def __init__(self, start, end):
|
74
|
+
"""Creates a target object by passing in the start/end times in seconds
|
75
|
+
as a float."""
|
76
|
+
self.start = start
|
77
|
+
self.end = end
|
78
|
+
# A list of targets, appended to by the owner of this object.
|
79
|
+
self.targets = []
|
80
|
+
self.weighted_duration = 0.0
|
81
|
+
|
82
|
+
def Duration(self):
|
83
|
+
"""Returns the task duration in seconds as a float."""
|
84
|
+
return self.end - self.start
|
85
|
+
|
86
|
+
def SetWeightedDuration(self, weighted_duration):
|
87
|
+
"""Sets the duration, in seconds, passed in as a float."""
|
88
|
+
self.weighted_duration = weighted_duration
|
89
|
+
|
90
|
+
def WeightedDuration(self):
|
91
|
+
"""Returns the task's weighted duration in seconds as a float.
|
92
|
+
|
93
|
+
Weighted_duration takes the elapsed time of the task and divides it
|
94
|
+
by how many other tasks were running at the same time. Thus, it
|
95
|
+
represents the approximate impact of this task on the total build time,
|
96
|
+
with serialized or serializing steps typically ending up with much
|
97
|
+
longer weighted durations.
|
98
|
+
weighted_duration should always be the same or shorter than duration.
|
99
|
+
"""
|
100
|
+
# Allow for modest floating-point errors
|
101
|
+
epsilon = 0.000002
|
102
|
+
if (self.weighted_duration > self.Duration() + epsilon):
|
103
|
+
print '%s > %s?' % (self.weighted_duration, self.Duration())
|
104
|
+
assert(self.weighted_duration <= self.Duration() + epsilon)
|
105
|
+
return self.weighted_duration
|
106
|
+
|
107
|
+
def DescribeTargets(self):
|
108
|
+
"""Returns a printable string that summarizes the targets."""
|
109
|
+
if len(self.targets) == 1:
|
110
|
+
return self.targets[0]
|
111
|
+
# Some build steps generate dozens of outputs - handle them sanely.
|
112
|
+
# It's a bit odd that if there are three targets we return all three
|
113
|
+
# but if there are more than three we just return two, but this works
|
114
|
+
# well in practice.
|
115
|
+
elif len(self.targets) > 3:
|
116
|
+
return '(%d items) ' % len(self.targets) + (
|
117
|
+
', '.join(self.targets[:2]) + ', ...')
|
118
|
+
else:
|
119
|
+
return ', '.join(self.targets)
|
120
|
+
|
121
|
+
|
122
|
+
# Copied with some modifications from ninjatracing
|
123
|
+
def ReadTargets(log, show_all):
|
124
|
+
"""Reads all targets from .ninja_log file |log_file|, sorted by duration.
|
125
|
+
|
126
|
+
The result is a list of Target objects."""
|
127
|
+
header = log.readline()
|
128
|
+
assert header == '# ninja log v5\n', \
|
129
|
+
'unrecognized ninja log version %r' % header
|
130
|
+
targets_dict = {}
|
131
|
+
last_end_seen = 0.0
|
132
|
+
for line in log:
|
133
|
+
parts = line.strip().split('\t')
|
134
|
+
if len(parts) != 5:
|
135
|
+
# If ninja.exe is rudely halted then the .ninja_log file may be
|
136
|
+
# corrupt. Silently continue.
|
137
|
+
continue
|
138
|
+
start, end, _, name, cmdhash = parts # Ignore restat.
|
139
|
+
# Convert from integral milliseconds to float seconds.
|
140
|
+
start = int(start) / 1000.0
|
141
|
+
end = int(end) / 1000.0
|
142
|
+
if not show_all and end < last_end_seen:
|
143
|
+
# An earlier time stamp means that this step is the first in a new
|
144
|
+
# build, possibly an incremental build. Throw away the previous
|
145
|
+
# data so that this new build will be displayed independently.
|
146
|
+
# This has to be done by comparing end times because records are
|
147
|
+
# written to the .ninja_log file when commands complete, so end
|
148
|
+
# times are guaranteed to be in order, but start times are not.
|
149
|
+
targets_dict = {}
|
150
|
+
target = None
|
151
|
+
if cmdhash in targets_dict:
|
152
|
+
target = targets_dict[cmdhash]
|
153
|
+
if not show_all and (target.start != start or target.end != end):
|
154
|
+
# If several builds in a row just run one or two build steps then
|
155
|
+
# the end times may not go backwards so the last build may not be
|
156
|
+
# detected as such. However in many cases there will be a build step
|
157
|
+
# repeated in the two builds and the changed start/stop points for
|
158
|
+
# that command, identified by the hash, can be used to detect and
|
159
|
+
# reset the target dictionary.
|
160
|
+
targets_dict = {}
|
161
|
+
target = None
|
162
|
+
if not target:
|
163
|
+
targets_dict[cmdhash] = target = Target(start, end)
|
164
|
+
last_end_seen = end
|
165
|
+
target.targets.append(name)
|
166
|
+
return targets_dict.values()
|
167
|
+
|
168
|
+
|
169
|
+
def GetExtension(target):
|
170
|
+
"""Return the file extension that best represents a target.
|
171
|
+
|
172
|
+
For targets that generate multiple outputs it is important to return a
|
173
|
+
consistent 'canonical' extension. Ultimately the goal is to group build steps
|
174
|
+
by type."""
|
175
|
+
for output in target.targets:
|
176
|
+
# Normalize all mojo related outputs to 'mojo'.
|
177
|
+
if output.count('.mojom') > 0:
|
178
|
+
extension = 'mojo'
|
179
|
+
break
|
180
|
+
# Not a true extension, but a good grouping.
|
181
|
+
if output.endswith('type_mappings'):
|
182
|
+
extension = 'type_mappings'
|
183
|
+
break
|
184
|
+
extension = os.path.splitext(output)[1]
|
185
|
+
if len(extension) == 0:
|
186
|
+
extension = '(no extension found)'
|
187
|
+
if extension in ['.pdb', '.dll', '.exe']:
|
188
|
+
extension = 'PEFile (linking)'
|
189
|
+
# Make sure that .dll and .exe are grouped together and that the
|
190
|
+
# .dll.lib files don't cause these to be listed as libraries
|
191
|
+
break
|
192
|
+
if extension in ['.so', '.TOC']:
|
193
|
+
extension = '.so (linking)'
|
194
|
+
# Attempt to identify linking, avoid identifying as '.TOC'
|
195
|
+
break
|
196
|
+
return extension
|
197
|
+
|
198
|
+
|
199
|
+
def SummarizeEntries(entries):
|
200
|
+
"""Print a summary of the passed in list of Target objects."""
|
201
|
+
|
202
|
+
# Create a list that is in order by time stamp and has entries for the
|
203
|
+
# beginning and ending of each build step (one time stamp may have multiple
|
204
|
+
# entries due to multiple steps starting/stopping at exactly the same time).
|
205
|
+
# Iterate through this list, keeping track of which tasks are running at all
|
206
|
+
# times. At each time step calculate a running total for weighted time so
|
207
|
+
# that when each task ends its own weighted time can easily be calculated.
|
208
|
+
task_start_stop_times = []
|
209
|
+
|
210
|
+
earliest = -1
|
211
|
+
latest = 0
|
212
|
+
total_cpu_time = 0
|
213
|
+
for target in entries:
|
214
|
+
if earliest < 0 or target.start < earliest:
|
215
|
+
earliest = target.start
|
216
|
+
if target.end > latest:
|
217
|
+
latest = target.end
|
218
|
+
total_cpu_time += target.Duration()
|
219
|
+
task_start_stop_times.append((target.start, 'start', target))
|
220
|
+
task_start_stop_times.append((target.end, 'stop', target))
|
221
|
+
length = latest - earliest
|
222
|
+
weighted_total = 0.0
|
223
|
+
|
224
|
+
task_start_stop_times.sort()
|
225
|
+
# Now we have all task start/stop times sorted by when they happen. If a
|
226
|
+
# task starts and stops on the same time stamp then the start will come
|
227
|
+
# first because of the alphabet, which is important for making this work
|
228
|
+
# correctly.
|
229
|
+
# Track the tasks which are currently running.
|
230
|
+
running_tasks = {}
|
231
|
+
# Record the time we have processed up to so we know how to calculate time
|
232
|
+
# deltas.
|
233
|
+
last_time = task_start_stop_times[0][0]
|
234
|
+
# Track the accumulated weighted time so that it can efficiently be added
|
235
|
+
# to individual tasks.
|
236
|
+
last_weighted_time = 0.0
|
237
|
+
# Scan all start/stop events.
|
238
|
+
for event in task_start_stop_times:
|
239
|
+
time, action_name, target = event
|
240
|
+
# Accumulate weighted time up to now.
|
241
|
+
num_running = len(running_tasks)
|
242
|
+
if num_running > 0:
|
243
|
+
# Update the total weighted time up to this moment.
|
244
|
+
last_weighted_time += (time - last_time) / float(num_running)
|
245
|
+
if action_name == 'start':
|
246
|
+
# Record the total weighted task time when this task starts.
|
247
|
+
running_tasks[target] = last_weighted_time
|
248
|
+
if action_name == 'stop':
|
249
|
+
# Record the change in the total weighted task time while this task ran.
|
250
|
+
weighted_duration = last_weighted_time - running_tasks[target]
|
251
|
+
target.SetWeightedDuration(weighted_duration)
|
252
|
+
weighted_total += weighted_duration
|
253
|
+
del running_tasks[target]
|
254
|
+
last_time = time
|
255
|
+
assert(len(running_tasks) == 0)
|
256
|
+
|
257
|
+
# Warn if the sum of weighted times is off by more than half a second.
|
258
|
+
if abs(length - weighted_total) > 500:
|
259
|
+
print 'Discrepancy!!! Length = %.3f, weighted total = %.3f' % (
|
260
|
+
length, weighted_total)
|
261
|
+
|
262
|
+
# Print the slowest build steps (by weighted time).
|
263
|
+
print ' Longest build steps:'
|
264
|
+
entries.sort(key=lambda x: x.WeightedDuration())
|
265
|
+
for target in entries[-long_count:]:
|
266
|
+
print ' %8.1f weighted s to build %s (%.1f s CPU time)' % (
|
267
|
+
target.WeightedDuration(),
|
268
|
+
target.DescribeTargets(), target.Duration())
|
269
|
+
|
270
|
+
# Sum up the time by file extension/type of the output file
|
271
|
+
count_by_ext = {}
|
272
|
+
time_by_ext = {}
|
273
|
+
weighted_time_by_ext = {}
|
274
|
+
# Scan through all of the targets to build up per-extension statistics.
|
275
|
+
for target in entries:
|
276
|
+
extension = GetExtension(target)
|
277
|
+
time_by_ext[extension] = time_by_ext.get(extension, 0) + target.Duration()
|
278
|
+
weighted_time_by_ext[extension] = weighted_time_by_ext.get(extension,
|
279
|
+
0) + target.WeightedDuration()
|
280
|
+
count_by_ext[extension] = count_by_ext.get(extension, 0) + 1
|
281
|
+
|
282
|
+
print ' Time by build-step type:'
|
283
|
+
# Copy to a list with extension name and total time swapped, to (time, ext)
|
284
|
+
weighted_time_by_ext_sorted = sorted((y, x) for (x, y) in
|
285
|
+
weighted_time_by_ext.items())
|
286
|
+
# Print the slowest build target types (by weighted time):
|
287
|
+
for time, extension in weighted_time_by_ext_sorted[-long_ext_count:]:
|
288
|
+
print (' %8.1f s weighted time to generate %d %s files '
|
289
|
+
'(%1.1f s CPU time)') % (time, count_by_ext[extension],
|
290
|
+
extension, time_by_ext[extension])
|
291
|
+
|
292
|
+
print ' %.1f s weighted time (%.1f s CPU time, %1.1fx parallelism)' % (
|
293
|
+
length, total_cpu_time,
|
294
|
+
total_cpu_time * 1.0 / length)
|
295
|
+
print ' %d build steps completed, average of %1.2f/s' % (
|
296
|
+
len(entries), len(entries) / (length))
|
297
|
+
|
298
|
+
|
299
|
+
def main():
|
300
|
+
log_file = '.ninja_log'
|
301
|
+
parser = argparse.ArgumentParser()
|
302
|
+
parser.add_argument('-C', dest='build_directory',
|
303
|
+
help='Build directory.')
|
304
|
+
parser.add_argument('--log-file',
|
305
|
+
help="specific ninja log file to analyze.")
|
306
|
+
args, _extra_args = parser.parse_known_args()
|
307
|
+
if args.build_directory:
|
308
|
+
log_file = os.path.join(args.build_directory, log_file)
|
309
|
+
if args.log_file:
|
310
|
+
log_file = args.log_file
|
311
|
+
|
312
|
+
try:
|
313
|
+
with open(log_file, 'r') as log:
|
314
|
+
entries = ReadTargets(log, False)
|
315
|
+
SummarizeEntries(entries)
|
316
|
+
except IOError:
|
317
|
+
print 'Log file %r not found, no build summary created.' % log_file
|
318
|
+
return errno.ENOENT
|
319
|
+
|
320
|
+
|
321
|
+
if __name__ == '__main__':
|
322
|
+
sys.exit(main())
|
@@ -80,7 +80,7 @@ def CheckChangeWasUploaded(input_api, output_api):
|
|
80
80
|
|
81
81
|
### Content checks
|
82
82
|
|
83
|
-
def CheckAuthorizedAuthor(input_api, output_api):
|
83
|
+
def CheckAuthorizedAuthor(input_api, output_api, bot_whitelist=None):
|
84
84
|
"""For non-googler/chromites committers, verify the author's email address is
|
85
85
|
in AUTHORS.
|
86
86
|
"""
|
@@ -93,6 +93,11 @@ def CheckAuthorizedAuthor(input_api, output_api):
|
|
93
93
|
if not author:
|
94
94
|
input_api.logging.info('No author, skipping AUTHOR check')
|
95
95
|
return []
|
96
|
+
|
97
|
+
# This is used for CLs created by trusted robot accounts.
|
98
|
+
if bot_whitelist and author in bot_whitelist:
|
99
|
+
return []
|
100
|
+
|
96
101
|
authors_path = input_api.os_path.join(
|
97
102
|
input_api.PresubmitLocalPath(), 'AUTHORS')
|
98
103
|
valid_authors = (
|
@@ -528,11 +533,7 @@ def GetUnitTests(input_api, output_api, unit_tests, env=None):
|
|
528
533
|
|
529
534
|
results = []
|
530
535
|
for unit_test in unit_tests:
|
531
|
-
cmd = []
|
532
|
-
if input_api.platform == 'win32' and unit_test.endswith('.py'):
|
533
|
-
# Windows needs some help.
|
534
|
-
cmd = [input_api.python_executable]
|
535
|
-
cmd.append(unit_test)
|
536
|
+
cmd = [unit_test]
|
536
537
|
if input_api.verbose:
|
537
538
|
cmd.append('--verbose')
|
538
539
|
kwargs = {'cwd': input_api.PresubmitLocalPath()}
|
@@ -611,6 +612,7 @@ def GetPythonUnitTests(input_api, output_api, unit_tests):
|
|
611
612
|
if env.get('PYTHONPATH'):
|
612
613
|
backpath.append(env.get('PYTHONPATH'))
|
613
614
|
env['PYTHONPATH'] = input_api.os_path.pathsep.join((backpath))
|
615
|
+
env.pop('VPYTHON_CLEAR_PYTHONPATH', None)
|
614
616
|
cmd = [input_api.python_executable, '-m', '%s' % unit_test]
|
615
617
|
results.append(input_api.Command(
|
616
618
|
name=unit_test_name,
|
@@ -730,12 +732,11 @@ def GetPylint(input_api, output_api, white_list=None, black_list=None,
|
|
730
732
|
|
731
733
|
input_api.logging.info('Running pylint on %d files', len(files))
|
732
734
|
input_api.logging.debug('Running pylint on: %s', files)
|
733
|
-
# Copy the system path to the environment so pylint can find the right
|
734
|
-
# imports.
|
735
735
|
env = input_api.environ.copy()
|
736
|
-
import sys
|
737
736
|
env['PYTHONPATH'] = input_api.os_path.pathsep.join(
|
738
|
-
|
737
|
+
extra_paths_list).encode('utf8')
|
738
|
+
env.pop('VPYTHON_CLEAR_PYTHONPATH', None)
|
739
|
+
input_api.logging.debug(' with extra PYTHONPATH: %r', extra_paths_list)
|
739
740
|
|
740
741
|
def GetPylintCmd(flist, extra, parallel):
|
741
742
|
# Windows needs help running python files so we explicitly specify
|
@@ -797,15 +798,6 @@ def RunPylint(input_api, *args, **kwargs):
|
|
797
798
|
return input_api.RunTests(GetPylint(input_api, *args, **kwargs), False)
|
798
799
|
|
799
800
|
|
800
|
-
def CheckRietveldTryJobExecution(dummy_input_api, output_api,
|
801
|
-
dummy_host_url, dummy_platforms,
|
802
|
-
dummy_owner):
|
803
|
-
return [
|
804
|
-
output_api.PresubmitNotifyResult(
|
805
|
-
'CheckRietveldTryJobExecution is deprecated, please remove it.')
|
806
|
-
]
|
807
|
-
|
808
|
-
|
809
801
|
def CheckBuildbotPendingBuilds(input_api, output_api, url, max_pendings,
|
810
802
|
ignored):
|
811
803
|
try:
|
@@ -839,9 +831,29 @@ def CheckBuildbotPendingBuilds(input_api, output_api, url, max_pendings,
|
|
839
831
|
return []
|
840
832
|
|
841
833
|
|
834
|
+
def CheckOwnersFormat(input_api, output_api):
|
835
|
+
affected_files = set([
|
836
|
+
f.LocalPath()
|
837
|
+
for f in input_api.change.AffectedFiles()
|
838
|
+
if 'OWNERS' in f.LocalPath() and f.Action() != 'D'
|
839
|
+
])
|
840
|
+
if not affected_files:
|
841
|
+
return []
|
842
|
+
try:
|
843
|
+
input_api.owners_db.load_data_needed_for(affected_files)
|
844
|
+
return []
|
845
|
+
except Exception as e:
|
846
|
+
return [output_api.PresubmitError(
|
847
|
+
'Error parsing OWNERS files:\n%s' % e)]
|
848
|
+
|
849
|
+
|
842
850
|
def CheckOwners(input_api, output_api, source_file_filter=None):
|
851
|
+
affected_files = set([f.LocalPath() for f in
|
852
|
+
input_api.change.AffectedFiles(file_filter=source_file_filter)])
|
853
|
+
affects_owners = any('OWNERS' in name for name in affected_files)
|
854
|
+
|
843
855
|
if input_api.is_committing:
|
844
|
-
if input_api.tbr:
|
856
|
+
if input_api.tbr and not affects_owners:
|
845
857
|
return [output_api.PresubmitNotifyResult(
|
846
858
|
'--tbr was specified, skipping OWNERS check')]
|
847
859
|
needed = 'LGTM from an OWNER'
|
@@ -852,15 +864,13 @@ def CheckOwners(input_api, output_api, source_file_filter=None):
|
|
852
864
|
'This is a dry run, but these failures would be reported on ' +
|
853
865
|
'commit:\n' + text)
|
854
866
|
else:
|
855
|
-
return [output_api.PresubmitError(
|
856
|
-
|
867
|
+
return [output_api.PresubmitError(
|
868
|
+
'OWNERS check failed: this CL has no Gerrit change number, '
|
869
|
+
'so we can\'t check it for approvals.')]
|
857
870
|
else:
|
858
871
|
needed = 'OWNER reviewers'
|
859
872
|
output_fn = output_api.PresubmitNotifyResult
|
860
873
|
|
861
|
-
affected_files = set([f.LocalPath() for f in
|
862
|
-
input_api.change.AffectedFiles(file_filter=source_file_filter)])
|
863
|
-
|
864
874
|
owners_db = input_api.owners_db
|
865
875
|
owners_db.override_files = input_api.change.OriginalOwnersFiles()
|
866
876
|
owner_email, reviewers = GetCodereviewOwnerAndReviewers(
|
@@ -870,24 +880,22 @@ def CheckOwners(input_api, output_api, source_file_filter=None):
|
|
870
880
|
|
871
881
|
owner_email = owner_email or input_api.change.author_email
|
872
882
|
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
883
|
+
finder = input_api.owners_finder(
|
884
|
+
affected_files, input_api.change.RepositoryRoot(),
|
885
|
+
owner_email, reviewers, fopen=file, os_path=input_api.os_path,
|
886
|
+
email_postfix='', disable_color=True,
|
887
|
+
override_files=input_api.change.OriginalOwnersFiles())
|
888
|
+
missing_files = finder.unreviewed_files
|
879
889
|
|
880
890
|
if missing_files:
|
881
891
|
output_list = [
|
882
892
|
output_fn('Missing %s for these files:\n %s' %
|
883
893
|
(needed, '\n '.join(sorted(missing_files))))]
|
894
|
+
if input_api.tbr and affects_owners:
|
895
|
+
output_list.append(output_fn('Note that TBR does not apply to changes '
|
896
|
+
'that affect OWNERS files.'))
|
884
897
|
if not input_api.is_committing:
|
885
898
|
suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
|
886
|
-
finder = input_api.owners_finder(
|
887
|
-
missing_files, input_api.change.RepositoryRoot(),
|
888
|
-
owner_email, fopen=file, os_path=input_api.os_path,
|
889
|
-
email_postfix='', disable_color=True,
|
890
|
-
override_files=input_api.change.OriginalOwnersFiles())
|
891
899
|
owners_with_comments = []
|
892
900
|
def RecordComments(text):
|
893
901
|
owners_with_comments.append(finder.print_indent() + text)
|
@@ -903,25 +911,25 @@ def CheckOwners(input_api, output_api, source_file_filter=None):
|
|
903
911
|
return [output_fn('Missing LGTM from someone other than %s' % owner_email)]
|
904
912
|
return []
|
905
913
|
|
914
|
+
|
906
915
|
def GetCodereviewOwnerAndReviewers(input_api, email_regexp, approval_needed):
|
907
916
|
"""Return the owner and reviewers of a change, if any.
|
908
917
|
|
909
918
|
If approval_needed is True, only reviewers who have approved the change
|
910
919
|
will be returned.
|
911
920
|
"""
|
912
|
-
# Rietveld is default.
|
913
|
-
func = _RietveldOwnerAndReviewers
|
914
|
-
if input_api.gerrit:
|
915
|
-
func = _GerritOwnerAndReviewers
|
916
|
-
return func(input_api, email_regexp, approval_needed)
|
917
|
-
|
918
|
-
|
919
|
-
def _GetRietveldIssueProps(input_api, messages):
|
920
|
-
"""Gets the issue properties from rietveld."""
|
921
921
|
issue = input_api.change.issue
|
922
|
-
if issue
|
923
|
-
return
|
924
|
-
|
922
|
+
if not issue:
|
923
|
+
return None, (set() if approval_needed else
|
924
|
+
_ReviewersFromChange(input_api.change))
|
925
|
+
|
926
|
+
owner_email = input_api.gerrit.GetChangeOwner(issue)
|
927
|
+
reviewers = set(
|
928
|
+
r for r in input_api.gerrit.GetChangeReviewers(issue, approval_needed)
|
929
|
+
if _match_reviewer_email(r, owner_email, email_regexp))
|
930
|
+
input_api.logging.debug('owner: %s; approvals given by: %s',
|
931
|
+
owner_email, ', '.join(sorted(reviewers)))
|
932
|
+
return owner_email, reviewers
|
925
933
|
|
926
934
|
|
927
935
|
def _ReviewersFromChange(change):
|
@@ -937,49 +945,6 @@ def _ReviewersFromChange(change):
|
|
937
945
|
def _match_reviewer_email(r, owner_email, email_regexp):
|
938
946
|
return email_regexp.match(r) and r != owner_email
|
939
947
|
|
940
|
-
def _RietveldOwnerAndReviewers(input_api, email_regexp, approval_needed=False):
|
941
|
-
"""Return the owner and reviewers of a change, if any.
|
942
|
-
|
943
|
-
If approval_needed is True, only reviewers who have approved the change
|
944
|
-
will be returned.
|
945
|
-
"""
|
946
|
-
issue_props = _GetRietveldIssueProps(input_api, True)
|
947
|
-
if not issue_props:
|
948
|
-
return None, (set() if approval_needed else
|
949
|
-
_ReviewersFromChange(input_api.change))
|
950
|
-
|
951
|
-
if not approval_needed:
|
952
|
-
return issue_props['owner_email'], set(issue_props['reviewers'])
|
953
|
-
|
954
|
-
owner_email = issue_props['owner_email']
|
955
|
-
|
956
|
-
messages = issue_props.get('messages', [])
|
957
|
-
approvers = set(
|
958
|
-
m['sender'] for m in messages
|
959
|
-
if m.get('approval') and _match_reviewer_email(m['sender'], owner_email,
|
960
|
-
email_regexp))
|
961
|
-
return owner_email, approvers
|
962
|
-
|
963
|
-
|
964
|
-
def _GerritOwnerAndReviewers(input_api, email_regexp, approval_needed=False):
|
965
|
-
"""Return the owner and reviewers of a change, if any.
|
966
|
-
|
967
|
-
If approval_needed is True, only reviewers who have approved the change
|
968
|
-
will be returned.
|
969
|
-
"""
|
970
|
-
issue = input_api.change.issue
|
971
|
-
if not issue:
|
972
|
-
return None, (set() if approval_needed else
|
973
|
-
_ReviewersFromChange(input_api.change))
|
974
|
-
|
975
|
-
owner_email = input_api.gerrit.GetChangeOwner(issue)
|
976
|
-
reviewers = set(
|
977
|
-
r for r in input_api.gerrit.GetChangeReviewers(issue, approval_needed)
|
978
|
-
if _match_reviewer_email(r, owner_email, email_regexp))
|
979
|
-
input_api.logging.debug('owner: %s; approvals given by: %s',
|
980
|
-
owner_email, ', '.join(sorted(reviewers)))
|
981
|
-
return owner_email, reviewers
|
982
|
-
|
983
948
|
|
984
949
|
def CheckSingletonInHeaders(input_api, output_api, source_file_filter=None):
|
985
950
|
"""Deprecated, must be removed."""
|
@@ -1057,6 +1022,10 @@ def PanProjectChecks(input_api, output_api,
|
|
1057
1022
|
print " %s took a long time: %dms" % (snapshot_memory[1], delta_ms)
|
1058
1023
|
snapshot_memory[:] = (dt2, msg)
|
1059
1024
|
|
1025
|
+
snapshot("checking owners files format")
|
1026
|
+
results.extend(input_api.canned_checks.CheckOwnersFormat(
|
1027
|
+
input_api, output_api))
|
1028
|
+
|
1060
1029
|
if owners_check:
|
1061
1030
|
snapshot("checking owners")
|
1062
1031
|
results.extend(input_api.canned_checks.CheckOwners(
|
@@ -1091,12 +1060,21 @@ def PanProjectChecks(input_api, output_api,
|
|
1091
1060
|
return results
|
1092
1061
|
|
1093
1062
|
|
1094
|
-
def CheckPatchFormatted(
|
1063
|
+
def CheckPatchFormatted(
|
1064
|
+
input_api, output_api, check_js=False, check_python=False,
|
1065
|
+
result_factory=None):
|
1066
|
+
result_factory = result_factory or output_api.PresubmitPromptWarning
|
1095
1067
|
import git_cl
|
1096
|
-
|
1097
|
-
|
1068
|
+
|
1069
|
+
display_args = []
|
1098
1070
|
if check_js:
|
1099
|
-
|
1071
|
+
display_args.append('--js')
|
1072
|
+
if check_python:
|
1073
|
+
# --python requires --full
|
1074
|
+
display_args.extend(['--python', '--full'])
|
1075
|
+
|
1076
|
+
cmd = ['-C', input_api.change.RepositoryRoot(),
|
1077
|
+
'cl', 'format', '--dry-run', '--presubmit'] + display_args
|
1100
1078
|
presubmit_subdir = input_api.os_path.relpath(
|
1101
1079
|
input_api.PresubmitLocalPath(), input_api.change.RepositoryRoot())
|
1102
1080
|
if presubmit_subdir.startswith('..') or presubmit_subdir == '.':
|
@@ -1112,10 +1090,11 @@ def CheckPatchFormatted(input_api, output_api, check_js=False):
|
|
1112
1090
|
short_path = presubmit_subdir
|
1113
1091
|
else:
|
1114
1092
|
short_path = input_api.basename(input_api.change.RepositoryRoot())
|
1115
|
-
|
1093
|
+
display_args.append(presubmit_subdir)
|
1094
|
+
return [result_factory(
|
1116
1095
|
'The %s directory requires source formatting. '
|
1117
|
-
'Please run: git cl format %s
|
1118
|
-
(short_path, '
|
1096
|
+
'Please run: git cl format %s' %
|
1097
|
+
(short_path, ' '.join(display_args)))]
|
1119
1098
|
# As this is just a warning, ignore all other errors if the user
|
1120
1099
|
# happens to have a broken clang-format, doesn't use git, etc etc.
|
1121
1100
|
return []
|
@@ -1217,7 +1196,7 @@ def CheckVPythonSpec(input_api, output_api, file_filter=None):
|
|
1217
1196
|
A list of input_api.Command objects containing verification commands.
|
1218
1197
|
"""
|
1219
1198
|
file_filter = file_filter or (lambda f: f.LocalPath().endswith('.vpython'))
|
1220
|
-
affected_files = input_api.
|
1199
|
+
affected_files = input_api.AffectedTestableFiles(file_filter=file_filter)
|
1221
1200
|
affected_files = map(lambda f: f.AbsoluteLocalPath(), affected_files)
|
1222
1201
|
|
1223
1202
|
commands = []
|
@@ -1235,6 +1214,7 @@ def CheckChangedLUCIConfigs(input_api, output_api):
|
|
1235
1214
|
import collections
|
1236
1215
|
import base64
|
1237
1216
|
import json
|
1217
|
+
import logging
|
1238
1218
|
import urllib2
|
1239
1219
|
|
1240
1220
|
import auth
|
@@ -1243,13 +1223,16 @@ def CheckChangedLUCIConfigs(input_api, output_api):
|
|
1243
1223
|
LUCI_CONFIG_HOST_NAME = 'luci-config.appspot.com'
|
1244
1224
|
|
1245
1225
|
cl = git_cl.Changelist()
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1226
|
+
if input_api.change.issue and input_api.gerrit:
|
1227
|
+
remote_branch = input_api.gerrit.GetDestRef(input_api.change.issue)
|
1228
|
+
else:
|
1229
|
+
remote, remote_branch = cl.GetRemoteBranch()
|
1230
|
+
if remote_branch.startswith('refs/remotes/%s/' % remote):
|
1231
|
+
remote_branch = remote_branch.replace(
|
1232
|
+
'refs/remotes/%s/' % remote, 'refs/heads/', 1)
|
1233
|
+
if remote_branch.startswith('refs/remotes/branch-heads/'):
|
1234
|
+
remote_branch = remote_branch.replace(
|
1235
|
+
'refs/remotes/branch-heads/', 'refs/branch-heads/', 1)
|
1253
1236
|
|
1254
1237
|
remote_host_url = cl.GetRemoteUrl()
|
1255
1238
|
if not remote_host_url:
|
@@ -1286,6 +1269,7 @@ def CheckChangedLUCIConfigs(input_api, output_api):
|
|
1286
1269
|
if not config_sets:
|
1287
1270
|
return [output_api.PresubmitWarning('No config_sets were returned')]
|
1288
1271
|
loc_pref = '%s/+/%s/' % (remote_host_url, remote_branch)
|
1272
|
+
logging.debug('Derived location prefix: %s', loc_pref)
|
1289
1273
|
dir_to_config_set = {
|
1290
1274
|
'%s/' % cs['location'][len(loc_pref):].rstrip('/'): cs['config_set']
|
1291
1275
|
for cs in config_sets
|
@@ -1296,6 +1280,7 @@ def CheckChangedLUCIConfigs(input_api, output_api):
|
|
1296
1280
|
for f in input_api.AffectedFiles():
|
1297
1281
|
# windows
|
1298
1282
|
file_path = f.LocalPath().replace(_os.sep, '/')
|
1283
|
+
logging.debug('Affected file path: %s', file_path)
|
1299
1284
|
for dr, cs in dir_to_config_set.iteritems():
|
1300
1285
|
if dr == '/' or file_path.startswith(dr):
|
1301
1286
|
cs_to_files[cs].append({
|