mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 02:29:55 +02:00
ci: build Linux release packages
This commit is contained in:
84
packaging/linux/README.md
Normal file
84
packaging/linux/README.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# Linux packaging
|
||||
|
||||
VniDrop ships native x64 packages for the two common Linux package families:
|
||||
|
||||
- Debian/Ubuntu: `.deb`
|
||||
- Current Fedora systems: `.rpm`
|
||||
|
||||
Both packages contain the application, its release Rust library, and a private
|
||||
Java runtime. Users do not need to install Java separately. The packages are
|
||||
currently distributed as direct GitHub Release downloads, so they use SHA-256
|
||||
checksums rather than a Linux repository signing key. A future APT or RPM
|
||||
repository should add repository metadata signing and its own update channel.
|
||||
|
||||
## GitHub Actions
|
||||
|
||||
The Linux packages workflow runs for relevant pull requests, release tags
|
||||
matching `vMAJOR.MINOR.PATCH`, and manual dispatches. Each native package is
|
||||
built and validated on its matching distribution family:
|
||||
|
||||
- `.deb` on Ubuntu 22.04 for a conservative glibc baseline
|
||||
- `.rpm` inside Fedora 43 so `jpackage` can discover normal RPM dependencies
|
||||
|
||||
The shared JVM suite runs inside the Debian build job. Package construction and
|
||||
payload validation happen in both build jobs, so there is no separate test
|
||||
runner. Pull requests build and verify both packages but do not retain
|
||||
artifacts. Manual runs retain build artifacts for 14 days. A pushed version tag
|
||||
whose commit is on `master` creates the matching GitHub Release with the `.deb`,
|
||||
`.rpm`, and a combined `SHA256SUMS`.
|
||||
|
||||
The existing `v1.0.0` tag predates this workflow and will not run it
|
||||
retroactively. Use the next version tag after this configuration reaches
|
||||
`master`.
|
||||
|
||||
## Install a downloaded package
|
||||
|
||||
Verify downloads from the directory containing all three release files:
|
||||
|
||||
```bash
|
||||
sha256sum -c SHA256SUMS
|
||||
```
|
||||
|
||||
On Debian or Ubuntu:
|
||||
|
||||
```bash
|
||||
sudo apt install ./vnidrop_VERSION-1_amd64.deb
|
||||
```
|
||||
|
||||
On Fedora:
|
||||
|
||||
```bash
|
||||
sudo dnf install ./vnidrop-VERSION-1.x86_64.rpm
|
||||
```
|
||||
|
||||
The package manager installs declared system-library dependencies and creates
|
||||
the VniDrop desktop launcher. Uninstall with `sudo apt remove vnidrop` or
|
||||
`sudo dnf remove vnidrop`.
|
||||
|
||||
## Manual native builds
|
||||
|
||||
Use JDK 21 and Rust 1.91. Build DEB packages on Debian/Ubuntu with `dpkg` and
|
||||
`fakeroot`; build RPM packages on Fedora with `rpm-build`. Building an RPM on
|
||||
Ubuntu prevents `jpackage` from discovering normal RPM dependencies.
|
||||
|
||||
From the repository root on the matching Linux family, run one of:
|
||||
|
||||
```bash
|
||||
./gradlew :shared:jvmTest :desktopApp:packageReleaseDeb \
|
||||
-Pvnidrop.version=1.0.0 \
|
||||
-Pvnidrop.desktop.rustVariant=release \
|
||||
-Pvnidrop.diagnostics.included=false \
|
||||
--no-daemon --no-configuration-cache --stacktrace
|
||||
|
||||
./gradlew :shared:jvmTest :desktopApp:packageReleaseRpm \
|
||||
-Pvnidrop.version=1.0.0 \
|
||||
-Pvnidrop.desktop.rustVariant=release \
|
||||
-Pvnidrop.diagnostics.included=false \
|
||||
--no-daemon --no-configuration-cache --stacktrace
|
||||
```
|
||||
|
||||
Compose writes the packages under
|
||||
`desktopApp/build/compose/binaries/main-release/deb/` and
|
||||
`desktopApp/build/compose/binaries/main-release/rpm/`. The workflow then
|
||||
validates package identity, version, architecture, dependencies, bundled JVM,
|
||||
and release Rust payload before publishing anything.
|
||||
39
packaging/linux/resolve-version.sh
Executable file
39
packaging/linux/resolve-version.sh
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
version=${1:-1.0.0}
|
||||
|
||||
if [[ ${GITHUB_REF_TYPE:-} == "tag" ]]; then
|
||||
if [[ ! ${GITHUB_REF_NAME:-} =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Linux release tags must use vMAJOR.MINOR.PATCH" >&2
|
||||
exit 1
|
||||
fi
|
||||
version=${GITHUB_REF_NAME#v}
|
||||
fi
|
||||
|
||||
if [[ ! $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Version must use MAJOR.MINOR.PATCH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IFS=. read -r major minor patch <<< "$version"
|
||||
parts=("$major" "$minor" "$patch")
|
||||
|
||||
for index in "${!parts[@]}"; do
|
||||
part=${parts[$index]}
|
||||
if [[ $part != "0" && $part == 0* ]]; then
|
||||
echo "Version components must be canonical integers without leading zeroes" >&2
|
||||
exit 1
|
||||
fi
|
||||
if (( ${#part} > 5 )) || (( 10#$part > 65535 )); then
|
||||
echo "Version components must be between 0 and 65535" >&2
|
||||
exit 1
|
||||
fi
|
||||
if (( index == 0 && 10#$part == 0 )); then
|
||||
echo "The major version must be non-zero" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
printf '%s\n' "$version"
|
||||
96
packaging/linux/verify-package.sh
Executable file
96
packaging/linux/verify-package.sh
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if (( $# != 3 )); then
|
||||
echo "Usage: $0 <deb|rpm> <MAJOR.MINOR.PATCH> <package-path>" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
format=$1
|
||||
version=$2
|
||||
package_path=$3
|
||||
|
||||
fail() {
|
||||
echo "Package verification failed: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
require_command() {
|
||||
command -v "$1" >/dev/null 2>&1 || fail "required command '$1' is not installed"
|
||||
}
|
||||
|
||||
[[ -f $package_path ]] || fail "package not found: $package_path"
|
||||
require_command find
|
||||
require_command unzip
|
||||
|
||||
extract_root=$(mktemp -d)
|
||||
trap 'rm -rf "$extract_root"' EXIT
|
||||
|
||||
case $format in
|
||||
deb)
|
||||
require_command dpkg-deb
|
||||
[[ $(dpkg-deb -f "$package_path" Package) == "vnidrop" ]] || fail "unexpected Debian package name"
|
||||
[[ $(dpkg-deb -f "$package_path" Version) == "$version-1" ]] || fail "unexpected Debian package version"
|
||||
[[ $(dpkg-deb -f "$package_path" Architecture) == "amd64" ]] || fail "unexpected Debian architecture"
|
||||
[[ $(dpkg-deb -f "$package_path" Maintainer) == *"support@sudosy.fr"* ]] || fail "unexpected Debian maintainer"
|
||||
deb_dependencies=$(dpkg-deb -f "$package_path" Depends)
|
||||
deb_libc_pattern='(^|,[[:space:]])libc6([[:space:](]|,|$)'
|
||||
deb_xdg_pattern='(^|,[[:space:]])xdg-utils([[:space:](]|,|$)'
|
||||
[[ $deb_dependencies =~ $deb_libc_pattern ]] || fail "Debian package does not declare libc6"
|
||||
[[ $deb_dependencies =~ $deb_xdg_pattern ]] || fail "Debian package does not declare xdg-utils"
|
||||
dpkg-deb -x "$package_path" "$extract_root"
|
||||
;;
|
||||
rpm)
|
||||
require_command rpm
|
||||
require_command rpm2cpio
|
||||
require_command cpio
|
||||
metadata=$(rpm -qp --queryformat '%{NAME}\n%{VERSION}\n%{RELEASE}\n%{ARCH}\n%{LICENSE}\n' "$package_path")
|
||||
mapfile -t fields <<< "$metadata"
|
||||
[[ ${fields[0]:-} == "vnidrop" ]] || fail "unexpected RPM package name"
|
||||
[[ ${fields[1]:-} == "$version" ]] || fail "unexpected RPM package version"
|
||||
[[ ${fields[2]:-} == "1" ]] || fail "unexpected RPM release"
|
||||
[[ ${fields[3]:-} == "x86_64" ]] || fail "unexpected RPM architecture"
|
||||
[[ ${fields[4]:-} == "Apache-2.0" ]] || fail "unexpected RPM license"
|
||||
mapfile -t runtime_requirements < <(rpm -qpR "$package_path" | grep -Ev '^(rpmlib\(|/bin/sh$)' || true)
|
||||
printf '%s\n' "${runtime_requirements[@]}" | grep -Eq '^(glibc($|[[:space:]])|libc\.so\.6)' || fail "RPM package does not declare glibc"
|
||||
printf '%s\n' "${runtime_requirements[@]}" | grep -Fxq 'xdg-utils' || fail "RPM package does not declare xdg-utils"
|
||||
rpm2cpio "$package_path" | (
|
||||
cd "$extract_root"
|
||||
cpio -idm --quiet
|
||||
)
|
||||
;;
|
||||
*)
|
||||
fail "unsupported package format: $format"
|
||||
;;
|
||||
esac
|
||||
|
||||
mapfile -d '' -t launchers < <(find "$extract_root" -type f -iname 'vnidrop' -perm /111 -print0)
|
||||
(( ${#launchers[@]} == 1 )) || fail "expected exactly one executable VniDrop launcher"
|
||||
|
||||
mapfile -d '' -t desktop_entries < <(find "$extract_root" -type f -name '*.desktop' -print0)
|
||||
(( ${#desktop_entries[@]} == 1 )) || fail "expected exactly one desktop entry"
|
||||
grep -Eiq '^Exec=.*/VniDrop([[:space:]]|$)' "${desktop_entries[0]}" || fail "desktop entry does not launch VniDrop"
|
||||
grep -Eq '^MimeType=.*application/vnd\.vnidrop\.transfer(;|$)' "${desktop_entries[0]}" || fail "desktop entry does not register VniDrop invitations"
|
||||
|
||||
mapfile -d '' -t bundled_jvms < <(find "$extract_root" -type f -path '*/lib/runtime/lib/server/libjvm.so' -print0)
|
||||
(( ${#bundled_jvms[@]} == 1 )) || fail "expected exactly one bundled JVM"
|
||||
|
||||
mapfile -d '' -t debug_rust_jars < <(find "$extract_root" -type f -name 'shared-linux-x86-64-debug-*.jar' -print0)
|
||||
(( ${#debug_rust_jars[@]} == 0 )) || fail "package contains a debug Rust runtime JAR"
|
||||
|
||||
mapfile -d '' -t rust_jars < <(
|
||||
find "$extract_root" -type f -name 'shared-linux-x86-64-*.jar' ! -name 'shared-linux-x86-64-debug-*.jar' -print0
|
||||
)
|
||||
(( ${#rust_jars[@]} == 1 )) || fail "expected exactly one release Rust runtime JAR"
|
||||
|
||||
native_entry_size=$(unzip -p "${rust_jars[0]}" 'linux-x86-64/libvnidrop.so' | wc -c)
|
||||
[[ $native_entry_size =~ ^[0-9]+$ ]] || fail "release Rust runtime JAR does not contain libvnidrop.so"
|
||||
(( native_entry_size > 0 )) || fail "release Rust runtime JAR contains an empty libvnidrop.so"
|
||||
|
||||
mapfile -d '' -t shared_jars < <(find "$extract_root" -type f -name 'shared-jvm-*.jar' -print0)
|
||||
(( ${#shared_jars[@]} == 1 )) || fail "expected exactly one shared JVM JAR"
|
||||
unzip -p "${shared_jars[0]}" META-INF/MANIFEST.MF | tr -d '\r' |
|
||||
grep -Fxq "Implementation-Version: $version" || fail "packaged app version does not match $version"
|
||||
|
||||
printf 'Verified %s package: %s\n' "$format" "$package_path"
|
||||
Reference in New Issue
Block a user