Dot_Files/install.bash

447 lines
13 KiB
Bash
Raw Normal View History

2022-01-08 15:24:29 -06:00
#!/bin/bash
2022-01-08 19:16:41 -06:00
# Exit on error
set -e
2022-01-09 00:28:07 -06:00
set -o pipefail
2022-01-08 19:16:41 -06:00
2022-01-08 15:24:29 -06:00
### Information ###
# This script deploys all dot files and installs all the following dependencies:
# - curl
2022-01-09 00:28:07 -06:00
# - python3
2022-01-08 19:16:41 -06:00
# - rust
2022-01-08 15:24:29 -06:00
# - zsh
# - ripgrep
# - bat
2022-01-08 19:16:41 -06:00
# - fzf
2022-01-08 15:24:29 -06:00
# - exa
2022-01-08 19:16:41 -06:00
# - neovim
2022-01-09 00:28:07 -06:00
# - autojump
2022-01-08 15:24:29 -06:00
#
# Additional dependencies per operating system:
# + MacOs (Darwin)
# - homebrew
#
# By default this script backs up any existing files it has to overwrite to
#
# ~/dot-files-backup-%+s
#
# Where %+s is seconds since unix epoch
### Information ###
### CONSTANTS AND GLOBALS ###
# These are variables used globally or are statically assigned for use
# later
### CONSTANTS AND GLOBALS ###
2022-01-08 19:16:41 -06:00
SCRIPT_DEPENDENCIES=(
2022-01-09 00:28:07 -06:00
zsh
2022-01-08 19:16:41 -06:00
gcc
git
2022-01-09 00:28:07 -06:00
curl
2022-01-08 19:16:41 -06:00
)
GIT_REPOSITORY="https://gitlab.orion-technologies.io/philler/dot-files.git"
2022-01-08 15:24:29 -06:00
PKG_MANAGER="${1}"
2022-01-08 19:16:41 -06:00
OLD_DOT_FILES_BACKUP="dot-files-backup-$(date "+%s")"
2022-01-08 15:24:29 -06:00
### Utilities ###
# These functions assist with basic lookups and reused
# functionality
### Utilities ###
2022-01-08 19:16:41 -06:00
check_sudo() {
sudo -v >/dev/null 2>&1
return "${?}"
}
echo_rgb() {
# Echo a colored string to the terminal based on rgb values
#
# NOTE: This function will only truly work with terminals that support TRUE COLOR, see:
# https://gist.github.com/XVilka/8346728
#
# Positional Arguments:
#
# message <type: string> <position: 1> <required: true>
# - The message to be printed to stdout
# red <type: int> <position: 2> <required: true>
# - The red value from 0 to 255
# green <type: int> <position: 3> <required: true>
# - The green value from 0 to 255
# blue <type: int> <position: 4> <required: true>
# - The blue value from 0 to 255
# bg_red <type: int> <position: 5> <required: false>
# - The background red value from 0 to 255
# bg_green <type: int> <position: 6> <required: false>
# - The background green value from 0 to 255
# bg_blue <type: int> <position: 7> <required: false>
# - The background blue value from 0 to 255
#
# Usage:
# echo_rgb "Yep" 10 80 30
# echo_rgb "DESTROY MY EYES" 255 0 255 0 255 0
#
# POSIX Compliant:
# N/A
#
local red
local green
local blue
local input
local bg_red
local bg_green
local bg_blue
input="${1}"
red="${2}"
green="${3}"
blue="${4}"
bg_red="${5}"
bg_green="${6}"
bg_blue="${7}"
for num in "${@:2}"; do
[[ ! "${num}" =~ [0-9] ]] &&
echo "Given RGB value was not a number, received ${num}" >&2 &&
return 1
[[ "${num}" -gt 255 ]] &&
echo "Given RGB value must be less than 255, received ${num}" >&2 &&
return 1
[[ "${num}" -lt 0 ]] &&
echo "Given RGB value must be more than 0, received ${num}" &&
return 1
done
if [ -n "${5}" ]; then
[[ -z "${6}" ]] && echo "A value must be passed for bg_green" && return 1
[[ -z "${7}" ]] && echo "A value must be passed for bg_blue" && return 1
printf "\033[38;2;%s;%s;%s;48;2;%s;%s;%sm%s\033[m\n" \
"${red}" "${green}" "${blue}" "${bg_red}" "${bg_green}" "${bg_blue}" "${input}"
else
printf "\033[0;38;2;%s;%s;%sm%s\033[m\n" "${red}" "${green}" "${blue}" "${input}"
fi
return 0
}
important() {
echo_rgb "${1}" 0 220 255
}
log() {
# Print a message and send it to stdout or stderr depending upon log level, also configurable with debug etc.
#
# Arguments:
# level <type: string> <position: 1> <required: true>
# - The log level, defined within a case check in this function
# message <type: string> <position: 2> <required: true>
# - The info message
# line_number <type: int> <position: 3> <required: false>
# - The line number of the calling function (${LINNO})
#
# Usage:
# log "info" "Could not find that directory"
#
# POSIX Compliant:
# Yes
#
# Set debug status depending if a global debug variable has been set to either 1 or 0
local debug
if [ ${DEBUG} ]; then
debug=${DEBUG}
else
debug=0
fi
local FORMAT
FORMAT="[$(echo_rgb "$(date +%Y-%m-%dT%H:%M:%S)" 180 140 255)]"
# Convert the level to uppercase
local level
level=$(echo "${1}" | tr '[:lower:]' '[:upper:]')
local message
message="${2}"
case "${level}" in
INFO)
# Output all info log levels to stdout
printf "${FORMAT}[$(echo_rgb "INFO" 0 140 255)] %s\n" "${message}" >&1
return 0
;;
WARN | WARNING)
# Output all warning log levels to stdout
printf "${FORMAT}[$(echo_rgb "WARNING" 255 255 0)] %s\n" "${message}" >&1
return 0
;;
DEBUG)
# Output all debug log levels to stdout
if [ "${DEBUG}" ]; then
printf "${FORMAT}[$(echo_rgb "DEBUG" 0 160 110)] %s\n" "${message}" >&1
fi
return 0
;;
ERROR)
# Output all error log levels to stderr
printf "${FORMAT}[$(echo_rgb "ERROR" 255 0 0)] %s\n" "${message}" >&2
return 0
;;
# Further log levels can be added by extending this switch statement with more comparisons
*) # Default case, no matches
# Returns non-zero code as an improper log option was passed, this helps with using `set -e`
printf "${FORMAT}[ERROR] %s\n" "Invalid log level passed, received level \"${level}\" with message \"${message}\"" >&2
return 1
;;
esac
}
2022-01-08 15:24:29 -06:00
determine_os() {
# Determine the operating system or distribution if on linux.
#
# Sets the package manager accordingly and installs missing package managers
# if necessary.
# Initial detection for MacOS
if [[ "${OSTYPE}" = "*darwin*" ]]; then
log "info" "Detected distribution as $(important "MacOS")"
PKG_MANAGER="brew install"
if ! which "${PKG_MANAGER}" >/dev/null 2>&1; then
log "info" "Installing homebrew for MacOS"
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
else
local etc_release
local distribution
etc_release="/etc/os-release"
# Detect if os-release exists
if [[ ! -f "${etc_release}" ]]; then
log "error" "Could not find $(important "${etc_release}"), this system is unsupported..."
return 1
fi
distribution="$(grep -i "^NAME=" "${etc_release}" | cut -d '"' -f 2 | tr "[:upper:]" "[:lower:]")"
case "${distribution}" in
*centos*)
log "info" "Detected distribution as $(important "CentOS")"
if which dnf >/dev/null 2>&1; then
PKG_MANAGER="dnf install -y"
else
PKG_MANAGER="yum install -y"
fi
2022-01-09 00:28:07 -06:00
SCRIPT_DEPENDENCIES+=(python39.x86_64 python2.x86_64 gcc-c++.x86_64)
2022-01-08 15:24:29 -06:00
;;
*ubuntu*)
log "info" "Detected distribution as $(important "Ubuntu")"
PKG_MANAGER="apt install -y"
;;
*)
log "error" "Unable to determine distribution"
return 1
;;
esac
fi
}
2022-01-09 00:28:07 -06:00
install_dependencies() {
2022-01-08 15:24:29 -06:00
if [[ -z "${PKG_MANAGER}" ]]; then
log "info" "No package manager provided at command line, attempting to detect..."
2022-01-09 00:28:07 -06:00
determine_os || return 1
2022-01-08 15:24:29 -06:00
fi
# Failover catch in case something doesn't get put through correctly
2022-01-08 19:16:41 -06:00
if ! which "$(echo "${PKG_MANAGER}" | cut -d " " -f1)" >/dev/null 2>&1; then
2022-01-08 15:24:29 -06:00
log "error" "Unable to find a package manager!" && return 1
fi
log "info" "Package manager detected as $(important "${PKG_MANAGER}")"
### ZSH Installation ###
# This does NOT configure your shell to be zsh
# In order to set your shell to zsh use chsh:
#
# chsh -s zsh
#
### ZSH Installation ###
# Package Manager Installations, things from the given package manager, e.g. yum
2022-01-08 19:16:41 -06:00
local install_str
2022-01-09 00:28:07 -06:00
for pkg in "${SCRIPT_DEPENDENCIES[@]}"; do
2022-01-08 15:24:29 -06:00
if ! which "${pkg}" >/dev/null 2>&1; then
log "info" "Installing package dependency $(important "${pkg}")"
2022-01-08 19:16:41 -06:00
2022-01-09 00:28:07 -06:00
if [[ "${OSTYPE}" = *"darwin"* ]]; then
2022-01-08 19:16:41 -06:00
install_str="${PKG_MANAGER} ${pkg}"
else
install_str="sudo ${PKG_MANAGER} ${pkg}"
fi
if ! eval "${install_str}"; then
2022-01-08 15:24:29 -06:00
log "error" "Unable to install $(important "${pkg}")"
2022-01-08 19:16:41 -06:00
return 1
2022-01-08 15:24:29 -06:00
fi
fi
done
2022-01-08 19:16:41 -06:00
}
check_script_dependencies() {
for dep in "${SCRIPT_DEPENDENCIES[@]}"; do
if ! which "${dep}" >/dev/null 2>&1; then
log "error" "Script dependency $(important "${dep}") could not be located, contact your local administrator to install this dependency"
fi
done
}
install_source_sudo() {
local program_path
program_path="${1}"
local program_name
program_name="$(basename "${program_path}")"
2022-01-09 00:28:07 -06:00
local install_dir
install_dir="${2:-/usr/bin}"
2022-01-08 19:16:41 -06:00
if check_sudo; then
2022-01-09 00:28:07 -06:00
log "info" "Sudo access detected, copying $(important "${program_name}") to $(important "${install_dir}/${program_name}")"
sudo cp "${program_path}" "${install_dir}"
sudo chown "root:root" "/${install_dir}/${program_name}"
sudo chmod 751 "/${install_dir}/${program_name}"
2022-01-08 19:16:41 -06:00
fi
}
source_installer() {
local cargo_path
cargo_path="${HOME}/.cargo/"
local cargo_bin
cargo_bin="${cargo_path}/bin/"
log "info" "Installing $(important "rust")"
bash <(curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs) -y
source "${cargo_path}/env"
log "info" "Installing $(important "ripgrep") from cargo"
cargo install --locked ripgrep
install_source_sudo "${cargo_bin}/rg"
log "info" "Installing $(important "bat") from cargo"
cargo install --locked bat
install_source_sudo "${cargo_bin}/bat"
log "info" "Installing $(important "fzf") from git"
2022-01-09 00:28:07 -06:00
mv "${HOME}/.fzf" "${OLD_DOT_FILES_BACKUP}"
2022-01-08 19:16:41 -06:00
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
2022-01-09 00:28:07 -06:00
eval ~/.fzf/install --all
2022-01-08 19:16:41 -06:00
log "info" "Installing $(important "exa")"
cargo install --locked exa
install_source_sudo "${cargo_bin}/exa"
log "info" "Installing $(important "neovim")"
if [[ "${OSTYPE}" = *"darwin"* ]]; then
eval "${PKG_MANAGER} neovim"
else
local nvim_url
2022-01-09 00:28:07 -06:00
nvim_url="https://github.com/neovim/neovim/releases/download/stable/nvim.appimage"
curl -LO "${nvim_url}" --output nvim.appimage
chmod u+x nvim.appimage
mv nvim.appimage nvim
install_source_sudo "$(pwd)/nvim" "/usr/local/bin/"
if [[ ! -f "/usr/local/bin/nvim" ]]; then
2022-01-08 19:16:41 -06:00
log "warning" \
"Could not install nvim to the path as sudo access could not be found\n
nvim binary located at $(important "$(pwd)/nvim")"
2022-01-09 00:28:07 -06:00
else
rm -f nvim
2022-01-08 19:16:41 -06:00
fi
fi
2022-01-08 15:24:29 -06:00
2022-01-09 00:28:07 -06:00
local autojump_temp
autojump_temp="autojump-temp-$(date "+%s")"
log "info" "Installing $(important "autojump")"
git clone https://github.com/wting/autojump.git "${autojump_temp}" && cd "${autojump_temp}"
python3 install.py
cd .. && rm -rf "${autojump_temp}"
2022-01-08 15:24:29 -06:00
log "info" "Installing $(important "oh-my-zsh")"
2022-01-08 19:16:41 -06:00
if [[ -d "${HOME}/.oh-my-zsh/" ]]; then
log "info" "Found a previous oh-my-zsh installation, backing up to $(important "${OLD_DOT_FILES_BACKUP}")"
mv "${HOME}/.oh-my-zsh" "${OLD_DOT_FILES_BACKUP}"
fi
2022-01-08 15:24:29 -06:00
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
}
2022-01-08 19:16:41 -06:00
main() {
2022-01-09 00:34:43 -06:00
cd "${HOME}"
2022-01-08 19:16:41 -06:00
log "info" "Installing dependencies"
if check_sudo; then
log "info" "Sudo access found, installing dependencies"
2022-01-09 00:28:07 -06:00
if ! install_dependencies; then
log "error" "Unable to install dependencies"
return 1
2022-01-08 19:16:41 -06:00
fi
else
if ! check_script_dependencies; then
log "error" "Unable to find required script dependencies"
return 1
fi
fi
if ! source_installer; then
log "error" "Failed to install some dependencies from source"
2022-01-09 00:28:07 -06:00
return 1
2022-01-08 19:16:41 -06:00
fi
local dot_files_temp
dot_files_temp="dot-files-$(date "+%s")"
2022-01-08 19:31:04 -06:00
log "info" "Cloning $(important "dot files") from $(important "https://gitlab.orion-technologies.io/philler/dot-files.git") to $(important "${dot_files_temp}")"
2022-01-08 19:29:30 -06:00
2022-01-08 19:16:41 -06:00
mkdir -p "${OLD_DOT_FILES_BACKUP}"
git clone --recurse-submodules "${GIT_REPOSITORY}" "${dot_files_temp}" && cd "${dot_files_temp}"
2022-01-08 19:31:04 -06:00
log "info" "Installing $(important "dot files")"
2022-01-08 19:16:41 -06:00
local dot_base
local dot_home
2022-01-09 00:28:07 -06:00
local exclusion_dirs
exclusion_dirs=(
".."
"."
"install.bash"
)
2022-01-08 19:16:41 -06:00
for dot_file in {,.}*; do
2022-01-09 00:28:07 -06:00
if [[ "${exclusion_dirs[*]}" =~ "${dot_file}" ]]; then
2022-01-08 19:16:41 -06:00
continue
fi
2022-01-09 00:28:07 -06:00
2022-01-08 19:16:41 -06:00
dot_base="$(basename "${dot_file}")"
dot_home="${HOME}/${dot_base}"
2022-01-09 00:28:07 -06:00
if dir "${dot_home}" >/dev/null 2>&1; then
log "info" "Found existing dot file: $(important "${dot_home}"), moving to $(important "${OLD_DOT_FILES_BACKUP}/${dot_base}")"
2022-01-08 19:16:41 -06:00
mv "${dot_home}" "${OLD_DOT_FILES_BACKUP}"
fi
log "info" "Installing dot file $(important "${dot_file}") to $(important "${dot_home}")"
mv "${dot_file}" "${dot_home}"
done
log "info" "Cleaning up..."
rm -rf "${dot_files_temp}"
log "info" "Finished, don't forget to change your shell to zsh: $(important "chsh -s zsh")"
}
main