forked from microsoft/devicescript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpackageinstaller.ts
More file actions
95 lines (77 loc) · 2.59 KB
/
packageinstaller.ts
File metadata and controls
95 lines (77 loc) · 2.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { readFile, constants } from "node:fs/promises"
import { accessSync } from "node:fs"
import { join } from "node:path"
import { spawn } from "node:child_process"
import { isInteractive, verboseLog } from "./command"
import { PkgJson } from "@devicescript/compiler"
import { consoleBooleanAsk } from "./prompt"
function isYarnRepo(): boolean {
try {
accessSync(join(process.cwd(), "yarn.lock"), constants.R_OK)
return true
} catch {
return false
}
}
function getPackageInstallerCommand(
packageName?: string
): string[] {
if (isYarnRepo()) {
if (!packageName) return ["yarn", "install"]
return ["yarn", "add", packageName]
}
if (!packageName) return ["npm", "install"]
return ["npm", "install", "--save", "-D", "--no-workspaces", packageName]
}
async function isPackageInstalledLocally(pkgName: string): Promise<boolean> {
const pkgJsonString = await readFile(join(process.cwd(), "package.json"), {
encoding: "utf-8",
})
const pkgJson = JSON.parse(pkgJsonString) as PkgJson
return Object.keys(pkgJson.dependencies).includes(pkgName)
}
async function spawnAsyncInstaller(packageName: string) {
let resolve: () => void
let reject: () => void
const [rootCmd, ...cmdArgs] = getPackageInstallerCommand(packageName)
const installProcess = spawn(rootCmd, cmdArgs, {
cwd: process.cwd(),
env: process.env,
})
installProcess.stderr.on("data", data => {
verboseLog(`package installer process: ${data}`)
})
installProcess.on("close", code => {
verboseLog(`install process exit with code ${code}`)
if (code === 0) resolve()
else reject()
})
return new Promise((res, rej) => {
// @ts-ignore
resolve = res
reject = rej
})
}
export async function askForPackageInstallation(
pkgName: string,
installByDefault = true
) {
if (!isInteractive) return
if (await isPackageInstalledLocally(pkgName)) return
const shouldInstallPackage = await consoleBooleanAsk(
`Install package "${pkgName}"`,
installByDefault
)
if (shouldInstallPackage) {
try {
console.log(`Installing package "${pkgName}" ...`)
await spawnAsyncInstaller(pkgName)
console.log(`Package "${pkgName}" installed!`)
} catch (e) {
const installCmd = getPackageInstallerCommand(pkgName).join(" ")
console.log(
`Automatic package installation failed :( You can try to install it manually by running "${installCmd}"`
)
}
}
}