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
@@ -120,6 +120,12 @@ a
120
120
  .
121
121
  -1
122
122
  j
123
+ /XMLTO_EXTRA
124
+ a
125
+ --skip-validation
126
+ .
127
+ -1
128
+ j
123
129
  /^\$(MAN_HTML):
124
130
  a
125
131
  asciidoc-override.css
@@ -14,9 +14,6 @@ Example:
14
14
  - my_activity.py -jd to output stats for the week to json with deltas data.
15
15
  """
16
16
 
17
- # TODO(vadimsh): This script knows too much about ClientLogin and cookies. It
18
- # will stop to work on ~20 Apr 2015.
19
-
20
17
  # These services typically only provide a created time and a last modified time
21
18
  # for each item for general queries. This is not enough to determine if there
22
19
  # was activity in a given time period. So, we first query for all things created
@@ -24,11 +21,15 @@ Example:
24
21
  # check those details to determine if there was activity in the given period.
25
22
  # This means that query time scales mostly with (today() - begin).
26
23
 
24
+ import collections
25
+ import contextlib
27
26
  from datetime import datetime
28
27
  from datetime import timedelta
29
28
  from functools import partial
29
+ import itertools
30
30
  import json
31
31
  import logging
32
+ from multiprocessing.pool import ThreadPool
32
33
  import optparse
33
34
  import os
34
35
  import subprocess
@@ -112,27 +113,23 @@ gerrit_instances = [
112
113
  },
113
114
  ]
114
115
 
115
- google_code_projects = [
116
- {
117
- 'name': 'chromium',
116
+ monorail_projects = {
117
+ 'chromium': {
118
118
  'shorturl': 'crbug.com',
119
119
  'short_url_protocol': 'https',
120
120
  },
121
- {
122
- 'name': 'google-breakpad',
123
- },
124
- {
125
- 'name': 'gyp',
126
- },
127
- {
128
- 'name': 'skia',
129
- },
130
- {
131
- 'name': 'pdfium',
121
+ 'google-breakpad': {},
122
+ 'gyp': {},
123
+ 'skia': {},
124
+ 'pdfium': {
132
125
  'shorturl': 'crbug.com/pdfium',
133
126
  'short_url_protocol': 'https',
134
127
  },
135
- ]
128
+ 'v8': {
129
+ 'shorturl': 'crbug.com/v8',
130
+ 'short_url_protocol': 'https',
131
+ },
132
+ }
136
133
 
137
134
  def username(email):
138
135
  """Keeps the username of an email address."""
@@ -183,8 +180,8 @@ def datetime_from_rietveld(date_string):
183
180
  return datetime.strptime(date_string, '%Y-%m-%d %H:%M:%S')
184
181
 
185
182
 
186
- def datetime_from_google_code(date_string):
187
- return datetime.strptime(date_string, '%Y-%m-%dT%H:%M:%S.%fZ')
183
+ def datetime_from_monorail(date_string):
184
+ return datetime.strptime(date_string, '%Y-%m-%dT%H:%M:%S')
188
185
 
189
186
 
190
187
  class MyActivity(object):
@@ -196,8 +193,15 @@ class MyActivity(object):
196
193
  self.changes = []
197
194
  self.reviews = []
198
195
  self.issues = []
196
+ self.referenced_issues = []
199
197
  self.check_cookies()
200
198
  self.google_code_auth_token = None
199
+ self.access_errors = set()
200
+
201
+ def show_progress(self, how='.'):
202
+ if sys.stdout.isatty():
203
+ sys.stdout.write(how)
204
+ sys.stdout.flush()
201
205
 
202
206
  # Check the codereview cookie jar to determine which Rietveld instances to
203
207
  # authenticate to.
@@ -247,6 +251,7 @@ class MyActivity(object):
247
251
  reviewer=reviewer_email,
248
252
  modified_after=query_modified_after,
249
253
  with_messages=True)
254
+ self.show_progress()
250
255
 
251
256
  issues = filter(
252
257
  lambda i: (datetime_from_rietveld(i['created']) < self.modified_before),
@@ -279,11 +284,14 @@ class MyActivity(object):
279
284
  if description:
280
285
  # Handle both "Bug: 99999" and "BUG=99999" bug notations
281
286
  # Multiple bugs can be noted on a single line or in multiple ones.
282
- matches = re.findall(r'BUG[=:]\s?(((\d+)(,\s?)?)+)', description,
283
- flags=re.IGNORECASE)
287
+ matches = re.findall(
288
+ r'BUG[=:]\s?((((?:[a-zA-Z0-9-]+:)?\d+)(,\s?)?)+)', description,
289
+ flags=re.IGNORECASE)
284
290
  if matches:
285
291
  for match in matches:
286
292
  bugs.extend(match[0].replace(' ', '').split(','))
293
+ # Add default chromium: prefix if none specified.
294
+ bugs = [bug if ':' in bug else 'chromium:%s' % bug for bug in bugs]
287
295
 
288
296
  return bugs
289
297
 
@@ -293,6 +301,7 @@ class MyActivity(object):
293
301
  patchset_props = remote.get_patchset_properties(
294
302
  issue['issue'],
295
303
  issue['patchsets'][-1])
304
+ self.show_progress()
296
305
  ret['delta'] = '+%d,-%d' % (
297
306
  sum(f['num_added'] for f in patchset_props['files'].itervalues()),
298
307
  sum(f['num_removed'] for f in patchset_props['files'].itervalues()))
@@ -327,7 +336,7 @@ class MyActivity(object):
327
336
  ret['created'] = datetime_from_rietveld(issue['created'])
328
337
  ret['replies'] = self.process_rietveld_replies(issue['messages'])
329
338
 
330
- ret['bug'] = self.extract_bug_number_from_description(issue)
339
+ ret['bugs'] = self.extract_bug_number_from_description(issue)
331
340
  ret['landed_days_ago'] = issue['landed_days_ago']
332
341
 
333
342
  return ret
@@ -343,8 +352,7 @@ class MyActivity(object):
343
352
  ret.append(r)
344
353
  return ret
345
354
 
346
- @staticmethod
347
- def gerrit_changes_over_rest(instance, filters):
355
+ def gerrit_changes_over_rest(self, instance, filters):
348
356
  # Convert the "key:value" filter to a list of (key, value) pairs.
349
357
  req = list(f.split(':', 1) for f in filters)
350
358
  try:
@@ -354,7 +362,9 @@ class MyActivity(object):
354
362
  o_params=['MESSAGES', 'LABELS', 'DETAILED_ACCOUNTS',
355
363
  'CURRENT_REVISION', 'CURRENT_COMMIT']))
356
364
  except gerrit_util.GerritError, e:
357
- logging.error('Looking up %r: %s', instance['url'], e)
365
+ error_message = 'Looking up %r: %s' % (instance['url'], e)
366
+ if error_message not in self.access_errors:
367
+ self.access_errors.add(error_message)
358
368
  return []
359
369
 
360
370
  def gerrit_search(self, instance, owner=None, reviewer=None):
@@ -364,6 +374,7 @@ class MyActivity(object):
364
374
  filters = ['-age:%ss' % max_age, user_filter]
365
375
 
366
376
  issues = self.gerrit_changes_over_rest(instance, filters)
377
+ self.show_progress()
367
378
  issues = [self.process_gerrit_issue(instance, issue)
368
379
  for issue in issues]
369
380
 
@@ -399,7 +410,7 @@ class MyActivity(object):
399
410
  ret['replies'] = []
400
411
  ret['reviewers'] = set(r['author'] for r in ret['replies'])
401
412
  ret['reviewers'].discard(ret['author'])
402
- ret['bug'] = self.extract_bug_number_from_description(issue)
413
+ ret['bugs'] = self.extract_bug_number_from_description(issue)
403
414
  return ret
404
415
 
405
416
  @staticmethod
@@ -415,64 +426,114 @@ class MyActivity(object):
415
426
  })
416
427
  return ret
417
428
 
418
- def project_hosting_issue_search(self, instance):
429
+ def monorail_get_auth_http(self):
419
430
  auth_config = auth.extract_auth_config_from_options(self.options)
420
431
  authenticator = auth.get_authenticator_for_host(
421
432
  'bugs.chromium.org', auth_config)
422
- http = authenticator.authorize(httplib2.Http())
433
+ return authenticator.authorize(httplib2.Http())
434
+
435
+ def filter_modified_monorail_issue(self, issue):
436
+ """Precisely checks if an issue has been modified in the time range.
437
+
438
+ This fetches all issue comments to check if the issue has been modified in
439
+ the time range specified by user. This is needed because monorail only
440
+ allows filtering by last updated and published dates, which is not
441
+ sufficient to tell whether a given issue has been modified at some specific
442
+ time range. Any update to the issue is a reported as comment on Monorail.
443
+
444
+ Args:
445
+ issue: Issue dict as returned by monorail_query_issues method. In
446
+ particular, must have a key 'uid' formatted as 'project:issue_id'.
447
+
448
+ Returns:
449
+ Passed issue if modified, None otherwise.
450
+ """
451
+ http = self.monorail_get_auth_http()
452
+ project, issue_id = issue['uid'].split(':')
423
453
  url = ('https://monorail-prod.appspot.com/_ah/api/monorail/v1/projects'
424
- '/%s/issues') % instance['name']
425
- epoch = datetime.utcfromtimestamp(0)
426
- user_str = '%s@chromium.org' % self.user
454
+ '/%s/issues/%s/comments?maxResults=10000') % (project, issue_id)
455
+ _, body = http.request(url)
456
+ self.show_progress()
457
+ content = json.loads(body)
458
+ if not content:
459
+ logging.error('Unable to parse %s response from monorail.', project)
460
+ return issue
427
461
 
428
- query_data = urllib.urlencode({
429
- 'maxResults': 10000,
430
- 'q': user_str,
431
- 'publishedMax': '%d' % (self.modified_before - epoch).total_seconds(),
432
- 'updatedMin': '%d' % (self.modified_after - epoch).total_seconds(),
433
- })
462
+ for item in content.get('items', []):
463
+ comment_published = datetime_from_monorail(item['published'])
464
+ if self.filter_modified(comment_published):
465
+ return issue
466
+
467
+ return None
468
+
469
+ def monorail_query_issues(self, project, query):
470
+ http = self.monorail_get_auth_http()
471
+ url = ('https://monorail-prod.appspot.com/_ah/api/monorail/v1/projects'
472
+ '/%s/issues') % project
473
+ query_data = urllib.urlencode(query)
434
474
  url = url + '?' + query_data
435
475
  _, body = http.request(url)
476
+ self.show_progress()
436
477
  content = json.loads(body)
437
478
  if not content:
438
- logging.error('Unable to parse %s response from projecthosting.',
439
- instance['name'])
479
+ logging.error('Unable to parse %s response from monorail.', project)
440
480
  return []
441
481
 
442
482
  issues = []
443
- if 'items' in content:
444
- items = content['items']
445
- for item in items:
446
- if instance.get('shorturl'):
447
- protocol = instance.get('short_url_protocol', 'http')
448
- item_url = '%s://%s/%d' % (protocol, instance['shorturl'], item['id'])
449
- else:
450
- item_url = 'https://bugs.chromium.org/p/%s/issues/detail?id=%d' % (
451
- instance['name'], item['id'])
452
- issue = {
453
- 'header': item['title'],
454
- 'created': dateutil.parser.parse(item['published']),
455
- 'modified': dateutil.parser.parse(item['updated']),
456
- 'author': item['author']['name'],
457
- 'url': item_url,
458
- 'comments': [],
459
- 'status': item['status'],
460
- 'labels': [],
461
- 'components': []
462
- }
463
- if 'owner' in item:
464
- issue['owner'] = item['owner']['name']
465
- else:
466
- issue['owner'] = 'None'
467
- if issue['owner'] == user_str or issue['author'] == user_str:
468
- issues.append(issue)
469
- if 'labels' in item:
470
- issue['labels'] = item['labels']
471
- if 'components' in item:
472
- issue['components'] = item['components']
483
+ project_config = monorail_projects.get(project, {})
484
+ for item in content.get('items', []):
485
+ if project_config.get('shorturl'):
486
+ protocol = project_config.get('short_url_protocol', 'http')
487
+ item_url = '%s://%s/%d' % (
488
+ protocol, project_config['shorturl'], item['id'])
489
+ else:
490
+ item_url = 'https://bugs.chromium.org/p/%s/issues/detail?id=%d' % (
491
+ project, item['id'])
492
+ issue = {
493
+ 'uid': '%s:%s' % (project, item['id']),
494
+ 'header': item['title'],
495
+ 'created': datetime_from_monorail(item['published']),
496
+ 'modified': datetime_from_monorail(item['updated']),
497
+ 'author': item['author']['name'],
498
+ 'url': item_url,
499
+ 'comments': [],
500
+ 'status': item['status'],
501
+ 'labels': [],
502
+ 'components': []
503
+ }
504
+ if 'owner' in item:
505
+ issue['owner'] = item['owner']['name']
506
+ else:
507
+ issue['owner'] = 'None'
508
+ if 'labels' in item:
509
+ issue['labels'] = item['labels']
510
+ if 'components' in item:
511
+ issue['components'] = item['components']
512
+ issues.append(issue)
473
513
 
474
514
  return issues
475
515
 
516
+ def monorail_issue_search(self, project):
517
+ epoch = datetime.utcfromtimestamp(0)
518
+ user_str = '%s@chromium.org' % self.user
519
+
520
+ issues = self.monorail_query_issues(project, {
521
+ 'maxResults': 10000,
522
+ 'q': user_str,
523
+ 'publishedMax': '%d' % (self.modified_before - epoch).total_seconds(),
524
+ 'updatedMin': '%d' % (self.modified_after - epoch).total_seconds(),
525
+ })
526
+
527
+ return [
528
+ issue for issue in issues
529
+ if issue['author'] == user_str or issue['owner'] == user_str]
530
+
531
+ def monorail_get_issues(self, project, issue_ids):
532
+ return self.monorail_query_issues(project, {
533
+ 'maxResults': 10000,
534
+ 'q': 'id:%s' % ','.join(issue_ids)
535
+ })
536
+
476
537
  def print_heading(self, heading):
477
538
  print
478
539
  print self.options.output_format_heading.format(heading=heading)
@@ -528,8 +589,12 @@ class MyActivity(object):
528
589
  optional_values = {
529
590
  'created': review['created'].date().isoformat(),
530
591
  'modified': review['modified'].date().isoformat(),
592
+ 'status': review['status'],
531
593
  'activity': activity,
532
594
  }
595
+ if self.options.deltas:
596
+ optional_values['delta'] = review['delta']
597
+
533
598
  self.print_generic(self.options.output_format,
534
599
  self.options.output_format_reviews,
535
600
  review['header'],
@@ -588,26 +653,43 @@ class MyActivity(object):
588
653
  pass
589
654
 
590
655
  def get_changes(self):
591
- for instance in rietveld_instances:
592
- self.changes += self.rietveld_search(instance, owner=self.user)
593
-
594
- for instance in gerrit_instances:
595
- self.changes += self.gerrit_search(instance, owner=self.user)
656
+ num_instances = len(rietveld_instances) + len(gerrit_instances)
657
+ with contextlib.closing(ThreadPool(num_instances)) as pool:
658
+ rietveld_changes = pool.map_async(
659
+ lambda instance: self.rietveld_search(instance, owner=self.user),
660
+ rietveld_instances)
661
+ gerrit_changes = pool.map_async(
662
+ lambda instance: self.gerrit_search(instance, owner=self.user),
663
+ gerrit_instances)
664
+ rietveld_changes = itertools.chain.from_iterable(rietveld_changes.get())
665
+ gerrit_changes = itertools.chain.from_iterable(gerrit_changes.get())
666
+ self.changes = list(rietveld_changes) + list(gerrit_changes)
596
667
 
597
668
  def print_changes(self):
598
669
  if self.changes:
599
670
  self.print_heading('Changes')
600
671
  for change in self.changes:
601
- self.print_change(change)
672
+ self.print_change(change)
602
673
 
603
- def get_reviews(self):
604
- for instance in rietveld_instances:
605
- self.reviews += self.rietveld_search(instance, reviewer=self.user)
674
+ def print_access_errors(self):
675
+ if self.access_errors:
676
+ logging.error('Access Errors:')
677
+ for error in self.access_errors:
678
+ logging.error(error.rstrip())
606
679
 
607
- for instance in gerrit_instances:
608
- reviews = self.gerrit_search(instance, reviewer=self.user)
609
- reviews = filter(lambda r: not username(r['owner']) == self.user, reviews)
610
- self.reviews += reviews
680
+ def get_reviews(self):
681
+ num_instances = len(rietveld_instances) + len(gerrit_instances)
682
+ with contextlib.closing(ThreadPool(num_instances)) as pool:
683
+ rietveld_reviews = pool.map_async(
684
+ lambda instance: self.rietveld_search(instance, reviewer=self.user),
685
+ rietveld_instances)
686
+ gerrit_reviews = pool.map_async(
687
+ lambda instance: self.gerrit_search(instance, reviewer=self.user),
688
+ gerrit_instances)
689
+ rietveld_reviews = itertools.chain.from_iterable(rietveld_reviews.get())
690
+ gerrit_reviews = itertools.chain.from_iterable(gerrit_reviews.get())
691
+ gerrit_reviews = [r for r in gerrit_reviews if r['owner'] != self.user]
692
+ self.reviews = list(rietveld_reviews) + list(gerrit_reviews)
611
693
 
612
694
  def print_reviews(self):
613
695
  if self.reviews:
@@ -616,8 +698,38 @@ class MyActivity(object):
616
698
  self.print_review(review)
617
699
 
618
700
  def get_issues(self):
619
- for project in google_code_projects:
620
- self.issues += self.project_hosting_issue_search(project)
701
+ with contextlib.closing(ThreadPool(len(monorail_projects))) as pool:
702
+ monorail_issues = pool.map(
703
+ self.monorail_issue_search, monorail_projects.keys())
704
+ monorail_issues = list(itertools.chain.from_iterable(monorail_issues))
705
+
706
+ if not monorail_issues:
707
+ return
708
+
709
+ with contextlib.closing(ThreadPool(len(monorail_issues))) as pool:
710
+ filtered_issues = pool.map(
711
+ self.filter_modified_monorail_issue, monorail_issues)
712
+ self.issues = [issue for issue in filtered_issues if issue]
713
+
714
+ def get_referenced_issues(self):
715
+ if not self.issues:
716
+ self.get_issues()
717
+
718
+ if not self.changes:
719
+ self.get_changes()
720
+
721
+ referenced_issue_uids = set(itertools.chain.from_iterable(
722
+ change['bugs'] for change in self.changes))
723
+ fetched_issue_uids = set(issue['uid'] for issue in self.issues)
724
+ missing_issue_uids = referenced_issue_uids - fetched_issue_uids
725
+
726
+ missing_issues_by_project = collections.defaultdict(list)
727
+ for issue_uid in missing_issue_uids:
728
+ project, issue_id = issue_uid.split(':')
729
+ missing_issues_by_project[project].append(issue_id)
730
+
731
+ for project, issue_ids in missing_issues_by_project.iteritems():
732
+ self.referenced_issues += self.monorail_get_issues(project, issue_ids)
621
733
 
622
734
  def print_issues(self):
623
735
  if self.issues:
@@ -625,6 +737,51 @@ class MyActivity(object):
625
737
  for issue in self.issues:
626
738
  self.print_issue(issue)
627
739
 
740
+ def print_changes_by_issue(self, skip_empty_own):
741
+ if not self.issues or not self.changes:
742
+ return
743
+
744
+ self.print_heading('Changes by referenced issue(s)')
745
+ issues = {issue['uid']: issue for issue in self.issues}
746
+ ref_issues = {issue['uid']: issue for issue in self.referenced_issues}
747
+ changes_by_issue_uid = collections.defaultdict(list)
748
+ changes_by_ref_issue_uid = collections.defaultdict(list)
749
+ changes_without_issue = []
750
+ for change in self.changes:
751
+ added = False
752
+ for issue_uid in change['bugs']:
753
+ if issue_uid in issues:
754
+ changes_by_issue_uid[issue_uid].append(change)
755
+ added = True
756
+ if issue_uid in ref_issues:
757
+ changes_by_ref_issue_uid[issue_uid].append(change)
758
+ added = True
759
+ if not added:
760
+ changes_without_issue.append(change)
761
+
762
+ # Changes referencing own issues.
763
+ for issue_uid in issues:
764
+ if changes_by_issue_uid[issue_uid] or not skip_empty_own:
765
+ self.print_issue(issues[issue_uid])
766
+ for change in changes_by_issue_uid[issue_uid]:
767
+ print '', # this prints one space due to comma, but no newline
768
+ self.print_change(change)
769
+
770
+ # Changes referencing others' issues.
771
+ for issue_uid in ref_issues:
772
+ assert changes_by_ref_issue_uid[issue_uid]
773
+ self.print_issue(ref_issues[issue_uid])
774
+ for change in changes_by_ref_issue_uid[issue_uid]:
775
+ print '', # this prints one space due to comma, but no newline
776
+ self.print_change(change)
777
+
778
+ # Changes referencing no issues.
779
+ if changes_without_issue:
780
+ print self.options.output_format_no_url.format(title='Other changes')
781
+ for change in changes_without_issue:
782
+ print '', # this prints one space due to comma, but no newline
783
+ self.print_change(change)
784
+
628
785
  def print_activity(self):
629
786
  self.print_changes()
630
787
  self.print_reviews()
@@ -697,7 +854,19 @@ def main():
697
854
  parser.add_option(
698
855
  '-d', '--deltas',
699
856
  action='store_true',
700
- help='Fetch deltas for changes (slow).')
857
+ help='Fetch deltas for changes.')
858
+ parser.add_option(
859
+ '--no-referenced-issues',
860
+ action='store_true',
861
+ help='Do not fetch issues referenced by owned changes. Useful in '
862
+ 'combination with --changes-by-issue when you only want to list '
863
+ 'issues that have also been modified in the same time period.')
864
+ parser.add_option(
865
+ '--skip-own-issues-without-changes',
866
+ action='store_true',
867
+ help='Skips listing own issues without changes when showing changes '
868
+ 'grouped by referenced issue(s). See --changes-by-issue for more '
869
+ 'details.')
701
870
 
702
871
  activity_types_group = optparse.OptionGroup(parser, 'Activity Types',
703
872
  'By default, all activity will be looked up and '
@@ -715,6 +884,9 @@ def main():
715
884
  '-r', '--reviews',
716
885
  action='store_true',
717
886
  help='Show reviews.')
887
+ activity_types_group.add_option(
888
+ '--changes-by-issue', action='store_true',
889
+ help='Show changes grouped by referenced issue(s).')
718
890
  parser.add_option_group(activity_types_group)
719
891
 
720
892
  output_format_group = optparse.OptionGroup(parser, 'Output Format',
@@ -749,6 +921,9 @@ def main():
749
921
  '--output-format-heading', metavar='<format>',
750
922
  default=u'{heading}:',
751
923
  help='Specifies the format to use when printing headings.')
924
+ output_format_group.add_option(
925
+ '--output-format-no-url', default='{title}',
926
+ help='Specifies the format to use when printing activity without url.')
752
927
  output_format_group.add_option(
753
928
  '-m', '--markdown', action='store_true',
754
929
  help='Use markdown-friendly output (overrides --output-format '
@@ -821,19 +996,22 @@ def main():
821
996
  if options.markdown:
822
997
  options.output_format = ' * [{title}]({url})'
823
998
  options.output_format_heading = '### {heading} ###'
999
+ options.output_format_no_url = ' * {title}'
824
1000
  logging.info('Searching for activity by %s', options.user)
825
1001
  logging.info('Using range %s to %s', options.begin, options.end)
826
1002
 
827
1003
  my_activity = MyActivity(options)
1004
+ my_activity.show_progress('Loading data')
828
1005
 
829
- if not (options.changes or options.reviews or options.issues):
1006
+ if not (options.changes or options.reviews or options.issues or
1007
+ options.changes_by_issue):
830
1008
  options.changes = True
831
1009
  options.issues = True
832
1010
  options.reviews = True
833
1011
 
834
1012
  # First do any required authentication so none of the user interaction has to
835
1013
  # wait for actual work.
836
- if options.changes:
1014
+ if options.changes or options.changes_by_issue:
837
1015
  my_activity.auth_for_changes()
838
1016
  if options.reviews:
839
1017
  my_activity.auth_for_reviews()
@@ -841,15 +1019,21 @@ def main():
841
1019
  logging.info('Looking up activity.....')
842
1020
 
843
1021
  try:
844
- if options.changes:
1022
+ if options.changes or options.changes_by_issue:
845
1023
  my_activity.get_changes()
846
1024
  if options.reviews:
847
1025
  my_activity.get_reviews()
848
- if options.issues:
1026
+ if options.issues or options.changes_by_issue:
849
1027
  my_activity.get_issues()
1028
+ if not options.no_referenced_issues:
1029
+ my_activity.get_referenced_issues()
850
1030
  except auth.AuthenticationError as e:
851
1031
  logging.error('auth.AuthenticationError: %s', e)
852
1032
 
1033
+ my_activity.show_progress('\n')
1034
+
1035
+ my_activity.print_access_errors()
1036
+
853
1037
  output_file = None
854
1038
  try:
855
1039
  if options.output:
@@ -862,9 +1046,15 @@ def main():
862
1046
  if options.json:
863
1047
  my_activity.dump_json()
864
1048
  else:
865
- my_activity.print_changes()
866
- my_activity.print_reviews()
867
- my_activity.print_issues()
1049
+ if options.changes:
1050
+ my_activity.print_changes()
1051
+ if options.reviews:
1052
+ my_activity.print_reviews()
1053
+ if options.issues:
1054
+ my_activity.print_issues()
1055
+ if options.changes_by_issue:
1056
+ my_activity.print_changes_by_issue(
1057
+ options.skip_own_issues_without_changes)
868
1058
  finally:
869
1059
  if output_file:
870
1060
  logging.info('Done printing to file.')