/
BaseUpdater.ts
119 lines (102 loc) · 3.79 KB
/
BaseUpdater.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import * as fs from "fs"
import * as path from "path"
import { AllPublishOptions } from "builder-util-runtime"
import { AppAdapter } from "./AppAdapter"
import { AppUpdater, DownloadExecutorTask } from "./AppUpdater"
export abstract class BaseUpdater extends AppUpdater {
protected quitAndInstallCalled = false
private quitHandlerAdded = false
protected constructor(options?: AllPublishOptions | null, app?: AppAdapter) {
super(options, app)
}
quitAndInstall(isSilent = false, isForceRunAfter = false): void {
this._logger.info(`Install on explicit quitAndInstall`)
const isInstalled = this.install(isSilent, isSilent ? isForceRunAfter : true)
if (isInstalled) {
setImmediate(() => {
this.app.quit()
})
} else {
this.quitAndInstallCalled = false
}
}
protected executeDownload(taskOptions: DownloadExecutorTask): Promise<Array<string>> {
return super.executeDownload({
...taskOptions,
done: event => {
this.dispatchUpdateDownloaded(event)
this.addQuitHandler()
return Promise.resolve()
},
})
}
// must be sync
protected abstract doInstall(options: InstallOptions): boolean
// must be sync (because quit even handler is not async)
protected install(isSilent: boolean, isForceRunAfter: boolean): boolean {
if (this.quitAndInstallCalled) {
this._logger.warn("install call ignored: quitAndInstallCalled is set to true")
return false
}
const downloadedUpdateHelper = this.downloadedUpdateHelper
const installerPath = downloadedUpdateHelper == null ? null : downloadedUpdateHelper.file
const downloadedFileInfo = downloadedUpdateHelper == null ? null : downloadedUpdateHelper.downloadedFileInfo
if (installerPath == null || downloadedFileInfo == null) {
this.dispatchError(new Error("No valid update available, can't quit and install"))
return false
}
// prevent calling several times
this.quitAndInstallCalled = true
try {
let installPathRequiresElevation = false
if (process.platform === "win32") {
try {
const accessTestPath = path.join(path.dirname(process.execPath), `access-${Math.floor(Math.random() * 100)}.tmp`)
fs.writeFileSync(accessTestPath, " ")
fs.rmSync(accessTestPath)
} catch (err) {
// Require admin rights if needed
installPathRequiresElevation = true
}
}
this._logger.info(`Install: isSilent: ${isSilent}, isForceRunAfter: ${isForceRunAfter}, installPathRequiresElevation: ${installPathRequiresElevation}`)
return this.doInstall({
installerPath,
isSilent,
isForceRunAfter,
isAdminRightsRequired: installPathRequiresElevation || downloadedFileInfo.isAdminRightsRequired,
})
} catch (e) {
this.dispatchError(e)
return false
}
}
protected addQuitHandler(): void {
if (this.quitHandlerAdded || !this.autoInstallOnAppQuit) {
return
}
this.quitHandlerAdded = true
this.app.onQuit(exitCode => {
if (this.quitAndInstallCalled) {
this._logger.info("Update installer has already been triggered. Quitting application.")
return
}
if (!this.autoInstallOnAppQuit) {
this._logger.info("Update will not be installed on quit because autoInstallOnAppQuit is set to false.")
return
}
if (exitCode !== 0) {
this._logger.info(`Update will be not installed on quit because application is quitting with exit code ${exitCode}`)
return
}
this._logger.info("Auto install update on quit")
this.install(true, false)
})
}
}
export interface InstallOptions {
readonly installerPath: string
readonly isSilent: boolean
readonly isForceRunAfter: boolean
readonly isAdminRightsRequired: boolean
}