#!/usr/bin/env bash set -eo pipefail DEPS_PATH="${HOME}/.local/share" SOURCE_DIR="$( cd $(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)/../dots; pwd)" PKG_INSTALL_CMD="" BOLD=$(tput bold) CYAN=$(tput setaf 6) M_COLOR=$(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}" local prefix="${M_COLOR}ZSH${RESET} - " case "${level}" in INFO) printf "%s%sINFO:%s %s%s%s\n" \ "${prefix}" \ "${CYAN}" \ "${RESET}" \ "${BOLD}" \ "${message}" \ "${RESET}" >&2 return 0 ;; WARN*) printf "%s%sWARN:%s %s%s%s\n" \ "${prefix}" \ "${YELLOW}" \ "${RESET}" \ "${BOLD}" \ "${message}" \ "${RESET}" >&2 return 0 ;; ERROR) printf "%s%sERROR:%s %s%s%s\n" \ "${prefix}" \ "${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 "${M_COLOR}%.s─${RESET}" $(seq 1 "$(tput cols)") } install-fzf() { local install_path="${1}/fzf" if ! [[ -e "${install_path}" ]]; then git clone --depth 1 https://github.com/junegunn/fzf.git "${install_path}" fi if ! [[ -e "${HOME}/.config/fzf/fzf.zsh" ]]; then log "info" "No ${M_COLOR}fzf${RESET_BOLD} config file found, generating" "${install_path}/install" \ --key-bindings \ --completion \ --no-update-rc \ --xdg >/dev/null else log "info" "${M_COLOR}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 ${M_COLOR}cargo${RESET_BOLD}: ${M_COLOR}${CARGO_HOME}${RESET_BOLD} & ${M_COLOR}rustup${RESET_BOLD}: ${M_COLOR}${RUSTUP_HOME}${RESET_BOLD}" curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --quiet else log "info" "${M_COLOR}Rust${RESET_BOLD} already installed, skipping" fi if [[ -z "$(ls "${RUSTUP_HOME}/toolchains" >/dev/null)" ]]; then log "info" "No toolchain found, installing a ${M_COLOR}Rust${RESET_BOLD} toolchain" log "info" "Setting ${M_COLOR}Rust${RESET_BOLD}'s toolchain to ${M_COLOR}stable${RESET_BOLD}" if ! "${CARGO_HOME}/bin/rustup" default stable; then log "error" "Failed to set a ${M_COLOR}Rust${RESET_BOLD} toolchain" return 1 fi else log "info" "${M_COLOR}Rust${RESET_BOLD} toolchain found, skipping toolchain setup" fi export PATH="${PATH}:${install_path}/cargo/bin" } install-omz() { local install_path="${1}/omz" if ! [[ -e "${install_path}" ]]; then git clone https://github.com/ohmyzsh/ohmyzsh.git "${install_path}" else log "info" "${M_COLOR}oh-my-zsh${RESET_BOLD} already installed, skipping" fi } install-cargo-binary() { local binary="${1}" cargo install "${binary}" } install-autojump() { local install_path="${1}/autojump" if ! [[ -e "${install_path}" ]]; then cd "$(mktemp -d)" git clone "https://github.com/wting/autojump.git" "autojump" || return 1 ( cd "autojump" python3 "install.py" -d "${install_path}" sed -i "s/\#\!\/usr\/bin\/env\ python/\#\!\/usr\/bin\/env\ python3/" \ "${install_path}/bin/autojump" ) || return 1 else log "info" "${M_COLOR}Autojump${RESET_BOLD} already installed, skipping" fi } check-script-deps() { local commands_to_check=( git gcc make python3 zsh ) local ret_code=0 for cmd in "${commands_to_check[@]}"; do if ! command -v "${cmd}" >/dev/null; then log "error" "Could not find command: ${M_COLOR}${cmd}${RESET_BOLD}, ensure you install this dependency" ret_code=1 else log "info" "Found dependency ${M_COLOR}${cmd}${RESET_BOLD}" fi done return "${ret_code}" } install-pyenv() { local install_path="${1}/pyenv" if ! [[ -e "${install_path}" ]]; then git clone https://github.com/pyenv/pyenv.git "${install_path}" || return 1 ( cd "${install_path}" src/configure && make -C src ) || return 1 else log "info" "${M_COLOR}Pyenv${RESET_BOLD} already installed, skipping" fi } create-dirs() { local dirs=( "${HOME}/.local/bin" "${HOME}/.local/share" ) ret_code=0 for dir in "${dirs[@]}"; do log "info" "Creating directory ${M_COLOR}${dir}${RESET_BOLD}" if ! mkdir -p "${dir}"; then log "error" "Failed to create directory: ${M_COLOR}${dir}${RESET_BOLD}" ret_code=1 fi done return "${ret_code}" } 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="${SOURCE_DIR}/${install_paths[${install_key}]}" local dest_path="${HOME}/${install_paths[${install_key}]}" if [[ -e "${dest_path}" ]]; then log "info" "${M_COLOR}${install_key}${RESET_BOLD} already exists at ${M_COLOR}${dest_path}${RESET_BOLD}, skipping" continue fi log "info" "Linking ${M_COLOR}${install_key}${RESET_BOLD}, ${M_COLOR}${src_path}${RESET_BOLD} to ${M_COLOR}${dest_path}${RESET_BOLD}" if ! ln -s "${src_path}" "${dest_path}"; then log "error" "Failed linking ${M_COLOR}${install_key}${RESET_BOLD}, ${M_COLOR}${src_path}${RESET_BOLD} to ${M_COLOR}${dest_path}${RESET_BOLD}" return 1 fi done } main() { local tasks_done=() log "info" "Set source directory as ${M_COLOR}${SOURCE_DIR}${RESET_BOLD}" log "info" "Dependencies directory set to ${M_COLOR}${DEPS_PATH}${RESET_BOLD}" log "info" "Packager install command set to ${M_COLOR}${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" "Creating directories" if ! create-dirs; then log "error" "Unable to create required directories" exit 1 fi log "info" "Finished creating directories" print-break log "info" "Installing ${M_COLOR}FZF${RESET_BOLD}" if ! install-fzf "${DEPS_PATH}"; then log "error" "Failed to install ${M_COLOR}FZF${RESET_BOLD}" exit 1 fi log "info" "Successfully installed ${M_COLOR}FZF${RESET_BOLD}" tasks_done+=("Install FZF") print-break log "info" "Installing Rust" if ! install-rust "${DEPS_PATH}"; then log "error" "Failed to install ${M_COLOR}Rust${RESET_BOLD}" exit 1 fi log "info" "Successfully installed ${M_COLOR}Rust${RESET_BOLD}" tasks_done+=("Install Rust") print-break log "info" "Installing Cargo programs" local cargo_binaries=( ripgrep exa fd-find bat ) for pkg in "${cargo_binaries[@]}"; do log "info" "Attempting install of ${M_COLOR}${pkg}${RESET_BOLD}" if ! install-cargo-binary "${pkg}"; then log "error" "Failed installation of ${M_COLOR}${pkg}${RESET_BOLD}" exit 1 fi done log "info" "Finished installing Cargo programs" print-break log "info" "Installing ${M_COLOR}Pyenv${RESET_BOLD}" if ! install-pyenv "${DEPS_PATH}"; then log "error" "Failed to install ${M_COLOR}Pyenv${RESET_BOLD}" exit 1 fi log "info" "Finished installing ${M_COLOR}Pyenv${RESET_BOLD}" print-break log "info" "Installing ${M_COLOR}autojump${RESET_BOLD}" if ! install-autojump "${DEPS_PATH}"; then log "error" "Failed to install ${M_COLOR}autojump${RESET_BOLD}" exit 1 fi log "info" "Finished installing ${M_COLOR}autojump${RESET_BOLD}" print-break log "info" "Install ${M_COLOR}Oh My ZSH${RESET_BOLD}" install-omz "${DEPS_PATH}" log "info" "Finished installing ${M_COLOR}Oh My ZSH${RESET_BOLD}" print-break log "info" "Deploying ${M_COLOR}ZSH${RESET_BOLD} configuration files" if ! deploy-config; then log "error" "Failed to deploy configuration files" exit 1 fi log "info" "Successfully installed ${M_COLOR}ZSH${RESET_BOLD} configuration files" print-break log "info" "Finished installing ${M_COLOR}ZSH${RESET_BOLD} configurations and dependencies" } main "${@}"