Files
gary e9f9fdd6fc
Release / goreleaser (push) Successful in 3m1s
feat: release klink v0.1.0
2026-07-19 22:27:20 +08:00

144 lines
4.0 KiB
Bash
Executable File

#!/bin/sh
set -eu
repository_url=${KLINK_REPOSITORY_URL:-https://gitea.bytevibe.dev/gary/klink}
api_url=${KLINK_API_URL:-https://gitea.bytevibe.dev/api/v1/repos/gary/klink/releases/latest}
requested_version=${KLINK_VERSION:-}
install_dir=${KLINK_INSTALL_DIR:-}
say() {
printf '%s\n' "$*"
}
fail() {
printf 'klink installer: %s\n' "$*" >&2
exit 1
}
require_command() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
fetch_stdout() {
url=$1
case "$url" in
https://*) curl -fsSL --proto '=https' --tlsv1.2 "$url" ;;
*)
[ "${KLINK_ALLOW_INSECURE:-}" = "1" ] || fail "refusing non-HTTPS URL: $url"
curl -fsSL "$url"
;;
esac
}
fetch_file() {
url=$1
output=$2
case "$url" in
https://*) curl -fsSL --proto '=https' --tlsv1.2 -o "$output" "$url" ;;
*)
[ "${KLINK_ALLOW_INSECURE:-}" = "1" ] || fail "refusing non-HTTPS URL: $url"
curl -fsSL -o "$output" "$url"
;;
esac
}
require_command curl
require_command tar
require_command awk
require_command sed
require_command mktemp
require_command tr
if [ -n "${KLINK_OS:-}" ]; then
target_os=$KLINK_OS
else
case "$(uname -s)" in
Darwin) target_os=darwin ;;
Linux) target_os=linux ;;
*) fail "unsupported operating system: $(uname -s)" ;;
esac
fi
if [ -n "${KLINK_ARCH:-}" ]; then
machine=$KLINK_ARCH
else
machine=$(uname -m)
fi
case "$machine" in
x86_64|amd64) target_arch=amd64 ;;
arm64|aarch64) target_arch=arm64 ;;
*) fail "unsupported architecture: $machine" ;;
esac
if [ -n "$requested_version" ]; then
case "$requested_version" in
v*) tag=$requested_version ;;
*) tag=v$requested_version ;;
esac
else
release_json=$(fetch_stdout "$api_url") || fail "could not read the latest Gitea release"
tag=$(printf '%s' "$release_json" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
[ -n "$tag" ] || fail "latest Gitea release has no tag"
fi
version=${tag#v}
[ -n "$version" ] || fail "invalid release tag: $tag"
asset=klink_${version}_${target_os}_${target_arch}.tar.gz
download_base=${repository_url%/}/releases/download/$tag
temporary=$(mktemp -d "${TMPDIR:-/tmp}/klink-install.XXXXXX") || fail "could not create a temporary directory"
cleanup() {
rm -rf "$temporary"
}
trap cleanup EXIT HUP INT TERM
archive=$temporary/$asset
checksums=$temporary/checksums.txt
say "Downloading klink $tag for $target_os/$target_arch..."
fetch_file "$download_base/$asset" "$archive"
fetch_file "$download_base/checksums.txt" "$checksums"
expected=$(awk -v name="$asset" '{ file=$2; sub(/^\*/, "", file); if (file == name) { print $1; exit } }' "$checksums")
[ -n "$expected" ] || fail "$asset is not listed in checksums.txt"
if command -v sha256sum >/dev/null 2>&1; then
actual=$(sha256sum "$archive" | awk '{print $1}')
elif command -v shasum >/dev/null 2>&1; then
actual=$(shasum -a 256 "$archive" | awk '{print $1}')
else
fail "sha256sum or shasum is required"
fi
[ "$(printf '%s' "$actual" | tr 'A-F' 'a-f')" = "$(printf '%s' "$expected" | tr 'A-F' 'a-f')" ] || fail "SHA256 checksum mismatch for $asset"
extract_dir=$temporary/extract
mkdir -p "$extract_dir"
tar -xzf "$archive" -C "$extract_dir"
binary=$extract_dir/klink
[ -f "$binary" ] || fail "release archive does not contain klink"
if [ -z "$install_dir" ]; then
if [ -d /usr/local/bin ] && [ -w /usr/local/bin ]; then
install_dir=/usr/local/bin
else
install_dir=$HOME/.local/bin
fi
fi
mkdir -p "$install_dir"
destination=$install_dir/klink
staged=$install_dir/.klink-install.$$
cp "$binary" "$staged"
chmod 755 "$staged"
mv -f "$staged" "$destination"
say "Installed klink $tag to $destination"
case ":${PATH:-}:" in
*:"$install_dir":*) ;;
*)
say "Add $install_dir to PATH, for example:"
say " export PATH=\"$install_dir:\$PATH\""
;;
esac
if ! command -v ssh >/dev/null 2>&1; then
say "Warning: OpenSSH was not found in PATH; install it before connecting to nodes."
fi