diff --git a/.changeset/yellow-snakes-sneeze.md b/.changeset/yellow-snakes-sneeze.md new file mode 100644 index 00000000000..806bc96bfab --- /dev/null +++ b/.changeset/yellow-snakes-sneeze.md @@ -0,0 +1,6 @@ +--- +"app-builder-lib": minor +"electron-updater": minor +--- + +feat: Implement autoupdates for pacman diff --git a/packages/app-builder-lib/src/targets/FpmTarget.ts b/packages/app-builder-lib/src/targets/FpmTarget.ts index c9efaa00e80..46baf32e8c6 100644 --- a/packages/app-builder-lib/src/targets/FpmTarget.ts +++ b/packages/app-builder-lib/src/targets/FpmTarget.ts @@ -278,7 +278,7 @@ export default class FpmTarget extends Target { } private supportsAutoUpdate(target: string) { - return ["deb", "rpm"].includes(target) + return ["deb", "rpm", "pacman"].includes(target) } } diff --git a/packages/electron-updater/src/AppImageUpdater.ts b/packages/electron-updater/src/AppImageUpdater.ts index a8cc747e79a..a498ac13bee 100644 --- a/packages/electron-updater/src/AppImageUpdater.ts +++ b/packages/electron-updater/src/AppImageUpdater.ts @@ -30,7 +30,7 @@ export class AppImageUpdater extends BaseUpdater { /*** @private */ protected doDownloadUpdate(downloadUpdateOptions: DownloadUpdateOptions): Promise> { const provider = downloadUpdateOptions.updateInfoAndProvider.provider - const fileInfo = findFile(provider.resolveFiles(downloadUpdateOptions.updateInfoAndProvider.info), "AppImage", ["rpm", "deb"])! + const fileInfo = findFile(provider.resolveFiles(downloadUpdateOptions.updateInfoAndProvider.info), "AppImage", ["rpm", "deb", "pacman"])! return this.executeDownload({ fileExtension: "AppImage", fileInfo, diff --git a/packages/electron-updater/src/DebUpdater.ts b/packages/electron-updater/src/DebUpdater.ts index 19705a72ea2..52e618dae87 100644 --- a/packages/electron-updater/src/DebUpdater.ts +++ b/packages/electron-updater/src/DebUpdater.ts @@ -13,7 +13,7 @@ export class DebUpdater extends BaseUpdater { /*** @private */ protected doDownloadUpdate(downloadUpdateOptions: DownloadUpdateOptions): Promise> { const provider = downloadUpdateOptions.updateInfoAndProvider.provider - const fileInfo = findFile(provider.resolveFiles(downloadUpdateOptions.updateInfoAndProvider.info), "deb", ["AppImage", "rpm"])! + const fileInfo = findFile(provider.resolveFiles(downloadUpdateOptions.updateInfoAndProvider.info), "deb", ["AppImage", "rpm", "pacman"])! return this.executeDownload({ fileExtension: "deb", fileInfo, diff --git a/packages/electron-updater/src/PacmanUpdater.ts b/packages/electron-updater/src/PacmanUpdater.ts new file mode 100644 index 00000000000..61c9b9e8406 --- /dev/null +++ b/packages/electron-updater/src/PacmanUpdater.ts @@ -0,0 +1,41 @@ +import { AllPublishOptions } from "builder-util-runtime" +import { AppAdapter } from "./AppAdapter" +import { DownloadUpdateOptions } from "./AppUpdater" +import { BaseUpdater, InstallOptions } from "./BaseUpdater" +import { DOWNLOAD_PROGRESS } from "./main" +import { findFile } from "./providers/Provider" + +export class PacmanUpdater extends BaseUpdater { + constructor(options?: AllPublishOptions | null, app?: AppAdapter) { + super(options, app) + } + + /*** @private */ + protected doDownloadUpdate(downloadUpdateOptions: DownloadUpdateOptions): Promise> { + const provider = downloadUpdateOptions.updateInfoAndProvider.provider + const fileInfo = findFile(provider.resolveFiles(downloadUpdateOptions.updateInfoAndProvider.info), "pacman", ["AppImage", "deb", "rpm"])! + return this.executeDownload({ + fileExtension: "pacman", + fileInfo, + downloadUpdateOptions, + task: async (updateFile, downloadOptions) => { + if (this.listenerCount(DOWNLOAD_PROGRESS) > 0) { + downloadOptions.onProgress = it => this.emit(DOWNLOAD_PROGRESS, it) + } + await this.httpExecutor.download(fileInfo.url, updateFile, downloadOptions) + }, + }) + } + + protected doInstall(options: InstallOptions): boolean { + const sudo = this.wrapSudo() + // pkexec doesn't want the command to be wrapped in " quotes + const wrapper = /pkexec/i.test(sudo) ? "" : `"` + const cmd = ["pacman", "-U", "--noconfirm", options.installerPath] + this.spawnSyncLog(sudo, [`${wrapper}/bin/bash`, "-c", `'${cmd.join(" ")}'${wrapper}`]) + if (options.isForceRunAfter) { + this.app.relaunch() + } + return true + } +} diff --git a/packages/electron-updater/src/RpmUpdater.ts b/packages/electron-updater/src/RpmUpdater.ts index 201170ad783..035a92c25cd 100644 --- a/packages/electron-updater/src/RpmUpdater.ts +++ b/packages/electron-updater/src/RpmUpdater.ts @@ -13,7 +13,7 @@ export class RpmUpdater extends BaseUpdater { /*** @private */ protected doDownloadUpdate(downloadUpdateOptions: DownloadUpdateOptions): Promise> { const provider = downloadUpdateOptions.updateInfoAndProvider.provider - const fileInfo = findFile(provider.resolveFiles(downloadUpdateOptions.updateInfoAndProvider.info), "rpm", ["AppImage", "deb"])! + const fileInfo = findFile(provider.resolveFiles(downloadUpdateOptions.updateInfoAndProvider.info), "rpm", ["AppImage", "deb", "pacman"])! return this.executeDownload({ fileExtension: "rpm", fileInfo, diff --git a/packages/electron-updater/src/main.ts b/packages/electron-updater/src/main.ts index 33f03bf5576..ae7055d0e97 100644 --- a/packages/electron-updater/src/main.ts +++ b/packages/electron-updater/src/main.ts @@ -12,6 +12,7 @@ export { CancellationToken, PackageFileInfo, ProgressInfo, UpdateFileInfo, Updat export { Provider } from "./providers/Provider" export { AppImageUpdater } from "./AppImageUpdater" export { DebUpdater } from "./DebUpdater" +export { PacmanUpdater } from "./PacmanUpdater" export { RpmUpdater } from "./RpmUpdater" export { MacUpdater } from "./MacUpdater" export { NsisUpdater } from "./NsisUpdater" @@ -45,6 +46,9 @@ function doLoadAutoUpdater(): AppUpdater { case "rpm": _autoUpdater = new (require("./RpmUpdater").RpmUpdater)() break + case "pacman": + _autoUpdater = new (require("./PacmanUpdater").PacmanUpdater)() + break default: break } diff --git a/pages/auto-update.md b/pages/auto-update.md index 5500fc45343..c706df9a75c 100644 --- a/pages/auto-update.md +++ b/pages/auto-update.md @@ -14,7 +14,7 @@ Read the remainder of this guide to configure everything. ## Auto-updatable Targets * macOS: DMG. -* Linux: AppImage, DEB and RPM. +* Linux: AppImage, DEB, Pacman (beta) and RPM. * Windows: NSIS. All these targets are default, custom configuration is not required. (Though it is possible to [pass in additional configuration, e.g. request headers](#custom-options-instantiating-updater-directly).) @@ -213,4 +213,4 @@ Emitted on progress. ## UpdateInfo -{!./electron-updater.Interface.UpdateInfo.md!} \ No newline at end of file +{!./electron-updater.Interface.UpdateInfo.md!} diff --git a/pages/programmatic-usage.md b/pages/programmatic-usage.md index 6db93c98cca..8a0a11b20ab 100644 --- a/pages/programmatic-usage.md +++ b/pages/programmatic-usage.md @@ -104,7 +104,7 @@ const options = { Encoding: "UTF-8", MimeType: "x-scheme-handler/deeplink" }, - target: ["AppImage", "rpm", "deb"] + target: ["AppImage", "rpm", "deb", "pacman"] }, deb: { priority: "optional", diff --git a/test/snapshots/updater/linuxUpdaterTest.js.snap b/test/snapshots/updater/linuxUpdaterTest.js.snap index 20d914bae6d..c049878205e 100644 --- a/test/snapshots/updater/linuxUpdaterTest.js.snap +++ b/test/snapshots/updater/linuxUpdaterTest.js.snap @@ -43,6 +43,49 @@ Array [ ] `; +exports[`test pacman download 1`] = ` +Object { + "files": Array [ + Object { + "blockMapSize": 82581, + "sha512": "u6MIxgkAyGQJNoQh/xZaVN2quQ7+So3t5RXnA2RspDuF0PiMk4q3xE5DhjnTdYCUpFANykEyt/QfmSriGoRamw==", + "size": 79016577, + "url": "electron-quick-start-typescript-1.0.4-x86_64.AppImage", + }, + Object { + "sha512": "TUEgrKUlS8RGFW86GlN8YZpuAK5TL0pbVDERmAvv5dPOHXI9VbvrlDEEwCzn0NYrvajVQW03jz64Ik5mhRSCvg==", + "size": 56079686, + "url": "electron-quick-start-typescript-1.0.4-amd64.deb", + }, + Object { + "sha512": "RRTErNJKHJX+tfxSzE0EItjPgd+Oh7t4okaaRS4EveokyQp1fZgheLmPuxOft4ptKqjZCvFW+m200rvJRuYcWg==", + "size": 56055361, + "url": "electron-quick-start-typescript-1.0.4-x86_64.rpm", + }, + Object { + "sha512": "2mUqhYKCSlAw1aWUNz2707tsqcp2/xSAsVrUVZtKZyfZEzGus63L/A5sW963i1jfuzrWk0HfdyUqYNFNS2HSWA==", + "size": 56075488, + "url": "electron-quick-start-typescript-1.0.4-x64.pacman", + }, + ], + "path": "electron-quick-start-typescript-1.0.4-x86_64.AppImage", + "releaseDate": "2024-09-08T16:57:10.775Z", + "releaseName": "1.0.4", + "releaseNotes": "

pacman autoupdate release added

", + "sha512": "u6MIxgkAyGQJNoQh/xZaVN2quQ7+So3t5RXnA2RspDuF0PiMk4q3xE5DhjnTdYCUpFANykEyt/QfmSriGoRamw==", + "tag": "v1.0.4", + "version": "1.0.4", +} +`; + +exports[`test pacman download 2`] = ` +Array [ + "checking-for-update", + "update-available", + "update-downloaded", +] +`; + exports[`test rpm download 1`] = ` Object { "files": Array [ diff --git a/test/src/ExtraBuildResourcesTest.ts b/test/src/ExtraBuildResourcesTest.ts index 619790d701f..acf5be8abbb 100644 --- a/test/src/ExtraBuildResourcesTest.ts +++ b/test/src/ExtraBuildResourcesTest.ts @@ -119,7 +119,7 @@ test.ifAll.ifNotWindows( publish: null, // https://github.com/electron-userland/electron-builder/issues/1355 linux: { - target: ["AppImage", "deb", "rpm"], + target: ["AppImage", "deb", "rpm", "pacman"], }, compression: "store", }, diff --git a/test/src/updater/linuxUpdaterTest.ts b/test/src/updater/linuxUpdaterTest.ts index 86611bc28de..5736415dbb0 100644 --- a/test/src/updater/linuxUpdaterTest.ts +++ b/test/src/updater/linuxUpdaterTest.ts @@ -1,9 +1,9 @@ import { GithubOptions } from "builder-util-runtime" -import { DebUpdater, RpmUpdater } from "electron-updater" +import { DebUpdater, RpmUpdater, PacmanUpdater } from "electron-updater" import { assertThat } from "../helpers/fileAssert" import { createTestAppAdapter, tuneTestUpdater, validateDownload, writeUpdateConfig } from "../helpers/updaterTestUtil" -const runTest = async (updaterClass: any, expectedExtension: "deb" | "rpm" | "AppImage") => { +const runTest = async (updaterClass: any, expectedExtension: "deb" | "rpm" | "AppImage" | "pacman") => { const testAppAdapter = await createTestAppAdapter("1.0.1") const updater = new updaterClass(null, testAppAdapter) tuneTestUpdater(updater, { platform: "linux" }) @@ -29,6 +29,10 @@ test("test rpm download", async () => { await runTest(RpmUpdater, "rpm") }) +test("test pacman download", async () => { + await runTest(PacmanUpdater, "pacman") +}) + test("test deb download", async () => { await runTest(DebUpdater, "deb") })