#!/usr/bin/env bash set -e set -o pipefail NZ_DEPS=("curl" "jq" "basename" "tar" "find" "readlink") NZ_DEP_ERR=100 NZ_ARCH_OS="unknown" NZ_PLATFORM_ERR=101 NZ_JSON_URL="https://ziglang.org/download/index.json" NZ_DIR="$HOME/.night.zig" NZ_VERSION="0.2.0" NZ_USAGE=" USAGE: nz <SUBCOMMAND> SUBCOMMANDS: update Update both zig nightly toolchain & nz itself update nightly Update zig nightly toolchain only update nz Update nz itself only cleanup Remove outdated nightly toolchains version Show nz version info help Show this message " #https://stackoverflow.com/a/33297950 function check_dep { local dep="$1" if command -v "$dep" >/dev/null 2>&1 ; then return 0 else return "$NZ_DEP_ERR" fi } function script_echo { printf '[night.zig] %b\n' "$1" } function check_deps { for dep in "${NZ_DEPS[@]}"; do if check_dep "$dep"; then : else >&2 script_echo "Dependency ${dep} is not installed. Exiting now..." exit "$NZ_DEP_ERR" fi done } function arch_info { local arch local uname_m uname_m="$(uname -m)" if [[ "$uname_m" == "arm64" ]]; then arch="aarch64" elif [[ "$uname_m" == "amd64" ]]; then arch="x86_64" elif [[ "$uname_m" == "x86_64" ]]; then arch="x86_64" elif [[ "$uname_m" == "i386" ]]; then arch="x86" elif [[ "$uname_m" == "riscv64" ]]; then arch="riscv64" elif [[ "$uname_m" == "powerpc" ]]; then arch="powerpc" elif [[ "$uname_m" == "ppc64el" ]]; then arch="powerpc64le" else arch="unknown" fi echo "$arch" } # https://stackoverflow.com/a/8597411 function os_info { local os if [[ "$OSTYPE" == "linux-gnu"* ]]; then os="linux" elif [[ "$OSTYPE" == "darwin"* ]]; then os="macos" elif [[ "$OSTYPE" == "cygwin" ]]; then # POSIX compatibility layer and Linux environment emulation for Windows os="windows" elif [[ "$OSTYPE" == "msys" ]]; then # Lightweight shell and GNU utilities compiled for Windows (part of MinGW) os="windows" elif [[ "$OSTYPE" == "win32" ]]; then # I'm not sure this can happen. os="windows" elif [[ "$OSTYPE" == "freebsd"* ]]; then os="unknown" else os="unknown" fi echo "$os" } function validate_platform { NZ_ARCH_OS="$(arch_info)-$(os_info)" if [[ "$NZ_ARCH_OS" == *"unknown"* ]]; then >&2 script_echo "No prebuilt nightly binary available for ${NZ_ARCH_OS}. Exiting now..." exit "$NZ_PLATFORM_ERR" else : fi } function nightly_needs_update { local upstream_ver="$1" local latest_dir_name="$(basename "$(readlink -f "$NZ_DIR"/latest)")" if [[ "$latest_dir_name" == *"$upstream_ver"* ]]; then return 1 else return 0 fi } # works for both macOS and linux # https://unix.stackexchange.com/a/84980 function mktempdir { mktemp -d 2>/dev/null || mktemp -d -t 'tmpdir' } function fetch_tar { local tar_url="$1" local tar_name="$(basename "$tar_url")" local temp_dir="$(mktempdir)" script_echo "Fetching nightly tar ball...\n" curl --output-dir "$temp_dir" --output "$tar_name" "$tar_url" script_echo "Fetch completed.\n" echo "$temp_dir/$tar_name" } function unpack_tar { local tar_path="$1" mkdir -p "$NZ_DIR" local containing_dir="$(tar -tf "$tar_path" | head -1)" local new_install_dir_name="${containing_dir%/}" script_echo "Extracting nightly tar ball...\n" tar -xf "$tar_path" -C "$NZ_DIR" script_echo "Extraction completed.\n" echo "$new_install_dir_name" } function config_latest { script_echo "Configuring latest nightly...\n" local new_install_dir_name="$1" ( cd "$NZ_DIR" rm -f latest ln -s "$new_install_dir_name" latest ) script_echo "Latest nightly configured.\n" } function install_nightly { local tar_url="$1" local tar_path="$(fetch_tar "$tar_url" | tee /dev/tty | tail -n 1)" local new_install_dir_name="$(unpack_tar "$tar_path" | tee /dev/tty | tail -n 1)" config_latest "$new_install_dir_name" } function update_nightly_if_necessary { script_echo "Checking upstream nightly version...\n" local json="$(curl "$NZ_JSON_URL")" local upstream_ver="$(jq -n "$json" | jq -r ".master.version")" if nightly_needs_update "$upstream_ver"; then script_echo "Your nighly is outdated, updating now...\n" local tar_url="$(jq -n "$json" | jq -r ".master.\"$NZ_ARCH_OS\".tarball")" install_nightly "$tar_url" script_echo "Nightly update completed.\n" else script_echo "Your nightly is already up to date. Skip updating...\n" fi } function deploy_nz { # I know it's confusing naming # so the full path of `nz` is: # ~/.night.zig/nz/nz local nz_bin_dir="$NZ_DIR"/nz mkdir -p "$nz_bin_dir" rm -f "$nz_bin_dir"/nz script_echo "Deploying latest nz...\n" curl --output-dir "$nz_bin_dir" --output "nz" "https://raw.githubusercontent.com/jsomedon/night.zig/main/nz" chmod +x "$nz_bin_dir"/nz script_echo "Latest nz deployed successfully.\n" } function rm_outdated_nightly { script_echo "Cleaning up outdated nightly bins...\n" ( cd "$NZ_DIR" local to_be_removed=$(find "." -maxdepth 1 ! -name "nz" ! -name "latest" ! -name "$(basename "$(readlink -f latest)")" ! -name ".") for tbr in $to_be_removed; do echo "removing ${NZ_DIR}/$(basename "$tbr")..." rm -rf "$tbr" done ) script_echo "Cleanup completed.\n" } function show_version { script_echo "version $NZ_VERSION" } function deploy_nightly { local json="$(curl "$NZ_JSON_URL")" local tar_url="$(jq -n "$json" | jq -r ".master.\"$NZ_ARCH_OS\".tarball")" script_echo "Deploying latest nightly...\n" install_nightly "$tar_url" script_echo "Latest nightly deployed successfully.\n" } function path_needs_config { local path=$1 if [[ "$PATH" == *"$path"* ]]; then return 1 else return 0 fi } function config_path { local path=$1 script_echo "Adding ${path} to \$PATH...\n" # script_echo "You should config your \$PATH; put this line in your shell's profile file:" # script_echo "export PATH=${path}:\$PATH\n" local os="$(os_info)" local bash_profile if [[ "$os" == "macos" ]];then bash_profile="${HOME}/.bash_profile" elif [[ "$os" == "linux" ]];then bash_profile="${HOME}/.bashrc" else script_echo "\$PATH auto configuration is not supported on this system: ${os}" script_echo "You should manually configure your \$PATH; put this line in your shell's profile file:" script_echo "export PATH=${path}:\$PATH\n" return 0 fi echo "export PATH=${path}:\$PATH" >> "$bash_profile" script_echo "Added ${path} to \$PATH.\n" } function config_path_if_necessary { local path=$1 if path_needs_config "$path"; then config_path "$path" else : fi } function show_help { show_version printf "%s" "$NZ_USAGE" } function main { check_deps validate_platform if [[ $# -eq 0 ]]; then show_help elif [[ $1 == "update" ]]; then if [[ $# -eq 1 ]]; then update_nightly_if_necessary deploy_nz elif [[ $# -eq 2 ]]; then if [[ $2 == "nightly" ]]; then update_nightly_if_necessary elif [[ $2 == "nz" ]]; then deploy_nz else show_help fi else show_help fi elif [[ $1 == "cleanup" ]]; then rm_outdated_nightly elif [[ $1 == "version" ]]; then show_version elif [[ $1 == "_bootstrap" ]]; then # hidden option, only used upon first time install script_echo "Starting fresh installation...\n" deploy_nightly deploy_nz script_echo "Installation completed.\n" config_path_if_necessary "$NZ_DIR"/latest config_path_if_necessary "$NZ_DIR"/nz else show_help fi } main "$@"