diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 62d9c08a6..fe19e2615 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -499,13 +499,15 @@ jobs: uses: ./.github/actions/setup # bsdtar (libarchive-tools) is fpm's mtree generator for the pacman target. + # rpmbuild (rpm) is what fpm shells out to for the rpm target; without it the + # build fails at packaging, not at config parse. # patchelf is what build-linux-compositor-addon.mjs renames the ffmpeg symbols # with, so the addon cannot bind to Chromium's bundled ffmpeg — an unconditional # dependency that resolvePatchelf() throws on. It happens to be preinstalled on # the ubuntu-24.04 image, which is why this has worked; declaring it means the # build stops depending on the runner image's contents. - name: Install Linux packaging and native build dependencies - run: sudo apt-get update && sudo apt-get install -y libarchive-tools patchelf + run: sudo apt-get update && sudo apt-get install -y libarchive-tools rpm patchelf - name: Stage whisper-stt binaries shell: bash @@ -516,6 +518,30 @@ jobs: - name: Build Linux app run: npm run build:linux -- --publish never + # The guard for the trap documented on the upload step below: `if-no-files-found` + # evaluates the union of the globs, so a format that stops being produced is + # invisible there. It is a real failure mode and not a hypothetical one — the rpm + # target was added to electron-builder.json5's `linux.target` alone, where the CLI + # list in `build:linux` overrides it, and the upload glob for it would have matched + # nothing on every release with the job still green. One assertion per format. + - name: Verify every Linux format was produced + run: | + if [[ ! -d release ]]; then + echo "::error::electron-builder produced no release/ directory" + exit 1 + fi + MISSING=() + for ext in AppImage deb pacman rpm; do + COUNT="$(find release -type f -name "*.${ext}" -printf . | wc -c)" + echo "${ext}: ${COUNT}" + if [[ "$COUNT" -eq 0 ]]; then MISSING+=("$ext"); fi + done + if [[ "${#MISSING[@]}" -gt 0 ]]; then + echo "::error::No artifact produced for: ${MISSING[*]} — check the target list in package.json's build:linux, which overrides linux.target in electron-builder.json5" + find release -maxdepth 2 -type f -print + exit 1 + fi + - name: Upload Linux packages uses: actions/upload-artifact@v4 with: @@ -524,6 +550,7 @@ jobs: release/**/*.AppImage release/**/*.deb release/**/*.pacman + release/**/*.rpm # No *.zsync: nothing produces one. zsync is electron-updater's delta format, # this repo has no updater (no electron-updater, no autoUpdater, no # latest-linux.yml), and app-builder-lib 26.x dropped zsync entirely in favour diff --git a/README.md b/README.md index 372662287..20c8dc4ea 100644 --- a/README.md +++ b/README.md @@ -83,16 +83,21 @@ Download the `.exe` installer directly from the [Releases page](https://github.c ### Linux -Three packages are published to the [Releases page](https://github.com/getopenscreen/openscreen/releases) for each version. Pick the one that matches your distro: +Four packages are published to the [Releases page](https://github.com/getopenscreen/openscreen/releases) for each version. Pick the one that matches your distro: **Debian / Ubuntu / Pop!_OS (`.deb`)** ```bash -sudo apt install ./Openscreen-Linux-latest.deb +sudo apt install ./Openscreen-Linux-*.deb +``` + +**Fedora / RHEL / CentOS (`.rpm`)** +```bash +sudo dnf install ./Openscreen-Linux-*.rpm ``` **Arch / Manjaro (`.pacman`)** ```bash -sudo pacman -U Openscreen-Linux-latest.pacman +sudo pacman -U Openscreen-Linux-*.pacman ``` **Any distro (`.AppImage`)** diff --git a/electron-builder.json5 b/electron-builder.json5 index 9879089be..c3e3b9d40 100644 --- a/electron-builder.json5 +++ b/electron-builder.json5 @@ -102,10 +102,16 @@ } }, "linux": { + // Cette liste ne suffit PAS à produire un artefact en CI : `build:linux` passe + // ses cibles en ligne de commande (`electron-builder --linux AppImage deb pacman + // rpm`), et la CLI REMPLACE `linux.target` au lieu de le compléter. Toute cible + // ajoutée ici doit l'être aussi dans le script, sinon elle n'existe que pour un + // `electron-builder --linux` nu, que rien n'exécute. "target": [ "AppImage", "deb", - "pacman" + "pacman", + "rpm" ], "icon": "icons/icons/png", "artifactName": "${productName}-Linux-${version}.${ext}", @@ -176,6 +182,32 @@ "vulkan-swrast" ] }, + "rpm": { + // Même règle que ci-dessus : la liste REMPLACE le défaut d'electron-builder, + // donc les huit premières entrées SONT ce défaut (FpmTarget.getDefaultDepends, + // cas "rpm"), verbatim, suivies des deux qui nous sont propres. + // + // `mesa-vulkan-drivers` porte le même nom sur Fedora que sur Debian : c'est le + // paquet qui garantit lavapipe, sans quoi l'aperçu du compositeur est indisponible. + // + // `libsecret` n'est PAS dans le défaut rpm alors qu'il l'est dans le défaut deb + // (`libsecret-1-0`). `safeStorage` chiffre les clés d'API des fournisseurs LLM + // (electron/ai-edition/llm-config-store.ts) et passe par le Secret Service : + // sans lui, `isEncryptionAvailable()` répond faux et l'enregistrement d'une clé + // lève. Une omission d'electron-builder, pas un choix. + "depends": [ + "gtk3", + "libnotify", + "nss", + "libXScrnSaver", + "(libXtst or libXtst6)", + "xdg-utils", + "at-spi2-core", + "(libuuid or libuuid1)", + "libsecret", + "mesa-vulkan-drivers" + ] + }, "win": { "target": [ "nsis" diff --git a/package.json b/package.json index 8b2065643..287e8bb79 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "build:native:linux": "node scripts/build-linux-pipewire-helper.mjs", "build:win": "npm run build:native:win && npm run fetch:ffmpeg && npm run build:native:compositor && tsc && vite build && electron-builder --win --config.npmRebuild=false", "build:win:store": "npm run build:native:win && npm run fetch:ffmpeg && npm run build:native:compositor && tsc && vite build && electron-builder --win appx --config.npmRebuild=false", - "build:linux": "npm run fetch:ffmpeg:sdk && npm run build:native:linux && npm run build:native:compositor:linux && tsc && vite build && electron-builder --linux AppImage deb pacman --config.npmRebuild=false", + "build:linux": "npm run fetch:ffmpeg:sdk && npm run build:native:linux && npm run build:native:compositor:linux && tsc && vite build && electron-builder --linux AppImage deb pacman rpm --config.npmRebuild=false", "build:whisper-binaries": "bash scripts/build-whisper-stt.sh", "test:whisper-stt": "node scripts/test-whisper-stt.mjs", "test": "vitest --run", diff --git a/technical-documentation/engineering/build-and-packaging.md b/technical-documentation/engineering/build-and-packaging.md index 0aecb5996..9795be997 100644 --- a/technical-documentation/engineering/build-and-packaging.md +++ b/technical-documentation/engineering/build-and-packaging.md @@ -12,7 +12,7 @@ OpenScreen builds its renderer, Electron main process, preload bridge, native he | `npm run build:mac` | Builds the ScreenCaptureKit and cursor helpers, checks TypeScript, runs Vite, and packages the macOS target. | | `npm run build:win` | Builds WGC/cursor helpers and the D3D11 compositor addon, fetches FFmpeg, checks TypeScript, runs Vite, and packages the Windows NSIS target without npm rebuild. | | `npm run build:win:store` | Performs the Windows native and renderer build, then asks electron-builder for the configured AppX Store package. | -| `npm run build:linux` | Checks TypeScript, runs Vite, then packages AppImage, Debian, and pacman artifacts without npm rebuild. | +| `npm run build:linux` | Checks TypeScript, runs Vite, then packages AppImage, Debian, pacman, and RPM artifacts without npm rebuild. Its explicit `--linux` target list overrides `linux.target` in `electron-builder.json5`, so a target added to the config alone is never built. | | `npm run build:native:mac` | Uses SwiftPM to build requested single-architecture ScreenCaptureKit and macOS cursor helpers and stages them under `electron/native/bin/darwin-*`. | | `npm run build:native:win` | Uses CMake/Ninja in an MSVC environment to build WGC capture and cursor-sampler executables and stage x64 binaries. | | `npm run build:native:compositor` | Uses Cargo/MSVC and the pinned shared FFmpeg SDK to build `compositor_view.node`. | @@ -124,7 +124,7 @@ Electron-builder targets DMG for both `arm64` and `x64`, enables hardened runtim ### Linux and Nix -Electron-builder produces AppImage, `.deb`, and `.pacman` targets. The flake separately supports `x86_64-linux` and `aarch64-linux`, offers NixOS and Home Manager modules, and builds a wrapper around nixpkgs' system Electron. `nix/package.nix` runs Vite directly, installs `dist/`, `dist-electron/`, production npm dependencies, wallpapers, icons, and a desktop entry; it does not invoke electron-builder. The release workflow later opens a PR to update the Nix package version and npm dependency hash after stable releases. +Electron-builder produces AppImage, `.deb`, `.pacman`, and `.rpm` targets. Each fpm target carries its own `depends` list, which *replaces* electron-builder's default rather than extending it; all three package formats therefore repeat that default verbatim before adding the Vulkan ICD (`mesa-vulkan-drivers`, `vulkan-swrast` on Arch) the native compositor needs. The RPM list also restores `libsecret`, which electron-builder includes in its `deb` default but omits from its `rpm` one, and which `safeStorage` needs to encrypt LLM credentials. The flake separately supports `x86_64-linux` and `aarch64-linux`, offers NixOS and Home Manager modules, and builds a wrapper around nixpkgs' system Electron. `nix/package.nix` runs Vite directly, installs `dist/`, `dist-electron/`, production npm dependencies, wallpapers, icons, and a desktop entry; it does not invoke electron-builder. The release workflow later opens a PR to update the Nix package version and npm dependency hash after stable releases. ## Node and toolchain versions diff --git a/technical-documentation/engineering/ci-workflows.md b/technical-documentation/engineering/ci-workflows.md index 7807c473b..011529447 100644 --- a/technical-documentation/engineering/ci-workflows.md +++ b/technical-documentation/engineering/ci-workflows.md @@ -21,7 +21,7 @@ flowchart TD ReleaseBuild["build.yml
v* tag or dispatch"] --> Win[Windows NSIS] ReleaseBuild --> Store[Windows AppX] ReleaseBuild --> Mac["macOS arm64 and x64 DMGs"] - ReleaseBuild --> Linux["AppImage, deb, pacman"] + ReleaseBuild --> Linux["AppImage, deb, pacman, rpm"] Win --> Publish[GitHub release] Mac --> Publish Linux --> Publish @@ -101,7 +101,7 @@ A `v*` tag or manual dispatch starts platform builds. Dispatch accepts `arch` (` - `build-windows` runs `npm run build:win` and uploads `openscreen-windows` for 30 days. - `build-windows-store` runs `npm run build:win:store` and uploads `openscreen-windows-store` for 30 days. - `build-macos` is an `arm64`/`x64` matrix. It builds Vite/Electron and native helpers, packages and optionally signs the app, creates DMGs, notarizes every signed build including pre-releases, and uploads one artifact per architecture for 30 days. -- `build-linux` produces AppImage, deb, and pacman files and uploads `openscreen-linux` for 30 days. No zsync: that is electron-updater's delta format, this repo ships no updater, and app-builder-lib 26.x embeds a block map in the AppImage instead. +- `build-linux` produces AppImage, deb, pacman, and rpm files and uploads `openscreen-linux` for 30 days. It asserts one artifact per format before uploading, because `if-no-files-found: error` evaluates the union of the upload globs and so cannot catch a single format that stopped being produced. No zsync: that is electron-updater's delta format, this repo ships no updater, and app-builder-lib 26.x embeds a block map in the AppImage instead. - `publish-release` waits for Windows NSIS, macOS, and Linux jobs; the Store job is not a dependency. It checks the tag against `package.json`, downloads the NSIS/macOS/Linux artifacts, and creates or updates a GitHub release with `OPENSCREEN_RELEASE_TOKEN`. The build comments and package behavior refer to the local Whisper architecture documented in [transcription and captions](../architecture/transcription-and-captions.md). The STT model downloads to user data at runtime and is not a release-build asset. diff --git a/website/docs/installation.md b/website/docs/installation.md index d00941abb..141498332 100644 --- a/website/docs/installation.md +++ b/website/docs/installation.md @@ -2,13 +2,14 @@ id: installation title: Installation sidebar_position: 2 -description: "Install OpenScreen on macOS, Windows, or Linux — .dmg, .exe, .deb, .pacman, AppImage, and a Nix flake, including the macOS Gatekeeper step." +description: "Install OpenScreen on macOS, Windows, or Linux — .dmg, .exe, .deb, .rpm, .pacman, AppImage, and a Nix flake, including the macOS Gatekeeper step." keywords: - install screen recorder - download OpenScreen - macOS dmg - Windows installer - Linux deb + - Fedora rpm - AppImage - Nix flake --- @@ -41,13 +42,18 @@ Download and run the `.exe` installer from [Releases](https://github.com/getopen ## Linux -Three packages are published per release — pick the one matching your distro. +Four packages are published per release — pick the one matching your distro. **Debian / Ubuntu / Pop!_OS** ```bash sudo apt install ./Openscreen-Linux-*.deb ``` +**Fedora / RHEL / CentOS** +```bash +sudo dnf install ./Openscreen-Linux-*.rpm +``` + **Arch / Manjaro** ```bash sudo pacman -U Openscreen-Linux-*.pacman diff --git a/website/src/lib/release.ts b/website/src/lib/release.ts index df0242877..bb48b148e 100644 --- a/website/src/lib/release.ts +++ b/website/src/lib/release.ts @@ -30,6 +30,7 @@ export const ASSET_PATTERNS = { macIntel: /Mac.*x64.*\.dmg$/i, windows: /\.exe$/i, deb: /\.deb$/i, + rpm: /\.rpm$/i, pacman: /\.pacman$/i, appImage: /\.AppImage$/i, } as const; diff --git a/website/src/pages/download.tsx b/website/src/pages/download.tsx index 3d19ac594..fec64fe17 100644 --- a/website/src/pages/download.tsx +++ b/website/src/pages/download.tsx @@ -25,7 +25,7 @@ const PAGE_URL = "https://getopenscreen.com/download/"; // structured-data description that contradicts the meta one is worse than none. const PAGE_TITLE = "Download for Windows, macOS & Linux"; const PAGE_DESCRIPTION = - "Download OpenScreen free for Windows, macOS, and Linux — .dmg, .exe, .deb, .pacman, AppImage, and a Nix flake. Open source, no account, no watermark."; + "Download OpenScreen free for Windows, macOS, and Linux — .dmg, .exe, .deb, .rpm, .pacman, AppImage, and a Nix flake. Open source, no account, no watermark."; type PlatformSpec = { id: string; @@ -60,6 +60,7 @@ const PLATFORMS: PlatformSpec[] = [ icon: TerminalSquare, options: [ { kind: "deb", label: "Debian, Ubuntu, Pop!_OS", sublabel: "Package · .deb" }, + { kind: "rpm", label: "Fedora, RHEL, CentOS", sublabel: "Package · .rpm" }, { kind: "pacman", label: "Arch, Manjaro", sublabel: "Package · .pacman" }, { kind: "appImage", label: "Any distribution", sublabel: "Portable · .AppImage" }, ], diff --git a/website/src/pages/index.tsx b/website/src/pages/index.tsx index 93fbd1c8f..e7109c5d9 100644 --- a/website/src/pages/index.tsx +++ b/website/src/pages/index.tsx @@ -331,8 +331,9 @@ export default function Home() {

- The macOS line is only needed if Gatekeeper blocks the app. Linux also ships - .pacman, an AppImage, and a Nix flake — every artifact is on the{" "} + The macOS line is only needed if Gatekeeper blocks the app. Linux also ships{" "} + .rpm, .pacman, an AppImage, and a Nix flake — every artifact + is on the{" "} Releases page, and{" "} Installation has the full steps.