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