#!/usr/bin/env bash set -eo pipefail DEPS_PATH="${HOME}/.local/share" SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" PKG_INSTALL_CMD="" BOLD=$(tput bold) CYAN=$(tput setaf 6) GREEN=$(tput setaf 2) YELLOW=$(tput setaf 3) RED=$(tput setaf 1) RESET=$(tput sgr0) RESET_BOLD="${RESET}${BOLD}" log() { # Print a message and send it to stdout or stderr depending upon log level, also configurable with debug etc. # # Arguments: # level # - The log level, defined within a case check in this function # message # - The info message # # Usage: # log "info" "Could not find that directory" # # POSIX Compliant: # Yes # # Convert the level to uppercase local level level=$(printf "%s" "${1}" | tr '[:lower:]' '[:upper:]') local message message="${2}" case "${level}" in INFO) printf "%sINFO:%s %s%s%s\n" \ "${CYAN}" \ "${RESET}" \ "${BOLD}" \ "${message}" \ "${RESET}" >&2 return 0 ;; WARN*) printf "%sWARN:%s %s%s%s\n" \ "${YELLOW}" \ "${RESET}" \ "${BOLD}" \ "${message}" \ "${RESET}" >&2 return 0 ;; ERROR) printf "%sERROR:%s %s%s%s\n" \ "${RED}" \ "${RESET}" \ "${BOLD}" \ "${message}" \ "${RESET}" >&2 return 0 ;; # Further log levels can be added by extending this switch statement with more comparisons esac } print-break() { printf "${GREEN}%.s─${RESET}" $(seq 1 "$(tput cols)") } log "${@}" install-fzf() { local install_path="${1}/fzf" if ! [[ -e "${install_path}" ]]; then git clone --depth 1 https://github.com/junegunn/fzf.git "${install_path}" "${install_path}/install" \ --key-bindings \ --completion \ --no-update-rc \ --xdg >/dev/null else log "info" "${GREEN}FZF${RESET_BOLD} already installed, skipping" fi } install-rust() { local install_path="${1}" export CARGO_HOME="${install_path}/cargo" export RUSTUP_HOME="${install_path}/rustup" if ! [[ -e "${CARGO_HOME}" ]] || ! [[ -e "${RUSTUP_HOME}" ]]; then log "info" "Rust installs set to ${GREEN}cargo${RESET_BOLD}: ${GREEN}${CARGO_HOME}${RESET_BOLD} & ${GREEN}rustup${RESET_BOLD}: ${GREEN}${RUSTUP_HOME}${RESET_BOLD}" curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --quiet if [[ -z "$(ls "${RUSTUP_HOME}/toolchains" >/dev/null)" ]]; then log "info" "No toolchain found, installing a ${GREEN}Rust${RESET_BOLD} toolchain" log "info" "Setting ${GREEN}Rust${RESET_BOLD}'s toolchain to ${GREEN}stable${RESET_BOLD}" if ! rustup default stable; then log "error" "Failed to set a ${GREEN}Rust${RESET_BOLD} toolchain" return 1 fi else log "info" "${GREEN}Rust${RESET_BOLD} toolchain found, skipping toolchain setup" fi else log "info" "${GREEN}Rust${RESET_BOLD} already installed, skipping" fi export PATH="${PATH}:${install_path}/cargo/bin" } install-cargo-binary() { local binary="${1}" cargo install "${binary}" } check-script-deps() { local commands_to_check=( git gcc ) local ret_code=0 for cmd in "${commands_to_check[@]}"; do if ! command -v "${cmd}" >/dev/null; then log "warning" "Could not find command: ${GREEN}${cmd}${RESET_BOLD}, attempting automatic installation" install-from-pkg-mngr "${cmd}" ret_code=1 else log "info" "Found dependency ${GREEN}${cmd}${RESET_BOLD}" fi done return "${ret_code}" } install-from-pkg-mngr() { if [[ "${SKIP_PKG_INSTALL}" = true ]]; then return fi local pkg_to_install="${*}" local ret_code=0 log "info" "Installing ${GREEN}${pkg_to_install}${RESET_BOLD}" if ! "$(eval "${PKG_INSTALL_CMD}" "${pkg_to_install}")"; then log "error" "Failed to install ${GREEN}${pkg_to_install}${RESET_BOLD}" ret_code=1 fi if ((ret_code > 0)); then return 1 else log "info" "Successfully installed ${GREEN}${pkg_to_install}${RESET_BOLD}" fi } deploy-config() { local install_paths declare -A install_paths=( ["zshrc"]=".zshrc" ["ZSH-Config"]=".config/zsh" ) for install_key in "${!install_paths[@]}"; do local src_path="${SCRIPT_DIR}/${install_paths[${install_key}]}" local dest_path="${HOME}/${install_paths[${install_key}]}" if [[ -e "${dest_path}" ]]; then log "info" "${GREEN}${install_key}${RESET_BOLD} already exists at ${GREEN}${dest_path}${RESET_BOLD}, skipping" continue fi log "info" "Linking ${GREEN}${install_key}${RESET_BOLD}, ${GREEN}${src_path}${RESET_BOLD} to ${GREEN}${dest_path}${RESET_BOLD}" if ! ln -s "${src_path}" "${dest_path}"; then log "error" "Failed linking ${GREEN}${install_key}${RESET_BOLD}, ${GREEN}${src_path}${RESET_BOLD} to ${GREEN}${dest_path}${RESET_BOLD}" return 1 fi done } main() { local tasks_done=() PKG_INSTALL_CMD="${*}" if [[ -z "${PKG_INSTALL_CMD}" ]] && ! [[ "${SKIP_PKG_INSTALL}" = true ]]; then log "error" "A package installer must be passed to install missing packages, or ${GREEN}SKIP_PKG_INSTALL=TRUE${RESET_BOLD} must be set." return 1 fi log "info" "Dependencies directory set to ${GREEN}${DEPS_PATH}${RESET_BOLD}" log "info" "Packager install command set to ${GREEN}${PKG_INSTALL_CMD}${RESET_BOLD}" mkdir -p "${DEPS_PATH}" print-break log "info" "Checking script dependencies..." if ! check-script-deps; then log "error" "Script dependencies failed, install missing dependencies and try again" exit 1 fi log "info" "Script dependencies good" print-break log "info" "Installing ${GREEN}FZF${RESET_BOLD}" if ! install-fzf "${DEPS_PATH}"; then log "error" "Failed to install ${GREEN}FZF${RESET_BOLD}" exit 1 fi log "info" "Successfully installed ${GREEN}FZF${RESET_BOLD}" tasks_done+=("Install FZF") print-break log "info" "Installing Rust" if ! install-rust "${DEPS_PATH}"; then log "error" "Failed to install ${GREEN}Rust${RESET_BOLD}" exit 1 fi log "info" "Successfully installed ${GREEN}Rust${RESET_BOLD}" tasks_done+=("Install Rust") print-break log "info" "Installing Cargo programs" local cargo_binaries=( ripgrep exa ) for pkg in "${cargo_binaries[@]}"; do log "info" "Attempting install of ${GREEN}${pkg}${RESET_BOLD}" if ! install-cargo-binary "${pkg}"; then log "error" "Failed installation of ${GREEN}${pkg}${RESET_BOLD}" exit 1 fi done log "info" "Finished installing Cargo programs" print-break log "info" "Installing ${GREEN}ZSH${RESET_BOLD}" if ! command -v "zsh" >/dev/null; then if ! install-from-pkg-mngr "zsh"; then log "error" "Failed to install ${GREEN}ZSH${RESET_BOLD}" exit 1 fi else log "info" "${GREEN}ZSH${RESET_BOLD} already installed, skipping" fi log "info" "Successfully installed ${GREEN}ZSH${RESET_BOLD}" log "info" "Deploying ${GREEN}ZSH${RESET_BOLD} configuration files" if ! deploy-config; then log "error" "Failed to deploy configuration files" exit 1 fi log "info" "Successfully installed ${GREEN}ZSH${RESET_BOLD} configuration files" log "info" "Finished installing ${GREEN}ZSH${RESET_BOLD} configurations and dependencies" } main "${@}"