install.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. 'use strict';
  2. var _templateObject = _taggedTemplateLiteral(['\n Skipping installation:\n\n Pass the ', ' option if you\'d like to reinstall anyway.\n '], ['\n Skipping installation:\n\n Pass the ', ' option if you\'d like to reinstall anyway.\n ']),
  3. _templateObject2 = _taggedTemplateLiteral(['\n ', ' Warning: It looks like you\'ve installed Cypress globally.\n\n This will work, but it\'s not recommended.\n\n The recommended way to install Cypress is as a devDependency per project.\n\n You should probably run these commands:\n\n - ', '\n - ', '\n '], ['\n ', ' Warning: It looks like you\\\'ve installed Cypress globally.\n\n This will work, but it\'\\s not recommended.\n\n The recommended way to install Cypress is as a devDependency per project.\n\n You should probably run these commands:\n\n - ', '\n - ', '\n ']),
  4. _templateObject3 = _taggedTemplateLiteral(['\n ', ' Skipping binary installation: Environment variable CYPRESS_INSTALL_BINARY = 0.'], ['\n ', ' Skipping binary installation: Environment variable CYPRESS_INSTALL_BINARY = 0.']),
  5. _templateObject4 = _taggedTemplateLiteral(['\n ', ' Overriding Cypress cache directory to: ', '\n\n Previous installs of Cypress may not be found.\n '], ['\n ', ' Overriding Cypress cache directory to: ', '\n\n Previous installs of Cypress may not be found.\n ']),
  6. _templateObject5 = _taggedTemplateLiteral(['\n Failed to access ', ':\n\n ', '\n '], ['\n Failed to access ', ':\n\n ', '\n ']),
  7. _templateObject6 = _taggedTemplateLiteral(['\n Cypress ', ' is installed in ', '\n '], ['\n Cypress ', ' is installed in ', '\n ']),
  8. _templateObject7 = _taggedTemplateLiteral(['\n ', ' Warning: Forcing a binary version different than the default.\n\n The CLI expected to install version: ', '\n\n Instead we will install version: ', '\n\n These versions may not work properly together.\n '], ['\n ', ' Warning: Forcing a binary version different than the default.\n\n The CLI expected to install version: ', '\n\n Instead we will install version: ', '\n\n These versions may not work properly together.\n ']);
  9. function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
  10. var _ = require('lodash');
  11. var os = require('os');
  12. var path = require('path');
  13. var chalk = require('chalk');
  14. var debug = require('debug')('cypress:cli');
  15. var Listr = require('listr');
  16. var verbose = require('@cypress/listr-verbose-renderer');
  17. var Promise = require('bluebird');
  18. var logSymbols = require('log-symbols');
  19. var _require = require('common-tags'),
  20. stripIndent = _require.stripIndent;
  21. var fs = require('../fs');
  22. var download = require('./download');
  23. var util = require('../util');
  24. var state = require('./state');
  25. var unzip = require('./unzip');
  26. var logger = require('../logger');
  27. var _require2 = require('../errors'),
  28. throwFormErrorText = _require2.throwFormErrorText,
  29. errors = _require2.errors;
  30. var alreadyInstalledMsg = function alreadyInstalledMsg() {
  31. if (!util.isPostInstall()) {
  32. logger.log(stripIndent(_templateObject, chalk.yellow('--force')));
  33. }
  34. };
  35. var displayCompletionMsg = function displayCompletionMsg() {
  36. // check here to see if we are globally installed
  37. if (util.isInstalledGlobally()) {
  38. // if we are display a warning
  39. logger.log();
  40. logger.warn(stripIndent(_templateObject2, logSymbols.warning, chalk.cyan('npm uninstall -g cypress'), chalk.cyan('npm install --save-dev cypress')));
  41. return;
  42. }
  43. logger.log();
  44. logger.log('You can now open Cypress by running:', chalk.cyan(path.join('node_modules', '.bin', 'cypress'), 'open'));
  45. logger.log();
  46. logger.log(chalk.grey('https://on.cypress.io/installing-cypress'));
  47. logger.log();
  48. };
  49. var downloadAndUnzip = function downloadAndUnzip(_ref) {
  50. var version = _ref.version,
  51. installDir = _ref.installDir,
  52. downloadDir = _ref.downloadDir;
  53. var progress = {
  54. throttle: 100,
  55. onProgress: null
  56. };
  57. var downloadDestination = path.join(downloadDir, 'cypress.zip');
  58. var rendererOptions = getRendererOptions();
  59. // let the user know what version of cypress we're downloading!
  60. logger.log('Installing Cypress ' + chalk.gray('(version: ' + version + ')'));
  61. logger.log();
  62. var tasks = new Listr([{
  63. title: util.titleize('Downloading Cypress'),
  64. task: function task(ctx, _task) {
  65. // as our download progresses indicate the status
  66. progress.onProgress = progessify(_task, 'Downloading Cypress');
  67. return download.start({ version: version, downloadDestination: downloadDestination, progress: progress }).then(function (redirectVersion) {
  68. if (redirectVersion) version = redirectVersion;
  69. debug('finished downloading file: ' + downloadDestination);
  70. }).then(function () {
  71. // save the download destination for unzipping
  72. util.setTaskTitle(_task, util.titleize(chalk.green('Downloaded Cypress')), rendererOptions.renderer);
  73. });
  74. }
  75. }, unzipTask({
  76. progress: progress,
  77. zipFilePath: downloadDestination,
  78. installDir: installDir,
  79. rendererOptions: rendererOptions
  80. }), {
  81. title: util.titleize('Finishing Installation'),
  82. task: function task(ctx, _task2) {
  83. var cleanup = function cleanup() {
  84. debug('removing zip file %s', downloadDestination);
  85. return fs.removeAsync(downloadDestination);
  86. };
  87. return cleanup().then(function () {
  88. debug('finished installation in', installDir);
  89. util.setTaskTitle(_task2, util.titleize(chalk.green('Finished Installation'), chalk.gray(installDir)), rendererOptions.renderer);
  90. });
  91. }
  92. }], rendererOptions);
  93. // start the tasks!
  94. return Promise.resolve(tasks.run());
  95. };
  96. var start = function start() {
  97. var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  98. // handle deprecated / removed
  99. if (util.getEnv('CYPRESS_BINARY_VERSION')) {
  100. return throwFormErrorText(errors.removed.CYPRESS_BINARY_VERSION)();
  101. }
  102. if (util.getEnv('CYPRESS_SKIP_BINARY_INSTALL')) {
  103. return throwFormErrorText(errors.removed.CYPRESS_SKIP_BINARY_INSTALL)();
  104. }
  105. debug('installing with options %j', options);
  106. _.defaults(options, {
  107. force: false
  108. });
  109. var pkgVersion = util.pkgVersion();
  110. var needVersion = pkgVersion;
  111. debug('version in package.json is', needVersion);
  112. // let this environment variable reset the binary version we need
  113. if (util.getEnv('CYPRESS_INSTALL_BINARY')) {
  114. // because passed file paths are often double quoted
  115. // and might have extra whitespace around, be robust and trim the string
  116. var trimAndRemoveDoubleQuotes = true;
  117. var envVarVersion = util.getEnv('CYPRESS_INSTALL_BINARY', trimAndRemoveDoubleQuotes);
  118. debug('using environment variable CYPRESS_INSTALL_BINARY "%s"', envVarVersion);
  119. if (envVarVersion === '0') {
  120. debug('environment variable CYPRESS_INSTALL_BINARY = 0, skipping install');
  121. logger.log(stripIndent(_templateObject3, chalk.yellow('Note:')));
  122. logger.log();
  123. return Promise.resolve();
  124. }
  125. // if this doesn't match the expected version
  126. // then print warning to the user
  127. if (envVarVersion !== needVersion) {
  128. // reset the version to the env var version
  129. needVersion = envVarVersion;
  130. }
  131. }
  132. if (util.getEnv('CYPRESS_CACHE_FOLDER')) {
  133. var envCache = util.getEnv('CYPRESS_CACHE_FOLDER');
  134. logger.log(stripIndent(_templateObject4, chalk.yellow('Note:'), chalk.cyan(envCache)));
  135. logger.log();
  136. }
  137. var installDir = state.getVersionDir(pkgVersion);
  138. var cacheDir = state.getCacheDir();
  139. var binaryDir = state.getBinaryDir(pkgVersion);
  140. return fs.ensureDirAsync(cacheDir).catch({ code: 'EACCES' }, function (err) {
  141. return throwFormErrorText(errors.invalidCacheDirectory)(stripIndent(_templateObject5, chalk.cyan(cacheDir), err.message));
  142. }).then(function () {
  143. return state.getBinaryPkgVersionAsync(binaryDir);
  144. }).then(function (binaryVersion) {
  145. if (!binaryVersion) {
  146. debug('no binary installed under cli version');
  147. return true;
  148. }
  149. debug('installed version is', binaryVersion, 'version needed is', needVersion);
  150. logger.log();
  151. logger.log(stripIndent(_templateObject6, chalk.green(binaryVersion), chalk.cyan(installDir)));
  152. logger.log();
  153. if (options.force) {
  154. debug('performing force install over existing binary');
  155. return true;
  156. }
  157. if (binaryVersion === needVersion || !util.isSemver(needVersion)) {
  158. // our version matches, tell the user this is a noop
  159. alreadyInstalledMsg();
  160. return false;
  161. }
  162. return true;
  163. }).then(function (shouldInstall) {
  164. // noop if we've been told not to download
  165. if (!shouldInstall) {
  166. debug('Not downloading or installing binary');
  167. return;
  168. }
  169. if (needVersion !== pkgVersion) {
  170. logger.log(chalk.yellow(stripIndent(_templateObject7, logSymbols.warning, chalk.green(pkgVersion), chalk.green(needVersion))));
  171. logger.log();
  172. }
  173. // see if version supplied is a path to a binary
  174. return fs.pathExistsAsync(needVersion).then(function (exists) {
  175. if (exists) {
  176. return path.extname(needVersion) === '.zip' ? needVersion : false;
  177. }
  178. var possibleFile = util.formAbsolutePath(needVersion);
  179. debug('checking local file', possibleFile, 'cwd', process.cwd());
  180. return fs.pathExistsAsync(possibleFile).then(function (exists) {
  181. // if this exists return the path to it
  182. // else false
  183. if (exists && path.extname(possibleFile) === '.zip') {
  184. return possibleFile;
  185. }
  186. return false;
  187. });
  188. }).then(function (pathToLocalFile) {
  189. if (pathToLocalFile) {
  190. var absolutePath = path.resolve(needVersion);
  191. debug('found local file at', absolutePath);
  192. debug('skipping download');
  193. var rendererOptions = getRendererOptions();
  194. return new Listr([unzipTask({
  195. progress: {
  196. throttle: 100,
  197. onProgress: null
  198. },
  199. zipFilePath: absolutePath,
  200. installDir: installDir,
  201. rendererOptions: rendererOptions
  202. })], rendererOptions).run();
  203. }
  204. if (options.force) {
  205. debug('Cypress already installed at', installDir);
  206. debug('but the installation was forced');
  207. }
  208. debug('preparing to download and unzip version ', needVersion, 'to path', installDir);
  209. var downloadDir = os.tmpdir();
  210. return downloadAndUnzip({ version: needVersion, installDir: installDir, downloadDir: downloadDir });
  211. })
  212. // delay 1 sec for UX, unless we are testing
  213. .then(function () {
  214. return Promise.delay(1000);
  215. }).then(displayCompletionMsg);
  216. });
  217. };
  218. module.exports = {
  219. start: start
  220. };
  221. var unzipTask = function unzipTask(_ref2) {
  222. var zipFilePath = _ref2.zipFilePath,
  223. installDir = _ref2.installDir,
  224. progress = _ref2.progress,
  225. rendererOptions = _ref2.rendererOptions;
  226. return {
  227. title: util.titleize('Unzipping Cypress'),
  228. task: function task(ctx, _task3) {
  229. // as our unzip progresses indicate the status
  230. progress.onProgress = progessify(_task3, 'Unzipping Cypress');
  231. return unzip.start({ zipFilePath: zipFilePath, installDir: installDir, progress: progress }).then(function () {
  232. util.setTaskTitle(_task3, util.titleize(chalk.green('Unzipped Cypress')), rendererOptions.renderer);
  233. });
  234. }
  235. };
  236. };
  237. var progessify = function progessify(task, title) {
  238. // return higher order function
  239. return function (percentComplete, remaining) {
  240. percentComplete = chalk.white(' ' + percentComplete + '%');
  241. // pluralize seconds remaining
  242. remaining = chalk.gray(remaining + 's');
  243. util.setTaskTitle(task, util.titleize(title, percentComplete, remaining), getRendererOptions().renderer);
  244. };
  245. };
  246. // if we are running in CI then use
  247. // the verbose renderer else use
  248. // the default
  249. var getRendererOptions = function getRendererOptions() {
  250. var renderer = util.isCi() ? verbose : 'default';
  251. if (logger.logLevel() === 'silent') {
  252. renderer = 'silent';
  253. }
  254. return {
  255. renderer: renderer
  256. };
  257. };