-
Notifications
You must be signed in to change notification settings - Fork 9.2k
/
install-cli.ts
102 lines (85 loc) · 2.3 KB
/
install-cli.ts
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
96
97
98
99
100
101
102
import * as FSE from 'fs-extra'
import * as Path from 'path'
import * as fsAdmin from 'fs-admin'
/** The path for the installed command line tool. */
export const InstalledCLIPath = '/usr/local/bin/github'
/** The path to the packaged CLI. */
const PackagedPath = Path.resolve(__dirname, 'static', 'github.sh')
/** Install the command line tool on macOS. */
export async function installCLI(): Promise<void> {
const installedPath = await getResolvedInstallPath()
if (installedPath === PackagedPath) {
return
}
try {
await symlinkCLI(false)
} catch (e) {
// If we error without running as an admin, try again as an admin.
await symlinkCLI(true)
}
}
async function getResolvedInstallPath(): Promise<string | null> {
try {
return await FSE.readlink(InstalledCLIPath)
} catch {
return null
}
}
function removeExistingSymlink(asAdmin: boolean) {
if (!asAdmin) {
return FSE.unlink(InstalledCLIPath)
}
return new Promise<void>((resolve, reject) => {
fsAdmin.unlink(InstalledCLIPath, error => {
if (error !== null) {
reject(
new Error(
`Failed to remove file at ${InstalledCLIPath}. Authorization of GitHub Desktop Helper is required.`
)
)
return
}
resolve()
})
})
}
function createDirectories(asAdmin: boolean) {
const path = Path.dirname(InstalledCLIPath)
if (!asAdmin) {
return FSE.mkdirp(path)
}
return new Promise<void>((resolve, reject) => {
fsAdmin.makeTree(path, error => {
if (error !== null) {
reject(
new Error(
`Failed to create intermediate directories to ${InstalledCLIPath}`
)
)
return
}
resolve()
})
})
}
function createNewSymlink(asAdmin: boolean) {
if (!asAdmin) {
return FSE.symlink(PackagedPath, InstalledCLIPath)
}
return new Promise<void>((resolve, reject) => {
fsAdmin.symlink(PackagedPath, InstalledCLIPath, error => {
if (error !== null) {
reject(
new Error(`Failed to symlink ${PackagedPath} to ${InstalledCLIPath}`)
)
return
}
resolve()
})
})
}
async function symlinkCLI(asAdmin: boolean): Promise<void> {
await removeExistingSymlink(asAdmin)
await createDirectories(asAdmin)
await createNewSymlink(asAdmin)
}