UNPKG

4.19 kBJavaScriptView Raw
1
2const util = require('util');
3const { getCliLocation } = require('../utils');
4const exec = util.promisify(require('child_process').exec);
5const spawn = require('child_process').spawn;
6const path = require('path');
7const { NpmPackageError } = require('../errors');
8const Promise = require('bluebird');
9const fse = require('fs-extra');
10const logger = require('./logger').getLogger("cli-service");
11const { requireWithFallback } = require("./requireWithFallback")
12
13async function getLatestPackageVersion(packageName) {
14 const result = await exec(`npm view ${packageName} version`);
15 return result.stdout.trim();
16}
17
18function getPackageIfInstalledLocally(packageName) {
19 try {
20 // note: this code fails is require itself throws here
21 // rather than an ENOENT - but since lazy dependencies are all controlled
22 // by us that's probably fine.
23 return requireWithFallback(packageName);
24 } catch (err) {
25 return false;
26 }
27}
28
29function getLocallyInstalledPackageVersion(rootPath, packageName) {
30 return require(path.join(rootPath, `./node_modules/${packageName}/package.json`)).version;
31}
32
33function installPackageLocally(rootPath, packageName) {
34 return exec(`npm install ${packageName} --no-save --no-package-lock --no-prune`, {cwd: rootPath});
35}
36
37function installPackagesLocally(rootPath, packageNames) {
38 return exec(`npm i ${packageNames.join(' ')} --no-save --no-package-lock --no-prune`, {cwd: rootPath});
39}
40
41const cliLocation = getCliLocation();
42const localNpmLocationUnderNpm = path.resolve(cliLocation, 'node_modules', 'npm', 'bin', 'npm-cli.js');
43const localNpmLocationUnderYarn = path.resolve(cliLocation, '../../', 'npm', 'bin', 'npm-cli.js');
44
45let localNpmLocation;
46fse.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
60function 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
111module.exports = {
112 getLatestPackageVersion,
113 getPackageIfInstalledLocally,
114 getLocallyInstalledPackageVersion,
115 installPackageLocally,
116 installPackagesLocally,
117 installPackages
118};