feat(packaging): COPR repository for Fedora

The spec builds from the tag archive and a vendored crates tarball when
git_dir is not defined, so COPR can build it without network access.
release.yml publishes the vendor tarball and submits the build to COPR
after the release is published.

Refs #42
This commit is contained in:
nvrl committed 2026-10-17 11:44:33 +02:00
1 parent eb25c16fe6
commit 29b87ece72
9 files changed
+201 -27

No files matched your search

+66
View File
@@ -0,0 +1,66 @@
name: COPR
on:
# Called by release.yml once the GitHub release and its assets exist: COPR
# downloads the tag archive and the vendored crates from the release.
workflow_call:
inputs:
version:
required: true
type: string
secrets:
COPR_CONFIG:
required: true
workflow_dispatch:
inputs:
version:
description: 'Release to build, such as 3.5.0. It must already have its vendor tarball.'
required: true
type: string
permissions:
contents: read
concurrency:
group: copr
cancel-in-progress: false
jobs:
build:
name: Build in COPR
runs-on: ubuntu-24.04
container: fedora:latest
env:
VERSION: ${{ inputs.version }}
COPR_PROJECT: narrrl/proton-drive-linux
steps:
- name: Install packaging tools
run: dnf -y install copr-cli rpm-build rpmdevtools
- name: Checkout repository
uses: actions/checkout@v7
- name: Configure COPR access
env:
COPR_CONFIG: ${{ secrets.COPR_CONFIG }}
run: |
install -d -m700 ~/.config
printf '%s\n' "$COPR_CONFIG" > ~/.config/copr
chmod 600 ~/.config/copr
# COPR rebuilds the source package without our --define, so the version
# has to be written into the spec itself.
- name: Build the source package
run: |
version="${VERSION#v}"
spec=packaging/proton-drive-linux.spec
sed -i -E "s/^(%\{!\?version: %global version )[^}]*\}/\1${version}}/" "$spec"
grep -qF "%global version ${version}}" "$spec"
mkdir -p rpmbuild/SOURCES
spectool -g -C rpmbuild/SOURCES "$spec"
rpmbuild -bs --define "_topdir $PWD/rpmbuild" "$spec"
# Waits for the build, so a failed COPR build fails this job.
- name: Submit to COPR
run: copr-cli build "$COPR_PROJECT" rpmbuild/SRPMS/*.src.rpm
+20
View File
@@ -52,8 +52,10 @@ jobs:
tag_version="${GITHUB_REF_NAME#v}"
manifest_version="$(sed -n 's/^version = "\([^"]*\)"/\1/p' Cargo.toml | head -n1)"
pkgbuild_version="$(sed -n 's/^pkgver=//p' packaging/PKGBUILD | head -n1)"
spec_version="$(sed -n 's/^%{!?version: %global version \([^}]*\)}/\1/p' packaging/proton-drive-linux.spec)"
test "$tag_version" = "$manifest_version"
test "$tag_version" = "$pkgbuild_version"
test "$tag_version" = "$spec_version"
- name: Release quality gates
run: |
@@ -129,6 +131,12 @@ jobs:
# Create tarball
tar -czf proton-drive-linux-${{ env.VERSION }}-x86_64.tar.gz -C dist/binaries .
# Every crate the build needs, so COPR can build the spec without network.
- name: Package vendored crates (.tar.xz)
run: |
cargo vendor --locked dist/vendor > /dev/null
tar -cJf proton-drive-linux-vendor-${{ env.VERSION }}.tar.xz -C dist vendor
- name: Package Debian package (.deb)
run: |
mkdir -p deb/DEBIAN
@@ -230,6 +238,7 @@ jobs:
path: |
*.deb
*.tar.gz
*.tar.xz
*.rpm
if-no-files-found: error
@@ -297,6 +306,7 @@ jobs:
files: |
*.deb
*.tar.gz
*.tar.xz
*.rpm
draft: false
prerelease: false
@@ -312,3 +322,13 @@ jobs:
version: ${{ github.ref_name }}
secrets:
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
copr:
name: Build COPR packages
needs: publish
if: startsWith(github.ref, 'refs/tags/')
uses: ./.github/workflows/copr.yml
with:
version: ${{ github.ref_name }}
secrets:
COPR_CONFIG: ${{ secrets.COPR_CONFIG }}
+3 -2
View File
@@ -74,14 +74,15 @@ scriptable CLI.
| Distribution | Package |
|---|---|
| Debian, Ubuntu 24.04 or newer | `.deb` from the [latest release](https://github.com/narrrl/proton-drive-linux/releases/latest) |
| Fedora 44 or newer | `.rpm` from the [latest release](https://github.com/narrrl/proton-drive-linux/releases/latest) |
| Fedora 44 or newer | [`narrrl/proton-drive-linux`](https://copr.fedorainfracloud.org/coprs/narrrl/proton-drive-linux/) in COPR, or the `.rpm` from the [latest release](https://github.com/narrrl/proton-drive-linux/releases/latest) |
| Arch Linux | [`proton-drive-for-linux`](https://aur.archlinux.org/packages/proton-drive-for-linux) (also `-bin` and `-git`) in the AUR |
| NixOS | The flake in this repository: see [Install → NixOS](docs/INSTALL.md#nixos-flake) |
| Anything else | [Build from source](docs/INSTALL.md#build-from-source) |
```bash
sudo apt install ./proton-drive-linux_*.deb # Debian, Ubuntu
sudo dnf install ./proton-drive-linux-*.rpm # Fedora
sudo dnf copr enable narrrl/proton-drive-linux # Fedora
sudo dnf install proton-drive-linux
paru -S proton-drive-for-linux # Arch
```
+5
View File
@@ -11,6 +11,11 @@ scratch (user data in `staging/` and `recovery/` is never touched by this).
## [Unreleased]
### Added
- **A COPR repository for Fedora**, so `dnf upgrade` brings each new release:
`sudo dnf copr enable narrrl/proton-drive-linux`. Every release also ships the vendored crates
as `proton-drive-linux-vendor-<version>.tar.xz`, which the COPR build uses offline (#42).
## [3.5.0] — 2026-10-16
Schema: **44**. Queued changes get an index by kind and name, and each synced file remembers the
+11 -8
View File
@@ -150,22 +150,25 @@ to the GitHub wiki, so keep their file names.
Releases are cut from `main` by pushing a `v*` tag. `.github/workflows/release.yml` then:
1. checks that the tag, the workspace version in `Cargo.toml` and `pkgver` in
`packaging/PKGBUILD` agree;
1. checks that the tag, the workspace version in `Cargo.toml`, `pkgver` in
`packaging/PKGBUILD` and the default version in `packaging/proton-drive-linux.spec` agree;
2. runs the quality gates;
3. builds the release binaries and packages a `.tar.gz`, a `.deb` and a GPG-signed `.rpm`, and
builds the Nix flake at the tag, which is what a flake input pinned to `vX.Y.Z` gets, and
pushes it to the `proton-drive-linux` Cachix cache (secret `CACHIX_AUTH_TOKEN`);
3. builds the release binaries and packages a `.tar.gz`, a `.deb`, a GPG-signed `.rpm` and a
`.tar.xz` of the vendored crates, and builds the Nix flake at the tag, which is what a flake
input pinned to `vX.Y.Z` gets, and pushes it to the `proton-drive-linux` Cachix cache (secret
`CACHIX_AUTH_TOKEN`);
4. publishes them as a GitHub release, with the version's section of `docs/CHANGELOG.md` as the
notes;
5. calls `.github/workflows/aur.yml`, which updates and pushes the AUR recipes and commits them
back to `main`.
back to `main`;
6. calls `.github/workflows/copr.yml`, which builds the release in the
[COPR repository](../packaging/copr/README.md) (secret `COPR_CONFIG`).
To prepare a release:
```bash
# 1. Bump the version in Cargo.toml, packaging/PKGBUILD, po/pdfs.pot and the pinned flake
# URL in docs/INSTALL.md, then refresh the lock file.
# 1. Bump the version in Cargo.toml, packaging/PKGBUILD, packaging/proton-drive-linux.spec,
# po/pdfs.pot and the pinned flake URL in docs/INSTALL.md, then refresh the lock file.
cargo update --workspace
# 2. Move the [Unreleased] notes in docs/CHANGELOG.md under the new version.
# 3. Commit, tag and push.
+11
View File
@@ -59,6 +59,17 @@ sudo apt install ./proton-drive-linux_*_amd64.deb
### Fedora (44 or newer)
The [COPR repository](https://copr.fedorainfracloud.org/coprs/narrrl/proton-drive-linux/) builds
every release, so `dnf upgrade` keeps the client up to date:
```bash
sudo dnf copr enable narrrl/proton-drive-linux
sudo dnf install proton-drive-linux
```
The `.rpm` from the release page installs the same files, but you have to download each new
version yourself:
```bash
sudo dnf install ./proton-drive-linux-*.x86_64.rpm
```
+3 -1
View File
@@ -75,7 +75,9 @@ operations, and the client only writes them to its local log.
## Packages
- The `.rpm` is signed with GPG.
- The `.rpm` on the release page is signed with GPG.
- The COPR packages are built by Fedora's COPR service from the tagged source and the vendored
crates of the release, and are signed with the COPR project's own key.
- The `.deb` and the `.tar.gz` are built by GitHub Actions from the tagged source, and are not
signed.
- The AUR packages build from the tagged source or from `main`, or install the release binaries
+43
View File
@@ -0,0 +1,43 @@
# COPR repository
Fedora users install from the COPR project
[`narrrl/proton-drive-linux`](https://copr.fedorainfracloud.org/coprs/narrrl/proton-drive-linux/),
so `dnf upgrade` brings every release. COPR builds `packaging/proton-drive-linux.spec` from two
release assets:
| Source | What it is |
| --- | --- |
| `Source0` | GitHub's archive of the `v<version>` tag |
| `Source1` | `proton-drive-linux-vendor-<version>.tar.xz`: every crate from `Cargo.lock`, made by `cargo vendor` in `release.yml` |
With the vendored crates the build needs no network, so the COPR project keeps network access
off.
## Releasing a new version
`.github/workflows/copr.yml` does this automatically:
- **On a release tag**, `release.yml` calls it after the GitHub release is published. It writes
the version into the spec, downloads both sources with `spectool`, builds a source package
and submits it with `copr-cli build`. The job waits for COPR, so a failed build fails the
release workflow.
- **By hand**, run the workflow from the Actions tab with a version. The release must already
have its vendor tarball.
It needs the `COPR_CONFIG` repository secret: the whole content of `~/.config/copr` from
<https://copr.fedorainfracloud.org/api/>. **The token expires after 180 days.** Renew it on that
page and replace the secret, or the next release's COPR job fails.
To do the same by hand:
```bash
spectool -g -C ~/rpmbuild/SOURCES packaging/proton-drive-linux.spec
rpmbuild -bs packaging/proton-drive-linux.spec
copr-cli build narrrl/proton-drive-linux ~/rpmbuild/SRPMS/proton-drive-linux-*.src.rpm
```
## Project settings
- Chroots: `fedora-44-x86_64`, `fedora-45-x86_64` and `fedora-rawhide-x86_64`. The spec is
`ExclusiveArch: x86_64` and needs `rust >= 1.96`.
- Network access in builds: off.
+39 -16
View File
@@ -1,13 +1,19 @@
# Local in-tree RPM (mirrors packaging/PKGBUILD).
# From the repository root:
# rpmbuild -bb packaging/proton-drive-linux.spec --define "git_dir $PWD" ...
# %build needs network so cargo can fetch crates.io (same trade-off as the Arch PKGBUILD).
# Two ways to build this spec:
#
# - From a checkout (local builds and the release workflow). From the repository root:
# rpmbuild -bb packaging/proton-drive-linux.spec --define "git_dir $PWD" ...
# %build needs network so cargo can fetch crates.io (same trade-off as the Arch PKGBUILD).
# - From the release tarballs (COPR, .github/workflows/copr.yml), when git_dir is not
# defined. Source1 holds every crate, so the build runs offline.
%global debug_package %{nil}
# Match Arch PKGBUILD `!lto` — LTO has broken some GTK/Rust links in practice.
%global _lto_cflags %{nil}
%{!?version: %global version 0.4.0}
%{!?version: %global version 3.5.0}
%global forge https://github.com/narrrl/proton-drive-linux
# Files come from the checkout, or from the unpacked tag archive.
%global src %{?git_dir}%{!?git_dir:.}
Name: proton-drive-linux
Version: %{version}
@@ -16,9 +22,13 @@ Summary: Unofficial Proton Drive client for Linux (FUSE, CLI, GTK4 app +
License: MIT
URL: https://proton-drive.narl.io
ExclusiveArch: x86_64
%if 0%{!?git_dir:1}
Source0: %{forge}/archive/refs/tags/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
Source1: %{forge}/releases/download/v%{version}/%{name}-vendor-%{version}.tar.xz
%endif
BuildRequires: cargo
BuildRequires: rust
BuildRequires: rust >= 1.96
BuildRequires: pkgconf-pkg-config
BuildRequires: fuse3-devel
BuildRequires: gtk4-devel
@@ -57,18 +67,31 @@ block-level caching, a scriptable CLI, and a GTK4/Libadwaita desktop app with
system tray and search launcher. Unofficial and not affiliated with Proton AG.
%prep
# In-tree build: no Source tarball. Pass --define "git_dir /path/to/checkout".
test -n "%{?git_dir}" || (echo 'Pass --define "git_dir $PWD" from the repo root' >&2; exit 1)
%if 0%{?git_dir:1}
# In-tree build: no Source tarball.
test -f %{git_dir}/Cargo.toml
cp -a %{git_dir}/LICENSE .
%else
# -a 1 unpacks the vendored crates into vendor/ inside the source tree.
%autosetup -n %{name}-%{version} -a 1
mkdir -p .cargo
cat > .cargo/config.toml <<'EOF'
[source.crates-io]
replace-with = "vendored-sources"
[source.vendored-sources]
directory = "vendor"
EOF
%endif
%build
# The release workflow has already built target/release and passes --define "prebuilt 1".
# rpmbuild exports its own compiler flags, which would make cargo rebuild everything.
%if 0%{?prebuilt}
test -x %{git_dir}/target/release/pdfs
%else
cd %{git_dir}
cargo build --release --locked \
cd %{src}
cargo build --release %{?git_dir:--locked}%{!?git_dir:--frozen} \
--bin pdfs \
--bin pdfs-tray \
--bin pdfs-app \
@@ -76,21 +99,21 @@ cargo build --release --locked \
%endif
%install
rel=%{git_dir}/target/release
rel=%{src}/target/release
install -D -m0755 "$rel/pdfs" %{buildroot}%{_bindir}/pdfs
install -D -m0755 "$rel/pdfs-tray" %{buildroot}%{_bindir}/pdfs-tray
install -D -m0755 "$rel/pdfs-app" %{buildroot}%{_bindir}/pdfs-app
install -D -m0755 "$rel/pdfs-prompt" %{buildroot}%{_bindir}/pdfs-prompt
install -D -m0644 %{git_dir}/packaging/io.narl.proton-drive-linux.desktop \
install -D -m0644 %{src}/packaging/io.narl.proton-drive-linux.desktop \
%{buildroot}%{_datadir}/applications/io.narl.proton-drive-linux.desktop
install -D -m0644 %{git_dir}/packaging/io.narl.proton-drive-linux-tray.desktop \
install -D -m0644 %{src}/packaging/io.narl.proton-drive-linux-tray.desktop \
%{buildroot}%{_sysconfdir}/xdg/autostart/io.narl.proton-drive-linux-tray.desktop
install -D -m0644 %{git_dir}/packaging/io.narl.proton-drive-linux.svg \
install -D -m0644 %{src}/packaging/io.narl.proton-drive-linux.svg \
%{buildroot}%{_datadir}/icons/hicolor/scalable/apps/io.narl.proton-drive-linux.svg
install -D -m0644 %{git_dir}/packaging/proton-drive.service \
install -D -m0644 %{src}/packaging/proton-drive.service \
%{buildroot}/usr/lib/systemd/user/proton-drive.service
%{git_dir}/po/build.sh %{buildroot}%{_datadir}/locale
%{src}/po/build.sh %{buildroot}%{_datadir}/locale
# Removing the package does not stop a running daemon: it keeps serving the
# mount from the deleted binary, so files deleted under the mount afterwards,