libv8 8.4.255.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (639) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +45 -0
  6. data/CHANGELOG.md +111 -0
  7. data/Gemfile +4 -0
  8. data/README.md +152 -0
  9. data/Rakefile +125 -0
  10. data/appveyor.yml.disabled +36 -0
  11. data/ext/libv8/arch.rb +20 -0
  12. data/ext/libv8/builder.rb +106 -0
  13. data/ext/libv8/extconf.rb +7 -0
  14. data/ext/libv8/location.rb +89 -0
  15. data/ext/libv8/paths.rb +28 -0
  16. data/lib/libv8.rb +9 -0
  17. data/lib/libv8/version.rb +3 -0
  18. data/libv8.gemspec +30 -0
  19. data/scaleway.png +0 -0
  20. data/spec/location_spec.rb +69 -0
  21. data/spec/spec_helper.rb +4 -0
  22. data/thefrontside.png +0 -0
  23. data/vendor/depot_tools/.cipd_impl.ps1 +129 -0
  24. data/vendor/depot_tools/.gitattributes +55 -0
  25. data/vendor/depot_tools/.gitignore +92 -0
  26. data/vendor/depot_tools/.style.yapf +4 -0
  27. data/vendor/depot_tools/.vpython +55 -0
  28. data/vendor/depot_tools/.vpython3 +23 -0
  29. data/vendor/depot_tools/CROS_OWNERS +7 -0
  30. data/vendor/depot_tools/GOMA_OWNERS +9 -0
  31. data/vendor/depot_tools/LICENSE +27 -0
  32. data/vendor/depot_tools/LUCI_OWNERS +5 -0
  33. data/vendor/depot_tools/OWNERS +39 -0
  34. data/vendor/depot_tools/PRESUBMIT.py +150 -0
  35. data/vendor/depot_tools/README.gclient.md +67 -0
  36. data/vendor/depot_tools/README.git-cl.md +99 -0
  37. data/vendor/depot_tools/README.md +78 -0
  38. data/vendor/depot_tools/WATCHLISTS +26 -0
  39. data/vendor/depot_tools/auth.py +163 -0
  40. data/vendor/depot_tools/autoninja +36 -0
  41. data/vendor/depot_tools/autoninja.bat +33 -0
  42. data/vendor/depot_tools/autoninja.py +148 -0
  43. data/vendor/depot_tools/bb +12 -0
  44. data/vendor/depot_tools/bb.bat +7 -0
  45. data/vendor/depot_tools/bootstrap/README.md +155 -0
  46. data/vendor/depot_tools/bootstrap/bootstrap.py +356 -0
  47. data/vendor/depot_tools/bootstrap/git-bash.template.sh +12 -0
  48. data/vendor/depot_tools/bootstrap/git.template.bat +5 -0
  49. data/vendor/depot_tools/bootstrap/manifest.txt +27 -0
  50. data/vendor/depot_tools/bootstrap/manifest_bleeding_edge.txt +27 -0
  51. data/vendor/depot_tools/bootstrap/profile.d.python.sh +20 -0
  52. data/vendor/depot_tools/bootstrap/python27.bat +46 -0
  53. data/vendor/depot_tools/bootstrap/python3.bat +46 -0
  54. data/vendor/depot_tools/bootstrap/win_tools.bat +79 -0
  55. data/vendor/depot_tools/bootstrap_python3 +35 -0
  56. data/vendor/depot_tools/breakpad.py +12 -0
  57. data/vendor/depot_tools/cbuildbot +1 -0
  58. data/vendor/depot_tools/chrome_set_ver +1 -0
  59. data/vendor/depot_tools/cipd +247 -0
  60. data/vendor/depot_tools/cipd.bat +67 -0
  61. data/vendor/depot_tools/cipd_bin_setup.bat +6 -0
  62. data/vendor/depot_tools/cipd_bin_setup.sh +22 -0
  63. data/vendor/depot_tools/cipd_client_version +1 -0
  64. data/vendor/depot_tools/cipd_client_version.digests +22 -0
  65. data/vendor/depot_tools/cipd_manifest.txt +63 -0
  66. data/vendor/depot_tools/cipd_manifest.versions +438 -0
  67. data/vendor/depot_tools/cit +8 -0
  68. data/vendor/depot_tools/cit.bat +12 -0
  69. data/vendor/depot_tools/cit.py +167 -0
  70. data/vendor/depot_tools/clang-format +8 -0
  71. data/vendor/depot_tools/clang-format.bat +12 -0
  72. data/vendor/depot_tools/clang_format.py +79 -0
  73. data/vendor/depot_tools/clang_format_merge_driver +8 -0
  74. data/vendor/depot_tools/clang_format_merge_driver.bat +12 -0
  75. data/vendor/depot_tools/clang_format_merge_driver.py +69 -0
  76. data/vendor/depot_tools/codereview.settings +6 -0
  77. data/vendor/depot_tools/compile_single_file +8 -0
  78. data/vendor/depot_tools/compile_single_file.bat +11 -0
  79. data/vendor/depot_tools/compile_single_file.py +79 -0
  80. data/vendor/depot_tools/cpplint.bat +11 -0
  81. data/vendor/depot_tools/cpplint.py +6097 -0
  82. data/vendor/depot_tools/cpplint_chromium.py +50 -0
  83. data/vendor/depot_tools/cros +87 -0
  84. data/vendor/depot_tools/cros_sdk +1 -0
  85. data/vendor/depot_tools/crosjobs +13 -0
  86. data/vendor/depot_tools/detect_host_arch.py +55 -0
  87. data/vendor/depot_tools/dirmd +12 -0
  88. data/vendor/depot_tools/dirmd.bat +7 -0
  89. data/vendor/depot_tools/download_from_google_storage +8 -0
  90. data/vendor/depot_tools/download_from_google_storage.bat +12 -0
  91. data/vendor/depot_tools/download_from_google_storage.py +634 -0
  92. data/vendor/depot_tools/ensure_bootstrap +53 -0
  93. data/vendor/depot_tools/fetch +21 -0
  94. data/vendor/depot_tools/fetch.bat +28 -0
  95. data/vendor/depot_tools/fetch.py +319 -0
  96. data/vendor/depot_tools/fetch_configs/android.py +34 -0
  97. data/vendor/depot_tools/fetch_configs/android_internal.py +34 -0
  98. data/vendor/depot_tools/fetch_configs/breakpad.py +44 -0
  99. data/vendor/depot_tools/fetch_configs/chromium.py +66 -0
  100. data/vendor/depot_tools/fetch_configs/config_util.py +52 -0
  101. data/vendor/depot_tools/fetch_configs/crashpad.py +41 -0
  102. data/vendor/depot_tools/fetch_configs/dart.py +45 -0
  103. data/vendor/depot_tools/fetch_configs/depot_tools.py +44 -0
  104. data/vendor/depot_tools/fetch_configs/devtools-frontend.py +44 -0
  105. data/vendor/depot_tools/fetch_configs/goma_client.py +41 -0
  106. data/vendor/depot_tools/fetch_configs/gyp.py +41 -0
  107. data/vendor/depot_tools/fetch_configs/infra.py +40 -0
  108. data/vendor/depot_tools/fetch_configs/infra_internal.py +45 -0
  109. data/vendor/depot_tools/fetch_configs/inspector_protocol.py +40 -0
  110. data/vendor/depot_tools/fetch_configs/ios.py +34 -0
  111. data/vendor/depot_tools/fetch_configs/ios_internal.py +39 -0
  112. data/vendor/depot_tools/fetch_configs/nacl.py +48 -0
  113. data/vendor/depot_tools/fetch_configs/naclports.py +47 -0
  114. data/vendor/depot_tools/fetch_configs/node-ci.py +41 -0
  115. data/vendor/depot_tools/fetch_configs/pdfium.py +40 -0
  116. data/vendor/depot_tools/fetch_configs/skia.py +41 -0
  117. data/vendor/depot_tools/fetch_configs/skia_buildbot.py +41 -0
  118. data/vendor/depot_tools/fetch_configs/syzygy.py +41 -0
  119. data/vendor/depot_tools/fetch_configs/v8.py +44 -0
  120. data/vendor/depot_tools/fetch_configs/webrtc.py +52 -0
  121. data/vendor/depot_tools/fetch_configs/webrtc_android.py +34 -0
  122. data/vendor/depot_tools/fetch_configs/webrtc_ios.py +34 -0
  123. data/vendor/depot_tools/fix_encoding.py +385 -0
  124. data/vendor/depot_tools/gclient +38 -0
  125. data/vendor/depot_tools/gclient-new-workdir.py +124 -0
  126. data/vendor/depot_tools/gclient.bat +32 -0
  127. data/vendor/depot_tools/gclient.py +3198 -0
  128. data/vendor/depot_tools/gclient_completion.sh +76 -0
  129. data/vendor/depot_tools/gclient_eval.py +891 -0
  130. data/vendor/depot_tools/gclient_paths.py +152 -0
  131. data/vendor/depot_tools/gclient_scm.py +1615 -0
  132. data/vendor/depot_tools/gclient_utils.py +1280 -0
  133. data/vendor/depot_tools/gerrit_client.py +151 -0
  134. data/vendor/depot_tools/gerrit_util.py +996 -0
  135. data/vendor/depot_tools/git-cache +6 -0
  136. data/vendor/depot_tools/git-cl +6 -0
  137. data/vendor/depot_tools/git-crrev-parse +53 -0
  138. data/vendor/depot_tools/git-drover +6 -0
  139. data/vendor/depot_tools/git-find-releases +6 -0
  140. data/vendor/depot_tools/git-footers +6 -0
  141. data/vendor/depot_tools/git-freeze +8 -0
  142. data/vendor/depot_tools/git-gs +9 -0
  143. data/vendor/depot_tools/git-hyper-blame +6 -0
  144. data/vendor/depot_tools/git-map +6 -0
  145. data/vendor/depot_tools/git-map-branches +6 -0
  146. data/vendor/depot_tools/git-mark-merge-base +6 -0
  147. data/vendor/depot_tools/git-nav-downstream +6 -0
  148. data/vendor/depot_tools/git-nav-upstream +6 -0
  149. data/vendor/depot_tools/git-new-branch +6 -0
  150. data/vendor/depot_tools/git-number +6 -0
  151. data/vendor/depot_tools/git-rebase-update +6 -0
  152. data/vendor/depot_tools/git-rename-branch +6 -0
  153. data/vendor/depot_tools/git-reparent-branch +6 -0
  154. data/vendor/depot_tools/git-retry +8 -0
  155. data/vendor/depot_tools/git-runhooks +23 -0
  156. data/vendor/depot_tools/git-squash-branch +6 -0
  157. data/vendor/depot_tools/git-templates/description +3 -0
  158. data/vendor/depot_tools/git-templates/hooks/applypatch-msg +4 -0
  159. data/vendor/depot_tools/git-templates/hooks/post-applypatch +4 -0
  160. data/vendor/depot_tools/git-templates/hooks/post-checkout +4 -0
  161. data/vendor/depot_tools/git-templates/hooks/post-commit +4 -0
  162. data/vendor/depot_tools/git-templates/hooks/post-merge +4 -0
  163. data/vendor/depot_tools/git-templates/hooks/post-update +4 -0
  164. data/vendor/depot_tools/git-templates/hooks/pre-applypatch +4 -0
  165. data/vendor/depot_tools/git-templates/hooks/pre-auto-gc +4 -0
  166. data/vendor/depot_tools/git-templates/hooks/pre-commit +4 -0
  167. data/vendor/depot_tools/git-templates/hooks/pre-rebase +4 -0
  168. data/vendor/depot_tools/git-templates/hooks/prepare-commit-msg +4 -0
  169. data/vendor/depot_tools/git-templates/info/exclude +6 -0
  170. data/vendor/depot_tools/git-thaw +13 -0
  171. data/vendor/depot_tools/git-upstream-diff +9 -0
  172. data/vendor/depot_tools/git_cache.py +786 -0
  173. data/vendor/depot_tools/git_cl.py +5158 -0
  174. data/vendor/depot_tools/git_cl_completion.sh +48 -0
  175. data/vendor/depot_tools/git_common.py +1101 -0
  176. data/vendor/depot_tools/git_dates.py +62 -0
  177. data/vendor/depot_tools/git_drover.py +469 -0
  178. data/vendor/depot_tools/git_find_releases.py +67 -0
  179. data/vendor/depot_tools/git_footers.py +261 -0
  180. data/vendor/depot_tools/git_freezer.py +40 -0
  181. data/vendor/depot_tools/git_hyper_blame.py +391 -0
  182. data/vendor/depot_tools/git_map.py +166 -0
  183. data/vendor/depot_tools/git_map_branches.py +354 -0
  184. data/vendor/depot_tools/git_mark_merge_base.py +73 -0
  185. data/vendor/depot_tools/git_nav_downstream.py +69 -0
  186. data/vendor/depot_tools/git_new_branch.py +82 -0
  187. data/vendor/depot_tools/git_number.py +301 -0
  188. data/vendor/depot_tools/git_rebase_update.py +351 -0
  189. data/vendor/depot_tools/git_rename_branch.py +55 -0
  190. data/vendor/depot_tools/git_reparent_branch.py +101 -0
  191. data/vendor/depot_tools/git_retry.py +181 -0
  192. data/vendor/depot_tools/git_squash_branch.py +28 -0
  193. data/vendor/depot_tools/git_upstream_diff.py +64 -0
  194. data/vendor/depot_tools/gn +8 -0
  195. data/vendor/depot_tools/gn.bat +12 -0
  196. data/vendor/depot_tools/gn.py +78 -0
  197. data/vendor/depot_tools/goma_auth +12 -0
  198. data/vendor/depot_tools/goma_auth.bat +8 -0
  199. data/vendor/depot_tools/goma_ctl +12 -0
  200. data/vendor/depot_tools/goma_ctl.bat +8 -0
  201. data/vendor/depot_tools/gsutil.py +190 -0
  202. data/vendor/depot_tools/gsutil.py.bat +23 -0
  203. data/vendor/depot_tools/gsutil.vpython +120 -0
  204. data/vendor/depot_tools/infra/README.md +1 -0
  205. data/vendor/depot_tools/infra/config/OWNERS +7 -0
  206. data/vendor/depot_tools/infra/config/README.md +1 -0
  207. data/vendor/depot_tools/infra/config/recipes.cfg +26 -0
  208. data/vendor/depot_tools/led +12 -0
  209. data/vendor/depot_tools/led.bat +7 -0
  210. data/vendor/depot_tools/lockfile.py +116 -0
  211. data/vendor/depot_tools/luci-auth +13 -0
  212. data/vendor/depot_tools/luci-auth.bat +8 -0
  213. data/vendor/depot_tools/lucicfg +12 -0
  214. data/vendor/depot_tools/lucicfg.bat +7 -0
  215. data/vendor/depot_tools/mac_toolchain +12 -0
  216. data/vendor/depot_tools/man/html/depot_tools.html +934 -0
  217. data/vendor/depot_tools/man/html/depot_tools_tutorial.html +1593 -0
  218. data/vendor/depot_tools/man/html/git-cl.html +1033 -0
  219. data/vendor/depot_tools/man/html/git-drover.html +1048 -0
  220. data/vendor/depot_tools/man/html/git-footers.html +878 -0
  221. data/vendor/depot_tools/man/html/git-freeze.html +859 -0
  222. data/vendor/depot_tools/man/html/git-hyper-blame.html +878 -0
  223. data/vendor/depot_tools/man/html/git-map-branches.html +904 -0
  224. data/vendor/depot_tools/man/html/git-map.html +887 -0
  225. data/vendor/depot_tools/man/html/git-mark-merge-base.html +826 -0
  226. data/vendor/depot_tools/man/html/git-nav-downstream.html +844 -0
  227. data/vendor/depot_tools/man/html/git-nav-upstream.html +853 -0
  228. data/vendor/depot_tools/man/html/git-new-branch.html +932 -0
  229. data/vendor/depot_tools/man/html/git-rebase-update.html +961 -0
  230. data/vendor/depot_tools/man/html/git-rename-branch.html +794 -0
  231. data/vendor/depot_tools/man/html/git-reparent-branch.html +847 -0
  232. data/vendor/depot_tools/man/html/git-retry.html +858 -0
  233. data/vendor/depot_tools/man/html/git-squash-branch.html +881 -0
  234. data/vendor/depot_tools/man/html/git-thaw.html +794 -0
  235. data/vendor/depot_tools/man/html/git-upstream-diff.html +923 -0
  236. data/vendor/depot_tools/man/man1/git-cl.1 +198 -0
  237. data/vendor/depot_tools/man/man1/git-drover.1 +330 -0
  238. data/vendor/depot_tools/man/man1/git-footers.1 +144 -0
  239. data/vendor/depot_tools/man/man1/git-freeze.1 +113 -0
  240. data/vendor/depot_tools/man/man1/git-hyper-blame.1 +128 -0
  241. data/vendor/depot_tools/man/man1/git-map-branches.1 +210 -0
  242. data/vendor/depot_tools/man/man1/git-map.1 +179 -0
  243. data/vendor/depot_tools/man/man1/git-mark-merge-base.1 +69 -0
  244. data/vendor/depot_tools/man/man1/git-nav-downstream.1 +112 -0
  245. data/vendor/depot_tools/man/man1/git-nav-upstream.1 +122 -0
  246. data/vendor/depot_tools/man/man1/git-new-branch.1 +176 -0
  247. data/vendor/depot_tools/man/man1/git-rebase-update.1 +177 -0
  248. data/vendor/depot_tools/man/man1/git-rename-branch.1 +53 -0
  249. data/vendor/depot_tools/man/man1/git-reparent-branch.1 +93 -0
  250. data/vendor/depot_tools/man/man1/git-retry.1 +108 -0
  251. data/vendor/depot_tools/man/man1/git-squash-branch.1 +129 -0
  252. data/vendor/depot_tools/man/man1/git-thaw.1 +54 -0
  253. data/vendor/depot_tools/man/man1/git-upstream-diff.1 +153 -0
  254. data/vendor/depot_tools/man/man7/depot_tools.7 +139 -0
  255. data/vendor/depot_tools/man/man7/depot_tools_tutorial.7 +1061 -0
  256. data/vendor/depot_tools/man/push_to_gs.sh +4 -0
  257. data/vendor/depot_tools/man/src/.gitignore +5 -0
  258. data/vendor/depot_tools/man/src/_aliases.txt +5 -0
  259. data/vendor/depot_tools/man/src/_footer.txt +8 -0
  260. data/vendor/depot_tools/man/src/_git-cl_desc.helper.txt +1 -0
  261. data/vendor/depot_tools/man/src/_git-drover_desc.helper.txt +2 -0
  262. data/vendor/depot_tools/man/src/_git-footers_desc.helper.txt +1 -0
  263. data/vendor/depot_tools/man/src/_git-freeze_desc.helper.txt +1 -0
  264. data/vendor/depot_tools/man/src/_git-hyper-blame_desc.helper.txt +1 -0
  265. data/vendor/depot_tools/man/src/_git-map-branches_desc.helper.txt +4 -0
  266. data/vendor/depot_tools/man/src/_git-map_desc.helper.txt +3 -0
  267. data/vendor/depot_tools/man/src/_git-mark-merge-base_desc.helper.txt +1 -0
  268. data/vendor/depot_tools/man/src/_git-nav-downstream_desc.helper.txt +1 -0
  269. data/vendor/depot_tools/man/src/_git-nav-upstream_desc.helper.txt +1 -0
  270. data/vendor/depot_tools/man/src/_git-new-branch_desc.helper.txt +1 -0
  271. data/vendor/depot_tools/man/src/_git-rebase-update_desc.helper.txt +1 -0
  272. data/vendor/depot_tools/man/src/_git-rename-branch_desc.helper.txt +1 -0
  273. data/vendor/depot_tools/man/src/_git-reparent-branch_desc.helper.txt +1 -0
  274. data/vendor/depot_tools/man/src/_git-retry_desc.helper.txt +2 -0
  275. data/vendor/depot_tools/man/src/_git-squash-branch_desc.helper.txt +1 -0
  276. data/vendor/depot_tools/man/src/_git-thaw_desc.helper.txt +2 -0
  277. data/vendor/depot_tools/man/src/_git-upstream-diff_desc.helper.txt +1 -0
  278. data/vendor/depot_tools/man/src/_helper_prefix.txt +1 -0
  279. data/vendor/depot_tools/man/src/asciidoc-override.css +7 -0
  280. data/vendor/depot_tools/man/src/common_demo_functions.sh +84 -0
  281. data/vendor/depot_tools/man/src/demo_repo.sh +43 -0
  282. data/vendor/depot_tools/man/src/depot_tools.txt +28 -0
  283. data/vendor/depot_tools/man/src/depot_tools_tutorial.demo.walkthrough.sh +155 -0
  284. data/vendor/depot_tools/man/src/depot_tools_tutorial.txt +432 -0
  285. data/vendor/depot_tools/man/src/filter_demo_output.py +141 -0
  286. data/vendor/depot_tools/man/src/git-cl.txt +119 -0
  287. data/vendor/depot_tools/man/src/git-drover.demo.1.sh +22 -0
  288. data/vendor/depot_tools/man/src/git-drover.demo.2.sh +23 -0
  289. data/vendor/depot_tools/man/src/git-drover.demo.3.sh +27 -0
  290. data/vendor/depot_tools/man/src/git-drover.demo.4.sh +39 -0
  291. data/vendor/depot_tools/man/src/git-drover.demo.common.sh +19 -0
  292. data/vendor/depot_tools/man/src/git-drover.txt +102 -0
  293. data/vendor/depot_tools/man/src/git-footers.demo.1.sh +17 -0
  294. data/vendor/depot_tools/man/src/git-footers.txt +71 -0
  295. data/vendor/depot_tools/man/src/git-freeze.demo.1.sh +23 -0
  296. data/vendor/depot_tools/man/src/git-freeze.txt +54 -0
  297. data/vendor/depot_tools/man/src/git-hyper-blame.demo.1.sh +3 -0
  298. data/vendor/depot_tools/man/src/git-hyper-blame.demo.2.sh +4 -0
  299. data/vendor/depot_tools/man/src/git-hyper-blame.demo.common.sh +57 -0
  300. data/vendor/depot_tools/man/src/git-hyper-blame.txt +85 -0
  301. data/vendor/depot_tools/man/src/git-map-branches.demo.1.sh +8 -0
  302. data/vendor/depot_tools/man/src/git-map-branches.txt +64 -0
  303. data/vendor/depot_tools/man/src/git-map.demo.1.sh +3 -0
  304. data/vendor/depot_tools/man/src/git-map.txt +67 -0
  305. data/vendor/depot_tools/man/src/git-mark-merge-base.txt +46 -0
  306. data/vendor/depot_tools/man/src/git-nav-downstream.demo.1.sh +12 -0
  307. data/vendor/depot_tools/man/src/git-nav-downstream.txt +40 -0
  308. data/vendor/depot_tools/man/src/git-nav-upstream.demo.1.sh +12 -0
  309. data/vendor/depot_tools/man/src/git-nav-upstream.txt +39 -0
  310. data/vendor/depot_tools/man/src/git-new-branch.demo.1.sh +17 -0
  311. data/vendor/depot_tools/man/src/git-new-branch.txt +82 -0
  312. data/vendor/depot_tools/man/src/git-rebase-update.txt +141 -0
  313. data/vendor/depot_tools/man/src/git-rename-branch.txt +28 -0
  314. data/vendor/depot_tools/man/src/git-reparent-branch.txt +61 -0
  315. data/vendor/depot_tools/man/src/git-retry.txt +67 -0
  316. data/vendor/depot_tools/man/src/git-squash-branch.demo.1.sh +12 -0
  317. data/vendor/depot_tools/man/src/git-squash-branch.txt +59 -0
  318. data/vendor/depot_tools/man/src/git-thaw.txt +29 -0
  319. data/vendor/depot_tools/man/src/git-upstream-diff.txt +107 -0
  320. data/vendor/depot_tools/man/src/make_docs.sh +260 -0
  321. data/vendor/depot_tools/man/src/prep_demo_repo.sh +103 -0
  322. data/vendor/depot_tools/metrics.README.md +101 -0
  323. data/vendor/depot_tools/metrics.py +297 -0
  324. data/vendor/depot_tools/metrics_utils.py +293 -0
  325. data/vendor/depot_tools/my_activity.py +971 -0
  326. data/vendor/depot_tools/ninja +44 -0
  327. data/vendor/depot_tools/ninja-linux32 +0 -0
  328. data/vendor/depot_tools/ninja-linux64 +0 -0
  329. data/vendor/depot_tools/ninja-mac +0 -0
  330. data/vendor/depot_tools/ninja.exe +0 -0
  331. data/vendor/depot_tools/ninjalog.README.md +64 -0
  332. data/vendor/depot_tools/ninjalog_uploader.py +233 -0
  333. data/vendor/depot_tools/ninjalog_uploader_wrapper.py +125 -0
  334. data/vendor/depot_tools/owners.py +641 -0
  335. data/vendor/depot_tools/owners_finder.py +385 -0
  336. data/vendor/depot_tools/post_build_ninja_summary.py +350 -0
  337. data/vendor/depot_tools/presubmit_canned_checks.py +1655 -0
  338. data/vendor/depot_tools/presubmit_support.py +1923 -0
  339. data/vendor/depot_tools/profile.xml +8 -0
  340. data/vendor/depot_tools/prpc +13 -0
  341. data/vendor/depot_tools/prpc.bat +8 -0
  342. data/vendor/depot_tools/pylint +9 -0
  343. data/vendor/depot_tools/pylint-1.5 +78 -0
  344. data/vendor/depot_tools/pylint-1.6 +78 -0
  345. data/vendor/depot_tools/pylint-1.7 +78 -0
  346. data/vendor/depot_tools/pylint-1.8 +78 -0
  347. data/vendor/depot_tools/pylint-1.9 +78 -0
  348. data/vendor/depot_tools/pylint.bat +12 -0
  349. data/vendor/depot_tools/pylint_main.py +45 -0
  350. data/vendor/depot_tools/pylintrc +349 -0
  351. data/vendor/depot_tools/python-bin/python3 +7 -0
  352. data/vendor/depot_tools/python_runner.sh +60 -0
  353. data/vendor/depot_tools/rdb +12 -0
  354. data/vendor/depot_tools/rdb.bat +7 -0
  355. data/vendor/depot_tools/recipes/OWNERS +4 -0
  356. data/vendor/depot_tools/recipes/README.recipes.md +1079 -0
  357. data/vendor/depot_tools/recipes/recipe_modules/OWNERS +1 -0
  358. data/vendor/depot_tools/recipes/recipe_modules/bot_update/OWNERS +2 -0
  359. data/vendor/depot_tools/recipes/recipe_modules/bot_update/__init__.py +38 -0
  360. data/vendor/depot_tools/recipes/recipe_modules/bot_update/api.py +516 -0
  361. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/basic.json +117 -0
  362. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/basic_luci.json +117 -0
  363. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/basic_with_branch_heads.json +118 -0
  364. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/clobber.json +211 -0
  365. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/deprecated_got_revision_mapping.json +194 -0
  366. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/gerrit_no_rebase_patch_ref.json +211 -0
  367. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/gerrit_no_reset.json +211 -0
  368. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/input_commit_with_id_without_repo.json +210 -0
  369. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/multiple_patch_refs.json +214 -0
  370. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/no_apply_patch_on_gclient.json +265 -0
  371. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/no_cp_checkout_HEAD.json +65 -0
  372. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/no_cp_checkout_a_branch_head.json +65 -0
  373. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/no_cp_checkout_a_specific_commit.json +65 -0
  374. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/no_cp_checkout_master.json +65 -0
  375. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/refs.json +212 -0
  376. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/reset_root_solution_revision.json +210 -0
  377. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/resolve_chromium_fixed_version.json +117 -0
  378. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail.json +95 -0
  379. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch.json +209 -0
  380. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch_download.json +193 -0
  381. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_angle.json +265 -0
  382. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_branch_heads.json +261 -0
  383. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_feature_branch.json +261 -0
  384. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_v8_feature_branch.json +265 -0
  385. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_webrtc.json +265 -0
  386. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8.json +265 -0
  387. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8_head_by_default.json +265 -0
  388. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/unrecognized_commit_repo.json +8 -0
  389. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/with_tags.json +211 -0
  390. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.py +308 -0
  391. data/vendor/depot_tools/recipes/recipe_modules/bot_update/resources/__init__.py +0 -0
  392. data/vendor/depot_tools/recipes/recipe_modules/bot_update/resources/bot_update.py +1258 -0
  393. data/vendor/depot_tools/recipes/recipe_modules/bot_update/test_api.py +93 -0
  394. data/vendor/depot_tools/recipes/recipe_modules/bot_update/tests/do_not_retry_patch_failures_in_cq.py +42 -0
  395. data/vendor/depot_tools/recipes/recipe_modules/bot_update/tests/ensure_checkout.py +35 -0
  396. data/vendor/depot_tools/recipes/recipe_modules/cipd/__init__.py +9 -0
  397. data/vendor/depot_tools/recipes/recipe_modules/cipd/api.py +455 -0
  398. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/basic.json +403 -0
  399. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/basic_pkg.json +403 -0
  400. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/describe-failed.json +82 -0
  401. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/describe-many-instances.json +411 -0
  402. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/mac64.json +403 -0
  403. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/pkg_bad_file.json +315 -0
  404. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/pkg_bad_mode.json +313 -0
  405. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/pkg_bad_verfile.json +313 -0
  406. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/win64.json +403 -0
  407. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.py +187 -0
  408. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/junk arch.json +5 -0
  409. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/junk bits.json +5 -0
  410. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_arm_32.json +12 -0
  411. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_arm_64.json +12 -0
  412. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_intel_32.json +12 -0
  413. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_intel_64.json +12 -0
  414. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_mips_64.json +12 -0
  415. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/mac_intel_64.json +12 -0
  416. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/win_intel_32.json +12 -0
  417. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/win_intel_64.json +12 -0
  418. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.py +59 -0
  419. data/vendor/depot_tools/recipes/recipe_modules/cipd/test_api.py +93 -0
  420. data/vendor/depot_tools/recipes/recipe_modules/depot_tools/__init__.py +9 -0
  421. data/vendor/depot_tools/recipes/recipe_modules/depot_tools/api.py +75 -0
  422. data/vendor/depot_tools/recipes/recipe_modules/depot_tools/examples/full.expected/basic.json +83 -0
  423. data/vendor/depot_tools/recipes/recipe_modules/depot_tools/examples/full.expected/basic_luci.json +83 -0
  424. data/vendor/depot_tools/recipes/recipe_modules/depot_tools/examples/full.expected/win.json +83 -0
  425. data/vendor/depot_tools/recipes/recipe_modules/depot_tools/examples/full.py +55 -0
  426. data/vendor/depot_tools/recipes/recipe_modules/gclient/__init__.py +13 -0
  427. data/vendor/depot_tools/recipes/recipe_modules/gclient/api.py +428 -0
  428. data/vendor/depot_tools/recipes/recipe_modules/gclient/config.py +462 -0
  429. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/basic.json +238 -0
  430. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/revision.json +240 -0
  431. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/tryserver.json +238 -0
  432. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.py +95 -0
  433. data/vendor/depot_tools/recipes/recipe_modules/gclient/resources/diff_deps.py +16 -0
  434. data/vendor/depot_tools/recipes/recipe_modules/gclient/test_api.py +36 -0
  435. data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/diff_deps.expected/basic.json +55 -0
  436. data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/diff_deps.expected/dont have revision yet.json +84 -0
  437. data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/diff_deps.expected/no change, exception.json +83 -0
  438. data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/diff_deps.expected/windows.json +55 -0
  439. data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/diff_deps.py +88 -0
  440. data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/patch_project.py +92 -0
  441. data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/sync_failure.py +24 -0
  442. data/vendor/depot_tools/recipes/recipe_modules/gerrit/__init__.py +8 -0
  443. data/vendor/depot_tools/recipes/recipe_modules/gerrit/api.py +178 -0
  444. data/vendor/depot_tools/recipes/recipe_modules/gerrit/examples/full.expected/basic.json +284 -0
  445. data/vendor/depot_tools/recipes/recipe_modules/gerrit/examples/full.py +73 -0
  446. data/vendor/depot_tools/recipes/recipe_modules/gerrit/test_api.py +53 -0
  447. data/vendor/depot_tools/recipes/recipe_modules/git/__init__.py +11 -0
  448. data/vendor/depot_tools/recipes/recipe_modules/git/api.py +405 -0
  449. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic.json +217 -0
  450. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_branch.json +217 -0
  451. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_file_name.json +219 -0
  452. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_hash.json +216 -0
  453. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_ref.json +217 -0
  454. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_submodule_update_force.json +218 -0
  455. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_tags.json +218 -0
  456. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/can_fail_build.json +164 -0
  457. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/cannot_fail_build.json +220 -0
  458. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/cat-file_test.json +239 -0
  459. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/count-objects_delta.json +290 -0
  460. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/count-objects_failed.json +220 -0
  461. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/count-objects_with_bad_output.json +222 -0
  462. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/count-objects_with_bad_output_fails_build.json +111 -0
  463. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/curl_trace_file.json +218 -0
  464. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/git-cache-checkout.json +265 -0
  465. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/platform_win.json +217 -0
  466. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/rebase_failed.json +221 -0
  467. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/remote_not_origin.json +219 -0
  468. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/set_got_revision.json +218 -0
  469. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.py +170 -0
  470. data/vendor/depot_tools/recipes/recipe_modules/git/resources/git_setup.py +52 -0
  471. data/vendor/depot_tools/recipes/recipe_modules/git/test_api.py +18 -0
  472. data/vendor/depot_tools/recipes/recipe_modules/git_cl/__init__.py +5 -0
  473. data/vendor/depot_tools/recipes/recipe_modules/git_cl/api.py +50 -0
  474. data/vendor/depot_tools/recipes/recipe_modules/git_cl/config.py +22 -0
  475. data/vendor/depot_tools/recipes/recipe_modules/git_cl/examples/full.expected/basic.json +105 -0
  476. data/vendor/depot_tools/recipes/recipe_modules/git_cl/examples/full.py +47 -0
  477. data/vendor/depot_tools/recipes/recipe_modules/gitiles/OWNERS +2 -0
  478. data/vendor/depot_tools/recipes/recipe_modules/gitiles/__init__.py +12 -0
  479. data/vendor/depot_tools/recipes/recipe_modules/gitiles/api.py +257 -0
  480. data/vendor/depot_tools/recipes/recipe_modules/gitiles/examples/full.expected/basic.json +596 -0
  481. data/vendor/depot_tools/recipes/recipe_modules/gitiles/examples/full.py +93 -0
  482. data/vendor/depot_tools/recipes/recipe_modules/gitiles/resources/gerrit_client.py +251 -0
  483. data/vendor/depot_tools/recipes/recipe_modules/gitiles/test_api.py +95 -0
  484. data/vendor/depot_tools/recipes/recipe_modules/gitiles/tests/parse_repo_url.expected/basic.json +5 -0
  485. data/vendor/depot_tools/recipes/recipe_modules/gitiles/tests/parse_repo_url.py +49 -0
  486. data/vendor/depot_tools/recipes/recipe_modules/gsutil/__init__.py +4 -0
  487. data/vendor/depot_tools/recipes/recipe_modules/gsutil/api.py +222 -0
  488. data/vendor/depot_tools/recipes/recipe_modules/gsutil/examples/full.expected/basic.json +247 -0
  489. data/vendor/depot_tools/recipes/recipe_modules/gsutil/examples/full.py +92 -0
  490. data/vendor/depot_tools/recipes/recipe_modules/gsutil/resources/gsutil_smart_retry.py +69 -0
  491. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/__init__.py +36 -0
  492. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/api.py +140 -0
  493. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/ancient_version.json +83 -0
  494. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/automatic_version.json +83 -0
  495. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/explicit_version.json +83 -0
  496. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/linux.json +21 -0
  497. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/mac.json +83 -0
  498. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/win.json +21 -0
  499. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.py +42 -0
  500. data/vendor/depot_tools/recipes/recipe_modules/presubmit/__init__.py +27 -0
  501. data/vendor/depot_tools/recipes/recipe_modules/presubmit/api.py +251 -0
  502. data/vendor/depot_tools/recipes/recipe_modules/presubmit/examples/full.expected/basic.json +27 -0
  503. data/vendor/depot_tools/recipes/recipe_modules/presubmit/examples/full.py +19 -0
  504. data/vendor/depot_tools/recipes/recipe_modules/presubmit/properties.proto +14 -0
  505. data/vendor/depot_tools/recipes/recipe_modules/presubmit/test_api.py +19 -0
  506. data/vendor/depot_tools/recipes/recipe_modules/presubmit/tests/execute.py +247 -0
  507. data/vendor/depot_tools/recipes/recipe_modules/presubmit/tests/prepare.py +49 -0
  508. data/vendor/depot_tools/recipes/recipe_modules/tryserver/__init__.py +18 -0
  509. data/vendor/depot_tools/recipes/recipe_modules/tryserver/api.py +264 -0
  510. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/basic_tags.json +57 -0
  511. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch.json +190 -0
  512. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch_and_target_ref.json +190 -0
  513. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_wrong_patch.json +21 -0
  514. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_wrong_patch_new.json +22 -0
  515. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.py +95 -0
  516. data/vendor/depot_tools/recipes/recipe_modules/tryserver/test_api.py +14 -0
  517. data/vendor/depot_tools/recipes/recipe_modules/tryserver/tests/gerrit_change_fetch_ref_timeout.py +29 -0
  518. data/vendor/depot_tools/recipes/recipe_modules/tryserver/tests/gerrit_change_owner.expected/basic.json +5 -0
  519. data/vendor/depot_tools/recipes/recipe_modules/tryserver/tests/gerrit_change_owner.py +22 -0
  520. data/vendor/depot_tools/recipes/recipe_modules/tryserver/tests/gerrit_change_target_ref.py +32 -0
  521. data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/__init__.py +25 -0
  522. data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/api.py +137 -0
  523. data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/examples/full.expected/linux.json +21 -0
  524. data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/examples/full.expected/mac.json +21 -0
  525. data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/examples/full.expected/win.json +108 -0
  526. data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/examples/full.py +21 -0
  527. data/vendor/depot_tools/recipes/recipes.py +249 -0
  528. data/vendor/depot_tools/recipes/recipes/fetch_end_to_end_test.expected/basic.json +175 -0
  529. data/vendor/depot_tools/recipes/recipes/fetch_end_to_end_test.py +56 -0
  530. data/vendor/depot_tools/recipes/trigger_recipe_roller.txt +13 -0
  531. data/vendor/depot_tools/repo +1194 -0
  532. data/vendor/depot_tools/roll-dep +21 -0
  533. data/vendor/depot_tools/roll-dep.bat +21 -0
  534. data/vendor/depot_tools/roll_dep.py +282 -0
  535. data/vendor/depot_tools/scm.py +415 -0
  536. data/vendor/depot_tools/setup_color.py +130 -0
  537. data/vendor/depot_tools/split_cl.py +263 -0
  538. data/vendor/depot_tools/subcommand.py +261 -0
  539. data/vendor/depot_tools/subprocess2.py +258 -0
  540. data/vendor/depot_tools/third_party/__init__.py +5 -0
  541. data/vendor/depot_tools/third_party/colorama/LICENSE.txt +27 -0
  542. data/vendor/depot_tools/third_party/colorama/README.chromium +12 -0
  543. data/vendor/depot_tools/third_party/colorama/README.rst +346 -0
  544. data/vendor/depot_tools/third_party/colorama/__init__.py +6 -0
  545. data/vendor/depot_tools/third_party/colorama/ansi.py +102 -0
  546. data/vendor/depot_tools/third_party/colorama/ansitowin32.py +257 -0
  547. data/vendor/depot_tools/third_party/colorama/initialise.py +80 -0
  548. data/vendor/depot_tools/third_party/colorama/win32.py +152 -0
  549. data/vendor/depot_tools/third_party/colorama/winterm.py +169 -0
  550. data/vendor/depot_tools/third_party/coverage/AUTHORS.txt +43 -0
  551. data/vendor/depot_tools/third_party/coverage/PKG-INFO +41 -0
  552. data/vendor/depot_tools/third_party/coverage/README.chromium +13 -0
  553. data/vendor/depot_tools/third_party/coverage/__init__.py +120 -0
  554. data/vendor/depot_tools/third_party/coverage/__main__.py +4 -0
  555. data/vendor/depot_tools/third_party/coverage/annotate.py +101 -0
  556. data/vendor/depot_tools/third_party/coverage/backward.py +184 -0
  557. data/vendor/depot_tools/third_party/coverage/bytecode.py +75 -0
  558. data/vendor/depot_tools/third_party/coverage/cmdline.py +740 -0
  559. data/vendor/depot_tools/third_party/coverage/codeunit.py +145 -0
  560. data/vendor/depot_tools/third_party/coverage/collector.py +353 -0
  561. data/vendor/depot_tools/third_party/coverage/config.py +213 -0
  562. data/vendor/depot_tools/third_party/coverage/control.py +776 -0
  563. data/vendor/depot_tools/third_party/coverage/data.py +278 -0
  564. data/vendor/depot_tools/third_party/coverage/debug.py +54 -0
  565. data/vendor/depot_tools/third_party/coverage/execfile.py +171 -0
  566. data/vendor/depot_tools/third_party/coverage/files.py +309 -0
  567. data/vendor/depot_tools/third_party/coverage/fullcoverage/encodings.py +57 -0
  568. data/vendor/depot_tools/third_party/coverage/html.py +387 -0
  569. data/vendor/depot_tools/third_party/coverage/htmlfiles/coverage_html.js +376 -0
  570. data/vendor/depot_tools/third_party/coverage/htmlfiles/index.html +104 -0
  571. data/vendor/depot_tools/third_party/coverage/htmlfiles/jquery-1.4.3.min.js +166 -0
  572. data/vendor/depot_tools/third_party/coverage/htmlfiles/jquery.hotkeys.js +99 -0
  573. data/vendor/depot_tools/third_party/coverage/htmlfiles/jquery.isonscreen.js +53 -0
  574. data/vendor/depot_tools/third_party/coverage/htmlfiles/jquery.min.js +166 -0
  575. data/vendor/depot_tools/third_party/coverage/htmlfiles/jquery.tablesorter.min.js +2 -0
  576. data/vendor/depot_tools/third_party/coverage/htmlfiles/keybd_closed.png +0 -0
  577. data/vendor/depot_tools/third_party/coverage/htmlfiles/keybd_open.png +0 -0
  578. data/vendor/depot_tools/third_party/coverage/htmlfiles/pyfile.html +90 -0
  579. data/vendor/depot_tools/third_party/coverage/htmlfiles/style.css +300 -0
  580. data/vendor/depot_tools/third_party/coverage/misc.py +163 -0
  581. data/vendor/depot_tools/third_party/coverage/parser.py +666 -0
  582. data/vendor/depot_tools/third_party/coverage/phystokens.py +208 -0
  583. data/vendor/depot_tools/third_party/coverage/report.py +92 -0
  584. data/vendor/depot_tools/third_party/coverage/results.py +286 -0
  585. data/vendor/depot_tools/third_party/coverage/summary.py +86 -0
  586. data/vendor/depot_tools/third_party/coverage/templite.py +166 -0
  587. data/vendor/depot_tools/third_party/coverage/version.py +9 -0
  588. data/vendor/depot_tools/third_party/coverage/xmlreport.py +155 -0
  589. data/vendor/depot_tools/third_party/httplib2/LICENSE +1339 -0
  590. data/vendor/depot_tools/third_party/httplib2/README.chromium +15 -0
  591. data/vendor/depot_tools/third_party/httplib2/__init__.py +1780 -0
  592. data/vendor/depot_tools/third_party/httplib2/cacerts.txt +2196 -0
  593. data/vendor/depot_tools/third_party/httplib2/iri2uri.py +110 -0
  594. data/vendor/depot_tools/third_party/httplib2/socks.py +448 -0
  595. data/vendor/depot_tools/third_party/repo/COPYING +202 -0
  596. data/vendor/depot_tools/third_party/repo/README.chromium +4 -0
  597. data/vendor/depot_tools/third_party/repo/__init__.py +0 -0
  598. data/vendor/depot_tools/third_party/repo/progress.py +117 -0
  599. data/vendor/depot_tools/third_party/retry_decorator/LICENSE.google +30 -0
  600. data/vendor/depot_tools/third_party/retry_decorator/__init__.py +0 -0
  601. data/vendor/depot_tools/third_party/retry_decorator/decorators.py +45 -0
  602. data/vendor/depot_tools/third_party/schema/.editorconfig +15 -0
  603. data/vendor/depot_tools/third_party/schema/.gitignore +174 -0
  604. data/vendor/depot_tools/third_party/schema/.travis.yml +37 -0
  605. data/vendor/depot_tools/third_party/schema/LICENSE-MIT +19 -0
  606. data/vendor/depot_tools/third_party/schema/MANIFEST.in +1 -0
  607. data/vendor/depot_tools/third_party/schema/README.chromium +12 -0
  608. data/vendor/depot_tools/third_party/schema/README.rst +382 -0
  609. data/vendor/depot_tools/third_party/schema/__init__.py +1 -0
  610. data/vendor/depot_tools/third_party/schema/schema.py +338 -0
  611. data/vendor/depot_tools/third_party/schema/setup.cfg +5 -0
  612. data/vendor/depot_tools/third_party/schema/setup.py +30 -0
  613. data/vendor/depot_tools/third_party/schema/test_schema.py +556 -0
  614. data/vendor/depot_tools/third_party/schema/tox.ini +33 -0
  615. data/vendor/depot_tools/third_party/six/LICENSE.txt +18 -0
  616. data/vendor/depot_tools/third_party/six/README.chromium +10 -0
  617. data/vendor/depot_tools/third_party/six/__init__.py +762 -0
  618. data/vendor/depot_tools/update_depot_tools +138 -0
  619. data/vendor/depot_tools/update_depot_tools.bat +65 -0
  620. data/vendor/depot_tools/update_depot_tools_toggle.py +38 -0
  621. data/vendor/depot_tools/upload_metrics.py +26 -0
  622. data/vendor/depot_tools/upload_to_google_storage.py +306 -0
  623. data/vendor/depot_tools/vpython +42 -0
  624. data/vendor/depot_tools/vpython.bat +7 -0
  625. data/vendor/depot_tools/vpython3 +55 -0
  626. data/vendor/depot_tools/vpython3.bat +12 -0
  627. data/vendor/depot_tools/watchlists.py +141 -0
  628. data/vendor/depot_tools/weekly +54 -0
  629. data/vendor/depot_tools/win32imports.py +61 -0
  630. data/vendor/depot_tools/win_toolchain/OWNERS +2 -0
  631. data/vendor/depot_tools/win_toolchain/README.md +74 -0
  632. data/vendor/depot_tools/win_toolchain/get_toolchain_if_necessary.py +599 -0
  633. data/vendor/depot_tools/win_toolchain/package_from_installed.py +524 -0
  634. data/vendor/depot_tools/wtf +81 -0
  635. data/vendor/depot_tools/yapf +21 -0
  636. data/vendor/depot_tools/yapf.bat +12 -0
  637. data/vendor/depot_tools/zsh-goodies/README +6 -0
  638. data/vendor/depot_tools/zsh-goodies/_gclient +14 -0
  639. metadata +729 -0
