electron-updator 0.1.0 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -7
- package/build/app-updator.js +246 -0
- package/build/common/constants.js +96 -0
- package/build/elelctron-app-adapter.js +33 -0
- package/build/index.js +10 -0
- package/build/libs/installer.exe +0 -0
- package/build/libs/unzip.exe +0 -0
- package/build/mac-updator.js +108 -0
- package/build/utils/download-file.js +74 -0
- package/build/utils/index.js +122 -0
- package/build/utils/install-macos-dmg.js +151 -0
- package/build/utils/sudo-prompt-exec.js +23 -0
- package/build/windows-updator.js +87 -0
- package/package.json +51 -20
- package/bin/electron-updator.js +0 -3
- package/index.js +0 -3
- package/lib/electron-updator.js +0 -1
package/README.md
CHANGED
@@ -8,23 +8,34 @@
|
|
8
8
|
|
9
9
|
[npm-image]: https://img.shields.io/npm/v/electron-updator.svg
|
10
10
|
[npm-url]: https://npmjs.org/package/electron-updator
|
11
|
-
[ci-image]: https://github.com/
|
12
|
-
[ci-url]: https://github.com/
|
13
|
-
[codecov-image]: https://img.shields.io/codecov/c/github/
|
14
|
-
[codecov-url]: https://codecov.io/gh/
|
11
|
+
[ci-image]: https://github.com/electron-modules/electron-updator/actions/workflows/ci.yml/badge.svg
|
12
|
+
[ci-url]: https://github.com/electron-modules/electron-updator/actions/workflows/ci.yml
|
13
|
+
[codecov-image]: https://img.shields.io/codecov/c/github/electron-modules/electron-updator.svg?logo=codecov
|
14
|
+
[codecov-url]: https://codecov.io/gh/electron-modules/electron-updator
|
15
15
|
[node-image]: https://img.shields.io/badge/node.js-%3E=_16-green.svg
|
16
16
|
[node-url]: http://nodejs.org/download/
|
17
17
|
[download-image]: https://img.shields.io/npm/dm/electron-updator.svg
|
18
18
|
[download-url]: https://npmjs.org/package/electron-updator
|
19
19
|
|
20
|
-
> electron
|
21
|
-
|
20
|
+
> electron updator
|
22
21
|
## Installment
|
23
22
|
|
24
23
|
```bash
|
25
|
-
$ npm i electron-updator --save
|
24
|
+
$ npm i electron-updator --save
|
26
25
|
```
|
27
26
|
|
27
|
+
<!-- GITCONTRIBUTOR_START -->
|
28
|
+
|
29
|
+
## Contributors
|
30
|
+
|
31
|
+
|[<img src="https://avatars.githubusercontent.com/u/1011681?v=4" width="100px;"/><br/><sub><b>xudafeng</b></sub>](https://github.com/xudafeng)<br/>|[<img src="https://avatars.githubusercontent.com/u/4081746?v=4" width="100px;"/><br/><sub><b>zlyi</b></sub>](https://github.com/zlyi)<br/>|
|
32
|
+
| :---: | :---: |
|
33
|
+
|
34
|
+
|
35
|
+
This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Mon Jan 30 2023 19:21:07 GMT+0800`.
|
36
|
+
|
37
|
+
<!-- GITCONTRIBUTOR_END -->
|
38
|
+
|
28
39
|
## License
|
29
40
|
|
30
41
|
The MIT License (MIT)
|
@@ -0,0 +1,246 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.AppUpdator = void 0;
|
4
|
+
const eventemitter3_1 = require("eventemitter3");
|
5
|
+
const constants_1 = require("./common/constants");
|
6
|
+
const download_file_1 = require("./utils/download-file");
|
7
|
+
const utils_1 = require("./utils");
|
8
|
+
const elelctron_app_adapter_1 = require("./elelctron-app-adapter");
|
9
|
+
class AppUpdator extends eventemitter3_1.EventEmitter {
|
10
|
+
constructor(options, app) {
|
11
|
+
super();
|
12
|
+
this.state = "idle" /* StateType.Idle */;
|
13
|
+
this.options = options;
|
14
|
+
this.logger = this._wrapLogger(options.logger);
|
15
|
+
this.app = app || new elelctron_app_adapter_1.ElectronAppAdapter();
|
16
|
+
this.startTimeStamp = new Date().getTime();
|
17
|
+
this.logger.info('AppUpdator#constructor');
|
18
|
+
this.availableUpdate = {
|
19
|
+
resourcePath: '',
|
20
|
+
latestAsarPath: '',
|
21
|
+
downloadTargetDir: '',
|
22
|
+
};
|
23
|
+
}
|
24
|
+
_wrapLogger(logger) {
|
25
|
+
if (!logger) {
|
26
|
+
logger = console;
|
27
|
+
}
|
28
|
+
const _logger = { ...logger };
|
29
|
+
const _wrap = (message, callback) => {
|
30
|
+
callback(`ElectronUpdator(${this.startTimeStamp})${message}`);
|
31
|
+
};
|
32
|
+
_logger.error = (message) => {
|
33
|
+
_wrap(message, logger.error);
|
34
|
+
};
|
35
|
+
_logger.info = (message) => {
|
36
|
+
_wrap(message, logger.info);
|
37
|
+
};
|
38
|
+
_logger.warn = (message) => {
|
39
|
+
_wrap(message, logger.warn);
|
40
|
+
};
|
41
|
+
return _logger;
|
42
|
+
}
|
43
|
+
setState(state) {
|
44
|
+
this.logger.info(`AppUpdator#setState${state}`);
|
45
|
+
this.state = state;
|
46
|
+
}
|
47
|
+
setFeedUrl(url) {
|
48
|
+
this.logger.info(`AppUpdator#setFeedUrl:url is ${url}`);
|
49
|
+
if (url && this.options) {
|
50
|
+
this.options.url = url;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
async checkForUpdates(executeType = constants_1.ExecuteType.Auto) {
|
54
|
+
this.logger.info(`AppUpdator#checkForUpdates:state is ${this.state}`);
|
55
|
+
if (executeType === constants_1.ExecuteType.User) {
|
56
|
+
if (this.state === "downloaded" /* StateType.Downloaded */) {
|
57
|
+
this.logger.info(`AppUpdator#checkForUpdates:UPDATE_DOWNLOADED`);
|
58
|
+
this.emit(constants_1.EventType.UPDATE_DOWNLOADED, {
|
59
|
+
executeType,
|
60
|
+
});
|
61
|
+
}
|
62
|
+
else {
|
63
|
+
this.logger.info(`AppUpdator#checkForUpdates:UPDATE_NOT_AVAILABLE`);
|
64
|
+
this.emit(constants_1.EventType.UPDATE_NOT_AVAILABLE, { updateInfo: this.updateInfo });
|
65
|
+
}
|
66
|
+
return;
|
67
|
+
}
|
68
|
+
this.setState("idle" /* StateType.Idle */);
|
69
|
+
try {
|
70
|
+
// 新一轮更新流程,更新 TimeStamp
|
71
|
+
this.startTimeStamp = new Date().getTime();
|
72
|
+
this.setState("checking-for-update" /* StateType.CheckingForUpdate */);
|
73
|
+
this.emit(constants_1.EventType.CHECKING_FOR_UPDATE);
|
74
|
+
const updateInfoResponse = await (0, utils_1.requestUpdateInfo)(this.options);
|
75
|
+
this.updateInfo = (this.options?.responseFormatter ? this.options?.responseFormatter(updateInfoResponse) : updateInfoResponse);
|
76
|
+
const needUpdate = this.options?.needUpdate(updateInfoResponse);
|
77
|
+
if (!needUpdate) {
|
78
|
+
this.logger.info(`updateInfo is ${JSON.stringify(this.updateInfo)},needUpdate is false`);
|
79
|
+
this.emit(constants_1.EventType.UPDATE_NOT_AVAILABLE, { updateInfo: this.updateInfo });
|
80
|
+
this.setState("idle" /* StateType.Idle */);
|
81
|
+
return;
|
82
|
+
}
|
83
|
+
this.logger.info(`AppUpdator#checkForUpdates:needUpdate is true`);
|
84
|
+
this.availableUpdate = this.doGetAvailableUpdateInfo(this.updateInfo);
|
85
|
+
if (!this.options?.autoDownload) {
|
86
|
+
this.logger.info(`AppUpdator#checkForUpdates:emit UPDATE_AVAILABLE`);
|
87
|
+
this.emit(constants_1.EventType.UPDATE_AVAILABLE, {
|
88
|
+
executeType,
|
89
|
+
updateInfo: this.updateInfo,
|
90
|
+
});
|
91
|
+
return;
|
92
|
+
}
|
93
|
+
this.downloadUpdate(executeType);
|
94
|
+
}
|
95
|
+
catch (e) {
|
96
|
+
e.customMessage = e.customMessage ? e.customMessage : `${constants_1.InstallResultType.CheckForUpdatesError}_${e.message}`;
|
97
|
+
this.logError(e);
|
98
|
+
this.setState("idle" /* StateType.Idle */);
|
99
|
+
}
|
100
|
+
}
|
101
|
+
async downloadUpdate(executeType = constants_1.ExecuteType.User) {
|
102
|
+
this.logger.info(`AppUpdator#downloadUpdate:executeType is ${executeType}`);
|
103
|
+
await this.downloadUpdateFile(this.updateInfo);
|
104
|
+
const result = await this.preCheck();
|
105
|
+
if (result.success) {
|
106
|
+
this.logger.info(`AppUpdator#downloadUpdate:emit UPDATE_DOWNLOADED`);
|
107
|
+
this.emit(constants_1.EventType.UPDATE_DOWNLOADED, {
|
108
|
+
executeType,
|
109
|
+
});
|
110
|
+
}
|
111
|
+
else {
|
112
|
+
this.logError(result.error);
|
113
|
+
this.setState("idle" /* StateType.Idle */);
|
114
|
+
}
|
115
|
+
}
|
116
|
+
async quitAndInstall() {
|
117
|
+
this.logger.info(`AppUpdator#quitAndInstall:state is ${this.state}`);
|
118
|
+
if (this.state !== "downloaded" /* StateType.Downloaded */) {
|
119
|
+
return;
|
120
|
+
}
|
121
|
+
this.setState("idle" /* StateType.Idle */);
|
122
|
+
try {
|
123
|
+
let result = { success: false };
|
124
|
+
if (this.updateInfo?.updateType === constants_1.UpdateType.Package) {
|
125
|
+
result = await this.doQuitAndInstallPackage();
|
126
|
+
}
|
127
|
+
else {
|
128
|
+
result = await this.doQuitAndInstallAsar();
|
129
|
+
}
|
130
|
+
if (result.success) {
|
131
|
+
this.logger.warn(`AppUpdator#quitAndInstall:install success`);
|
132
|
+
this.emit(constants_1.EventType.BEFORE_QUIT_FOR_UPDATE);
|
133
|
+
}
|
134
|
+
else {
|
135
|
+
result.message = `error: ${result.error?.message}`;
|
136
|
+
this.dispatchError(result.error);
|
137
|
+
}
|
138
|
+
}
|
139
|
+
catch (e) {
|
140
|
+
this.dispatchError(e);
|
141
|
+
}
|
142
|
+
}
|
143
|
+
async preCheckForAsar() {
|
144
|
+
this.logger.info(`AppUpdator#preCheckForAsar`);
|
145
|
+
return await this.unzip();
|
146
|
+
}
|
147
|
+
async preCheck() {
|
148
|
+
this.logger.info(`AppUpdator#preCheck`);
|
149
|
+
const { resourcePath } = this.availableUpdate;
|
150
|
+
if (this.state !== "downloaded" /* StateType.Downloaded */) {
|
151
|
+
return {
|
152
|
+
success: false,
|
153
|
+
error: new Error(`AppUpdator#preCheck:update status(${this.state}) error`),
|
154
|
+
};
|
155
|
+
}
|
156
|
+
// 清理老包
|
157
|
+
try {
|
158
|
+
this.logger.info(`AppUpdator#preCheck:cleanOldArchive`);
|
159
|
+
await (0, utils_1.cleanOldArchive)(resourcePath);
|
160
|
+
}
|
161
|
+
catch (e) {
|
162
|
+
this.logError(e);
|
163
|
+
}
|
164
|
+
let result = { success: true };
|
165
|
+
const { downloadTargetDir } = this.availableUpdate;
|
166
|
+
try {
|
167
|
+
const hasLatestFile = await (0, utils_1.existsAsync)(downloadTargetDir);
|
168
|
+
// 下载失败返回提示
|
169
|
+
if (!hasLatestFile) {
|
170
|
+
return {
|
171
|
+
success: false,
|
172
|
+
error: new Error('file is notfound'),
|
173
|
+
};
|
174
|
+
}
|
175
|
+
}
|
176
|
+
catch (e) {
|
177
|
+
return {
|
178
|
+
success: false,
|
179
|
+
error: e,
|
180
|
+
};
|
181
|
+
}
|
182
|
+
if (this.updateInfo?.updateType === constants_1.UpdateType.Package) {
|
183
|
+
result = await this.doPreCheckForPackage();
|
184
|
+
}
|
185
|
+
else {
|
186
|
+
result = await this.preCheckForAsar();
|
187
|
+
}
|
188
|
+
return result;
|
189
|
+
}
|
190
|
+
async downloadUpdateFile(updateInfo) {
|
191
|
+
if (this.state !== "checking-for-update" /* StateType.CheckingForUpdate */) {
|
192
|
+
throw new Error(`AppUpdator#downloadUpdateFile:update status(${this.state}) error`);
|
193
|
+
}
|
194
|
+
const { url, signature } = updateInfo.files[0];
|
195
|
+
const { downloadTargetDir } = this.availableUpdate;
|
196
|
+
this.setState("downloading" /* StateType.Downloading */);
|
197
|
+
try {
|
198
|
+
await (0, download_file_1.downloadFile)({
|
199
|
+
logger: this.logger,
|
200
|
+
url,
|
201
|
+
signature,
|
202
|
+
targetDir: downloadTargetDir,
|
203
|
+
emit: this.emit,
|
204
|
+
progressHandle: (data) => {
|
205
|
+
this.emit(constants_1.EventType.UPDATE_DOWNLOAD_PROGRESS, data);
|
206
|
+
},
|
207
|
+
});
|
208
|
+
this.logger.info(`AppUpdator#downloadUpdateFile:Downloaded`);
|
209
|
+
this.setState("downloaded" /* StateType.Downloaded */);
|
210
|
+
}
|
211
|
+
catch (e) {
|
212
|
+
this.setState("idle" /* StateType.Idle */);
|
213
|
+
e.customMessage = `${constants_1.InstallResultType.DownloadError}_${e.message}`;
|
214
|
+
this.logError(e);
|
215
|
+
}
|
216
|
+
}
|
217
|
+
async unzip() {
|
218
|
+
this.logger.info(`AppUpdator#unzip:start`);
|
219
|
+
try {
|
220
|
+
const result = await this.doUnzip();
|
221
|
+
if (!result.success) {
|
222
|
+
return result;
|
223
|
+
}
|
224
|
+
const { latestAsarPath } = this.availableUpdate;
|
225
|
+
const exist = await (0, utils_1.existFile)(latestAsarPath);
|
226
|
+
return Promise.resolve({ success: exist });
|
227
|
+
}
|
228
|
+
catch (error) {
|
229
|
+
error.customMessage = constants_1.InstallResultType.UpdateUnzipError;
|
230
|
+
return Promise.resolve({
|
231
|
+
success: false,
|
232
|
+
error,
|
233
|
+
});
|
234
|
+
}
|
235
|
+
}
|
236
|
+
dispatchError(e) {
|
237
|
+
this.logError(e);
|
238
|
+
this.emit(constants_1.EventType.ERROR, e.message);
|
239
|
+
}
|
240
|
+
logError(e) {
|
241
|
+
const message = (e.stack || e).toString();
|
242
|
+
this.logger.error(message);
|
243
|
+
}
|
244
|
+
}
|
245
|
+
exports.AppUpdator = AppUpdator;
|
246
|
+
//# sourceMappingURL=app-updator.js.map
|
@@ -0,0 +1,96 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.EventType = exports.DownloadProgressStatus = exports.ExecuteType = exports.UpdateType = exports.InstallResultType = exports.OldArchivePrefix = void 0;
|
4
|
+
/**
|
5
|
+
* 更新包备份前缀
|
6
|
+
*/
|
7
|
+
exports.OldArchivePrefix = 'old-';
|
8
|
+
/**
|
9
|
+
* 安装结果类型
|
10
|
+
*/
|
11
|
+
var InstallResultType;
|
12
|
+
(function (InstallResultType) {
|
13
|
+
InstallResultType["UpdateUnzipError"] = "update-unzip-error";
|
14
|
+
InstallResultType["DownloadError"] = "download-error";
|
15
|
+
InstallResultType["UpdateSuccess"] = "update-success";
|
16
|
+
InstallResultType["CheckForUpdatesError"] = "check-for-updates-error";
|
17
|
+
})(InstallResultType = exports.InstallResultType || (exports.InstallResultType = {}));
|
18
|
+
/**
|
19
|
+
* 更新类型
|
20
|
+
*/
|
21
|
+
var UpdateType;
|
22
|
+
(function (UpdateType) {
|
23
|
+
/** 全量更新 */
|
24
|
+
UpdateType["Package"] = "package";
|
25
|
+
/** 动态更新 */
|
26
|
+
UpdateType["Asar"] = "asar";
|
27
|
+
/** 更新包更新 */
|
28
|
+
UpdateType["Assets"] = "assets";
|
29
|
+
})(UpdateType = exports.UpdateType || (exports.UpdateType = {}));
|
30
|
+
/**
|
31
|
+
* 执行类型
|
32
|
+
*/
|
33
|
+
var ExecuteType;
|
34
|
+
(function (ExecuteType) {
|
35
|
+
/**
|
36
|
+
* 自动触发
|
37
|
+
*/
|
38
|
+
ExecuteType["User"] = "user";
|
39
|
+
/**
|
40
|
+
* 手动触发
|
41
|
+
*/
|
42
|
+
ExecuteType["Auto"] = "auto";
|
43
|
+
})(ExecuteType = exports.ExecuteType || (exports.ExecuteType = {}));
|
44
|
+
/**
|
45
|
+
* 执行类型
|
46
|
+
*/
|
47
|
+
var DownloadProgressStatus;
|
48
|
+
(function (DownloadProgressStatus) {
|
49
|
+
/**
|
50
|
+
* 开始
|
51
|
+
*/
|
52
|
+
DownloadProgressStatus["Begin"] = "begin";
|
53
|
+
/**
|
54
|
+
* 下载中
|
55
|
+
*/
|
56
|
+
DownloadProgressStatus["Downloading"] = "downloading";
|
57
|
+
/**
|
58
|
+
* 结束
|
59
|
+
*/
|
60
|
+
DownloadProgressStatus["End"] = "end";
|
61
|
+
})(DownloadProgressStatus = exports.DownloadProgressStatus || (exports.DownloadProgressStatus = {}));
|
62
|
+
/**
|
63
|
+
* 事件类型
|
64
|
+
*/
|
65
|
+
var EventType;
|
66
|
+
(function (EventType) {
|
67
|
+
/**
|
68
|
+
* 下载完成
|
69
|
+
*/
|
70
|
+
EventType["UPDATE_DOWNLOADED"] = "update-downloaded";
|
71
|
+
/**
|
72
|
+
* 下载进度
|
73
|
+
*/
|
74
|
+
EventType["UPDATE_DOWNLOAD_PROGRESS"] = "update-download-progress";
|
75
|
+
/**
|
76
|
+
* 用户调用 quitAndInstall 之后发出,可在次事件后完成关闭窗口、重启等操作
|
77
|
+
*/
|
78
|
+
EventType["BEFORE_QUIT_FOR_UPDATE"] = "before-quit-for-update";
|
79
|
+
/**
|
80
|
+
* 有可用更新
|
81
|
+
*/
|
82
|
+
EventType["UPDATE_AVAILABLE"] = "update-available";
|
83
|
+
/**
|
84
|
+
* 开始检查更新
|
85
|
+
*/
|
86
|
+
EventType["CHECKING_FOR_UPDATE"] = "checking-for-update";
|
87
|
+
/**
|
88
|
+
* 无可用更新
|
89
|
+
*/
|
90
|
+
EventType["UPDATE_NOT_AVAILABLE"] = "update-not-available";
|
91
|
+
/**
|
92
|
+
* 错误
|
93
|
+
*/
|
94
|
+
EventType["ERROR"] = "error";
|
95
|
+
})(EventType = exports.EventType || (exports.EventType = {}));
|
96
|
+
//# sourceMappingURL=constants.js.map
|
@@ -0,0 +1,33 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.ElectronAppAdapter = void 0;
|
4
|
+
const electron_1 = require("electron");
|
5
|
+
class ElectronAppAdapter {
|
6
|
+
constructor(app = electron_1.app) {
|
7
|
+
this.app = app;
|
8
|
+
}
|
9
|
+
get name() {
|
10
|
+
return this.app.getName();
|
11
|
+
}
|
12
|
+
get isPackaged() {
|
13
|
+
return this.app.isPackaged === true;
|
14
|
+
}
|
15
|
+
get userDataPath() {
|
16
|
+
return this.app.getPath('userData');
|
17
|
+
}
|
18
|
+
get exePath() {
|
19
|
+
return this.app.getPath('exe');
|
20
|
+
}
|
21
|
+
exit(code) {
|
22
|
+
this.app.exit(code);
|
23
|
+
}
|
24
|
+
relaunch(code) {
|
25
|
+
this.app.relaunch();
|
26
|
+
this.app.exit(code);
|
27
|
+
}
|
28
|
+
quit() {
|
29
|
+
this.app.quit();
|
30
|
+
}
|
31
|
+
}
|
32
|
+
exports.ElectronAppAdapter = ElectronAppAdapter;
|
33
|
+
//# sourceMappingURL=elelctron-app-adapter.js.map
|
package/build/index.js
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
const constants_1 = require("./common/constants");
|
4
|
+
const mac_updator_1 = require("./mac-updator");
|
5
|
+
const windows_updator_1 = require("./windows-updator");
|
6
|
+
exports.default = {
|
7
|
+
UpdateType: constants_1.UpdateType, EventType: constants_1.EventType, ExecuteType: constants_1.ExecuteType,
|
8
|
+
MacUpdator: mac_updator_1.MacUpdator, WindowsUpdator: windows_updator_1.WindowsUpdator, DownloadProgressStatus: constants_1.DownloadProgressStatus,
|
9
|
+
};
|
10
|
+
//# sourceMappingURL=index.js.map
|
Binary file
|
Binary file
|
@@ -0,0 +1,108 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.MacUpdator = void 0;
|
7
|
+
const path_1 = __importDefault(require("path"));
|
8
|
+
const app_updator_1 = require("./app-updator");
|
9
|
+
const constants_1 = require("./common/constants");
|
10
|
+
const install_macos_dmg_1 = __importDefault(require("./utils/install-macos-dmg"));
|
11
|
+
const utils_1 = require("./utils");
|
12
|
+
class MacUpdator extends app_updator_1.AppUpdator {
|
13
|
+
constructor(options) {
|
14
|
+
super(options);
|
15
|
+
}
|
16
|
+
doGetAvailableUpdateInfo(updateInfo) {
|
17
|
+
this.logger.info('MacUpdator#doGetAvailableUpdateInfo:start');
|
18
|
+
const exePath = this.app.exePath;
|
19
|
+
const resourcePath = path_1.default.resolve(exePath, '..', '..', 'Resources');
|
20
|
+
const latestAsarPath = path_1.default.resolve(resourcePath, 'latest.asar');
|
21
|
+
const latestAppPath = path_1.default.resolve(resourcePath, 'latest');
|
22
|
+
let downloadTargetDir = `${latestAsarPath}.zip`;
|
23
|
+
if (updateInfo.updateType === constants_1.UpdateType.Package) {
|
24
|
+
downloadTargetDir = `${latestAppPath}.dmg`;
|
25
|
+
}
|
26
|
+
return {
|
27
|
+
resourcePath,
|
28
|
+
downloadTargetDir,
|
29
|
+
latestAsarPath,
|
30
|
+
};
|
31
|
+
}
|
32
|
+
async doPreCheckForPackage() {
|
33
|
+
this.logger.info('MacUpdator#doPreCheckForPackage:start');
|
34
|
+
// Mac 全量安装前,先进行 dmg 安装检查
|
35
|
+
return await (0, install_macos_dmg_1.default)(this.options, this.logger, this.availableUpdate, this.updateInfo, true);
|
36
|
+
}
|
37
|
+
/**
|
38
|
+
* 资源解压
|
39
|
+
* @return
|
40
|
+
*/
|
41
|
+
async doUnzip() {
|
42
|
+
this.logger.info('MacUpdator#doUnzip:start');
|
43
|
+
const { resourcePath, downloadTargetDir } = this.availableUpdate;
|
44
|
+
try {
|
45
|
+
// 直接解压
|
46
|
+
await (0, utils_1.execAsync)(`unzip -o ${downloadTargetDir}`, {
|
47
|
+
cwd: resourcePath,
|
48
|
+
maxBuffer: 2 ** 28,
|
49
|
+
});
|
50
|
+
return {
|
51
|
+
success: true,
|
52
|
+
};
|
53
|
+
}
|
54
|
+
catch (error) {
|
55
|
+
return {
|
56
|
+
success: false,
|
57
|
+
error,
|
58
|
+
};
|
59
|
+
}
|
60
|
+
}
|
61
|
+
async doQuitAndInstallAsar() {
|
62
|
+
this.logger.info('MacUpdator#doQuitAndInstallAsar:start');
|
63
|
+
if (!this.availableUpdate) {
|
64
|
+
this.logger.error('MacUpdator#doQuitAndInstallAsar:not availableUpdate');
|
65
|
+
return Promise.resolve({ success: false });
|
66
|
+
}
|
67
|
+
const { resourcePath, latestAsarPath } = this.availableUpdate;
|
68
|
+
const oldAsarPath = path_1.default.resolve(resourcePath, `${constants_1.OldArchivePrefix}${new Date().getTime()}.asar`);
|
69
|
+
const currentAsarPath = path_1.default.resolve(resourcePath, 'app.asar');
|
70
|
+
try {
|
71
|
+
// 将老包改名 app.asar => old-xxxx.asar
|
72
|
+
if (await (0, utils_1.existsAsync)(currentAsarPath)) {
|
73
|
+
await (0, utils_1.renameAsync)(currentAsarPath, oldAsarPath);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
catch (error) {
|
77
|
+
return {
|
78
|
+
success: false,
|
79
|
+
error,
|
80
|
+
};
|
81
|
+
}
|
82
|
+
try {
|
83
|
+
// 新包替换
|
84
|
+
await (0, utils_1.renameAsync)(latestAsarPath, currentAsarPath);
|
85
|
+
}
|
86
|
+
catch (error) {
|
87
|
+
// 替换出错,需要把老包还原
|
88
|
+
await (0, utils_1.renameAsync)(oldAsarPath, currentAsarPath);
|
89
|
+
return {
|
90
|
+
success: false,
|
91
|
+
error,
|
92
|
+
};
|
93
|
+
}
|
94
|
+
this.logger.warn('AppUpdator#quitAndInstall:install success');
|
95
|
+
this.emit(constants_1.EventType.BEFORE_QUIT_FOR_UPDATE);
|
96
|
+
// 重启应用
|
97
|
+
this.app.relaunch();
|
98
|
+
return {
|
99
|
+
success: true,
|
100
|
+
};
|
101
|
+
}
|
102
|
+
async doQuitAndInstallPackage() {
|
103
|
+
this.logger.info('AppUpdator#doQuitAndInstallPackage:start');
|
104
|
+
return await (0, install_macos_dmg_1.default)(this.options, this.logger, this.availableUpdate, this.updateInfo);
|
105
|
+
}
|
106
|
+
}
|
107
|
+
exports.MacUpdator = MacUpdator;
|
108
|
+
//# sourceMappingURL=mac-updator.js.map
|
@@ -0,0 +1,74 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.downloadFile = void 0;
|
7
|
+
const urllib_1 = __importDefault(require("urllib"));
|
8
|
+
const constants_1 = require("../common/constants");
|
9
|
+
const _1 = require(".");
|
10
|
+
/**
|
11
|
+
* 文件下载
|
12
|
+
* @param updator 更新实例
|
13
|
+
* @param url 下载地址
|
14
|
+
* @param signature 下载签名
|
15
|
+
* @param targeDir 下载目录
|
16
|
+
* @param progressHandle 下载状态回调
|
17
|
+
* @return
|
18
|
+
*/
|
19
|
+
const downloadFile = async ({ logger, url, signature, targetDir, progressHandle }) => {
|
20
|
+
logger.info('downloadFile#downloadFile (start)');
|
21
|
+
const writeStream = (0, _1.createWriteStream)(targetDir);
|
22
|
+
let currentLength = 0;
|
23
|
+
progressHandle({
|
24
|
+
status: constants_1.DownloadProgressStatus.Begin,
|
25
|
+
});
|
26
|
+
return new Promise((resolve, reject) => {
|
27
|
+
urllib_1.default
|
28
|
+
.request(url, {
|
29
|
+
streaming: true,
|
30
|
+
followRedirect: true,
|
31
|
+
timeout: 10 * 60 * 1000,
|
32
|
+
})
|
33
|
+
.then((res) => {
|
34
|
+
const totalLength = res.headers['content-length'];
|
35
|
+
logger.info(`downloadFile#downloadFile (then),totalLength is ${totalLength}`);
|
36
|
+
res.res.on('data', (data) => {
|
37
|
+
try {
|
38
|
+
currentLength += data.length;
|
39
|
+
const progress = (currentLength / totalLength) * 100;
|
40
|
+
progressHandle({
|
41
|
+
status: constants_1.DownloadProgressStatus.Downloading,
|
42
|
+
progress,
|
43
|
+
url,
|
44
|
+
signature,
|
45
|
+
data,
|
46
|
+
});
|
47
|
+
writeStream.write(data);
|
48
|
+
}
|
49
|
+
catch (e) {
|
50
|
+
reject(e);
|
51
|
+
}
|
52
|
+
});
|
53
|
+
res.res.on('end', () => {
|
54
|
+
// 推迟调用 end(): https://stackoverflow.com/a/53878933
|
55
|
+
process.nextTick(() => writeStream.end());
|
56
|
+
try {
|
57
|
+
progressHandle({
|
58
|
+
status: constants_1.DownloadProgressStatus.End,
|
59
|
+
url,
|
60
|
+
signature,
|
61
|
+
});
|
62
|
+
logger.info('download file success, url:%s, to %s', url, targetDir);
|
63
|
+
resolve();
|
64
|
+
}
|
65
|
+
catch (e) {
|
66
|
+
reject(e);
|
67
|
+
}
|
68
|
+
});
|
69
|
+
res.res.on('error', reject);
|
70
|
+
});
|
71
|
+
});
|
72
|
+
};
|
73
|
+
exports.downloadFile = downloadFile;
|
74
|
+
//# sourceMappingURL=download-file.js.map
|
@@ -0,0 +1,122 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.getExecuteFile = exports.requestUpdateInfo = exports.existFile = exports.cleanOldArchive = exports.spawnAsync = exports.waitUntil = exports.sleep = exports.getMacOSAppPath = exports.sudoPrompt = exports.existsSync = exports.createWriteStream = exports.isMac = exports.isWin = exports.execAsync = exports.rimrafAsync = exports.readdirAsync = exports.existsAsync = exports.renameAsync = void 0;
|
7
|
+
const path_1 = __importDefault(require("path"));
|
8
|
+
const child_process_1 = require("child_process");
|
9
|
+
const util_1 = __importDefault(require("util"));
|
10
|
+
const urllib_1 = __importDefault(require("urllib"));
|
11
|
+
const sudo_prompt_alt_1 = __importDefault(require("sudo-prompt-alt"));
|
12
|
+
exports.sudoPrompt = sudo_prompt_alt_1.default;
|
13
|
+
const rimraf_alt_1 = __importDefault(require("rimraf-alt"));
|
14
|
+
const original_fs_1 = require("original-fs");
|
15
|
+
Object.defineProperty(exports, "existsSync", { enumerable: true, get: function () { return original_fs_1.existsSync; } });
|
16
|
+
Object.defineProperty(exports, "createWriteStream", { enumerable: true, get: function () { return original_fs_1.createWriteStream; } });
|
17
|
+
const constants_1 = require("../common/constants");
|
18
|
+
exports.renameAsync = util_1.default.promisify(original_fs_1.rename);
|
19
|
+
exports.existsAsync = util_1.default.promisify(original_fs_1.exists);
|
20
|
+
exports.readdirAsync = util_1.default.promisify(original_fs_1.readdir);
|
21
|
+
exports.rimrafAsync = util_1.default.promisify(rimraf_alt_1.default);
|
22
|
+
exports.execAsync = util_1.default.promisify(child_process_1.exec);
|
23
|
+
exports.isWin = process.platform === 'win32';
|
24
|
+
exports.isMac = process.platform === 'darwin';
|
25
|
+
const getMacOSAppPath = () => {
|
26
|
+
const sep = path_1.default.sep;
|
27
|
+
const execPath = process.execPath;
|
28
|
+
const contentPath = ['', 'Contents', 'MacOS'].join(sep);
|
29
|
+
return execPath.split(contentPath)[0];
|
30
|
+
};
|
31
|
+
exports.getMacOSAppPath = getMacOSAppPath;
|
32
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
33
|
+
exports.sleep = sleep;
|
34
|
+
const waitUntil = async (handle, options = { retryTime: 10, ms: 1000 }) => {
|
35
|
+
let retryTime = 0;
|
36
|
+
const p = async () => {
|
37
|
+
const isOk = handle();
|
38
|
+
if (!isOk) {
|
39
|
+
if (retryTime === options.retryTime) {
|
40
|
+
return false;
|
41
|
+
}
|
42
|
+
retryTime++;
|
43
|
+
await (0, exports.sleep)(options.ms);
|
44
|
+
return await p();
|
45
|
+
}
|
46
|
+
return true;
|
47
|
+
};
|
48
|
+
return await p();
|
49
|
+
};
|
50
|
+
exports.waitUntil = waitUntil;
|
51
|
+
const spawnAsync = (command, options) => {
|
52
|
+
let stdout = '';
|
53
|
+
let stderr = '';
|
54
|
+
const child = (0, child_process_1.spawn)(command, options);
|
55
|
+
child.stdout.on('data', (data) => {
|
56
|
+
stdout += data;
|
57
|
+
});
|
58
|
+
child.stderr.on('data', (data) => {
|
59
|
+
stderr += data;
|
60
|
+
});
|
61
|
+
return new Promise((resolve, reject) => {
|
62
|
+
child.on('error', reject);
|
63
|
+
child.on('close', (code) => {
|
64
|
+
if (code === 0) {
|
65
|
+
return resolve(stdout.toString());
|
66
|
+
}
|
67
|
+
const err = new Error(`child exited with code ${code}`);
|
68
|
+
err.code = code;
|
69
|
+
err.stderr = stderr.toString();
|
70
|
+
reject(err);
|
71
|
+
});
|
72
|
+
});
|
73
|
+
};
|
74
|
+
exports.spawnAsync = spawnAsync;
|
75
|
+
const cleanOldArchive = async (resourcePath) => {
|
76
|
+
const resourceArray = await (0, exports.readdirAsync)(resourcePath);
|
77
|
+
if (!resourceArray || !resourceArray.length) {
|
78
|
+
return;
|
79
|
+
}
|
80
|
+
const oldArchiveSource = resourceArray.filter((item) => item.startsWith(constants_1.OldArchivePrefix));
|
81
|
+
return await Promise.all(oldArchiveSource.map(async (file) => {
|
82
|
+
const filePath = path_1.default.join(resourcePath, file);
|
83
|
+
if (await (0, exports.existsAsync)(filePath)) {
|
84
|
+
await (0, exports.rimrafAsync)(filePath);
|
85
|
+
}
|
86
|
+
}));
|
87
|
+
};
|
88
|
+
exports.cleanOldArchive = cleanOldArchive;
|
89
|
+
const existFile = async (path) => {
|
90
|
+
const _existFile = await (0, exports.waitUntil)(() => (0, original_fs_1.existsSync)(path), {
|
91
|
+
ms: 1000,
|
92
|
+
retryTime: 30,
|
93
|
+
});
|
94
|
+
return _existFile;
|
95
|
+
};
|
96
|
+
exports.existFile = existFile;
|
97
|
+
const requestUpdateInfo = async (options) => {
|
98
|
+
const { url } = options;
|
99
|
+
if (!url) {
|
100
|
+
throw new Error('request url can\'t be empty');
|
101
|
+
}
|
102
|
+
let res = null;
|
103
|
+
try {
|
104
|
+
res = await urllib_1.default.request(url, {
|
105
|
+
dataType: 'json',
|
106
|
+
timeout: 10 * 1000,
|
107
|
+
});
|
108
|
+
}
|
109
|
+
catch (e) {
|
110
|
+
throw e;
|
111
|
+
}
|
112
|
+
if (!res || res.status !== 200) {
|
113
|
+
throw new Error(`request failure,status is ${res.status}`);
|
114
|
+
}
|
115
|
+
return res.data;
|
116
|
+
};
|
117
|
+
exports.requestUpdateInfo = requestUpdateInfo;
|
118
|
+
const getExecuteFile = (file) => {
|
119
|
+
return path_1.default.join(__dirname, '..', 'libs', file);
|
120
|
+
};
|
121
|
+
exports.getExecuteFile = getExecuteFile;
|
122
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1,151 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const os_1 = __importDefault(require("os"));
|
7
|
+
const path_1 = __importDefault(require("path"));
|
8
|
+
const _1 = require(".");
|
9
|
+
const index_1 = require("./index");
|
10
|
+
const _log = (logger, e) => {
|
11
|
+
const message = (e.stack || e).toString();
|
12
|
+
logger.error?.(message);
|
13
|
+
};
|
14
|
+
exports.default = async (updatorOptions, logger, availableUpdate, updateInfo, preCheck = false) => {
|
15
|
+
const { productName } = updatorOptions || {};
|
16
|
+
const { downloadTargetDir } = availableUpdate || {};
|
17
|
+
const appPath = (0, _1.getMacOSAppPath)();
|
18
|
+
const tmpPath = path_1.default.join(os_1.default.tmpdir(), String(new Date().getTime())); // 本地临时文件使用的目录
|
19
|
+
const volumesPath = path_1.default.join('/Volumes', updatorOptions.dmgTitleFormatter ? updatorOptions.dmgTitleFormatter(updatorOptions, updateInfo) : productName);
|
20
|
+
const volumesAppPath = path_1.default.join(volumesPath, `${productName}.app`);
|
21
|
+
// step 1: 检测是否支持 hdiutil;
|
22
|
+
try {
|
23
|
+
const res = (await (0, index_1.spawnAsync)('which', ['hdiutil']));
|
24
|
+
if (!res.includes('/bin/hdiutil')) {
|
25
|
+
throw new Error('hdiutil not found');
|
26
|
+
}
|
27
|
+
}
|
28
|
+
catch (error) {
|
29
|
+
if (preCheck) {
|
30
|
+
_log(logger, error);
|
31
|
+
}
|
32
|
+
return {
|
33
|
+
success: false,
|
34
|
+
error,
|
35
|
+
};
|
36
|
+
}
|
37
|
+
// step 2: eject 一次 volume 下的 app,兜底,避免上一次结束时执行失败
|
38
|
+
try {
|
39
|
+
await (0, index_1.spawnAsync)('hdiutil', ['eject', volumesPath]);
|
40
|
+
}
|
41
|
+
catch (e) {
|
42
|
+
// 如果前一次更新时 eject 成功,这里文件不存在会报错,是个正常的 case,不用处理上报
|
43
|
+
}
|
44
|
+
finally {
|
45
|
+
const volumeAppNotExist = await (0, _1.waitUntil)(() => !(0, index_1.existsSync)(volumesAppPath), {
|
46
|
+
ms: 300,
|
47
|
+
retryTime: 5,
|
48
|
+
});
|
49
|
+
if (!volumeAppNotExist) {
|
50
|
+
const error = new Error('volume not exists');
|
51
|
+
if (preCheck) {
|
52
|
+
_log(logger, error);
|
53
|
+
}
|
54
|
+
return {
|
55
|
+
success: false,
|
56
|
+
error,
|
57
|
+
};
|
58
|
+
}
|
59
|
+
}
|
60
|
+
// step 3: 执行 hdiutil attach,挂载 dmg
|
61
|
+
try {
|
62
|
+
await (0, index_1.spawnAsync)('hdiutil', ['attach', downloadTargetDir]);
|
63
|
+
}
|
64
|
+
catch (error) {
|
65
|
+
_log(logger, error);
|
66
|
+
}
|
67
|
+
finally {
|
68
|
+
// 判断有没有新的 dmg 文件,没有的话提示用户重新下载
|
69
|
+
const volumeAppExist = await (0, _1.waitUntil)(() => (0, index_1.existsSync)(volumesAppPath), {
|
70
|
+
ms: 300,
|
71
|
+
retryTime: 5,
|
72
|
+
});
|
73
|
+
if (!volumeAppExist) {
|
74
|
+
const error = new Error('attach fail');
|
75
|
+
if (preCheck) {
|
76
|
+
_log(logger, error);
|
77
|
+
}
|
78
|
+
return {
|
79
|
+
success: false,
|
80
|
+
error,
|
81
|
+
};
|
82
|
+
}
|
83
|
+
}
|
84
|
+
if (preCheck) {
|
85
|
+
// 如果是预检查,直接返回
|
86
|
+
try {
|
87
|
+
await (0, index_1.spawnAsync)('hdiutil', ['eject', volumesPath]);
|
88
|
+
}
|
89
|
+
catch (error) {
|
90
|
+
_log(logger, error);
|
91
|
+
}
|
92
|
+
return {
|
93
|
+
success: true,
|
94
|
+
};
|
95
|
+
}
|
96
|
+
// step 4: 将当前目录下的 app 移到临时目录,如果后续操作失败了兜底用
|
97
|
+
try {
|
98
|
+
await (0, index_1.spawnAsync)('mv', [appPath, tmpPath]);
|
99
|
+
}
|
100
|
+
catch (error) {
|
101
|
+
error.customMessage = 'step4 mv to tmp path error';
|
102
|
+
_log(logger, error);
|
103
|
+
}
|
104
|
+
finally {
|
105
|
+
// 看临时目录文件是否移动成功
|
106
|
+
const tmpPathExist = await (0, _1.waitUntil)(() => (0, index_1.existsSync)(tmpPath), {
|
107
|
+
ms: 300,
|
108
|
+
retryTime: 5,
|
109
|
+
});
|
110
|
+
if (!tmpPathExist) {
|
111
|
+
const error = new Error('cp to tmp path fail');
|
112
|
+
return {
|
113
|
+
success: false,
|
114
|
+
error,
|
115
|
+
};
|
116
|
+
}
|
117
|
+
}
|
118
|
+
// step 5: 将新的 app 文件移动到 Applications 目录下,如果失败 or 查不到移入文件,将临时目录下的文件移动回来
|
119
|
+
try {
|
120
|
+
await (0, index_1.spawnAsync)('cp', ['-R', volumesAppPath, appPath]);
|
121
|
+
}
|
122
|
+
catch (error) {
|
123
|
+
_log(logger, error);
|
124
|
+
}
|
125
|
+
finally {
|
126
|
+
const appExist = await (0, _1.waitUntil)(() => (0, index_1.existsSync)(appPath), {
|
127
|
+
ms: 300,
|
128
|
+
retryTime: 5,
|
129
|
+
});
|
130
|
+
// 查不到新移入的 dmg,将原 dmg 再移动回来
|
131
|
+
if (!appExist) {
|
132
|
+
const error = new Error('cp to app fail');
|
133
|
+
await (0, index_1.spawnAsync)('mv', [tmpPath, appPath]);
|
134
|
+
return {
|
135
|
+
success: false,
|
136
|
+
error,
|
137
|
+
};
|
138
|
+
}
|
139
|
+
}
|
140
|
+
// step 6: 执行 hdiutil eject,推出
|
141
|
+
try {
|
142
|
+
await (0, index_1.spawnAsync)('hdiutil', ['eject', volumesPath]);
|
143
|
+
}
|
144
|
+
catch (error) {
|
145
|
+
_log(logger, error);
|
146
|
+
}
|
147
|
+
return {
|
148
|
+
success: true,
|
149
|
+
};
|
150
|
+
};
|
151
|
+
//# sourceMappingURL=install-macos-dmg.js.map
|
@@ -0,0 +1,23 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.sudoPromptExec = void 0;
|
4
|
+
const index_1 = require("./index");
|
5
|
+
function sudoPromptExec(appUpdatorOptions, logger, shell) {
|
6
|
+
const options = {
|
7
|
+
name: appUpdatorOptions.productName,
|
8
|
+
};
|
9
|
+
return new Promise((resolve, reject) => {
|
10
|
+
logger.warn(`update#sudoPromptExec_shell_${shell}`);
|
11
|
+
index_1.sudoPrompt.exec(shell, options, (error, stdout, _) => {
|
12
|
+
if (error) {
|
13
|
+
reject(error);
|
14
|
+
logger.error(`update#sudoPromptExec_error_${error}`);
|
15
|
+
return;
|
16
|
+
}
|
17
|
+
resolve(stdout);
|
18
|
+
logger.warn(`update#sudoPromptExec_stdout_${stdout}`);
|
19
|
+
});
|
20
|
+
});
|
21
|
+
}
|
22
|
+
exports.sudoPromptExec = sudoPromptExec;
|
23
|
+
//# sourceMappingURL=sudo-prompt-exec.js.map
|
@@ -0,0 +1,87 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.WindowsUpdator = void 0;
|
7
|
+
const path_1 = __importDefault(require("path"));
|
8
|
+
const electron_1 = require("electron");
|
9
|
+
const constants_1 = require("./common/constants");
|
10
|
+
const sudo_prompt_exec_1 = require("./utils/sudo-prompt-exec");
|
11
|
+
const app_updator_1 = require("./app-updator");
|
12
|
+
const utils_1 = require("./utils");
|
13
|
+
class WindowsUpdator extends app_updator_1.AppUpdator {
|
14
|
+
doGetAvailableUpdateInfo(updateInfo) {
|
15
|
+
this.logger.info(`WindowsUpdator#doGetAvailableUpdateInfo:start`);
|
16
|
+
let resourcePath = path_1.default.resolve(this.app.userDataPath);
|
17
|
+
const latestAsarPath = path_1.default.resolve(resourcePath, 'latest.asar');
|
18
|
+
const latestAppPath = path_1.default.resolve(resourcePath, 'latest');
|
19
|
+
let downloadTargetDir = `${latestAsarPath}.zip`;
|
20
|
+
if (updateInfo.updateType === constants_1.UpdateType.Package) {
|
21
|
+
downloadTargetDir = `${latestAppPath}.exe`;
|
22
|
+
}
|
23
|
+
return {
|
24
|
+
resourcePath,
|
25
|
+
downloadTargetDir,
|
26
|
+
latestAsarPath,
|
27
|
+
};
|
28
|
+
}
|
29
|
+
async doPreCheckForPackage() {
|
30
|
+
this.logger.info(`WindowsUpdator#doPreCheckForPackage:start`);
|
31
|
+
// Windows 全量安装默认预检正常
|
32
|
+
return Promise.resolve({ success: true });
|
33
|
+
}
|
34
|
+
async doUnzip() {
|
35
|
+
this.logger.info(`WindowsUpdator#doUnzip:start`);
|
36
|
+
try {
|
37
|
+
const { downloadTargetDir, resourcePath } = this.availableUpdate;
|
38
|
+
const unzipExe = (0, utils_1.getExecuteFile)('unzip.exe');
|
39
|
+
const executeCommand = `"${unzipExe}" -o "${downloadTargetDir}" -d "${resourcePath}"`;
|
40
|
+
await (0, utils_1.execAsync)(executeCommand);
|
41
|
+
}
|
42
|
+
catch (error) {
|
43
|
+
return {
|
44
|
+
success: false,
|
45
|
+
error,
|
46
|
+
};
|
47
|
+
}
|
48
|
+
this.logger.info(`WindowsUpdator#doUnzip:success`);
|
49
|
+
return {
|
50
|
+
success: true,
|
51
|
+
};
|
52
|
+
}
|
53
|
+
async doQuitAndInstallPackage() {
|
54
|
+
this.logger.info(`WindowsUpdator#doQuitAndInstallPackage:success`);
|
55
|
+
const { downloadTargetDir } = this.availableUpdate;
|
56
|
+
try {
|
57
|
+
// Windows 全量安装
|
58
|
+
const shellOpen = electron_1.shell.openItem || electron_1.shell.openPath;
|
59
|
+
shellOpen(downloadTargetDir);
|
60
|
+
setTimeout(() => {
|
61
|
+
this.app.exit(0);
|
62
|
+
}, 30);
|
63
|
+
return Promise.resolve({ success: true });
|
64
|
+
}
|
65
|
+
catch (error) {
|
66
|
+
return Promise.resolve({ success: false, error });
|
67
|
+
}
|
68
|
+
}
|
69
|
+
async doQuitAndInstallAsar() {
|
70
|
+
this.logger.info(`WindowsUpdator#doQuitAndInstallAsar:start`);
|
71
|
+
const productName = this.options?.productName;
|
72
|
+
const { resourcePath } = this.availableUpdate;
|
73
|
+
const exePath = this.app.exePath;
|
74
|
+
const updateExePath = (0, utils_1.getExecuteFile)('installer.exe');
|
75
|
+
const targetPath = path_1.default.resolve(exePath, '..', 'resources');
|
76
|
+
const executeCommand = `"${updateExePath}" "${targetPath}" "${resourcePath}" "${productName}.exe" "${exePath}"`;
|
77
|
+
try {
|
78
|
+
await (0, sudo_prompt_exec_1.sudoPromptExec)(this.options, this.logger, executeCommand);
|
79
|
+
return Promise.resolve({ success: true });
|
80
|
+
}
|
81
|
+
catch (error) {
|
82
|
+
return Promise.resolve({ success: false, error });
|
83
|
+
}
|
84
|
+
}
|
85
|
+
}
|
86
|
+
exports.WindowsUpdator = WindowsUpdator;
|
87
|
+
//# sourceMappingURL=windows-updator.js.map
|
package/package.json
CHANGED
@@ -1,34 +1,65 @@
|
|
1
1
|
{
|
2
2
|
"name": "electron-updator",
|
3
|
-
"version": "0.1.
|
4
|
-
"description": "electron-updator",
|
5
|
-
"
|
6
|
-
|
7
|
-
"
|
3
|
+
"version": "0.1.3",
|
4
|
+
"description": "electron-updator is a software updator management solution for Electron applications, It is convenient to complete full software update and dynamic update.",
|
5
|
+
"scripts": {
|
6
|
+
"build": "sh ./build.sh",
|
7
|
+
"test": "egg-bin test test/**/index.test.ts",
|
8
|
+
"lint": "eslint --fix --quiet --ext .js,.jsx ./src",
|
9
|
+
"prepublishOnly": "npm run build",
|
10
|
+
"contributor": "git-contributor",
|
11
|
+
"dev": "ttsc -p tsconfig.json -watch"
|
8
12
|
},
|
13
|
+
"main": "./build",
|
14
|
+
"keywords": [
|
15
|
+
"electron",
|
16
|
+
"updator",
|
17
|
+
"auto-updator"
|
18
|
+
],
|
9
19
|
"files": [
|
10
|
-
"
|
11
|
-
"
|
20
|
+
"build/**/*.js",
|
21
|
+
"build/**/*.exe"
|
12
22
|
],
|
13
|
-
"main": "index.js",
|
14
23
|
"repository": {
|
15
24
|
"type": "git",
|
16
|
-
"url": "
|
25
|
+
"url": "https://github.com/electron-modules/electron-updator"
|
17
26
|
},
|
18
27
|
"dependencies": {
|
28
|
+
"eventemitter3": "^4.0.0",
|
29
|
+
"lodash": "4.17.21",
|
30
|
+
"moment": "2.29.4",
|
31
|
+
"rimraf-alt": "*",
|
32
|
+
"sudo-prompt-alt": "9",
|
33
|
+
"urllib": "2.34.1"
|
19
34
|
},
|
20
35
|
"devDependencies": {
|
21
|
-
"
|
22
|
-
"
|
23
|
-
"
|
24
|
-
"
|
25
|
-
"
|
26
|
-
"
|
27
|
-
|
28
|
-
|
29
|
-
"
|
30
|
-
"
|
31
|
-
"
|
36
|
+
"@applint/spec": "^1.2.0",
|
37
|
+
"@types/lodash": "^4.14.181",
|
38
|
+
"@types/mocha": "^10.0.1",
|
39
|
+
"@types/mock-require": "^2.0.1",
|
40
|
+
"@types/react-dom": "^17.0.16",
|
41
|
+
"@typescript-eslint/parser": "^5.19.0",
|
42
|
+
"babel-plugin-module-resolver": "^4.1.0",
|
43
|
+
"concurrently": "^5.3.0",
|
44
|
+
"copyfiles": "^2.4.1",
|
45
|
+
"cross-env": "^7.0.3",
|
46
|
+
"detect-port": "1",
|
47
|
+
"egg-bin": "^5.9.0",
|
48
|
+
"electron": "18",
|
49
|
+
"electron-windows": "18",
|
50
|
+
"eslint": "^7.32.0",
|
51
|
+
"git-contributor": "*",
|
52
|
+
"husky": "^7.0.4",
|
53
|
+
"mm": "^3.0.2",
|
54
|
+
"mock-require": "^3.0.3",
|
55
|
+
"prettier": "^2.6.2",
|
56
|
+
"prop-types": "^15.7.2",
|
57
|
+
"style-loader": "^1.1.2",
|
58
|
+
"ts-loader": "^9.2.8",
|
59
|
+
"ts-node": "^10.7.0",
|
60
|
+
"ttypescript": "^1.5.15",
|
61
|
+
"typescript": "^4.6.3",
|
62
|
+
"typescript-transform-paths": "^3.3.1"
|
32
63
|
},
|
33
64
|
"husky": {
|
34
65
|
"hooks": {
|
package/bin/electron-updator.js
DELETED
package/index.js
DELETED
package/lib/electron-updator.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
'use strict';
|