1073 lines
51 KiB
Bash
1073 lines
51 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# @description Copies the `~/.config/shell/exports.sh` file to `/etc/zshenv` so that non-interactive ZSH sessions have all of the same
|
|
# environment PATH variables as interactive sessions. This was initially required to make Cakebrew work on macOS.
|
|
addZshEnv() {
|
|
### Ensure /etc/zshenv is populated
|
|
# No equivalent type of file for Bash
|
|
logg info "Copying ${XDG_CONFIG_HOME:-$HOME/.config}/shell/exports.sh to /etc/zshenv" && sudo cp -f "${XDG_CONFIG_HOME:-$HOME/.config}/shell/exports.sh" /etc/zshenv
|
|
}
|
|
|
|
# @description Ensures fonts are available at the system level and, on Linux, it configures the system font settings.
|
|
applyFontsToSystem() {
|
|
### Sync user fonts with system fonts
|
|
if [ -d /Applications ] && [ -d /System ]; then
|
|
### macOS
|
|
logg info 'Copying fonts from ~/Library/Fonts and ~/.local/share/fonts to /Library/Fonts to make them available globally'
|
|
FONT_DIR='/Library/Fonts'
|
|
sudo rsync -av "$HOME/Library/Fonts" "$FONT_DIR"
|
|
sudo rsync -av "${XDG_DATA_HOME:-$HOME/.local/share}/fonts" "$FONT_DIR"
|
|
else
|
|
### Linux
|
|
### Copy fonts
|
|
logg info 'Copying fonts from ~/.local/share/fonts to /usr/local/share/fonts to make them available globally'
|
|
FONT_DIR='/usr/local/share/fonts'
|
|
sudo rsync -av "${XDG_DATA_HOME:-$HOME/.local/share}/fonts" "$FONT_DIR"
|
|
|
|
### Configure system font properties
|
|
if [ -d /etc/fonts ]; then
|
|
logg info 'Copying ~/.config/fontconfig/fonts.conf to /etc/fonts/local.conf'
|
|
sudo cp -f "${XDG_CONFIG_HOME:-$HOME/.config}/fontconfig/fonts.conf" /etc/fonts/local.conf
|
|
else
|
|
logg warn 'The /etc/fonts directory is missing'
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# @description Applies various `dconf`, `xconf`, etc. settings to Linux systems
|
|
applyLinuxConfSettings() {
|
|
if [ "{{ .host.distro.family }}" = "linux" ] && command -v apply-linux-conf-settings > /dev/null; then
|
|
apply-linux-conf-settings
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script applies various themes to Linux systems that use GNOME or KDE.
|
|
applyLinuxThemeFiles() {
|
|
if [ "{{ .host.distro.family }}" = "linux" ]; then
|
|
### Ensure /usr/local/bin/squash-symlink is present
|
|
if [ ! -f /usr/local/bin/squash-symlink ] && [ -f "$HOME/.local/bin/squash-symlink" ]; then
|
|
logg info 'Copying ~/.local/bin/squash-symlink to /usr/local/bin/squash-symlink'
|
|
sudo cp -f "$HOME/.local/bin/squash-symlink" /usr/local/bin/squash-symlink
|
|
sudo chmod +x /usr/local/bin/squash-symlink
|
|
fi
|
|
|
|
### Clean up system theme settings
|
|
for ITEM_TO_BE_REMOVED in "/usr/share/backgrounds/images" "/usr/share/backgrounds/f32" "/usr/share/backgrounds/qubes" "/usr/share/wallpapers"; do
|
|
if [ -d "$ITEM_TO_BE_REMOVED" ] || [ -f "$ITEM_TO_BE_REMOVED" ]; then
|
|
sudo rm -rf "$ITEM_TO_BE_REMOVED"
|
|
logg success "Removed $ITEM_TO_BE_REMOVED"
|
|
fi
|
|
done
|
|
|
|
### Ensure /usr/local/share exists
|
|
if [ ! -d /usr/local/share ]; then
|
|
sudo mkdir -p /usr/local/share
|
|
logg success 'Created /usr/local/share'
|
|
fi
|
|
|
|
### Copy theme files over to /usr/local/share
|
|
if [ -d "$HOME/.local/src/{{ .theme | lower }}/share" ]; then
|
|
logg info 'Copying ~/.local/src/{{ .theme | lower }}/share to /usr/local/share'
|
|
sudo rsync --chown=root:root --chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r -artvu --inplace "${XDG_DATA_HOME:-$HOME/.local/share}/betelgeuse/share/" "/usr/local/share/" > /dev/null
|
|
else
|
|
logg warn '~/.local/share/betelgeuse/share is missing'
|
|
fi
|
|
|
|
### Flatten GRUB theme files (i.e. convert symlinks to regular files)
|
|
if command -v squash-symlink > /dev/null; then
|
|
logg info 'Converting /usr/local/share/grub symlinks to equivalent regular files'
|
|
sudo find /usr/local/share/grub -type l -exec squash-symlink {} +
|
|
else
|
|
logg warn 'squash-symlink is not a script in the PATH'
|
|
fi
|
|
|
|
### Ensure /usr/share/backgrounds/default.png is deleted
|
|
if [ -f /usr/share/backgrounds/default.png ]; then
|
|
sudo rm -f /usr/share/backgrounds/default.png
|
|
fi
|
|
|
|
### Add the default image symlink based on the OS
|
|
if [ '{{ .host.distro.id }}' == 'archlinux' ]; then
|
|
sudo ln -s /usr/local/share/wallpapers/Betelgeuse-Archlinux/contents/source.png /usr/share/backgrounds/default.png
|
|
elif [ '{{ .host.distro.id }}' == 'centos' ]; then
|
|
sudo ln -s /usr/local/share/wallpapers/Betelgeuse-CentOS/contents/source.png /usr/share/backgrounds/default.png
|
|
elif [ '{{ .host.distro.id }}' == 'darwin' ]; then
|
|
sudo ln -s /usr/local/share/wallpapers/Betelgeuse-macOS/contents/source.png /usr/share/backgrounds/default.png
|
|
elif [ '{{ .host.distro.id }}' == 'debian' ]; then
|
|
sudo ln -s /usr/local/share/wallpapers/Betelgeuse-Debian/contents/source.png /usr/share/backgrounds/default.png
|
|
elif [ '{{ .host.distro.id }}' == 'fedora' ]; then
|
|
sudo ln -s /usr/local/share/wallpapers/Betelgeuse-Fedora/contents/source.png /usr/share/backgrounds/default.png
|
|
elif [ '{{ .host.distro.id }}' == 'ubuntu' ]; then
|
|
sudo ln -s /usr/local/share/wallpapers/Betelgeuse-Ubuntu/contents/source.png /usr/share/backgrounds/default.png
|
|
elif [ '{{ .host.distro.id }}' == 'windows' ]; then
|
|
sudo ln -s /usr/local/share/wallpapers/Betelgeuse-Windows/contents/source.png /usr/share/backgrounds/default.png
|
|
else
|
|
sudo ln -s /usr/local/share/wallpapers/Betelgeuse/contents/source.png /usr/share/backgrounds/default.png
|
|
fi
|
|
|
|
### Note: ubuntu-default-greyscale-wallpaper.png symlink to whiteish gray background
|
|
|
|
### Set appropriate platform-specific icon in plymouth theme
|
|
if [ -f '/usr/local/share/plymouth/themes/{{ .theme }}/icons/{{ .host.distro.id }}.png' ]; then
|
|
sudo cp -f '/usr/local/share/plymouth/themes/{{ .theme }}/icons/{{ .host.distro.id }}.png' '/usr/local/share/plymouth/themes/{{ .theme }}/icon.png'
|
|
logg success 'Added platform-specific icon to {{ .theme }} Plymouth theme'
|
|
else
|
|
logg warn 'The {{ .host.distro.id }}.png icon is not available in the icons folder insider the {{ .theme }} Plymouth theme'
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script configures the root user's folder so that scripts running as the root user can:
|
|
#
|
|
# 1. Access binaries installed by the provisioning user (by setting the appropriate `~/.bashrc` and `~/.zshrc` symlinks)
|
|
# 2. Use the same shell profile rules that the provisioning user uses (by symlinking the `~/.config/shell`, `~/.bashrc`, and `~/.zshrc` locations)
|
|
applyRootConfig() {
|
|
### Detect root folder
|
|
if [ -d /var/root ]; then
|
|
ROOT_FOLDER="/var/root"
|
|
elif [ -d /root ]; then
|
|
ROOT_FOLDER="/root"
|
|
else
|
|
logg warn 'Unable to find root user folder location'
|
|
fi
|
|
|
|
if [ -n "$ROOT_FOLDER" ]; then
|
|
### Copy minimal set of profile configuration files
|
|
logg info "Copying ~/.bashrc to $ROOT_FOLDER/.bashrc" && sudo cp -f "$HOME/.bashrc" "$ROOT_FOLDER/.bashrc"
|
|
logg info "Copying ~/.zshrc to $ROOT_FOLDER/.zshrc" && sudo cp -f "$HOME/.zshrc" "$ROOT_FOLDER/.zshrc"
|
|
logg info "Ensuring ~/.config folder exists" && sudo mkdir -p "$ROOT_FOLDER/.config"
|
|
logg info "Copying ~/.config/shell to $ROOT_FOLDER/.config/shell" && sudo mkdir -p "$ROOT_FOLDER/.config" && sudo rm -rf "$ROOT_FOLDER/.config/shell" && sudo cp -rf "$HOME/.config/shell" "$ROOT_FOLDER/.config/shell"
|
|
|
|
### Copy Autorestic configurations
|
|
logg info "Copying ${XDG_CONFIG_HOME:-$HOME/.config}/autorestic/autorestic-system.yml file to $ROOT_FOLDER/.autorestic.yml" && sudo cp -f "${XDG_CONFIG_HOME:-$HOME/.config}/autorestic/autorestic-system.yml" "$ROOT_FOLDER/.autorestic.yml"
|
|
logg info "Removing ${XDG_CONFIG_HOME:-$HOME/.config}/autorestic/autorestic-system.yml" && sudo rm -f "${XDG_CONFIG_HOME:-$HOME/.config}/autorestic/autorestic-system.yml"
|
|
logg info "Applying proper permissions to $ROOT_FOLDER/.autorestic.yml" && sudo chmod 600 "$ROOT_FOLDER/.autorestic.yml"
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This function ensures the macOS desktop wallpaper is set to the macOS Betelgeuse wallpaper. It uses the
|
|
# `m` CLI to apply the change.
|
|
#
|
|
# This function ensures the Qubes desktop wallpaper is set to the Qubes Betelgeuse wallpaper on KDE by
|
|
# using the `ksetwallpaper` script found in `~/.local/bin/ksetwallpaper`.
|
|
applyWallpaper() {
|
|
{{ if (eq .host.distro.id "qubes") -}}
|
|
logg info 'Setting wallpaper to /usr/local/share/wallpapers/Betelgeuse/contents/images/3440x1440.jpg'
|
|
ksetwallpaper --file /usr/local/share/wallpapers/Betelgeuse/contents/images/3440x1440.jpg
|
|
{{ else -}}
|
|
### Set macOS wallpaper
|
|
if command -v m > /dev/null && [ -f "${XDG_DATA_HOME:-$HOME/.local/share}/betelgeuse/share/wallpapers/Betelgeuse-macOS/contents/source.png" ]; then
|
|
logg info 'Setting macOS wallpaper with m'
|
|
m wallpaper "${XDG_DATA_HOME:-$HOME/.local/share}/betelgeuse/share/wallpapers/Betelgeuse-macOS/contents/source.png"
|
|
else
|
|
logg warn 'Either m or the macOS default wallpaper is missing.'
|
|
fi
|
|
{{ end -}}
|
|
}
|
|
|
|
# @description
|
|
# This script ensures ASDF is setup and then adds the plugins specified in the `~/.tool-versions` file. After that,
|
|
# it ensures the ASDF plugins are pre-installed.
|
|
asdfPluginInstall() {
|
|
### Re-source ~/.bashrc if necessary
|
|
if [ -z "$ASDF_DIR" ]; then
|
|
logg info 'ASDF_DIR is not defined so ~/.bashrc will be sourced' && source ~/.bashrc
|
|
fi
|
|
|
|
if [ -f "$ASDF_DIR/asdf.sh" ] && [ -f ~/.tool-versions ]; then
|
|
logg info 'Sourcing asdf.sh'
|
|
. ${ASDF_DIR}/asdf.sh
|
|
cat .tool-versions | while read TOOL; do
|
|
logg info 'Installing ASDF plugin '"$(echo "$TOOL" | sed 's/ .*//')"'' && asdf plugin add "$(echo "$TOOL" | sed 's/ .*//')" > /dev/null && logg info "Successfully added $(echo "$TOOL" | sed 's/ .*//') via ASDF"
|
|
done
|
|
# Only proceed with installation if either DEBUG_MODE is enabled or ~/.cache/megabyte-labs/asdf-install is missing
|
|
# Added to save time between tests because PHP takes awhile to install
|
|
if [ "$DEBUG_MODE" == 'true' ] || [ ! -f "${XDG_CACHE_HOME:-$HOME/.cache}/megabyte-labs/asdf-install" ]; then
|
|
logg info 'Installing ASDF dependencies derived from ~/.tool-versions via asdf install'
|
|
asdf install || EXIT_CODE=$?
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
logg error 'Error installing the ASDF plugins specified in ~/.tool-versions'
|
|
fi
|
|
mkdir -p "${XDG_CACHE_HOME:-$HOME/.cache}/megabyte-labs"
|
|
touch "${XDG_CACHE_HOME:-$HOME/.cache}/megabyte-labs/asdf-install"
|
|
fi
|
|
else
|
|
logg warn 'The $ASDF_DIR/asdf.sh or ~/.tool-versions file is not present'
|
|
fi
|
|
}
|
|
|
|
### Helper function for configureNetworkManager
|
|
ensureNetworkConfigs() {
|
|
if [ ! -d /etc/network/if-up.d ]; then
|
|
logg info 'Creating /etc/network/if-up.d folder'
|
|
sudo mkdir -p /etc/network/if-up.d
|
|
fi
|
|
if [ ! -d /etc/network/if-post-down.d ]; then
|
|
logg info 'Creating /etc/network/if-post.d folder'
|
|
sudo mkdir -p /etc/network/if-post.d
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script installs OpenVPN and WireGuard VPN profiles. It does a few things to install the profiles and make sure
|
|
# they are usable by desktop users:
|
|
#
|
|
# 1. It ensures OpenVPN and `NetworkManager-*` plugins are installed (this allows you to see all the different VPN profile types available when you try to import a VPN profile on Linux devices)
|
|
# 2. Imports the OpenVPN profiles stored in `${XDG_CONFIG_HOME:-$HOME/.config}/vpn`
|
|
# 3. Applies the OpenVPN username and password to all the OpenVPN profiles (which can be passed in as `OVPN_USERNAME` and `OVPN_PASSWORD` if you use the environment variable method)
|
|
# 4. Bypasses the OpenVPN connection for all the networks defined in `.host.vpn.excludedSubnets` (in the `home/.chezmoi.yaml.tmpl` file)
|
|
# 5. Repeats the process for WireGuard by looping through all the `*.nmconnection` files stored in `${XDG_CONFIG_HOME:-$HOME/.config}/vpn` (username and password should already be stored in the encrypted files)
|
|
#
|
|
# ## Creating VPN Profiles
|
|
#
|
|
# More details on embedding your VPN profiles into your Install Doctor fork can be found by reading the [Secrets documentation](https://install.doctor/docs/customization/secrets#vpn-profiles).
|
|
#
|
|
# ## Links
|
|
#
|
|
# * [VPN profile folder](https://github.com/megabyte-labs/install.doctor/blob/master/home/dot_config/vpn)
|
|
# * [VPN profile documentation](https://install.doctor/docs/customization/secrets#vpn-profiles)
|
|
configureNetworkManagerVPNProfiles() {
|
|
if [ "{{ .host.distro.family }}" = "linux" ]; then
|
|
{{ $ovpnUsername := (env "OVPN_USERNAME") }}
|
|
{{ if (stat (joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "OVPN_USERNAME")) }}
|
|
{{ $ovpnUsername := (includeTemplate "secrets/OVPN_USERNAME" | decrypt | trim) }}
|
|
{{ end }}
|
|
|
|
{{ $ovpnPassword := (env "OVPN_PASSWORD") }}
|
|
{{ if (stat (joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "OVPN_PASSWORD")) }}
|
|
{{ $ovpnPassword := (includeTemplate "secrets/OVPN_PASSWORD" | decrypt | trim) }}
|
|
{{ end }}
|
|
|
|
RESTART_NM=false
|
|
|
|
### Ensure `NetworkManager` plugins are
|
|
# NOTE: By default, all the NetworkManager plugins are installed.
|
|
if command -v apt-get > /dev/null; then
|
|
sudo apt-get install -y network-manager*
|
|
elif command -v dnf > /dev/null; then
|
|
sudo dnf install -y openvpn NetworkManager*
|
|
elif command -v pacman > /dev/null; then
|
|
sudo pacman -Syu openvpn networkmanager*
|
|
else
|
|
logg warn 'Unknown package manager - install OpenVPN / WireGuard / NetworkManager plugins individually'
|
|
fi
|
|
|
|
### Ensures `nmcli` (the CLI for NetworkManager) is available in the `PATH`
|
|
if command -v nmcli > /dev/null; then
|
|
### Sets up OpenVPN profiles
|
|
if [ '{{ $ovpnUsername }}' != '' ] && [ '{{ $ovpnPassword }}' != '' ]; then
|
|
find "${XDG_CONFIG_HOME:-$HOME/.config}/vpn" -type f -name "*.ovpn" | while read OVPN_FILE; do
|
|
### Adds the OpenVPN profiles by importing the `*.ovpn` files in `${XDG_CONFIG_HOME:-$HOME/.config}/vpn` and then applying the OpenVPN username and password
|
|
logg info "Adding $OVPN_FILE to NetworkManager OpenVPN profiles"
|
|
OVPN_NAME="$(basename "$OVPN_FILE" | sed 's/.ovpn$//')"
|
|
nmcli connection import type openvpn file "$OVPN_FILE"
|
|
nmcli connection modify "$OVPN_NAME" +vpn.data 'username={{- $ovpnUsername }}'
|
|
nmcli connection modify "$OVPN_NAME" vpn.secrets 'password={{- $ovpnPassword }}'
|
|
nmcli connection modify "$OVPN_NAME" +vpn.data password-flags=0
|
|
|
|
### Register the excluded subnets in the routeadd / routedel files
|
|
for EXCLUDED_SUBNET in '{{ join "' '" .host.vpn.excludedSubnets }}'; do
|
|
ensureNetworkConfigs
|
|
nmcli connection modify "$OVPN_NAME" +ipv4.routes "$EXCLUDED_SUBNET" | sudo tee -a /etc/network/if-up.d/routeadd
|
|
nmcli connection modify "$OVPN_NAME" -ipv4.routes "$EXCLUDED_SUBNET" | sudo tee -a /etc/network/if-post-down.d/routedel
|
|
done
|
|
RESTART_NM=true
|
|
done
|
|
else
|
|
logg info 'Either the OpenVPN username or password is undefined.'
|
|
logg info 'See the docs/VARIABLES.md file for details.'
|
|
fi
|
|
|
|
{{ if (stat (joinPath .host.home ".config" "age" "chezmoi.txt")) }}
|
|
### Setup WireGuard profiles
|
|
if [ -d /etc/NetworkManager/system-connections ]; then
|
|
find "${XDG_CONFIG_HOME:-$HOME/.config}/vpn" -type f -name "*.nmconnection" | while read WG_FILE; do
|
|
### Ensure the WireGuard NetworkManager plugin is available
|
|
if [ ! -d /usr/lib/NetworkManager/nm-wireguard-service ]; then
|
|
logg info 'The nm-wireguard-service is not present'
|
|
logg info 'Installing the nm-wireguard-service'
|
|
fi
|
|
|
|
### Add the WireGuard profiles
|
|
logg info "Adding $WG_FILE to /etc/NetworkManager/system-connections"
|
|
WG_FILENAME="$(basename "$WG_FILE")"
|
|
chezmoi decrypt "$WG_FILE" | sudo tee "/etc/NetworkManager/system-connections/$WG_FILENAME"
|
|
|
|
### Register the excluded subnets in the routeadd / routedel files
|
|
for EXCLUDED_SUBNET in '{{ join "' '" .host.vpn.excludedSubnets }}'; do
|
|
ensureNetworkConfigs
|
|
WG_PROFILE_NAME="$(echo "$WG_FILENAME" | sed 's/.nmconnection$//')"
|
|
nmcli connection modify "$WG_PROFILE_NAME" +ipv4.routes "$EXCLUDED_SUBNET" | sudo tee -a /etc/network/if-up.d/routeadd
|
|
nmcli connection modify "$WG_PROFILE_NAME" -ipv4.routes "$EXCLUDED_SUBNET" | sudo tee -a /etc/network/if-post-down.d/routedel
|
|
done
|
|
RESTART_NM=true
|
|
done
|
|
else
|
|
logg warn '/etc/NetworkManager/system-connections is not a directory!'
|
|
fi
|
|
{{ end -}}
|
|
|
|
### Restart NetworkManager if changes were made and environment is not WSL
|
|
if [ "$RESTART_NM" == 'true' ] && [[ ! "$(test -d proc && grep Microsoft /proc/version > /dev/null)" ]]; then
|
|
logg info 'Restarting NetworkManager since VPN profiles were updated'
|
|
sudo service NetworkManager restart
|
|
fi
|
|
else
|
|
logg warn 'nmcli is unavailable'
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script applies the SSH server MOTD banner and `sshd_config` (which are housed in the `home/private_dot_ssh/system` location)
|
|
# to the system by copying the files to the system location and then restarting / enabling the system SSH server.
|
|
#
|
|
# ## Links
|
|
#
|
|
# * [System SSHD configurations](https://github.com/megabyte-labs/install.doctor/tree/master/home/private_dot_ssh/system)
|
|
configureSSHD() {
|
|
### Update /etc/ssh/sshd_config if environment is not WSL
|
|
if [[ ! "$(test -d /proc && grep Microsoft /proc/version > /dev/null)" ]]; then
|
|
if [ -d /etc/ssh ]; then
|
|
logg info 'Copying ~/.ssh/system/banner to /etc/ssh/banner' && sudo cp -f "$HOME/.ssh/system/banner" /etc/ssh/banner
|
|
logg info 'Copying ~/.ssh/system/sshd_config to /etc/ssh/sshd_config' && sudo cp -f "$HOME/.ssh/system/sshd_config" /etc/ssh/sshd_config
|
|
|
|
if command -v semanage > /dev/null; then
|
|
logg info 'Apply SELinux configuration addressing custom SSH port' && sudo semanage port -a -t ssh_port_t -p tcp {{ .host.ssh.port }}
|
|
logg info 'Allow NIS SSHD' && sudo setsebool -P nis_enabled 1
|
|
fi
|
|
|
|
### Ensure keys are created
|
|
logg info 'Running sudo ssh-keygen -A' && sudo ssh-keygen -A
|
|
|
|
### Restart SSH server
|
|
if [ -d /Applications ] && [ -d /System ]; then
|
|
### macOS
|
|
logg info 'Running sudo systemsetup -setremotelogin on' && sudo systemsetup -setremotelogin on
|
|
logg info 'Running sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist' && sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist 2> /dev/null
|
|
logg info 'Running sudo launchctl stop com.openssh.sshd' && sudo launchctl stop com.openssh.sshd
|
|
logg info 'Running sudo launchctl start com.openssh.sshd' && sudo launchctl start com.openssh.sshd && logg info 'Successfully ran launchctl start com.openssh.sshd'
|
|
else
|
|
### Linux
|
|
logg info 'Enabling the sshd service'
|
|
sudo systemctl enable sshd
|
|
logg info 'Restarting the sshd service'
|
|
sudo systemctl restart sshd && logg info 'Successfully ran sudo systemctl restart sshd'
|
|
fi
|
|
else
|
|
logg warn 'The /etc/ssh folder does not exist'
|
|
fi
|
|
else
|
|
logg info 'Skipping sshd_config application since environment is WSL'
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script allows you to apply `dconf` settings that you can store in your fork of Install Doctor. By default,
|
|
# it makes a handful of `dconf` settings optimizations.
|
|
dconfSettings() {
|
|
if command -v dconf > /dev/null; then
|
|
### Update background to be OS-specific
|
|
if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/dconf/settings/org.gnome.desktop.background" ]; then
|
|
logg info 'Checking for presence of /usr/local/share/wallpapers/Betelgeuse-{{ title .host.distro.id }}/contents/source.jpg'
|
|
if [ -f /usr/local/share/wallpapers/Betelgeuse-{{ title .host.distro.id }}/contents/source.jpg ]; then
|
|
logg info "Updating ${XDG_CONFIG_HOME:-$HOME/.config}/dconf/settings/org.gnome.desktop.background to point to OS-specific background"
|
|
TMP="$(mktemp)"
|
|
sed 's/Betelgeuse/Betelgeuse-{{ title .host.distro.id }}/g' < "${XDG_CONFIG_HOME:-$HOME/.config}/dconf/settings/org.gnome.desktop.background" > "$TMP"
|
|
mv "$TMP" "${XDG_CONFIG_HOME:-$HOME/.config}/dconf/settings/org.gnome.desktop.background"
|
|
else
|
|
logg info 'OS-specific background not found'
|
|
fi
|
|
fi
|
|
|
|
### Backup system settings
|
|
DCONF_TMP="$(mktemp)"
|
|
dconf dump / > "$DCONF_TMP"
|
|
logg info 'Backed up system dconf settings to '"$DCONF_TMP"
|
|
|
|
### Reset system settings / load saved configurations from ~/.config/dconf/settings
|
|
if [ -d "${XDG_CONFIG_HOME:-$HOME/.config}/dconf/settings" ]; then
|
|
find "${XDG_CONFIG_HOME:-$HOME/.config}/dconf/settings" -mindepth 1 -maxdepth 1 -type f | while read DCONF_CONFIG_FILE; do
|
|
if [ "$DEBUG_MODE" == 'true' ]; then
|
|
logg info 'Dconf configuration file:'
|
|
echo "$DCONF_CONFIG_FILE"
|
|
fi
|
|
DCONF_SETTINGS_ID="/$(basename "$DCONF_CONFIG_FILE" | sed 's/\./\//g')/"
|
|
if [ "$DEBUG_MODE" == 'true' ]; then
|
|
logg info 'Dconf settings ID:'
|
|
echo "$DCONF_SETTINGS_ID"
|
|
fi
|
|
### Reset dconf settings if environment variable RESET_DCONF is set to true
|
|
if [ "$RESET_DCONF" == 'true' ]; then
|
|
logg info 'Resetting dconf settings for '"$DCONF_SETTINGS_ID"''
|
|
dconf reset -f "$DCONF_SETTINGS_ID"
|
|
fi
|
|
logg info 'Loading versioned dconf settings for '"$DCONF_SETTINGS_ID"''
|
|
dconf load "$DCONF_SETTINGS_ID" < "$DCONF_CONFIG_FILE"
|
|
logg success 'Finished applying dconf settings for '"$DCONF_SETTINGS_ID"''
|
|
done
|
|
else
|
|
logg warn '~/.config/dconf/settings does not exist!'
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script decrypts the SSH key files that are housed in the `home/.chezmoitemplates/ssh` section of the repository.
|
|
# It loops through all the files in `home/.chezmoitemplates/ssh` and stores them to the `~/.ssh` folder
|
|
# when they are successfully decrypted.
|
|
#
|
|
# This script generates a pair of default `id_rsa` and `id_rsa.pub` keys if one is not already present
|
|
# on the system after the Install Doctor provisioning process completes. It also ensures the private
|
|
# key is only readable and writable the provisioning user.
|
|
decryptSSHKeys() {
|
|
### Unpack existing encrypted keys
|
|
logg info 'Decrypting SSH keys stored in the home/.chezmoitemplates/ssh folder of the Install Doctor repo / fork.'
|
|
find "{{ .chezmoi.sourceDir }}/.chezmoitemplates/ssh" -type f | while read SSH_FILE; do
|
|
### Decrypt SSH file with Chezmoi
|
|
logg info "Decrypting the $(basename "$SSH_FILE") encrypted SSH file"
|
|
chezmoi decrypt "$SSH_FILE" > "$HOME/.ssh/$(basename "$SSH_FILE")" || EXIT_CODE=$?
|
|
|
|
### Handle failed decryption with warning log message
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
logg warn "Unable to decrypt the file stored in $SSH_FILE"
|
|
fi
|
|
|
|
### Apply appropriate permission to decrypted ~/.ssh file
|
|
if [ -f "$HOME/.ssh/$(basename "$SSH_FILE")" ]; then
|
|
logg info "Applying appropriate permissions on $HOME/.ssh/$(basename "$SSH_FILE")"
|
|
chmod 600 "$HOME/.ssh/$(basename "$SSH_FILE")"
|
|
fi
|
|
done
|
|
|
|
### Ensure id_rsa is present and create one if it does not exist
|
|
if [ ! -f "$HOME/.ssh/id_rsa" ]; then
|
|
logg 'Generating missing default private key / public key (~/.ssh/id_rsa)'
|
|
ssh-keygen -b 4096 -t rsa -f "$HOME/.ssh/id_rsa" -q -N ""
|
|
chmod 600 "$HOME/.ssh/id_rsa"
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script installs and activates the latest version of Emscripten. This script
|
|
# implements the [instructions outlined on Emscripten's website](https://emscripten.org/docs/getting_started/downloads.html#installation-instructions-using-the-emsdk-recommended).
|
|
#
|
|
# This script will only run when `${XDG_DATA_HOME:-$HOME/.local/share}/emsdk` is present on the system. This folder
|
|
# is populated via the definition in `home/.chezmoiexternal.toml.tmpl`.
|
|
emscriptenInstall() {
|
|
if [ -d "${XDG_DATA_HOME:-$HOME/.local/share}/emsdk" ]; then
|
|
logg info 'Pulling latest changes for Emscripten source code' && cd "${XDG_DATA_HOME:-$HOME/.local/share}/emsdk" && git pull
|
|
logg info "Running emsdk install latest" && emsdk install latest > /dev/null
|
|
logg info "Running emsdk activate latest" && emsdk activate latest > /dev/null
|
|
logg info 'Profile source inclusions are already implemented in Bash / ZSH profile'
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# Adds auto-update feature to macOS that automatically downloads and installs updates. Also enables
|
|
# an auto-update feature for Homebrew on macOS.
|
|
enableAutoUpdateDarwin() {
|
|
if [ -d /Applications ] && [ -d /System ]; then
|
|
### Enable automated system updates on macOS
|
|
if [ -f "$HOME/Library/LaunchDaemons/com.apple.automatedupdates.plist" ] && [ ! -f "/Library/LaunchDaemons/com.apple.automatedupdates.plist" ]; then
|
|
logg info 'Configuring macOS to automatically apply system updates'
|
|
sudo mkdir -p /Library/LaunchDaemons
|
|
sudo cp -f "$HOME/Library/LaunchDaemons/com.apple.automatedupdates.plist" "/Library/LaunchDaemons/com.apple.automatedupdates.plist"
|
|
logg info 'Loading /Library/LaunchDaemons/com.apple.automatedupdates.plist'
|
|
sudo launchctl load "/Library/LaunchDaemons/com.apple.automatedupdates.plist" && logg success 'launchctl load successful'
|
|
fi
|
|
|
|
### Enable Homebrew auto-update service
|
|
if brew autoupdate status | grep 'Autoupdate is not configured.' > /dev/null; then
|
|
logg info 'Enabling Homebrew auto-update service (every 24 hours)'
|
|
brew autoupdate start --cleanup --greedy --upgrade
|
|
fi
|
|
fi
|
|
}
|
|
|
|
ensurePipUpdated() {
|
|
### python3.10 pip update
|
|
if command -v python3.10 > /dev/null; then
|
|
logg info 'Ensuring python3.10 pip is updated' && python3.10 -m pip install --upgrade pip &
|
|
fi
|
|
|
|
### python3.11 pip update
|
|
if command -v python3.11 > /dev/null; then
|
|
logg info 'Ensuring python3.11 pip is updated' && python3.11 -m pip install --upgrade pip &
|
|
fi
|
|
|
|
### python3.12 pip update
|
|
# if command -v python3.12 > /dev/null; then
|
|
# logg info 'Ensuring python3.12 pip is updated' && python3.12 -m pip install --upgrade pip &
|
|
# fi
|
|
wait
|
|
}
|
|
|
|
# @description
|
|
# This script modifies the `/etc/environment` file on Linux devices to include:
|
|
#
|
|
# * `export QT_STYLE_OVERRIDE=kvantum-dark` which is required for the Linux GNOME / KDE themeing that relies on Kvantum.
|
|
ensureQtStyleOverride() {
|
|
if [ ! -d /Applications ] || [ ! -d /System ]; then
|
|
### Linux
|
|
### Ensure QT_STYLE_OVERRIDE is set in /etc/environment
|
|
logg info 'Ensuring QT_STYLE_OVERRIDE is set in /etc/environment'
|
|
if cat /etc/environment | grep QT_STYLE_OVERRIDE > /dev/null; then
|
|
sudo sed -i 's/.*QT_STYLE_OVERRIDE.*/export QT_STYLE_OVERRIDE=kvantum-dark/' /etc/environment
|
|
logg info 'Updated QT_STYLE_OVERRIDE in /etc/environment'
|
|
else
|
|
echo 'export QT_STYLE_OVERRIDE=kvantum-dark' | sudo tee -a /etc/environment
|
|
logg info 'Added QT_STYLE_OVERRIDE to /etc/environment'
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# @description Run `gem update --system` if `gem` is available
|
|
ensureSystemGemUpdated() {
|
|
### Ensure gem is updated
|
|
if command -v gem > /dev/null; then
|
|
logg info 'Ensuring system gem is updated' && gem update --system > /dev/null
|
|
else
|
|
logg info 'Could not find gem in PATH so skipping gem system update'
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script ensures ZSH is used as the default shell by ensuring it is added to `/etc/shells`. The script
|
|
# also ensures ZSH is available at `/usr/local/bin/zsh` on ARM64 systems by symlinking the Homebrew ZSH shell
|
|
# to `/usr/local/bin/zsh` if it is missing.
|
|
ensureZshShell() {
|
|
logg 'Ensuring ZSH is set as the default shell'
|
|
if ! grep -qc "/usr/local/bin/zsh" /etc/shells; then
|
|
echo "/usr/local/bin/zsh" | sudo tee -a /etc/shells > /dev/null
|
|
fi
|
|
|
|
if [ ! -f /usr/local/bin/zsh ] && [ -f "${HOMEBREW_PREFIX:-/opt/homebrew}/bin/zsh" ]; then
|
|
sudo ln -sf "${HOMEBREW_PREFIX:-/opt/homebrew}/bin/zsh" /usr/local/bin/zsh
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script ensures your GNOME extensions come pre-configured to your liking. It provides the ability
|
|
# to automatically install a configurable list of GNOME extensions as well as apply your preferred settings.
|
|
gnomeExtensionSettings() {
|
|
if command -v gnome-shell > /dev/null; then
|
|
### Ensure /tmp/install-gnome-extensions.txt is not present on the system
|
|
if [ -f /tmp/install-gnome-extensions.txt ]; then
|
|
rm -f /tmp/install-gnome-extensions.txt
|
|
fi
|
|
|
|
### Register temporary file for gnome.yml JSON
|
|
if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/desktop/gnome.yml" ]; then
|
|
TMP_YQ="$(mktemp)"
|
|
cat "${XDG_CONFIG_HOME:-$HOME/.config}/desktop/gnome.yml" | yq e -o=j '.' > "$TMP_YQ"
|
|
fi
|
|
|
|
### Populate /tmp/install-gnome-extensions.txt with GNOME extensions that need to be installed
|
|
if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/desktop/gnome.yml" ]; then
|
|
cat "$TMP_YQ" | jq -c '.default_gnome_extensions[] | tojson' | while read EXT; do
|
|
TMP="$(mktemp)"
|
|
echo "$EXT" | sed 's/^.\(.*\).$/\1/' > "$TMP"
|
|
EXT_URL="$(cat "$TMP" | jq -r '.url')"
|
|
EXT_ID="$(cat "$TMP" | jq -r '.regex')"
|
|
echo "$EXT_URL" >> /tmp/install-gnome-extensions.txt
|
|
if [ ! -d "${XDG_DATA_HOME:-$HOME/.local/share}/gnome-shell/extensions" ]; then
|
|
mkdir -p "${XDG_DATA_HOME:-$HOME/.local/share}/gnome-shell/extensions"
|
|
fi
|
|
find "${XDG_DATA_HOME:-$HOME/.local/share}/gnome-shell/extensions" -mindepth 1 -maxdepth 1 -type d | while read EXT_FOLDER; do
|
|
if [[ "$EXT_FOLDER" == *"$EXT_ID"* ]] && [ -f /tmp/install-gnome-extensions.txt ]; then
|
|
TMP_EXT="$(mktemp)"
|
|
head -n -1 /tmp/install-gnome-extensions.txt > "$TMP_EXT"
|
|
mv -f "$TMP_EXT" /tmp/install-gnome-extensions.txt > /dev/null
|
|
fi
|
|
done
|
|
done
|
|
else
|
|
logg warn 'The ~/.config/desktop/gnome.yml file is missing so GNOME extension install orders cannot be calculated'
|
|
fi
|
|
|
|
### Remove /tmp/install-gnome-extensions.txt if it is empty
|
|
if [ "$(cat /tmp/install-gnome-extensions.txt)" == "" ]; then
|
|
rm -f /tmp/install-gnome-extensions.txt > /dev/null
|
|
fi
|
|
|
|
### Install the GNOME extensions using the `install-gnome-extensions` script
|
|
if command -v install-gnome-extensions > /dev/null; then
|
|
if [ -f /tmp/install-gnome-extensions.txt ]; then
|
|
logg info 'Running the install-gnome-extensions script'
|
|
cd /tmp
|
|
install-gnome-extensions --enable --overwrite --file /tmp/install-gnome-extensions.txt
|
|
rm -f /tmp/install-gnome-extensions.txt
|
|
logg success 'Finished installing the GNOME extensions'
|
|
else
|
|
logg info 'No new GNOME extensions to install'
|
|
fi
|
|
else
|
|
logg warn 'Cannot install GNOME extensions because the install-gnome-extensions script is missing from ~/.local/bin'
|
|
fi
|
|
|
|
### Apply plugin gsettings
|
|
if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/desktop/gnome.yml" ]; then
|
|
cat "$TMP_YQ" | jq -c '.default_gnome_extensions[] | tojson' | while read EXT; do
|
|
if [ "$DEBUG_MODE" == 'true' ]; then
|
|
logg info 'Extension data:'
|
|
echo "$EXT"
|
|
fi
|
|
TMP="$(mktemp)"
|
|
echo "$EXT" | sed 's/^.\(.*\).$/\1/' > "$TMP"
|
|
EXT_URL="$(cat "$TMP" | jq -r '.url')"
|
|
EXT_ID="$(cat "$TMP" | jq -r '.regex')"
|
|
if [ "$DEBUG_MODE" == 'true' ]; then
|
|
logg info 'Extension ID:'
|
|
echo "$EXT_ID"
|
|
fi
|
|
EXT_SETTINGS_TYPE="$(cat "$TMP" | jq -r '.settings | type')"
|
|
EXT_SETTINGS="$(cat "$TMP" | jq -r '.settings')"
|
|
if [ "$EXT_SETTINGS" != 'null' ]; then
|
|
logg info 'Evaluating extension settings for '"$EXT_ID"''
|
|
if [ "$EXT_SETTINGS_TYPE" == 'array' ]; then
|
|
cat "$TMP" | jq -r '.settings[]' | while read EXT_SETTING; do
|
|
logg info 'Applying following extension setting:'
|
|
echo "$EXT_SETTING"
|
|
eval "$EXT_SETTING"
|
|
done
|
|
else
|
|
logg info 'Applying following extension setting:'
|
|
echo "$EXT_SETTINGS"
|
|
eval "$EXT_SETTINGS"
|
|
fi
|
|
logg success 'Applied gsettings configuration for the '"$EXT_ID"' GNOME extension'
|
|
fi
|
|
done
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script configures GRUB2 with a custom theme on Linux systems.
|
|
grubSettings() {
|
|
if [ "{{ .host.distro.family }}" = "linux" ]; then
|
|
### Fix Qubes issue
|
|
if command -v qubesctl > /dev/null && [ -f /boot/grub2/grubenv ] && [ -d /boot/efi/EFI/qubes ]; then
|
|
sudo cp -f /boot/grub2/grubenv /boot/efi/EFI/qubes/grubenv
|
|
logg success 'Copied /boot/grub2/grubenv to /boot/efi/EFI/qubes/grubenv'
|
|
fi
|
|
|
|
### Ensure /boot/grub2/themes is directory
|
|
if [ ! -d /boot/grub2/themes ]; then
|
|
sudo mkdir -p /boot/grub2/themes
|
|
logg success 'Created /boot/grub2/themes'
|
|
fi
|
|
|
|
### Copy GRUB theme to /boot/grub2/themes
|
|
if [ -d /usr/local/share/grub/themes ]; then
|
|
sudo cp -rf /usr/local/share/grub/themes /boot/grub2/
|
|
logg success 'Copied GRUB themes in /usr/local/share/grub/themes to /boot/grub2/themes'
|
|
else
|
|
logg warn '/usr/local/share/grub/themes is missing'
|
|
fi
|
|
|
|
### Set default GRUB screen resolution variables
|
|
SCREEN_RATIO_ULTRAWIDE="2100"
|
|
GRUB_RESOLUTION_TYPE="1080p"
|
|
|
|
### Determine screen size ratio (used for picking GRUB2 theme resolution)
|
|
if command -v xrandr > /dev/null && command -v uniq > /dev/null; then
|
|
SCREEN_WIDTH="$(xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f1)"
|
|
SCREEN_HEIGHT="$(xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f2)"
|
|
SCREEN_RATIO="$(awk -v height="$SCREEN_HEIGHT" -v width="$SCREEN_WIDTH" 'BEGIN { print ((height / width) * 1000) }')"
|
|
SCREEN_RATIO="${SCREEN_RATIO%.*}"
|
|
logg success "Screen detected as $SCREEN_WIDTH x $SCREEN_HEIGHT (ratio of $SCREEN_RATIO)"
|
|
if (( $(echo "$SCREEN_RATIO $SCREEN_RATIO_ULTRAWIDE" | awk '{print ($1 > $2)}') )); then
|
|
GRUB_RESOLUTION_TYPE="ultrawide"
|
|
logg info 'GRUB resolution registered as ultrawide'
|
|
fi
|
|
else
|
|
logg warn 'Missing either xrandr or uniq (required for calculating screen size ratio)'
|
|
fi
|
|
|
|
### Optimize the GRUB resolution
|
|
if [ -f /etc/default/grub ]; then
|
|
### GRUB_GFXMODE
|
|
logg info 'Setting GRUB_GFXMODE=auto in /etc/default/grub'
|
|
if cat /etc/default/grub | grep GRUB_GFX_MODE > /dev/null; then
|
|
sudo sed -i 's/.*GRUB_GFXMODE.*/GRUB_GFXMODE=auto/' /etc/default/grub
|
|
else
|
|
echo "GRUB_GFXMODE=auto" | sudo tee -a /etc/default/grub > /dev/null
|
|
fi
|
|
|
|
### GRUB_GFXPAYLOAD_LINUX
|
|
logg info 'Setting GRUB_GFXPAYLOAD_LINUX=keep in /etc/default/grub'
|
|
if cat /etc/default/grub | grep GRUB_GFXPAYLOAD_LINUX > /dev/null; then
|
|
sudo sed -i 's/.*GRUB_GFXPAYLOAD_LINUX.*/GRUB_GFXPAYLOAD_LINUX="keep"/' /etc/default/grub
|
|
else
|
|
echo 'GRUB_GFXPAYLOAD_LINUX="keep"' | sudo tee -a /etc/default/grub > /dev/null
|
|
fi
|
|
|
|
### GRUB_THEME
|
|
logg info 'Setting GRUB_THEME={{ .theme }} in /etc/default/grub'
|
|
if cat /etc/default/grub | grep GRUB_THEME > /dev/null; then
|
|
sudo sed -i 's/.*GRUB_THEME.*/GRUB_THEME="{{ .theme }}-'"$GRUB_RESOLUTION_TYPE"'"/' /etc/default/grub
|
|
else
|
|
echo 'GRUB_THEME="{{ .theme }}-'"$GRUB_RESOLUTION_TYPE"'"' | sudo tee -a /etc/default/grub > /dev/null
|
|
fi
|
|
|
|
### GRUB_BACKGROUND
|
|
# Removed since the background should be flat black which is configurable
|
|
# Leaving this code here in case we need to add a flat black image background for some reason
|
|
# logg info 'Setting GRUB_BACKGROUND=/usr/local/share/grub/{{ .theme }}-blue.png in /etc/default/grub'
|
|
# if cat /etc/default/grub | grep GRUB_BACKGROUND > /dev/null; then
|
|
# sudo sed -i 's/.*GRUB_BACKGROUND.*/GRUB_BACKGROUND="\/usr\/local\/share\/grub\/{{ .theme }}-blue.png"/' /etc/default/grub
|
|
# else
|
|
# echo 'GRUB_BACKGROUND="/usr/local/share/grub/{{ .theme }}-blue.png"' | sudo tee -a /etc/default/grub > /dev/null
|
|
# fi
|
|
|
|
### GRUB_TIMEOUT
|
|
logg info 'Setting GRUB_TIMEOUT={{ .grub.timeout }} in /etc/default/grub'
|
|
if cat /etc/default/grub | grep GRUB_TIMEOUT > /dev/null; then
|
|
sudo sed -i 's/.*GRUB_TIMEOUT.*/GRUB_TIMEOUT="{{ .grub.timeout }}"/' /etc/default/grub
|
|
else
|
|
echo 'GRUB_TIMEOUT="{{ .grub.timeout }}"' | sudo tee -a /etc/default/grub > /dev/null
|
|
fi
|
|
|
|
### GRUB_FORCE_HIDDEN_MENU
|
|
logg info 'Setting GRUB_FORCE_HIDDEN_MENU={{ .grub.shiftToSee }} in /etc/default/grub'
|
|
sudo sed -i '/GRUB_FORCE_HIDDEN_MENU/d' /etc/default/grub
|
|
echo "GRUB_FORCE_HIDDEN_MENU={{ .grub.shiftToSee }}" | sudo tee -a /etc/default/grub > /dev/null
|
|
|
|
### Remove duplicate lines in /etc/default/grub
|
|
logg info 'Ensuring there are no duplicate entries in /etc/default/grub'
|
|
cat /etc/default/grub | uniq | sudo tee /etc/default/grub > /dev/null
|
|
else
|
|
logg warn '/etc/default/grub is missing'
|
|
fi
|
|
|
|
### Determine platform-specific icon to use
|
|
if command -v qubesctl > /dev/null; then
|
|
GRUB_ICON='qubes'
|
|
elif [ -f "/usr/local/share/grub/themes/{{ .theme }}-$GRUB_RESOLUTION_TYPE/icons/{{ .host.distro.id }}.png" ]; then
|
|
GRUB_ICON='{{ .host.distro.id }}'
|
|
elif [ -f "/usr/local/share/grub/themes/{{ .theme }}-$GRUB_RESOLUTION_TYPE/icons/{{ .host.distro.family }}.png" ]; then
|
|
GRUB_ICON='{{ .host.distro.family }}'
|
|
else
|
|
GRUB_ICON='linux'
|
|
fi
|
|
|
|
### Copy icon to GRUB2 theme folder
|
|
# Check looks in /usr/local/share/grub because on some systems the /boot folder is behind permissions for non-root users
|
|
if [ -f "/usr/local/share/grub/themes/{{ .theme }}-$GRUB_RESOLUTION_TYPE/icons/$GRUB_ICON.png" ]; then
|
|
sudo cp -f /boot/grub2/themes/{{ .theme }}-$GRUB_RESOLUTION_TYPE/icons/$GRUB_ICON.png /boot/grub2/themes/{{ .theme }}-$GRUB_RESOLUTION_TYPE/icon.png
|
|
logg success 'Copied platform-specific icon to GRUB2 theme folder'
|
|
else
|
|
logg warn "/boot/grub2/themes/{{ .theme }}-$GRUB_RESOLUTION_TYPE/icons/$GRUB_ICON.png is missing"
|
|
fi
|
|
|
|
### Hide unnecessary Boot messages and Bliking cursor
|
|
GRUB_DEFAULT_CMDLINE=$(grep 'GRUB_CMDLINE_LINUX_DEFAULT' /etc/default/grub)
|
|
if [[ -n $GRUB_DEFAULT_CMDLINE ]]; then
|
|
KERNEL_PARAMS_QUIET=$(echo "$GRUB_DEFAULT_CMDLINE" | grep 'quiet')
|
|
logg info 'Updating GRUB_CMDLINE_LINUX_DEFAULT to hide log messages'
|
|
if [[ -z $KERNEL_PARAMS_QUIET ]]; then
|
|
sudo sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="quiet loglevel=3 systemd.show_status=auto rd.udev.log_level=3 vt.global_cursor_default=0 /' /etc/default/grub
|
|
else
|
|
NEW_KERNEL_PARAMS=$(echo $KERNEL_PARAMS_QUIET | sed -e "s/quiet/quiet loglevel=3 systemd.show_status=auto rd.udev.log_level=3 vt.global_cursor_default=0/")
|
|
sudo sed -i "s/^GRUB_CMDLINE_LINUX_DEFAULT.*/${NEW_KERNEL_PARAMS}/" /etc/default/grub
|
|
fi
|
|
else
|
|
logg info 'GRUB_CMDLINE_LINUX_DEFAULT was not present, adding one with parameters to hide log messages'
|
|
echo 'GRUB_CMDLINE_LINUX_DEFAULT="quiet loglevel=3 systemd.show_status=auto rd.udev.log_level=3 vt.global_cursor_default=0"' | sudo tee -a /etc/default/grub > /dev/null
|
|
fi
|
|
|
|
|
|
### Ensure grub2-mkconfig is available
|
|
if ! command -v grub2-mkconfig > /dev/null; then
|
|
if command -v grub-mkconfig > /dev/null; then
|
|
sudo ln -s "$(which grub-mkconfig)" /usr/bin/grub2-mkconfig
|
|
elif sudo which grub-mkconfig > /dev/null; then
|
|
sudo ln -s "$(sudo which grub-mkconfig)" /usr/bin/grub2-mkconfig
|
|
else
|
|
logg warn 'Neither grub2-mkconfig or grub-mkconfig are available'
|
|
fi
|
|
fi
|
|
|
|
### Apply GRUB2 theme
|
|
# Set export DEBUG_MODE=true to bypass GRUB2 / Plymouth application
|
|
if [ "$DEBUG_MODE" != 'true' ]; then
|
|
if command -v grub2-mkconfig > /dev/null; then
|
|
if [ -d /sys/firmware/efi ]; then
|
|
logg info 'Assuming system is UEFI-enabled since /sys/firmware/efi is present'
|
|
if [ -f /boot/efi/EFI/qubes/grub.cfg ]; then
|
|
logg info 'Running sudo grub2-mkconfig -o /boot/efi/EFI/qubes/grub.cfg'
|
|
sudo grub2-mkconfig -o /boot/efi/EFI/qubes/grub.cfg
|
|
logg success 'Applied GRUB2 theme'
|
|
elif [ -f /boot/efi/EFI/grub.cfg ]; then
|
|
logg info 'Running sudo grub2-mkconfig -o /boot/efi/EFI/grub.cfg'
|
|
sudo grub2-mkconfig -o /boot/efi/EFI/grub.cfg
|
|
logg success 'Applied GRUB2 theme'
|
|
else
|
|
logg warn 'Unknown GRUB2 configuration - not applying GRUB2 theme'
|
|
fi
|
|
else
|
|
logg info 'Assuming system is non-UEFI since /sys/firmware/efi is not present'
|
|
logg info 'Running sudo grub2-mkconfig -o /boot/grub2/grub.cfg'
|
|
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
|
|
logg success 'Applied GRUB2 theme'
|
|
fi
|
|
elif [ -f /usr/sbin/update-grub ]; then
|
|
logg info 'Running sudo update-grub'
|
|
sudo update-grub
|
|
else
|
|
logg warn 'Unable to find appropriate GRUB mkconfig command'
|
|
fi
|
|
else
|
|
logg info 'Skipping GRUB2 theme application because DEBUG_MODE is set to true'
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script sets the [Docker Rclone plugin](https://rclone.org/docker/) which allows you to mount Rclone mounts as Docker volumes
|
|
#
|
|
# ## Docker Rclone
|
|
#
|
|
# The Docker Rclone installation ensures necessary system directories are initialized / created. It also copies the [Docker Rclone configuration](https://github.com/megabyte-labs/install.doctor/blob/master/home/dot_config/rclone/private_docker-rclone.conf.tmpl)
|
|
# to the proper system location.
|
|
installDockerRclonePlugin() {
|
|
### Docker Rclone plugin
|
|
# Source: https://rclone.org/docker/
|
|
# First, ensure Docker Rclone configuration exists (which only happens when the Chezmoi Age decryption key is present as well as keys for Rclone)
|
|
if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/rclone/docker-rclone.conf" ]; then
|
|
### Ensure Docker Rclone plugin system folders exist
|
|
logg info 'Ensure Docker Rclone plugin system folders exist'
|
|
logg info 'Ensuring directory /var/lib/docker-plugins/rclone/config is created' && sudo mkdir -p /var/lib/docker-plugins/rclone/config
|
|
logg info 'Ensuring directory /var/lib/docker-plugins/rclone/cache is created' && sudo mkdir -p /var/lib/docker-plugins/rclone/cache
|
|
|
|
### Copy Rclone configuration
|
|
logg info "Copy the Rclone configuration from ${XDG_CONFIG_HOME:-$HOME/.config}/rclone/docker-rclone.conf to /var/lib/docker-plugins/rclone/config/rclone.conf"
|
|
sudo cp -f "${XDG_CONFIG_HOME:-$HOME/.config}/rclone/docker-rclone.conf" /var/lib/docker-plugins/rclone/config/rclone.conf
|
|
|
|
### Install the Rclone Docker plugin (if not already installed)
|
|
if ! sudo su -c 'docker plugin ls' - "$USER" | grep 'rclone:latest' > /dev/null; then
|
|
sudo su -c 'docker plugin install rclone/docker-volume-rclone:amd64 args="-v" --alias rclone --grant-all-permissions' - "$USER"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# @description Installs a terminal theme that matches across various terminals by utilizing the `~/.local/bin/install-terminal-theme` script
|
|
installTerminalTheme() {
|
|
if command -v install-terminal-theme > /dev/null; then
|
|
install-terminal-theme
|
|
else
|
|
logg warn 'install-terminal-theme is not available'
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script loads crontab jobs that are defined and housed in your Install Doctor fork.
|
|
loadCronjobs() {
|
|
logg info 'Installing user crontab jobs'
|
|
crontab < "${XDG_CONFIG_HOME:-$HOME/.config}/crontab/config-user" || EXIT_CODE=$?
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
logg error 'Failed to load cronjobs for user'
|
|
fi
|
|
|
|
logg info 'Installing system crontab jobs'
|
|
sudo crontab < "${XDG_CONFIG_HOME:-$HOME/.config}/crontab/config-system" || EXIT_CODE=$?
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
logg error 'Failed to load cronjobs for system'
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script houses a wide range of macOS system tweaks that are intended to improve the developer experience on macOS,
|
|
# as well as improve security. Some of the tweaks include modifying default settings for various applications.
|
|
macOSSettings() {
|
|
if [ -d /System ] && [ -d /Applications ] && [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/shell/macos.sh" ]; then
|
|
bash "${XDG_CONFIG_HOME:-$HOME/.config}/shell/macos.sh"
|
|
fi
|
|
}
|
|
|
|
# @description Ensures all files in `~/.local/bin` are executable
|
|
makeLocalBinExecutable() {
|
|
logg info 'Ensuring all files in ~/.local/bin are executable'
|
|
find "$HOME/.local/bin" -mindepth 1 -maxdepth 2 -type f | while read EXE_FILE; do
|
|
if [ "$(echo -n "$EXE_FILE" | tail -c 3)" != ".md" ]; then
|
|
chmod +x "$EXE_FILE"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# @description
|
|
# Install Doctor was previously called Gas Station. It was also Ansible based. Some of the features that Install Doctor
|
|
# provides are made available via Ansible roles that Gas Station provides. This script symlinks Gas Station's roles
|
|
# so that they can be leveraged by Install Doctor.
|
|
#
|
|
# Some of the roles that Gas Station provides are not available via Ansible Galaxy yet. This script symlinks Gas Station
|
|
# roles to an Ansible Galaxy / Ansible friendly location.
|
|
#
|
|
# ## Ansible Installation
|
|
#
|
|
# If Ansible is not already installed, this script will also install Ansible and all the necessary requirements using `pipx`.
|
|
# This script must run before the `install-packages` script because some of the Ansible roles might be leveraged by it.
|
|
#
|
|
# ## TODO
|
|
#
|
|
# * Move installation logic into the ZX installer so that Ansible and its dependencies are only installed when required
|
|
# * Remove Ansible dependency completely
|
|
symlinkAnsibleRoles() {
|
|
logg info 'Ensuring Gas Station roles are symlinked to ~/.local/share/ansible/roles'
|
|
mkdir -p "${XDG_DATA_HOME:-$HOME/.local/share}/ansible/roles"
|
|
find "${XDG_DATA_HOME:-$HOME/.local/share}/gas-station/roles" -mindepth 2 -maxdepth 2 -type d | while read ROLE_PATH; do
|
|
ROLE_FOLDER="professormanhattan.$(echo "$ROLE_PATH" | sed 's/.*\/\([^\/]*\)$/\1/')"
|
|
ALT_ROLE_FOLDER="$(echo "$ROLE_PATH" | sed 's/.*\/\([^\/]*\)$/\1/')"
|
|
if [ ! -d "${XDG_DATA_HOME:-$HOME/.local/share}/ansible/roles/$ROLE_FOLDER" ] || [ "$(readlink -f "${XDG_DATA_HOME:-$HOME/.local/share}/ansible/roles/$ROLE_FOLDER")" != "$ROLE_PATH" ]; then
|
|
logg info 'Symlinking '"$ROLE_FOLDER"''
|
|
rm -f "${XDG_DATA_HOME:-$HOME/.local/share}/ansible/roles/$ROLE_FOLDER"
|
|
ln -s "$ROLE_PATH" "${XDG_DATA_HOME:-$HOME/.local/share}/ansible/roles/$ROLE_FOLDER"
|
|
fi
|
|
if [ ! -d "${XDG_DATA_HOME:-$HOME/.local/share}/ansible/roles/$ALT_ROLE_FOLDER" ] || [ "$(readlink -f "${XDG_DATA_HOME:-$HOME/.local/share}/ansible/roles/$ALT_ROLE_FOLDER")" != "$ROLE_PATH" ]; then
|
|
rm -f "${XDG_DATA_HOME:-$HOME/.local/share}/ansible/roles/$ALT_ROLE_FOLDER"
|
|
ln -s "$ROLE_PATH" "${XDG_DATA_HOME:-$HOME/.local/share}/ansible/roles/$ALT_ROLE_FOLDER"
|
|
fi
|
|
done
|
|
|
|
if [ -f "${XDG_DATA_HOME:-$HOME/.local/share}/gas-station/requirements.yml" ]; then
|
|
### Install Ansible Galaxy and dependencies if missing
|
|
if ! command -v ansible-galaxy > /dev/null; then
|
|
if ! command -v pipx > /dev/null; then
|
|
logg info 'Installing pipx via Homebrew'
|
|
brew install --quiet pipx
|
|
logg info 'Running pipx ensurepath'
|
|
pipx ensurepath
|
|
fi
|
|
logg info 'Installing ansible-core via pipx'
|
|
pipx install ansible-core
|
|
if [ -d /Applications ] && [ -d /System ]; then
|
|
logg info 'Injecting macOS-specific pipx dependencies via pipx'
|
|
pipx inject ansible-core PyObjC PyObjC-core
|
|
fi
|
|
logg info 'Injecting Ansible dependencies via pipx'
|
|
pipx inject ansible-core docker lxml netaddr pexpect python-vagrant pywinrm requests-credssp watchdog
|
|
mkdir -p "${XDG_CACHE_HOME:-$HOME/.cache}/megabyte-labs"
|
|
touch "${XDG_CACHE_HOME:-$HOME/.cache}/megabyte-labs/ansible-installed"
|
|
fi
|
|
|
|
### Ensure Ansible Galaxy was successfully loaded and then install the Ansible Galaxy requirements
|
|
if command -v ansible-galaxy > /dev/null; then
|
|
logg info 'Ensuring Ansible Galaxy collections are installed'
|
|
export ANSIBLE_CONFIG="${XDG_DATA_HOME:-$HOME/.local/share}/ansible/ansible.cfg"
|
|
ansible-galaxy install -r "${XDG_DATA_HOME:-$HOME/.local/share}/ansible/requirements.yml" > /dev/null || EXIT_CODE=$?
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
logg error 'Failed to install Ansible requirements from Ansible Galaxy'
|
|
if [ -d "${XDG_DATA_HOME:-$HOME/.local/share}/gas-station/collections" ]; then
|
|
logg info 'Attempting to use locally stored Ansible requirements'
|
|
cd "${XDG_DATA_HOME:-$HOME/.local/share}/gas-station/collections"
|
|
ansible-galaxy install -r requirements.yml || SECOND_EXIT_CODE=$?
|
|
if [ -n "$SECOND_EXIT_CODE" ]; then
|
|
logg error 'Failed to install requirements from both the cloud and the local copy' && exit 1
|
|
fi
|
|
else
|
|
logg warn "${XDG_DATA_HOME:-$HOME/.local/share}/gas-station/collections is missing"
|
|
fi
|
|
fi
|
|
else
|
|
logg warn 'Unable to install the Ansible Galaxy requirements.yml since the ansible-galaxy executable is missing from the PATH'
|
|
fi
|
|
else
|
|
logg warn '~/.local/share/ansible/requirements.yml is missing'
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script checks if `python3` is available and if `python` is not available. If both are true, then the script
|
|
# symlinks `python` to `python3` so that the `python` command uses `python3`.
|
|
#
|
|
# This is useful if you do not want to install Python 2.7 and would like Python 3 to be used in all scenarios where Python is
|
|
# invoked with the `python` command.
|
|
symlinkPython() {
|
|
### Symlink python3 to python if it is unavailable
|
|
if ! command -v python > /dev/null && command -v python3 > /dev/null; then
|
|
logg info 'Symlinking python3 to python since the latter is unavailable'
|
|
sudo ln -s "$(which python3)" /usr/local/bin/python
|
|
fi
|
|
}
|
|
|
|
# @description
|
|
# This script creates an empty directory with each user's name in `/var/log/user`. It initializes the folder in hopes
|
|
# that we can eventually store all user logs in a single directory alongside the system logs folder.
|
|
userLogFolders() {
|
|
find '{{ .host.homeParentFolder }}' -mindepth 1 -maxdepth 1 -type d | while read HOME_DIR; do
|
|
USER_FOLDER="$(echo "$HOME_DIR" | sed 's/.*\/\([^\/]*\)$/\1/')"
|
|
if [ -d "$HOME_DIR/.local" ]; then
|
|
if [ ! -d "/var/log/user/$USER_FOLDER" ]; then
|
|
logg info 'Creating /var/log/user/'"$USER_FOLDER"'' && sudo mkdir -p "/var/log/user/$USER_FOLDER"
|
|
fi
|
|
logg info "Applying user permissions to /var/log/user/$USER_FOLDER" && sudo chown -Rf "$USER_FOLDER" "/var/log/user/$USER_FOLDER"
|
|
fi
|
|
done
|
|
}
|
|
|
|
if [ -n "$DEBUG" ] || [ -n "$DEBUG_MODE" ]; then
|
|
logg info 'The DEBUG or DEBUG_MODE environment variable is set so the post-dotfile-application routine tasks will be run synchronously'
|
|
addZshEnv
|
|
applyFontsToSystem
|
|
applyLinuxConfSettings
|
|
applyLinuxThemeFiles
|
|
applyRootConfig
|
|
applyWallpaper
|
|
asdfPluginInstall
|
|
configureNetworkManagerVPNProfiles
|
|
configureSSHD
|
|
dconfSettings
|
|
decryptSSHKeys
|
|
emscriptenInstall
|
|
enableAutoUpdateDarwin
|
|
ensureQtStyleOverride
|
|
ensurePipUpdated
|
|
ensureSystemGemUpdated
|
|
ensureZshShell
|
|
gnomeExtensionSettings
|
|
grubSettings
|
|
installDockerRclonePlugin
|
|
installTerminalTheme
|
|
loadCronjobs
|
|
macOSSettings
|
|
makeLocalBinExecutable
|
|
symlinkAnsibleRoles
|
|
symlinkPython
|
|
userLogFolders
|
|
else
|
|
addZshEnv &
|
|
applyFontsToSystem &
|
|
applyLinuxConfSettings &
|
|
applyLinuxThemeFiles &
|
|
applyRootConfig &
|
|
applyWallpaper &
|
|
asdfPluginInstall &
|
|
configureNetworkManagerVPNProfiles &
|
|
configureSSHD &
|
|
dconfSettings &
|
|
decryptSSHKeys &
|
|
emscriptenInstall &
|
|
enableAutoUpdateDarwin &
|
|
ensureQtStyleOverride &
|
|
ensurePipUpdated &
|
|
ensureSystemGemUpdated &
|
|
ensureZshShell &
|
|
gnomeExtensionSettings &
|
|
grubSettings &
|
|
installDockerRclonePlugin &
|
|
installTerminalTheme &
|
|
loadCronjobs &
|
|
macOSSettings &
|
|
makeLocalBinExecutable &
|
|
symlinkAnsibleRoles &
|
|
symlinkPython &
|
|
userLogFolders &
|
|
wait
|
|
fi
|
|
|
|
logg info 'Completed post-dotfile-application routine'
|