Files
BikeControl/scripts/build-arch.sh
T
dtourolleandClaude Opus 5 57eb5e809b Virtual gearing, trainer-speed blend, and cadence decode
Gears are expressed as an offset to the commanded gradient, leaving the
physics on the route's true gradient so shifting changes effort, not speed.
Neutral gear commands exactly the route gradient, so an un-shifted ride is
unchanged.

Cadence is not in FTMS on this trainer but is on its Zwift channel, decoded
against captured frames. The undeclared FTMS trailing bytes were ruled out:
wheel RPM restated at a fixed 73.8x speed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 15:33:28 +02:00

161 lines
6.0 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Build (and by default install) an Arch Linux package for BikeControl.
#
# Tauri's bundler has no pacman target, so we ship a hand-written PKGBUILD in
# packaging/arch/ and build it with makepkg. makepkg is Arch-specific and
# refuses to run as root, so run this as your normal user — the install step
# calls sudo pacman itself.
#
# The version comes from git: the tag on master/main, the branch name elsewhere.
#
# Usage:
# scripts/build-arch.sh # build, then pacman -U the result
# scripts/build-arch.sh --no-install # build only (CI / packaging runs)
# scripts/build-arch.sh --sync-deps # let makepkg -s pacman-install makedeps
# scripts/build-arch.sh --print-version # show the version that would be built
# OUTPUT_DIR=dist scripts/build-arch.sh # also copy the .pkg.tar.zst there
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
INSTALL=1
SYNC_DEPS=0
PRINT_ONLY=0
for arg in "$@"; do
case "$arg" in
--no-install) INSTALL=0 ;;
--install) INSTALL=1 ;;
--sync-deps) SYNC_DEPS=1 ;;
--print-version) PRINT_ONLY=1 ;;
-h|--help) sed -n '2,15p' "${BASH_SOURCE[0]}"; exit 0 ;;
*) echo "❌ Unknown option: $arg (try --help)" >&2; exit 2 ;;
esac
done
[[ $PRINT_ONLY -eq 1 ]] || command -v makepkg >/dev/null || {
echo "❌ makepkg not found — this script must run on an Arch-based system." >&2
exit 1
}
[[ $PRINT_ONLY -eq 1 || $EUID -ne 0 ]] || {
echo "❌ Do not run this as root; makepkg refuses to build as root." >&2
exit 1
}
# --- Version -----------------------------------------------------------------
# Release builds (master/main, or a detached checkout as CI does on a tag) take
# their version from the git tag. Branch builds take it from the branch name, so
# a package sitting in /var/cache/pacman or `pacman -Qi bikecontrol` says which
# branch it came from. Both get an .r<commits>.g<sha> suffix so two builds of the
# same branch/tag are distinguishable and sort in commit order.
#
# pacman forbids hyphens, colons, slashes and whitespace in a pkgver, so branch
# and tag names are sanitised to underscores. Note that pacman's vercmp ranks a
# leading digit above a leading letter, so installing a branch build on top of a
# release build reads as a "downgrade" — harmless, and --noconfirm accepts it.
_cargo_version() {
sed -n '/^\[workspace\.package\]/,/^\[/ s/^version[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' \
"$REPO_ROOT/Cargo.toml" | head -1
}
_sanitize() { printf '%s' "$1" | sed 's/[^A-Za-z0-9._+]/_/g'; }
# Sets the globals PKGVER and VERSION_SOURCE (rather than echoing, so the
# "where did this version come from" note survives out of a subshell).
derive_pkgver() {
local cargover branch desc tag rest count sha
cargover="$(_cargo_version)"
[[ -n "$cargover" ]] || { echo "❌ Could not read version from Cargo.toml" >&2; exit 1; }
if ! git -C "$REPO_ROOT" rev-parse --git-dir >/dev/null 2>&1; then
VERSION_SOURCE="Cargo.toml (not a git checkout)"
PKGVER="$cargover"; return
fi
count="$(git -C "$REPO_ROOT" rev-list --count HEAD 2>/dev/null || echo 0)"
sha="g$(git -C "$REPO_ROOT" rev-parse --short HEAD 2>/dev/null || echo unknown)"
# Empty on a detached HEAD — that is how CI checks out a tag, so treat it as a
# release build rather than a branch build.
branch="$(git -C "$REPO_ROOT" symbolic-ref --quiet --short HEAD 2>/dev/null || true)"
if [[ -z "$branch" || "$branch" == master || "$branch" == main ]]; then
if desc="$(git -C "$REPO_ROOT" describe --tags --long 2>/dev/null)"; then
# v0.2.0-3-gabc1234 -> tag=v0.2.0, count=3. Strips the trailing two
# hyphen-separated fields, so a tag containing hyphens survives intact.
tag="${desc%-*-*}"; rest="${desc#"$tag"-}"; count="${rest%-*}"; sha="${rest#*-}"
VERSION_SOURCE="git tag ${desc%-*-*}"
tag="$(_sanitize "${tag#v}")"
if [[ "$count" == 0 ]]; then
PKGVER="$tag"
else
VERSION_SOURCE="$VERSION_SOURCE +$count commits"
PKGVER="$tag.r$count.$sha"
fi
else
VERSION_SOURCE="Cargo.toml (no tags yet)"
PKGVER="$cargover.r$count.$sha"
fi
else
VERSION_SOURCE="branch $branch"
PKGVER="$(_sanitize "$branch").r$count.$sha"
fi
}
# BIKECONTROL_PKGVER may be set by the caller (CI) to pin the version exactly.
if [[ -n "${BIKECONTROL_PKGVER:-}" ]]; then
PKGVER="$BIKECONTROL_PKGVER"
VERSION_SOURCE="\$BIKECONTROL_PKGVER"
else
derive_pkgver
fi
if [[ $PRINT_ONLY -eq 1 ]]; then
echo "$PKGVER"
echo "(from $VERSION_SOURCE)" >&2
exit 0
fi
echo "🚴 Building BikeControl Arch package $PKGVER"
echo " version from: $VERSION_SOURCE"
echo "============================================="
# Build straight out of the working tree; give cargo a writable, repo-local home
# so a makepkg run never fights with the user's ~/.cargo permissions.
export BIKECONTROL_SRC="$REPO_ROOT"
export BIKECONTROL_PKGVER="$PKGVER"
export CARGO_HOME="${CARGO_HOME:-$REPO_ROOT/.cargo-arch}"
if [[ $SYNC_DEPS -eq 0 ]]; then
# Without -s, makepkg only checks that the makedeps are present. rustup users
# have cargo on PATH without the `rust` package installed, so warn rather than
# drag in a duplicate toolchain.
for tool in cargo npm node pkg-config; do
command -v "$tool" >/dev/null || echo "⚠️ $tool not on PATH — build may fail (or rerun with --sync-deps)"
done
fi
cd "$REPO_ROOT/packaging/arch"
MAKEPKG_ARGS=(-f --noconfirm --nodeps)
[[ $SYNC_DEPS -eq 1 ]] && MAKEPKG_ARGS=(-sf --noconfirm)
makepkg "${MAKEPKG_ARGS[@]}"
PKG="$(ls -1t ./*.pkg.tar.zst | head -1)"
echo ""
echo "✅ Built $PKG"
if [[ -n "${OUTPUT_DIR:-}" ]]; then
mkdir -p "$OUTPUT_DIR"
cp -v "$PKG" "$OUTPUT_DIR/"
echo "📦 Copied to $OUTPUT_DIR"
fi
if [[ $INSTALL -eq 1 ]]; then
echo ""
echo "📥 Installing $PKG (sudo pacman -U)"
sudo pacman -U --noconfirm "$PKG"
echo ""
echo "✅ Installed. Run it with: bikecontrol"
echo " Example profiles: /usr/share/bikecontrol/profiles/"
else
echo ""
echo "️ Skipped install. To install manually: sudo pacman -U $PWD/${PKG#./}"
fi