diff --git a/.github/workflows/omnipackage.yml b/.github/workflows/omnipackage.yml new file mode 100644 index 0000000000..813264f973 --- /dev/null +++ b/.github/workflows/omnipackage.yml @@ -0,0 +1,52 @@ +name: Build Linux packages (omnipackage) + +on: + workflow_dispatch: + push: + branches: [master] + +jobs: + list-distros: + runs-on: ubuntu-24.04 + outputs: + distros: ${{ steps.get-distros.outputs.distros }} + steps: + - name: Install omnipackage + run: | + echo 'deb https://repositories.omnipackage.org/omnipackage-rs/stable/ubuntu_24.04 stable/' | sudo tee /etc/apt/sources.list.d/omnipackage_omnipackage.list + curl -fsSL https://repositories.omnipackage.org/omnipackage-rs/stable/ubuntu_24.04/stable/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/omnipackage_omnipackage.gpg > /dev/null + sudo apt-get update + sudo apt-get install -y omnipackage + + - uses: actions/checkout@v6 + + - name: Get distro list + id: get-distros + run: echo "distros=$(omnipackage info --list-distros . --format json)" >> "$GITHUB_OUTPUT" + + release: + needs: [list-distros] + runs-on: ubuntu-24.04 + concurrency: + group: omnipackage-${{ matrix.distro }} + cancel-in-progress: false + strategy: + fail-fast: false + matrix: + distro: ${{ fromJson(needs.list-distros.outputs.distros) }} + steps: + - name: Install omnipackage + run: | + echo 'deb https://repositories.omnipackage.org/omnipackage-rs/stable/ubuntu_24.04 stable/' | sudo tee /etc/apt/sources.list.d/omnipackage_omnipackage.list + curl -fsSL https://repositories.omnipackage.org/omnipackage-rs/stable/ubuntu_24.04/stable/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/omnipackage_omnipackage.gpg > /dev/null + sudo apt-get update + sudo apt-get install -y omnipackage + + - uses: actions/checkout@v6 + with: + submodules: recursive + + - run: echo "${{ secrets.OMNIPACKAGE_DOTENV }}" > .env + + - name: Release packages for ${{ matrix.distro }} + run: omnipackage release . --distros "${{ matrix.distro }}" diff --git a/.omnipackage/config.yml b/.omnipackage/config.yml new file mode 100644 index 0000000000..5e09c27bd4 --- /dev/null +++ b/.omnipackage/config.yml @@ -0,0 +1,264 @@ +version_extractors: + - name: package_json + provider: "file" + file: + file: "package.json" + regex: '"version": "(.+)-dev"' + +common: &common + package_name: "pulsar-dev" + maintainer: "Chuck Norris " + homepage: https://pulsar-edit.dev/ + description: A community-led, hyper-hackable text editor + +repositories: + - name: R2 test repo + provider: s3 + gpg_private_key_base64: "${GPG_PRIVATE_KEY_BASE64}" + <<: *common + s3: + bucket: repositories-test + path_in_bucket: "pulsar-dev" + bucket_public_url: "https://repositories-test.omnipackage.org" + endpoint: "${CLOUDFLARE_R2_ENDPOINT}" + access_key_id: "${CLOUDFLARE_R2_ACCESS_KEY_ID}" + secret_access_key: "${CLOUDFLARE_R2_SECRET_ACCESS_KEY}" + region: auto + force_path_style: true + cloudflare_zone_id: "${CLOUDFLARE_ZONE_ID}" + cloudflare_api_token: "${CLOUDFLARE_API_TOKEN}" + + - name: Local test + <<: *common + gpg_private_key_base64: "${GPG_PRIVATE_KEY_BASE64}" + provider: localfs + localfs: + path: /run/media/oleg/c3996ce0-a379-4403-9d64-7d4c0536463f/dev/omnipackage-repos/pulsar-dev + +rpm: &rpm + <<: *common + before_build_script: ".omnipackage/prepare.sh" + rpm: + spec_template: ".omnipackage/specfile.spec.liquid" + +deb: &deb + <<: *common + before_build_script: ".omnipackage/prepare.sh" + deb: + debian_templates: ".omnipackage/deb" + +# Shared libs are picked up automatically by rpmbuild's dependency generator +# (and by dpkg-shlibdeps for debs). Only list things ELF scanning can't infer: +# commands invoked at runtime and services we depend on via pkexec/etc. +opensuse: &opensuse + build_dependencies: + [ + "libsecret-devel", + "libX11-devel", + "libxkbfile-devel", + "gcc", + "gcc-c++", + "make", + "python313-distutils-extra", + "wget", + "git", + "wayland-devel", + "libxkbcommon-devel", + "libgnome-keyring-devel", + "pkg-config", + ] + runtime_dependencies: + [ + "git", + "xdg-utils", + "polkit", + ] + <<: *rpm + +# Fedora differs from openSUSE on package names: pkgconf-pkg-config provides +# pkg-config, and libgnome-keyring-devel was retired (libsecret is enough). +fedora: &fedora + build_dependencies: + [ + "libsecret-devel", + "libX11-devel", + "libxkbfile-devel", + "gcc", + "gcc-c++", + "make", + "python3", + "python3-setuptools", + "wget", + "git", + "wayland-devel", + "libxkbcommon-devel", + "pkgconf-pkg-config", + ] + runtime_dependencies: + [ + "git", + "xdg-utils", + "polkit", + ] + <<: *rpm + +debian: &debian + build_dependencies: + [ + "build-essential", + "git", + "wget", + "curl", + "ca-certificates", + "pkg-config", + "python3", + "python3-setuptools", + "libsecret-1-dev", + "libx11-dev", + "libxkbfile-dev", + "libwayland-dev", + "libxkbcommon-dev", + ] + runtime_dependencies: + [ + "git", + "xdg-utils", + "policykit-1", + "libglib2.0-bin | kde-cli-tools | kde-runtime", + ] + <<: *deb + +# RHEL clones (AlmaLinux/RockyLinux). EL9 defaults python3 to 3.9 (works for +# node-gyp out of the box); EL10 ships 3.12 (the python3-setuptools dep gives +# us the vendored distutils shim prepare.sh's symlink picks up). +# libxkbfile-devel is intentionally omitted from build_dependencies because +# it lives in CRB (disabled by default on AlmaLinux/Rocky). prepare.sh +# capability-detects the CRB repo file and enables it inline (no-op on +# Fedora / non-dnf distros). +redhat: &redhat + build_dependencies: + [ + "libsecret-devel", + "libX11-devel", + "gcc", + "gcc-c++", + "make", + "python3", + "python3-setuptools", + "wget", + "git", + "wayland-devel", + "libxkbcommon-devel", + "pkgconf-pkg-config", + ] + runtime_dependencies: + [ + "git", + "xdg-utils", + "polkit", + ] + <<: *rpm + +# Mageia ships -devel headers under the lib64*-devel namespace on x86_64, +# and uses bare `pkgconf` rather than pkgconf-pkg-config. +mageia: &mageia + build_dependencies: + [ + "lib64secret-devel", + "lib64x11-devel", + "lib64xkbfile-devel", + "gcc", + "gcc-c++", + "make", + "python3", + "python3-setuptools", + "wget", + "git", + "lib64wayland-devel", + "lib64xkbcommon-devel", + "pkgconf", + ] + runtime_dependencies: + [ + "git", + "xdg-utils", + "polkit", + ] + <<: *rpm + +builds: + - distro: "opensuse_tumbleweed" + <<: *opensuse + + - distro: "opensuse_16.0" + <<: *opensuse + + - distro: "opensuse_15.6" + # Leap 15.6's default python3 is 3.6 (too old for node-gyp); install + # python311 explicitly. stdlib distutils is still present in 3.11, so no + # setuptools shim or python*-distutils-extra is needed. + <<: *opensuse + build_dependencies: + [ + "libsecret-devel", + "libX11-devel", + "libxkbfile-devel", + "gcc", + "gcc-c++", + "make", + "python311", + "wget", + "git", + "wayland-devel", + "libxkbcommon-devel", + "libgnome-keyring-devel", + "pkg-config", + ] + + - distro: "fedora_42" + <<: *fedora + + - distro: "fedora_43" + <<: *fedora + + - distro: "fedora_44" + <<: *fedora + + - distro: "fedora_rawhide" + <<: *fedora + + - distro: "debian_12" + <<: *debian + + - distro: "debian_13" + <<: *debian + + - distro: "ubuntu_22.04" + <<: *debian + + - distro: "ubuntu_24.04" + <<: *debian + + - distro: "ubuntu_26.04" + <<: *debian + + - distro: "almalinux_9" + <<: *redhat + + - distro: "almalinux_10" + <<: *redhat + + - distro: "rockylinux_9" + <<: *redhat + + - distro: "rockylinux_10" + <<: *redhat + + - distro: "mageia_9" + <<: *mageia + +ignore_source_files: + - .git + - .env + - "*.log" + - node_modules diff --git a/.omnipackage/deb/changelog.liquid b/.omnipackage/deb/changelog.liquid new file mode 100644 index 0000000000..08c2891e59 --- /dev/null +++ b/.omnipackage/deb/changelog.liquid @@ -0,0 +1,5 @@ +{{ package_name }} ({{ version }}-0) stable; urgency=low + + * Release {{ version }} + + -- {{ maintainer }} {{ current_time_rfc2822 }} diff --git a/.omnipackage/deb/compat.liquid b/.omnipackage/deb/compat.liquid new file mode 100644 index 0000000000..f599e28b8a --- /dev/null +++ b/.omnipackage/deb/compat.liquid @@ -0,0 +1 @@ +10 diff --git a/.omnipackage/deb/control.liquid b/.omnipackage/deb/control.liquid new file mode 100644 index 0000000000..4eff564740 --- /dev/null +++ b/.omnipackage/deb/control.liquid @@ -0,0 +1,12 @@ +Source: {{ package_name }} +Section: devel +Priority: optional +Maintainer: {{ maintainer }} +Build-Depends: debhelper (>= 8.0.0), {{ build_dependencies | join: ', ' }} +Standards-Version: 3.9.4 +Homepage: {{ homepage }} + +Package: {{ package_name }} +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}{% if runtime_dependencies.size > 0 %}, {{ runtime_dependencies | join: ', ' }}{% endif %} +Description: {{ description }} diff --git a/.omnipackage/deb/postinst.liquid b/.omnipackage/deb/postinst.liquid new file mode 100644 index 0000000000..853cc2255a --- /dev/null +++ b/.omnipackage/deb/postinst.liquid @@ -0,0 +1,8 @@ +#!/bin/sh +# Chromium's setuid sandbox helper must be 4755 root:root or the renderer +# refuses to start. dh_fixperms strips the bit during build, so set it here. +set -e + +chmod 4755 /usr/lib/{{ package_name }}/chrome-sandbox + +exit 0 diff --git a/.omnipackage/deb/rules.liquid b/.omnipackage/deb/rules.liquid new file mode 100644 index 0000000000..83504ed611 --- /dev/null +++ b/.omnipackage/deb/rules.liquid @@ -0,0 +1,31 @@ +#!/usr/bin/make -f +# debian.rules — Debian build rules. Indents are TABS, not spaces. +# -*- makefile -*- + +export DESTROOT=$(CURDIR)/debian/{{ package_name }} +# export DH_VERBOSE=1 + +%: + dh $@ --parallel + +# install.sh is shared with the rpm spec; second arg is the package name so +# /usr/lib// and the launcher symlinks line up. +override_dh_auto_install: + $(CURDIR)/.omnipackage/install.sh $(DESTROOT) {{ package_name }} + +# Pulsar bundles its own dependencies under /usr/lib//. Skipping the +# default strip pass keeps electron's native helper binaries usable; without +# this dh_strip mangles libffmpeg/libvk_swiftshader and the editor segfaults +# on launch. +override_dh_strip: + +# Don't try to mess with the bundled .so/.node files — they're shipped as-is +# by electron-builder and the binary patcher would otherwise rewrite RPATHs we +# rely on. +override_dh_shlibdeps: + +# chrome-sandbox needs setuid root at runtime (see postinst). Skip the +# default fixperms so the bit survives if anything ever sets it pre-package; +# postinst restores it on install regardless. +override_dh_fixperms: + dh_fixperms -X chrome-sandbox diff --git a/.omnipackage/install.sh b/.omnipackage/install.sh new file mode 100755 index 0000000000..9864372cb1 --- /dev/null +++ b/.omnipackage/install.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +source /profile + +set -xEeuo pipefail + +BUILDROOT=$1 +NAME=$2 +# "" for stock `pulsar`, "-dev" for `pulsar-dev`, etc. Used to suffix the ppm +# CLI symlink so multiple Pulsar packages can coexist on the same system. +SUFFIX="${NAME#pulsar}" + +# wayland-client.h, xkbcommon.h, etc. live in non-default include dirs on some +# distros; surface them via pkg-config so native module builds find them. +export CPLUS_INCLUDE_PATH=$(pkg-config --cflags-only-I wayland-client xkbcommon x11 xkbfile | tr ' ' '\n' | sed 's/^-I//' | paste -sd:)${CPLUS_INCLUDE_PATH:+:$CPLUS_INCLUDE_PATH} + +nvm install +npm install -g yarn +corepack enable +nvm use +node -v + +yarn install +yarn build +yarn build:apm + +# Reduce electron-builder to a single `dir` target: skip the appimage/deb/rpm +# wrappers we never use, and swap tar.gz for `dir` so it stops after producing +# dist/linux-unpacked/. Saves the tar+untar round trip and the compression +# pass. (Edits the in-tree copy inside the build sandbox only — repo file is +# untouched.) +sed -i "s|target: 'tar.gz'|target: 'dir'|; /target: 'appimage'/d; /target: 'deb'/d; /target: 'rpm'/d" script/electron-builder.js +yarn dist linux + +# Stage the unpacked Pulsar tree under /usr/lib/. +mkdir -p $BUILDROOT/usr/lib/$NAME +cp -a dist/linux-unpacked/. $BUILDROOT/usr/lib/$NAME/ +rm -rf $BUILDROOT/usr/lib/$NAME/resources/app/ppm/spec # shebang in some files there messes up the dependencies + +# Let Chromium's setuid sandbox helper actually engage. The rpm spec installs +# chrome-sandbox as 4755 root:root (%attr); here we just strip the +# --no-sandbox flag pulsar.sh hardcodes so the sandbox is not disabled at +# launch. +sed -i 's/ --no-sandbox//g' $BUILDROOT/usr/lib/$NAME/resources/pulsar.sh + +# pulsar.sh derives ATOM_EXECUTABLE_NAME from basename($0) and then checks +# $PULSAR_PATH/$ATOM_EXECUTABLE_NAME. The tarball ships the binary as `pulsar`, +# so for packages renamed away from stock (e.g. `pulsar-dev`) we need a sibling +# symlink under the package name or pulsar.sh aborts with +# "Cannot locate Pulsar". +if [ "$NAME" != "pulsar" ]; then + ln -sf pulsar $BUILDROOT/usr/lib/$NAME/$NAME +fi + +# User-facing CLI entrypoints. Suffix the ppm symlink so we do not collide with +# the stock pulsar package's /usr/bin/ppm. +mkdir -p $BUILDROOT/usr/bin/ +ln -sf /usr/lib/$NAME/resources/pulsar.sh $BUILDROOT/usr/bin/$NAME +ln -sf /usr/lib/$NAME/resources/app/ppm/bin/ppm $BUILDROOT/usr/bin/ppm$SUFFIX + +# Desktop entry. Exec goes through /usr/bin/$NAME (pulsar.sh) so ATOM_HOME and +# release-channel inference behave the same as terminal launches; pulsar.sh +# itself appends --no-sandbox. +mkdir -p $BUILDROOT/usr/share/applications +DISPLAY_NAME="Pulsar${SUFFIX}" +cat > $BUILDROOT/usr/share/applications/$NAME.desktop </dev/null 2>&1 && \ + grep -qER '^\[(crb|CRB)\]' /etc/yum.repos.d/ 2>/dev/null; then + # libxkbfile-devel — XKBfile.h (linked by @pulsar-edit/keyboard-layout) + # xorg-x11-proto-devel — XKBrules.h (included by the same module on Linux); + # openSUSE pulls this transitively via libX11-devel, + # EL clones do not. Modern name is xorgproto-devel + # but RHEL 9/10 still ship the legacy name. + dnf install -y --enablerepo=crb libxkbfile-devel xorg-x11-proto-devel +fi + +export NVM_DIR=/nvm +export PROFILE=/profile + +mkdir -p $NVM_DIR +touch $PROFILE + +if nvm --version; then + exit 0 +fi + +wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash +source $PROFILE + +nvm --version diff --git a/.omnipackage/specfile.spec.liquid b/.omnipackage/specfile.spec.liquid new file mode 100644 index 0000000000..a203ddae26 --- /dev/null +++ b/.omnipackage/specfile.spec.liquid @@ -0,0 +1,58 @@ +Name: {{ package_name }} +Version: {{ version }} +Release: 1%{?dist} +Summary: Pulsar editor +License: GPL-3.0-or-later +URL: https://pulsar-edit.dev +Source0: {{ source_folder_name }}.tar.gz +#AutoReqProv: no # Avoid libchromiumcontent.so missing dependency + +BuildRequires: {{ build_dependencies | join: ' ' }} +{% if runtime_dependencies.size > 0 %} +Requires: {{ runtime_dependencies | join: ', ' }} +{% endif %} + +# Disable Fedora's shebang mangling script, +# which errors out on any file with versionless `python` in its shebang +# See: https://github.com/atom/atom/issues/21937 +%undefine __brp_mangle_shebangs + +%define debug_package %{nil} +%define _build_id_links none + +%description +{{ description }} + + +%prep +%setup -q + + +%build + + +%install +.omnipackage/install.sh %{buildroot} %{name} + + +%files +/usr/lib/%{name}/ +%attr(4755, root, root) /usr/lib/%{name}/chrome-sandbox +/usr/bin/%{name} +/usr/bin/ppm-dev +/usr/share/applications/%{name}.desktop +/usr/share/polkit-1/actions/%{name}.policy +/usr/share/icons/hicolor/16x16/apps/%{name}.png +/usr/share/icons/hicolor/22x22/apps/%{name}.png +/usr/share/icons/hicolor/24x24/apps/%{name}.png +/usr/share/icons/hicolor/32x32/apps/%{name}.png +/usr/share/icons/hicolor/48x48/apps/%{name}.png +/usr/share/icons/hicolor/64x64/apps/%{name}.png +/usr/share/icons/hicolor/128x128/apps/%{name}.png +/usr/share/icons/hicolor/256x256/apps/%{name}.png +/usr/share/icons/hicolor/384x384/apps/%{name}.png + + +%changelog +* Sun Feb 18 2024 Chuck Norris +- Chuck Norris does not use revision control software. None of his code has ever needed revision.