UNPKG

2.9 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 SherryError = require('./SherryError')
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 ({
27 cwd,
28 npmClient,
29 installArgs,
30 packages,
31 saveDev,
32 registry
33}) => {
34 npmClient = npmClient || getNpmClient()
35 const packageName = packages ? packages.join(', ') : 'packages'
36
37 return new Promise((resolve, reject) => {
38 const args = [packages ? 'add' : 'install'].concat(packages ? packages : [])
39 if (saveDev) {
40 args.push(npmClient === 'npm' ? '-D' : '--dev')
41 }
42 if (registry) {
43 args.push('--registry', registry)
44 }
45
46 if (installArgs) {
47 args.push(...installArgs)
48 }
49
50 logger.debug(npmClient, args.join(' '))
51 spinner.start(`Installing ${packageName} with ${npmClient}`)
52
53 const ps = spawn(npmClient, args, {
54 stdio: [0, 'pipe', 'pipe'],
55 cwd,
56 env: Object.assign(
57 {
58 FORCE_COLOR: true,
59 /* eslint-disable camelcase */
60 npm_config_color: 'always',
61 npm_config_progress: true
62 /* eslint-enable camelcase */
63 },
64 process.env
65 )
66 })
67
68 let output = ''
69 const stream = process.stderr
70
71 ps.stdout &&
72 ps.stdout.on('data', data => {
73 output += data
74 spinner.stop()
75 stream.write(data)
76 spinner.start()
77 })
78
79 ps.stderr &&
80 ps.stderr.on('data', data => {
81 output += data
82 spinner.stop()
83 stream.write(data)
84 spinner.start()
85 })
86
87 ps.on('close', code => {
88 spinner.stop()
89 // Clear output when succeeded
90 if (code === 0) {
91 const columns = stream.columns || 80
92 const lineCount = stripAnsi(output)
93 .split('\n')
94 .reduce((count, line) => {
95 return count + Math.max(1, Math.ceil(wcwidth(line) / columns))
96 }, 0)
97 for (let i = 0; i < lineCount; i++) {
98 if (i > 0) {
99 readline.moveCursor(stream, 0, -1)
100 }
101 readline.clearLine(stream, 0)
102 readline.cursorTo(stream, 0)
103 }
104 logger.success(`Installed ${packageName}`)
105 } else {
106 throw new SherryError(`Failed to install ${packageName} in ${cwd}`)
107 }
108 resolve({ code, npmClient })
109 })
110
111 ps.on('error', reject)
112 })
113}
114
115module.exports.getNpmClient = getNpmClient
116module.exports.setNpmClient = setNpmClient