1 | const { exec } = require('child_process')
|
2 | const { sep, join } = require('path')
|
3 | const { stat } = require('fs/promises')
|
4 | const { UTRError } = require('./error')
|
5 | const { getOutput } = require('./output')
|
6 |
|
7 | function npm (job, ...args) {
|
8 | return new Promise((resolve, reject) => {
|
9 | const childProcess = exec(`npm ${args.join(' ')}`, (err, stdout, stderr) => {
|
10 | if (err) {
|
11 | reject(UTRError.NPM_FAILED(stderr))
|
12 | } else {
|
13 | resolve(stdout.trim())
|
14 | }
|
15 | })
|
16 | if (args[0] === 'install') {
|
17 | getOutput(job).monitor(childProcess)
|
18 | }
|
19 | })
|
20 | }
|
21 |
|
22 | async function folderExists (path) {
|
23 | try {
|
24 | const result = await stat(path)
|
25 | return result.isDirectory()
|
26 | } catch (e) {
|
27 | return false
|
28 | }
|
29 | }
|
30 |
|
31 | let localRoot
|
32 | let globalRoot
|
33 |
|
34 | function resolveDependencyPath (name) {
|
35 | require(name)
|
36 | const pattern = `${sep}node_modules${sep}${name}${sep}`
|
37 | const path = Object.keys(require.cache).filter(path => path.includes(pattern))[0]
|
38 | if (path) {
|
39 | const pos = path.indexOf(pattern)
|
40 | return path.substring(0, pos + pattern.length - 1)
|
41 | }
|
42 | }
|
43 |
|
44 | module.exports = {
|
45 | resolveDependencyPath,
|
46 |
|
47 | async resolvePackage (job, name) {
|
48 | let modulePath
|
49 | let justInstalled = false
|
50 | try {
|
51 | modulePath = resolveDependencyPath(name)
|
52 | } catch (e) {
|
53 | }
|
54 | if (!modulePath) {
|
55 | if (!localRoot) {
|
56 | [localRoot, globalRoot] = await Promise.all([
|
57 | npm(job, 'root'),
|
58 | npm(job, 'root', '--global')
|
59 | ])
|
60 | }
|
61 | const localPath = join(localRoot, name)
|
62 | if (await folderExists(localPath)) {
|
63 | modulePath = localPath
|
64 | } else {
|
65 | const globalPath = join(globalRoot, name)
|
66 | if (!await folderExists(globalPath)) {
|
67 | if (!job.npmInstall) {
|
68 | throw UTRError.NPM_DEPENDENCY_NOT_FOUND(name)
|
69 | }
|
70 | const previousStatus = job.status
|
71 | job.status = `Installing ${name}...`
|
72 | await npm(job, 'install', name, '-g')
|
73 | justInstalled = true
|
74 | job.status = previousStatus
|
75 | }
|
76 | modulePath = globalPath
|
77 | }
|
78 | }
|
79 | const output = getOutput(job)
|
80 | const installedPackage = require(join(modulePath, 'package.json'))
|
81 | const { version: installedVersion } = installedPackage
|
82 | output.resolvedPackage(name, modulePath, installedVersion)
|
83 | if (!justInstalled) {
|
84 | const latestVersion = await npm(job, 'view', name, 'version')
|
85 | if (latestVersion !== installedVersion) {
|
86 | output.packageNotLatest(name, latestVersion)
|
87 | }
|
88 | }
|
89 | return modulePath
|
90 | }
|
91 | }
|