diff --git a/setup.sh b/setup.sh index a29aba4..63125d7 100755 --- a/setup.sh +++ b/setup.sh @@ -1,30 +1,73 @@ #!/usr/bin/env bash -NIXOS_RELEASE=24.05 -GIT_REPO=https://git.mvl.sh/vleeuwenmenno/dotfiles.git +set -euo pipefail +IFS=$'\n\t' -# Check if $HOME/.dotfiles-setup exists, if so exit because setup has already been run -if [ -f $HOME/.dotfiles-setup ]; then - echo "Setup has already been run, exiting..." - exit 0 -fi +# Constants +readonly NIXOS_RELEASE="24.05" +readonly GIT_REPO="https://git.mvl.sh/vleeuwenmenno/dotfiles.git" +readonly DOTFILES_DIR="${HOME}/dotfiles" +readonly SETUP_MARKER="${HOME}/.dotfiles-setup" -# Check if $HOME/dotfiles exists, if not clone the dotfiles repo -if [ ! -d $HOME/dotfiles ]; then - tput setaf 3 - echo "Cloning dotfiles repo..." - tput sgr0 - git clone $GIT_REPO $HOME/dotfiles -fi +# Color constants +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[0;33m' +readonly NC='\033[0m' # No Color + +# Helper functions +log_info() { + echo -e "${YELLOW}$1${NC}" +} + +log_success() { + echo -e "${GREEN}$1${NC}" +} + +log_error() { + echo -e "${RED}$1${NC}" >&2 +} + +die() { + log_error "$1" + exit 1 +} + +confirm_symlink() { + local link="$1" + local msg="$2" + if [ ! -L "$link" ]; then + die "$msg" + fi +} + +backup_file() { + local file="$1" + if [ -f "$file" ]; then + log_info "Backing up $file to $file.bak..." + mv "$file" "$file.bak" || die "Failed to backup $file" + fi +} + +check_prerequisites() { + command -v git >/dev/null 2>&1 || die "Git is required but not installed" + command -v sudo >/dev/null 2>&1 || die "Sudo is required but not installed" +} + +validate_hostname() { + local hostname="$1" + if [[ -z "$hostname" || ! "$hostname" =~ ^[a-zA-Z0-9_-]+$ || ${#hostname} -gt 64 ]]; then + return 1 + fi + return 0 +} create_hardware_config() { - hostname=$1 + local hostname="$1" + log_info "Creating hardware configuration for $hostname..." - tput setaf 3 - echo "Creating hardware configuration for $hostname..." - tput sgr0 - - template=" + local config_file="$DOTFILES_DIR/config/nixos/hardware/$hostname.nix" + local template=$(cat << 'EOF' { config, lib, @@ -34,49 +77,62 @@ create_hardware_config() { }: { imports = [ /etc/nixos/hardware-configuration.nix ]; - networking.hostName = \"$hostname\"; - }" + networking.hostName = "%s"; + } +EOF +) - echo "$template" > $HOME/dotfiles/config/nixos/hardware/$hostname.nix + printf "$template" "$hostname" > "$config_file" || \ + die "Failed to create hardware configuration" - if [ -f $HOME/dotfiles/config/nixos/hardware/$hostname.nix ]; then - tput setaf 2 - echo "Hardware configuration created successfully." - echo "Consider adding additional hardware configuration to ~/dotfiles/config/nixos/hardware/$hostname.nix." - tput sgr0 - else - tput setaf 1 - echo "Failed to create hardware configuration. Exiting..." - tput sgr0 - exit 1 - fi + log_success "Hardware configuration created successfully." + log_info "Consider adding additional hardware configuration to $config_file" - # Ask if this is a server or workstation - tput setaf 3 - echo "Is this a server or workstation? (s/w)" - tput sgr0 - + # System type selection + local systemType while true; do - read -p "(s/w): " systemType - if [[ $systemType == "s" || $systemType == "w" ]]; then + log_info "Is this a server or workstation? (s/w)" + read -r -p "(s/w): " systemType + if [[ "$systemType" =~ ^[sw]$ ]]; then break fi - - echo "Invalid input. Please enter 's' for server or 'w' for workstation." + log_error "Invalid input. Please enter 's' for server or 'w' for workstation." done - - if [ $systemType == "s" ]; then + local isServer="false" + local isWorkstation="false" + if [ "$systemType" = "s" ]; then isServer="true" - isWorkstation="false" else - isServer="false" isWorkstation="true" fi - flakeConfiguration=" + # Update flake configurations + update_nixos_flake "$hostname" "$isServer" "$isWorkstation" || \ + die "Failed to update NixOS flake configuration" + + update_home_manager_flake "$hostname" "$isServer" || \ + die "Failed to update Home Manager flake configuration" - "$hostname" = nixpkgs.lib.nixosSystem { + # Add new files to git + git -C "$DOTFILES_DIR" add \ + "config/nixos/hardware/$hostname.nix" \ + "config/nixos/flake.nix" \ + "config/home-manager/flake.nix" || \ + die "Failed to add files to git" + + log_info "\nDon't forget to commit and push the changes to the dotfiles repo after testing." + git -C "$DOTFILES_DIR" status + echo +} + +update_nixos_flake() { + local hostname="$1" + local isServer="$2" + local isWorkstation="$3" + + local flake_config=" + \"$hostname\" = nixpkgs.lib.nixosSystem { inherit system; modules = [ ./hardware/$hostname.nix @@ -89,266 +145,180 @@ create_hardware_config() { isServer = $isServer; }; }; - " - # Insert flakeConfiguration into flake.nix at nixosConfigurations = { ... } - sed -i "s/nixosConfigurations = {/nixosConfigurations = { $flakeConfiguration/g" $HOME/dotfiles/config/nixos/flake.nix + local flake_file="$DOTFILES_DIR/config/nixos/flake.nix" + sed -i "s/nixosConfigurations = {/nixosConfigurations = { $flake_config/g" "$flake_file" - # Validate flake.nix with nixfmt - nix-shell -p nixfmt --run "nixfmt $HOME/dotfiles/config/nixos/flake.nix" + # Validate flake.nix + nix-shell -p nixfmt --run "nixfmt $flake_file" || return 1 + log_success "NixOS Flake configuration added successfully." +} - if [ $? -ne 0 ]; then - tput setaf 1 - echo "Something went wrong adding the flake configuration for NixOS." - echo "Failed to validate flake.nix. Exiting..." - tput sgr0 - exit 1 - fi +update_home_manager_flake() { + local hostname="$1" + local isServer="$2" - tput setaf 2 - echo "NixOS Flake configuration added successfully." - tput sgr0 - - haFlakeConfiguration=" - - "$hostname" = home-manager.lib.homeManagerConfiguration { + local flake_config=" + \"$hostname\" = home-manager.lib.homeManagerConfiguration { inherit pkgs; modules = [ ./home.nix ]; extraSpecialArgs = { inherit pkgs pkgs-unstable; isServer = $isServer; - hostname = "$hostname"; + hostname = \"$hostname\"; }; }; - " - # Insert haFlakeConfiguration into flake.nix of home-manager at homeConfigurations = { - sed -i "s/homeConfigurations = {/homeConfigurations = { $haFlakeConfiguration/g" $HOME/dotfiles/config/home-manager/flake.nix + local flake_file="$DOTFILES_DIR/config/home-manager/flake.nix" + sed -i "s/homeConfigurations = {/homeConfigurations = { $flake_config/g" "$flake_file" - # Validate flake.nix with nixfmt - nix-shell -p nixfmt --run "nixfmt $HOME/dotfiles/config/home-manager/flake.nix" - - if [ $? -ne 0 ]; then - tput setaf 1 - echo "Something went wrong adding the flake configuration for Home Manager." - echo "Failed to validate flake.nix. Exiting..." - tput sgr0 - exit 1 - fi - - tput setaf 2 - echo "Home Manager Flake configuration added successfully." - tput sgr0 - - - # Add to git - git add $HOME/dotfiles/config/nixos/hardware/$hostname.nix $HOME/dotfiles/config/nixos/flake.nix $HOME/dotfiles/config/home-manager/flake.nix - - tput setaf 3 - echo "" - echo "Don't forget to commit and push the changes to the dotfiles repo after testing." - tput sgr0 - - git status - echo "" + # Validate flake.nix + nix-shell -p nixfmt --run "nixfmt $flake_file" || return 1 + log_success "Home Manager Flake configuration added successfully." } install_nix() { - if [ -x "$(command -v nixos-version)" ]; then - tput setaf 2 - echo "Detected NixOS, skipping Nix setup." - tput sgr0 - return - else - tput setaf 3 - echo "NixOS not detected, installing Nix..." - tput sgr0 - sh <(curl -L https://nixos.org/nix/install) --daemon + if command -v nixos-version >/dev/null 2>&1; then + log_success "Detected NixOS, skipping Nix setup." + return 0 + fi - if [ $? -ne 0 ]; then - tput setaf 1 - echo "Failed to install Nix. Exiting..." - tput sgr0 - exit 1 - fi + log_info "NixOS not detected, installing Nix..." + if ! sh <(curl -L https://nixos.org/nix/install) --daemon; then + die "Failed to install Nix" fi } -clear_files() { - tput setaf 3 - echo "Setting up symlinks..." - tput sgr0 +setup_symlinks() { + log_info "Setting up symlinks..." - # Link .bashrc - if [ -f $HOME/.bashrc ]; then - echo "Backing up $HOME/.bashrc to $HOME/.bashrc.bak..." - mv $HOME/.bashrc $HOME/.bashrc.bak + # Backup and create symlinks + backup_file "$HOME/.bashrc" + backup_file "$HOME/.profile" + + if [ -d "$HOME/.config/home-manager" ]; then + log_info "Backing up ~/.config/home-manager to ~/.config/home-manager.bak..." + mv "$HOME/.config/home-manager" "$HOME/.config/home-manager.bak" || \ + die "Failed to backup home-manager config" fi - # Link proper home-manager configs - if [ -d ~/.config/home-manager ]; then - echo "Backing up ~/.config/home-manager to ~/.config/home-manager.bak..." - mv ~/.config/home-manager ~/.config/home-manager.bak - fi - echo "Linking ~/.config/home-manager to $HOME/dotfiles/config/home-manager..." - ln -s $HOME/dotfiles/config/home-manager ~/.config/home-manager + log_info "Linking ~/.config/home-manager to $DOTFILES_DIR/config/home-manager..." + ln -s "$DOTFILES_DIR/config/home-manager" "$HOME/.config/home-manager" || \ + die "Failed to create home-manager symlink" - # Link proper nixos configs - if [ -d /etc/nixos ]; then - echo "Backing up /etc/nixos/configuration.nix to /etc/nixos/configuration.nix.bak..." - sudo mv /etc/nixos/configuration.nix /etc/nixos/configuration.nix.bak + if [ -d "/etc/nixos" ]; then + backup_file "/etc/nixos/configuration.nix" fi - echo "Linking /etc/nixos/configuration.nix to $HOME/dotfiles/config/nixos/configuration.nix..." - sudo ln -s $HOME/dotfiles/config/nixos/configuration.nix /etc/nixos/configuration.nix - # Confirm paths are now proper symlinks - if [ -L ~/.config/home-manager ] && [ -L /etc/nixos/configuration.nix ]; then - # Confirm .bashrc and .profile are no longer present to prevent conflicts in nixoos-rebuild/home-manager switch - if [ ! -f $HOME/.bashrc ] && [ ! -f $HOME/.profile ]; then - tput setaf 2 - echo "Symlinks set up successfully." - tput sgr0 - else - tput setaf 1 - echo "Failed to set up symlinks. Exiting..." - tput sgr0 - exit 1 - fi - else - tput setaf 1 - echo "Failed to set up symlinks. Exiting..." - tput sgr0 - exit 1 - fi + log_info "Linking /etc/nixos/configuration.nix to $DOTFILES_DIR/config/nixos/configuration.nix..." + sudo ln -s "$DOTFILES_DIR/config/nixos/configuration.nix" "/etc/nixos/configuration.nix" || \ + die "Failed to create nixos configuration symlink" + + # Verify symlinks + confirm_symlink "$HOME/.config/home-manager" "Failed to set up home-manager symlink" + confirm_symlink "/etc/nixos/configuration.nix" "Failed to set up nixos configuration symlink" + + log_success "Symlinks set up successfully." } install_home_manager() { - if [ -x "$(command -v home-manager)" ]; then - tput setaf 2 - echo "Home Manager already installed. Skipping..." - tput sgr0 - return + if command -v home-manager >/dev/null 2>&1; then + log_success "Home Manager already installed. Skipping..." + return 0 fi - tput setaf 3 - echo "Installing Home Manager..." - tput sgr0 - - sudo nix-channel --add https://github.com/nix-community/home-manager/archive/release-$NIXOS_RELEASE.tar.gz home-manager - sudo nix-channel --update - sudo nix-shell '' -A install - nix-shell '' -A install - - if [ $? -ne 0 ]; then - tput setaf 1 - echo "Failed to install Home Manager. Exiting..." - tput sgr0 - exit 1 - fi + log_info "Installing Home Manager..." + + sudo nix-channel --add "https://github.com/nix-community/home-manager/archive/release-$NIXOS_RELEASE.tar.gz" home-manager || \ + die "Failed to add home-manager channel" + + sudo nix-channel --update || die "Failed to update channels" + + sudo nix-shell '' -A install || die "Failed to install home-manager (sudo)" + nix-shell '' -A install || die "Failed to install home-manager" } prepare_hostname() { - # Check if $HOME/.hostname exists, if skip hostname setup - if [ -f $HOME/.hostname ]; then - hostname=$(cat $HOME/.hostname) - tput setaf 2 - echo "Hostname already found in $HOME/.hostname. Using $hostname." - tput sgr0 + local hostname_file="$HOME/.hostname" + local hostname - # Check if config/nixos/hardware/ contains config/nixos/hardware/$hostname.nix - if [ ! -f $HOME/dotfiles/config/nixos/hardware/$hostname.nix ]; then - echo "No hardware configuration found for $hostname. Please create a hardware configuration for this machine." - exit 1 + if [ -f "$hostname_file" ]; then + hostname=$(cat "$hostname_file") + log_success "Hostname already found in $hostname_file. Using $hostname." + + if [ ! -f "$DOTFILES_DIR/config/nixos/hardware/$hostname.nix" ]; then + die "No hardware configuration found for $hostname. Please create a hardware configuration for this machine." fi - tput setaf 2 - echo "Hardware configuration found for $hostname. Continuing setup..." - tput sgr0 + log_success "Hardware configuration found for $hostname. Continuing setup..." return fi - # Ask the user what hostname this machine should have - tput setaf 3 - echo "Enter the hostname for this machine:" - tput sgr0 - read hostname - - # Validate hostname to ensure it's not empty, contains only alphanumeric characters, and is less than 64 characters - while [[ -z $hostname || ! $hostname =~ ^[a-zA-Z0-9_-]+$ || ${#hostname} -gt 64 ]]; do - echo "Invalid hostname. Please enter a valid hostname:" - read hostname + while true; do + log_info "Enter the hostname for this machine:" + read -r hostname + if validate_hostname "$hostname"; then + break + fi + log_error "Invalid hostname. Please enter a valid hostname:" done - # Check if config/nixos/hardware/ contains config/nixos/hardware/$hostname.nix - if [ ! -f $HOME/dotfiles/config/nixos/hardware/$hostname.nix ]; then - echo "No hardware configuration found for $hostname." - create_hardware_config $hostname - return - fi - - tput setaf 2 - echo "Hardware configuration found for $hostname. Continuing setup..." - tput sgr0 - - # Set the hostname by dumping it into $HOME/.hostname - touch $HOME/.hostname - echo $hostname > $HOME/.hostname - - # Confirm we saved the hostname to $HOME/.hostname - if [ -f $HOME/.hostname ] && [ $(cat $HOME/.hostname) == $hostname ]; then - tput setaf 2 - echo "Hostname set successfully." - tput sgr0 + if [ ! -f "$DOTFILES_DIR/config/nixos/hardware/$hostname.nix" ]; then + log_info "No hardware configuration found for $hostname." + create_hardware_config "$hostname" else - tput setaf 1 - echo "Failed to set hostname. Exiting..." - tput sgr0 - exit 1 + log_success "Hardware configuration found for $hostname. Continuing setup..." fi + + echo "$hostname" > "$hostname_file" || die "Failed to save hostname" + log_success "Hostname set successfully." } -prepare_hostname -clear_files -install_nix -install_home_manager +main() { + # Check if setup has already been run + if [ -f "$SETUP_MARKER" ]; then + log_info "Setup has already been run, exiting..." + exit 0 + fi -# Rebuild NixOS -cd $HOME/dotfiles/config/nixos && sudo nixos-rebuild switch --flake .#$hostname --impure -if [ $? -ne 0 ]; then - tput setaf 1 - echo "Failed to rebuild NixOS. Exiting..." - tput sgr0 - exit 1 -fi + # Check prerequisites + check_prerequisites -# Rebuild Home Manager -cd $HOME/dotfiles/config/home-manager && NIXPKGS_ALLOW_UNFREE=1 home-manager switch --flake .#$hostname --impure -if [ $? -ne 0 ]; then - tput setaf 1 - echo "Failed to rebuild Home Manager. Exiting..." - tput sgr0 - exit 1 -fi + # Clone dotfiles if needed + if [ ! -d "$DOTFILES_DIR" ]; then + log_info "Cloning dotfiles repo..." + git clone "$GIT_REPO" "$DOTFILES_DIR" || die "Failed to clone dotfiles repository" + fi -# Make .profile a symlink to .bashrc -if [ -f $HOME/.profile ]; then - echo "Backup up $HOME/.profile to $HOME/.profile.bak..." - mv $HOME/.profile $HOME/.profile.bak -fi + # Run setup steps + prepare_hostname + setup_symlinks + install_nix + install_home_manager -tput setaf 2 -echo -echo "Setup complete. Please logout / restart to continue with 'dotf update'." -echo -tput sgr0 + # Get hostname + local hostname + hostname=$(cat "$HOME/.hostname") || die "Failed to read hostname" -touch $HOME/.dotfiles-setup + # Rebuild NixOS + cd "$DOTFILES_DIR/config/nixos" || die "Failed to change to nixos config directory" + sudo nixos-rebuild switch --flake ".#$hostname" --impure || \ + die "Failed to rebuild NixOS" -tput setaf 1 -echo -echo "!!! Please logout / restart to continue !!!" -echo "~~~ Proceed by running 'dotf update' ~~~" -echo -tput sgr0 + # Rebuild Home Manager + cd "$DOTFILES_DIR/config/home-manager" || die "Failed to change to home-manager config directory" + NIXPKGS_ALLOW_UNFREE=1 home-manager switch --flake ".#$hostname" --impure || \ + die "Failed to rebuild Home Manager" + + # Create setup marker + touch "$SETUP_MARKER" || die "Failed to create setup marker" + + # Final success message + log_success "\nSetup complete. Please logout / restart to continue with 'dotf update'.\n" + log_error "\n!!! Please logout / restart to continue !!!" + log_error "~~~ Proceed by running 'dotf update' ~~~\n" +} + +main "$@"