Attempt installer/updating
32
.github/actions/setup-rust/action.yml
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
name: Setup Rust
|
||||
description: Install the Rust toolchain (+ optional targets) and restore the build cache.
|
||||
inputs:
|
||||
target:
|
||||
description: Comma-separated extra target triples to install
|
||||
required: false
|
||||
default: ''
|
||||
save-cache:
|
||||
description: Whether to save the Rust cache
|
||||
required: false
|
||||
default: 'false'
|
||||
restore-cache:
|
||||
description: Whether to restore the Rust cache
|
||||
required: false
|
||||
default: 'true'
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install Rust (stable)
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
targets: ${{ inputs.target }}
|
||||
components: cargo, clippy, rustc, rustfmt
|
||||
|
||||
- name: Cache Rust
|
||||
if: ${{ inputs.restore-cache == 'true' }}
|
||||
uses: Swatinem/rust-cache@master
|
||||
with:
|
||||
key: ${{ inputs.target }}
|
||||
save-if: ${{ inputs.save-cache }}
|
||||
shared-key: release-cache
|
||||
293
.github/workflows/oneclient_release.yml
vendored
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
name: OneClient Release Build
|
||||
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CARGO_PACKAGER_SIGN_PRIVATE_KEY: ${{ secrets.CARGO_PACKAGER_SIGN_PRIVATE_KEY }}
|
||||
CARGO_PACKAGER_SIGN_PRIVATE_KEY_PASSWORD: ${{ secrets.CARGO_PACKAGER_SIGN_PRIVATE_KEY_PASSWORD }}
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
tag: ${{ steps.version.outputs.tag }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Resolve version from Cargo.toml
|
||||
id: version
|
||||
shell: bash
|
||||
run: |
|
||||
VERSION=$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "tag=oneclient-$VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create/ensure draft release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG: ${{ steps.version.outputs.tag }}
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
if ! gh release view "$TAG" >/dev/null 2>&1; then
|
||||
gh release create "$TAG" \
|
||||
--draft \
|
||||
--title "OneClient $VERSION" \
|
||||
--notes "Automated release for OneClient $VERSION."
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
package:
|
||||
needs: prepare
|
||||
permissions:
|
||||
contents: write
|
||||
# Required so SignPath can download the uploaded build artifact.
|
||||
actions: read
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- platform: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
os_key: darwin
|
||||
arch: aarch64
|
||||
formats: app,dmg
|
||||
- platform: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
os_key: darwin
|
||||
arch: x86_64
|
||||
formats: app,dmg
|
||||
- platform: ubuntu-22.04
|
||||
target: ''
|
||||
os_key: linux
|
||||
arch: x86_64
|
||||
formats: deb,appimage
|
||||
- platform: windows-latest
|
||||
target: ''
|
||||
os_key: windows
|
||||
arch: x86_64
|
||||
formats: nsis
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust
|
||||
uses: ./.github/actions/setup-rust
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
save-cache: true
|
||||
restore-cache: true
|
||||
|
||||
- name: (Linux) Install system dependencies
|
||||
if: matrix.platform == 'ubuntu-22.04'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential cmake pkg-config clang python3 \
|
||||
libfontconfig-dev libfreetype-dev \
|
||||
libgl1-mesa-dev libx11-dev libxcursor-dev libxi-dev libxrandr-dev \
|
||||
libxkbcommon-dev libxkbcommon-x11-dev libwayland-dev libdbus-1-dev \
|
||||
libfuse2
|
||||
|
||||
- name: Install cargo-packager
|
||||
shell: bash
|
||||
run: cargo install cargo-packager --version 0.11.8 --locked
|
||||
|
||||
- name: Import Apple Developer certificate
|
||||
if: startsWith(matrix.platform, 'macos')
|
||||
env:
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
run: |
|
||||
echo "$APPLE_CERTIFICATE" | base64 --decode > certificate.p12
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security set-keychain-settings -t 3600 -u build.keychain
|
||||
security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
|
||||
CERT_ID=$(security find-identity -v -p codesigning build.keychain | awk -F'"' '/Developer ID Application/ {print $2; exit}')
|
||||
if [ -z "$CERT_ID" ]; then
|
||||
echo "::error::No Developer ID Application certificate found in keychain."
|
||||
exit 1
|
||||
fi
|
||||
echo "APPLE_SIGNING_IDENTITY=$CERT_ID" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Build release binary
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${{ matrix.target }}" ]; then
|
||||
cargo build --release --bin oneclient_app --target ${{ matrix.target }}
|
||||
else
|
||||
cargo build --release --bin oneclient_app
|
||||
fi
|
||||
|
||||
- name: Package
|
||||
shell: bash
|
||||
env:
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
run: |
|
||||
ARGS="--release --formats ${{ matrix.formats }}"
|
||||
if [ -n "${{ matrix.target }}" ]; then
|
||||
ARGS="$ARGS --target ${{ matrix.target }}"
|
||||
fi
|
||||
cargo packager $ARGS --verbose
|
||||
|
||||
- name: Resolve packager output dir
|
||||
id: outdir
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${{ matrix.target }}" ]; then
|
||||
echo "dir=target/${{ matrix.target }}/release" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "dir=target/release" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: (Windows) Locate installer
|
||||
if: matrix.platform == 'windows-latest'
|
||||
id: win_installer
|
||||
shell: bash
|
||||
run: echo "path=$(ls ${{ steps.outdir.outputs.dir }}/*-setup.exe | head -n1)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: (Windows) Upload unsigned installer artifact
|
||||
if: matrix.platform == 'windows-latest'
|
||||
id: win_upload_unsigned
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: oneclient-windows-installer-unsigned
|
||||
path: ${{ steps.win_installer.outputs.path }}
|
||||
|
||||
- name: (Windows) Submit SignPath signing request
|
||||
if: matrix.platform == 'windows-latest'
|
||||
uses: signpath/github-action-submit-signing-request@v1
|
||||
with:
|
||||
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
|
||||
organization-id: ${{ secrets.SIGNPATH_ORGANIZATION_ID }}
|
||||
project-slug: onelauncher
|
||||
signing-policy-slug: test-signing
|
||||
artifact-configuration-slug: onelauncher-installer
|
||||
github-artifact-id: ${{ steps.win_upload_unsigned.outputs.artifact-id }}
|
||||
wait-for-completion: true
|
||||
output-artifact-directory: signed
|
||||
|
||||
- name: (Windows) Replace installer with signed one + recompute updater sig
|
||||
if: matrix.platform == 'windows-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
signed="$(ls signed/*-setup.exe | head -n1)"
|
||||
# Overwrite the unsigned installer in the packager out dir with the signed exe.
|
||||
cp "$signed" "${{ steps.win_installer.outputs.path }}"
|
||||
# Recompute the updater signature over the SIGNED exe.
|
||||
cargo packager signer sign \
|
||||
--private-key "$CARGO_PACKAGER_SIGN_PRIVATE_KEY" \
|
||||
--password "$CARGO_PACKAGER_SIGN_PRIVATE_KEY_PASSWORD" \
|
||||
"${{ steps.win_installer.outputs.path }}"
|
||||
|
||||
- name: Upload installers and build manifest fragment
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG: ${{ needs.prepare.outputs.tag }}
|
||||
OUT_DIR: ${{ steps.outdir.outputs.dir }}
|
||||
OS_KEY: ${{ matrix.os_key }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
shopt -s nullglob
|
||||
|
||||
# Identify the single updater artifact for this platform (the file with a
|
||||
# sibling .sig): -setup.exe (nsis), *.app.tar.gz (app), *.AppImage.tar.gz (appimage).
|
||||
updater_file=""; fmt=""; ext=""
|
||||
case "$OS_KEY" in
|
||||
windows) updater_file="$(ls "$OUT_DIR"/*-setup.exe | head -n1)"; fmt="nsis"; ext="exe" ;;
|
||||
darwin) updater_file="$(ls "$OUT_DIR"/*.app.tar.gz | head -n1)"; fmt="app"; ext="app.tar.gz" ;;
|
||||
linux) updater_file="$(ls "$OUT_DIR"/*.AppImage.tar.gz 2>/dev/null | head -n1)"; fmt="appimage"; ext="AppImage.tar.gz"
|
||||
if [ -z "$updater_file" ]; then updater_file="$(ls "$OUT_DIR"/*.AppImage | head -n1)"; ext="AppImage"; fi ;;
|
||||
esac
|
||||
|
||||
# The updater bundle isn't always arch-tagged by cargo-packager, so the two
|
||||
# macOS legs would collide on the release. Rename the updater artifact + its .sig
|
||||
# to an arch-unique name before upload, and point the manifest at that name.
|
||||
unique="OneClient_${VERSION}_${OS_KEY}_${ARCH}.${ext}"
|
||||
cp "$updater_file" "$OUT_DIR/$unique"
|
||||
cp "$updater_file.sig" "$OUT_DIR/$unique.sig"
|
||||
|
||||
# Upload human-facing installers (dmg/deb/AppImage/signed exe) + the renamed
|
||||
# updater bundle and its .sig. Skip the un-renamed updater bundle to avoid clashes.
|
||||
for f in "$OUT_DIR"/*.dmg "$OUT_DIR"/*.deb "$OUT_DIR"/*.AppImage "$OUT_DIR"/*-setup.exe "$OUT_DIR/$unique" "$OUT_DIR/$unique.sig"; do
|
||||
[ -e "$f" ] || continue
|
||||
gh release upload "$TAG" "$f" --clobber
|
||||
done
|
||||
|
||||
base="$unique"
|
||||
mkdir -p fragments
|
||||
SIG="$(cat "$updater_file.sig")" \
|
||||
URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/${base}" \
|
||||
FMT="$fmt" \
|
||||
KEY="${OS_KEY}-${ARCH}" \
|
||||
python3 - <<'PY'
|
||||
import json, os
|
||||
frag = {
|
||||
os.environ["KEY"]: {
|
||||
"signature": os.environ["SIG"],
|
||||
"url": os.environ["URL"],
|
||||
"format": os.environ["FMT"],
|
||||
}
|
||||
}
|
||||
with open(f"fragments/{os.environ['KEY']}.json", "w") as f:
|
||||
json.dump(frag, f)
|
||||
PY
|
||||
|
||||
- name: Upload manifest fragment
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: manifest-${{ matrix.os_key }}-${{ matrix.arch }}
|
||||
path: fragments/*.json
|
||||
|
||||
manifest:
|
||||
needs: [prepare, package]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Download all manifest fragments
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: manifest-*
|
||||
path: fragments
|
||||
merge-multiple: true
|
||||
|
||||
- name: Assemble latest.json
|
||||
env:
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import json, glob, os, datetime
|
||||
platforms = {}
|
||||
for path in glob.glob("fragments/*.json"):
|
||||
with open(path) as f:
|
||||
platforms.update(json.load(f))
|
||||
manifest = {
|
||||
"version": os.environ["VERSION"],
|
||||
"pub_date": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
"platforms": platforms,
|
||||
}
|
||||
with open("latest.json", "w") as f:
|
||||
json.dump(manifest, f, indent=2)
|
||||
print(json.dumps(manifest, indent=2))
|
||||
PY
|
||||
|
||||
- name: Upload latest.json to release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG: ${{ needs.prepare.outputs.tag }}
|
||||
run: gh release upload "$TAG" latest.json --clobber
|
||||
|
|
@ -55,6 +55,19 @@ The app crate is `oneclient_app`:
|
|||
After you finish making your changes and committed them to your branch, run
|
||||
`cargo fmt` and `cargo clippy` to fix style inconsistencies and catch lints.
|
||||
|
||||
### Packaging
|
||||
|
||||
Installers are built with [cargo-packager] (config in
|
||||
`packages/oneclient_app/Cargo.toml` under `[package.metadata.packager]`):
|
||||
|
||||
- `cargo install cargo-packager --locked`
|
||||
- `cargo build --release -p oneclient_app`
|
||||
- `cargo packager --release -p oneclient_app --formats <nsis|app,dmg|deb,appimage>`
|
||||
|
||||
Releases are cut by dispatching the `OneClient Release Build` GitHub Actions
|
||||
workflow. See the **Packaging / Releasing** section of the [README] for details
|
||||
and per-OS prerequisites.
|
||||
|
||||
### Pull Request
|
||||
|
||||
Once you have finished making your changes, create a pull request (PR) to submit them.
|
||||
|
|
@ -84,6 +97,7 @@ Run `xcode-select --install` in the terminal to install them. If they are alread
|
|||
|
||||
This CONTRIBUTING.md file was inspired by the [`github/docs` CONTRIBUTING.md] file, and we extend our gratitude to the original authors.
|
||||
|
||||
[cargo-packager]: https://github.com/crabnebula-dev/cargo-packager
|
||||
[Skia]: https://skia.org/
|
||||
[Freya setup guide]: https://book.freyaui.dev/setup.html
|
||||
[`cargo`]: https://doc.rust-lang.org/cargo/getting-started/installation.html
|
||||
|
|
|
|||
265
Cargo.lock
generated
|
|
@ -931,6 +931,42 @@ dependencies = [
|
|||
"wayland-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-packager-updater"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eec09acab5c2227aba2e592d431708305bdeb6d507703f6cd8983fb57b6c5ef7"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"cargo-packager-utils",
|
||||
"ctor 0.2.9",
|
||||
"dirs",
|
||||
"dunce",
|
||||
"flate2",
|
||||
"http",
|
||||
"log",
|
||||
"minisign-verify",
|
||||
"percent-encoding",
|
||||
"reqwest 0.12.28",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tar",
|
||||
"tempfile",
|
||||
"thiserror 1.0.69",
|
||||
"time",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-packager-utils"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b43458dd2ee3cdab3f5b105acd80791383b730380c929018701313d7d299d4e8"
|
||||
dependencies = [
|
||||
"ctor 0.2.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.63"
|
||||
|
|
@ -1304,6 +1340,16 @@ dependencies = [
|
|||
"hybrid-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.10.1"
|
||||
|
|
@ -1346,6 +1392,12 @@ version = "0.1.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac6b926516df9c60bfa16e107b21086399f8285a44ca9711344b9e553c5146e2"
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
|
|
@ -1373,7 +1425,28 @@ version = "6.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
"dirs-sys 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
dependencies = [
|
||||
"dirs-sys 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.4.6",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1384,7 +1457,7 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"redox_users 0.5.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
|
|
@ -2606,6 +2679,7 @@ dependencies = [
|
|||
"hyper",
|
||||
"hyper-util",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower-service",
|
||||
|
|
@ -3359,6 +3433,12 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "minisign-verify"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
|
|
@ -3530,6 +3610,12 @@ dependencies = [
|
|||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.4.2"
|
||||
|
|
@ -4020,6 +4106,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"arboard",
|
||||
"bytes 1.11.1",
|
||||
"cargo-packager-updater",
|
||||
"chrono",
|
||||
"freya",
|
||||
"freya-skia-safe",
|
||||
|
|
@ -4064,7 +4151,7 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"polyio",
|
||||
"rand 0.10.1",
|
||||
"reqwest",
|
||||
"reqwest 0.13.3",
|
||||
"sanitize-filename",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -4379,6 +4466,12 @@ dependencies = [
|
|||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
|
|
@ -4757,6 +4850,17 @@ dependencies = [
|
|||
"bitflags 2.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
||||
dependencies = [
|
||||
"getrandom 0.2.17",
|
||||
"libredox",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.2"
|
||||
|
|
@ -4797,6 +4901,48 @@ version = "0.8.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes 1.11.1",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-rustls",
|
||||
"hyper-util",
|
||||
"js-sys",
|
||||
"log",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-streams 0.4.2",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.13.3"
|
||||
|
|
@ -4841,7 +4987,7 @@ dependencies = [
|
|||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"wasm-streams 0.5.0",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
|
|
@ -5868,6 +6014,36 @@ dependencies = [
|
|||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde_core",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia"
|
||||
version = "0.11.4"
|
||||
|
|
@ -5900,7 +6076,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "a90a0ca3ee6a69f2ad28fd11621a4c3f03b371f366be500b64df260c4ffbafb4"
|
||||
dependencies = [
|
||||
"as-raw-xcb-connection",
|
||||
"ctor",
|
||||
"ctor 0.10.1",
|
||||
"libloading",
|
||||
"pkg-config",
|
||||
"tracing",
|
||||
|
|
@ -6538,6 +6714,19 @@ dependencies = [
|
|||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
version = "0.5.0"
|
||||
|
|
@ -6950,6 +7139,15 @@ dependencies = [
|
|||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
|
|
@ -6977,6 +7175,21 @@ dependencies = [
|
|||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
|
|
@ -7019,6 +7232,12 @@ dependencies = [
|
|||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
|
|
@ -7031,6 +7250,12 @@ version = "0.53.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
|
|
@ -7043,6 +7268,12 @@ version = "0.53.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
|
|
@ -7067,6 +7298,12 @@ version = "0.53.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
|
|
@ -7079,6 +7316,12 @@ version = "0.53.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
|
|
@ -7091,6 +7334,12 @@ version = "0.53.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
|
|
@ -7103,6 +7352,12 @@ version = "0.53.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
|
|
|
|||
16
README.md
|
|
@ -35,6 +35,22 @@ cargo run -p oneclient_app
|
|||
cargo build --release -p oneclient_app
|
||||
```
|
||||
|
||||
### Packaging / Releasing
|
||||
|
||||
Installers are produced with [**cargo-packager**](https://github.com/crabnebula-dev/cargo-packager)
|
||||
(the standalone bundler spun out of the Tauri bundler). Config lives in
|
||||
[`packages/oneclient_app/Cargo.toml`](./packages/oneclient_app/Cargo.toml) under
|
||||
`[package.metadata.packager]`.
|
||||
|
||||
```sh
|
||||
cargo install cargo-packager --locked
|
||||
|
||||
# Build the binary, then bundle it for the current OS:
|
||||
cargo build --release -p oneclient_app
|
||||
cargo packager --release -p oneclient_app --formats <targets>
|
||||
# Windows: nsis macOS: app,dmg Linux: deb,appimage
|
||||
```
|
||||
|
||||
### Versioning
|
||||
|
||||
The workspace shares a single version, defined in the root [`Cargo.toml`](./Cargo.toml)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ sysinfo.workspace = true
|
|||
anyhow.workspace = true
|
||||
regex.workspace = true
|
||||
|
||||
cargo-packager-updater = "=0.2.3"
|
||||
|
||||
# file dialog
|
||||
rfd = "=0.17.2"
|
||||
|
||||
|
|
@ -48,3 +50,43 @@ mimalloc = "=0.1.52"
|
|||
|
||||
[patch.crates-io]
|
||||
freya = { git = "https://github.com/marc2332/freya.git", branch = "fix/blur" }
|
||||
# Build then package (per OS):
|
||||
# cargo build --release -p oneclient_app
|
||||
# cargo packager --release -p oneclient_app --formats <nsis|app,dmg|deb,appimage>
|
||||
[package.metadata.packager]
|
||||
product-name = "OneClient"
|
||||
identifier = "org.polyfrost.OneClient"
|
||||
category = "Game"
|
||||
publisher = "Polyfrost"
|
||||
copyright = "© 2026 Polyfrost Inc."
|
||||
homepage = "https://polyfrost.org/projects/oneclient"
|
||||
license-file = "../../LICENSE"
|
||||
long-description = "Next-generation open source Minecraft launcher"
|
||||
formats = ["nsis", "app", "dmg", "deb", "appimage"]
|
||||
binaries = [{ path = "oneclient_app", main = true }]
|
||||
icons = [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico",
|
||||
]
|
||||
|
||||
[package.metadata.packager.macos]
|
||||
minimum-system-version = "10.15"
|
||||
entitlements = "distribution/App.entitlements"
|
||||
|
||||
[package.metadata.packager.dmg]
|
||||
app-position = { x = 190, y = 190 }
|
||||
app-folder-position = { x = 470, y = 190 }
|
||||
|
||||
[package.metadata.packager.windows]
|
||||
digest-algorithm = "sha256"
|
||||
timestamp-url = "https://timestamp.digicert.com"
|
||||
|
||||
[package.metadata.packager.deb]
|
||||
desktop-template = "distribution/linux/org.polyfrost.oneclient.template"
|
||||
|
||||
[package.metadata.packager.appimage]
|
||||
# desktop entry generated from the deb template above via the linux config
|
||||
|
||||
|
|
|
|||
18
packages/oneclient_app/distribution/App.entitlements
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<!-- allows us to load minecraft libraries -->
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
<!-- allows us to set DYLD_FALLBACK_LIBRARY_PATH set by cargo which breaks minecraft -->
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
<!-- allows us to request microphone permissions (for things like voice chat) -->
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<!-- allows us to request camera permissions (for things like voice chat) -->
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
[Desktop Entry]
|
||||
Name=OneClient
|
||||
Comment=Next-generation open source Minecraft launcher
|
||||
Exec={{exec}}
|
||||
Icon={{icon}}
|
||||
Type=Application
|
||||
Terminal=false
|
||||
StartupNotify=true
|
||||
Categories=Game;ActionGame;AdventureGame;Simulation;
|
||||
Keywords=mc;minecraft;game
|
||||
StartupWMClass={{exec}}
|
||||
Version=1.4
|
||||
BIN
packages/oneclient_app/icons/128x128.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
packages/oneclient_app/icons/128x128@2x.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
packages/oneclient_app/icons/32x32.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
packages/oneclient_app/icons/512x512.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
packages/oneclient_app/icons/StoreLogo.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
packages/oneclient_app/icons/icon.icns
Normal file
BIN
packages/oneclient_app/icons/icon.ico
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
packages/oneclient_app/icons/icon.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
|
|
@ -10,6 +10,7 @@ mod notifications;
|
|||
pub mod platform;
|
||||
mod routes;
|
||||
pub mod theme;
|
||||
pub mod updater;
|
||||
mod ui;
|
||||
pub(crate) mod utils;
|
||||
mod view;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ fn main() {
|
|||
oneclient_core::logger::init()
|
||||
}.expect("Failed to initialize logger");
|
||||
|
||||
oneclient_app::updater::spawn_update_check(settings.auto_update);
|
||||
|
||||
let (bridge, handle): (OneClientBridge, CoreBridgeHandle) = OneClientBridge::new();
|
||||
handle.spawn_runtime();
|
||||
|
||||
|
|
|
|||
42
packages/oneclient_app/src/updater.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
//! In-app self-update via [`cargo-packager-updater`].
|
||||
|
||||
use cargo_packager_updater::{Config, check_update};
|
||||
|
||||
pub const UPDATER_PUBKEY: &str = "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDFGODk3MkMyMjg0MjFDMDUKUldRRkhFSW93bktKSHpkWjNEMXNzaDVINVpCTU8xSnhuK2RnV0dTZ2FkcFJWbG1zUkhGYTNjaUkK";
|
||||
|
||||
pub const UPDATER_ENDPOINT: &str =
|
||||
"https://github.com/Polyfrost/OneLauncher/releases/latest/download/latest.json";
|
||||
|
||||
pub fn spawn_update_check(auto_install: bool) {
|
||||
std::thread::Builder::new()
|
||||
.name("oneclient-updater".into())
|
||||
.spawn(move || {
|
||||
if let Err(err) = run_check(auto_install) {
|
||||
tracing::warn!("update check failed: {err}");
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
||||
fn run_check(auto_install: bool) -> anyhow::Result<()> {
|
||||
let current = env!("CARGO_PKG_VERSION").parse()?;
|
||||
let config = Config {
|
||||
endpoints: vec![UPDATER_ENDPOINT.parse()?],
|
||||
pubkey: UPDATER_PUBKEY.into(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
match check_update(current, config)? {
|
||||
Some(update) => {
|
||||
tracing::info!("update available: {}", update.version);
|
||||
if auto_install {
|
||||
tracing::info!("downloading and installing update…");
|
||||
update.download_and_install()?;
|
||||
tracing::info!("update installed; restart to apply");
|
||||
}
|
||||
}
|
||||
None => tracing::info!("no update available"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ pub struct ViewState {
|
|||
pub struct LauncherSettings {
|
||||
pub settings_version: u32,
|
||||
pub log_debug: bool,
|
||||
pub auto_update: bool,
|
||||
pub enable_gamemode: bool,
|
||||
pub discord_enabled: bool,
|
||||
pub max_concurrent_requests: usize,
|
||||
|
|
@ -55,6 +56,7 @@ impl Default for LauncherSettings {
|
|||
Self {
|
||||
settings_version: 1,
|
||||
log_debug: false,
|
||||
auto_update: true,
|
||||
discord_enabled: true,
|
||||
enable_gamemode: false,
|
||||
max_concurrent_requests: 25,
|
||||
|
|
|
|||