This commit is contained in:
Brian Zalewski 2023-11-13 04:37:45 +00:00
parent c8ac018f64
commit d413ce15c7
5 changed files with 299 additions and 210 deletions

View file

@ -1,29 +1,41 @@
if ! command -v curl > /dev/null || ! command -v git > /dev/null || ! command -v expect > /dev/null || ! command -v rsync > /dev/null; then
if ! command -v curl > /dev/null || ! command -v git > /dev/null || ! command -v expect > /dev/null || ! command -v rsync > /dev/null || ! command -v unbuffer; then
if command -v apt-get > /dev/null; then
# Debian / Ubuntu
### Debian / Ubuntu
sudo apt-get update
sudo apt-get install -y build-essential curl expect git rsync
elif command -v dnf > /dev/null; then
# Fedora
### Fedora
sudo dnf install -y curl expect git rsync
elif command -v yum > /dev/null; then
# CentOS
### CentOS
sudo yum install -y curl expect git rsync
elif command -v pacman > /dev/null; then
# Archlinux
### Archlinux
sudo pacman update
sudo pacman -Syu base-devel curl expect git rsync procps-ng file
elif command -v zypper > /dev/null; then
# OpenSUSE
### OpenSUSE
sudo zypper install -y curl expect git rsync
elif command -v apk > /dev/null; then
# Alpine
### Alpine
apk add curl expect git rsync
elif [ -d /Applications ] && [ -d /Library ]; then
# macOS
### macOS
sudo xcode-select -p >/dev/null 2>&1 || xcode-select --install
elif [[ "$OSTYPE" == 'cygwin' ]] || [[ "$OSTYPE" == 'msys' ]] || [[ "$OSTYPE" == 'win32' ]]; then
# Windows
### Windows
choco install -y curl expect git rsync
elif command -v nix-env > /dev/null; then
### NixOS
echo "TODO - Add support for NixOS"
elif [[ "$OSTYPE" == 'freebsd'* ]]; then
### FreeBSD
echo "TODO - Add support for FreeBSD"
elif command -v pkg > /dev/null; then
### Termux
echo "TODO - Add support for Termux"
elif command -v xbps-install > /dev/null; then
### Void
echo "TODO - Add support for Void"
fi
fi

View file

@ -1,36 +1,45 @@
if ! command -v brew > /dev/null; then
if [ -d /home/linuxbrew/.linuxbrew/bin ]; then
eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)
logg info "Sourcing from /home/linuxbrew/.linuxbrew/bin/brew" && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
if ! command -v brew > /dev/null; then
echo "The /home/linuxbrew/.linuxbrew directory exists but something is not right. Try removing it and running the script again." && exit 1
logg error "The /home/linuxbrew/.linuxbrew directory exists but something is not right. Try removing it and running the script again." && exit 1
fi
else
# @description Installs Homebrew and addresses a couple potential issues
### Installs Homebrew and addresses a couple potential issues
if command -v sudo > /dev/null && sudo -n true; then
logg info "Installing Homebrew"
echo | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
else
echo "Homebrew is not installed. The script will attempt to install Homebrew and you might be prompted for your password."
logg info "Homebrew is not installed. The script will attempt to install Homebrew and you might be prompted for your password."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || BREW_EXIT_CODE="$?"
if [ -n "$BREW_EXIT_CODE" ]; then
if command -v brew > /dev/null; then
echo "Homebrew was installed but part of the installation failed. Trying a few things to fix the installation.."
logg warn "Homebrew was installed but part of the installation failed. Trying a few things to fix the installation.."
BREW_DIRS="share/man share/doc share/zsh/site-functions etc/bash_completion.d"
for BREW_DIR in $BREW_DIRS; do
if [ -d "$(brew --prefix)/$BREW_DIR" ]; then
sudo chown -R "$(whoami)" "$(brew --prefix)/$BREW_DIR"
logg info "Chowning $(brew --prefix)/$BREW_DIR" && sudo chown -R "$(whoami)" "$(brew --prefix)/$BREW_DIR"
fi
done
brew update --force --quiet
logg info "Running brew update --force --quiet" && brew update --force --quiet && logg success "Successfully ran brew update --force --quiet"
fi
fi
fi
# @description Ensures the `brew` binary is available on Linux machines. macOS installs `brew` into the default `PATH`
### Ensures the `brew` binary is available on Linux machines. macOS installs `brew` into the default `PATH`
# so nothing needs to be done for macOS.
if [ -d /home/linuxbrew/.linuxbrew/bin ]; then
eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)
logg info "Sourcing shellenv from /home/linuxbrew/.linuxbrew/bin/brew" && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
elif [ -f /opt/homebrew/bin/brew ]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
logg info "Sourcing shellenv from /opt/homebrew/bin/brew" && eval "$(/opt/homebrew/bin/brew shellenv)"
fi
fi
fi
if command -v brew > /dev/null; then
if ! brew list | grep gcc > /dev/null; then
logg info "Installing Homebrew gcc" && brew install gcc
fi
else
logg error "Failed to initialize Homebrew" && exit 2
fi

