mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 10:29:58 +02:00
Merge pull request #19 from sudosylabs/feat/linux-release
ci: build Linux release packages
This commit is contained in:
344
.github/workflows/linux-packages.yml
vendored
Normal file
344
.github/workflows/linux-packages.yml
vendored
Normal file
@@ -0,0 +1,344 @@
|
||||
name: Linux packages
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/linux-packages.yml"
|
||||
- "packaging/linux/**"
|
||||
- "assets/linux/**"
|
||||
- "desktopApp/**"
|
||||
- "shared/**"
|
||||
- "crates/vnidrop/**"
|
||||
- "Cargo.toml"
|
||||
- "Cargo.lock"
|
||||
- "LICENSE"
|
||||
- "build.gradle.kts"
|
||||
- "settings.gradle.kts"
|
||||
- "gradle.properties"
|
||||
- "gradle/**"
|
||||
- "gradlew"
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: Release version in MAJOR.MINOR.PATCH form
|
||||
required: true
|
||||
default: "1.0.0"
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: linux-packages-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
build-deb:
|
||||
name: Build Debian package (x64)
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install packaging tools
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes fakeroot unzip
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10.0.LTS"
|
||||
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||
|
||||
- name: Set up Rust 1.91
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # v1
|
||||
with:
|
||||
toolchain: "1.91.0"
|
||||
|
||||
- name: Cache Cargo
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: linux-deb-x64-cargo-1.91.0-${{ hashFiles('Cargo.lock') }}
|
||||
restore-keys: |
|
||||
linux-deb-x64-cargo-1.91.0-
|
||||
|
||||
- name: Resolve version
|
||||
id: version
|
||||
env:
|
||||
REQUESTED_VERSION: ${{ inputs.version || '1.0.0' }}
|
||||
run: |
|
||||
version=$(packaging/linux/resolve-version.sh "$REQUESTED_VERSION")
|
||||
echo "app=$version" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Test and build Debian package
|
||||
run: |
|
||||
./gradlew \
|
||||
:shared:jvmTest \
|
||||
:desktopApp:packageReleaseDeb \
|
||||
-Pvnidrop.version=${{ steps.version.outputs.app }} \
|
||||
-Pvnidrop.desktop.rustVariant=release \
|
||||
-Pvnidrop.diagnostics.included=false \
|
||||
--no-daemon \
|
||||
--no-configuration-cache \
|
||||
--stacktrace
|
||||
|
||||
- name: Validate Debian package
|
||||
id: package
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.app }}
|
||||
run: |
|
||||
mapfile -t packages < <(find desktopApp/build/compose/binaries/main-release/deb -maxdepth 1 -type f -name '*.deb')
|
||||
if (( ${#packages[@]} != 1 )); then
|
||||
echo "Expected exactly one Debian package, found ${#packages[@]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
output_directory=build/release/linux/deb
|
||||
output_name="vnidrop_${VERSION}-1_amd64.deb"
|
||||
mkdir -p "$output_directory"
|
||||
cp "${packages[0]}" "$output_directory/$output_name"
|
||||
packaging/linux/verify-package.sh deb "$VERSION" "$output_directory/$output_name"
|
||||
(
|
||||
cd "$output_directory"
|
||||
sha256sum "$output_name" > "$output_name.sha256"
|
||||
)
|
||||
|
||||
- name: Upload Debian artifact
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: vnidrop-${{ steps.version.outputs.app }}-linux-deb-x64
|
||||
path: build/release/linux/deb/
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
compression-level: 0
|
||||
|
||||
- name: Summarize Debian package
|
||||
run: |
|
||||
echo "### Debian package" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "- Version: ${{ steps.version.outputs.app }}-1" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "- Architecture: amd64" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "- Build baseline: Ubuntu 22.04" >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
build-rpm:
|
||||
name: Build RPM package (x64)
|
||||
runs-on: ubuntu-24.04
|
||||
container:
|
||||
image: registry.fedoraproject.org/fedora:43
|
||||
volumes:
|
||||
- /usr/local/lib/android/sdk:/usr/local/lib/android/sdk
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
ANDROID_HOME: /usr/local/lib/android/sdk
|
||||
ANDROID_SDK_ROOT: /usr/local/lib/android/sdk
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
steps:
|
||||
- name: Install build and packaging tools
|
||||
run: |
|
||||
dnf install --assumeyes \
|
||||
alsa-lib \
|
||||
cpio \
|
||||
curl \
|
||||
cups-libs \
|
||||
desktop-file-utils \
|
||||
findutils \
|
||||
fontconfig \
|
||||
freetype \
|
||||
gcc \
|
||||
gcc-c++ \
|
||||
git \
|
||||
gzip \
|
||||
gtk3 \
|
||||
libX11 \
|
||||
libXext \
|
||||
libXi \
|
||||
libXrandr \
|
||||
libXrender \
|
||||
libXtst \
|
||||
make \
|
||||
mesa-libGL \
|
||||
rpm-build \
|
||||
tar \
|
||||
unzip \
|
||||
which \
|
||||
xz \
|
||||
zstd
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: "21.0.11+10.0.LTS"
|
||||
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||
|
||||
- name: Set up Rust 1.91
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # v1
|
||||
with:
|
||||
toolchain: "1.91.0"
|
||||
|
||||
- name: Cache Cargo
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: linux-rpm-x64-cargo-1.91.0-${{ hashFiles('Cargo.lock') }}
|
||||
restore-keys: |
|
||||
linux-rpm-x64-cargo-1.91.0-
|
||||
|
||||
- name: Resolve version
|
||||
id: version
|
||||
env:
|
||||
REQUESTED_VERSION: ${{ inputs.version || '1.0.0' }}
|
||||
run: |
|
||||
version=$(packaging/linux/resolve-version.sh "$REQUESTED_VERSION")
|
||||
echo "app=$version" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build RPM package
|
||||
run: |
|
||||
./gradlew \
|
||||
:desktopApp:packageReleaseRpm \
|
||||
-Pvnidrop.version=${{ steps.version.outputs.app }} \
|
||||
-Pvnidrop.desktop.rustVariant=release \
|
||||
-Pvnidrop.diagnostics.included=false \
|
||||
--no-daemon \
|
||||
--no-configuration-cache \
|
||||
--stacktrace
|
||||
|
||||
- name: Validate RPM package
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.app }}
|
||||
run: |
|
||||
mapfile -t packages < <(find desktopApp/build/compose/binaries/main-release/rpm -maxdepth 1 -type f -name '*.rpm')
|
||||
if (( ${#packages[@]} != 1 )); then
|
||||
echo "Expected exactly one RPM package, found ${#packages[@]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
output_directory=build/release/linux/rpm
|
||||
output_name="vnidrop-${VERSION}-1.x86_64.rpm"
|
||||
mkdir -p "$output_directory"
|
||||
cp "${packages[0]}" "$output_directory/$output_name"
|
||||
packaging/linux/verify-package.sh rpm "$VERSION" "$output_directory/$output_name"
|
||||
(
|
||||
cd "$output_directory"
|
||||
sha256sum "$output_name" > "$output_name.sha256"
|
||||
)
|
||||
|
||||
- name: Upload RPM artifact
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: vnidrop-${{ steps.version.outputs.app }}-linux-rpm-x64
|
||||
path: build/release/linux/rpm/
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
compression-level: 0
|
||||
|
||||
- name: Summarize RPM package
|
||||
run: |
|
||||
echo "### RPM package" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "- Version: ${{ steps.version.outputs.app }}-1" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "- Architecture: x86_64" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "- Build environment: Fedora 43" >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
publish-release:
|
||||
name: Publish GitHub Release assets
|
||||
if: github.event_name == 'push' && github.ref_type == 'tag'
|
||||
needs:
|
||||
- build-deb
|
||||
- build-rpm
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 15
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout release history
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Verify tag is on master
|
||||
run: |
|
||||
if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/master; then
|
||||
echo "Release tags must point to a commit on master" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Download Linux artifacts
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
pattern: vnidrop-*-linux-*-x64
|
||||
path: build/release/linux
|
||||
merge-multiple: true
|
||||
|
||||
- name: Verify artifacts and checksums
|
||||
run: |
|
||||
cd build/release/linux
|
||||
shopt -s nullglob
|
||||
deb_packages=(*.deb)
|
||||
rpm_packages=(*.rpm)
|
||||
checksum_files=(*.sha256)
|
||||
if (( ${#deb_packages[@]} != 1 || ${#rpm_packages[@]} != 1 || ${#checksum_files[@]} != 2 )); then
|
||||
echo "Expected one DEB, one RPM, and two checksum sidecars" >&2
|
||||
exit 1
|
||||
fi
|
||||
version=${GITHUB_REF_NAME#v}
|
||||
if [[ ${deb_packages[0]} != "vnidrop_${version}-1_amd64.deb" || ${rpm_packages[0]} != "vnidrop-${version}-1.x86_64.rpm" ]]; then
|
||||
echo "Downloaded package names do not match tag $GITHUB_REF_NAME" >&2
|
||||
exit 1
|
||||
fi
|
||||
sha256sum --check "${checksum_files[@]}"
|
||||
sha256sum "${deb_packages[@]}" "${rpm_packages[@]}" > SHA256SUMS
|
||||
rm -- "${checksum_files[@]}"
|
||||
|
||||
- name: Publish GitHub Release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
run: |
|
||||
tag=${GITHUB_REF_NAME}
|
||||
version=${tag#v}
|
||||
if gh release view "$tag" >/dev/null 2>&1; then
|
||||
echo "GitHub Release $tag already exists; refusing to replace its assets" >&2
|
||||
exit 1
|
||||
fi
|
||||
gh release create "$tag" \
|
||||
build/release/linux/*.deb \
|
||||
build/release/linux/*.rpm \
|
||||
build/release/linux/SHA256SUMS \
|
||||
--verify-tag \
|
||||
--title "VniDrop $version" \
|
||||
--generate-notes
|
||||
@@ -37,11 +37,12 @@ compose.desktop {
|
||||
buildTypes.release.proguard.isEnabled.set(false)
|
||||
|
||||
nativeDistributions {
|
||||
targetFormats(TargetFormat.Dmg, TargetFormat.Deb)
|
||||
targetFormats(TargetFormat.Dmg, TargetFormat.Deb, TargetFormat.Rpm)
|
||||
packageName = "VniDrop"
|
||||
packageVersion = appVersion
|
||||
description = "Send files directly across your devices"
|
||||
vendor = "Sudosy Labs"
|
||||
licenseFile.set(project.file("../LICENSE"))
|
||||
macOS {
|
||||
bundleID = "com.vnidrop.app"
|
||||
iconFile.set(project.file("../assets/macos/app-icon.icns"))
|
||||
@@ -52,6 +53,9 @@ compose.desktop {
|
||||
linux {
|
||||
packageName = "vnidrop"
|
||||
iconFile.set(project.file("../assets/linux/app-icon.png"))
|
||||
debMaintainer = "support@sudosy.fr"
|
||||
appRelease = "1"
|
||||
rpmLicenseType = "Apache-2.0"
|
||||
}
|
||||
fileAssociation(
|
||||
mimeType = "application/vnd.vnidrop.transfer",
|
||||
|
||||
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