#!/usr/bin/env bash # @file System Tweaks # @brief Applies a set of system tweaks such as ensuring the hostname is set, setting the timezone, and more # @description # This script applies system tweaks that should be made before the rest of the provisioning process. {{ includeTemplate "universal/profile-before" }} {{ includeTemplate "universal/logg-before" }} export VOLTA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}/volta" export PATH="$VOLTA_HOME/bin:$PATH" # @description # This script determines the ideal `/swapfile` size by checking how much RAM is available on the system. # It then creates the appropriate `/swapfile` by considering factors such as the file system type. It # currently supports BTRFS and regular file systems. # # After the `/swapfile` is created, it is enabled and assigned the appropriate permissions. # # ## TODO # # * Add logic that creates a swapfile for ZFS-based systems # * Integrate logic from https://gitlab.com/megabyte-labs/gas-station/-/blob/master/roles/system/common/tasks/linux/swap.yml allocateSwap() { if [ "{{ .host.distro.family }}" = "linux" ]; then if [ ! -f /swapfile ]; then ### Determine ideal size of /swapfile MEMORY_IN_KB="$(grep MemTotal /proc/meminfo | sed 's/.* \(.*\) kB/\1/')" MEMORY_IN_GB="$((MEMORY_IN_KB / 1024 / 1024))" if [ "$MEMORY_IN_GB" -gt 64 ]; then SWAP_SPACE="$((MEMORY_IN_GB / 10))" elif [ "$MEMORY_IN_GB" -gt 32 ]; then SWAP_SPACE="$((MEMORY_IN_GB / 8))" elif [ "$MEMORY_IN_GB" -gt 8 ]; then SWAP_SPACE="$((MEMORY_IN_GB / 4))" else SWAP_SPACE="$MEMORY_IN_GB" fi ### Create /swapfile FS_TYPE="$(df -Th | grep ' /$' | sed 's/[^ ]*\s*\([^ ]*\).*/\1/')" if [ "$FS_TYPE" == 'btrfs' ]; then logg info 'Creating BTRFS /swapfile' sudo btrfs filesystem mkswapfile /swapfile elif [ "$FS_TYPE" == 'zfs' ]; then logg warn 'ZFS system detected - add logic here to add /swapfile' else logg info "Creating a $SWAP_SPACE GB /swapfile" sudo fallocate -l "${SWAP_SPACE}G" /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile fi ### Enable the /swapfile if [ -f /swapfile ]; then logg info 'Running sudo swapon /swapfile' sudo swapon /swapfile if cat /etc/fstab | grep "/swapfile"; then sudo sed -i '/\/swapfile/\/swapfile none swap defaults 0 0/' /etc/fstab else echo "/swapfile none swap defaults 0 0" | sudo tee -a /etc/fstab > /dev/null fi fi fi fi } # @description # This script imports your publicly hosted GPG key using `pgp.mit.edu` as the key host. It then assigns it # the ultimate trust level. It also downloads and configures GPG to use the configuration defined in `.config.gpg` # in the `home/.chezmoidata.yaml` file. configureGPG() { export KEYID="{{ .user.gpg.id }}" if [ -n "$KEYID" ] && command -v gpg > /dev/null; then if [ ! -d "$HOME/.gnupg" ]; then mkdir "$HOME/.gnupg" fi chown "$(whoami)" "$HOME/.gnupg" chmod 700 "$HOME/.gnupg" chown -Rf "$(whoami)" "$HOME/.gnupg/" find "$HOME/.gnupg" -type f -exec chmod 600 {} \; find "$HOME/.gnupg" -type d -exec chmod 700 {} \; if [ ! -f "$HOME/.gnupg/gpg.conf" ]; then logg 'Downloading hardened gpg.conf file to ~/.gpnupg/gpg.conf' curl -sSL --compressed "{{ .config.gpg }}" > "$HOME/.gnupg/gpg.conf" chmod 600 "$HOME/.gnupg/gpg.conf" fi logg info 'Killing dirmngr instance and reloading daemon with standard-resolver' && sudo pkill dirmngr dirmngr --daemon --standard-resolver KEYID_TRIMMED="$(echo "$KEYID" | sed 's/^0x//')" if ! gpg --list-secret-keys --keyid-format=long | grep "$KEYID_TRIMMED" > /dev/null; then if [ -f "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/private_dot_gnupg/public/${KEYID}.asc" ]; then logg info "Importing GPG key stored in ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/private_dot_gnupg/public/${KEYID}.asc since its name matches the GPG key ID in .chezmoi.yaml.tmpl" gpg --import "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/private_dot_gnupg/public/${KEYID}.asc" && logg success 'Successfully imported master GPG key' else logg info 'Attempting to download the specified public GPG key ({{ .user.gpg.id }}) from public keyservers' gpg --keyserver https://pgp.mit.edu --recv "$KEYID" || EXIT_CODE=$? if [ -n "$EXIT_CODE" ]; then logg info 'Non-zero exit code received when downloading public GPG key' gpg --keyserver hkps://pgp.mit.edu --recv "$KEYID" || EXIT_CODE=$? if [ -n "$EXIT_CODE" ]; then logg info 'Non-zero exit code received when trying to retrieve public user GPG key on hkps://pgp.mit.edu' else logg success 'Successfully imported configured public user GPG key' fi fi fi else logg info 'Key is already in keyring' fi logg info 'Stopping dirmngr' gpgconf --kill dirmngr && logg info 'Stopped dirmngr' || info warn 'Failed to stop dirmngr' logg 'Ensuring the trust of the provided public GPG key is set to maximum' echo -e "trust\n5\ny" | gpg --command-fd 0 --edit-key "$KEYID" else logg warn 'gpg appears to be unavailable. Is it installed and on the PATH?' fi } # @description Disable the creation of `.DS_Store` files on macOS. disableDStoreFileCreation() { if command -v m > /dev/null; then logg info 'Disabling creation of .DS_Store files' echo y | m dir dsfiles off fi } # @description Enables transparent dark-mode on macOS enableDarkTransparentMode() { if command -v m > /dev/null; then logg info 'Enabling dark mode' && m appearance darkmode YES logg info 'Enabling theme transparency' && m appearance transparency YES fi } # @description Helper function for installing Homebrew packages that have a matching package name and binary executable name. ensureBrewPackageInstalled() { if ! command -v "$1" > /dev/null; then if command -v brew; then logg info "Installing $1 via Homebrew" brew install --quiet "$1" || EXIT_CODE=$? if [ -n "$EXIT_CODE" ]; then logg error "$1 was not successfully installed via Homebrew" unset EXIT_CODE fi else logg error "brew is unavailable. Cannot use it to perform installation of $1" fi else logg info "$1 is already installed" fi } # @description Ensure delta is installed via Homebrew ensureDeltaInstalled() { if ! command -v delta > /dev/null; then if command -v brew; then logg 'Installing delta via Homebrew' brew install --quiet git-delta || DELTA_EXIT_CODE=$? if [ -n "$DELTA_EXIT_CODE" ]; then logg error 'git-delta was not successfully installed via Homebrew' fi else logg 'brew is unavailable. Cannot use it to perform a system installation of node.' fi else logg 'delta is available' fi } # @description Ensure Node is installed via Homebrew ensureNodeInstalled() { ### Ensure node is installed if ! command -v node > /dev/null; then if command -v brew; then logg 'Installing node via Homebrew' brew install --quiet node || NODE_EXIT_CODE=$? if [ -n "$NODE_EXIT_CODE" ]; then logg warn 'Calling brew link --overwrite node because the Node.js installation seems to be misconfigured' brew link --overwrite node fi else logg 'brew is unavailable. Cannot use it to perform a system installation of node.' fi else logg 'node is available' fi } # @description # This script ensures that there is a group with the same name of the provisioning user available on the system. ensureUserGroup() { if [ "{{ .host.distro.family }}" = "darwin" ]; then if [ -n "$USER" ]; then logg info "Adding the $USER user to the $USER group" ### Ensure user has group of same name (required for Macports) logg info "Ensuring user ($USER) has a group with the same name ($USER) and that it is a member. Sudo privileges may be required" GROUP="$USER" USERNAME="$USER" ### Add group sudo dscl . create /Groups/$GROUP ### Add GroupID to group if [[ "$(sudo dscl . read /Groups/$GROUP gid 2>&1)" == *'No such key'* ]]; then MAX_ID_GROUP="$(dscl . -list /Groups gid | awk '{print $2}' | sort -ug | tail -1)" GROUP_ID="$((MAX_ID_GROUP+1))" sudo dscl . create /Groups/$GROUP gid "$GROUP_ID" fi ### Add user sudo dscl . create /Users/$USERNAME ### Add PrimaryGroupID to user if [[ "$(sudo dscl . read /Users/$USERNAME PrimaryGroupID 2>&1)" == *'No such key'* ]]; then sudo dscl . create /Users/$USERNAME PrimaryGroupID 20 fi ### Add UniqueID to user if [[ "$(sudo dscl . read /Users/$USERNAME UniqueID 2>&1)" == *'No such key'* ]]; then MAX_ID_USER="$(dscl . -list /Users UniqueID | awk '{print $2}' | sort -ug | tail -1)" USER_ID="$((MAX_ID_USER+1))" sudo dscl . create /Users/$USERNAME UniqueID "$USERID" fi ### Add user to group sudo dseditgroup -o edit -t user -a $USERNAME $GROUP else logg warn 'The USER environment variable is unavailable' fi fi } # @description Increases the amount of memory a process can consume on Linux. In the case of `netdata` and other programs, many systems will suggest # increasing the `vm.max_map_count`. According to a [RedHat article](https://access.redhat.com/solutions/99913), the default value is `65530`. # This function increases that value to `262144` if `sysctl` is available on the system. increaseMapCount() { if [ ! -d /Applications ] && [ ! -d /System ]; then ### Linux if command -v sysctl > /dev/null; then logg info 'Increasing vm.max_map_count size to 262144' sudo sysctl -w vm.max_map_count=262144 > /dev/null fi fi } # @description Helper function for installDocker that installs pre-built gVisor using method recommended on official website function gVisorPreBuilt() { logg info 'Installing gVisor using method recommended on official website' set -e mkdir /tmp/gvisor && cd /tmp/gvisor ARCH=$(uname -m) URL="https://storage.googleapis.com/gvisor/releases/release/latest/${ARCH}" logg info 'Downloading gVisor runsc and containerd-shim-runsc-v1 SHA signatures' wget "${URL}/runsc ${URL}/runsc.sha512" "${URL}/containerd-shim-runsc-v1 ${URL}/containerd-shim-runsc-v1.sha512" sha512sum -c runsc.sha512 -c containerd-shim-runsc-v1.sha512 rm -f *.sha512 chmod a+rx runsc containerd-shim-runsc-v1 sudo mv runsc containerd-shim-runsc-v1 /usr/local/bin } # @description Helper function for installDocker that installs gVisor using alternate Go method described on the GitHub page function gVisorGo() { # Official build timed out - use Go method logg info 'Installing gVisor using the Go fallback method' sudo chown -Rf "$(whoami)" /usr/local/src/gvisor cd /usr/local/src/gvisor echo "module runsc" > go.mod GO111MODULE=on go get gvisor.dev/gvisor/runsc@go CGO_ENABLED=0 GO111MODULE=on sudo -E go build -o /usr/local/bin/runsc gvisor.dev/gvisor/runsc GO111MODULE=on sudo -E go build -o /usr/local/bin/containerd-shim-runsc-v1 gvisor.dev/gvisor/shim } # @description Helper function for installDocker that installs gVisor using the [GitHub developer page method](https://github.com/google/gvisor#installing-from-source). This method requires Docker to be installed function gVisorSource() { ### Ensure sources are cloned / up-to-date logg info 'Building gVisor from source' if [ -d /usr/local/src/gvisor ]; then cd /usr/local/src/gvisor sudo git reset --hard HEAD sudo git clean -fxd sudo git pull origin master else sudo git clone https://github.com/google/gvisor.git /usr/local/src/gvisor fi ### Build gVisor cd /usr/local/src/gvisor sudo mkdir -p bin # Wait 5 minutes for build to finish, and if it does not use Go # TODO - Generate container-shim-runsc-v1 as well (low priority since this method is not used and is only recommended for development) sudo timeout 600 make copy TARGETS=runsc DESTINATION=bin/ if [ -f ./bin/runsc ]; then sudo cp ./bin/runsc /usr/local/bin else logg error 'Timed out while building runsc from source (10 minutes)' && exit 6 fi } # @description Helper function for installDocker that Installs systemsecret credential helper for Linux function installCredentialSecretService() { curl -sSL https://github.com/docker/docker-credential-helpers/releases/download/v0.7.0/docker-credential-secretservice-v0.7.0.linux-amd64 > /tmp/docker-credential-secretservice sudo mv /tmp/docker-credential-secretservice /usr/local/bin/docker-credential-secretservice } # @description # This script ensures Docker is installed and then adds the provisioning user to the `docker` group so that they can # access Docker without `sudo`. It also installs and configures gVisor for use with Docker. # # ## gVisor # # gVisor is included with our Docker setup because it improves the security of Docker. gVisor is an application kernel, written in Go, # that implements a substantial portion of the Linux system call interface. It provides an additional layer of isolation between running # applications and the host operating system. It has gained a lot of attention, perhaps partly, because it is maintained by Google. installDocker() { ### Ensures `~/.config/docker` is symlinked to `~/.docker` which is required for Docker Desktop compatibility since it currently does not honor XDG spec. This will ### remove the current configuration at `~/.docker` if it is present and not symlinked to `~/.config/docker`. if [ "$(readlink -f "$HOME/.docker")" != "${XDG_CONFIG_HOME:-$HOME/.config}/docker" ]; then logg info 'Removing ~/.docker if present' && rm -rf "$HOME/.docker" logg info 'Ensuring ~/.config/docker exists' && mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/docker" logg info 'Symlinking ~/.config/docker to ~/.docker for Docker Desktop compatibility' && ln -s "${XDG_CONFIG_HOME:-$HOME/.config}/docker" "$HOME/.docker" else logg info 'Symlink from ~/.config/docker to ~/.docker is already present' fi ### Install Docker if [ -d /Applications ] && [ -d /System ]; then ### macOS if [ ! -d /Applications/Docker.app ]; then logg info 'Installing Docker on macOS via Homebrew cask' brew install --cask --quiet --no-quarantine docker else logg info 'Docker appears to be installed already' fi logg info 'Opening the Docker for Desktop app so that the Docker engine starts running' # TODO - --install-privileged-components may be necessary for `docker extension` command but it causes the command to no longer work # open --background -a Docker --args --accept-license --unattended --install-privileged-components open --background -a Docker --args --accept-license --unattended elif command -v apt-get > /dev/null; then . /etc/os-release if [ "$ID" == 'ubuntu' ]; then logg info 'Installing Docker on Ubuntu' else logg info 'Installing Docker on Debian' fi sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg lsb-release sudo mkdir -p /etc/apt/keyrings curl -fsSL "https://download.docker.com/linux/$ID/gpg" | sudo gpg --dearmor --yes -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$ID $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin elif command -v dnf > /dev/null; then . /etc/os-release if [ "$ID" == 'centos' ]; then logg info 'Installing Docker on CentOS' elif [ "$ID" == 'fedora' ]; then logg info 'Installing Docker on Fedora' else logg error 'Unknown OS - cannot install Docker' && exit 1 fi sudo dnf -y install dnf-plugins-core sudo dnf config-manager --add-repo "https://download.docker.com/linux/$ID/docker-ce.repo" sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin elif command -v yum > /dev/null; then # CentOS logg info 'Installing Docker on CentOS' sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin elif command -v apk > /dev/null; then # Alpine logg info 'Installing Docker on Alpine' sudo apk add --update docker elif command -v pacman > /dev/null; then # Archlinux logg info 'Installing Docker on Archlinux' sudo pacman -Syu sudo pacman -S docker elif command -v zypper > /dev/null; then # OpenSUSE logg info 'Installing Docker on OpenSUSE' sudo zypper addrepo https://download.docker.com/linux/sles/docker-ce.repo sudo zypper install docker-ce docker-ce-cli containerd.io docker-compose-plugin fi ### Add Docker group on Linux if command -v groupadd > /dev/null; then # Linux if ! cat /etc/group | grep docker > /dev/null; then logg info 'Creating Docker group' sudo groupadd docker fi logg info 'Adding user to Docker group' sudo usermod -aG docker "$USER" fi ### Boot Docker on start with systemd on Linux machines if command -v systemctl > /dev/null; then # Systemd Linux sudo systemctl start docker.service sudo systemctl enable docker.service sudo systemctl enable containerd.service fi ### Add gVisor if [ ! -d /Applications ] || [ ! -d /System ]; then ### Linux if ! command -v docker-credential-secretservice > /dev/null; then installCredentialSecretService fi if ! command -v runsc > /dev/null; then ### Install gVisor gVisorPreBuilt || PRE_BUILT_EXIT_CODE=$? if [ -n "$PRE_BUILT_EXIT_CODE" ]; then logg warn 'gVisor failed to install using the pre-built method' gVisorGo || GO_METHOD_EXIT_CODE=$? if [ -n "$GO_METHOD_EXIT_CODE" ]; then logg warn 'gVisor failed to install using the Go fallback method' gVisorSource || SOURCE_EXIT_CODE=$? if [ -n "$SOURCE_EXIT_CODE" ]; then logg error 'All gVisor installation methods failed' && exit 1 else logg success 'gVisor installed via source' fi else logg success 'gVisor installed via Go fallback method' fi else logg success 'gVisor installed from pre-built Google-provided binaries' fi else logg info 'runsc is installed' fi ### Ensure Docker is configured to use runsc if [ ! -f /etc/docker/daemon.json ]; then ### Configure Docker to use gVisor ### Create /etc/docker/daemon.json logg info 'Creating /etc/docker' sudo mkdir -p /etc/docker if [ -f "${XDG_DATA_HOME:-$HOME/.local/share}/home/dot_config/docker/daemon.json" ]; then logg info 'Creating /etc/docker/daemon.json' sudo cp -f "${XDG_DATA_HOME:-$HOME/.local/share}/home/dot_config/docker/daemon.json" /etc/docker/daemon.json else logg warn "${XDG_DATA_HOME:-$HOME/.local/share}/home/dot_config/docker/daemon.json is not available so the /etc/docker/daemon.json file cannot be populated" fi ### Restart / enable Docker if [[ ! "$(test -d /proc && grep Microsoft /proc/version > /dev/null)" ]] && command -v systemctl > /dev/null; then logg info 'Restarting Docker service' sudo systemctl restart docker.service sudo systemctl restart containerd.service fi ### Test Docker /w runsc logg info 'Testing that Docker can load application with runsc' docker run --rm --runtime=runsc hello-world || RUNSC_EXIT_CODE=$? if [ -n "$RUNSC_EXIT_CODE" ]; then logg error 'Failed to run the Docker hello-world container with runsc' && exit 5 else logg info 'Docker successfully ran the hello-world container with runsc' fi fi fi } # @description # This script enrolls the device as a JumpCloud managed asset. The `JUMPCLOUD_CONNECT_KEY` secret should # be populated using one of the methods described in the [Secrets documentation](https://install.doctor/docs/customization/secrets). # # *Note: You should check out the supported systems before trying to enroll devices.* # # ## JumpCloud on macOS # # macOS offers a native device management feature offered through Apple Business. It is the preferred # method since it offers most of the desirable features (like remote wipe). The [JumpCloud MDM documentation](https://support.jumpcloud.com/support/s/article/Getting-Started-MDM) # details the steps required to register macOS MDM profiles with JumpCloud. # # ## Links # # * [JumpCloud device management requirements](https://support.jumpcloud.com/support/s/article/jumpcloud-agent-compatibility-system-requirements-and-impacts1) installJumpCloud() { if [ "{{ .host.distro.family }}" = "linux" ]; then if [ "{{ if (stat (joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "JUMPCLOUD_CONNECT_KEY")) }}{{- includeTemplate "secrets/JUMPCLOUD_CONNECT_KEY" | decrypt | trim -}}{{ else }}{{- env "JUMPCLOUD_CONNECT_KEY" -}}{{ end }}" != "" ]; then logg info 'Enrolling device with JumpCloud by running the kickstart script' curl --tlsv1.2 --silent --show-error --header 'x-connect-key: {{ if (stat (joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "JUMPCLOUD_CONNECT_KEY")) }}{{- includeTemplate "secrets/JUMPCLOUD_CONNECT_KEY" | decrypt | trim -}}{{ else }}{{- env "JUMPCLOUD_CONNECT_KEY" -}}{{ end }}' https://kickstart.jumpcloud.com/Kickstart | sudo bash fi fi } # @description # This script removes some of the software deemed to be "bloatware" by cycling through the values defined in # `.removeLinuxPackages` of the `home/.chezmoidata.yaml` file. removeLinuxBloatware() { if [ "{{ .host.distro.family }}" = "linux" ]; then {{- $removePackages := join " " .removeLinuxPackages }} ### Remove bloatware packages defined in .chezmoidata.yaml for PKG in {{ $removePackages }}; do if command -v apk > /dev/null; then if apk list "$PKG" | grep "$PKG" > /dev/null; then sudo apk delete "$PKG" fi elif command -v apt-get > /dev/null; then if dpkg -l "$PKG" | grep -E '^ii' > /dev/null; then sudo apt-get remove -y "$PKG" logg success 'Removed '"$PKG"' via apt-get' fi elif command -v dnf > /dev/null; then if rpm -qa | grep "$PKG" > /dev/null; then sudo dnf remove -y "$PKG" logg success 'Removed '"$PKG"' via dnf' fi elif command -v yum > /dev/null; then if rpm -qa | grep "$PKG" > /dev/null; then sudo yum remove -y "$PKG" logg success 'Removed '"$PKG"' via yum' fi elif command -v pacman > /dev/null; then if pacman -Qs "$PKG" > /dev/null; then sudo pacman -R "$PKG" logg success 'Removed '"$PKG"' via pacman' fi elif command -v zypper > /dev/null; then if rpm -qa | grep "$PKG" > /dev/null; then sudo zypper remove -y "$PKG" logg success 'Removed '"$PKG"' via zypper' fi fi done fi } # @description Sets the hostname using `scutil` on macOS and using `hostname` and `hostnamectl` on Linux. On macOS, the HostName, LocalHostName, and ComputerName # are set equal to the value stored in `.host.hostname` (in `.chezmoi.yaml.tmpl`) but with the `.host.domain` stripped off. On Linux, the same is done # but only the hostname is set. On Linux, the hostname is set with the `hostname` command and then also with the `hostnamectl` command if it is available. # # ## Sources # # * [Changing Linux hostname permanently](https://www.tecmint.com/set-hostname-permanently-in-linux/) setHostname() { if [ -d /Applications ] && [ -d /System ]; then # Source: https://apple.stackexchange.com/questions/287760/set-the-hostname-computer-name-for-macos logg info 'Setting macOS hostname / local hostname / computer name' sudo scutil --set HostName '{{ .host.hostname | replace .host.domain "" | replace "." "" }}.{{ .host.domain }}' && logg success 'Changed HostName to {{ .host.hostname | replace .host.domain "" | replace "." "" }}.{{ .host.domain }}' sudo scutil --set LocalHostName '{{ .host.hostname | replace .host.domain "" | replace "." "" }}' && logg success 'Changed LocalHostName to {{ .host.hostname | replace .host.domain "" | replace "." "" }}' sudo scutil --set ComputerName '{{ .host.hostname | replace .host.domain "" | replace "." "" }}' && logg success 'Changed ComputerName to {{ .host.hostname | replace .host.domain "" | replace "." "" }}' logg info 'Flushing DNS cache' dscacheutil -flushcache elif [ -f /etc/passwd ]; then logg info 'Setting Linux hostname' hostname '{{ .host.hostname | replace .host.domain "" | replace "." "" }}.{{ .host.domain }}' && logg success 'Changed hostname to {{ .host.hostname | replace .host.domain "" | replace "." "" }}.{{ .host.domain }}' if command -v hostnamectl > /dev/null; then logg info 'Ensuring hostname persists after reboot' sudo hostnamectl set-hostname '{{ .host.hostname | replace .host.domain "" | replace "." "" }}.{{ .host.domain }}' && logg success 'Permanently changed hostname to {{ .host.hostname | replace .host.domain "" | replace "." "" }}.{{ .host.domain }}' else logg warn 'hostnamectl was not available in the PATH - this operating system type might be unsupported' fi else logg warn 'Could not configure hostname because system type was not detectable' fi } # @description Sets the NTP server using `m` on macOS setNtpServer() { if command -v m > /dev/null; then ### macOS m ntp set {{ .user.ntpServer }} else logg warn 'Skipped setting the NTP server' fi } # @description Sets the system timezone using `timedatectl` on Linux and `m` on macOS. If neither commands are available # then a warning message is printed. setTimezone() { if command -v timedatectl > /dev/null; then ### Linux logg info 'Setting timezone to {{ .user.timezone }}' sudo timedatectl set-timezone {{ .user.timezone }} elif command -v m > /dev/null; then ### macOS logg info 'Setting timezone to {{ .user.timezone }}' && m timezone set {{ .user.timezone }} else logg warn 'Neither timedatectl (Linux) or m (macOS) were found on the system' fi } # @description Configures macOS to enable the notification center showNotificationCenter() { if command -v m > /dev/null; then logg info 'Configuring macOS to show notification center' && m notification showcenter YES fi } installBrewPackages() { ensureNodeInstalled ensureDeltaInstalled ensureBrewPackageInstalled "gh" ensureBrewPackageInstalled "go" ensureBrewPackageInstalled "zx" ensureBrewPackageInstalled "volta" volta install node@latest & npm install -g npm@latest & wait logg success 'Finished installing auxilary Homebrew packages' } if [ -n "$DEBUG" ] || [ -n "$DEBUG_MODE" ]; then logg info 'The DEBUG or DEBUG_MODE environment variable is set so preliminary system tweaks will be run synchronously' allocateSwap configureGPG disableDStoreFileCreation enableDarkTransparentMode ensureUserGroup increaseMapCount installBrewPackages installDocker installJumpCloud removeLinuxBloatware setHostname setNtpServer setTimezone showNotificationCenter else allocateSwap & configureGPG & disableDStoreFileCreation & enableDarkTransparentMode & ensureUserGroup & increaseMapCount & installBrewPackages & installDocker & installJumpCloud & removeLinuxBloatware & setHostname & setNtpServer & setTimezone & showNotificationCenter & wait fi logg success 'Successfully applied preliminary system tweaks'