@@ -0,0 +1,1923 @@
1
+ #!/usr/bin/env python
2
+ # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3
+ # Use of this source code is governed by a BSD-style license that can be
4
+ # found in the LICENSE file.
5
+
6
+ """Enables directory-specific presubmit checks to run at upload and/or commit.
7
+ """
8
+
9
+ from __future__ import print_function
10
+
11
+ __version__ = '1.8.0'
12
+
13
+ # TODO(joi) Add caching where appropriate/needed. The API is designed to allow
14
+ # caching (between all different invocations of presubmit scripts for a given
15
+ # change). We should add it as our presubmit scripts start feeling slow.
16
+
17
+ import argparse
18
+ import ast # Exposed through the API.
19
+ import contextlib
20
+ import cpplint
21
+ import fnmatch # Exposed through the API.
22
+ import glob
23
+ import inspect
24
+ import itertools
25
+ import json # Exposed through the API.
26
+ import logging
27
+ import multiprocessing
28
+ import os # Somewhat exposed through the API.
29
+ import random
30
+ import re # Exposed through the API.
31
+ import signal
32
+ import sys # Parts exposed through API.
33
+ import tempfile # Exposed through the API.
34
+ import threading
35
+ import time
36
+ import traceback
37
+ import unittest # Exposed through the API.
38
+ from warnings import warn
39
+
40
+ # Local imports.
41
+ import fix_encoding
42
+ import gclient_paths # Exposed through the API
43
+ import gclient_utils
44
+ import git_footers
45
+ import gerrit_util
46
+ import owners
47
+ import owners_finder
48
+ import presubmit_canned_checks
49
+ import scm
50
+ import subprocess2 as subprocess # Exposed through the API.
51
+
52
+ if sys.version_info.major == 2:
53
+ # TODO(1009814): Expose urllib2 only through urllib_request and urllib_error
54
+ import urllib2 # Exposed through the API.
55
+ import urlparse
56
+ import urllib2 as urllib_request
57
+ import urllib2 as urllib_error
58
+ else:
59
+ import urllib.parse as urlparse
60
+ import urllib.request as urllib_request
61
+ import urllib.error as urllib_error
62
+
63
+ # Ask for feedback only once in program lifetime.
64
+ _ASKED_FOR_FEEDBACK = False
65
+
66
+
67
+ def time_time():
68
+ # Use this so that it can be mocked in tests without interfering with python
69
+ # system machinery.
70
+ return time.time()
71
+
72
+
73
+ class PresubmitFailure(Exception):
74
+ pass
75
+
76
+
77
+ class CommandData(object):
78
+ def __init__(self, name, cmd, kwargs, message, python3=False):
79
+ self.name = name
80
+ self.cmd = cmd
81
+ self.stdin = kwargs.get('stdin', None)
82
+ self.kwargs = kwargs.copy()
83
+ self.kwargs['stdout'] = subprocess.PIPE
84
+ self.kwargs['stderr'] = subprocess.STDOUT
85
+ self.kwargs['stdin'] = subprocess.PIPE
86
+ self.message = message
87
+ self.info = None
88
+ self.python3 = python3
89
+
90
+
91
+ # Adapted from
92
+ # https://github.com/google/gtest-parallel/blob/master/gtest_parallel.py#L37
93
+ #
94
+ # An object that catches SIGINT sent to the Python process and notices
95
+ # if processes passed to wait() die by SIGINT (we need to look for
96
+ # both of those cases, because pressing Ctrl+C can result in either
97
+ # the main process or one of the subprocesses getting the signal).
98
+ #
99
+ # Before a SIGINT is seen, wait(p) will simply call p.wait() and
100
+ # return the result. Once a SIGINT has been seen (in the main process
101
+ # or a subprocess, including the one the current call is waiting for),
102
+ # wait(p) will call p.terminate().
103
+ class SigintHandler(object):
104
+ sigint_returncodes = {-signal.SIGINT, # Unix
105
+ -1073741510, # Windows
106
+ }
107
+ def __init__(self):
108
+ self.__lock = threading.Lock()
109
+ self.__processes = set()
110
+ self.__got_sigint = False
111
+ self.__previous_signal = signal.signal(signal.SIGINT, self.interrupt)
112
+
113
+ def __on_sigint(self):
114
+ self.__got_sigint = True
115
+ while self.__processes:
116
+ try:
117
+ self.__processes.pop().terminate()
118
+ except OSError:
119
+ pass
120
+
121
+ def interrupt(self, signal_num, frame):
122
+ with self.__lock:
123
+ self.__on_sigint()
124
+ self.__previous_signal(signal_num, frame)
125
+
126
+ def got_sigint(self):
127
+ with self.__lock:
128
+ return self.__got_sigint
129
+
130
+ def wait(self, p, stdin):
131
+ with self.__lock:
132
+ if self.__got_sigint:
133
+ p.terminate()
134
+ self.__processes.add(p)
135
+ stdout, stderr = p.communicate(stdin)
136
+ code = p.returncode
137
+ with self.__lock:
138
+ self.__processes.discard(p)
139
+ if code in self.sigint_returncodes:
140
+ self.__on_sigint()
141
+ return stdout, stderr
142
+
143
+ sigint_handler = SigintHandler()
144
+
145
+
146
+ class Timer(object):
147
+ def __init__(self, timeout, fn):
148
+ self.completed = False
149
+ self._fn = fn
150
+ self._timer = threading.Timer(timeout, self._onTimer) if timeout else None
151
+
152
+ def __enter__(self):
153
+ if self._timer:
154
+ self._timer.start()
155
+ return self
156
+
157
+ def __exit__(self, _type, _value, _traceback):
158
+ if self._timer:
159
+ self._timer.cancel()
160
+
161
+ def _onTimer(self):
162
+ self._fn()
163
+ self.completed = True
164
+
165
+
166
+ class ThreadPool(object):
167
+ def __init__(self, pool_size=None, timeout=None):
168
+ self.timeout = timeout
169
+ self._pool_size = pool_size or multiprocessing.cpu_count()
170
+ self._messages = []
171
+ self._messages_lock = threading.Lock()
172
+ self._tests = []
173
+ self._tests_lock = threading.Lock()
174
+ self._nonparallel_tests = []
175
+
176
+ def _GetCommand(self, test):
177
+ vpython = 'vpython'
178
+ if test.python3:
179
+ vpython += '3'
180
+ if sys.platform == 'win32':
181
+ vpython += '.bat'
182
+
183
+ cmd = test.cmd
184
+ if cmd[0] == 'python':
185
+ cmd = list(cmd)
186
+ cmd[0] = vpython
187
+ elif cmd[0].endswith('.py'):
188
+ cmd = [vpython] + cmd
189
+
190
+ # On Windows, scripts on the current directory take precedence over PATH, so
191
+ # that when testing depot_tools on Windows, calling `vpython.bat` will
192
+ # execute the copy of vpython of the depot_tools under test instead of the
193
+ # one in the bot.
194
+ # As a workaround, we run the tests from the parent directory instead.
195
+ if (cmd[0] == vpython and
196
+ 'cwd' in test.kwargs and
197
+ os.path.basename(test.kwargs['cwd']) == 'depot_tools'):
198
+ test.kwargs['cwd'] = os.path.dirname(test.kwargs['cwd'])
199
+ cmd[1] = os.path.join('depot_tools', cmd[1])
200
+
201
+ return cmd
202
+
203
+ def _RunWithTimeout(self, cmd, stdin, kwargs):
204
+ p = subprocess.Popen(cmd, **kwargs)
205
+ with Timer(self.timeout, p.terminate) as timer:
206
+ stdout, _ = sigint_handler.wait(p, stdin)
207
+ if timer.completed:
208
+ stdout = 'Process timed out after %ss\n%s' % (self.timeout, stdout)
209
+ return p.returncode, stdout
210
+
211
+ def CallCommand(self, test):
212
+ """Runs an external program.
213
+
214
+ This function converts invocation of .py files and invocations of 'python'
215
+ to vpython invocations.
216
+ """
217
+ cmd = self._GetCommand(test)
218
+ try:
219
+ start = time_time()
220
+ returncode, stdout = self._RunWithTimeout(cmd, test.stdin, test.kwargs)
221
+ duration = time_time() - start
222
+ except Exception:
223
+ duration = time_time() - start
224
+ return test.message(
225
+ '%s\n%s exec failure (%4.2fs)\n%s' % (
226
+ test.name, ' '.join(cmd), duration, traceback.format_exc()))
227
+
228
+ if returncode != 0:
229
+ return test.message(
230
+ '%s\n%s (%4.2fs) failed\n%s' % (
231
+ test.name, ' '.join(cmd), duration, stdout))
232
+
233
+ if test.info:
234
+ return test.info('%s\n%s (%4.2fs)' % (test.name, ' '.join(cmd), duration))
235
+
236
+ def AddTests(self, tests, parallel=True):
237
+ if parallel:
238
+ self._tests.extend(tests)
239
+ else:
240
+ self._nonparallel_tests.extend(tests)
241
+
242
+ def RunAsync(self):
243
+ self._messages = []
244
+
245
+ def _WorkerFn():
246
+ while True:
247
+ test = None
248
+ with self._tests_lock:
249
+ if not self._tests:
250
+ break
251
+ test = self._tests.pop()
252
+ result = self.CallCommand(test)
253
+ if result:
254
+ with self._messages_lock:
255
+ self._messages.append(result)
256
+
257
+ def _StartDaemon():
258
+ t = threading.Thread(target=_WorkerFn)
259
+ t.daemon = True
260
+ t.start()
261
+ return t
262
+
263
+ while self._nonparallel_tests:
264
+ test = self._nonparallel_tests.pop()
265
+ result = self.CallCommand(test)
266
+ if result:
267
+ self._messages.append(result)
268
+
269
+ if self._tests:
270
+ threads = [_StartDaemon() for _ in range(self._pool_size)]
271
+ for worker in threads:
272
+ worker.join()
273
+
274
+ return self._messages
275
+
276
+
277
+ def normpath(path):
278
+ '''Version of os.path.normpath that also changes backward slashes to
279
+ forward slashes when not running on Windows.
280
+ '''
281
+ # This is safe to always do because the Windows version of os.path.normpath
282
+ # will replace forward slashes with backward slashes.
283
+ path = path.replace(os.sep, '/')
284
+ return os.path.normpath(path)
285
+
286
+
287
+ def _RightHandSideLinesImpl(affected_files):
288
+ """Implements RightHandSideLines for InputApi and GclChange."""
289
+ for af in affected_files:
290
+ lines = af.ChangedContents()
291
+ for line in lines:
292
+ yield (af, line[0], line[1])
293
+
294
+
295
+ def prompt_should_continue(prompt_string):
296
+ sys.stdout.write(prompt_string)
297
+ response = sys.stdin.readline().strip().lower()
298
+ return response in ('y', 'yes')
299
+
300
+
301
+ # Top level object so multiprocessing can pickle
302
+ # Public access through OutputApi object.
303
+ class _PresubmitResult(object):
304
+ """Base class for result objects."""
305
+ fatal = False
306
+ should_prompt = False
307
+
308
+ def __init__(self, message, items=None, long_text=''):
309
+ """
310
+ message: A short one-line message to indicate errors.
311
+ items: A list of short strings to indicate where errors occurred.
312
+ long_text: multi-line text output, e.g. from another tool
313
+ """
314
+ self._message = message
315
+ self._items = items or []
316
+ self._long_text = long_text.rstrip()
317
+
318
+ def handle(self):
319
+ sys.stdout.write(self._message)
320
+ sys.stdout.write('\n')
321
+ for index, item in enumerate(self._items):
322
+ sys.stdout.write(' ')
323
+ # Write separately in case it's unicode.
324
+ sys.stdout.write(str(item))
325
+ if index < len(self._items) - 1:
326
+ sys.stdout.write(' \\')
327
+ sys.stdout.write('\n')
328
+ if self._long_text:
329
+ sys.stdout.write('\n***************\n')
330
+ # Write separately in case it's unicode.
331
+ sys.stdout.write(self._long_text)
332
+ sys.stdout.write('\n***************\n')
333
+
334
+ def json_format(self):
335
+ return {
336
+ 'message': self._message,
337
+ 'items': [str(item) for item in self._items],
338
+ 'long_text': self._long_text,
339
+ 'fatal': self.fatal
340
+ }
341
+
342
+
343
+ # Top level object so multiprocessing can pickle
344
+ # Public access through OutputApi object.
345
+ class _PresubmitError(_PresubmitResult):
346
+ """A hard presubmit error."""
347
+ fatal = True
348
+
349
+
350
+ # Top level object so multiprocessing can pickle
351
+ # Public access through OutputApi object.
352
+ class _PresubmitPromptWarning(_PresubmitResult):
353
+ """An warning that prompts the user if they want to continue."""
354
+ should_prompt = True
355
+
356
+
357
+ # Top level object so multiprocessing can pickle
358
+ # Public access through OutputApi object.
359
+ class _PresubmitNotifyResult(_PresubmitResult):
360
+ """Just print something to the screen -- but it's not even a warning."""
361
+ pass
362
+
363
+
364
+ # Top level object so multiprocessing can pickle
365
+ # Public access through OutputApi object.
366
+ class _MailTextResult(_PresubmitResult):
367
+ """A warning that should be included in the review request email."""
368
+ def __init__(self, *args, **kwargs):
369
+ super(_MailTextResult, self).__init__()
370
+ raise NotImplementedError()
371
+
372
+ class GerritAccessor(object):
373
+ """Limited Gerrit functionality for canned presubmit checks to work.
374
+
375
+ To avoid excessive Gerrit calls, caches the results.
376
+ """
377
+
378
+ def __init__(self, host):
379
+ self.host = host
380
+ self.cache = {}
381
+
382
+ def _FetchChangeDetail(self, issue):
383
+ # Separate function to be easily mocked in tests.
384
+ try:
385
+ return gerrit_util.GetChangeDetail(
386
+ self.host, str(issue),
387
+ ['ALL_REVISIONS', 'DETAILED_LABELS', 'ALL_COMMITS'])
388
+ except gerrit_util.GerritError as e:
389
+ if e.http_status == 404:
390
+ raise Exception('Either Gerrit issue %s doesn\'t exist, or '
391
+ 'no credentials to fetch issue details' % issue)
392
+ raise
393
+
394
+ def GetChangeInfo(self, issue):
395
+ """Returns labels and all revisions (patchsets) for this issue.
396
+
397
+ The result is a dictionary according to Gerrit REST Api.
398
+ https://gerrit-review.googlesource.com/Documentation/rest-api.html
399
+
400
+ However, API isn't very clear what's inside, so see tests for example.
401
+ """
402
+ assert issue
403
+ cache_key = int(issue)
404
+ if cache_key not in self.cache:
405
+ self.cache[cache_key] = self._FetchChangeDetail(issue)
406
+ return self.cache[cache_key]
407
+
408
+ def GetChangeDescription(self, issue, patchset=None):
409
+ """If patchset is none, fetches current patchset."""
410
+ info = self.GetChangeInfo(issue)
411
+ # info is a reference to cache. We'll modify it here adding description to
412
+ # it to the right patchset, if it is not yet there.
413
+
414
+ # Find revision info for the patchset we want.
415
+ if patchset is not None:
416
+ for rev, rev_info in info['revisions'].items():
417
+ if str(rev_info['_number']) == str(patchset):
418
+ break
419
+ else:
420
+ raise Exception('patchset %s doesn\'t exist in issue %s' % (
421
+ patchset, issue))
422
+ else:
423
+ rev = info['current_revision']
424
+ rev_info = info['revisions'][rev]
425
+
426
+ return rev_info['commit']['message']
427
+
428
+ def GetDestRef(self, issue):
429
+ ref = self.GetChangeInfo(issue)['branch']
430
+ if not ref.startswith('refs/'):
431
+ # NOTE: it is possible to create 'refs/x' branch,
432
+ # aka 'refs/heads/refs/x'. However, this is ill-advised.
433
+ ref = 'refs/heads/%s' % ref
434
+ return ref
435
+
436
+ def GetChangeOwner(self, issue):
437
+ return self.GetChangeInfo(issue)['owner']['email']
438
+
439
+ def GetChangeReviewers(self, issue, approving_only=True):
440
+ changeinfo = self.GetChangeInfo(issue)
441
+ if approving_only:
442
+ labelinfo = changeinfo.get('labels', {}).get('Code-Review', {})
443
+ values = labelinfo.get('values', {}).keys()
444
+ try:
445
+ max_value = max(int(v) for v in values)
446
+ reviewers = [r for r in labelinfo.get('all', [])
447
+ if r.get('value', 0) == max_value]
448
+ except ValueError: # values is the empty list
449
+ reviewers = []
450
+ else:
451
+ reviewers = changeinfo.get('reviewers', {}).get('REVIEWER', [])
452
+ return [r.get('email') for r in reviewers]
453
+
454
+ def UpdateDescription(self, description, issue):
455
+ gerrit_util.SetCommitMessage(self.host, issue, description, notify='NONE')
456
+
457
+
458
+ class OutputApi(object):
459
+ """An instance of OutputApi gets passed to presubmit scripts so that they
460
+ can output various types of results.
461
+ """
462
+ PresubmitResult = _PresubmitResult
463
+ PresubmitError = _PresubmitError
464
+ PresubmitPromptWarning = _PresubmitPromptWarning
465
+ PresubmitNotifyResult = _PresubmitNotifyResult
466
+ MailTextResult = _MailTextResult
467
+
468
+ def __init__(self, is_committing):
469
+ self.is_committing = is_committing
470
+ self.more_cc = []
471
+
472
+ def AppendCC(self, cc):
473
+ """Appends a user to cc for this change."""
474
+ self.more_cc.append(cc)
475
+
476
+ def PresubmitPromptOrNotify(self, *args, **kwargs):
477
+ """Warn the user when uploading, but only notify if committing."""
478
+ if self.is_committing:
479
+ return self.PresubmitNotifyResult(*args, **kwargs)
480
+ return self.PresubmitPromptWarning(*args, **kwargs)
481
+
482
+
483
+ class InputApi(object):
484
+ """An instance of this object is passed to presubmit scripts so they can
485
+ know stuff about the change they're looking at.
486
+ """
487
+ # Method could be a function
488
+ # pylint: disable=no-self-use
489
+
490
+ # File extensions that are considered source files from a style guide
491
+ # perspective. Don't modify this list from a presubmit script!
492
+ #
493
+ # Files without an extension aren't included in the list. If you want to
494
+ # filter them as source files, add r'(^|.*?[\\\/])[^.]+$' to the allow list.
495
+ # Note that ALL CAPS files are skipped in DEFAULT_FILES_TO_SKIP below.
496
+ DEFAULT_FILES_TO_CHECK = (
497
+ # C++ and friends
498
+ r'.+\.c$', r'.+\.cc$', r'.+\.cpp$', r'.+\.h$', r'.+\.m$', r'.+\.mm$',
499
+ r'.+\.inl$', r'.+\.asm$', r'.+\.hxx$', r'.+\.hpp$', r'.+\.s$', r'.+\.S$',
500
+ # Scripts
501
+ r'.+\.js$', r'.+\.py$', r'.+\.sh$', r'.+\.rb$', r'.+\.pl$', r'.+\.pm$',
502
+ # Other
503
+ r'.+\.java$', r'.+\.mk$', r'.+\.am$', r'.+\.css$', r'.+\.mojom$',
504
+ r'.+\.fidl$'
505
+ )
506
+
507
+ # Path regexp that should be excluded from being considered containing source
508
+ # files. Don't modify this list from a presubmit script!
509
+ DEFAULT_FILES_TO_SKIP = (
510
+ r'testing_support[\\\/]google_appengine[\\\/].*',
511
+ r'.*\bexperimental[\\\/].*',
512
+ # Exclude third_party/.* but NOT third_party/{WebKit,blink}
513
+ # (crbug.com/539768 and crbug.com/836555).
514
+ r'.*\bthird_party[\\\/](?!(WebKit|blink)[\\\/]).*',
515
+ # Output directories (just in case)
516
+ r'.*\bDebug[\\\/].*',
517
+ r'.*\bRelease[\\\/].*',
518
+ r'.*\bxcodebuild[\\\/].*',
519
+ r'.*\bout[\\\/].*',
520
+ # All caps files like README and LICENCE.
521
+ r'.*\b[A-Z0-9_]{2,}$',
522
+ # SCM (can happen in dual SCM configuration). (Slightly over aggressive)
523
+ r'(|.*[\\\/])\.git[\\\/].*',
524
+ r'(|.*[\\\/])\.svn[\\\/].*',
525
+ # There is no point in processing a patch file.
526
+ r'.+\.diff$',
527
+ r'.+\.patch$',
528
+ )
529
+
530
+ # TODO(https://crbug.com/1098562): Remove once no longer used
531
+ @property
532
+ def DEFAULT_WHITE_LIST(self):
533
+ return self.DEFAULT_FILES_TO_CHECK
534
+
535
+ # TODO(https://crbug.com/1098562): Remove once no longer used
536
+ @DEFAULT_WHITE_LIST.setter
537
+ def DEFAULT_WHITE_LIST(self, value):
538
+ self.DEFAULT_FILES_TO_CHECK = value
539
+
540
+ # TODO(https://crbug.com/1098562): Remove once no longer used
541
+ @property
542
+ def DEFAULT_ALLOW_LIST(self):
543
+ return self.DEFAULT_FILES_TO_CHECK
544
+
545
+ # TODO(https://crbug.com/1098562): Remove once no longer used
546
+ @DEFAULT_ALLOW_LIST.setter
547
+ def DEFAULT_ALLOW_LIST(self, value):
548
+ self.DEFAULT_FILES_TO_CHECK = value
549
+
550
+ # TODO(https://crbug.com/1098562): Remove once no longer used
551
+ @property
552
+ def DEFAULT_BLACK_LIST(self):
553
+ return self.DEFAULT_FILES_TO_SKIP
554
+
555
+ # TODO(https://crbug.com/1098562): Remove once no longer used
556
+ @DEFAULT_BLACK_LIST.setter
557
+ def DEFAULT_BLACK_LIST(self, value):
558
+ self.DEFAULT_FILES_TO_SKIP = value
559
+
560
+ # TODO(https://crbug.com/1098562): Remove once no longer used
561
+ @property
562
+ def DEFAULT_BLOCK_LIST(self):
563
+ return self.DEFAULT_FILES_TO_SKIP
564
+
565
+ # TODO(https://crbug.com/1098562): Remove once no longer used
566
+ @DEFAULT_BLOCK_LIST.setter
567
+ def DEFAULT_BLOCK_LIST(self, value):
568
+ self.DEFAULT_FILES_TO_SKIP = value
569
+
570
+ def __init__(self, change, presubmit_path, is_committing,
571
+ verbose, gerrit_obj, dry_run=None, thread_pool=None, parallel=False):
572
+ """Builds an InputApi object.
573
+
574
+ Args:
575
+ change: A presubmit.Change object.
576
+ presubmit_path: The path to the presubmit script being processed.
577
+ is_committing: True if the change is about to be committed.
578
+ gerrit_obj: provides basic Gerrit codereview functionality.
579
+ dry_run: if true, some Checks will be skipped.
580
+ parallel: if true, all tests reported via input_api.RunTests for all
581
+ PRESUBMIT files will be run in parallel.
582
+ """
583
+ # Version number of the presubmit_support script.
584
+ self.version = [int(x) for x in __version__.split('.')]
585
+ self.change = change
586
+ self.is_committing = is_committing
587
+ self.gerrit = gerrit_obj
588
+ self.dry_run = dry_run
589
+
590
+ self.parallel = parallel
591
+ self.thread_pool = thread_pool or ThreadPool()
592
+
593
+ # We expose various modules and functions as attributes of the input_api
594
+ # so that presubmit scripts don't have to import them.
595
+ self.ast = ast
596
+ self.basename = os.path.basename
597
+ self.cpplint = cpplint
598
+ self.fnmatch = fnmatch
599
+ self.gclient_paths = gclient_paths
600
+ # TODO(yyanagisawa): stop exposing this when python3 become default.
601
+ # Since python3's tempfile has TemporaryDirectory, we do not need this.
602
+ self.temporary_directory = gclient_utils.temporary_directory
603
+ self.glob = glob.glob
604
+ self.json = json
605
+ self.logging = logging.getLogger('PRESUBMIT')
606
+ self.os_listdir = os.listdir
607
+ self.os_path = os.path
608
+ self.os_stat = os.stat
609
+ self.os_walk = os.walk
610
+ self.re = re
611
+ self.subprocess = subprocess
612
+ self.sys = sys
613
+ self.tempfile = tempfile
614
+ self.time = time
615
+ self.unittest = unittest
616
+ if sys.version_info.major == 2:
617
+ self.urllib2 = urllib2
618
+ self.urllib_request = urllib_request
619
+ self.urllib_error = urllib_error
620
+
621
+ self.is_windows = sys.platform == 'win32'
622
+
623
+ # Set python_executable to 'vpython' in order to allow scripts in other
624
+ # repos (e.g. src.git) to automatically pick up that repo's .vpython file,
625
+ # instead of inheriting the one in depot_tools.
626
+ self.python_executable = 'vpython'
627
+ self.environ = os.environ
628
+
629
+ # InputApi.platform is the platform you're currently running on.
630
+ self.platform = sys.platform
631
+
632
+ self.cpu_count = multiprocessing.cpu_count()
633
+
634
+ # The local path of the currently-being-processed presubmit script.
635
+ self._current_presubmit_path = os.path.dirname(presubmit_path)
636
+
637
+ # We carry the canned checks so presubmit scripts can easily use them.
638
+ self.canned_checks = presubmit_canned_checks
639
+
640
+ # Temporary files we must manually remove at the end of a run.
641
+ self._named_temporary_files = []
642
+
643
+ # TODO(dpranke): figure out a list of all approved owners for a repo
644
+ # in order to be able to handle wildcard OWNERS files?
645
+ self.owners_db = owners.Database(change.RepositoryRoot(),
646
+ fopen=open, os_path=self.os_path)
647
+ self.owners_finder = owners_finder.OwnersFinder
648
+ self.verbose = verbose
649
+ self.Command = CommandData
650
+
651
+ # Replace <hash_map> and <hash_set> as headers that need to be included
652
+ # with 'base/containers/hash_tables.h' instead.
653
+ # Access to a protected member _XX of a client class
654
+ # pylint: disable=protected-access
655
+ self.cpplint._re_pattern_templates = [
656
+ (a, b, 'base/containers/hash_tables.h')
657
+ if header in ('<hash_map>', '<hash_set>') else (a, b, header)
658
+ for (a, b, header) in cpplint._re_pattern_templates
659
+ ]
660
+
661
+ def SetTimeout(self, timeout):
662
+ self.thread_pool.timeout = timeout
663
+
664
+ def PresubmitLocalPath(self):
665
+ """Returns the local path of the presubmit script currently being run.
666
+
667
+ This is useful if you don't want to hard-code absolute paths in the
668
+ presubmit script. For example, It can be used to find another file
669
+ relative to the PRESUBMIT.py script, so the whole tree can be branched and
670
+ the presubmit script still works, without editing its content.
671
+ """
672
+ return self._current_presubmit_path
673
+
674
+ def AffectedFiles(self, include_deletes=True, file_filter=None):
675
+ """Same as input_api.change.AffectedFiles() except only lists files
676
+ (and optionally directories) in the same directory as the current presubmit
677
+ script, or subdirectories thereof. Note that files are listed using the OS
678
+ path separator, so backslashes are used as separators on Windows.
679
+ """
680
+ dir_with_slash = normpath('%s/' % self.PresubmitLocalPath())
681
+ if len(dir_with_slash) == 1:
682
+ dir_with_slash = ''
683
+
684
+ return list(filter(
685
+ lambda x: normpath(x.AbsoluteLocalPath()).startswith(dir_with_slash),
686
+ self.change.AffectedFiles(include_deletes, file_filter)))
687
+
688
+ def LocalPaths(self):
689
+ """Returns local paths of input_api.AffectedFiles()."""
690
+ paths = [af.LocalPath() for af in self.AffectedFiles()]
691
+ logging.debug('LocalPaths: %s', paths)
692
+ return paths
693
+
694
+ def AbsoluteLocalPaths(self):
695
+ """Returns absolute local paths of input_api.AffectedFiles()."""
696
+ return [af.AbsoluteLocalPath() for af in self.AffectedFiles()]
697
+
698
+ def AffectedTestableFiles(self, include_deletes=None, **kwargs):
699
+ """Same as input_api.change.AffectedTestableFiles() except only lists files
700
+ in the same directory as the current presubmit script, or subdirectories
701
+ thereof.
702
+ """
703
+ if include_deletes is not None:
704
+ warn('AffectedTestableFiles(include_deletes=%s)'
705
+ ' is deprecated and ignored' % str(include_deletes),
706
+ category=DeprecationWarning,
707
+ stacklevel=2)
708
+ return list(filter(
709
+ lambda x: x.IsTestableFile(),
710
+ self.AffectedFiles(include_deletes=False, **kwargs)))
711
+
712
+ def AffectedTextFiles(self, include_deletes=None):
713
+ """An alias to AffectedTestableFiles for backwards compatibility."""
714
+ return self.AffectedTestableFiles(include_deletes=include_deletes)
715
+
716
+ def FilterSourceFile(self, affected_file, files_to_check=None,
717
+ files_to_skip=None, allow_list=None, block_list=None,
718
+ white_list=None, black_list=None):
719
+ """Filters out files that aren't considered 'source file'.
720
+
721
+ If files_to_check or files_to_skip is None, InputApi.DEFAULT_FILES_TO_CHECK
722
+ and InputApi.DEFAULT_FILES_TO_SKIP is used respectively.
723
+
724
+ The lists will be compiled as regular expression and
725
+ AffectedFile.LocalPath() needs to pass both list.
726
+
727
+ Note: if files_to_check or files_to_skip is not set, and
728
+ white_list/allow_list or black_list/block_list is, then those values are
729
+ used. This is used for backward compatibility reasons.
730
+
731
+ Note: Copy-paste this function to suit your needs or use a lambda function.
732
+ """
733
+ # TODO(https://crbug.com/1098560): Add warnings before removing bc.
734
+ if files_to_check is None:
735
+ files_to_check = allow_list or white_list
736
+ if files_to_skip is None:
737
+ files_to_skip = block_list or black_list
738
+
739
+ if files_to_check is None:
740
+ files_to_check = self.DEFAULT_FILES_TO_CHECK
741
+ if files_to_skip is None:
742
+ files_to_skip = self.DEFAULT_FILES_TO_SKIP
743
+
744
+ def Find(affected_file, items):
745
+ local_path = affected_file.LocalPath()
746
+ for item in items:
747
+ if self.re.match(item, local_path):
748
+ return True
749
+ return False
750
+ return (Find(affected_file, files_to_check) and
751
+ not Find(affected_file, files_to_skip))
752
+
753
+ def AffectedSourceFiles(self, source_file):
754
+ """Filter the list of AffectedTestableFiles by the function source_file.
755
+
756
+ If source_file is None, InputApi.FilterSourceFile() is used.
757
+ """
758
+ if not source_file:
759
+ source_file = self.FilterSourceFile
760
+ return list(filter(source_file, self.AffectedTestableFiles()))
761
+
762
+ def RightHandSideLines(self, source_file_filter=None):
763
+ """An iterator over all text lines in 'new' version of changed files.
764
+
765
+ Only lists lines from new or modified text files in the change that are
766
+ contained by the directory of the currently executing presubmit script.
767
+
768
+ This is useful for doing line-by-line regex checks, like checking for
769
+ trailing whitespace.
770
+
771
+ Yields:
772
+ a 3 tuple:
773
+ the AffectedFile instance of the current file;
774
+ integer line number (1-based); and
775
+ the contents of the line as a string.
776
+
777
+ Note: The carriage return (LF or CR) is stripped off.
778
+ """
779
+ files = self.AffectedSourceFiles(source_file_filter)
780
+ return _RightHandSideLinesImpl(files)
781
+
782
+ def ReadFile(self, file_item, mode='r'):
783
+ """Reads an arbitrary file.
784
+
785
+ Deny reading anything outside the repository.
786
+ """
787
+ if isinstance(file_item, AffectedFile):
788
+ file_item = file_item.AbsoluteLocalPath()
789
+ if not file_item.startswith(self.change.RepositoryRoot()):
790
+ raise IOError('Access outside the repository root is denied.')
791
+ return gclient_utils.FileRead(file_item, mode)
792
+
793
+ def CreateTemporaryFile(self, **kwargs):
794
+ """Returns a named temporary file that must be removed with a call to
795
+ RemoveTemporaryFiles().
796
+
797
+ All keyword arguments are forwarded to tempfile.NamedTemporaryFile(),
798
+ except for |delete|, which is always set to False.
799
+
800
+ Presubmit checks that need to create a temporary file and pass it for
801
+ reading should use this function instead of NamedTemporaryFile(), as
802
+ Windows fails to open a file that is already open for writing.
803
+
804
+ with input_api.CreateTemporaryFile() as f:
805
+ f.write('xyz')
806
+ f.close()
807
+ input_api.subprocess.check_output(['script-that', '--reads-from',
808
+ f.name])
809
+
810
+
811
+ Note that callers of CreateTemporaryFile() should not worry about removing
812
+ any temporary file; this is done transparently by the presubmit handling
813
+ code.
814
+ """
815
+ if 'delete' in kwargs:
816
+ # Prevent users from passing |delete|; we take care of file deletion
817
+ # ourselves and this prevents unintuitive error messages when we pass
818
+ # delete=False and 'delete' is also in kwargs.
819
+ raise TypeError('CreateTemporaryFile() does not take a "delete" '
820
+ 'argument, file deletion is handled automatically by '
821
+ 'the same presubmit_support code that creates InputApi '
822
+ 'objects.')
823
+ temp_file = self.tempfile.NamedTemporaryFile(delete=False, **kwargs)
824
+ self._named_temporary_files.append(temp_file.name)
825
+ return temp_file
826
+
827
+ @property
828
+ def tbr(self):
829
+ """Returns if a change is TBR'ed."""
830
+ return 'TBR' in self.change.tags or self.change.TBRsFromDescription()
831
+
832
+ def RunTests(self, tests_mix, parallel=True):
833
+ tests = []
834
+ msgs = []
835
+ for t in tests_mix:
836
+ if isinstance(t, OutputApi.PresubmitResult) and t:
837
+ msgs.append(t)
838
+ else:
839
+ assert issubclass(t.message, _PresubmitResult)
840
+ tests.append(t)
841
+ if self.verbose:
842
+ t.info = _PresubmitNotifyResult
843
+ if not t.kwargs.get('cwd'):
844
+ t.kwargs['cwd'] = self.PresubmitLocalPath()
845
+ self.thread_pool.AddTests(tests, parallel)
846
+ # When self.parallel is True (i.e. --parallel is passed as an option)
847
+ # RunTests doesn't actually run tests. It adds them to a ThreadPool that
848
+ # will run all tests once all PRESUBMIT files are processed.
849
+ # Otherwise, it will run them and return the results.
850
+ if not self.parallel:
851
+ msgs.extend(self.thread_pool.RunAsync())
852
+ return msgs
853
+
854
+
855
+ class _DiffCache(object):
856
+ """Caches diffs retrieved from a particular SCM."""
857
+ def __init__(self, upstream=None):
858
+ """Stores the upstream revision against which all diffs will be computed."""
859
+ self._upstream = upstream
860
+
861
+ def GetDiff(self, path, local_root):
862
+ """Get the diff for a particular path."""
863
+ raise NotImplementedError()
864
+
865
+ def GetOldContents(self, path, local_root):
866
+ """Get the old version for a particular path."""
867
+ raise NotImplementedError()
868
+
869
+
870
+ class _GitDiffCache(_DiffCache):
871
+ """DiffCache implementation for git; gets all file diffs at once."""
872
+ def __init__(self, upstream):
873
+ super(_GitDiffCache, self).__init__(upstream=upstream)
874
+ self._diffs_by_file = None
875
+
876
+ def GetDiff(self, path, local_root):
877
+ if not self._diffs_by_file:
878
+ # Compute a single diff for all files and parse the output; should
879
+ # with git this is much faster than computing one diff for each file.
880
+ diffs = {}
881
+
882
+ # Don't specify any filenames below, because there are command line length
883
+ # limits on some platforms and GenerateDiff would fail.
884
+ unified_diff = scm.GIT.GenerateDiff(local_root, files=[], full_move=True,
885
+ branch=self._upstream)
886
+
887
+ # This regex matches the path twice, separated by a space. Note that
888
+ # filename itself may contain spaces.
889
+ file_marker = re.compile('^diff --git (?P<filename>.*) (?P=filename)$')
890
+ current_diff = []
891
+ keep_line_endings = True
892
+ for x in unified_diff.splitlines(keep_line_endings):
893
+ match = file_marker.match(x)
894
+ if match:
895
+ # Marks the start of a new per-file section.
896
+ diffs[match.group('filename')] = current_diff = [x]
897
+ elif x.startswith('diff --git'):
898
+ raise PresubmitFailure('Unexpected diff line: %s' % x)
899
+ else:
900
+ current_diff.append(x)
901
+
902
+ self._diffs_by_file = dict(
903
+ (normpath(path), ''.join(diff)) for path, diff in diffs.items())
904
+
905
+ if path not in self._diffs_by_file:
906
+ raise PresubmitFailure(
907
+ 'Unified diff did not contain entry for file %s' % path)
908
+
909
+ return self._diffs_by_file[path]
910
+
911
+ def GetOldContents(self, path, local_root):
912
+ return scm.GIT.GetOldContents(local_root, path, branch=self._upstream)
913
+
914
+
915
+ class AffectedFile(object):
916
+ """Representation of a file in a change."""
917
+
918
+ DIFF_CACHE = _DiffCache
919
+
920
+ # Method could be a function
921
+ # pylint: disable=no-self-use
922
+ def __init__(self, path, action, repository_root, diff_cache):
923
+ self._path = path
924
+ self._action = action
925
+ self._local_root = repository_root
926
+ self._is_directory = None
927
+ self._cached_changed_contents = None
928
+ self._cached_new_contents = None
929
+ self._diff_cache = diff_cache
930
+ logging.debug('%s(%s)', self.__class__.__name__, self._path)
931
+
932
+ def LocalPath(self):
933
+ """Returns the path of this file on the local disk relative to client root.
934
+
935
+ This should be used for error messages but not for accessing files,
936
+ because presubmit checks are run with CWD=PresubmitLocalPath() (which is
937
+ often != client root).
938
+ """
939
+ return normpath(self._path)
940
+
941
+ def AbsoluteLocalPath(self):
942
+ """Returns the absolute path of this file on the local disk.
943
+ """
944
+ return os.path.abspath(os.path.join(self._local_root, self.LocalPath()))
945
+
946
+ def Action(self):
947
+ """Returns the action on this opened file, e.g. A, M, D, etc."""
948
+ return self._action
949
+
950
+ def IsTestableFile(self):
951
+ """Returns True if the file is a text file and not a binary file.
952
+
953
+ Deleted files are not text file."""
954
+ raise NotImplementedError() # Implement when needed
955
+
956
+ def IsTextFile(self):
957
+ """An alias to IsTestableFile for backwards compatibility."""
958
+ return self.IsTestableFile()
959
+
960
+ def OldContents(self):
961
+ """Returns an iterator over the lines in the old version of file.
962
+
963
+ The old version is the file before any modifications in the user's
964
+ workspace, i.e. the 'left hand side'.
965
+
966
+ Contents will be empty if the file is a directory or does not exist.
967
+ Note: The carriage returns (LF or CR) are stripped off.
968
+ """
969
+ return self._diff_cache.GetOldContents(self.LocalPath(),
970
+ self._local_root).splitlines()
971
+
972
+ def NewContents(self):
973
+ """Returns an iterator over the lines in the new version of file.
974
+
975
+ The new version is the file in the user's workspace, i.e. the 'right hand
976
+ side'.
977
+
978
+ Contents will be empty if the file is a directory or does not exist.
979
+ Note: The carriage returns (LF or CR) are stripped off.
980
+ """
981
+ if self._cached_new_contents is None:
982
+ self._cached_new_contents = []
983
+ try:
984
+ self._cached_new_contents = gclient_utils.FileRead(
985
+ self.AbsoluteLocalPath(), 'rU').splitlines()
986
+ except IOError:
987
+ pass # File not found? That's fine; maybe it was deleted.
988
+ return self._cached_new_contents[:]
989
+
990
+ def ChangedContents(self):
991
+ """Returns a list of tuples (line number, line text) of all new lines.
992
+
993
+ This relies on the scm diff output describing each changed code section
994
+ with a line of the form
995
+
996
+ ^@@ <old line num>,<old size> <new line num>,<new size> @@$
997
+ """
998
+ if self._cached_changed_contents is not None:
999
+ return self._cached_changed_contents[:]
1000
+ self._cached_changed_contents = []
1001
+ line_num = 0
1002
+
1003
+ for line in self.GenerateScmDiff().splitlines():
1004
+ m = re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
1005
+ if m:
1006
+ line_num = int(m.groups(1)[0])
1007
+ continue
1008
+ if line.startswith('+') and not line.startswith('++'):
1009
+ self._cached_changed_contents.append((line_num, line[1:]))
1010
+ if not line.startswith('-'):
1011
+ line_num += 1
1012
+ return self._cached_changed_contents[:]
1013
+
1014
+ def __str__(self):
1015
+ return self.LocalPath()
1016
+
1017
+ def GenerateScmDiff(self):
1018
+ return self._diff_cache.GetDiff(self.LocalPath(), self._local_root)
1019
+
1020
+
1021
+ class GitAffectedFile(AffectedFile):
1022
+ """Representation of a file in a change out of a git checkout."""
1023
+ # Method 'NNN' is abstract in class 'NNN' but is not overridden
1024
+ # pylint: disable=abstract-method
1025
+
1026
+ DIFF_CACHE = _GitDiffCache
1027
+
1028
+ def __init__(self, *args, **kwargs):
1029
+ AffectedFile.__init__(self, *args, **kwargs)
1030
+ self._server_path = None
1031
+ self._is_testable_file = None
1032
+
1033
+ def IsTestableFile(self):
1034
+ if self._is_testable_file is None:
1035
+ if self.Action() == 'D':
1036
+ # A deleted file is not testable.
1037
+ self._is_testable_file = False
1038
+ else:
1039
+ self._is_testable_file = os.path.isfile(self.AbsoluteLocalPath())
1040
+ return self._is_testable_file
1041
+
1042
+
1043
+ class Change(object):
1044
+ """Describe a change.
1045
+
1046
+ Used directly by the presubmit scripts to query the current change being
1047
+ tested.
1048
+
1049
+ Instance members:
1050
+ tags: Dictionary of KEY=VALUE pairs found in the change description.
1051
+ self.KEY: equivalent to tags['KEY']
1052
+ """
1053
+
1054
+ _AFFECTED_FILES = AffectedFile
1055
+
1056
+ # Matches key/value (or 'tag') lines in changelist descriptions.
1057
+ TAG_LINE_RE = re.compile(
1058
+ '^[ \t]*(?P<key>[A-Z][A-Z_0-9]*)[ \t]*=[ \t]*(?P<value>.*?)[ \t]*$')
1059
+ scm = ''
1060
+
1061
+ def __init__(
1062
+ self, name, description, local_root, files, issue, patchset, author,
1063
+ upstream=None):
1064
+ if files is None:
1065
+ files = []
1066
+ self._name = name
1067
+ # Convert root into an absolute path.
1068
+ self._local_root = os.path.abspath(local_root)
1069
+ self._upstream = upstream
1070
+ self.issue = issue
1071
+ self.patchset = patchset
1072
+ self.author_email = author
1073
+
1074
+ self._full_description = ''
1075
+ self.tags = {}
1076
+ self._description_without_tags = ''
1077
+ self.SetDescriptionText(description)
1078
+
1079
+ assert all(
1080
+ (isinstance(f, (list, tuple)) and len(f) == 2) for f in files), files
1081
+
1082
+ diff_cache = self._AFFECTED_FILES.DIFF_CACHE(self._upstream)
1083
+ self._affected_files = [
1084
+ self._AFFECTED_FILES(path, action.strip(), self._local_root, diff_cache)
1085
+ for action, path in files
1086
+ ]
1087
+
1088
+ def Name(self):
1089
+ """Returns the change name."""
1090
+ return self._name
1091
+
1092
+ def DescriptionText(self):
1093
+ """Returns the user-entered changelist description, minus tags.
1094
+
1095
+ Any line in the user-provided description starting with e.g. 'FOO='
1096
+ (whitespace permitted before and around) is considered a tag line. Such
1097
+ lines are stripped out of the description this function returns.
1098
+ """
1099
+ return self._description_without_tags
1100
+
1101
+ def FullDescriptionText(self):
1102
+ """Returns the complete changelist description including tags."""
1103
+ return self._full_description
1104
+
1105
+ def SetDescriptionText(self, description):
1106
+ """Sets the full description text (including tags) to |description|.
1107
+
1108
+ Also updates the list of tags."""
1109
+ self._full_description = description
1110
+
1111
+ # From the description text, build up a dictionary of key/value pairs
1112
+ # plus the description minus all key/value or 'tag' lines.
1113
+ description_without_tags = []
1114
+ self.tags = {}
1115
+ for line in self._full_description.splitlines():
1116
+ m = self.TAG_LINE_RE.match(line)
1117
+ if m:
1118
+ self.tags[m.group('key')] = m.group('value')
1119
+ else:
1120
+ description_without_tags.append(line)
1121
+
1122
+ # Change back to text and remove whitespace at end.
1123
+ self._description_without_tags = (
1124
+ '\n'.join(description_without_tags).rstrip())
1125
+
1126
+ def AddDescriptionFooter(self, key, value):
1127
+ """Adds the given footer to the change description.
1128
+
1129
+ Args:
1130
+ key: A string with the key for the git footer. It must conform to
1131
+ the git footers format (i.e. 'List-Of-Tokens') and will be case
1132
+ normalized so that each token is title-cased.
1133
+ value: A string with the value for the git footer.
1134
+ """
1135
+ description = git_footers.add_footer(
1136
+ self.FullDescriptionText(), git_footers.normalize_name(key), value)
1137
+ self.SetDescriptionText(description)
1138
+
1139
+ def RepositoryRoot(self):
1140
+ """Returns the repository (checkout) root directory for this change,
1141
+ as an absolute path.
1142
+ """
1143
+ return self._local_root
1144
+
1145
+ def __getattr__(self, attr):
1146
+ """Return tags directly as attributes on the object."""
1147
+ if not re.match(r'^[A-Z_]*$', attr):
1148
+ raise AttributeError(self, attr)
1149
+ return self.tags.get(attr)
1150
+
1151
+ def GitFootersFromDescription(self):
1152
+ """Return the git footers present in the description.
1153
+
1154
+ Returns:
1155
+ footers: A dict of {footer: [values]} containing a multimap of the footers
1156
+ in the change description.
1157
+ """
1158
+ return git_footers.parse_footers(self.FullDescriptionText())
1159
+
1160
+ def BugsFromDescription(self):
1161
+ """Returns all bugs referenced in the commit description."""
1162
+ tags = [b.strip() for b in self.tags.get('BUG', '').split(',') if b.strip()]
1163
+ footers = []
1164
+ parsed = self.GitFootersFromDescription()
1165
+ unsplit_footers = parsed.get('Bug', []) + parsed.get('Fixed', [])
1166
+ for unsplit_footer in unsplit_footers:
1167
+ footers += [b.strip() for b in unsplit_footer.split(',')]
1168
+ return sorted(set(tags + footers))
1169
+
1170
+ def ReviewersFromDescription(self):
1171
+ """Returns all reviewers listed in the commit description."""
1172
+ # We don't support a 'R:' git-footer for reviewers; that is in metadata.
1173
+ tags = [r.strip() for r in self.tags.get('R', '').split(',') if r.strip()]
1174
+ return sorted(set(tags))
1175
+
1176
+ def TBRsFromDescription(self):
1177
+ """Returns all TBR reviewers listed in the commit description."""
1178
+ tags = [r.strip() for r in self.tags.get('TBR', '').split(',') if r.strip()]
1179
+ # TODO(crbug.com/839208): Remove support for 'Tbr:' when TBRs are
1180
+ # programmatically determined by self-CR+1s.
1181
+ footers = self.GitFootersFromDescription().get('Tbr', [])
1182
+ return sorted(set(tags + footers))
1183
+
1184
+ # TODO(crbug.com/753425): Delete these once we're sure they're unused.
1185
+ @property
1186
+ def BUG(self):
1187
+ return ','.join(self.BugsFromDescription())
1188
+ @property
1189
+ def R(self):
1190
+ return ','.join(self.ReviewersFromDescription())
1191
+ @property
1192
+ def TBR(self):
1193
+ return ','.join(self.TBRsFromDescription())
1194
+
1195
+ def AllFiles(self, root=None):
1196
+ """List all files under source control in the repo."""
1197
+ raise NotImplementedError()
1198
+
1199
+ def AffectedFiles(self, include_deletes=True, file_filter=None):
1200
+ """Returns a list of AffectedFile instances for all files in the change.
1201
+
1202
+ Args:
1203
+ include_deletes: If false, deleted files will be filtered out.
1204
+ file_filter: An additional filter to apply.
1205
+
1206
+ Returns:
1207
+ [AffectedFile(path, action), AffectedFile(path, action)]
1208
+ """
1209
+ affected = list(filter(file_filter, self._affected_files))
1210
+
1211
+ if include_deletes:
1212
+ return affected
1213
+ return list(filter(lambda x: x.Action() != 'D', affected))
1214
+
1215
+ def AffectedTestableFiles(self, include_deletes=None, **kwargs):
1216
+ """Return a list of the existing text files in a change."""
1217
+ if include_deletes is not None:
1218
+ warn('AffectedTeestableFiles(include_deletes=%s)'
1219
+ ' is deprecated and ignored' % str(include_deletes),
1220
+ category=DeprecationWarning,
1221
+ stacklevel=2)
1222
+ return list(filter(
1223
+ lambda x: x.IsTestableFile(),
1224
+ self.AffectedFiles(include_deletes=False, **kwargs)))
1225
+
1226
+ def AffectedTextFiles(self, include_deletes=None):
1227
+ """An alias to AffectedTestableFiles for backwards compatibility."""
1228
+ return self.AffectedTestableFiles(include_deletes=include_deletes)
1229
+
1230
+ def LocalPaths(self):
1231
+ """Convenience function."""
1232
+ return [af.LocalPath() for af in self.AffectedFiles()]
1233
+
1234
+ def AbsoluteLocalPaths(self):
1235
+ """Convenience function."""
1236
+ return [af.AbsoluteLocalPath() for af in self.AffectedFiles()]
1237
+
1238
+ def RightHandSideLines(self):
1239
+ """An iterator over all text lines in 'new' version of changed files.
1240
+
1241
+ Lists lines from new or modified text files in the change.
1242
+
1243
+ This is useful for doing line-by-line regex checks, like checking for
1244
+ trailing whitespace.
1245
+
1246
+ Yields:
1247
+ a 3 tuple:
1248
+ the AffectedFile instance of the current file;
1249
+ integer line number (1-based); and
1250
+ the contents of the line as a string.
1251
+ """
1252
+ return _RightHandSideLinesImpl(
1253
+ x for x in self.AffectedFiles(include_deletes=False)
1254
+ if x.IsTestableFile())
1255
+
1256
+ def OriginalOwnersFiles(self):
1257
+ """A map from path names of affected OWNERS files to their old content."""
1258
+ def owners_file_filter(f):
1259
+ return 'OWNERS' in os.path.split(f.LocalPath())[1]
1260
+ files = self.AffectedFiles(file_filter=owners_file_filter)
1261
+ return dict([(f.LocalPath(), f.OldContents()) for f in files])
1262
+
1263
+
1264
+ class GitChange(Change):
1265
+ _AFFECTED_FILES = GitAffectedFile
1266
+ scm = 'git'
1267
+
1268
+ def AllFiles(self, root=None):
1269
+ """List all files under source control in the repo."""
1270
+ root = root or self.RepositoryRoot()
1271
+ return subprocess.check_output(
1272
+ ['git', '-c', 'core.quotePath=false', 'ls-files', '--', '.'],
1273
+ cwd=root).splitlines()
1274
+
1275
+
1276
+ def ListRelevantPresubmitFiles(files, root):
1277
+ """Finds all presubmit files that apply to a given set of source files.
1278
+
1279
+ If inherit-review-settings-ok is present right under root, looks for
1280
+ PRESUBMIT.py in directories enclosing root.
1281
+
1282
+ Args:
1283
+ files: An iterable container containing file paths.
1284
+ root: Path where to stop searching.
1285
+
1286
+ Return:
1287
+ List of absolute paths of the existing PRESUBMIT.py scripts.
1288
+ """
1289
+ files = [normpath(os.path.join(root, f)) for f in files]
1290
+
1291
+ # List all the individual directories containing files.
1292
+ directories = set([os.path.dirname(f) for f in files])
1293
+
1294
+ # Ignore root if inherit-review-settings-ok is present.
1295
+ if os.path.isfile(os.path.join(root, 'inherit-review-settings-ok')):
1296
+ root = None
1297
+
1298
+ # Collect all unique directories that may contain PRESUBMIT.py.
1299
+ candidates = set()
1300
+ for directory in directories:
1301
+ while True:
1302
+ if directory in candidates:
1303
+ break
1304
+ candidates.add(directory)
1305
+ if directory == root:
1306
+ break
1307
+ parent_dir = os.path.dirname(directory)
1308
+ if parent_dir == directory:
1309
+ # We hit the system root directory.
1310
+ break
1311
+ directory = parent_dir
1312
+
1313
+ # Look for PRESUBMIT.py in all candidate directories.
1314
+ results = []
1315
+ for directory in sorted(list(candidates)):
1316
+ try:
1317
+ for f in os.listdir(directory):
1318
+ p = os.path.join(directory, f)
1319
+ if os.path.isfile(p) and re.match(
1320
+ r'PRESUBMIT.*\.py$', f) and not f.startswith('PRESUBMIT_test'):
1321
+ results.append(p)
1322
+ except OSError:
1323
+ pass
1324
+
1325
+ logging.debug('Presubmit files: %s', ','.join(results))
1326
+ return results
1327
+
1328
+
1329
+ class GetTryMastersExecuter(object):
1330
+ @staticmethod
1331
+ def ExecPresubmitScript(script_text, presubmit_path, project, change):
1332
+ """Executes GetPreferredTryMasters() from a single presubmit script.
1333
+
1334
+ Args:
1335
+ script_text: The text of the presubmit script.
1336
+ presubmit_path: Project script to run.
1337
+ project: Project name to pass to presubmit script for bot selection.
1338
+
1339
+ Return:
1340
+ A map of try masters to map of builders to set of tests.
1341
+ """
1342
+ context = {}
1343
+ try:
1344
+ exec(compile(script_text, 'PRESUBMIT.py', 'exec', dont_inherit=True),
1345
+ context)
1346
+ except Exception as e:
1347
+ raise PresubmitFailure('"%s" had an exception.\n%s'
1348
+ % (presubmit_path, e))
1349
+
1350
+ function_name = 'GetPreferredTryMasters'
1351
+ if function_name not in context:
1352
+ return {}
1353
+ get_preferred_try_masters = context[function_name]
1354
+ if not len(inspect.getargspec(get_preferred_try_masters)[0]) == 2:
1355
+ raise PresubmitFailure(
1356
+ 'Expected function "GetPreferredTryMasters" to take two arguments.')
1357
+ return get_preferred_try_masters(project, change)
1358
+
1359
+
1360
+ class GetPostUploadExecuter(object):
1361
+ @staticmethod
1362
+ def ExecPresubmitScript(script_text, presubmit_path, gerrit_obj, change):
1363
+ """Executes PostUploadHook() from a single presubmit script.
1364
+
1365
+ Args:
1366
+ script_text: The text of the presubmit script.
1367
+ presubmit_path: Project script to run.
1368
+ gerrit_obj: The GerritAccessor object.
1369
+ change: The Change object.
1370
+
1371
+ Return:
1372
+ A list of results objects.
1373
+ """
1374
+ context = {}
1375
+ try:
1376
+ exec(compile(script_text, 'PRESUBMIT.py', 'exec', dont_inherit=True),
1377
+ context)
1378
+ except Exception as e:
1379
+ raise PresubmitFailure('"%s" had an exception.\n%s'
1380
+ % (presubmit_path, e))
1381
+
1382
+ function_name = 'PostUploadHook'
1383
+ if function_name not in context:
1384
+ return {}
1385
+ post_upload_hook = context[function_name]
1386
+ if not len(inspect.getargspec(post_upload_hook)[0]) == 3:
1387
+ raise PresubmitFailure(
1388
+ 'Expected function "PostUploadHook" to take three arguments.')
1389
+ return post_upload_hook(gerrit_obj, change, OutputApi(False))
1390
+
1391
+
1392
+ def _MergeMasters(masters1, masters2):
1393
+ """Merges two master maps. Merges also the tests of each builder."""
1394
+ result = {}
1395
+ for (master, builders) in itertools.chain(masters1.items(),
1396
+ masters2.items()):
1397
+ new_builders = result.setdefault(master, {})
1398
+ for (builder, tests) in builders.items():
1399
+ new_builders.setdefault(builder, set([])).update(tests)
1400
+ return result
1401
+
1402
+
1403
+ def DoGetTryMasters(change,
1404
+ changed_files,
1405
+ repository_root,
1406
+ default_presubmit,
1407
+ project,
1408
+ verbose,
1409
+ output_stream):
1410
+ """Get the list of try masters from the presubmit scripts.
1411
+
1412
+ Args:
1413
+ changed_files: List of modified files.
1414
+ repository_root: The repository root.
1415
+ default_presubmit: A default presubmit script to execute in any case.
1416
+ project: Optional name of a project used in selecting trybots.
1417
+ verbose: Prints debug info.
1418
+ output_stream: A stream to write debug output to.
1419
+
1420
+ Return:
1421
+ Map of try masters to map of builders to set of tests.
1422
+ """
1423
+ presubmit_files = ListRelevantPresubmitFiles(changed_files, repository_root)
1424
+ if not presubmit_files and verbose:
1425
+ output_stream.write('Warning, no PRESUBMIT.py found.\n')
1426
+ results = {}
1427
+ executer = GetTryMastersExecuter()
1428
+
1429
+ if default_presubmit:
1430
+ if verbose:
1431
+ output_stream.write('Running default presubmit script.\n')
1432
+ fake_path = os.path.join(repository_root, 'PRESUBMIT.py')
1433
+ results = _MergeMasters(results, executer.ExecPresubmitScript(
1434
+ default_presubmit, fake_path, project, change))
1435
+ for filename in presubmit_files:
1436
+ filename = os.path.abspath(filename)
1437
+ if verbose:
1438
+ output_stream.write('Running %s\n' % filename)
1439
+ # Accept CRLF presubmit script.
1440
+ presubmit_script = gclient_utils.FileRead(filename, 'rU')
1441
+ results = _MergeMasters(results, executer.ExecPresubmitScript(
1442
+ presubmit_script, filename, project, change))
1443
+
1444
+ # Make sets to lists again for later JSON serialization.
1445
+ for builders in results.values():
1446
+ for builder in builders:
1447
+ builders[builder] = list(builders[builder])
1448
+
1449
+ if results and verbose:
1450
+ output_stream.write('%s\n' % str(results))
1451
+ return results
1452
+
1453
+
1454
+ def DoPostUploadExecuter(change,
1455
+ gerrit_obj,
1456
+ verbose):
1457
+ """Execute the post upload hook.
1458
+
1459
+ Args:
1460
+ change: The Change object.
1461
+ gerrit_obj: The GerritAccessor object.
1462
+ verbose: Prints debug info.
1463
+ """
1464
+ presubmit_files = ListRelevantPresubmitFiles(
1465
+ change.LocalPaths(), change.RepositoryRoot())
1466
+ if not presubmit_files and verbose:
1467
+ sys.stdout.write('Warning, no PRESUBMIT.py found.\n')
1468
+ results = []
1469
+ executer = GetPostUploadExecuter()
1470
+ # The root presubmit file should be executed after the ones in subdirectories.
1471
+ # i.e. the specific post upload hooks should run before the general ones.
1472
+ # Thus, reverse the order provided by ListRelevantPresubmitFiles.
1473
+ presubmit_files.reverse()
1474
+
1475
+ for filename in presubmit_files:
1476
+ filename = os.path.abspath(filename)
1477
+ if verbose:
1478
+ sys.stdout.write('Running %s\n' % filename)
1479
+ # Accept CRLF presubmit script.
1480
+ presubmit_script = gclient_utils.FileRead(filename, 'rU')
1481
+ results.extend(executer.ExecPresubmitScript(
1482
+ presubmit_script, filename, gerrit_obj, change))
1483
+
1484
+ if not results:
1485
+ return 0
1486
+
1487
+ sys.stdout.write('\n')
1488
+ sys.stdout.write('** Post Upload Hook Messages **\n')
1489
+
1490
+ exit_code = 0
1491
+ for result in results:
1492
+ if result.fatal:
1493
+ exit_code = 1
1494
+ result.handle()
1495
+ sys.stdout.write('\n')
1496
+
1497
+ return exit_code
1498
+
1499
+
1500
+ class PresubmitExecuter(object):
1501
+ def __init__(self, change, committing, verbose,
1502
+ gerrit_obj, dry_run=None, thread_pool=None, parallel=False):
1503
+ """
1504
+ Args:
1505
+ change: The Change object.
1506
+ committing: True if 'git cl land' is running, False if 'git cl upload' is.
1507
+ gerrit_obj: provides basic Gerrit codereview functionality.
1508
+ dry_run: if true, some Checks will be skipped.
1509
+ parallel: if true, all tests reported via input_api.RunTests for all
1510
+ PRESUBMIT files will be run in parallel.
1511
+ """
1512
+ self.change = change
1513
+ self.committing = committing
1514
+ self.gerrit = gerrit_obj
1515
+ self.verbose = verbose
1516
+ self.dry_run = dry_run
1517
+ self.more_cc = []
1518
+ self.thread_pool = thread_pool
1519
+ self.parallel = parallel
1520
+
1521
+ def ExecPresubmitScript(self, script_text, presubmit_path):
1522
+ """Executes a single presubmit script.
1523
+
1524
+ Args:
1525
+ script_text: The text of the presubmit script.
1526
+ presubmit_path: The path to the presubmit file (this will be reported via
1527
+ input_api.PresubmitLocalPath()).
1528
+
1529
+ Return:
1530
+ A list of result objects, empty if no problems.
1531
+ """
1532
+
1533
+ # Change to the presubmit file's directory to support local imports.
1534
+ main_path = os.getcwd()
1535
+ os.chdir(os.path.dirname(presubmit_path))
1536
+
1537
+ # Load the presubmit script into context.
1538
+ input_api = InputApi(self.change, presubmit_path, self.committing,
1539
+ self.verbose, gerrit_obj=self.gerrit,
1540
+ dry_run=self.dry_run, thread_pool=self.thread_pool,
1541
+ parallel=self.parallel)
1542
+ output_api = OutputApi(self.committing)
1543
+ context = {}
1544
+ try:
1545
+ exec(compile(script_text, 'PRESUBMIT.py', 'exec', dont_inherit=True),
1546
+ context)
1547
+ except Exception as e:
1548
+ raise PresubmitFailure('"%s" had an exception.\n%s' % (presubmit_path, e))
1549
+
1550
+ # These function names must change if we make substantial changes to
1551
+ # the presubmit API that are not backwards compatible.
1552
+ if self.committing:
1553
+ function_name = 'CheckChangeOnCommit'
1554
+ else:
1555
+ function_name = 'CheckChangeOnUpload'
1556
+ if function_name in context:
1557
+ try:
1558
+ context['__args'] = (input_api, output_api)
1559
+ logging.debug('Running %s in %s', function_name, presubmit_path)
1560
+ result = eval(function_name + '(*__args)', context)
1561
+ logging.debug('Running %s done.', function_name)
1562
+ self.more_cc.extend(output_api.more_cc)
1563
+ finally:
1564
+ for f in input_api._named_temporary_files:
1565
+ os.remove(f)
1566
+ if not isinstance(result, (tuple, list)):
1567
+ raise PresubmitFailure(
1568
+ 'Presubmit functions must return a tuple or list')
1569
+ for item in result:
1570
+ if not isinstance(item, OutputApi.PresubmitResult):
1571
+ raise PresubmitFailure(
1572
+ 'All presubmit results must be of types derived from '
1573
+ 'output_api.PresubmitResult')
1574
+ else:
1575
+ result = () # no error since the script doesn't care about current event.
1576
+
1577
+ # Return the process to the original working directory.
1578
+ os.chdir(main_path)
1579
+ return result
1580
+
1581
+ def DoPresubmitChecks(change,
1582
+ committing,
1583
+ verbose,
1584
+ default_presubmit,
1585
+ may_prompt,
1586
+ gerrit_obj,
1587
+ dry_run=None,
1588
+ parallel=False,
1589
+ json_output=None):
1590
+ """Runs all presubmit checks that apply to the files in the change.
1591
+
1592
+ This finds all PRESUBMIT.py files in directories enclosing the files in the
1593
+ change (up to the repository root) and calls the relevant entrypoint function
1594
+ depending on whether the change is being committed or uploaded.
1595
+
1596
+ Prints errors, warnings and notifications. Prompts the user for warnings
1597
+ when needed.
1598
+
1599
+ Args:
1600
+ change: The Change object.
1601
+ committing: True if 'git cl land' is running, False if 'git cl upload' is.
1602
+ verbose: Prints debug info.
1603
+ default_presubmit: A default presubmit script to execute in any case.
1604
+ may_prompt: Enable (y/n) questions on warning or error. If False,
1605
+ any questions are answered with yes by default.
1606
+ gerrit_obj: provides basic Gerrit codereview functionality.
1607
+ dry_run: if true, some Checks will be skipped.
1608
+ parallel: if true, all tests specified by input_api.RunTests in all
1609
+ PRESUBMIT files will be run in parallel.
1610
+
1611
+ Return:
1612
+ 1 if presubmit checks failed or 0 otherwise.
1613
+ """
1614
+ old_environ = os.environ
1615
+ try:
1616
+ # Make sure python subprocesses won't generate .pyc files.
1617
+ os.environ = os.environ.copy()
1618
+ os.environ['PYTHONDONTWRITEBYTECODE'] = '1'
1619
+
1620
+ if committing:
1621
+ sys.stdout.write('Running presubmit commit checks ...\n')
1622
+ else:
1623
+ sys.stdout.write('Running presubmit upload checks ...\n')
1624
+ start_time = time_time()
1625
+ presubmit_files = ListRelevantPresubmitFiles(
1626
+ change.AbsoluteLocalPaths(), change.RepositoryRoot())
1627
+ if not presubmit_files and verbose:
1628
+ sys.stdout.write('Warning, no PRESUBMIT.py found.\n')
1629
+ results = []
1630
+ thread_pool = ThreadPool()
1631
+ executer = PresubmitExecuter(change, committing, verbose, gerrit_obj,
1632
+ dry_run, thread_pool, parallel)
1633
+ if default_presubmit:
1634
+ if verbose:
1635
+ sys.stdout.write('Running default presubmit script.\n')
1636
+ fake_path = os.path.join(change.RepositoryRoot(), 'PRESUBMIT.py')
1637
+ results += executer.ExecPresubmitScript(default_presubmit, fake_path)
1638
+ for filename in presubmit_files:
1639
+ filename = os.path.abspath(filename)
1640
+ if verbose:
1641
+ sys.stdout.write('Running %s\n' % filename)
1642
+ # Accept CRLF presubmit script.
1643
+ presubmit_script = gclient_utils.FileRead(filename, 'rU')
1644
+ results += executer.ExecPresubmitScript(presubmit_script, filename)
1645
+
1646
+ results += thread_pool.RunAsync()
1647
+
1648
+ messages = {}
1649
+ should_prompt = False
1650
+ presubmits_failed = False
1651
+ for result in results:
1652
+ if result.fatal:
1653
+ presubmits_failed = True
1654
+ messages.setdefault('ERRORS', []).append(result)
1655
+ elif result.should_prompt:
1656
+ should_prompt = True
1657
+ messages.setdefault('Warnings', []).append(result)
1658
+ else:
1659
+ messages.setdefault('Messages', []).append(result)
1660
+
1661
+ sys.stdout.write('\n')
1662
+ for name, items in messages.items():
1663
+ sys.stdout.write('** Presubmit %s **\n' % name)
1664
+ for item in items:
1665
+ item.handle()
1666
+ sys.stdout.write('\n')
1667
+
1668
+ total_time = time_time() - start_time
1669
+ if total_time > 1.0:
1670
+ sys.stdout.write(
1671
+ 'Presubmit checks took %.1fs to calculate.\n\n' % total_time)
1672
+
1673
+ if not should_prompt and not presubmits_failed:
1674
+ sys.stdout.write('Presubmit checks passed.\n')
1675
+ elif should_prompt:
1676
+ sys.stdout.write('There were presubmit warnings. ')
1677
+ if may_prompt:
1678
+ presubmits_failed = not prompt_should_continue(
1679
+ 'Are you sure you wish to continue? (y/N): ')
1680
+
1681
+ if json_output:
1682
+ # Write the presubmit results to json output
1683
+ presubmit_results = {
1684
+ 'errors': [
1685
+ error.json_format()
1686
+ for error in messages.get('ERRORS', [])
1687
+ ],
1688
+ 'notifications': [
1689
+ notification.json_format()
1690
+ for notification in messages.get('Messages', [])
1691
+ ],
1692
+ 'warnings': [
1693
+ warning.json_format()
1694
+ for warning in messages.get('Warnings', [])
1695
+ ],
1696
+ 'more_cc': executer.more_cc,
1697
+ }
1698
+
1699
+ gclient_utils.FileWrite(
1700
+ json_output, json.dumps(presubmit_results, sort_keys=True))
1701
+
1702
+ global _ASKED_FOR_FEEDBACK
1703
+ # Ask for feedback one time out of 5.
1704
+ if (len(results) and random.randint(0, 4) == 0 and not _ASKED_FOR_FEEDBACK):
1705
+ sys.stdout.write(
1706
+ 'Was the presubmit check useful? If not, run "git cl presubmit -v"\n'
1707
+ 'to figure out which PRESUBMIT.py was run, then run git blame\n'
1708
+ 'on the file to figure out who to ask for help.\n')
1709
+ _ASKED_FOR_FEEDBACK = True
1710
+
1711
+ return 1 if presubmits_failed else 0
1712
+ finally:
1713
+ os.environ = old_environ
1714
+
1715
+
1716
+ def _scan_sub_dirs(mask, recursive):
1717
+ if not recursive:
1718
+ return [x for x in glob.glob(mask) if x not in ('.svn', '.git')]
1719
+
1720
+ results = []
1721
+ for root, dirs, files in os.walk('.'):
1722
+ if '.svn' in dirs:
1723
+ dirs.remove('.svn')
1724
+ if '.git' in dirs:
1725
+ dirs.remove('.git')
1726
+ for name in files:
1727
+ if fnmatch.fnmatch(name, mask):
1728
+ results.append(os.path.join(root, name))
1729
+ return results
1730
+
1731
+
1732
+ def _parse_files(args, recursive):
1733
+ logging.debug('Searching for %s', args)
1734
+ files = []
1735
+ for arg in args:
1736
+ files.extend([('M', f) for f in _scan_sub_dirs(arg, recursive)])
1737
+ return files
1738
+
1739
+
1740
+ def _parse_change(parser, options):
1741
+ """Process change options.
1742
+
1743
+ Args:
1744
+ parser: The parser used to parse the arguments from command line.
1745
+ options: The arguments parsed from command line.
1746
+ Returns:
1747
+ A GitChange if the change root is a git repository, or a Change otherwise.
1748
+ """
1749
+ if options.files and options.all_files:
1750
+ parser.error('<files> cannot be specified when --all-files is set.')
1751
+
1752
+ change_scm = scm.determine_scm(options.root)
1753
+ if change_scm != 'git' and not options.files:
1754
+ parser.error('<files> is not optional for unversioned directories.')
1755
+
1756
+ if options.files:
1757
+ change_files = _parse_files(options.files, options.recursive)
1758
+ elif options.all_files:
1759
+ change_files = [('M', f) for f in scm.GIT.GetAllFiles(options.root)]
1760
+ else:
1761
+ change_files = scm.GIT.CaptureStatus(
1762
+ options.root, options.upstream or None)
1763
+
1764
+ logging.info('Found %d file(s).', len(change_files))
1765
+
1766
+ change_class = GitChange if change_scm == 'git' else Change
1767
+ return change_class(
1768
+ options.name,
1769
+ options.description,
1770
+ options.root,
1771
+ change_files,
1772
+ options.issue,
1773
+ options.patchset,
1774
+ options.author,
1775
+ upstream=options.upstream)
1776
+
1777
+
1778
+ def _parse_gerrit_options(parser, options):
1779
+ """Process gerrit options.
1780
+
1781
+ SIDE EFFECTS: Modifies options.author and options.description from Gerrit if
1782
+ options.gerrit_fetch is set.
1783
+
1784
+ Args:
1785
+ parser: The parser used to parse the arguments from command line.
1786
+ options: The arguments parsed from command line.
1787
+ Returns:
1788
+ A GerritAccessor object if options.gerrit_url is set, or None otherwise.
1789
+ """
1790
+ gerrit_obj = None
1791
+ if options.gerrit_url:
1792
+ gerrit_obj = GerritAccessor(urlparse.urlparse(options.gerrit_url).netloc)
1793
+
1794
+ if not options.gerrit_fetch:
1795
+ return gerrit_obj
1796
+
1797
+ if not options.gerrit_url or not options.issue or not options.patchset:
1798
+ parser.error(
1799
+ '--gerrit_fetch requires --gerrit_url, --issue and --patchset.')
1800
+
1801
+ options.author = gerrit_obj.GetChangeOwner(options.issue)
1802
+ options.description = gerrit_obj.GetChangeDescription(
1803
+ options.issue, options.patchset)
1804
+
1805
+ logging.info('Got author: "%s"', options.author)
1806
+ logging.info('Got description: """\n%s\n"""', options.description)
1807
+
1808
+ return gerrit_obj
1809
+
1810
+
1811
+ @contextlib.contextmanager
1812
+ def canned_check_filter(method_names):
1813
+ filtered = {}
1814
+ try:
1815
+ for method_name in method_names:
1816
+ if not hasattr(presubmit_canned_checks, method_name):
1817
+ logging.warn('Skipping unknown "canned" check %s' % method_name)
1818
+ continue
1819
+ filtered[method_name] = getattr(presubmit_canned_checks, method_name)
1820
+ setattr(presubmit_canned_checks, method_name, lambda *_a, **_kw: [])
1821
+ yield
1822
+ finally:
1823
+ for name, method in filtered.items():
1824
+ setattr(presubmit_canned_checks, name, method)
1825
+
1826
+
1827
+ def main(argv=None):
1828
+ parser = argparse.ArgumentParser(usage='%(prog)s [options] <files...>')
1829
+ hooks = parser.add_mutually_exclusive_group()
1830
+ hooks.add_argument('-c', '--commit', action='store_true',
1831
+ help='Use commit instead of upload checks.')
1832
+ hooks.add_argument('-u', '--upload', action='store_false', dest='commit',
1833
+ help='Use upload instead of commit checks.')
1834
+ hooks.add_argument('--post_upload', action='store_true',
1835
+ help='Run post-upload commit hooks.')
1836
+ parser.add_argument('-r', '--recursive', action='store_true',
1837
+ help='Act recursively.')
1838
+ parser.add_argument('-v', '--verbose', action='count', default=0,
1839
+ help='Use 2 times for more debug info.')
1840
+ parser.add_argument('--name', default='no name')
1841
+ parser.add_argument('--author')
1842
+ desc = parser.add_mutually_exclusive_group()
1843
+ desc.add_argument('--description', default='', help='The change description.')
1844
+ desc.add_argument('--description_file',
1845
+ help='File to read change description from.')
1846
+ parser.add_argument('--issue', type=int, default=0)
1847
+ parser.add_argument('--patchset', type=int, default=0)
1848
+ parser.add_argument('--root', default=os.getcwd(),
1849
+ help='Search for PRESUBMIT.py up to this directory. '
1850
+ 'If inherit-review-settings-ok is present in this '
1851
+ 'directory, parent directories up to the root file '
1852
+ 'system directories will also be searched.')
1853
+ parser.add_argument('--upstream',
1854
+ help='Git only: the base ref or upstream branch against '
1855
+ 'which the diff should be computed.')
1856
+ parser.add_argument('--default_presubmit')
1857
+ parser.add_argument('--may_prompt', action='store_true', default=False)
1858
+ parser.add_argument('--skip_canned', action='append', default=[],
1859
+ help='A list of checks to skip which appear in '
1860
+ 'presubmit_canned_checks. Can be provided multiple times '
1861
+ 'to skip multiple canned checks.')
1862
+ parser.add_argument('--dry_run', action='store_true', help=argparse.SUPPRESS)
1863
+ parser.add_argument('--gerrit_url', help=argparse.SUPPRESS)
1864
+ parser.add_argument('--gerrit_fetch', action='store_true',
1865
+ help=argparse.SUPPRESS)
1866
+ parser.add_argument('--parallel', action='store_true',
1867
+ help='Run all tests specified by input_api.RunTests in '
1868
+ 'all PRESUBMIT files in parallel.')
1869
+ parser.add_argument('--json_output',
1870
+ help='Write presubmit errors to json output.')
1871
+ parser.add_argument('--all_files', action='store_true',
1872
+ help='Mark all files under source control as modified.')
1873
+ parser.add_argument('files', nargs='*',
1874
+ help='List of files to be marked as modified when '
1875
+ 'executing presubmit or post-upload hooks. fnmatch '
1876
+ 'wildcards can also be used.')
1877
+
1878
+ options = parser.parse_args(argv)
1879
+
1880
+ log_level = logging.ERROR
1881
+ if options.verbose >= 2:
1882
+ log_level = logging.DEBUG
1883
+ elif options.verbose:
1884
+ log_level = logging.INFO
1885
+ log_format = ('[%(levelname).1s%(asctime)s %(process)d %(thread)d '
1886
+ '%(filename)s] %(message)s')
1887
+ logging.basicConfig(format=log_format, level=log_level)
1888
+
1889
+ if options.description_file:
1890
+ options.description = gclient_utils.FileRead(options.description_file)
1891
+ gerrit_obj = _parse_gerrit_options(parser, options)
1892
+ change = _parse_change(parser, options)
1893
+
1894
+ try:
1895
+ if options.post_upload:
1896
+ return DoPostUploadExecuter(
1897
+ change,
1898
+ gerrit_obj,
1899
+ options.verbose)
1900
+ with canned_check_filter(options.skip_canned):
1901
+ return DoPresubmitChecks(
1902
+ change,
1903
+ options.commit,
1904
+ options.verbose,
1905
+ options.default_presubmit,
1906
+ options.may_prompt,
1907
+ gerrit_obj,
1908
+ options.dry_run,
1909
+ options.parallel,
1910
+ options.json_output)
1911
+ except PresubmitFailure as e:
1912
+ print(e, file=sys.stderr)
1913
+ print('Maybe your depot_tools is out of date?', file=sys.stderr)
1914
+ return 2
1915
+
1916
+
1917
+ if __name__ == '__main__':
1918
+ fix_encoding.fix_encoding()
1919
+ try:
1920
+ sys.exit(main())
1921
+ except KeyboardInterrupt:
1922
+ sys.stderr.write('interrupted\n')
1923
+ sys.exit(2)