235 lines
6.3 KiB
Bash
Executable File
235 lines
6.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
REPO="shakkernerd/kova"
|
|
DEFAULT_PREFIX="${HOME}/.kova"
|
|
DEFAULT_BIN_DIR="${HOME}/.local/bin"
|
|
DEFAULT_OCM_INSTALL_URL="https://raw.githubusercontent.com/shakkernerd/ocm/main/install.sh"
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Install Kova from GitHub release artifacts.
|
|
|
|
Usage:
|
|
install.sh [--version <tag>] [--prefix <dir>] [--bin-dir <dir>] [--archive <path>]
|
|
[--install-ocm] [--require-ocm] [--skip-ocm]
|
|
|
|
Options:
|
|
--version <tag> Release tag to install. Defaults to latest.
|
|
--prefix <dir> Kova install root. Defaults to ~/.kova.
|
|
--bin-dir <dir> Directory for the kova symlink. Defaults to ~/.local/bin.
|
|
--archive <path> Install from a local release archive, useful for testing.
|
|
--install-ocm Install OCM if it is missing.
|
|
--require-ocm Fail if OCM is missing after optional installation.
|
|
--skip-ocm Do not check OCM.
|
|
--help Show this help.
|
|
|
|
Environment:
|
|
KOVA_VERSION Same as --version.
|
|
KOVA_PREFIX Same as --prefix.
|
|
KOVA_BIN_DIR Same as --bin-dir.
|
|
KOVA_ARCHIVE Same as --archive.
|
|
KOVA_INSTALL_OCM Set to 1 to install OCM when missing.
|
|
KOVA_REQUIRE_OCM Set to 1 to fail when OCM is missing.
|
|
KOVA_SKIP_OCM Set to 1 to skip OCM checks.
|
|
OCM_INSTALL_URL OCM installer URL.
|
|
EOF
|
|
}
|
|
|
|
require_command() {
|
|
if ! command -v "$1" >/dev/null 2>&1; then
|
|
echo "error: required command not found: $1" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
download_url_for() {
|
|
local version="$1"
|
|
if [[ "$version" == "latest" ]]; then
|
|
printf 'https://github.com/%s/releases/latest/download/kova.tar.gz\n' "$REPO"
|
|
else
|
|
printf 'https://github.com/%s/releases/download/%s/kova.tar.gz\n' "$REPO" "$version"
|
|
fi
|
|
}
|
|
|
|
checksum_url_for() {
|
|
printf '%s.sha256\n' "$(download_url_for "$1")"
|
|
}
|
|
|
|
truthy() {
|
|
[[ "${1:-}" == "1" || "${1:-}" == "true" || "${1:-}" == "yes" ]]
|
|
}
|
|
|
|
verify_checksum() {
|
|
local archive="$1"
|
|
local checksum_file="$2"
|
|
local expected actual
|
|
|
|
expected="$(awk '{print $1}' "$checksum_file")"
|
|
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
|
|
echo "warning: sha256sum/shasum not found; skipping checksum verification" >&2
|
|
return 0
|
|
fi
|
|
|
|
if [[ "$expected" != "$actual" ]]; then
|
|
echo "error: checksum mismatch for ${archive}" >&2
|
|
echo "expected: ${expected}" >&2
|
|
echo "actual: ${actual}" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
version="${KOVA_VERSION:-latest}"
|
|
prefix="${KOVA_PREFIX:-$DEFAULT_PREFIX}"
|
|
bin_dir="${KOVA_BIN_DIR:-$DEFAULT_BIN_DIR}"
|
|
archive="${KOVA_ARCHIVE:-}"
|
|
install_ocm="${KOVA_INSTALL_OCM:-0}"
|
|
require_ocm="${KOVA_REQUIRE_OCM:-0}"
|
|
skip_ocm="${KOVA_SKIP_OCM:-0}"
|
|
ocm_install_url="${OCM_INSTALL_URL:-$DEFAULT_OCM_INSTALL_URL}"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--version)
|
|
shift
|
|
[[ $# -gt 0 ]] || { echo "error: --version requires a value" >&2; exit 1; }
|
|
version="$1"
|
|
;;
|
|
--prefix)
|
|
shift
|
|
[[ $# -gt 0 ]] || { echo "error: --prefix requires a value" >&2; exit 1; }
|
|
prefix="$1"
|
|
;;
|
|
--bin-dir)
|
|
shift
|
|
[[ $# -gt 0 ]] || { echo "error: --bin-dir requires a value" >&2; exit 1; }
|
|
bin_dir="$1"
|
|
;;
|
|
--archive)
|
|
shift
|
|
[[ $# -gt 0 ]] || { echo "error: --archive requires a value" >&2; exit 1; }
|
|
archive="$1"
|
|
;;
|
|
--install-ocm)
|
|
install_ocm="1"
|
|
;;
|
|
--require-ocm)
|
|
require_ocm="1"
|
|
;;
|
|
--skip-ocm)
|
|
skip_ocm="1"
|
|
;;
|
|
--help|-h)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "error: unknown argument: $1" >&2
|
|
usage >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
require_command tar
|
|
require_command mktemp
|
|
require_command node
|
|
|
|
tmp_dir="$(mktemp -d)"
|
|
cleanup() {
|
|
rm -rf "$tmp_dir"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
if [[ -z "$archive" ]]; then
|
|
require_command curl
|
|
url="$(download_url_for "$version")"
|
|
archive="${tmp_dir}/kova.tar.gz"
|
|
checksum_file="${tmp_dir}/kova.tar.gz.sha256"
|
|
|
|
echo "Downloading ${url}"
|
|
curl -fsSL "$url" -o "$archive"
|
|
if curl -fsSL "$(checksum_url_for "$version")" -o "$checksum_file"; then
|
|
verify_checksum "$archive" "$checksum_file"
|
|
else
|
|
echo "warning: checksum file unavailable; continuing without checksum verification" >&2
|
|
fi
|
|
else
|
|
if [[ ! -f "$archive" ]]; then
|
|
echo "error: archive not found: ${archive}" >&2
|
|
exit 1
|
|
fi
|
|
checksum_file="${archive}.sha256"
|
|
if [[ -f "$checksum_file" ]]; then
|
|
verify_checksum "$archive" "$checksum_file"
|
|
fi
|
|
fi
|
|
|
|
extract_dir="${tmp_dir}/extract"
|
|
mkdir -p "$extract_dir"
|
|
tar -xzf "$archive" -C "$extract_dir"
|
|
|
|
app_source="$(find "$extract_dir" -mindepth 1 -maxdepth 1 -type d | head -n 1)"
|
|
if [[ -z "$app_source" || ! -f "${app_source}/bin/kova.mjs" ]]; then
|
|
echo "error: release archive did not contain bin/kova.mjs" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! truthy "$skip_ocm"; then
|
|
if command -v ocm >/dev/null 2>&1; then
|
|
:
|
|
elif truthy "$install_ocm"; then
|
|
require_command curl
|
|
echo "OCM missing; installing via ${ocm_install_url}"
|
|
curl -fsSL "$ocm_install_url" | bash
|
|
export PATH="${HOME}/.local/bin:${PATH}"
|
|
elif truthy "$require_ocm"; then
|
|
echo "error: ocm is required but was not found on PATH" >&2
|
|
echo "rerun with KOVA_INSTALL_OCM=1 or install ocm first" >&2
|
|
exit 1
|
|
else
|
|
echo "warning: ocm was not found on PATH; install OCM before running real Kova scenarios" >&2
|
|
echo "rerun with KOVA_INSTALL_OCM=1 to install OCM automatically" >&2
|
|
fi
|
|
fi
|
|
|
|
if command -v ocm >/dev/null 2>&1 && ! truthy "$skip_ocm"; then
|
|
KOVA_HOME="$prefix" node "${app_source}/bin/kova.mjs" setup --ci --json >/dev/null
|
|
else
|
|
KOVA_HOME="$prefix" node "${app_source}/bin/kova.mjs" help >/dev/null
|
|
fi
|
|
|
|
mkdir -p "$prefix" "${prefix}/bin" "$bin_dir"
|
|
rm -rf "${prefix}/app"
|
|
mv "$app_source" "${prefix}/app"
|
|
|
|
launcher="${prefix}/bin/kova"
|
|
cat > "$launcher" <<EOF
|
|
#!/usr/bin/env bash
|
|
export KOVA_HOME="${prefix}"
|
|
exec node "${prefix}/app/bin/kova.mjs" "\$@"
|
|
EOF
|
|
chmod 0755 "$launcher"
|
|
|
|
ln -sfn "$launcher" "${bin_dir}/kova"
|
|
|
|
echo "Installed kova to ${prefix}/app"
|
|
echo "Linked kova at ${bin_dir}/kova"
|
|
case ":${PATH}:" in
|
|
*":${bin_dir}:"*) ;;
|
|
*)
|
|
echo "Add ${bin_dir} to your PATH to run kova from any shell."
|
|
;;
|
|
esac
|
|
echo ""
|
|
echo "Next:"
|
|
echo " kova version"
|
|
echo " kova setup"
|
|
echo " kova self-check"
|
|
echo " kova matrix plan --profile smoke --target runtime:stable"
|