UNPKG

2.71 kBJavaScriptView Raw
1const readline = require('readline')
2const stripAnsi = require('strip-ansi')
3const spawn = require('cross-spawn')
4const wcwidth = require('wcwidth')
5const spinner = require('./spinner')
6const logger = require('./logger')
7const SAOError = require('./SAOError')
8
9let cachedNpmClient = null
10
11function setNpmClient(npmClient) {
12 if (npmClient) {
13 cachedNpmClient = npmClient
14 return npmClient
15 }
16
17 const { stdout, status } = spawn.sync('yarn', ['--version'])
18 cachedNpmClient = status === 0 && stdout ? 'yarn' : 'npm'
19 return cachedNpmClient
20}
21
22function getNpmClient() {
23 return cachedNpmClient || setNpmClient()
24}
25
26module.exports = async ({ cwd, npmClient, installArgs, packages, saveDev }) => {
27 npmClient = npmClient || getNpmClient()
28 const packageName = packages ? packages.join(', ') : 'packages'
29 spinner.start(`Installing ${packageName} with ${npmClient}`)
30
31 return new Promise((resolve, reject) => {
32 const args = [packages ? 'add' : 'install'].concat(packages ? packages : [])
33 if (saveDev) {
34 args.push(npmClient === 'npm' ? '-D' : '--dev')
35 }
36 const ps = spawn(npmClient, args.concat(installArgs || []), {
37 stdio: [0, 'pipe', 'pipe'],
38 cwd,
39 env: Object.assign(
40 {
41 FORCE_COLOR: true,
42 /* eslint-disable camelcase */
43 npm_config_color: 'always',
44 npm_config_progress: true
45 /* eslint-enable camelcase */
46 },
47 process.env
48 )
49 })
50
51 let output = ''
52 const stream = process.stderr
53
54 ps.stdout &&
55 ps.stdout.on('data', data => {
56 output += data
57 spinner.stop()
58 stream.write(data)
59 spinner.start()
60 })
61
62 ps.stderr &&
63 ps.stderr.on('data', data => {
64 output += data
65 spinner.stop()
66 stream.write(data)
67 spinner.start()
68 })
69
70 ps.on('close', code => {
71 spinner.stop()
72 // Clear output when succeeded
73 if (code === 0) {
74 const columns = stream.columns || 80
75 const lineCount = stripAnsi(output)
76 .split('\n')
77 .reduce((count, line) => {
78 return count + Math.max(1, Math.ceil(wcwidth(line) / columns))
79 }, 0)
80 for (let i = 0; i < lineCount; i++) {
81 if (i > 0) {
82 readline.moveCursor(stream, 0, -1)
83 }
84 readline.clearLine(stream, 0)
85 readline.cursorTo(stream, 0)
86 }
87 logger.success(`Installed ${packageName}`)
88 } else {
89 throw new SAOError(`Failed to install ${packageName} in ${cwd}`)
90 }
91 resolve({ code, npmClient })
92 })
93
94 ps.on('error', reject)
95 })
96}
97
98module.exports.getNpmClient = getNpmClient
99module.exports.setNpmClient = setNpmClient