1 |
|
2 | const util = require('util');
|
3 | const { getCliLocation } = require('../utils');
|
4 | const exec = util.promisify(require('child_process').exec);
|
5 | const spawn = require('child_process').spawn;
|
6 | const path = require('path');
|
7 | const { NpmPackageError } = require('../errors');
|
8 | const Promise = require('bluebird');
|
9 | const fse = require('fs-extra');
|
10 | const logger = require('./logger').getLogger("cli-service");
|
11 | const { requireWithFallback } = require("./requireWithFallback")
|
12 |
|
13 | async function getLatestPackageVersion(packageName) {
|
14 | const result = await exec(`npm view ${packageName} version`);
|
15 | return result.stdout.trim();
|
16 | }
|
17 |
|
18 | function getPackageIfInstalledLocally(packageName) {
|
19 | try {
|
20 |
|
21 |
|
22 |
|
23 | return requireWithFallback(packageName);
|
24 | } catch (err) {
|
25 | return false;
|
26 | }
|
27 | }
|
28 |
|
29 | function getLocallyInstalledPackageVersion(rootPath, packageName) {
|
30 | return require(path.join(rootPath, `./node_modules/${packageName}/package.json`)).version;
|
31 | }
|
32 |
|
33 | function installPackageLocally(rootPath, packageName) {
|
34 | return exec(`npm install ${packageName} --no-save --no-package-lock --no-prune`, {cwd: rootPath});
|
35 | }
|
36 |
|
37 | function installPackagesLocally(rootPath, packageNames) {
|
38 | return exec(`npm i ${packageNames.join(' ')} --no-save --no-package-lock --no-prune`, {cwd: rootPath});
|
39 | }
|
40 |
|
41 | const cliLocation = getCliLocation();
|
42 | const localNpmLocationUnderNpm = path.resolve(cliLocation, 'node_modules', 'npm', 'bin', 'npm-cli.js');
|
43 | const localNpmLocationUnderYarn = path.resolve(cliLocation, '../../', 'npm', 'bin', 'npm-cli.js');
|
44 |
|
45 | let localNpmLocation;
|
46 | fse.exists(localNpmLocationUnderNpm).then(exists => {
|
47 | if (exists) {
|
48 | localNpmLocation = localNpmLocationUnderNpm;
|
49 | } else {
|
50 | fse.exists(localNpmLocationUnderYarn).then(yarnExists => {
|
51 | if (yarnExists) {
|
52 | localNpmLocation = localNpmLocationUnderYarn;
|
53 | } else {
|
54 | throw new Error('Can\'t find local NPM package');
|
55 | }
|
56 | });
|
57 | }
|
58 | });
|
59 |
|
60 | function installPackages(prefix, packageNames, proxyUri, timeoutMs) {
|
61 | return new Promise((resolve, reject) => {
|
62 | const proxyFlag = proxyUri ? ['--proxy', proxyUri] : [];
|
63 |
|
64 | const envVars = proxyUri ? {env: Object.assign(process.env, {'HTTP_PROXY': proxyUri, 'HTTPS_PROXY': proxyUri })} : {};
|
65 |
|
66 | let stdout = '';
|
67 | let stderr = '';
|
68 |
|
69 | const npmInstall = spawn('node', [localNpmLocation, 'i', '--prefix', prefix, '--prefer-offline', '--no-audit', ...packageNames, ...proxyFlag], envVars);
|
70 | npmInstall.stderr.pipe(process.stderr);
|
71 | npmInstall.stdout.pipe(process.stdout);
|
72 |
|
73 | npmInstall.stdout.on('data', (data) => {
|
74 | stdout += data;
|
75 | });
|
76 |
|
77 | npmInstall.stderr.on('data', (data) => {
|
78 | stderr += data;
|
79 | });
|
80 |
|
81 | npmInstall.on('close', (code) => {
|
82 | if (code) {
|
83 |
|
84 | let errorString;
|
85 | try {
|
86 | const packageVersion = /npm ERR! 404 '(.+)' is not in the npm registry/gm.exec(stderr)[1];
|
87 | const packageName = packageVersion.split('@')[0];
|
88 | errorString = `404 Not Found - GET https://registry.npmjs.org/${packageName} - Not found`;
|
89 | } catch(err) {
|
90 | errorString = `Npm Install closed with exit code ${code}\n stdout: ${stdout} stderr: ${stderr}` ;
|
91 | }
|
92 |
|
93 | logger.debug(`Npm Install closed with exit code ${code}`, {message: errorString});
|
94 |
|
95 | reject(new NpmPackageError(errorString));
|
96 | } else {
|
97 | resolve(stdout);
|
98 | }
|
99 | });
|
100 |
|
101 | setTimeout(() => {
|
102 | try {
|
103 | npmInstall.kill();
|
104 | } finally {
|
105 | reject(new Promise.TimeoutError());
|
106 | }
|
107 | }, timeoutMs);
|
108 | });
|
109 | }
|
110 |
|
111 | module.exports = {
|
112 | getLatestPackageVersion,
|
113 | getPackageIfInstalledLocally,
|
114 | getLocallyInstalledPackageVersion,
|
115 | installPackageLocally,
|
116 | installPackagesLocally,
|
117 | installPackages
|
118 | };
|