View file

@ -12,7 +12,7 @@ logg() {
fi
elif [ "$TYPE" == 'info' ]; then
if command -v gum > /dev/null; then
gum style " $(gum style --foreground="#00ffff" "○") $(gum style --faint --foreground="#ffffff" "$MSG")"
gum style " $(gum style --foreground="#00ffff" "○") $(gum style --faint "$MSG")"
else
echo "INFO: $MSG"
fi

View file

@ -67,28 +67,32 @@ if [ -n "$CI" ]; then
export WORK_ENVIRONMENT=false
fi
# @description Disconnect from WARP, if connected
if command -v warp-cli > /dev/null; then
if warp-cli status | grep 'Connected' > /dev/null; then
warp-cli disconnect && echo "Disconnected WARP to prevent conflicts"
fi
fi
# @description Detect `START_REPO` format and determine appropriate git address, otherwise use the master Install Doctor branch
if [ -z "$START_REPO" ]; then
START_REPO="https://github.com/megabyte-labs/install.doctor.git"
else
if [[ "$START_REPO" == *"/"* ]]; then
# Either full git address or GitHubUser/RepoName
if [[ "$START_REPO" == *":"* ]] || [[ "$START_REPO" == *"//"* ]]; then
START_REPO="$START_REPO"
else
START_REPO="https://github.com/${START_REPO}.git"
fi
setStartRepo() {
if [ -z "$START_REPO" ]; then
START_REPO="https://github.com/megabyte-labs/install.doctor.git"
else
START_REPO="https://github.com/$START_REPO/install.doctor.git"
if [[ "$START_REPO" == *"/"* ]]; then
# Either full git address or GitHubUser/RepoName
if [[ "$START_REPO" == *":"* ]] || [[ "$START_REPO" == *"//"* ]]; then
START_REPO="$START_REPO"
else
START_REPO="https://github.com/${START_REPO}.git"
fi
else
START_REPO="https://github.com/$START_REPO/install.doctor.git"
fi
fi
fi
}
# @description Disconnect from WARP, if connected
warpDisconnect() {
if command -v warp-cli > /dev/null; then
if warp-cli status | grep 'Connected' > /dev/null; then
warp-cli disconnect && echo "Disconnected WARP to prevent conflicts"
fi
fi
}
# @description Logs with style using Gum if it is installed, otherwise it uses `echo`. It also leverages Glow to render markdown.
# When Glow is not installed, it uses `cat`.

View file

@ -51,72 +51,88 @@
# [Install Doctor homepage](https://install.doctor)
# [Install Doctor documentation portal](https://install.doctor/docs) (includes tips, tricks, and guides on how to customize the system to your liking)
# @description Ensure Ubuntu / Debian run in `noninteractive` mode
export DEBIAN_FRONTEND=noninteractive
# @description Load default settings if it is in a CI setting
if [ -n "$CI" ]; then
export HOST="$HOST"
export NO_RESTART=true
export HEADLESS_INSTALL=true
export SOFTWARE_GROUP="Full"
export FULL_NAME="Brian Zalewski"
export PRIMARY_EMAIL="help@megabyte.space"
export PUBLIC_SERVICES_DOMAIN="lab.megabyte.space"
export RESTRICTED_ENVIRONMENT=false
export WORK_ENVIRONMENT=false
fi
# @description Disconnect from WARP, if connected
if command -v warp-cli > /dev/null; then
if warp-cli status | grep 'Connected' > /dev/null; then
warp-cli disconnect && echo "Disconnected WARP to prevent conflicts"
fi
fi
# @description Detect `START_REPO` format and determine appropriate git address, otherwise use the master Install Doctor branch
if [ -z "$START_REPO" ] && [ -z "$REPO" ]; then
START_REPO="https://github.com/megabyte-labs/install.doctor.git"
else
if [ -n "$REPO" ] && [ -z "$START_REPO" ]; then
START_REPO="$REPO"
fi
if [[ "$START_REPO" == *"/"* ]]; then
# Either full git address or GitHubUser/RepoName
if [[ "$START_REPO" == *":"* ]] || [[ "$START_REPO" == *"//"* ]]; then
START_REPO="$START_REPO"
else
START_REPO="https://github.com/${START_REPO}.git"
fi
else
START_REPO="https://github.com/$START_REPO/install.doctor.git"
fi
fi
{{ include "partials" "logg" }}
# @description Notify user that they can press CTRL+C to prevent /etc/sudoers from being modified (which is currently required for headless installs on some systems)
sudo -n true || SUDO_EXIT_CODE=$?
logg info 'Your user will temporarily be granted passwordless sudo for the duration of the script'
if [ -n "$SUDO_EXIT_CODE" ]; then
logg info 'Press CTRL+C to bypass this prompt to either enter your password when needed or perform a non-privileged installation'
logg info 'Note: Non-privileged installations are not yet supported'
fi
# @description Add current user to /etc/sudoers so that headless automation is possible
if ! sudo cat /etc/sudoers | grep '# TEMPORARY FOR INSTALL DOCTOR' > /dev/null; then
if [ -n "$SUDO_PASSWORD" ]; then
printf '%s\n' "$SUDO_PASSWORD" | sudo -p "" -S echo "$(whoami) ALL=(ALL:ALL) NOPASSWD: ALL # TEMPORARY FOR INSTALL DOCTOR" | sudo tee -a /etc/sudoers
# @section Environment variables and system dependencies
# @description Ensure Ubuntu / Debian run in `noninteractive` mode. Detect `START_REPO` format and determine appropriate git address,
# otherwise use the master Install Doctor branch
setEnvironmentVariables() {
export DEBIAN_FRONTEND=noninteractive
if [ -z "$START_REPO" ] && [ -z "$REPO" ]; then
export START_REPO="https://github.com/megabyte-labs/install.doctor.git"
else
echo "$(whoami) ALL=(ALL:ALL) NOPASSWD: ALL # TEMPORARY FOR INSTALL DOCTOR" | sudo tee -a /etc/sudoers
if [ -n "$REPO" ] && [ -z "$START_REPO" ]; then
export START_REPO="$REPO"
fi
if [[ "$START_REPO" == *"/"* ]]; then
# Either full git address or GitHubUser/RepoName
if [[ "$START_REPO" == *":"* ]] || [[ "$START_REPO" == *"//"* ]]; then
export START_REPO="$START_REPO"
else
export START_REPO="https://github.com/${START_REPO}.git"
fi
else
export START_REPO="https://github.com/$START_REPO/install.doctor.git"
fi
fi
fi
}
# @section Qubes dom0 Bootstrap
# @description Perform Qubes dom0 specific logic like updating system packages, setting up the Tor VM, updating TemplateVMs, and
# beginning the provisioning process using Ansible and an AppVM used to handle the provisioning process
if command -v qubesctl > /dev/null; then
# @description Ensure sys-whonix is configured (for Qubes dom0)
# @description Ensure dependencies like `git` and `curl` are installed (among a few other lightweight system packages)
ensureBasicDeps() {
{{ include "partials" "basic-deps" }}
}
# @description Ensure Homebrew is installed and available in the `PATH`
ensureHomebrew() {
{{ include "partials" "homebrew" }}
}
# @description Load default settings if it is in a CI setting
setCIEnvironmentVariables() {
if [ -n "$CI" ]; then
logg info "Automatically setting environment variables since the CI environment variable is defined"
logg info "Setting HOST to $HOST" && export HOST="$HOST"
logg info "Setting NO_RESTART to true" && export NO_RESTART=true
logg info "Setting HEADLESS_INSTALL to true " && export HEADLESS_INSTALL=true
logg info "Setting SOFTWARE_GROUP to Full-Desktop" && export SOFTWARE_GROUP="Full-Desktop"
logg info "Setting FULL_NAME to Brian Zalewski" && export FULL_NAME="Brian Zalewski"
logg info "Setting PRIMARY_EMAIL to help@megabyte.space" && export PRIMARY_EMAIL="help@megabyte.space"
logg info "Setting PUBLIC_SERVICES_DOMAIN to lab.megabyte.space" && export PUBLIC_SERVICES_DOMAIN="lab.megabyte.space"
logg info "Setting RESTRICTED_ENVIRONMENT to false" && export RESTRICTED_ENVIRONMENT=false
logg info "Setting WORK_ENVIRONMENT to false" && export WORK_ENVIRONMENT=false
fi
}
# @description Disconnect from WARP, if connected
ensureWarpDisconnected() {
if command -v warp-cli > /dev/null; then
if warp-cli status | grep 'Connected' > /dev/null; then
logg info "Disconnecting from WARP" && warp-cli disconnect && logg success "Disconnected WARP to prevent conflicts"
fi
fi
}
# @description Notify user that they can press CTRL+C to prevent `/etc/sudoers` from being modified (which is currently required for headless installs on some systems).
# Additionally, this function will add the current user to `/etc/sudoers` so that headless automation is possible.
setupPasswordlessSudo() {
sudo -n true || SUDO_EXIT_CODE=$?
logg info 'Your user will temporarily be granted passwordless sudo for the duration of the script'
if [ -n "$SUDO_EXIT_CODE" ]; then
logg info 'Press CTRL+C to bypass this prompt to either enter your password when needed or perform a non-privileged installation'
logg info 'Note: Non-privileged installations are not yet supported'
fi
if ! sudo cat /etc/sudoers | grep '# TEMPORARY FOR INSTALL DOCTOR' > /dev/null; then
if [ -n "$SUDO_PASSWORD" ]; then
printf '%s\n' "$SUDO_PASSWORD" | sudo -p "" -S echo "$(whoami) ALL=(ALL:ALL) NOPASSWD: ALL # TEMPORARY FOR INSTALL DOCTOR" | sudo tee -a /etc/sudoers
else
echo "$(whoami) ALL=(ALL:ALL) NOPASSWD: ALL # TEMPORARY FOR INSTALL DOCTOR" | sudo tee -a /etc/sudoers
fi
fi
}
# @section Qubes dom0
# @description Ensure sys-whonix is configured (for Qubes dom0)
ensureSysWhonix() {
CONFIG_WIZARD_COUNT=0
function configureWizard() {
if xwininfo -root -tree | grep "Anon Connection Wizard"; then
@ -143,21 +159,27 @@ if command -v qubesctl > /dev/null; then
fi
fi
}
}
# @description Ensure dom0 is updated
# @description Ensure dom0 is updated
ensureDom0Updated() {
if [ ! -f /root/dom0-updated ]; then
sudo qubesctl --show-output state.sls update.qubes-dom0
sudo qubes-dom0-update --clean -y
touch /root/dom0-updated
fi
}
# @description Ensure sys-whonix is running
# @description Ensure sys-whonix is running
ensureSysWhonixRunning() {
if ! qvm-check --running sys-whonix; then
qvm-start sys-whonix --skip-if-running
configureWizard > /dev/null
fi
}
# @description Ensure TemplateVMs are updated
# @description Ensure TemplateVMs are updated
ensureTemplateVMsUpdated() {
if [ ! -f /root/templatevms-updated ]; then
# timeout of 10 minutes is added here because the whonix-gw VM does not like to get updated
# with this method. Anyone know how to fix this?
@ -167,17 +189,20 @@ if command -v qubesctl > /dev/null; then
done< <(qvm-ls --all --no-spinner --fields=name,state | grep Running | grep -v sys-net | grep -v sys-firewall | grep -v sys-whonix | grep -v dom0 | awk '{print $1}')
sudo touch /root/templatevms-updated
fi
}
# @description Ensure provisioning VM can run commands on any VM
# @description Ensure provisioning VM can run commands on any VM
ensureProvisioningVMPermissions() {
echo "/bin/bash" | sudo tee /etc/qubes-rpc/qubes.VMShell
sudo chmod 755 /etc/qubes-rpc/qubes.VMShell
echo "${ANSIBLE_PROVISION_VM:=provision}"' dom0 allow' | sudo tee /etc/qubes-rpc/policy/qubes.VMShell
echo "$ANSIBLE_PROVISION_VM"' $anyvm allow' | sudo tee -a /etc/qubes-rpc/policy/qubes.VMShell
sudo chown "$(whoami):$(whoami)" /etc/qubes-rpc/policy/qubes.VMShell
sudo chmod 644 /etc/qubes-rpc/policy/qubes.VMShell
}
# @description Create provisioning VM and initialize the provisioning process from there
# @description Create provisioning VM and initialize the provisioning process from there
createAndInitProvisionVM() {
qvm-create --label red --template debian-11 "$ANSIBLE_PROVISION_VM" &> /dev/null || true
qvm-volume extend "$ANSIBLE_PROVISION_VM:private" "40G"
if [ -f ~/.vaultpass ]; then
@ -185,68 +210,87 @@ if command -v qubesctl > /dev/null; then
qvm-copy-to-vm "$ANSIBLE_PROVISION_VM" ~/.vaultpass
qvm-run "$ANSIBLE_PROVISION_VM" 'cp ~/QubesIncoming/dom0/.vaultpass ~/.vaultpass'
fi
}
# @description Restart the provisioning process with the same script but from the provisioning VM
# @description Restart the provisioning process with the same script but from the provisioning VM
runStartScriptInProvisionVM() {
qvm-run --pass-io "$ANSIBLE_PROVISION_VM" 'curl -sSL https://install.doctor/start > ~/start.sh && bash ~/start.sh'
exit 0
fi
}
# @description Ensure basic system packages are available on the device
{{ include "partials" "basic-deps" }}
# @description Perform Qubes dom0 specific logic like updating system packages, setting up the Tor VM, updating TemplateVMs, and
# beginning the provisioning process using Ansible and an AppVM used to handle the provisioning process
handleQubesDom0() {
if command -v qubesctl > /dev/null; then
ensureSysWhonix
ensureDom0Updated
ensureSysWhonixRunning
ensureTemplateVMsUpdated
ensureProvisioningVMPermissions
createAndInitProvisionVM
runStartScriptInProvisionVM
exit 0
fi
}
# @description Ensure Homebrew is installed and available
{{ include "partials" "homebrew" }}
# @section Homebrew dependencies
# @description Helper function used by [[ensureHomebrewDeps]] to ensure a Homebrew package is installed after
# first checking if it is already available on the system.
installBrewPackage() {
if ! command -v "$1" > /dev/null; then
logg 'Installing '"$1"''
brew install "$1"
fi
}
# @description Ensure Chezmoi is installed
if ! command -v chezmoi > /dev/null; then
brew install chezmoi
fi
# @description Installs various dependencies using Homebrew.
#
# 1. Ensures Chezmoi, Node.js, and ZX are installed.
# 2. Installs Glow and Gum if the `HEADLESS_INSTALL` environment variable is not set.
# 3. If the system is macOS, then also install `gsed`.
ensureHomebrewDeps() {
### TUI experience
if [ -z "$HEADLESS_INSTALL" ]; then
installBrewPackage "gum"
installBrewPackage "glow"
fi
# @description Ensure Node.js is installed
if ! command -v node > /dev/null; then
brew install node
fi
### Base dependencies
installBrewPackage "chezmoi"
installBrewPackage "node"
installBrewPackage "zx"
# @description Ensure ZX is installed
if ! command -v zx > /dev/null; then
brew install zx
fi
### macOS
if [ -d /Applications ] && [ -d /System ]; then
installBrewPackage "gsed"
fi
}
# @description Install Glow / Gum if the `HEADLESS_INSTALL` variable is not set to true
if [ "$HEADLESS_INSTALL" != 'true' ]; then
# @description Ensure Gum is installed
if ! command -v gum > /dev/null; then
brew install gum
fi
# @section Chezmoi
# @description Ensure the `${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi` directory is cloned and up-to-date using the previously
# set `START_REPO` as the source repository.
cloneChezmoiSourceRepo() {
logg info 'Setting git http.postBuffer value high for large source repository' && git config --global http.postBuffer 524288000
if [ -d "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/.git" ]; then
logg info "Changing directory to ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi" && cd "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi"
logg info "Pulling the latest changes in ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi" && git pull origin master
else
logg info "Ensuring ${XDG_DATA_HOME:-$HOME/.local/share} is a folder" && mkdir -p "${XDG_DATA_HOME:-$HOME/.local/share}"
logg info "Cloning ${START_REPO} to ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi" && git clone "${START_REPO}" "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi"
fi
}
# @description Ensure Glow is installed
if ! command -v glow > /dev/null; then
brew install glow
fi
fi
# @description Ensure the ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi directory is cloned and up-to-date
logg info 'Setting git http.postBuffer value high for large source repository'
git config --global http.postBuffer 524288000
if [ -d "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/.git" ]; then
cd "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi"
logg info "Pulling the latest changes from ${START_REPO:-https://github.com/megabyte-labs/install.doctor.git}"
git pull origin master
else
logg info "Ensuring ${XDG_DATA_HOME:-$HOME/.local/share} is a folder"
mkdir -p "${XDG_DATA_HOME:-$HOME/.local/share}"
logg info "Cloning ${START_REPO} to ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi"
git clone ${START_REPO} "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi"
fi
# @description If the `${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml` file is missing, then guide the user through the initial setup
if [ ! -f "${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml" ]; then
# @description Show introduction message if Glow is installed
# @description Guide the user through the initial setup by showing TUI introduction and accepting input through various prompts.
#
# 1. Show `chezmoi-intro.md` with `glow`
# 2. Prompt for the software group if the `SOFTWARE_GROUP` variable is not defined
# 3. Run `chezmoi init` when the Chezmoi configuration is missing (i.e. `${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml`)
initChezmoiAndPrompt() {
### Show `chezmoi-intro.md` with `glow`
if command -v glow > /dev/null; then
glow "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/docs/terminal/chezmoi-intro.md"
fi
# @description Prompt for the software group if the `SOFTWARE_GROUP` variable is not defined
### Prompt for the software group if the `SOFTWARE_GROUP` variable is not defined
if command -v gum > /dev/null; then
if [ -z "$SOFTWARE_GROUP" ]; then
logg prompt 'Select the software group you would like to install. If your environment is a macOS, Windows, or environment with the DISPLAY environment variable then desktop software will be installed too. The software groups are in the '"${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml"' file.'
@ -257,74 +301,94 @@ if [ ! -f "${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml" ]; then
logg error 'Woops! Gum needs to be installed for the guided installation. Try running brew install gum' && exit 1
fi
# @description Run `chezmoi init` when the Chezmoi configuration is missing
logg info 'Running chezmoi init since the '"${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml"' is not present'
chezmoi init
fi
if [ ! -f "${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml" ]; then
### Run `chezmoi init` when the Chezmoi configuration is missing
logg info 'Running chezmoi init since the '"${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml"' is not present'
chezmoi init
fi
}
# @description Run `chezmoi apply` and enable verbose mode if the `DEBUG_MODE` or `DEBUG` environment variable is set to true
if [ "$DEBUG_MODE" = 'true' ]; then
DEBUG_MODIFIER="-vvvvv"
elif [ "$DEBUG" = 'true' ]; then
DEBUG_MODIFIER="-vvvvv"
fi
configureDebugMode() {
if [ -n "$DEBUG_MODE" ] || [ -n "$DEBUG" ]; then
logg info "Either DEBUG_MODE or DEBUG environment variables were set so Chezmoi will be run in debug mode"
export DEBUG_MODIFIER="-vvvvv"
fi
}
# @description Save the log of the provision process to `$HOME/.local/var/log/install.doctor/install.doctor.$(date +%s).log` and add the Chezmoi
# `--force` flag if the `HEADLESS_INSTALL` variable is set to true.
mkdir -p "$HOME/.local/var/log/install.doctor"
LOG_FILE="$HOME/.local/var/log/install.doctor/install.doctor.$(date +%s).log"
if [ "$HEADLESS_INSTALL" = 'true' ]; then
logg info 'Running chezmoi apply forcefully'
if command -v unbuffer > /dev/null; then
if command -v caffeinate > /dev/null; then
caffeinate unbuffer -p chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE"
# `--force` flag if the `HEADLESS_INSTALL` variable is set to `true``.
runChezmoi() {
mkdir -p "$HOME/.local/var/log/install.doctor"
LOG_FILE="$HOME/.local/var/log/install.doctor/install.doctor.$(date +%s).log"
if [ "$HEADLESS_INSTALL" = 'true' ]; then
logg info 'Running chezmoi apply forcefully'
if command -v unbuffer > /dev/null; then
if command -v caffeinate > /dev/null; then
caffeinate unbuffer -p chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE"
else
unbuffer -p chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE"
fi
else
unbuffer -p chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE"
if command -v caffeinate > /dev/null; then
caffeinate chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE"
else
chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE"
fi
fi
else
if command -v caffeinate > /dev/null; then
caffeinate chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE"
logg info 'Running chezmoi apply'
if command -v unbuffer > /dev/null; then
if command -v caffeinate > /dev/null; then
caffeinate unbuffer -p chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE"
else
unbuffer -p chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE"
fi
else
chezmoi apply $DEBUG_MODIFIER -k --force 2>&1 | tee "$LOG_FILE"
if command -v caffeinate > /dev/null; then
caffeinate chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE"
else
chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE"
fi
fi
fi
else
logg info 'Running chezmoi apply'
if command -v unbuffer > /dev/null; then
if command -v caffeinate > /dev/null; then
caffeinate unbuffer -p chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE"
else
unbuffer -p chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE"
fi
else
if command -v caffeinate > /dev/null; then
caffeinate chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE"
else
chezmoi apply $DEBUG_MODIFIER -k 2>&1 | tee "$LOG_FILE"
fi
fi
fi
# @description Ensure gsed is available on macOS (for modifying `/etc/sudoers` to remove passwordless sudo)
if [ -d /Applications ] && [ -d /System ]; then
if ! command -v gsed > /dev/null; then
if command -v brew > /dev/null; then
brew install gsed
else
logg warn 'Homebrew is not available and passwordless sudo might still be enabled in /etc/sudoers. Modify the file manually if you wish to disable passwordless sudo.'
fi
fi
fi
}
# @section Post-provision logic
# @description Ensure temporary passwordless sudo privileges are removed from `/etc/sudoers`
if command -v gsed > /dev/null; then
removePasswordlessSudo() {
if command -v gsed > /dev/null; then
sudo gsed -i '/# TEMPORARY FOR INSTALL DOCTOR/d' /etc/sudoers || logg warn 'Failed to remove passwordless sudo from the /etc/sudoers file'
else
else
sudo sed -i '/# TEMPORARY FOR INSTALL DOCTOR/d' /etc/sudoers || logg warn 'Failed to remove passwordless sudo from the /etc/sudoers file'
fi
fi
}
# @description Render the `docs/terminal/post-install.md` file to the terminal at the end of the provisioning process
logg success 'Provisioning complete!'
if command -v glow > /dev/null && [ -f "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/docs/terminal/post-install.md" ]; then
glow "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/docs/terminal/post-install.md"
fi
postProvision() {
logg success 'Provisioning complete!'
if command -v glow > /dev/null && [ -f "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/docs/terminal/post-install.md" ]; then
glow "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/docs/terminal/post-install.md"
fi
}
# @section Execution order
# @description The `provisionLogic` function is used to define the order of the script. All of the functions it relies on are defined
# above.
provisionLogic() {
logg info "Setting environment variables" && setEnvironmentVariables
logg info "Handling CI variables" && setCIEnvironmentVariables
logg info "Ensuring WARP is disconnected" && ensureWarpDisconnected
logg info "Ensuring system Homebrew dependencies are installed" && ensureBasicDeps
logg info "Ensuring Homebrew is available" && ensureHomebrew
logg info "Applying passwordless sudo" && setupPasswordlessSudo
logg info "Handling Qubes dom0 logic (if applicable)" && handleQubesDom0
logg info "Cloning / updating source repository" && cloneChezmoiSourceRepo
logg info "Handling pre-provision logic" && initChezmoiAndPrompt
logg info "Handling debug mode if DEBUG or DEBUG_MODE are defined" && configureDebugMode
logg info "Running the Chezmoi provisioning" && runChezmoi
logg info "Ensuring temporary passwordless sudo is removed" && removePasswordlessSudo
logg info "Handling post-provision logic" && postProvision
}
provisionLogic