index.js 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.Registry = void 0;
  6. exports.browserDirectoryToMarkerFilePath = browserDirectoryToMarkerFilePath;
  7. exports.buildPlaywrightCLICommand = buildPlaywrightCLICommand;
  8. exports.findChromiumChannel = findChromiumChannel;
  9. exports.installBrowsersForNpmInstall = installBrowsersForNpmInstall;
  10. exports.installDefaultBrowsersForNpmInstall = installDefaultBrowsersForNpmInstall;
  11. exports.registryDirectory = exports.registry = void 0;
  12. Object.defineProperty(exports, "writeDockerVersion", {
  13. enumerable: true,
  14. get: function () {
  15. return _dependencies.writeDockerVersion;
  16. }
  17. });
  18. var os = _interopRequireWildcard(require("os"));
  19. var _path = _interopRequireDefault(require("path"));
  20. var util = _interopRequireWildcard(require("util"));
  21. var fs = _interopRequireWildcard(require("fs"));
  22. var _utilsBundle = require("../../utilsBundle");
  23. var _linuxUtils = require("../../utils/linuxUtils");
  24. var _network = require("../../utils/network");
  25. var _userAgent = require("../../utils/userAgent");
  26. var _utils = require("../../utils");
  27. var _fileUtils = require("../../utils/fileUtils");
  28. var _hostPlatform = require("../../utils/hostPlatform");
  29. var _spawnAsync = require("../../utils/spawnAsync");
  30. var _dependencies = require("./dependencies");
  31. var _browserFetcher = require("./browserFetcher");
  32. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  33. function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
  34. function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  35. /**
  36. * Copyright 2017 Google Inc. All rights reserved.
  37. * Modifications copyright (c) Microsoft Corporation.
  38. *
  39. * Licensed under the Apache License, Version 2.0 (the "License");
  40. * you may not use this file except in compliance with the License.
  41. * You may obtain a copy of the License at
  42. *
  43. * http://www.apache.org/licenses/LICENSE-2.0
  44. *
  45. * Unless required by applicable law or agreed to in writing, software
  46. * distributed under the License is distributed on an "AS IS" BASIS,
  47. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  48. * See the License for the specific language governing permissions and
  49. * limitations under the License.
  50. */
  51. const PACKAGE_PATH = _path.default.join(__dirname, '..', '..', '..');
  52. const BIN_PATH = _path.default.join(__dirname, '..', '..', '..', 'bin');
  53. const PLAYWRIGHT_CDN_MIRRORS = ['https://playwright.azureedge.net', 'https://playwright-akamai.azureedge.net', 'https://playwright-verizon.azureedge.net'];
  54. if (process.env.PW_TEST_CDN_THAT_SHOULD_WORK) {
  55. for (let i = 0; i < PLAYWRIGHT_CDN_MIRRORS.length; i++) {
  56. const cdn = PLAYWRIGHT_CDN_MIRRORS[i];
  57. if (cdn !== process.env.PW_TEST_CDN_THAT_SHOULD_WORK) PLAYWRIGHT_CDN_MIRRORS[i] = cdn + '.does-not-resolve.playwright.dev';
  58. }
  59. }
  60. const EXECUTABLE_PATHS = {
  61. 'chromium': {
  62. 'linux': ['chrome-linux', 'chrome'],
  63. 'mac': ['chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium'],
  64. 'win': ['chrome-win', 'chrome.exe']
  65. },
  66. 'firefox': {
  67. 'linux': ['firefox', 'firefox'],
  68. 'mac': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'],
  69. 'win': ['firefox', 'firefox.exe']
  70. },
  71. 'webkit': {
  72. 'linux': ['pw_run.sh'],
  73. 'mac': ['pw_run.sh'],
  74. 'win': ['Playwright.exe']
  75. },
  76. 'ffmpeg': {
  77. 'linux': ['ffmpeg-linux'],
  78. 'mac': ['ffmpeg-mac'],
  79. 'win': ['ffmpeg-win64.exe']
  80. }
  81. };
  82. const DOWNLOAD_PATHS = {
  83. 'chromium': {
  84. '<unknown>': undefined,
  85. 'ubuntu18.04-x64': 'builds/chromium/%s/chromium-linux.zip',
  86. 'ubuntu20.04-x64': 'builds/chromium/%s/chromium-linux.zip',
  87. 'ubuntu22.04-x64': 'builds/chromium/%s/chromium-linux.zip',
  88. 'ubuntu18.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
  89. 'ubuntu20.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
  90. 'ubuntu22.04-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
  91. 'debian11-x64': 'builds/chromium/%s/chromium-linux.zip',
  92. 'debian11-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
  93. 'debian12-x64': 'builds/chromium/%s/chromium-linux.zip',
  94. 'debian12-arm64': 'builds/chromium/%s/chromium-linux-arm64.zip',
  95. 'mac10.13': 'builds/chromium/%s/chromium-mac.zip',
  96. 'mac10.14': 'builds/chromium/%s/chromium-mac.zip',
  97. 'mac10.15': 'builds/chromium/%s/chromium-mac.zip',
  98. 'mac11': 'builds/chromium/%s/chromium-mac.zip',
  99. 'mac11-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip',
  100. 'mac12': 'builds/chromium/%s/chromium-mac.zip',
  101. 'mac12-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip',
  102. 'mac13': 'builds/chromium/%s/chromium-mac.zip',
  103. 'mac13-arm64': 'builds/chromium/%s/chromium-mac-arm64.zip',
  104. 'win64': 'builds/chromium/%s/chromium-win64.zip'
  105. },
  106. 'chromium-tip-of-tree': {
  107. '<unknown>': undefined,
  108. 'ubuntu18.04-x64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
  109. 'ubuntu20.04-x64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
  110. 'ubuntu22.04-x64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
  111. 'ubuntu18.04-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
  112. 'ubuntu20.04-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
  113. 'ubuntu22.04-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
  114. 'debian11-x64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
  115. 'debian11-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
  116. 'debian12-x64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux.zip',
  117. 'debian12-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip',
  118. 'mac10.13': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
  119. 'mac10.14': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
  120. 'mac10.15': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
  121. 'mac11': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
  122. 'mac11-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac-arm64.zip',
  123. 'mac12': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
  124. 'mac12-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac-arm64.zip',
  125. 'mac13': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac.zip',
  126. 'mac13-arm64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-mac-arm64.zip',
  127. 'win64': 'builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-win64.zip'
  128. },
  129. 'chromium-with-symbols': {
  130. '<unknown>': undefined,
  131. 'ubuntu18.04-x64': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
  132. 'ubuntu20.04-x64': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
  133. 'ubuntu22.04-x64': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
  134. 'ubuntu18.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
  135. 'ubuntu20.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
  136. 'ubuntu22.04-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
  137. 'debian11-x64': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
  138. 'debian11-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
  139. 'debian12-x64': 'builds/chromium/%s/chromium-with-symbols-linux.zip',
  140. 'debian12-arm64': 'builds/chromium/%s/chromium-with-symbols-linux-arm64.zip',
  141. 'mac10.13': 'builds/chromium/%s/chromium-with-symbols-mac.zip',
  142. 'mac10.14': 'builds/chromium/%s/chromium-with-symbols-mac.zip',
  143. 'mac10.15': 'builds/chromium/%s/chromium-with-symbols-mac.zip',
  144. 'mac11': 'builds/chromium/%s/chromium-with-symbols-mac.zip',
  145. 'mac11-arm64': 'builds/chromium/%s/chromium-with-symbols-mac-arm64.zip',
  146. 'mac12': 'builds/chromium/%s/chromium-with-symbols-mac.zip',
  147. 'mac12-arm64': 'builds/chromium/%s/chromium-with-symbols-mac-arm64.zip',
  148. 'mac13': 'builds/chromium/%s/chromium-with-symbols-mac.zip',
  149. 'mac13-arm64': 'builds/chromium/%s/chromium-with-symbols-mac-arm64.zip',
  150. 'win64': 'builds/chromium/%s/chromium-with-symbols-win64.zip'
  151. },
  152. 'firefox': {
  153. '<unknown>': undefined,
  154. 'ubuntu18.04-x64': 'builds/firefox/%s/firefox-ubuntu-18.04.zip',
  155. 'ubuntu20.04-x64': 'builds/firefox/%s/firefox-ubuntu-20.04.zip',
  156. 'ubuntu22.04-x64': 'builds/firefox/%s/firefox-ubuntu-22.04.zip',
  157. 'ubuntu18.04-arm64': undefined,
  158. 'ubuntu20.04-arm64': 'builds/firefox/%s/firefox-ubuntu-20.04-arm64.zip',
  159. 'ubuntu22.04-arm64': 'builds/firefox/%s/firefox-ubuntu-22.04-arm64.zip',
  160. 'debian11-x64': 'builds/firefox/%s/firefox-debian-11.zip',
  161. 'debian11-arm64': 'builds/firefox/%s/firefox-debian-11-arm64.zip',
  162. 'debian12-x64': 'builds/firefox/%s/firefox-debian-12.zip',
  163. 'debian12-arm64': 'builds/firefox/%s/firefox-debian-12-arm64.zip',
  164. 'mac10.13': 'builds/firefox/%s/firefox-mac-13.zip',
  165. 'mac10.14': 'builds/firefox/%s/firefox-mac-13.zip',
  166. 'mac10.15': 'builds/firefox/%s/firefox-mac-13.zip',
  167. 'mac11': 'builds/firefox/%s/firefox-mac-13.zip',
  168. 'mac11-arm64': 'builds/firefox/%s/firefox-mac-13-arm64.zip',
  169. 'mac12': 'builds/firefox/%s/firefox-mac-13.zip',
  170. 'mac12-arm64': 'builds/firefox/%s/firefox-mac-13-arm64.zip',
  171. 'mac13': 'builds/firefox/%s/firefox-mac-13.zip',
  172. 'mac13-arm64': 'builds/firefox/%s/firefox-mac-13-arm64.zip',
  173. 'win64': 'builds/firefox/%s/firefox-win64.zip'
  174. },
  175. 'firefox-beta': {
  176. '<unknown>': undefined,
  177. 'ubuntu18.04-x64': 'builds/firefox-beta/%s/firefox-beta-ubuntu-18.04.zip',
  178. 'ubuntu20.04-x64': 'builds/firefox-beta/%s/firefox-beta-ubuntu-20.04.zip',
  179. 'ubuntu22.04-x64': 'builds/firefox-beta/%s/firefox-beta-ubuntu-22.04.zip',
  180. 'ubuntu18.04-arm64': undefined,
  181. 'ubuntu20.04-arm64': undefined,
  182. 'ubuntu22.04-arm64': 'builds/firefox-beta/%s/firefox-beta-ubuntu-22.04-arm64.zip',
  183. 'debian11-x64': 'builds/firefox-beta/%s/firefox-beta-debian-11.zip',
  184. 'debian11-arm64': 'builds/firefox-beta/%s/firefox-beta-debian-11-arm64.zip',
  185. 'debian12-x64': 'builds/firefox-beta/%s/firefox-beta-debian-12.zip',
  186. 'debian12-arm64': 'builds/firefox-beta/%s/firefox-beta-debian-12-arm64.zip',
  187. 'mac10.13': 'builds/firefox-beta/%s/firefox-beta-mac-13.zip',
  188. 'mac10.14': 'builds/firefox-beta/%s/firefox-beta-mac-13.zip',
  189. 'mac10.15': 'builds/firefox-beta/%s/firefox-beta-mac-13.zip',
  190. 'mac11': 'builds/firefox-beta/%s/firefox-beta-mac-13.zip',
  191. 'mac11-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-13-arm64.zip',
  192. 'mac12': 'builds/firefox-beta/%s/firefox-beta-mac-13.zip',
  193. 'mac12-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-13-arm64.zip',
  194. 'mac13': 'builds/firefox-beta/%s/firefox-beta-mac-13.zip',
  195. 'mac13-arm64': 'builds/firefox-beta/%s/firefox-beta-mac-13-arm64.zip',
  196. 'win64': 'builds/firefox-beta/%s/firefox-beta-win64.zip'
  197. },
  198. 'firefox-asan': {
  199. '<unknown>': undefined,
  200. 'ubuntu18.04-x64': undefined,
  201. 'ubuntu20.04-x64': undefined,
  202. 'ubuntu22.04-x64': 'builds/firefox/%s/firefox-asan-ubuntu-22.04.zip',
  203. 'ubuntu18.04-arm64': undefined,
  204. 'ubuntu20.04-arm64': undefined,
  205. 'ubuntu22.04-arm64': undefined,
  206. 'debian11-x64': undefined,
  207. 'debian11-arm64': undefined,
  208. 'debian12-x64': undefined,
  209. 'debian12-arm64': undefined,
  210. 'mac10.13': 'builds/firefox/%s/firefox-asan-mac-13.zip',
  211. 'mac10.14': 'builds/firefox/%s/firefox-asan-mac-13.zip',
  212. 'mac10.15': 'builds/firefox/%s/firefox-asan-mac-13.zip',
  213. 'mac11': 'builds/firefox/%s/firefox-asan-mac-13.zip',
  214. 'mac11-arm64': undefined,
  215. 'mac12': 'builds/firefox/%s/firefox-asan-mac-13.zip',
  216. 'mac12-arm64': undefined,
  217. 'mac13': 'builds/firefox/%s/firefox-asan-mac-13.zip',
  218. 'mac13-arm64': undefined,
  219. 'win64': undefined
  220. },
  221. 'webkit': {
  222. '<unknown>': undefined,
  223. 'ubuntu18.04-x64': 'builds/deprecated-webkit-ubuntu-18.04/%s/deprecated-webkit-ubuntu-18.04.zip',
  224. 'ubuntu20.04-x64': 'builds/webkit/%s/webkit-ubuntu-20.04.zip',
  225. 'ubuntu22.04-x64': 'builds/webkit/%s/webkit-ubuntu-22.04.zip',
  226. 'ubuntu18.04-arm64': undefined,
  227. 'ubuntu20.04-arm64': 'builds/webkit/%s/webkit-ubuntu-20.04-arm64.zip',
  228. 'ubuntu22.04-arm64': 'builds/webkit/%s/webkit-ubuntu-22.04-arm64.zip',
  229. 'debian11-x64': 'builds/webkit/%s/webkit-debian-11.zip',
  230. 'debian11-arm64': 'builds/webkit/%s/webkit-debian-11-arm64.zip',
  231. 'debian12-x64': 'builds/webkit/%s/webkit-debian-12.zip',
  232. 'debian12-arm64': 'builds/webkit/%s/webkit-debian-12-arm64.zip',
  233. 'mac10.13': undefined,
  234. 'mac10.14': 'builds/deprecated-webkit-mac-10.14/%s/deprecated-webkit-mac-10.14.zip',
  235. 'mac10.15': 'builds/deprecated-webkit-mac-10.15/%s/deprecated-webkit-mac-10.15.zip',
  236. 'mac11': 'builds/webkit/%s/webkit-mac-11.zip',
  237. 'mac11-arm64': 'builds/webkit/%s/webkit-mac-11-arm64.zip',
  238. 'mac12': 'builds/webkit/%s/webkit-mac-12.zip',
  239. 'mac12-arm64': 'builds/webkit/%s/webkit-mac-12-arm64.zip',
  240. 'mac13': 'builds/webkit/%s/webkit-mac-13.zip',
  241. 'mac13-arm64': 'builds/webkit/%s/webkit-mac-13-arm64.zip',
  242. 'win64': 'builds/webkit/%s/webkit-win64.zip'
  243. },
  244. 'ffmpeg': {
  245. '<unknown>': undefined,
  246. 'ubuntu18.04-x64': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
  247. 'ubuntu20.04-x64': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
  248. 'ubuntu22.04-x64': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
  249. 'ubuntu18.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
  250. 'ubuntu20.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
  251. 'ubuntu22.04-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
  252. 'debian11-x64': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
  253. 'debian11-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
  254. 'debian12-x64': 'builds/ffmpeg/%s/ffmpeg-linux.zip',
  255. 'debian12-arm64': 'builds/ffmpeg/%s/ffmpeg-linux-arm64.zip',
  256. 'mac10.13': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
  257. 'mac10.14': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
  258. 'mac10.15': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
  259. 'mac11': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
  260. 'mac11-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip',
  261. 'mac12': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
  262. 'mac12-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip',
  263. 'mac13': 'builds/ffmpeg/%s/ffmpeg-mac.zip',
  264. 'mac13-arm64': 'builds/ffmpeg/%s/ffmpeg-mac-arm64.zip',
  265. 'win64': 'builds/ffmpeg/%s/ffmpeg-win64.zip'
  266. },
  267. 'android': {
  268. '<unknown>': 'builds/android/%s/android.zip',
  269. 'ubuntu18.04-x64': 'builds/android/%s/android.zip',
  270. 'ubuntu20.04-x64': 'builds/android/%s/android.zip',
  271. 'ubuntu22.04-x64': 'builds/android/%s/android.zip',
  272. 'ubuntu18.04-arm64': 'builds/android/%s/android.zip',
  273. 'ubuntu20.04-arm64': 'builds/android/%s/android.zip',
  274. 'ubuntu22.04-arm64': 'builds/android/%s/android.zip',
  275. 'debian11-x64': 'builds/android/%s/android.zip',
  276. 'debian11-arm64': 'builds/android/%s/android.zip',
  277. 'debian12-x64': 'builds/android/%s/android.zip',
  278. 'debian12-arm64': 'builds/android/%s/android.zip',
  279. 'mac10.13': 'builds/android/%s/android.zip',
  280. 'mac10.14': 'builds/android/%s/android.zip',
  281. 'mac10.15': 'builds/android/%s/android.zip',
  282. 'mac11': 'builds/android/%s/android.zip',
  283. 'mac11-arm64': 'builds/android/%s/android.zip',
  284. 'mac12': 'builds/android/%s/android.zip',
  285. 'mac12-arm64': 'builds/android/%s/android.zip',
  286. 'mac13': 'builds/android/%s/android.zip',
  287. 'mac13-arm64': 'builds/android/%s/android.zip',
  288. 'win64': 'builds/android/%s/android.zip'
  289. }
  290. };
  291. const registryDirectory = exports.registryDirectory = (() => {
  292. let result;
  293. const envDefined = (0, _utils.getFromENV)('PLAYWRIGHT_BROWSERS_PATH');
  294. if (envDefined === '0') {
  295. result = _path.default.join(__dirname, '..', '..', '..', '.local-browsers');
  296. } else if (envDefined) {
  297. result = envDefined;
  298. } else {
  299. let cacheDirectory;
  300. if (process.platform === 'linux') cacheDirectory = process.env.XDG_CACHE_HOME || _path.default.join(os.homedir(), '.cache');else if (process.platform === 'darwin') cacheDirectory = _path.default.join(os.homedir(), 'Library', 'Caches');else if (process.platform === 'win32') cacheDirectory = process.env.LOCALAPPDATA || _path.default.join(os.homedir(), 'AppData', 'Local');else throw new Error('Unsupported platform: ' + process.platform);
  301. result = _path.default.join(cacheDirectory, 'ms-playwright');
  302. }
  303. if (!_path.default.isAbsolute(result)) {
  304. // It is important to resolve to the absolute path:
  305. // - for unzipping to work correctly;
  306. // - so that registry directory matches between installation and execution.
  307. // INIT_CWD points to the root of `npm/yarn install` and is probably what
  308. // the user meant when typing the relative path.
  309. result = _path.default.resolve((0, _utils.getFromENV)('INIT_CWD') || process.cwd(), result);
  310. }
  311. return result;
  312. })();
  313. function isBrowserDirectory(browserDirectory) {
  314. const baseName = _path.default.basename(browserDirectory);
  315. for (const browserName of allDownloadable) {
  316. if (baseName.startsWith(browserName + '-')) return true;
  317. }
  318. return false;
  319. }
  320. function readDescriptors(browsersJSON) {
  321. return browsersJSON['browsers'].map(obj => {
  322. const name = obj.name;
  323. const revisionOverride = (obj.revisionOverrides || {})[_hostPlatform.hostPlatform];
  324. const revision = revisionOverride || obj.revision;
  325. const browserDirectoryPrefix = revisionOverride ? `${name}_${_hostPlatform.hostPlatform}_special` : `${name}`;
  326. const descriptor = {
  327. name,
  328. revision,
  329. // We only put browser version for the supported operating systems.
  330. browserVersion: revisionOverride ? undefined : obj.browserVersion,
  331. installByDefault: !!obj.installByDefault,
  332. // Method `isBrowserDirectory` determines directory to be browser iff
  333. // it starts with some browser name followed by '-'. Some browser names
  334. // are prefixes of others, e.g. 'webkit' is a prefix of `webkit-technology-preview`.
  335. // To avoid older registries erroneously removing 'webkit-technology-preview', we have to
  336. // ensure that browser folders to never include dashes inside.
  337. dir: _path.default.join(registryDirectory, browserDirectoryPrefix.replace(/-/g, '_') + '-' + revision)
  338. };
  339. return descriptor;
  340. });
  341. }
  342. const allDownloadable = ['chromium', 'firefox', 'webkit', 'ffmpeg', 'firefox-beta', 'chromium-with-symbols', 'chromium-tip-of-tree'];
  343. class Registry {
  344. constructor(browsersJSON) {
  345. this._executables = void 0;
  346. const descriptors = readDescriptors(browsersJSON);
  347. const findExecutablePath = (dir, name) => {
  348. let tokens = undefined;
  349. if (process.platform === 'linux') tokens = EXECUTABLE_PATHS[name]['linux'];else if (process.platform === 'darwin') tokens = EXECUTABLE_PATHS[name]['mac'];else if (process.platform === 'win32') tokens = EXECUTABLE_PATHS[name]['win'];
  350. return tokens ? _path.default.join(dir, ...tokens) : undefined;
  351. };
  352. const executablePathOrDie = (name, e, installByDefault, sdkLanguage) => {
  353. if (!e) throw new Error(`${name} is not supported on ${_hostPlatform.hostPlatform}`);
  354. const installCommand = buildPlaywrightCLICommand(sdkLanguage, `install${installByDefault ? '' : ' ' + name}`);
  355. if (!(0, _fileUtils.canAccessFile)(e)) {
  356. const currentDockerVersion = (0, _dependencies.readDockerVersionSync)();
  357. const preferredDockerVersion = currentDockerVersion ? (0, _dependencies.dockerVersion)(currentDockerVersion.dockerImageNameTemplate) : null;
  358. const isOutdatedDockerImage = currentDockerVersion && preferredDockerVersion && currentDockerVersion.dockerImageName !== preferredDockerVersion.dockerImageName;
  359. const prettyMessage = isOutdatedDockerImage ? [`Looks like ${sdkLanguage === 'javascript' ? 'Playwright Test or ' : ''}Playwright was just updated to ${preferredDockerVersion.driverVersion}.`, `Please update docker image as well.`, `- current: ${currentDockerVersion.dockerImageName}`, `- required: ${preferredDockerVersion.dockerImageName}`, ``, `<3 Playwright Team`].join('\n') : [`Looks like ${sdkLanguage === 'javascript' ? 'Playwright Test or ' : ''}Playwright was just installed or updated.`, `Please run the following command to download new browser${installByDefault ? 's' : ''}:`, ``, ` ${installCommand}`, ``, `<3 Playwright Team`].join('\n');
  360. throw new Error(`Executable doesn't exist at ${e}\n${(0, _utils.wrapInASCIIBox)(prettyMessage, 1)}`);
  361. }
  362. return e;
  363. };
  364. this._executables = [];
  365. const chromium = descriptors.find(d => d.name === 'chromium');
  366. const chromiumExecutable = findExecutablePath(chromium.dir, 'chromium');
  367. this._executables.push({
  368. type: 'browser',
  369. name: 'chromium',
  370. browserName: 'chromium',
  371. directory: chromium.dir,
  372. executablePath: () => chromiumExecutable,
  373. executablePathOrDie: sdkLanguage => executablePathOrDie('chromium', chromiumExecutable, chromium.installByDefault, sdkLanguage),
  374. installType: chromium.installByDefault ? 'download-by-default' : 'download-on-demand',
  375. validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'chromium', chromium.dir, ['chrome-linux'], [], ['chrome-win']),
  376. downloadURLs: this._downloadURLs(chromium),
  377. browserVersion: chromium.browserVersion,
  378. _install: () => this._downloadExecutable(chromium, chromiumExecutable),
  379. _dependencyGroup: 'chromium',
  380. _isHermeticInstallation: true
  381. });
  382. const chromiumWithSymbols = descriptors.find(d => d.name === 'chromium-with-symbols');
  383. const chromiumWithSymbolsExecutable = findExecutablePath(chromiumWithSymbols.dir, 'chromium');
  384. this._executables.push({
  385. type: 'tool',
  386. name: 'chromium-with-symbols',
  387. browserName: 'chromium',
  388. directory: chromiumWithSymbols.dir,
  389. executablePath: () => chromiumWithSymbolsExecutable,
  390. executablePathOrDie: sdkLanguage => executablePathOrDie('chromium-with-symbols', chromiumWithSymbolsExecutable, chromiumWithSymbols.installByDefault, sdkLanguage),
  391. installType: chromiumWithSymbols.installByDefault ? 'download-by-default' : 'download-on-demand',
  392. validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'chromium', chromiumWithSymbols.dir, ['chrome-linux'], [], ['chrome-win']),
  393. downloadURLs: this._downloadURLs(chromiumWithSymbols),
  394. browserVersion: chromiumWithSymbols.browserVersion,
  395. _install: () => this._downloadExecutable(chromiumWithSymbols, chromiumWithSymbolsExecutable),
  396. _dependencyGroup: 'chromium',
  397. _isHermeticInstallation: true
  398. });
  399. const chromiumTipOfTree = descriptors.find(d => d.name === 'chromium-tip-of-tree');
  400. const chromiumTipOfTreeExecutable = findExecutablePath(chromiumTipOfTree.dir, 'chromium');
  401. this._executables.push({
  402. type: 'tool',
  403. name: 'chromium-tip-of-tree',
  404. browserName: 'chromium',
  405. directory: chromiumTipOfTree.dir,
  406. executablePath: () => chromiumTipOfTreeExecutable,
  407. executablePathOrDie: sdkLanguage => executablePathOrDie('chromium-tip-of-tree', chromiumTipOfTreeExecutable, chromiumTipOfTree.installByDefault, sdkLanguage),
  408. installType: chromiumTipOfTree.installByDefault ? 'download-by-default' : 'download-on-demand',
  409. validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'chromium', chromiumTipOfTree.dir, ['chrome-linux'], [], ['chrome-win']),
  410. downloadURLs: this._downloadURLs(chromiumTipOfTree),
  411. browserVersion: chromiumTipOfTree.browserVersion,
  412. _install: () => this._downloadExecutable(chromiumTipOfTree, chromiumTipOfTreeExecutable),
  413. _dependencyGroup: 'chromium',
  414. _isHermeticInstallation: true
  415. });
  416. this._executables.push(this._createChromiumChannel('chrome', {
  417. 'linux': '/opt/google/chrome/chrome',
  418. 'darwin': '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
  419. 'win32': `\\Google\\Chrome\\Application\\chrome.exe`
  420. }, () => this._installChromiumChannel('chrome', {
  421. 'linux': 'reinstall_chrome_stable_linux.sh',
  422. 'darwin': 'reinstall_chrome_stable_mac.sh',
  423. 'win32': 'reinstall_chrome_stable_win.ps1'
  424. })));
  425. this._executables.push(this._createChromiumChannel('chrome-beta', {
  426. 'linux': '/opt/google/chrome-beta/chrome',
  427. 'darwin': '/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta',
  428. 'win32': `\\Google\\Chrome Beta\\Application\\chrome.exe`
  429. }, () => this._installChromiumChannel('chrome-beta', {
  430. 'linux': 'reinstall_chrome_beta_linux.sh',
  431. 'darwin': 'reinstall_chrome_beta_mac.sh',
  432. 'win32': 'reinstall_chrome_beta_win.ps1'
  433. })));
  434. this._executables.push(this._createChromiumChannel('chrome-dev', {
  435. 'linux': '/opt/google/chrome-unstable/chrome',
  436. 'darwin': '/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev',
  437. 'win32': `\\Google\\Chrome Dev\\Application\\chrome.exe`
  438. }));
  439. this._executables.push(this._createChromiumChannel('chrome-canary', {
  440. 'linux': '',
  441. 'darwin': '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',
  442. 'win32': `\\Google\\Chrome SxS\\Application\\chrome.exe`
  443. }));
  444. this._executables.push(this._createChromiumChannel('msedge', {
  445. 'linux': '/opt/microsoft/msedge/msedge',
  446. 'darwin': '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
  447. 'win32': `\\Microsoft\\Edge\\Application\\msedge.exe`
  448. }, () => this._installMSEdgeChannel('msedge', {
  449. 'linux': 'reinstall_msedge_stable_linux.sh',
  450. 'darwin': 'reinstall_msedge_stable_mac.sh',
  451. 'win32': 'reinstall_msedge_stable_win.ps1'
  452. })));
  453. this._executables.push(this._createChromiumChannel('msedge-beta', {
  454. 'linux': '/opt/microsoft/msedge-beta/msedge',
  455. 'darwin': '/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta',
  456. 'win32': `\\Microsoft\\Edge Beta\\Application\\msedge.exe`
  457. }, () => this._installMSEdgeChannel('msedge-beta', {
  458. 'darwin': 'reinstall_msedge_beta_mac.sh',
  459. 'linux': 'reinstall_msedge_beta_linux.sh',
  460. 'win32': 'reinstall_msedge_beta_win.ps1'
  461. })));
  462. this._executables.push(this._createChromiumChannel('msedge-dev', {
  463. 'linux': '/opt/microsoft/msedge-dev/msedge',
  464. 'darwin': '/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev',
  465. 'win32': `\\Microsoft\\Edge Dev\\Application\\msedge.exe`
  466. }, () => this._installMSEdgeChannel('msedge-dev', {
  467. 'darwin': 'reinstall_msedge_dev_mac.sh',
  468. 'linux': 'reinstall_msedge_dev_linux.sh',
  469. 'win32': 'reinstall_msedge_dev_win.ps1'
  470. })));
  471. this._executables.push(this._createChromiumChannel('msedge-canary', {
  472. 'linux': '',
  473. 'darwin': '/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary',
  474. 'win32': `\\Microsoft\\Edge SxS\\Application\\msedge.exe`
  475. }));
  476. const firefox = descriptors.find(d => d.name === 'firefox');
  477. const firefoxExecutable = findExecutablePath(firefox.dir, 'firefox');
  478. this._executables.push({
  479. type: 'browser',
  480. name: 'firefox',
  481. browserName: 'firefox',
  482. directory: firefox.dir,
  483. executablePath: () => firefoxExecutable,
  484. executablePathOrDie: sdkLanguage => executablePathOrDie('firefox', firefoxExecutable, firefox.installByDefault, sdkLanguage),
  485. installType: firefox.installByDefault ? 'download-by-default' : 'download-on-demand',
  486. validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'firefox', firefox.dir, ['firefox'], [], ['firefox']),
  487. downloadURLs: this._downloadURLs(firefox),
  488. browserVersion: firefox.browserVersion,
  489. _install: () => this._downloadExecutable(firefox, firefoxExecutable),
  490. _dependencyGroup: 'firefox',
  491. _isHermeticInstallation: true
  492. });
  493. const firefoxAsan = descriptors.find(d => d.name === 'firefox-asan');
  494. const firefoxAsanExecutable = findExecutablePath(firefoxAsan.dir, 'firefox');
  495. this._executables.push({
  496. type: 'browser',
  497. name: 'firefox-asan',
  498. browserName: 'firefox',
  499. directory: firefoxAsan.dir,
  500. executablePath: () => firefoxAsanExecutable,
  501. executablePathOrDie: sdkLanguage => executablePathOrDie('firefox-asan', firefoxAsanExecutable, firefoxAsan.installByDefault, sdkLanguage),
  502. installType: firefoxAsan.installByDefault ? 'download-by-default' : 'download-on-demand',
  503. validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'firefox', firefoxAsan.dir, ['firefox'], [], ['firefox']),
  504. downloadURLs: this._downloadURLs(firefoxAsan),
  505. browserVersion: firefoxAsan.browserVersion,
  506. _install: () => this._downloadExecutable(firefoxAsan, firefoxAsanExecutable),
  507. _dependencyGroup: 'firefox',
  508. _isHermeticInstallation: true
  509. });
  510. const firefoxBeta = descriptors.find(d => d.name === 'firefox-beta');
  511. const firefoxBetaExecutable = findExecutablePath(firefoxBeta.dir, 'firefox');
  512. this._executables.push({
  513. type: 'tool',
  514. name: 'firefox-beta',
  515. browserName: 'firefox',
  516. directory: firefoxBeta.dir,
  517. executablePath: () => firefoxBetaExecutable,
  518. executablePathOrDie: sdkLanguage => executablePathOrDie('firefox-beta', firefoxBetaExecutable, firefoxBeta.installByDefault, sdkLanguage),
  519. installType: firefoxBeta.installByDefault ? 'download-by-default' : 'download-on-demand',
  520. validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'firefox', firefoxBeta.dir, ['firefox'], [], ['firefox']),
  521. downloadURLs: this._downloadURLs(firefoxBeta),
  522. browserVersion: firefoxBeta.browserVersion,
  523. _install: () => this._downloadExecutable(firefoxBeta, firefoxBetaExecutable),
  524. _dependencyGroup: 'firefox',
  525. _isHermeticInstallation: true
  526. });
  527. const webkit = descriptors.find(d => d.name === 'webkit');
  528. const webkitExecutable = findExecutablePath(webkit.dir, 'webkit');
  529. const webkitLinuxLddDirectories = [_path.default.join('minibrowser-gtk'), _path.default.join('minibrowser-gtk', 'bin'), _path.default.join('minibrowser-gtk', 'lib'), _path.default.join('minibrowser-gtk', 'sys', 'lib'), _path.default.join('minibrowser-wpe'), _path.default.join('minibrowser-wpe', 'bin'), _path.default.join('minibrowser-wpe', 'lib'), _path.default.join('minibrowser-wpe', 'sys', 'lib')];
  530. this._executables.push({
  531. type: 'browser',
  532. name: 'webkit',
  533. browserName: 'webkit',
  534. directory: webkit.dir,
  535. executablePath: () => webkitExecutable,
  536. executablePathOrDie: sdkLanguage => executablePathOrDie('webkit', webkitExecutable, webkit.installByDefault, sdkLanguage),
  537. installType: webkit.installByDefault ? 'download-by-default' : 'download-on-demand',
  538. validateHostRequirements: sdkLanguage => this._validateHostRequirements(sdkLanguage, 'webkit', webkit.dir, webkitLinuxLddDirectories, ['libGLESv2.so.2', 'libx264.so'], ['']),
  539. downloadURLs: this._downloadURLs(webkit),
  540. browserVersion: webkit.browserVersion,
  541. _install: () => this._downloadExecutable(webkit, webkitExecutable),
  542. _dependencyGroup: 'webkit',
  543. _isHermeticInstallation: true
  544. });
  545. const ffmpeg = descriptors.find(d => d.name === 'ffmpeg');
  546. const ffmpegExecutable = findExecutablePath(ffmpeg.dir, 'ffmpeg');
  547. this._executables.push({
  548. type: 'tool',
  549. name: 'ffmpeg',
  550. browserName: undefined,
  551. directory: ffmpeg.dir,
  552. executablePath: () => ffmpegExecutable,
  553. executablePathOrDie: sdkLanguage => executablePathOrDie('ffmpeg', ffmpegExecutable, ffmpeg.installByDefault, sdkLanguage),
  554. installType: ffmpeg.installByDefault ? 'download-by-default' : 'download-on-demand',
  555. validateHostRequirements: () => Promise.resolve(),
  556. downloadURLs: this._downloadURLs(ffmpeg),
  557. _install: () => this._downloadExecutable(ffmpeg, ffmpegExecutable),
  558. _dependencyGroup: 'tools',
  559. _isHermeticInstallation: true
  560. });
  561. const android = descriptors.find(d => d.name === 'android');
  562. this._executables.push({
  563. type: 'tool',
  564. name: 'android',
  565. browserName: undefined,
  566. directory: android.dir,
  567. executablePath: () => undefined,
  568. executablePathOrDie: () => '',
  569. installType: 'download-on-demand',
  570. validateHostRequirements: () => Promise.resolve(),
  571. downloadURLs: this._downloadURLs(android),
  572. _install: () => this._downloadExecutable(android),
  573. _dependencyGroup: 'tools',
  574. _isHermeticInstallation: true
  575. });
  576. }
  577. _createChromiumChannel(name, lookAt, install) {
  578. const executablePath = (sdkLanguage, shouldThrow) => {
  579. const suffix = lookAt[process.platform];
  580. if (!suffix) {
  581. if (shouldThrow) throw new Error(`Chromium distribution '${name}' is not supported on ${process.platform}`);
  582. return undefined;
  583. }
  584. const prefixes = process.platform === 'win32' ? [process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env['PROGRAMFILES(X86)']].filter(Boolean) : [''];
  585. for (const prefix of prefixes) {
  586. const executablePath = _path.default.join(prefix, suffix);
  587. if ((0, _fileUtils.canAccessFile)(executablePath)) return executablePath;
  588. }
  589. if (!shouldThrow) return undefined;
  590. const location = prefixes.length ? ` at ${_path.default.join(prefixes[0], suffix)}` : ``;
  591. const installation = install ? `\nRun "${buildPlaywrightCLICommand(sdkLanguage, 'install ' + name)}"` : '';
  592. throw new Error(`Chromium distribution '${name}' is not found${location}${installation}`);
  593. };
  594. return {
  595. type: 'channel',
  596. name,
  597. browserName: 'chromium',
  598. directory: undefined,
  599. executablePath: sdkLanguage => executablePath(sdkLanguage, false),
  600. executablePathOrDie: sdkLanguage => executablePath(sdkLanguage, true),
  601. installType: install ? 'install-script' : 'none',
  602. validateHostRequirements: () => Promise.resolve(),
  603. _isHermeticInstallation: false,
  604. _install: install
  605. };
  606. }
  607. executables() {
  608. return this._executables;
  609. }
  610. findExecutable(name) {
  611. return this._executables.find(b => b.name === name);
  612. }
  613. defaultExecutables() {
  614. return this._executables.filter(e => e.installType === 'download-by-default');
  615. }
  616. _addRequirementsAndDedupe(executables) {
  617. const set = new Set();
  618. for (const executable of executables) {
  619. set.add(executable);
  620. if (executable.browserName === 'chromium') set.add(this.findExecutable('ffmpeg'));
  621. }
  622. return Array.from(set);
  623. }
  624. async _validateHostRequirements(sdkLanguage, browserName, browserDirectory, linuxLddDirectories, dlOpenLibraries, windowsExeAndDllDirectories) {
  625. if ((0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS')) {
  626. process.stderr.write('Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.\n');
  627. return;
  628. }
  629. const distributionInfo = await (0, _linuxUtils.getLinuxDistributionInfo)();
  630. if (browserName === 'firefox' && (distributionInfo === null || distributionInfo === void 0 ? void 0 : distributionInfo.id) === 'ubuntu' && (distributionInfo === null || distributionInfo === void 0 ? void 0 : distributionInfo.version) === '16.04') throw new Error(`Cannot launch Firefox on Ubuntu 16.04! Minimum required Ubuntu version for Firefox browser is 20.04`);
  631. if (os.platform() === 'linux') return await (0, _dependencies.validateDependenciesLinux)(sdkLanguage, linuxLddDirectories.map(d => _path.default.join(browserDirectory, d)), dlOpenLibraries);
  632. if (os.platform() === 'win32' && os.arch() === 'x64') return await (0, _dependencies.validateDependenciesWindows)(windowsExeAndDllDirectories.map(d => _path.default.join(browserDirectory, d)));
  633. }
  634. async installDeps(executablesToInstallDeps, dryRun) {
  635. const executables = this._addRequirementsAndDedupe(executablesToInstallDeps);
  636. const targets = new Set();
  637. for (const executable of executables) {
  638. if (executable._dependencyGroup) targets.add(executable._dependencyGroup);
  639. }
  640. targets.add('tools');
  641. if (os.platform() === 'win32') return await (0, _dependencies.installDependenciesWindows)(targets, dryRun);
  642. if (os.platform() === 'linux') return await (0, _dependencies.installDependenciesLinux)(targets, dryRun);
  643. }
  644. async install(executablesToInstall, forceReinstall) {
  645. const executables = this._addRequirementsAndDedupe(executablesToInstall);
  646. await fs.promises.mkdir(registryDirectory, {
  647. recursive: true
  648. });
  649. const lockfilePath = _path.default.join(registryDirectory, '__dirlock');
  650. const linksDir = _path.default.join(registryDirectory, '.links');
  651. let releaseLock;
  652. try {
  653. releaseLock = await _utilsBundle.lockfile.lock(registryDirectory, {
  654. retries: {
  655. // Retry 20 times during 10 minutes with
  656. // exponential back-off.
  657. // See documentation at: https://www.npmjs.com/package/retry#retrytimeoutsoptions
  658. retries: 20,
  659. factor: 1.27579
  660. },
  661. onCompromised: err => {
  662. throw new Error(`${err.message} Path: ${lockfilePath}`);
  663. },
  664. lockfilePath
  665. });
  666. // Create a link first, so that cache validation does not remove our own browsers.
  667. await fs.promises.mkdir(linksDir, {
  668. recursive: true
  669. });
  670. await fs.promises.writeFile(_path.default.join(linksDir, (0, _utils.calculateSha1)(PACKAGE_PATH)), PACKAGE_PATH);
  671. // Remove stale browsers.
  672. await this._validateInstallationCache(linksDir);
  673. // Install browsers for this package.
  674. for (const executable of executables) {
  675. if (!executable._install) throw new Error(`ERROR: Playwright does not support installing ${executable.name}`);
  676. const {
  677. embedderName
  678. } = (0, _userAgent.getEmbedderName)();
  679. if (!(0, _utils.getAsBooleanFromENV)('CI') && !executable._isHermeticInstallation && !forceReinstall && executable.executablePath(embedderName)) {
  680. const command = buildPlaywrightCLICommand(embedderName, 'install --force ' + executable.name);
  681. throw new Error('\n' + (0, _utils.wrapInASCIIBox)([`ATTENTION: "${executable.name}" is already installed on the system!`, ``, `"${executable.name}" installation is not hermetic; installing newer version`, `requires *removal* of a current installation first.`, ``, `To *uninstall* current version and re-install latest "${executable.name}":`, ``, `- Close all running instances of "${executable.name}", if any`, `- Use "--force" to install browser:`, ``, ` ${command}`, ``, `<3 Playwright Team`].join('\n'), 1));
  682. }
  683. await executable._install();
  684. }
  685. } catch (e) {
  686. if (e.code === 'ELOCKED') {
  687. const rmCommand = process.platform === 'win32' ? 'rm -R' : 'rm -rf';
  688. throw new Error('\n' + (0, _utils.wrapInASCIIBox)([`An active lockfile is found at:`, ``, ` ${lockfilePath}`, ``, `Either:`, `- wait a few minutes if other Playwright is installing browsers in parallel`, `- remove lock manually with:`, ``, ` ${rmCommand} ${lockfilePath}`, ``, `<3 Playwright Team`].join('\n'), 1));
  689. } else {
  690. throw e;
  691. }
  692. } finally {
  693. if (releaseLock) await releaseLock();
  694. }
  695. }
  696. async uninstall(all) {
  697. const linksDir = _path.default.join(registryDirectory, '.links');
  698. if (all) {
  699. const links = await fs.promises.readdir(linksDir).catch(() => []);
  700. for (const link of links) await fs.promises.unlink(_path.default.join(linksDir, link));
  701. } else {
  702. await fs.promises.unlink(_path.default.join(linksDir, (0, _utils.calculateSha1)(PACKAGE_PATH))).catch(() => {});
  703. }
  704. // Remove stale browsers.
  705. await this._validateInstallationCache(linksDir);
  706. return {
  707. numberOfBrowsersLeft: (await fs.promises.readdir(registryDirectory).catch(() => [])).filter(browserDirectory => isBrowserDirectory(browserDirectory)).length
  708. };
  709. }
  710. _downloadURLs(descriptor) {
  711. const paths = DOWNLOAD_PATHS[descriptor.name];
  712. const downloadPathTemplate = paths[_hostPlatform.hostPlatform] || paths['<unknown>'];
  713. if (!downloadPathTemplate) return [];
  714. const downloadPath = util.format(downloadPathTemplate, descriptor.revision);
  715. let downloadURLs = PLAYWRIGHT_CDN_MIRRORS.map(mirror => `${mirror}/${downloadPath}`);
  716. let downloadHostEnv;
  717. if (descriptor.name.startsWith('chromium')) downloadHostEnv = 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST';else if (descriptor.name.startsWith('firefox')) downloadHostEnv = 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST';else if (descriptor.name.startsWith('webkit')) downloadHostEnv = 'PLAYWRIGHT_WEBKIT_DOWNLOAD_HOST';
  718. const customHostOverride = downloadHostEnv && (0, _utils.getFromENV)(downloadHostEnv) || (0, _utils.getFromENV)('PLAYWRIGHT_DOWNLOAD_HOST');
  719. if (customHostOverride) downloadURLs = [`${customHostOverride}/${downloadPath}`];
  720. return downloadURLs;
  721. }
  722. async _downloadExecutable(descriptor, executablePath) {
  723. const downloadURLs = this._downloadURLs(descriptor);
  724. if (!downloadURLs.length) throw new Error(`ERROR: Playwright does not support ${descriptor.name} on ${_hostPlatform.hostPlatform}`);
  725. if (!_hostPlatform.isOfficiallySupportedPlatform) (0, _browserFetcher.logPolitely)(`BEWARE: your OS is not officially supported by Playwright; downloading fallback build for ${_hostPlatform.hostPlatform}.`);
  726. const displayName = descriptor.name.split('-').map(word => {
  727. return word === 'ffmpeg' ? 'FFMPEG' : word.charAt(0).toUpperCase() + word.slice(1);
  728. }).join(' ');
  729. const title = descriptor.browserVersion ? `${displayName} ${descriptor.browserVersion} (playwright build v${descriptor.revision})` : `${displayName} playwright build v${descriptor.revision}`;
  730. const downloadFileName = `playwright-download-${descriptor.name}-${_hostPlatform.hostPlatform}-${descriptor.revision}.zip`;
  731. const downloadConnectionTimeoutEnv = (0, _utils.getFromENV)('PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT');
  732. const downloadConnectionTimeout = +(downloadConnectionTimeoutEnv || '0') || 30_000;
  733. await (0, _browserFetcher.downloadBrowserWithProgressBar)(title, descriptor.dir, executablePath, downloadURLs, downloadFileName, downloadConnectionTimeout).catch(e => {
  734. throw new Error(`Failed to download ${title}, caused by\n${e.stack}`);
  735. });
  736. }
  737. async _installMSEdgeChannel(channel, scripts) {
  738. const scriptArgs = [];
  739. if (process.platform !== 'linux') {
  740. const products = lowercaseAllKeys(JSON.parse(await (0, _network.fetchData)({
  741. url: 'https://edgeupdates.microsoft.com/api/products'
  742. })));
  743. const productName = {
  744. 'msedge': 'Stable',
  745. 'msedge-beta': 'Beta',
  746. 'msedge-dev': 'Dev'
  747. }[channel];
  748. const product = products.find(product => product.product === productName);
  749. const searchConfig = {
  750. darwin: {
  751. platform: 'MacOS',
  752. arch: 'universal',
  753. artifact: 'pkg'
  754. },
  755. win32: {
  756. platform: 'Windows',
  757. arch: 'x64',
  758. artifact: 'msi'
  759. }
  760. }[process.platform];
  761. const release = searchConfig ? product.releases.find(release => release.platform === searchConfig.platform && release.architecture === searchConfig.arch && release.artifacts.length > 0) : null;
  762. const artifact = release ? release.artifacts.find(artifact => artifact.artifactname === searchConfig.artifact) : null;
  763. if (artifact) scriptArgs.push(artifact.location /* url */);else throw new Error(`Cannot install ${channel} on ${process.platform}`);
  764. }
  765. await this._installChromiumChannel(channel, scripts, scriptArgs);
  766. }
  767. async _installChromiumChannel(channel, scripts, scriptArgs = []) {
  768. const scriptName = scripts[process.platform];
  769. if (!scriptName) throw new Error(`Cannot install ${channel} on ${process.platform}`);
  770. const cwd = BIN_PATH;
  771. const isPowerShell = scriptName.endsWith('.ps1');
  772. if (isPowerShell) {
  773. const args = ['-ExecutionPolicy', 'Bypass', '-File', _path.default.join(BIN_PATH, scriptName), ...scriptArgs];
  774. const {
  775. code
  776. } = await (0, _spawnAsync.spawnAsync)('powershell.exe', args, {
  777. cwd,
  778. stdio: 'inherit'
  779. });
  780. if (code !== 0) throw new Error(`Failed to install ${channel}`);
  781. } else {
  782. const {
  783. command,
  784. args,
  785. elevatedPermissions
  786. } = await (0, _dependencies.transformCommandsForRoot)([`bash "${_path.default.join(BIN_PATH, scriptName)}" ${scriptArgs.join('')}`]);
  787. if (elevatedPermissions) console.log('Switching to root user to install dependencies...'); // eslint-disable-line no-console
  788. const {
  789. code
  790. } = await (0, _spawnAsync.spawnAsync)(command, args, {
  791. cwd,
  792. stdio: 'inherit'
  793. });
  794. if (code !== 0) throw new Error(`Failed to install ${channel}`);
  795. }
  796. }
  797. async _validateInstallationCache(linksDir) {
  798. // 1. Collect used downloads and package descriptors.
  799. const usedBrowserPaths = new Set();
  800. for (const fileName of await fs.promises.readdir(linksDir)) {
  801. const linkPath = _path.default.join(linksDir, fileName);
  802. let linkTarget = '';
  803. try {
  804. linkTarget = (await fs.promises.readFile(linkPath)).toString();
  805. const browsersJSON = require(_path.default.join(linkTarget, 'browsers.json'));
  806. const descriptors = readDescriptors(browsersJSON);
  807. for (const browserName of allDownloadable) {
  808. // We retain browsers if they are found in the descriptor.
  809. // Note, however, that there are older versions out in the wild that rely on
  810. // the "download" field in the browser descriptor and use its value
  811. // to retain and download browsers.
  812. // As of v1.10, we decided to abandon "download" field.
  813. const descriptor = descriptors.find(d => d.name === browserName);
  814. if (!descriptor) continue;
  815. const usedBrowserPath = descriptor.dir;
  816. const browserRevision = parseInt(descriptor.revision, 10);
  817. // Old browser installations don't have marker file.
  818. // We switched chromium from 999999 to 1000, 300000 is the new Y2K.
  819. const shouldHaveMarkerFile = browserName === 'chromium' && (browserRevision >= 786218 || browserRevision < 300000) || browserName === 'firefox' && browserRevision >= 1128 || browserName === 'webkit' && browserRevision >= 1307 ||
  820. // All new applications have a marker file right away.
  821. browserName !== 'firefox' && browserName !== 'chromium' && browserName !== 'webkit';
  822. if (!shouldHaveMarkerFile || (await (0, _fileUtils.existsAsync)(browserDirectoryToMarkerFilePath(usedBrowserPath)))) usedBrowserPaths.add(usedBrowserPath);
  823. }
  824. } catch (e) {
  825. await fs.promises.unlink(linkPath).catch(e => {});
  826. }
  827. }
  828. // 2. Delete all unused browsers.
  829. if (!(0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_SKIP_BROWSER_GC')) {
  830. let downloadedBrowsers = (await fs.promises.readdir(registryDirectory)).map(file => _path.default.join(registryDirectory, file));
  831. downloadedBrowsers = downloadedBrowsers.filter(file => isBrowserDirectory(file));
  832. const directories = new Set(downloadedBrowsers);
  833. for (const browserDirectory of usedBrowserPaths) directories.delete(browserDirectory);
  834. for (const directory of directories) (0, _browserFetcher.logPolitely)('Removing unused browser at ' + directory);
  835. await (0, _fileUtils.removeFolders)([...directories]);
  836. }
  837. }
  838. }
  839. exports.Registry = Registry;
  840. function browserDirectoryToMarkerFilePath(browserDirectory) {
  841. return _path.default.join(browserDirectory, 'INSTALLATION_COMPLETE');
  842. }
  843. function buildPlaywrightCLICommand(sdkLanguage, parameters) {
  844. switch (sdkLanguage) {
  845. case 'python':
  846. return `playwright ${parameters}`;
  847. case 'java':
  848. return `mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="${parameters}"`;
  849. case 'csharp':
  850. return `pwsh bin/Debug/netX/playwright.ps1 ${parameters}`;
  851. default:
  852. {
  853. const packageManagerCommand = (0, _utils.getPackageManagerExecCommand)();
  854. return `${packageManagerCommand} playwright ${parameters}`;
  855. }
  856. }
  857. }
  858. async function installDefaultBrowsersForNpmInstall() {
  859. const defaultBrowserNames = registry.defaultExecutables().map(e => e.name);
  860. return installBrowsersForNpmInstall(defaultBrowserNames);
  861. }
  862. async function installBrowsersForNpmInstall(browsers) {
  863. // PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD should have a value of 0 or 1
  864. if ((0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD')) {
  865. (0, _browserFetcher.logPolitely)('Skipping browsers download because `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` env variable is set');
  866. return false;
  867. }
  868. const executables = [];
  869. for (const browserName of browsers) {
  870. const executable = registry.findExecutable(browserName);
  871. if (!executable || executable.installType === 'none') throw new Error(`Cannot install ${browserName}`);
  872. executables.push(executable);
  873. }
  874. await registry.install(executables, false /* forceReinstall */);
  875. }
  876. function findChromiumChannel(sdkLanguage) {
  877. // Fall back to the stable channels of popular vendors to work out of the box.
  878. // Null means no installation and no channels found.
  879. let channel = null;
  880. for (const name of ['chromium', 'chrome', 'msedge']) {
  881. try {
  882. registry.findExecutable(name).executablePathOrDie(sdkLanguage);
  883. channel = name === 'chromium' ? undefined : name;
  884. break;
  885. } catch (e) {}
  886. }
  887. if (channel === null) {
  888. const installCommand = buildPlaywrightCLICommand(sdkLanguage, `install chromium`);
  889. const prettyMessage = [`No chromium-based browser found on the system.`, `Please run the following command to download one:`, ``, ` ${installCommand}`, ``, `<3 Playwright Team`].join('\n');
  890. throw new Error('\n' + (0, _utils.wrapInASCIIBox)(prettyMessage, 1));
  891. }
  892. return channel;
  893. }
  894. function lowercaseAllKeys(json) {
  895. if (typeof json !== 'object' || !json) return json;
  896. if (Array.isArray(json)) return json.map(lowercaseAllKeys);
  897. const result = {};
  898. for (const [key, value] of Object.entries(json)) result[key.toLowerCase()] = lowercaseAllKeys(value);
  899. return result;
  900. }
  901. const registry = exports.registry = new Registry(require('../../../browsers.json'));