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.
Files changed (195) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +10 -34
  3. data/CHANGELOG.md +16 -0
  4. data/README.md +9 -63
  5. data/Rakefile +2 -2
  6. data/ext/libv8/builder.rb +22 -87
  7. data/ext/libv8/extconf.rb +1 -1
  8. data/ext/libv8/paths.rb +5 -18
  9. data/lib/libv8/version.rb +1 -1
  10. data/spec/location_spec.rb +1 -2
  11. data/spec/spec_helper.rb +0 -1
  12. data/vendor/depot_tools/.gitattributes +1 -2
  13. data/vendor/depot_tools/OWNERS +0 -1
  14. data/vendor/depot_tools/PRESUBMIT.py +11 -6
  15. data/vendor/depot_tools/README.md +0 -1
  16. data/vendor/depot_tools/WATCHLISTS +0 -6
  17. data/vendor/depot_tools/auth.py +129 -87
  18. data/vendor/depot_tools/autoninja +11 -1
  19. data/vendor/depot_tools/autoninja.bat +7 -1
  20. data/vendor/depot_tools/autoninja.py +14 -6
  21. data/vendor/depot_tools/bootstrap/win/manifest.txt +1 -1
  22. data/vendor/depot_tools/bootstrap/win/manifest_bleeding_edge.txt +1 -1
  23. data/vendor/depot_tools/cipd +23 -2
  24. data/vendor/depot_tools/cipd.bat +2 -2
  25. data/vendor/depot_tools/cipd_client_version +1 -1
  26. data/vendor/depot_tools/cipd_manifest.txt +17 -7
  27. data/vendor/depot_tools/cit.py +7 -6
  28. data/vendor/depot_tools/cpplint.py +195 -35
  29. data/vendor/depot_tools/detect_host_arch.py +51 -0
  30. data/vendor/depot_tools/download_from_google_storage.py +85 -26
  31. data/vendor/depot_tools/fetch.py +11 -6
  32. data/vendor/depot_tools/fetch_configs/chromium.py +0 -1
  33. data/vendor/depot_tools/fetch_configs/goma_client.py +41 -0
  34. data/vendor/depot_tools/fetch_configs/infra.py +0 -1
  35. data/vendor/depot_tools/fetch_configs/infra_internal.py +0 -1
  36. data/vendor/depot_tools/gclient-new-workdir.py +4 -0
  37. data/vendor/depot_tools/gclient.py +732 -476
  38. data/vendor/depot_tools/gclient_eval.py +569 -58
  39. data/vendor/depot_tools/gclient_scm.py +258 -46
  40. data/vendor/depot_tools/gclient_utils.py +17 -1
  41. data/vendor/depot_tools/gerrit_util.py +46 -13
  42. data/vendor/depot_tools/git_cache.py +0 -2
  43. data/vendor/depot_tools/git_cl.py +176 -335
  44. data/vendor/depot_tools/git_common.py +19 -16
  45. data/vendor/depot_tools/git_footers.py +19 -5
  46. data/vendor/depot_tools/git_hyper_blame.py +9 -3
  47. data/vendor/depot_tools/git_new_branch.py +15 -3
  48. data/vendor/depot_tools/git_upstream_diff.py +7 -2
  49. data/vendor/depot_tools/gsutil.py +1 -1
  50. data/vendor/depot_tools/infra/config/cq.cfg +1 -2
  51. data/vendor/depot_tools/infra/config/recipes.cfg +1 -1
  52. data/vendor/depot_tools/luci-auth +13 -0
  53. data/vendor/depot_tools/luci-auth.bat +8 -0
  54. data/vendor/depot_tools/man/html/depot_tools.html +0 -8
  55. data/vendor/depot_tools/man/html/git-upstream-diff.html +20 -3
  56. data/vendor/depot_tools/man/man1/git-upstream-diff.1 +27 -6
  57. data/vendor/depot_tools/man/man7/depot_tools.7 +0 -5
  58. data/vendor/depot_tools/man/man7/depot_tools_tutorial.7 +2 -2
  59. data/vendor/depot_tools/man/src/git-upstream-diff.txt +21 -3
  60. data/vendor/depot_tools/man/src/make_docs.sh +6 -0
  61. data/vendor/depot_tools/my_activity.py +283 -93
  62. data/vendor/depot_tools/owners.py +9 -4
  63. data/vendor/depot_tools/owners_finder.py +7 -3
  64. data/vendor/depot_tools/post_build_ninja_summary.py +322 -0
  65. data/vendor/depot_tools/presubmit_canned_checks.py +91 -106
  66. data/vendor/depot_tools/presubmit_support.py +219 -157
  67. data/vendor/depot_tools/prpc +13 -0
  68. data/vendor/depot_tools/prpc.bat +8 -0
  69. data/vendor/depot_tools/recipes/OWNERS +3 -1
  70. data/vendor/depot_tools/recipes/README.recipes.md +70 -111
  71. data/vendor/depot_tools/recipes/recipe_modules/bot_update/__init__.py +12 -5
  72. data/vendor/depot_tools/recipes/recipe_modules/bot_update/api.py +36 -68
  73. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/deprecated_got_revision_mapping.json +0 -8
  74. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/{trychange_oauth2_json.json → no_apply_patch_on_gclient.json} +64 -10
  75. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/{no_shallow.json → shallow.json} +1 -1
  76. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob.json +0 -8
  77. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_empty_revision.json +0 -8
  78. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail.json +0 -6
  79. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch.json +0 -7
  80. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch_download.json +0 -6
  81. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_angle_deprecated.json +44 -0
  82. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/{trychange_oauth2_buildbot.json → tryjob_gerrit_branch_heads.json} +51 -5
  83. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8.json +0 -8
  84. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8_head_by_default.json +48 -8
  85. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.py +19 -26
  86. data/vendor/depot_tools/recipes/recipe_modules/bot_update/resources/bot_update.py +193 -155
  87. data/vendor/depot_tools/recipes/recipe_modules/bot_update/test_api.py +9 -0
  88. data/vendor/depot_tools/recipes/recipe_modules/gclient/api.py +2 -7
  89. data/vendor/depot_tools/recipes/recipe_modules/gclient/config.py +31 -5
  90. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/basic.json +37 -19
  91. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/buildbot.json +37 -19
  92. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/revision.json +37 -19
  93. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/tryserver.json +37 -23
  94. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.py +4 -0
  95. data/vendor/depot_tools/recipes/recipe_modules/gerrit/api.py +40 -8
  96. data/vendor/depot_tools/recipes/recipe_modules/gerrit/examples/full.expected/basic.json +3 -3
  97. data/vendor/depot_tools/recipes/recipe_modules/gerrit/examples/full.py +6 -3
  98. data/vendor/depot_tools/recipes/recipe_modules/gitiles/OWNERS +0 -1
  99. data/vendor/depot_tools/recipes/recipe_modules/tryserver/__init__.py +0 -1
  100. data/vendor/depot_tools/recipes/recipe_modules/tryserver/api.py +7 -56
  101. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_wrong_patch.json +0 -1
  102. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.py +15 -16
  103. data/vendor/depot_tools/recipes/recipes.py +4 -2
  104. data/vendor/depot_tools/recipes/trigger_recipe_roller.txt +12 -0
  105. data/vendor/depot_tools/roll_dep.py +35 -37
  106. data/vendor/depot_tools/support/chromite_wrapper +1 -1
  107. data/vendor/depot_tools/third_party/logilab/astroid/README.chromium +3 -3
  108. data/vendor/depot_tools/third_party/logilab/astroid/__pkginfo__.py +2 -2
  109. data/vendor/depot_tools/third_party/logilab/astroid/astpeephole.py +86 -0
  110. data/vendor/depot_tools/third_party/logilab/astroid/bases.py +53 -66
  111. data/vendor/depot_tools/third_party/logilab/astroid/brain/py2pytest.py +31 -31
  112. data/vendor/depot_tools/third_party/logilab/astroid/brain/pynose.py +39 -16
  113. data/vendor/depot_tools/third_party/logilab/astroid/brain/pysix_moves.py +225 -189
  114. data/vendor/depot_tools/third_party/logilab/astroid/inference.py +45 -41
  115. data/vendor/depot_tools/third_party/logilab/astroid/manager.py +1 -0
  116. data/vendor/depot_tools/third_party/logilab/astroid/modutils.py +2 -2
  117. data/vendor/depot_tools/third_party/logilab/astroid/node_classes.py +3 -2
  118. data/vendor/depot_tools/third_party/logilab/astroid/nodes.py +1 -0
  119. data/vendor/depot_tools/third_party/logilab/astroid/protocols.py +57 -3
  120. data/vendor/depot_tools/third_party/logilab/astroid/raw_building.py +1 -1
  121. data/vendor/depot_tools/third_party/logilab/astroid/rebuilder.py +21 -1
  122. data/vendor/depot_tools/third_party/logilab/astroid/scoped_nodes.py +58 -33
  123. data/vendor/depot_tools/third_party/pylint/README.chromium +2 -2
  124. data/vendor/depot_tools/third_party/pylint/__pkginfo__.py +3 -3
  125. data/vendor/depot_tools/third_party/pylint/checkers/base.py +6 -18
  126. data/vendor/depot_tools/third_party/pylint/checkers/classes.py +64 -63
  127. data/vendor/depot_tools/third_party/pylint/checkers/design_analysis.py +25 -57
  128. data/vendor/depot_tools/third_party/pylint/checkers/format.py +14 -10
  129. data/vendor/depot_tools/third_party/pylint/checkers/python3.py +142 -37
  130. data/vendor/depot_tools/third_party/pylint/checkers/spelling.py +10 -1
  131. data/vendor/depot_tools/third_party/pylint/checkers/stdlib.py +50 -7
  132. data/vendor/depot_tools/third_party/pylint/checkers/strings.py +1 -1
  133. data/vendor/depot_tools/third_party/pylint/epylint.py +2 -1
  134. data/vendor/depot_tools/third_party/pylint/gui.py +1 -1
  135. data/vendor/depot_tools/third_party/pylint/lint.py +88 -23
  136. data/vendor/depot_tools/third_party/pylint/reporters/html.py +37 -5
  137. data/vendor/depot_tools/third_party/pylint/testutils.py +1 -1
  138. data/vendor/depot_tools/third_party/pylint/utils.py +5 -0
  139. data/vendor/depot_tools/vpython +31 -1
  140. data/vendor/depot_tools/win_toolchain/get_toolchain_if_necessary.py +35 -2
  141. data/vendor/depot_tools/win_toolchain/package_from_installed.py +0 -15
  142. data/vendor/depot_tools/yapf +17 -0
  143. data/vendor/depot_tools/{apply_issue.bat → yapf.bat} +2 -2
  144. metadata +16 -58
  145. data/ext/libv8/compiler.rb +0 -39
  146. data/ext/libv8/compiler/apple_llvm.rb +0 -22
  147. data/ext/libv8/compiler/clang.rb +0 -22
  148. data/ext/libv8/compiler/gcc.rb +0 -22
  149. data/ext/libv8/compiler/generic_compiler.rb +0 -66
  150. data/ext/libv8/make.rb +0 -13
  151. data/ext/libv8/patcher.rb +0 -21
  152. data/patches/0001-Build-a-standalone-static-library.patch +0 -26
  153. data/patches/0002-Don-t-compile-unnecessary-stuff.patch +0 -85
  154. data/patches/0003-Use-the-fPIC-flag-for-the-static-library.patch +0 -25
  155. data/patches/0004-Do-not-embed-debug-symbols-in-macOS-libraries.patch +0 -25
  156. data/patches/0005-Remove-TryInstallOptimizedCode.patch +0 -321
  157. data/patches/mingw-generate-makefiles.sh +0 -97
  158. data/spec/compiler/apple_llvm_spec.rb +0 -37
  159. data/spec/compiler/clang_spec.rb +0 -37
  160. data/spec/compiler/gcc_spec.rb +0 -37
  161. data/spec/compiler/generic_compiler_spec.rb +0 -50
  162. data/spec/compiler_spec.rb +0 -45
  163. data/spec/support/compiler_helpers.rb +0 -47
  164. data/vendor/depot_tools/apply_issue +0 -8
  165. data/vendor/depot_tools/apply_issue.py +0 -315
  166. data/vendor/depot_tools/man/html/git-cherry-pick-upload.html +0 -815
  167. data/vendor/depot_tools/man/man1/git-cherry-pick-upload.1 +0 -80
  168. data/vendor/depot_tools/man/src/_git-cherry-pick-upload_desc.helper.txt +0 -1
  169. data/vendor/depot_tools/man/src/git-cherry-pick-upload.demo.1.sh +0 -17
  170. data/vendor/depot_tools/man/src/git-cherry-pick-upload.txt +0 -35
  171. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/trychange_oauth2.json +0 -8
  172. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/trychange_oauth2_json_win.json +0 -196
  173. data/vendor/depot_tools/recipes/recipe_modules/rietveld/__init__.py +0 -6
  174. data/vendor/depot_tools/recipes/recipe_modules/rietveld/api.py +0 -97
  175. data/vendor/depot_tools/recipes/recipe_modules/rietveld/examples/full.expected/basic.json +0 -8
  176. data/vendor/depot_tools/recipes/recipe_modules/rietveld/examples/full.expected/buildbot.json +0 -30
  177. data/vendor/depot_tools/recipes/recipe_modules/rietveld/examples/full.expected/no_auth.json +0 -27
  178. data/vendor/depot_tools/recipes/recipe_modules/rietveld/examples/full.py +0 -38
  179. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_rietveld_patch.json +0 -69
  180. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_rietveld_patch_new.json +0 -69
  181. data/vendor/depot_tools/third_party/cq_client/OWNERS +0 -2
  182. data/vendor/depot_tools/third_party/cq_client/README.depot_tools.md +0 -2
  183. data/vendor/depot_tools/third_party/cq_client/README.md +0 -59
  184. data/vendor/depot_tools/third_party/cq_client/__init__.py +0 -3
  185. data/vendor/depot_tools/third_party/cq_client/v1/__init__.py +0 -3
  186. data/vendor/depot_tools/third_party/cq_client/v1/cq.pb.go +0 -810
  187. data/vendor/depot_tools/third_party/cq_client/v1/cq.proto +0 -281
  188. data/vendor/depot_tools/third_party/cq_client/v1/cq_pb2.py +0 -794
  189. data/vendor/depot_tools/third_party/cq_client/v1/testdata/cq_both.cfg +0 -71
  190. data/vendor/depot_tools/third_party/cq_client/v1/testdata/cq_gerrit.cfg +0 -58
  191. data/vendor/depot_tools/third_party/cq_client/v1/testdata/cq_rietveld.cfg +0 -60
  192. data/vendor/depot_tools/third_party/cq_client/v2/__init__.py +0 -3
  193. data/vendor/depot_tools/third_party/cq_client/v2/cq.pb.go +0 -792
  194. data/vendor/depot_tools/third_party/cq_client/v2/cq.proto +0 -270
  195. 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
