update.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const AdmZip = require("adm-zip");
  4. const child_process = require("child_process");
  5. const fs = require("fs");
  6. const minimist = require("minimist");
  7. const path = require("path");
  8. const q = require("q");
  9. const rimraf = require("rimraf");
  10. const binaries_1 = require("../binaries");
  11. const cli_1 = require("../cli");
  12. const config_1 = require("../config");
  13. const files_1 = require("../files");
  14. const http_utils_1 = require("../http_utils");
  15. const utils_1 = require("../utils");
  16. const Opt = require("./");
  17. const initialize_1 = require("./initialize");
  18. const opts_1 = require("./opts");
  19. config_1.Config.runCommand = 'update';
  20. let logger = new cli_1.Logger('update');
  21. let prog = new cli_1.Program()
  22. .command('update', 'install or update selected binaries')
  23. .action(update)
  24. .addOption(opts_1.Opts[Opt.OUT_DIR])
  25. .addOption(opts_1.Opts[Opt.VERBOSE])
  26. .addOption(opts_1.Opts[Opt.IGNORE_SSL])
  27. .addOption(opts_1.Opts[Opt.PROXY])
  28. .addOption(opts_1.Opts[Opt.ALTERNATE_CDN])
  29. .addOption(opts_1.Opts[Opt.STANDALONE])
  30. .addOption(opts_1.Opts[Opt.CHROME])
  31. .addOption(opts_1.Opts[Opt.GECKO])
  32. .addOption(opts_1.Opts[Opt.ANDROID])
  33. .addOption(opts_1.Opts[Opt.ANDROID_API_LEVELS])
  34. .addOption(opts_1.Opts[Opt.ANDROID_ARCHITECTURES])
  35. .addOption(opts_1.Opts[Opt.ANDROID_PLATFORMS])
  36. .addOption(opts_1.Opts[Opt.ANDROID_ACCEPT_LICENSES]);
  37. if (config_1.Config.osType() === 'Darwin') {
  38. prog.addOption(opts_1.Opts[Opt.IOS]);
  39. }
  40. if (config_1.Config.osType() === 'Windows_NT') {
  41. prog.addOption(opts_1.Opts[Opt.IE]).addOption(opts_1.Opts[Opt.IE32]).addOption(opts_1.Opts[Opt.IE64]);
  42. }
  43. prog.addOption(opts_1.Opts[Opt.VERSIONS_STANDALONE])
  44. .addOption(opts_1.Opts[Opt.VERSIONS_CHROME])
  45. .addOption(opts_1.Opts[Opt.VERSIONS_APPIUM])
  46. .addOption(opts_1.Opts[Opt.VERSIONS_ANDROID])
  47. .addOption(opts_1.Opts[Opt.VERSIONS_GECKO]);
  48. if (config_1.Config.osType() === 'Windows_NT') {
  49. prog.addOption(opts_1.Opts[Opt.VERSIONS_IE]);
  50. }
  51. exports.program = prog;
  52. // stand alone runner
  53. let argv = minimist(process.argv.slice(2), prog.getMinimistOptions());
  54. if (argv._[0] === 'update-run') {
  55. prog.run(JSON.parse(JSON.stringify(argv)));
  56. }
  57. else if (argv._[0] === 'update-help') {
  58. prog.printHelp();
  59. }
  60. let browserFile;
  61. /**
  62. * Parses the options and downloads binaries if they do not exist.
  63. * @param options
  64. */
  65. function update(options) {
  66. let promises = [];
  67. let standalone = options[Opt.STANDALONE].getBoolean();
  68. let chrome = options[Opt.CHROME].getBoolean();
  69. let gecko = options[Opt.GECKO].getBoolean();
  70. let ie32 = false;
  71. let ie64 = false;
  72. if (options[Opt.IE]) {
  73. ie32 = ie32 || options[Opt.IE].getBoolean();
  74. }
  75. if (options[Opt.IE32]) {
  76. ie32 = ie32 || options[Opt.IE32].getBoolean();
  77. }
  78. if (options[Opt.IE64]) {
  79. ie64 = options[Opt.IE64].getBoolean();
  80. }
  81. let android = options[Opt.ANDROID].getBoolean();
  82. let ios = false;
  83. if (options[Opt.IOS]) {
  84. ios = options[Opt.IOS].getBoolean();
  85. }
  86. let outputDir = options[Opt.OUT_DIR].getString();
  87. try {
  88. browserFile =
  89. JSON.parse(fs.readFileSync(path.resolve(outputDir, 'update-config.json')).toString());
  90. }
  91. catch (err) {
  92. browserFile = {};
  93. }
  94. let android_api_levels = options[Opt.ANDROID_API_LEVELS].getString().split(',');
  95. let android_architectures = options[Opt.ANDROID_ARCHITECTURES].getString().split(',');
  96. let android_platforms = options[Opt.ANDROID_PLATFORMS].getString().split(',');
  97. let android_accept_licenses = options[Opt.ANDROID_ACCEPT_LICENSES].getBoolean();
  98. if (options[Opt.OUT_DIR].getString()) {
  99. if (path.isAbsolute(options[Opt.OUT_DIR].getString())) {
  100. outputDir = options[Opt.OUT_DIR].getString();
  101. }
  102. else {
  103. outputDir = path.resolve(config_1.Config.getBaseDir(), options[Opt.OUT_DIR].getString());
  104. }
  105. files_1.FileManager.makeOutputDirectory(outputDir);
  106. }
  107. let ignoreSSL = options[Opt.IGNORE_SSL].getBoolean();
  108. let proxy = options[Opt.PROXY].getString();
  109. http_utils_1.HttpUtils.assignOptions({ ignoreSSL, proxy });
  110. let verbose = options[Opt.VERBOSE].getBoolean();
  111. // setup versions for binaries
  112. let binaries = files_1.FileManager.setupBinaries(options[Opt.ALTERNATE_CDN].getString());
  113. binaries[binaries_1.Standalone.id].versionCustom = options[Opt.VERSIONS_STANDALONE].getString();
  114. binaries[binaries_1.ChromeDriver.id].versionCustom = options[Opt.VERSIONS_CHROME].getString();
  115. if (options[Opt.VERSIONS_IE]) {
  116. binaries[binaries_1.IEDriver.id].versionCustom = options[Opt.VERSIONS_IE].getString();
  117. }
  118. if (options[Opt.VERSIONS_GECKO]) {
  119. binaries[binaries_1.GeckoDriver.id].versionCustom = options[Opt.VERSIONS_GECKO].getString();
  120. }
  121. binaries[binaries_1.AndroidSDK.id].versionCustom = options[Opt.VERSIONS_ANDROID].getString();
  122. binaries[binaries_1.Appium.id].versionCustom = options[Opt.VERSIONS_APPIUM].getString();
  123. // if the file has not been completely downloaded, download it
  124. // else if the file has already been downloaded, unzip the file, rename it, and give it
  125. // permissions
  126. if (standalone) {
  127. let binary = binaries[binaries_1.Standalone.id];
  128. promises.push(files_1.FileManager.downloadFile(binary, outputDir)
  129. .then((downloaded) => {
  130. if (!downloaded) {
  131. logger.info(binary.name + ': file exists ' +
  132. path.resolve(outputDir, binary.filename()));
  133. logger.info(binary.name + ': ' + binary.filename() + ' up to date');
  134. }
  135. })
  136. .then(() => {
  137. updateBrowserFile(binary, outputDir);
  138. }));
  139. }
  140. if (chrome) {
  141. let binary = binaries[binaries_1.ChromeDriver.id];
  142. promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL).then(() => {
  143. return Promise.resolve(updateBrowserFile(binary, outputDir));
  144. }));
  145. }
  146. if (gecko) {
  147. let binary = binaries[binaries_1.GeckoDriver.id];
  148. promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL).then(() => {
  149. return Promise.resolve(updateBrowserFile(binary, outputDir));
  150. }));
  151. }
  152. if (ie64) {
  153. let binary = binaries[binaries_1.IEDriver.id];
  154. binary.osarch = config_1.Config.osArch(); // Win32 or x64
  155. promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL).then(() => {
  156. return Promise.resolve(updateBrowserFile(binary, outputDir));
  157. }));
  158. }
  159. if (ie32) {
  160. let binary = binaries[binaries_1.IEDriver.id];
  161. binary.osarch = 'Win32';
  162. promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL).then(() => {
  163. return Promise.resolve(updateBrowserFile(binary, outputDir));
  164. }));
  165. }
  166. if (android) {
  167. let binary = binaries[binaries_1.AndroidSDK.id];
  168. let sdk_path = path.resolve(outputDir, binary.executableFilename());
  169. let oldAVDList;
  170. updateBrowserFile(binary, outputDir);
  171. promises.push(q.nfcall(fs.readFile, path.resolve(sdk_path, 'available_avds.json'))
  172. .then((oldAVDs) => {
  173. oldAVDList = oldAVDs;
  174. }, () => {
  175. oldAVDList = '[]';
  176. })
  177. .then(() => {
  178. return updateBinary(binary, outputDir, proxy, ignoreSSL);
  179. })
  180. .then(() => {
  181. initialize_1.android(path.resolve(outputDir, binary.executableFilename()), android_api_levels, android_architectures, android_platforms, android_accept_licenses, binaries[binaries_1.AndroidSDK.id].versionCustom, JSON.parse(oldAVDList), logger, verbose);
  182. }));
  183. }
  184. if (ios) {
  185. initialize_1.iOS(logger);
  186. }
  187. if (android || ios) {
  188. installAppium(binaries[binaries_1.Appium.id], outputDir);
  189. updateBrowserFile(binaries[binaries_1.Appium.id], outputDir);
  190. }
  191. return Promise.all(promises).then(() => {
  192. writeBrowserFile(outputDir);
  193. });
  194. }
  195. function updateBinary(binary, outputDir, proxy, ignoreSSL) {
  196. return files_1.FileManager
  197. .downloadFile(binary, outputDir, (binary, outputDir, fileName) => {
  198. unzip(binary, outputDir, fileName);
  199. })
  200. .then(downloaded => {
  201. if (!downloaded) {
  202. // The file did not have to download, we should unzip it.
  203. logger.info(binary.name + ': file exists ' + path.resolve(outputDir, binary.filename()));
  204. let fileName = binary.filename();
  205. unzip(binary, outputDir, fileName);
  206. logger.info(binary.name + ': ' + binary.executableFilename() + ' up to date');
  207. }
  208. });
  209. }
  210. function unzip(binary, outputDir, fileName) {
  211. // remove the previously saved file and unzip it
  212. let osType = config_1.Config.osType();
  213. let mv = path.resolve(outputDir, binary.executableFilename());
  214. try {
  215. fs.unlinkSync(mv);
  216. }
  217. catch (err) {
  218. try {
  219. rimraf.sync(mv);
  220. }
  221. catch (err2) {
  222. }
  223. }
  224. // unzip the file
  225. logger.info(binary.name + ': unzipping ' + fileName);
  226. if (fileName.slice(-4) == '.zip') {
  227. try {
  228. let zip = new AdmZip(path.resolve(outputDir, fileName));
  229. zip.extractAllTo(outputDir, true);
  230. }
  231. catch (e) {
  232. throw new Error(`Invalid filename: ${path.resolve(outputDir, fileName)}`);
  233. }
  234. }
  235. else {
  236. // We will only ever get .tar files on linux
  237. child_process.spawnSync('tar', ['zxvf', path.resolve(outputDir, fileName), '-C', outputDir]);
  238. }
  239. // rename
  240. fs.renameSync(path.resolve(outputDir, binary.zipContentName()), mv);
  241. // set permissions
  242. if (osType !== 'Windows_NT') {
  243. logger.info(binary.name + ': setting permissions to 0755 for ' + mv);
  244. if (binary.id() !== binaries_1.AndroidSDK.id) {
  245. fs.chmodSync(mv, '0755');
  246. }
  247. else {
  248. fs.chmodSync(path.resolve(mv, 'tools', 'android'), '0755');
  249. fs.chmodSync(path.resolve(mv, 'tools', 'emulator'), '0755');
  250. // TODO(sjelin): get 64 bit versions working
  251. }
  252. }
  253. }
  254. function installAppium(binary, outputDir) {
  255. logger.info('appium: installing appium');
  256. let folder = path.resolve(outputDir, binary.filename());
  257. try {
  258. rimraf.sync(folder);
  259. }
  260. catch (err) {
  261. }
  262. fs.mkdirSync(folder);
  263. fs.writeFileSync(path.resolve(folder, 'package.json'), JSON.stringify({ scripts: { appium: 'appium' } }));
  264. utils_1.spawn('npm', ['install', 'appium@' + binary.version()], null, { cwd: folder });
  265. }
  266. function updateBrowserFile(binary, outputDir) {
  267. let currentDownload = path.resolve(outputDir, binary.executableFilename());
  268. // if browserFile[id] exists, we should update it
  269. if (browserFile[binary.id()]) {
  270. let binaryPath = browserFile[binary.id()];
  271. if (binaryPath.last === currentDownload) {
  272. return;
  273. }
  274. else {
  275. binaryPath.last = currentDownload;
  276. for (let bin of binaryPath.all) {
  277. if (bin === currentDownload) {
  278. return;
  279. }
  280. }
  281. binaryPath.all.push(currentDownload);
  282. }
  283. }
  284. else {
  285. // The browserFile[id] does not exist / has not been downloaded previously.
  286. // We should create the entry.
  287. let binaryPath = { last: currentDownload, all: [currentDownload] };
  288. browserFile[binary.id()] = binaryPath;
  289. }
  290. }
  291. function writeBrowserFile(outputDir) {
  292. let filePath = path.resolve(outputDir, 'update-config.json');
  293. fs.writeFileSync(filePath, JSON.stringify(browserFile));
  294. }
  295. // for testing
  296. function clearBrowserFile() {
  297. browserFile = {};
  298. }
  299. exports.clearBrowserFile = clearBrowserFile;
  300. //# sourceMappingURL=update.js.map