#!/usr/bin/env bash # Bootstrap and kick off installing DotFriedRice. # # Examples: # ./bootstrap # Clone from the default remote location # ./bootstrap --local # Copy from your $PWD instead of cloning (useful for testing) # # You can also customize the branch and more (check the env vars below). set -o errexit set -o pipefail set -o nounset export C_RED=$'\e[1;31;1m' export C_GREEN=$'\e[1;32;1m' export C_YELLOW=$'\e[1;33;1m' # shellcheck disable=2034 export C_BLUE=$'\e[1;34;1m' export C_MAGENTA=$'\e[1;35;1m' export C_CYAN=$'\e[1;36;1m' export C_WHITE=$'\e[1;37;1m' export C_RESET=$'\e[0m' export PACKAGES_CRITICAL=("git" "nano") export LOCAL="0" export CPU_ARCH= export OS_TYPE= export OS_KERNEL= export OS_DISTRO= export OS_DISTRO_ORIGINAL= export OS_DISTRO_LIKE= export OS_VERSION= export OS_IN_WSL="0" export OS_IN_CONTAINER="${OS_IN_CONTAINER:-0}" export GUI_LINUX="0" export GUI_ELIGIBLE="0" export GUI_ENABLED="0" export DOTFRIEDRICE_PATH="${DOTFRIEDRICE_PATH:-"${HOME}/dotfriedrice"}" export DOTFRIEDRICE_BRANCH="${DOTFRIEDRICE_BRANCH:-master}" export DOTFRIEDRICE_CLONE_URL="${DOTFRIEDRICE_CLONE_URL:-https://github.com/nickjj/dotfriedrice}" export DOTFRIEDRICE_UPSTREAM_URL="${DOTFRIEDRICE_UPSTREAM_URL:-"${DOTFRIEDRICE_CLONE_URL}"}" for arg in "${@}"; do case "${arg}" in --local) LOCAL=1 shift ;; esac done # ----------------------------------------------------------------------------- # Helper functions # ----------------------------------------------------------------------------- _skipping() { local message="${1}" local pre_message="${2:-}" printf "%b%bSkipping: %b%b\n" "${pre_message}" "${C_WHITE}" "${message}" "${C_RESET}" } _info() { local message="${1}" local pre_message="${2-\n\n}" printf "%b%b:: %b%b\n\n" "${pre_message}" "${C_CYAN}" "${message}" "${C_RESET}" } _warning() { local message="${1}" local pre_message="${2:-}" printf "%b%bWarning: %b%b\n" "${pre_message}" "${C_YELLOW}" "${message}" "${C_RESET}" } _error() { local message="${1}" local exit_strategy="${2-1}" printf "%bError: %b%b\n" "${C_RED}" "${message}" "${C_RESET}" >&2 # If the file is sourced, return instead of exit. if [[ "${BASH_SOURCE[0]}" != "${0}" && "${exit_strategy}" == "1" ]]; then exit_strategy="2" fi case "${exit_strategy}" in 1) exit 1 ;; 2) return 1 ;; "") return 0 ;; esac } _run_as_root() { if command -v sudo >/dev/null 2>&1; then sudo bash -c "${*}" else su -c "${*}" fi } _package_install() { local packages=("${@}") case "${OS_DISTRO}" in arch) _run_as_root pacman -Syu --noconfirm --needed "${packages[*]}" ;; debian) _run_as_root apt-get update && _run_as_root apt-get install --yes --no-install-recommends "${packages[*]}" ;; *) brew install "${packages[@]}" ;; esac } _dotfriedrice_env() { local flag="${1:-}" local gui_enabled= local commit="-" if [ "${flag}" == "--gui-enabled" ]; then gui_enabled=$'\n'"GUI_ENABLED=\"${GUI_ENABLED}\"" fi if [[ -d "${DOTFRIEDRICE_PATH}/.git" && -f "${DOTFRIEDRICE_PATH}/dotfriedrice" ]]; then commit="$(git -C "${DOTFRIEDRICE_PATH}" log -1 --format="%as :: %h :: %s" 2>/dev/null || echo "-")" fi cat <&2 Your distro identified as: '${OS_DISTRO_ORIGINAL}' (based on: '${OS_DISTRO_LIKE}') Supported distros are Arch and Debian based distros. If your distro identifies as one of those the expectation is it should be supported. If you feel this is a bug please open an issue at: ${DOTFRIEDRICE_CLONE_URL} Please include the output of running: cat /etc/os-release EOF _error "Your distro isn't supported, aborting!" fi # Are we in WSL? if grep --quiet --ignore-case "microsoft" /proc/version; then OS_IN_WSL="1" fi # We can't fully depend on these which is why this env var exists, but it # at least protects someone running this script who didn't pass in the # environment variable in the common case (Docker or Podman). [[ -f "/.dockerenv" || -f "/run/.containerenv" ]] && OS_IN_CONTAINER="1" # Can we install and configure a window manager and GUI tools? if [[ "${OS_DISTRO_LIKE}" = "arch" && "${OS_IN_WSL}" != "1" && "${OS_IN_CONTAINER}" != "1" ]]; then GUI_ELIGIBLE="1" fi if [[ "${GUI_LINUX}" == "1" && "${GUI_ELIGIBLE}" == "1" ]]; then GUI_ENABLED="1" fi ;; darwin*) OS_TYPE="darwin" OS_DISTRO="${OS_TYPE}" OS_DISTRO_ORIGINAL="${OS_DISTRO}" OS_DISTRO_LIKE="${OS_DISTRO}" OS_VERSION="$(uname -r)" ;; *) _error "'${OSTYPE}' isn't supported, aborting!" ;; esac OS_KERNEL="$(uname -r)" CPU_ARCH="$(uname -m)" } detect_env_results() { _info "DETECT ENVIRONMENT" local flag="${1:-}" detect_env _dotfriedrice_env "${flag}" # This will come up when running the dotfriedrice script for the first time. if [[ "${DOTFRIEDRICE_FIRST_RUN:-}" == "1" && "${GUI_ENABLED}" == "1" && "${OS_DISTRO_ORIGINAL}" != "${OS_DISTRO}" ]]; then cat </dev/null 2>&1; then _package_install "sudo" fi if sudo --validate >/dev/null 2>&1; then echo "Confirmed, it's working" else local sudoers_dir="/etc/sudoers.d" local real_user= real_user="${SUDO_USER:-${USER:-$(whoami)}}" local user_file="${sudoers_dir}/00_${real_user}" local user_entry="${real_user} ALL=(ALL:ALL) ALL" _run_as_root "mkdir -p ${sudoers_dir} && echo '${user_entry}' > ${user_file} && chmod 0440 ${user_file}" echo "'${user_file}' was created with '${user_entry}'" sudo --validate fi } install_homebrew() { _info "INSTALL HOMEBREW" local brew_prefix="/opt/homebrew" [ "${CPU_ARCH}" != "arm64" ] && brew_prefix="/usr/local" local brew_bin_path="${brew_prefix}/bin/brew" if [ -f "${brew_bin_path}" ]; then _skipping "Already installed" return fi /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" eval "$(${brew_bin_path} shellenv)" } install_critical_packages() { _info "INSTALL CRITICAL PACKAGES" if [ "${OS_TYPE}" == "darwin" ]; then PACKAGES_CRITICAL+=("bash") fi _package_install "${PACKAGES_CRITICAL[@]}" } _local_clone() { [ "${LOCAL}" != "1" ] && return 1 local source_path source_path="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" if [ "$(realpath "${source_path}")" == "$(realpath "${DOTFRIEDRICE_PATH}")" ]; then # This is already protected against in the clone_dotfriedrice function but # this is an extra layer of defense in case that function changes. _skipping "'${source_path}' is your real DotFriedRice path" else cp -R "${source_path}/." "${DOTFRIEDRICE_PATH}" # Ensure the containerized environment starts fresh. if [ "${OS_IN_CONTAINER}" == "1" ]; then rm -f \ "${DOTFRIEDRICE_PATH}/.config/ghostty/config.local" \ "${DOTFRIEDRICE_PATH}/.config/git/config.local" \ "${DOTFRIEDRICE_PATH}/.config/mako/config.local" \ "${DOTFRIEDRICE_PATH}/.config/niri/config.kdl.local" \ "${DOTFRIEDRICE_PATH}/.config/zsh/.aliases.local" \ "${DOTFRIEDRICE_PATH}/.config/zsh/.zprofile.local" \ "${DOTFRIEDRICE_PATH}/.config/zsh/.zsh_history" \ "${DOTFRIEDRICE_PATH}/.config/zsh/.zshrc.local" local git_config="${DOTFRIEDRICE_PATH}/.git/config" if grep --quiet "git@github.com:" "${git_config}"; then perl -pi -e "s|git@github.com:|https://github.com/|g" "${git_config}" fi cp -n "${DOTFRIEDRICE_PATH}/dotfriedrice-config.example" "${DOTFRIEDRICE_PATH}/dotfriedrice-config" fi fi echo "Locally copied from '${source_path}' to '${DOTFRIEDRICE_PATH}'" } clone_dotfriedrice() { _info "CLONE DOTFRIEDRICE" cat <