summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-09-03 10:25:08 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-09-03 10:25:08 +0900
commita92abe1eb0c6fb409e2d0f9b44695778988e7523 (patch)
tree86c24d8731cf422f014b5384ff02ddfa985baed1
parent3ee425cbed2b673ac90c2c86f241d7f2442032de (diff)
modified static/thesiah-mac.sh
-rwxr-xr-xstatic/thesiah-mac.sh397
1 files changed, 322 insertions, 75 deletions
diff --git a/static/thesiah-mac.sh b/static/thesiah-mac.sh
index d6cd90c..38f25ad 100755
--- a/static/thesiah-mac.sh
+++ b/static/thesiah-mac.sh
@@ -4,110 +4,253 @@
# Adaptation by: Soomin Im <si@thesiah.xyz>
# License: GNU GPLv3
+set -e # Exit on error
### VARIABLES ###
dotfilesrepo="https://github.com/TheSiahxyz/.dotfiles.git"
progsfile="thesiah.xyz/macprogs.csv"
repobranch="master"
+### ENVIRONMENT VARIABLES FOR NON-INTERACTIVE BREW ###
+export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
+export HOMEBREW_NO_INSTALL_CLEANUP=1
+export HOMEBREW_NO_AUTO_UPDATE=1
+export HOMEBREW_NO_ANALYTICS=1
+export HOMEBREW_NO_ENV_HINTS=1
### FUNCTIONS ###
+# Print formatted output
+print_header() {
+ echo "=================================================="
+ echo "$1"
+ echo "=================================================="
+}
+
+print_step() {
+ echo " -> $1"
+}
+
+print_success() {
+ echo " [OK] $1"
+}
+
+print_error() {
+ echo " [ERROR] $1" >&2
+}
+
+print_warning() {
+ echo " [WARNING] $1"
+}
+
+# Check if command exists
+command_exists() {
+ command -v "$1" >/dev/null 2>&1
+}
+
+# Check if directory exists and is writable
+check_directory() {
+ if [ ! -d "$1" ]; then
+ print_step "Creating directory: $1"
+ mkdir -p "$1" || error "Failed to create directory: $1"
+ fi
+
+ if [ ! -w "$1" ]; then
+ error "Directory is not writable: $1"
+ fi
+}
+
# Notify function using macOS's notification system
notify() {
- osascript -e "display notification \"$2\" with title \"$1\""
+ if command_exists osascript; then
+ osascript -e "display notification \"$2\" with title \"$1\"" 2>/dev/null || true
+ fi
}
# Error function for error handling and notification
error() {
- # Log to stderr and exit with failure.
- printf "%s\n" "$1" >&2
- exit 1
+ print_error "$1"
+ notify "Installation Failed" "$1"
+ exit 1
}
# Install Homebrew
brewinstall() {
- if ! command -v brew &>/dev/null; then
+ print_step "Checking Homebrew installation..."
+
+ if ! command_exists brew; then
+ print_step "Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+
+ # Add Homebrew to PATH for Apple Silicon Macs
+ if [ -f "/opt/homebrew/bin/brew" ]; then
+ eval "$(/opt/homebrew/bin/brew shellenv)"
+ elif [ -f "/usr/local/bin/brew" ]; then
+ eval "$(/usr/local/bin/brew shellenv)"
+ fi
+
+ # Verify brew is now available
+ if ! command_exists brew; then
+ error "Homebrew installation failed - brew command not found"
+ fi
+ else
+ print_success "Homebrew already installed"
fi
- brew update >/dev/null 2>&1
- brew upgrade >/dev/null 2>&1
- eval "$(/opt/homebrew/bin/brew shellenv)"
+
+ print_step "Updating Homebrew..."
+ brew update >/dev/null 2>&1 || print_warning "Homebrew update failed, continuing..."
+ brew upgrade >/dev/null 2>&1 || print_warning "Homebrew upgrade failed, continuing..."
}
-# Install Homebrew packages
+# Install Homebrew packages with non-interactive flags
installpkg() {
- if brew list "$1" | grep "$1" &>/dev/null; then
- echo "$1 is already installed."
- else
- echo "Installing $1..."
- brew install "$1" || error "Failed to install $1."
- fi
+ pkg="$1"
+ if brew list "$pkg" >/dev/null 2>&1; then
+ print_success "$pkg already installed"
+ else
+ print_step "Installing $pkg..."
+ # Use non-interactive flags to prevent user input prompts
+ brew install --force-bottle --no-quarantine "$pkg" 2>/dev/null || \
+ brew install "$pkg" || error "Failed to install $pkg"
+ print_success "$pkg installed successfully"
+ fi
}
# Install Homebrew Cask applications
caskinstall() {
- if brew list --cask "$1" | grep "$1" &>/dev/null; then
- echo "$1 is already installed."
- else
- echo "Installing $1..."
- brew install --cask "$1" || error "Failed to install $1."
- fi
+ pkg="$1"
+ if brew list --cask "$pkg" >/dev/null 2>&1; then
+ print_success "$pkg already installed"
+ else
+ print_step "Installing $pkg..."
+ # Use non-interactive flags for cask installations
+ brew install --cask --force --no-quarantine "$pkg" 2>/dev/null || \
+ brew install --cask "$pkg" || error "Failed to install $pkg"
+ print_success "$pkg installed successfully"
+ fi
}
# Install Python packages with pip
pipinstall() {
- echo "Installing the Python package: $1"
- if ! command -v pip3 &>/dev/null; then
- installpkg python # This installs pip3
- fi
- pip3 install "$1" || error "Failed to install Python package $1."
+ pkg="$1"
+ print_step "Installing Python package: $pkg"
+
+ if ! command_exists pip3; then
+ print_step "Installing Python (includes pip3)..."
+ installpkg python
+ fi
+
+ # Use --quiet flag to prevent pip from asking questions
+ pip3 install --quiet "$pkg" || error "Failed to install Python package $pkg"
+ print_success "$pkg installed successfully"
}
# Install Homebrew Tap packages
tapinstall() {
- # Extract the repository and package name
repo=$(echo "$1" | cut -d'/' -f1)
pkg=$(echo "$1" | cut -d'/' -f2)
- echo "Adding tap: $repo"
- brew tap "$repo" || error "Failed to tap $repo."
+ print_step "Adding tap: $repo"
+ brew tap "$repo" || error "Failed to tap $repo"
- echo "Installing package: $pkg from tap"
- brew install "$pkg" || error "Failed to install $pkg from tap."
+ print_step "Installing package: $pkg from tap"
+ # Use non-interactive flags for tap packages too
+ brew install --force-bottle --no-quarantine "$pkg" 2>/dev/null || \
+ brew install "$pkg" || error "Failed to install $pkg from tap"
+ print_success "$pkg installed successfully"
}
# Install mac apps with mas
masinstall() {
- echo "Installing the mac app: $1"
+ app_name="$1"
+ print_step "Installing Mac App Store app: $app_name"
- # Search for the app by name and get its ID using awk to parse the output
- id=$(mas search "$1" | awk -v appName="$1" '{if ($0 ~ appName) {print $1; exit}}')
- # Check if the id variable is set and not empty
+ # Search for the app by name and get its ID
+ id=$(mas search "$app_name" | awk -v appName="$app_name" '
+ tolower($0) ~ tolower(appName) {
+ print $1;
+ exit
+ }
+ ')
+
if [ -z "$id" ]; then
- error "Failed to find an ID for the app named $1."
+ error "Failed to find an ID for the app named $app_name"
else
- mas install "$id" || error "Failed to install the app $1."
+ print_step "Installing app ID: $id"
+ mas install "$id" || error "Failed to install the app $app_name"
+ print_success "$app_name installed successfully"
fi
}
# Clone and setup dotfiles
putgitrepo() {
- notify "Installation" "Downloading and installing config files..."
- dir=$(mktemp -d)
- if [ ! -d "$2" ]; then
- mkdir -p "$2"
- fi
- git clone --depth 1 --single-branch --no-tags -q --recursive -b "${3:-$repobranch}" "$1" "$dir" || error "Failed to clone $1."
- cp -Rf "$dir/"* "$2"
- rm -rf "$dir" # Clean up
+ repo="$1"
+ target="$2"
+ branch="${3:-$repobranch}"
+
+ print_step "Downloading and installing config files..."
+ notify "Installation" "Downloading and installing config files..."
+
+ # Check if git is available
+ if ! command_exists git; then
+ error "Git is not installed. Please install git first."
+ fi
+
+ # Check target directory
+ check_directory "$target"
+
+ dir=$(mktemp -d)
+
+ print_step "Cloning repository: $repo"
+ git clone --depth 1 --single-branch --no-tags -q --recursive -b "$branch" "$repo" "$dir" || \
+ error "Failed to clone $repo"
+
+ print_step "Copying files to target directory"
+ cp -Rf "$dir/"* "$target" 2>/dev/null || true
+ rm -rf "$dir"
+ print_success "Config files installed successfully"
}
# Installation loop for processing the programs.csv file
installationloop() {
- ([ -f "$progsfile" ] && cp "$progsfile" /tmp/programs.csv) || curl -Ls "$progsfile" | sed '/^#/d' >/tmp/programs.csv || error "Failed to download programs file."
+ csv_file="/tmp/programs.csv"
+
+ print_header "Installing Software Packages"
+
+ # Download programs file
+ if [ -f "$progsfile" ]; then
+ print_step "Using local programs file: $progsfile"
+ cp "$progsfile" "$csv_file"
+ else
+ print_step "Downloading programs list from: $progsfile"
+ if ! curl -Ls "$progsfile" | sed '/^#/d' > "$csv_file"; then
+ error "Failed to download programs file from $progsfile"
+ fi
+
+ # Verify file was downloaded and has content
+ if [ ! -s "$csv_file" ]; then
+ error "Downloaded programs file is empty"
+ fi
+ fi
+
+ # Count total packages for progress
+ total_packages=$(wc -l < "$csv_file" 2>/dev/null | tr -d ' ' || echo "0")
+ if [ "$total_packages" -eq 0 ]; then
+ error "No packages found in programs file"
+ fi
+
+ current=0
+
while IFS=, read -r tag program comment; do
- echo "$comment"
+ # Skip empty lines
+ if [ -z "$tag" ] || [ -z "$program" ]; then
+ continue
+ fi
+
+ current=$((current + 1))
+ echo ""
+ print_step "[$current/$total_packages] $comment"
+
case "$tag" in
"P") pipinstall "$program" ;;
"C") caskinstall "$program" ;;
@@ -115,39 +258,143 @@ installationloop() {
"T") tapinstall "$program" ;;
*) installpkg "$program" ;;
esac
- done </tmp/programs.csv
+ done < "$csv_file"
+
+ rm -f "$csv_file"
+ print_success "All packages installed successfully"
}
-finalize() {
- # Farewell
- echo "All done!"
- echo "Congrats! Provided there were no hidden errors, the script completed successfully and all the programs and configuration files should be in place.\\n\\n.t Soomin"
+# Setup shell configuration
+setup_shell() {
+ print_header "Setting up Shell Configuration"
+
+ print_step "Creating symbolic links for shell configs..."
+
+ # Create backup of existing configs
+ timestamp=$(date +%Y%m%d_%H%M%S)
+
+ [ -f ~/.zprofile ] && mv ~/.zprofile ~/.zprofile.backup.$timestamp
+ [ -f ~/.bash_profile ] && mv ~/.bash_profile ~/.bash_profile.backup.$timestamp
+ [ -f ~/.bashrc ] && mv ~/.bashrc ~/.bashrc.backup.$timestamp
+
+ # Create new symbolic links
+ ln -sf ~/.dotfiles/mac/.config/shell/profile ~/.zprofile
+ ln -sf ~/.dotfiles/mac/.config/bash/bash_profile ~/.bash_profile
+ ln -sf ~/.dotfiles/mac/.config/bash/bashrc ~/.bashrc
+
+ print_success "Shell configuration setup completed"
}
-### Main Installation Process ###
-# Ensure Homebrew is installed
-brewinstall || error "Failed to install Homebrew."
-
-# Ensure mas is installed
-installpkg "mas"
-
-# Start the installation loop for software from the CSV
-installationloop
-
-# Setup Dotfiles
-putgitrepo "$dotfilesrepo" "$HOME" "$repobranch" && mv "$HOME/$(echo "$dotfilesrepo" | sed 's|.*/\([^/]*\)\.git|\1|')" "$HOME/.dotfiles"
-
-# Sync profile
-ln -sf ~/.dotfiles/mac/.config/shell/profile ~/.zprofile
-ln -sf ~/.dotfiles/mac/.config/bash/bash_profile ~/.bash_profile
-ln -sf ~/.dotfiles/mac/.config/bash/bashrc ~/.bashrc
+# Setup dotfiles with stow
+setup_dotfiles() {
+ print_header "Setting up Dotfiles"
+
+ print_step "Installing dotfiles with stow..."
+
+ # Check if stow is available
+ if ! command_exists stow; then
+ print_warning "Stow not found, installing..."
+ installpkg stow
+ fi
+
+ # Check if dotfiles directory exists
+ if [ ! -d ~/.dotfiles ]; then
+ error "Dotfiles directory not found: ~/.dotfiles"
+ fi
+
+ cd ~/.dotfiles || error "Failed to change to dotfiles directory"
+
+ # Install global configurations
+ print_step "Installing global configurations..."
+ if [ -d "global" ]; then
+ stow --no-folding -S global || error "Failed to stow global configs"
+ else
+ print_warning "Global configs directory not found, skipping..."
+ fi
+
+ # Install macOS specific configurations
+ print_step "Installing macOS specific configurations..."
+ if [ -d "mac" ]; then
+ stow --no-folding -S mac || error "Failed to stow mac configs"
+ else
+ print_warning "Mac configs directory not found, skipping..."
+ fi
+
+ cd - > /dev/null
+ print_success "Dotfiles setup completed"
+}
-cd ~/.dotfiles
+# Finalize installation
+finalize() {
+ print_header "Installation Complete!"
+ echo ""
+ echo "Congratulations! The installation has completed successfully."
+ echo ""
+ echo "What was installed:"
+ echo " - Homebrew and essential packages"
+ echo " - Mac App Store applications"
+ echo " - Python packages"
+ echo " - Shell configuration files"
+ echo " - Dotfiles and system configurations"
+ echo ""
+ echo "Next steps:"
+ echo " - Restart your terminal or run: source ~/.zprofile"
+ echo " - Customize your configuration files in ~/.dotfiles"
+ echo " - Install additional packages as needed"
+ echo ""
+ echo "For support, visit: https://github.com/TheSiahxyz/.dotfiles"
+ echo ""
+ echo "Best regards,"
+ echo "Soomin"
+ echo ""
+
+ notify "Installation Complete" "THESIAH setup finished successfully!"
+}
-stow --no-folding -S global
-stow --no-folding -S mac
+### MAIN INSTALLATION PROCESS ###
-cd -
+main() {
+ print_header "THESIAH - macOS Auto Setup Script"
+ echo "Starting installation process..."
+ echo ""
+
+ # Check if running on macOS
+ if [ "$(uname)" != "Darwin" ]; then
+ error "This script is designed for macOS only"
+ fi
+
+ # Check if running as root
+ if [ "$(id -u)" -eq 0 ]; then
+ error "This script should not be run as root"
+ fi
+
+ # Ensure Homebrew is installed
+ brewinstall || error "Failed to install Homebrew"
+
+ # Ensure mas is installed
+ installpkg "mas"
+
+ # Start the installation loop for software from the CSV
+ installationloop
+
+ # Setup Dotfiles
+ putgitrepo "$dotfilesrepo" "$HOME" "$repobranch"
+
+ # Move dotfiles to proper location
+ dotfiles_dir=$(basename "$dotfilesrepo" .git)
+ if [ -d "$HOME/$dotfiles_dir" ]; then
+ mv "$HOME/$dotfiles_dir" "$HOME/.dotfiles"
+ fi
+
+ # Setup shell configuration
+ setup_shell
+
+ # Setup dotfiles with stow
+ setup_dotfiles
+
+ # Finalize
+ finalize
+}
-# Final
-finalize
+# Run main function
+main "$@"