diff --git a/.changeset/olive-impalas-nail.md b/.changeset/olive-impalas-nail.md new file mode 100644 index 000000000..27ecf98f1 --- /dev/null +++ b/.changeset/olive-impalas-nail.md @@ -0,0 +1,5 @@ +--- +"hunkdiff": patch +--- + +Support pacman/AUR installs via `HUNK_INSTALL_SOURCE=pacman`. diff --git a/src/core/install/installSource.test.ts b/src/core/install/installSource.test.ts index b5f30f99f..7ec220aeb 100644 --- a/src/core/install/installSource.test.ts +++ b/src/core/install/installSource.test.ts @@ -121,6 +121,17 @@ describe("install source detection", () => { ).toBe("curl"); }); + test("accepts pacman as declared install source", () => { + expect( + detectInstallSource({ + env: { HUNK_INSTALL_SOURCE: "pacman" }, + executablePath: join("/", "usr", "lib", "hunkdiff", "hunk"), + version: "1.2.3", + homeDir: HOME_DIR, + }), + ).toBe("pacman"); + }); + test("keeps npm for a .hunk segment that is not followed by bin", () => { expect( detectInstallSource({ diff --git a/src/core/install/installSource.ts b/src/core/install/installSource.ts index 2ed3237fb..72a5a5dc9 100644 --- a/src/core/install/installSource.ts +++ b/src/core/install/installSource.ts @@ -17,12 +17,20 @@ const INSTALL_DIR_ENV = "HUNK_INSTALL_DIR"; /** Path segments Homebrew always puts above its binaries, on macOS and Linux alike. */ const HOMEBREW_PATH_SEGMENTS = ["cellar", "homebrew", "linuxbrew"]; -export type InstallSource = "npm" | "homebrew" | "nix" | "mise" | "curl" | "dev"; +export type InstallSource = "npm" | "homebrew" | "nix" | "mise" | "pacman" | "curl" | "dev"; /** Package-manager clients that can install the global `hunkdiff` npm package. */ export type NpmClient = "npm" | "bun" | "pnpm"; -const INSTALL_SOURCES: readonly InstallSource[] = ["npm", "homebrew", "nix", "mise", "curl", "dev"]; +const INSTALL_SOURCES: readonly InstallSource[] = [ + "npm", + "homebrew", + "nix", + "mise", + "pacman", + "curl", + "dev", +]; export interface InstallSourceFacts { env?: NodeJS.ProcessEnv; diff --git a/src/core/install/latestRelease.ts b/src/core/install/latestRelease.ts index 74d93a09a..cd809b45a 100644 --- a/src/core/install/latestRelease.ts +++ b/src/core/install/latestRelease.ts @@ -158,6 +158,6 @@ export async function fetchChannelVersions( return fetchNpmChannelVersions(deps); } - // Nix, mise, and source builds install from somewhere Hunk cannot query or act on. + // Nix, mise, pacman and source builds install from somewhere Hunk cannot query or act on. return {}; } diff --git a/src/core/install/selfUpdate.test.ts b/src/core/install/selfUpdate.test.ts index a2dfc9ee5..c0ac160e2 100644 --- a/src/core/install/selfUpdate.test.ts +++ b/src/core/install/selfUpdate.test.ts @@ -341,6 +341,14 @@ describe("hunk update", () => { expect(result.stdout).toContain("Run `mise up hunk` to update it."); }); + test("points pacman installs at pacman or an AUR helper", async () => { + const result = await runUpdate({ installSource: "pacman" }); + + expect(result.exitCode).toBe(1); + expect(result.commands).toEqual([]); + expect(result.stdout).toContain("Update it through pacman or your AUR helper."); + }); + test("points source builds at install:bin", async () => { const result = await runUpdate({ installSource: "dev", installedVersion: "0.0.0-unknown" }); diff --git a/src/core/install/selfUpdate.ts b/src/core/install/selfUpdate.ts index 79ea4ef7c..429a14b67 100644 --- a/src/core/install/selfUpdate.ts +++ b/src/core/install/selfUpdate.ts @@ -239,6 +239,10 @@ function unmanagedInstallGuidance(installSource: InstallSource) { return ["Hunk was installed with mise.", "Run `mise up hunk` to update it."]; } + if (installSource === "pacman") { + return ["Hunk was installed with pacman.", "Update it through pacman or your AUR helper."]; + } + return [ "Hunk is running from a local source build.", "Run `bun run install:bin` in your Hunk checkout to update it.", diff --git a/src/core/process/updateNotice.test.ts b/src/core/process/updateNotice.test.ts index 5e168c1ac..153fec81f 100644 --- a/src/core/process/updateNotice.test.ts +++ b/src/core/process/updateNotice.test.ts @@ -270,6 +270,21 @@ describe("startup update notice", () => { }); }); + test("suppresses update notices for pacman-managed installs", async () => { + await withTempStatePath(async (statePath) => { + await expect( + resolveStartupUpdateNotice({ + env: { HUNK_INSTALL_SOURCE: "pacman" }, + fetchImpl: async () => { + throw new Error("should not fetch for pacman installs"); + }, + resolveInstalledVersion: () => "0.7.0", + statePath, + }), + ).resolves.toBeNull(); + }); + }); + test("detects unmarked mise installs from their mise install path", async () => { await withTempStatePath(async (statePath) => { await expect( diff --git a/src/core/process/updateNotice.ts b/src/core/process/updateNotice.ts index 4fa908be5..586716a9f 100644 --- a/src/core/process/updateNotice.ts +++ b/src/core/process/updateNotice.ts @@ -34,8 +34,10 @@ export type { InstallSource, UpdateChannel }; * starts. A notice there would ask the user to fix something mise just fixed. A local source build * is replaced by rebuilding the checkout it came from, which is the developer's own workflow and * not something a published version number should interrupt. + * + * AUR packages installed via pacman should be updated manually or via an AUR helper. */ -const SILENT_INSTALL_SOURCES: readonly InstallSource[] = ["mise", "dev"]; +const SILENT_INSTALL_SOURCES: readonly InstallSource[] = ["mise", "pacman", "dev"]; export interface UpdateNoticeDeps { env?: NodeJS.ProcessEnv;