set -euo pipefail
readonly red='\033[0;31m'
readonly green='\033[0;32m'
readonly yellow='\033[1;33m'
readonly blue='\033[0;34m'
readonly reset='\033[0m'
install_dir_result=""
tmp_dir_to_remove=""
cleanup() {
if [[ -n "$tmp_dir_to_remove" ]]; then
rm -rf "$tmp_dir_to_remove"
fi
}
log_info() {
printf '%b==>%b %s\n' "$blue" "$reset" "$1"
}
log_success() {
printf '%b==>%b %s\n' "$green" "$reset" "$1"
}
log_warning() {
printf '%b==>%b %s\n' "$yellow" "$reset" "$1"
}
log_error() {
printf '%bError:%b %s\n' "$red" "$reset" "$1" >&2
}
fetch_url() {
local url=$1
local output=$2
if command -v curl >/dev/null 2>&1; then
curl -fsSL --retry 3 --retry-connrefused --connect-timeout 10 --max-time 120 -o "$output" "$url"
elif command -v wget >/dev/null 2>&1; then
wget --tries=3 --timeout=120 -q -O "$output" "$url"
else
log_error "Neither curl nor wget found. Please install one of them."
exit 1
fi
}
fetch_stdout() {
local url=$1
if command -v curl >/dev/null 2>&1; then
curl -fsSL --retry 3 --retry-connrefused --connect-timeout 10 --max-time 30 "$url"
elif command -v wget >/dev/null 2>&1; then
wget --tries=3 --timeout=30 -qO- "$url"
else
log_error "Neither curl nor wget found. Please install one of them."
exit 1
fi
}
detect_platform() {
local os
local arch
case "$(uname -s)" in
Darwin)
os="darwin"
;;
Linux)
os="linux"
;;
*)
log_error "Unsupported operating system: $(uname -s)"
printf '\naven supports macOS and Linux.\n'
printf 'For other platforms, try building from source with Cargo:\n'
printf ' cargo install --git https://github.com/raine/aven\n\n'
exit 1
;;
esac
case "$(uname -m)" in
x86_64 | amd64)
arch="amd64"
;;
aarch64 | arm64)
arch="arm64"
;;
*)
log_error "Unsupported architecture: $(uname -m)"
printf '\naven release binaries are available for amd64 and arm64.\n'
printf 'For other architectures, try building from source with Cargo:\n'
printf ' cargo install --git https://github.com/raine/aven\n\n'
exit 1
;;
esac
printf '%s-%s\n' "$os" "$arch"
}
latest_version() {
local latest_url="https://api.github.com/repos/raine/aven/releases/latest"
local release_json
log_info "Fetching latest release..." >&2
release_json=$(fetch_stdout "$latest_url")
printf '%s\n' "$release_json" | sed -n -E 's/.*"tag_name": "([^"]+)".*/\1/p'
}
verify_checksum() {
local checksum_file=$1
if command -v sha256sum >/dev/null 2>&1; then
sha256sum -c "$checksum_file" >/dev/null
elif command -v shasum >/dev/null 2>&1; then
shasum -a 256 -c "$checksum_file" >/dev/null
else
log_warning "Neither sha256sum nor shasum found, skipping checksum verification"
return 0
fi
}
default_install_dir() {
if [[ -w /usr/local/bin ]]; then
printf '/usr/local/bin\n'
else
printf '%s/.local/bin\n' "$HOME"
fi
}
install_binary() {
local source_binary=$1
local install_dir=$2
local target_binary="$install_dir/aven"
local tmp_binary="$install_dir/aven.tmp.$$"
mkdir -p "$install_dir"
log_info "Installing to $target_binary..."
if [[ -w "$install_dir" ]]; then
cp "$source_binary" "$tmp_binary"
chmod 0755 "$tmp_binary"
mv -f "$tmp_binary" "$target_binary"
else
if ! command -v sudo >/dev/null 2>&1; then
log_error "$install_dir is not writable and sudo is not available"
exit 1
fi
sudo cp "$source_binary" "$tmp_binary"
sudo chmod 0755 "$tmp_binary"
sudo mv -f "$tmp_binary" "$target_binary"
fi
if [[ "$(uname -s)" == "Darwin" ]] && command -v xattr >/dev/null 2>&1; then
xattr -d com.apple.quarantine "$target_binary" 2>/dev/null || true
fi
}
install_from_release() {
local platform=$1
local version=${AVEN_VERSION:-}
local install_dir=${AVEN_INSTALL_DIR:-}
local tmp_dir
local archive_name
local checksum_file
local download_url
local checksum_url
tmp_dir=$(mktemp -d)
tmp_dir_to_remove=$tmp_dir
trap cleanup EXIT
if [[ -z "$version" ]]; then
version=$(latest_version)
if [[ -z "$version" ]]; then
log_error "Failed to fetch latest version"
printf '\nSpecify a version manually:\n'
printf ' AVEN_VERSION=v0.1.0 bash scripts/install\n\n'
exit 1
fi
fi
archive_name="aven-${platform}.tar.gz"
checksum_file="${archive_name%.tar.gz}.sha256"
download_url="https://github.com/raine/aven/releases/download/${version}/${archive_name}"
checksum_url="https://github.com/raine/aven/releases/download/${version}/${checksum_file}"
log_info "Installing version: $version"
log_info "Downloading $archive_name..."
fetch_url "$download_url" "$tmp_dir/$archive_name"
log_info "Verifying checksum..."
fetch_url "$checksum_url" "$tmp_dir/$checksum_file"
(cd "$tmp_dir" && verify_checksum "$checksum_file")
log_success "Checksum verified"
log_info "Extracting archive..."
tar -xzf "$tmp_dir/$archive_name" -C "$tmp_dir"
if [[ -z "$install_dir" ]]; then
install_dir=$(default_install_dir)
fi
install_binary "$tmp_dir/aven" "$install_dir"
install_dir_result=$install_dir
}
verify_installation() {
local install_dir=$1
local binary="$install_dir/aven"
if [[ ! -x "$binary" ]]; then
log_error "aven binary not found or not executable at $binary"
exit 1
fi
if ! "$binary" --help >/dev/null 2>&1; then
log_error "aven binary exists but failed to run"
exit 1
fi
log_success "aven is installed and ready!"
printf '\nGet started:\n'
printf ' aven config init\n'
printf ' aven tui\n\n'
printf 'Documentation: https://github.com/raine/aven\n\n'
if [[ ":$PATH:" != *":$install_dir:"* ]]; then
log_warning "$install_dir is not in your PATH"
printf '\nAdd this to your shell profile:\n'
printf " export PATH=\"\$PATH:%s\"\n\n" "$install_dir"
fi
}
main() {
local platform
printf '\naven installer\n\n'
log_info "Detecting platform..."
platform=$(detect_platform)
log_info "Platform: $platform"
install_from_release "$platform"
verify_installation "$install_dir_result"
}
main "$@"