build: tag rad --version with a +lfs-ipfs suffix, fix newline bug
Appends a semver build-metadata suffix to RADICLE_VERSION so `rad --version` (and radicle-node/git-remote-rad, which share this build script via symlink) unambiguously identify a binary as this fork rather than upstream heartwood -- useful for checking what a deploy target is actually running. While wiring this up, found and fixed a real pre-existing bug: none of the three `git` subprocess outputs captured here (GIT_HEAD, RADICLE_VERSION, SOURCE_DATE_EPOCH) were trimmed, so each carried a trailing newline into its `cargo::rustc-env=KEY=VALUE` directive. Harmless on its own since nothing followed it, but appending the +lfs-ipfs suffix landed after that embedded newline, splitting the directive across two lines -- cargo silently discards the second line as unrecognized, so the suffix never actually took effect until this trim was added. Also adds scripts/publish-package.sh: builds all four release binaries (rad, radicle-node, git-remote-rad, rad-lfs-transfer) and publishes them as a Forgejo generic package, so a deploy target without a Rust toolchain can download instead of rebuilding from source (see NOTES-lfs-store-note-write-bug.md's VPS deployment story for why that matters).
This commit is contained in:
parent
ae7aed5db5
commit
68202ce58d
15
build.rs
15
build.rs
|
|
@ -13,7 +13,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.ok()
|
||||
.and_then(|output| {
|
||||
if output.status.success() {
|
||||
String::from_utf8(output.stdout).ok()
|
||||
String::from_utf8(output.stdout).ok().map(|s| s.trim().to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.ok()
|
||||
.and_then(|output| {
|
||||
if output.status.success() {
|
||||
String::from_utf8(output.stdout).ok()
|
||||
String::from_utf8(output.stdout).ok().map(|s| s.trim().to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -61,6 +61,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
version
|
||||
};
|
||||
|
||||
// This is the `rad-lfs-ipfs` fork (Git LFS support backed by IPFS, see
|
||||
// README.md/LFS-IPFS.md) -- append a semver build-metadata suffix (the
|
||||
// `+...` part a `git describe`-derived version doesn't otherwise have
|
||||
// room for) so `--version` unambiguously identifies a binary as this
|
||||
// fork rather than upstream heartwood, e.g. when checking what a
|
||||
// deploy target is actually running. Applies to every binary in this
|
||||
// workspace, since they all share this build script via symlink.
|
||||
let version = format!("{version}+lfs-ipfs");
|
||||
|
||||
// Set a build-time `SOURCE_DATE_EPOCH` env var which includes the commit time.
|
||||
let commit_time = env::var("SOURCE_DATE_EPOCH").unwrap_or_else(|_| {
|
||||
Command::new("git")
|
||||
|
|
@ -72,7 +81,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.ok()
|
||||
.and_then(|output| {
|
||||
if output.status.success() {
|
||||
String::from_utf8(output.stdout).ok()
|
||||
String::from_utf8(output.stdout).ok().map(|s| s.trim().to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Builds release binaries for the LFS-over-IPFS stack (rad, radicle-node,
|
||||
# git-remote-rad, rad-lfs-transfer) and publishes them as a Forgejo generic
|
||||
# package, so a deploy target can `curl` a tarball instead of needing a full
|
||||
# Rust toolchain (see NOTES-lfs-store-note-write-bug.md's VPS deployment
|
||||
# story for why that matters -- rebuilding in place isn't always possible).
|
||||
#
|
||||
# Usage:
|
||||
# FORGEJO_TOKEN=... ./scripts/publish-package.sh [version]
|
||||
#
|
||||
# `version` defaults to `git describe --tags --always --dirty`, sanitized
|
||||
# for use in a URL path. The token needs the `write:package` scope; it's
|
||||
# read from $FORGEJO_TOKEN, falling back to ~/.config/forgejo/token if that
|
||||
# env var isn't set (chmod 600 that file if you use it).
|
||||
#
|
||||
# Config (override via env):
|
||||
# FORGEJO_HOST default: git.hswro.org
|
||||
# FORGEJO_OWNER default: mab122
|
||||
# PACKAGE_NAME default: radicle-lfs-ipfs
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
FORGEJO_HOST="${FORGEJO_HOST:-git.hswro.org}"
|
||||
FORGEJO_OWNER="${FORGEJO_OWNER:-mab122}"
|
||||
PACKAGE_NAME="${PACKAGE_NAME:-radicle-lfs-ipfs}"
|
||||
|
||||
repo_root="$(git rev-parse --show-toplevel)"
|
||||
cd "$repo_root"
|
||||
|
||||
if [ -n "${FORGEJO_TOKEN:-}" ]; then
|
||||
token="$FORGEJO_TOKEN"
|
||||
elif [ -r "$HOME/.config/forgejo/token" ]; then
|
||||
token="$(cat "$HOME/.config/forgejo/token")"
|
||||
else
|
||||
echo "error: no Forgejo API token found. Set \$FORGEJO_TOKEN, or put one" \
|
||||
"(scope: write:package) in ~/.config/forgejo/token (chmod 600)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
version_raw="${1:-$(git describe --tags --always --dirty)}"
|
||||
# Forgejo generic package versions must be URL-path-safe; a `git describe`
|
||||
# with a "-dirty" suffix or a leading "v" is otherwise fine, but sanitize
|
||||
# defensively rather than let a stray character break the upload URL.
|
||||
version="$(printf '%s' "$version_raw" | tr -c 'A-Za-z0-9._-' '-')"
|
||||
|
||||
if [ ! -f "$repo_root/radicle-lfs-transfer/Cargo.toml" ]; then
|
||||
echo "error: radicle-lfs-transfer/ submodule is empty -- run" \
|
||||
"'git submodule update --init' first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> Building release binaries (version: $version)"
|
||||
cargo build --release --locked -p radicle-cli --bin rad
|
||||
cargo build --release --locked -p radicle-node
|
||||
cargo build --release --locked -p radicle-remote-helper
|
||||
cargo build --release --locked --manifest-path radicle-lfs-transfer/Cargo.toml
|
||||
|
||||
target_triple="$(rustc -vV | sed -n 's/host: //p')"
|
||||
staging="$(mktemp -d)"
|
||||
trap 'rm -rf "$staging"' EXIT
|
||||
|
||||
cp target/release/rad "$staging/"
|
||||
cp target/release/radicle-node "$staging/"
|
||||
cp target/release/git-remote-rad "$staging/"
|
||||
cp radicle-lfs-transfer/target/release/rad-lfs-transfer "$staging/"
|
||||
|
||||
# Recorded because a binary built on a newer glibc can fail to run on an
|
||||
# older one (discovered live deploying this exact stack to a Debian VPS) --
|
||||
# anyone consuming this package needs to be able to check compatibility
|
||||
# before copying the binaries over, not find out by them failing to start.
|
||||
cat > "$staging/MANIFEST.txt" << EOF
|
||||
package: $PACKAGE_NAME
|
||||
version: $version
|
||||
git commit: $(git rev-parse HEAD)
|
||||
git branch: $(git rev-parse --abbrev-ref HEAD)
|
||||
built: $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
target triple: $target_triple
|
||||
rustc: $(rustc --version)
|
||||
glibc: $(ldd --version | head -1)
|
||||
contents:
|
||||
rad $(target/release/rad --version)
|
||||
radicle-node $(target/release/radicle-node --version)
|
||||
git-remote-rad $(target/release/git-remote-rad --version)
|
||||
rad-lfs-transfer (no --version; speaks git-lfs custom-transfer protocol on stdin/stdout)
|
||||
EOF
|
||||
|
||||
archive_name="${PACKAGE_NAME}-${version}-${target_triple}.tar.gz"
|
||||
archive_path="$staging/../${archive_name}"
|
||||
tar -C "$staging" -czf "$archive_path" .
|
||||
sha256sum "$archive_path" | awk '{print $1}' > "${archive_path}.sha256"
|
||||
|
||||
echo "==> Built $(du -h "$archive_path" | cut -f1) archive: $archive_name"
|
||||
|
||||
upload() {
|
||||
local file="$1" name="$2"
|
||||
local url="https://${FORGEJO_HOST}/api/packages/${FORGEJO_OWNER}/generic/${PACKAGE_NAME}/${version}/${name}"
|
||||
local status
|
||||
status="$(curl -sS -o /tmp/forgejo-upload-response.$$ -w '%{http_code}' \
|
||||
-H "Authorization: token ${token}" \
|
||||
-X PUT "$url" \
|
||||
-T "$file")"
|
||||
if [ "$status" = "201" ]; then
|
||||
echo " uploaded: $name"
|
||||
elif [ "$status" = "409" ]; then
|
||||
echo " error: $name already exists at version $version -- bump the version" \
|
||||
"or delete the existing package file in Forgejo first." >&2
|
||||
cat /tmp/forgejo-upload-response.$$ >&2
|
||||
rm -f /tmp/forgejo-upload-response.$$
|
||||
exit 1
|
||||
else
|
||||
echo " error: upload of $name failed (HTTP $status)" >&2
|
||||
cat /tmp/forgejo-upload-response.$$ >&2
|
||||
rm -f /tmp/forgejo-upload-response.$$
|
||||
exit 1
|
||||
fi
|
||||
rm -f /tmp/forgejo-upload-response.$$
|
||||
}
|
||||
|
||||
echo "==> Uploading to https://${FORGEJO_HOST}/${FORGEJO_OWNER}/-/packages/generic/${PACKAGE_NAME}/${version}"
|
||||
upload "$archive_path" "$archive_name"
|
||||
upload "${archive_path}.sha256" "${archive_name}.sha256"
|
||||
|
||||
echo "==> Done: https://${FORGEJO_HOST}/${FORGEJO_OWNER}/-/packages/generic/${PACKAGE_NAME}/${version}"
|
||||
Loading…
Reference in New Issue