#!/bin/bash # Color Utilities function green() { printf "\033[32m%s\033[0m\n\n" "$1"; } function orange() { printf "\033[38;5;208m%s\033[0m\n" "$1"; } function red() { printf "\033[91m%s\033[0m\n" "$1"; } function blue() { printf "\033[38;5;27m%s\033[0m\n" "$1"; } # Constants BACKUP_DIR="$HOME/backups" FILENAME="$BACKUP_DIR/$(date +%d_%m_%Y).tar" # Create backup directory if it doesn't exist function ensure_backup_dir() { if [[ ! -e "$BACKUP_DIR" ]]; then blue "Creating backup directory." mkdir -p "$BACKUP_DIR" fi } # Handle existing backup file function check_existing_backup() { if [[ -f "$FILENAME" ]]; then orange "$FILENAME already exists!" read -rp "Do you want to remove the existing backup file? (y/n) : " answer [[ $answer == 'y' ]] && rm "$FILENAME" || exit 1 fi } function generate_config_files() { green "Preparing iterm2 & brew config ..." local brew_file="$HOME/Brewfile" local iterm2_file="$HOME/iterm.itermexport" brew bundle dump --force --file="$brew_file" if [[ ! -f "$brew_file" ]]; then orange "$brew_file doesn't exist!" read -rp "Do you want to continue? (y/n): " answer [[ "$answer" == "y" ]] || exit 1 fi tar -rpf "$FILENAME" "$brew_file" if [[ ! -f "$iterm2_file" ]]; then orange "$iterm2_file doesn't exist!" read -rp "Do you want to continue? (y/n): " answer [[ "$answer" == "y" ]] || exit 1 fi tar -rpf "$FILENAME" "$iterm2_file" && rm "$iterm2_file" } # Backup dotfiles function backup_dotfiles() { green "Backing up dotfiles..." find "$HOME"/.* -maxdepth 0 -type f -exec tar -rpf "$FILENAME" {} + } # Exclude large config dirs and create gzipped archive of .config function backup_config_gz() { tar -rpf "$FILENAME" "$HOME/.config/git" tar -rpf "$FILENAME" "$HOME/.config/rclone" tar -rpf "$FILENAME" "$HOME/.config/telebit" tar -rpf "$FILENAME" "$HOME/.config/yarn/global/package.json" tar -rpf "$FILENAME" "$HOME/.gnupg/*.gpg" tar -rpf "$FILENAME" "$HOME/.gradle/gradle.properties" tar -rpf "$FILENAME" "$HOME/.android/debug.keystore" } # Append selected items to tar archive function backup_specific_items() { green "Backing up specific items..." tar -rpf "$FILENAME" --exclude=".git" "$HOME/.zsh" tar -rpf "$FILENAME" "$HOME/.ssh" tar -rpf "$FILENAME" $HOME/Library/LaunchAgents/local.* tar -rpf "$FILENAME" $HOME/Data/launchd/*/*.sh tar -rpf "$FILENAME" "$HOME/Library/Developer/Xcode/UserData/KeyBindings" tar -rpf "$FILENAME" --exclude="*.log" "$HOME/.aria2" tar -rpf "$FILENAME" /etc/hosts /etc/paths # tar -rpf "$FILENAME" /etc/postfix # tar -rpf "$FILENAME" /etc/apache2/**/*.conf } # Backup command output (defaults, crontab, brew list) function backup_system_state() { crontab -l >crontab.txt && tar -rpf "$FILENAME" crontab.txt && rm crontab.txt defaults read >defaults.txt && tar -rpf "$FILENAME" defaults.txt && rm defaults.txt brew list >homebrew.txt && tar -rpf "$FILENAME" homebrew.txt && rm homebrew.txt } # Append list of backed-up files function add_backup_log() { { echo "Save location: https://onedrive.live.com/?id=5FC8AF0024B02AE9%2118898&cid=5FC8AF0024B02AE9" echo -e "\n\nBackup List:\n" tar -tvf "$FILENAME" } >backup_log.txt tar -rpf "$FILENAME" backup_log.txt rm backup_log.txt } # Validate final backup size function validate_backup_size() { local size size_mb size=$(stat -f "%z" "$FILENAME") size_mb=$(echo "scale=2; $size / 1024 / 1024" | bc) blue "$FILENAME has size ${size_mb} MB" if [[ $size -gt 24000000 ]]; then red "Backup > 24 MB, aborting." exit 1 else green "Done!" fi } # === Main Execution === ensure_backup_dir check_existing_backup cd "$HOME" || exit 1 generate_config_files backup_dotfiles backup_config_gz backup_specific_items backup_system_state add_backup_log validate_backup_size exit 0 # Restore with: # sudo tar -xvf .tar -C / # brew bundle install --file=~/Brewfile