- # Eliminate files that the author can review.
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
- filtered_files, [author] if author else []))
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
- extra_paths_list + sys.path).encode('utf8')
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("OWNERS check failed: this change has "
856
- "no Rietveld issue number, so we can't check it for approvals.")]
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
- if owner_email:
874
- reviewers_plus_owner = set([owner_email]).union(reviewers)
875
- missing_files = owners_db.files_not_covered_by(affected_files,
876
- reviewers_plus_owner)
877
- else:
878
- missing_files = owners_db.files_not_covered_by(affected_files, reviewers)
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 and input_api.rietveld:
923
- return input_api.rietveld.get_issue_properties(
924
- issue=int(issue), messages=messages)
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(input_api, output_api, check_js=False):
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
- cmd = ['-C', input_api.change.RepositoryRoot(),
1097
- 'cl', 'format', '--dry-run', '--presubmit']
1068
+
1069
+ display_args = []
1098
1070
  if check_js:
1099
- cmd.append('--js')
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
- return [output_api.PresubmitPromptWarning(
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%s' %
1118
- (short_path, '--js ' if check_js else '', presubmit_subdir))]
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.AffectedFiles(file_filter=file_filter)
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
- remote, remote_branch = cl.GetRemoteBranch()
1247
- if remote_branch.startswith('refs/remotes/%s/' % remote):
1248
- remote_branch = remote_branch.replace(
1249
- 'refs/remotes/%s/' % remote, 'refs/heads/', 1)
1250
- if remote_branch.startswith('refs/remotes/branch-heads/'):
1251
- remote_branch = remote_branch.replace(
1252
- 'refs/remotes/branch-heads/', 'refs/branch-heads/', 1)
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({