mirror of
https://github.com/priyanshujain/margin-calendar.git
synced 2026-10-02 11:07:04 +00:00
announce updates rather than install them when a package manager owns the binary
This commit is contained in:
1 parent
ae5a7b4c0e
commit
958931f5ef
4 files changed
+79
-1
No files matched your search
+12
-1
@@ -233,6 +233,16 @@ fn show_main_window(app: &tauri::AppHandle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The package manager that owns this install, when one does. The Nix wrapper sets it to "nix":
|
||||||
|
/// the binary lives in a read-only store there, so the updater may announce a version but not
|
||||||
|
/// install it.
|
||||||
|
#[tauri::command]
|
||||||
|
fn packaged_by() -> Option<String> {
|
||||||
|
std::env::var("MARGIN_CALENDAR_PACKAGED_BY")
|
||||||
|
.ok()
|
||||||
|
.filter(|manager| !manager.is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
// generate_context! first, so the updater plugin registers only when the merged config
|
// generate_context! first, so the updater plugin registers only when the merged config
|
||||||
@@ -323,7 +333,8 @@ pub fn run() {
|
|||||||
sync::event_delete,
|
sync::event_delete,
|
||||||
sync::sync_now,
|
sync::sync_now,
|
||||||
sync::sync_status,
|
sync::sync_status,
|
||||||
sync::sync_flush
|
sync::sync_flush,
|
||||||
|
packaged_by
|
||||||
])
|
])
|
||||||
.build(context)
|
.build(context)
|
||||||
.expect("error while building Margin Calendar");
|
.expect("error while building Margin Calendar");
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { call } from "../ipc";
|
||||||
|
|
||||||
|
/** The package manager that owns this install, or null when the app updates itself. */
|
||||||
|
export const packagedBy = () => call<string | null>("packaged_by");
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// The one path where the updater must stand down: a package manager owns the binary, so a newer
|
||||||
|
// version is announced and never installed over it.
|
||||||
|
|
||||||
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const mocks = vi.hoisted(() => ({
|
||||||
|
check: vi.fn(),
|
||||||
|
relaunch: vi.fn(),
|
||||||
|
notify: vi.fn(),
|
||||||
|
call: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@tauri-apps/plugin-updater", () => ({ check: mocks.check }));
|
||||||
|
vi.mock("@tauri-apps/plugin-process", () => ({ relaunch: mocks.relaunch }));
|
||||||
|
vi.mock("../store/useToast", () => ({ notify: mocks.notify }));
|
||||||
|
vi.mock("../ipc", () => ({ isDesktop: true, call: mocks.call }));
|
||||||
|
|
||||||
|
import { checkForUpdates } from "./updates";
|
||||||
|
|
||||||
|
const downloadAndInstall = vi.fn();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
mocks.check.mockResolvedValue({ version: "0.0.5", downloadAndInstall });
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("checkForUpdates", () => {
|
||||||
|
it("installs and relaunches when the app owns its own binary", async () => {
|
||||||
|
mocks.call.mockResolvedValue(null);
|
||||||
|
await checkForUpdates();
|
||||||
|
expect(downloadAndInstall).toHaveBeenCalled();
|
||||||
|
expect(mocks.relaunch).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("points at the package manager instead of installing over it", async () => {
|
||||||
|
mocks.call.mockResolvedValue("nix");
|
||||||
|
await checkForUpdates();
|
||||||
|
expect(downloadAndInstall).not.toHaveBeenCalled();
|
||||||
|
expect(mocks.relaunch).not.toHaveBeenCalled();
|
||||||
|
expect(mocks.notify).toHaveBeenCalledWith(
|
||||||
|
"0.0.5 is out. Update with: nix profile upgrade margin-calendar",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not ask who owns the install when there is nothing newer", async () => {
|
||||||
|
mocks.check.mockResolvedValue(null);
|
||||||
|
await checkForUpdates();
|
||||||
|
expect(mocks.call).not.toHaveBeenCalled();
|
||||||
|
expect(mocks.notify).toHaveBeenCalledWith("Margin Calendar is up to date");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -4,11 +4,18 @@
|
|||||||
|
|
||||||
import { relaunch } from "@tauri-apps/plugin-process";
|
import { relaunch } from "@tauri-apps/plugin-process";
|
||||||
import { check } from "@tauri-apps/plugin-updater";
|
import { check } from "@tauri-apps/plugin-updater";
|
||||||
|
import { packagedBy } from "../api/updates";
|
||||||
import { isDesktop } from "../ipc";
|
import { isDesktop } from "../ipc";
|
||||||
import { notify } from "../store/useToast";
|
import { notify } from "../store/useToast";
|
||||||
|
|
||||||
let running = false;
|
let running = false;
|
||||||
|
|
||||||
|
/** A package manager owns the binary, so the update is announced and left to it. */
|
||||||
|
function updateHint(manager: string, version: string): string {
|
||||||
|
if (manager === "nix") return `${version} is out. Update with: nix profile upgrade margin-calendar`;
|
||||||
|
return `${version} is out. Update it through ${manager}`;
|
||||||
|
}
|
||||||
|
|
||||||
export async function checkForUpdates(): Promise<void> {
|
export async function checkForUpdates(): Promise<void> {
|
||||||
if (!isDesktop || running) return;
|
if (!isDesktop || running) return;
|
||||||
running = true;
|
running = true;
|
||||||
@@ -18,6 +25,11 @@ export async function checkForUpdates(): Promise<void> {
|
|||||||
notify("Margin Calendar is up to date");
|
notify("Margin Calendar is up to date");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const manager = await packagedBy();
|
||||||
|
if (manager) {
|
||||||
|
notify(updateHint(manager, update.version));
|
||||||
|
return;
|
||||||
|
}
|
||||||
notify(`Installing ${update.version}…`);
|
notify(`Installing ${update.version}…`);
|
||||||
await update.downloadAndInstall();
|
await update.downloadAndInstall();
|
||||||
await relaunch();
|
await relaunch();
|
||||||
|
|||||||
Reference in new issue
Block a user