Skip to content

Commit b0bb3af

Browse files
authored
Handle macOS app rename during app updates (#4491)
1 parent 46ed582 commit b0bb3af

File tree

15 files changed

+760
-16
lines changed

15 files changed

+760
-16
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/desktop/src/sidebar/update.tsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { type UnlistenFn } from "@tauri-apps/api/event";
22
import { message } from "@tauri-apps/plugin-dialog";
3-
import { relaunch } from "@tauri-apps/plugin-process";
43
import { useCallback, useEffect, useState } from "react";
54

65
import { commands, events } from "@hypr/plugin-updater2";
@@ -14,11 +13,18 @@ export function Update() {
1413
if (!version) {
1514
return;
1615
}
17-
const result = await commands.install(version);
18-
if (result.status === "ok") {
19-
await relaunch();
20-
} else {
21-
await message(`Failed to install update: ${result.error}`, {
16+
const installResult = await commands.install(version);
17+
if (installResult.status !== "ok") {
18+
await message(`Failed to install update: ${installResult.error}`, {
19+
title: "Update Failed",
20+
kind: "error",
21+
});
22+
return;
23+
}
24+
25+
const postInstallResult = await commands.postinstall(installResult.data);
26+
if (postInstallResult.status !== "ok") {
27+
await message(`Failed to apply update: ${postInstallResult.error}`, {
2228
title: "Update Failed",
2329
kind: "error",
2430
});

plugins/tray/src/menu_items/tray_check_update.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,14 @@ impl MenuItemHandler for TrayCheckUpdate {
107107
let app = app.clone();
108108
tauri::async_runtime::spawn(async move {
109109
match app.updater2().install(&version).await {
110-
Ok(()) => app.restart(),
110+
Ok(result) => {
111+
if let Err(e) = app.updater2().postinstall(result).await {
112+
app.dialog()
113+
.message(format!("Failed to apply update: {}", e))
114+
.title("Update Failed")
115+
.show(|_| {});
116+
}
117+
}
111118
Err(e) => {
112119
app.dialog()
113120
.message(format!("Failed to install update: {}", e))

plugins/updater2/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ tokio = { workspace = true, features = ["macros", "time"] }
2222
tauri = { workspace = true, features = ["test"] }
2323
tauri-specta = { workspace = true, features = ["derive", "typescript"] }
2424

25+
flate2 = "1"
2526
serde = { workspace = true }
2627
specta = { workspace = true }
2728
strum = { workspace = true, features = ["derive"] }
29+
tar = "0.4"
30+
tempfile = { workspace = true }
2831

2932
thiserror = { workspace = true }
3033
tracing = { workspace = true }

plugins/updater2/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const COMMANDS: &[&str] = &["check", "download", "install"];
1+
const COMMANDS: &[&str] = &["check", "download", "install", "postinstall"];
22

33
fn main() {
44
tauri_plugin::Builder::new(COMMANDS).build();

plugins/updater2/js/bindings.gen.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,22 @@ async download(version: string) : Promise<Result<null, string>> {
2222
else return { status: "error", error: e as any };
2323
}
2424
},
25-
async install(version: string) : Promise<Result<null, string>> {
25+
async install(version: string) : Promise<Result<InstallResult, string>> {
2626
try {
2727
return { status: "ok", data: await TAURI_INVOKE("plugin:updater2|install", { version }) };
2828
} catch (e) {
2929
if(e instanceof Error) throw e;
3030
else return { status: "error", error: e as any };
3131
}
3232
},
33+
async postinstall(result: InstallResult) : Promise<Result<null, string>> {
34+
try {
35+
return { status: "ok", data: await TAURI_INVOKE("plugin:updater2|postinstall", { result }) };
36+
} catch (e) {
37+
if(e instanceof Error) throw e;
38+
else return { status: "error", error: e as any };
39+
}
40+
},
3341
async maybeEmitUpdated() : Promise<void> {
3442
await TAURI_INVOKE("plugin:updater2|maybe_emit_updated");
3543
}
@@ -39,10 +47,12 @@ async maybeEmitUpdated() : Promise<void> {
3947

4048

4149
export const events = __makeEvents__<{
50+
updateDownloadFailedEvent: UpdateDownloadFailedEvent,
4251
updateDownloadingEvent: UpdateDownloadingEvent,
4352
updateReadyEvent: UpdateReadyEvent,
4453
updatedEvent: UpdatedEvent
4554
}>({
55+
updateDownloadFailedEvent: "plugin:updater2:update-download-failed-event",
4656
updateDownloadingEvent: "plugin:updater2:update-downloading-event",
4757
updateReadyEvent: "plugin:updater2:update-ready-event",
4858
updatedEvent: "plugin:updater2:updated-event"
@@ -54,6 +64,8 @@ updatedEvent: "plugin:updater2:updated-event"
5464

5565
/** user-defined types **/
5666

67+
export type InstallResult = { kind: "relaunch_current" } | { kind: "macos_bundle_update"; current_path: string; staged_path: string; target_path: string; backup_path: string; stage_dir: string }
68+
export type UpdateDownloadFailedEvent = { version: string }
5769
export type UpdateDownloadingEvent = { version: string }
5870
export type UpdateReadyEvent = { version: string }
5971
export type UpdatedEvent = { previous: string | null; current: string }
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Automatically generated - DO NOT EDIT!
2+
3+
"$schema" = "../../schemas/schema.json"
4+
5+
[[permission]]
6+
identifier = "allow-postinstall"
7+
description = "Enables the postinstall command without any pre-configured scope."
8+
commands.allow = ["postinstall"]
9+
10+
[[permission]]
11+
identifier = "deny-postinstall"
12+
description = "Denies the postinstall command without any pre-configured scope."
13+
commands.deny = ["postinstall"]

plugins/updater2/permissions/autogenerated/reference.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Default permissions for the plugin
77
- `allow-check`
88
- `allow-download`
99
- `allow-install`
10+
- `allow-postinstall`
1011
- `allow-maybe-emit-updated`
1112

1213
## Permission Table
@@ -119,6 +120,32 @@ Enables the maybe_emit_updated command without any pre-configured scope.
119120

120121
Denies the maybe_emit_updated command without any pre-configured scope.
121122

123+
</td>
124+
</tr>
125+
126+
<tr>
127+
<td>
128+
129+
`updater2:allow-postinstall`
130+
131+
</td>
132+
<td>
133+
134+
Enables the postinstall command without any pre-configured scope.
135+
136+
</td>
137+
</tr>
138+
139+
<tr>
140+
<td>
141+
142+
`updater2:deny-postinstall`
143+
144+
</td>
145+
<td>
146+
147+
Denies the postinstall command without any pre-configured scope.
148+
122149
</td>
123150
</tr>
124151
</table>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[default]
22
description = "Default permissions for the plugin"
3-
permissions = ["allow-check", "allow-download", "allow-install", "allow-maybe-emit-updated"]
3+
permissions = ["allow-check", "allow-download", "allow-install", "allow-postinstall", "allow-maybe-emit-updated"]

plugins/updater2/permissions/schemas/schema.json

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,22 @@
343343
"markdownDescription": "Denies the maybe_emit_updated command without any pre-configured scope."
344344
},
345345
{
346-
"description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-check`\n- `allow-download`\n- `allow-install`\n- `allow-maybe-emit-updated`",
346+
"description": "Enables the postinstall command without any pre-configured scope.",
347+
"type": "string",
348+
"const": "allow-postinstall",
349+
"markdownDescription": "Enables the postinstall command without any pre-configured scope."
350+
},
351+
{
352+
"description": "Denies the postinstall command without any pre-configured scope.",
353+
"type": "string",
354+
"const": "deny-postinstall",
355+
"markdownDescription": "Denies the postinstall command without any pre-configured scope."
356+
},
357+
{
358+
"description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-check`\n- `allow-download`\n- `allow-install`\n- `allow-postinstall`\n- `allow-maybe-emit-updated`",
347359
"type": "string",
348360
"const": "default",
349-
"markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-check`\n- `allow-download`\n- `allow-install`\n- `allow-maybe-emit-updated`"
361+
"markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-check`\n- `allow-download`\n- `allow-install`\n- `allow-postinstall`\n- `allow-maybe-emit-updated`"
350362
}
351363
]
352364
}

0 commit comments

Comments
 (0)