Files
dotfiles/scripts/setup_enterprise_ai_bash.sh
2026-02-23 12:49:59 -06:00

411 lines
14 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -euo pipefail
echo "🚀 Setting up Enterprise + AI Development Environment (Bash Edition)"
echo
HOME_DIR="$HOME"
BASHRC="$HOME_DIR/.bashrc"
BASH_PROFILE="$HOME_DIR/.bash_profile"
# Dotfiles remote — your local Gitea server
DOTFILES_REMOTE="http://172.27.0.35:3000/kenjim/dotfiles"
DOTFILES_DIR="$HOME_DIR/dotfiles"
# ------------------------------------------------------
# 0⃣ MACHINE PROFILE SELECTION
# ------------------------------------------------------
# Override: MACHINE_PROFILE=work ./setup_enterprise_ai_bash.sh
# MACHINE_PROFILE=personal ./setup_enterprise_ai_bash.sh
MACHINE_PROFILE="${MACHINE_PROFILE:-}"
if [[ -z "$MACHINE_PROFILE" ]]; then
echo "Select machine profile:"
echo " [1] work — OneDrive cloud, work workspace"
echo " [2] personal — ProtonDrive + GoogleDrive, personal workspace"
echo
read -r -p "Profile (1=work / 2=personal) [2]: " _choice
case "${_choice:-2}" in
1|work) MACHINE_PROFILE="work" ;;
2|personal) MACHINE_PROFILE="personal" ;;
*) MACHINE_PROFILE="personal" ;;
esac
fi
export MACHINE_PROFILE
echo " ▶ Profile: $MACHINE_PROFILE"
echo
# Derive hostname tag used to tag commits
MACHINE_TAG="$(hostname -s)-${MACHINE_PROFILE}"
# ------------------------------------------------------
# 1⃣ CREATE DIRECTORY STRUCTURE
# ------------------------------------------------------
echo "📁 Creating directory structure..."
mkdir -p "$HOME_DIR/workspace/src/"{personal,work,research}
mkdir -p "$HOME_DIR/workspace/"{experiments,notebooks,sandboxes,archive}
mkdir -p "$HOME_DIR/data/"{raw,processed,embeddings,synthetic}
mkdir -p "$HOME_DIR/models/"{huggingface,ollama,fine-tuned}
mkdir -p "$HOME_DIR/infra/"{docker,terraform,scripts}
mkdir -p "$HOME_DIR/ops"
mkdir -p "$HOME_DIR/scripts"
mkdir -p "$HOME_DIR/vault"
mkdir -p "$HOME_DIR/dotfiles"
mkdir -p "$HOME_DIR/dotfiles/.ssh/keys"
# Profile-specific cloud directories
if [[ "$MACHINE_PROFILE" == "work" ]]; then
# OneDrive is managed by the Microsoft OneDrive app and auto-mounts at:
# ~/Library/CloudStorage/OneDrive-<OrgName>/ (modern macOS)
# We create a stable symlink at ~/OneDrive for convenience.
ONEDRIVE_MOUNT=$(find "$HOME_DIR/Library/CloudStorage" -maxdepth 1 -iname 'OneDrive*' -type d 2>/dev/null | head -1 || true)
if [[ -n "$ONEDRIVE_MOUNT" ]]; then
ln -sfn "$ONEDRIVE_MOUNT" "$HOME_DIR/OneDrive" 2>/dev/null || true
echo " Linked ~/OneDrive → $ONEDRIVE_MOUNT"
else
mkdir -p "$HOME_DIR/OneDrive"
echo " Created ~/OneDrive placeholder (link manually once OneDrive app is signed in)"
fi
else
# Personal machine: ProtonDrive + Google Drive
mkdir -p "$HOME_DIR/Cloud/"{ProtonDrive,GoogleDrive}
fi
echo "✅ Directories created."
echo
# ------------------------------------------------------
# 2⃣ ENSURE .bash_profile LOADS .bashrc (macOS FIX)
# ------------------------------------------------------
if ! grep -q "source ~/.bashrc" "$BASH_PROFILE" 2>/dev/null; then
cat <<'EOF' >> "$BASH_PROFILE"
# Load .bashrc if it exists
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
EOF
echo "✅ .bash_profile updated to load .bashrc"
fi
# ------------------------------------------------------
# 3⃣ ADD ENTERPRISE AI ENV VARIABLES
# ------------------------------------------------------
if ! grep -q "### ENTERPRISE_AI_ENV ###" "$BASHRC" 2>/dev/null; then
cat <<'EOF' >> "$BASHRC"
### ENTERPRISE_AI_ENV ###
export WORKSPACE="$HOME/workspace"
export DATA_ROOT="$HOME/data"
export MODEL_ROOT="$HOME/models"
# HuggingFace cache location
export HF_HOME="$MODEL_ROOT/huggingface"
# Ollama model location
export OLLAMA_MODELS="$MODEL_ROOT/ollama"
# Convenience aliases
alias ws='cd $WORKSPACE'
alias src='cd $WORKSPACE/src'
alias data='cd $DATA_ROOT'
alias models='cd $MODEL_ROOT'
# Machine-local overrides (cloud paths, work vs personal — not synced via dotfiles)
[ -f ~/.bashrc.local ] && source ~/.bashrc.local
EOF
echo "✅ Environment variables added to .bashrc"
else
# Ensure .bashrc.local sourcing is present even on existing installs
if ! grep -q ".bashrc.local" "$BASHRC" 2>/dev/null; then
cat >> "$BASHRC" <<'LOCALEOF'
# Machine-local overrides (cloud paths, work vs personal — not synced via dotfiles)
[ -f ~/.bashrc.local ] && source ~/.bashrc.local
LOCALEOF
echo "✅ Added .bashrc.local sourcing to existing .bashrc"
fi
echo " Environment already configured."
fi
# ---- Write machine-specific .bashrc.local (never committed to dotfiles) ----
BASHRC_LOCAL="$HOME_DIR/.bashrc.local"
# Preserve any existing custom content below the managed block
LOCAL_CUSTOM=""
if [ -f "$BASHRC_LOCAL" ] && grep -q "### MACHINE_LOCAL_END ###" "$BASHRC_LOCAL" 2>/dev/null; then
LOCAL_CUSTOM=$(awk '/### MACHINE_LOCAL_END ###/{found=1; next} found{print}' "$BASHRC_LOCAL")
fi
cat > "$BASHRC_LOCAL" <<LOCALEOF
### MACHINE_LOCAL — managed by setup_enterprise_ai_bash.sh — DO NOT SYNC ###
# Profile : ${MACHINE_PROFILE}
# Host : $(hostname -s)
# Generated: $(date)
export MACHINE_PROFILE="${MACHINE_PROFILE}"
export MACHINE_HOST="$(hostname -s)"
LOCALEOF
if [[ "$MACHINE_PROFILE" == "work" ]]; then
cat >> "$BASHRC_LOCAL" <<'WORKEOF'
# --- Work / OneDrive ---
export CLOUD_ROOT="$HOME/OneDrive"
export ONEDRIVE_ROOT="$HOME/OneDrive"
alias cloud='cd $CLOUD_ROOT'
alias onedrive='cd $ONEDRIVE_ROOT'
WORKEOF
else
cat >> "$BASHRC_LOCAL" <<'PERSONALEOF'
# --- Personal / ProtonDrive + Google Drive ---
export CLOUD_ROOT="$HOME/Cloud"
export PROTON_ROOT="$HOME/Cloud/ProtonDrive"
export GDRIVE_ROOT="$HOME/Cloud/GoogleDrive"
alias cloud='cd $CLOUD_ROOT'
alias proton='cd $PROTON_ROOT'
alias gdrive='cd $GDRIVE_ROOT'
PERSONALEOF
fi
cat >> "$BASHRC_LOCAL" <<'TAILEOF'
### MACHINE_LOCAL_END ###
TAILEOF
# Re-append any custom content that was below the managed block
if [[ -n "$LOCAL_CUSTOM" ]]; then
echo "$LOCAL_CUSTOM" >> "$BASHRC_LOCAL"
fi
echo "✅ .bashrc.local written for profile: $MACHINE_PROFILE"
# ------------------------------------------------------
# 4⃣ INITIALIZE DOTFILES REPO (with Gitea remote)
# ------------------------------------------------------
echo "📦 Setting up dotfiles repo..."
# Copy the dotfiles manager into scripts/ if it isn't already there
SCRIPTS_DIR="$HOME_DIR/scripts"
DFM="$SCRIPTS_DIR/dotfiles_manager.sh"
if [ ! -f "$DFM" ]; then
SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "$SELF_DIR/dotfiles_manager.sh" ]; then
cp "$SELF_DIR/dotfiles_manager.sh" "$DFM"
chmod +x "$DFM"
echo "✅ dotfiles_manager.sh copied to $DFM"
else
echo "⚠️ dotfiles_manager.sh not found next to this script — skipping copy."
fi
fi
# Run init via the manager (handles clone-or-init and remote setup)
if [ -f "$DFM" ]; then
DOTFILES_DIR="$DOTFILES_DIR" DOTFILES_REMOTE="$DOTFILES_REMOTE" bash "$DFM" init
else
# Minimal fallback if manager isn't available
cd "$DOTFILES_DIR"
if [ ! -d ".git" ]; then
git init
git remote add origin "$DOTFILES_REMOTE"
echo ".DS_Store" > .gitignore
touch README.md
git add .
git commit -m "Initial dotfiles commit"
echo "✅ Dotfiles repo initialized."
else
echo " Dotfiles repo already exists."
fi
fi
echo
# ------------------------------------------------------
# 5⃣ ADD DOTFILES ALIASES TO .bashrc
# ------------------------------------------------------
if ! grep -q "### DOTFILES_ALIASES ###" "$BASHRC" 2>/dev/null; then
cat >> "$BASHRC" <<BASHEOF
### DOTFILES_ALIASES ###
export DOTFILES_DIR="\$HOME/dotfiles"
export DOTFILES_REMOTE="$DOTFILES_REMOTE"
# Dotfiles manager shortcut
alias dotfiles='bash \$HOME/scripts/dotfiles_manager.sh'
alias dot='bash \$HOME/scripts/dotfiles_manager.sh'
# Quick sync alias
alias dots-sync='bash \$HOME/scripts/dotfiles_manager.sh sync'
alias dots-push='bash \$HOME/scripts/dotfiles_manager.sh push'
alias dots-status='bash \$HOME/scripts/dotfiles_manager.sh status'
BASHEOF
echo "✅ Dotfiles aliases added to .bashrc"
else
echo " Dotfiles aliases already configured."
fi
# ------------------------------------------------------
# 6⃣ CREATE MACHINE BOOTSTRAP SCRIPT
# ------------------------------------------------------
cat <<'EOF' > "$HOME_DIR/scripts/bootstrap.sh"
#!/usr/bin/env bash
# bootstrap.sh — Restore Enterprise AI Environment on this machine
set -euo pipefail
echo "🔄 Restoring Enterprise AI Environment..."
# Reload shell config
# shellcheck disable=SC1091
[ -f ~/.bashrc ] && source ~/.bashrc
[ -f ~/.bash_profile ] && source ~/.bash_profile
echo " WORKSPACE : ${WORKSPACE:-not set}"
echo " DATA_ROOT : ${DATA_ROOT:-not set}"
echo " MODEL_ROOT : ${MODEL_ROOT:-not set}"
echo
# Sync latest dotfiles from git server
if [ -f "$HOME/scripts/dotfiles_manager.sh" ]; then
echo "📦 Syncing dotfiles..."
bash "$HOME/scripts/dotfiles_manager.sh" sync
else
echo "⚠️ dotfiles_manager.sh not found — run setup_enterprise_ai_bash.sh first."
fi
echo
echo "✅ Bootstrap complete."
EOF
chmod +x "$HOME_DIR/scripts/bootstrap.sh"
echo "✅ Bootstrap script created at ~/scripts/bootstrap.sh"
# ------------------------------------------------------
# 7⃣ INITIAL DOTFILES MIGRATION (interactive)
# ------------------------------------------------------
echo
read -p "Migrate critical shell & config files into dotfiles repo now? (y/n): " MIGRATE_NOW
if [[ "$MIGRATE_NOW" == "y" ]] && [ -f "$DFM" ]; then
echo
echo "📂 Tracking shell config files..."
# .bashrc.local is machine-specific — never track it in dotfiles
TRACK_FILES=()
[ -f "$BASHRC" ] && TRACK_FILES+=("$BASHRC")
[ -f "$BASH_PROFILE" ] && TRACK_FILES+=("$BASH_PROFILE")
[ -f "$HOME_DIR/.bash_aliases" ] && TRACK_FILES+=("$HOME_DIR/.bash_aliases")
[ -f "$HOME_DIR/.inputrc" ] && TRACK_FILES+=("$HOME_DIR/.inputrc")
[ -f "$HOME_DIR/.gitconfig" ] && TRACK_FILES+=("$HOME_DIR/.gitconfig")
[ -f "$HOME_DIR/.vimrc" ] && TRACK_FILES+=("$HOME_DIR/.vimrc")
[ -f "$HOME_DIR/.tmux.conf" ] && TRACK_FILES+=("$HOME_DIR/.tmux.conf")
# Scripts — track so they are part of the dotfiles repo and re-bootstrap any machine
[ -f "$SCRIPTS_DIR/dotfiles_manager.sh" ] && TRACK_FILES+=("$SCRIPTS_DIR/dotfiles_manager.sh")
[ -f "$SCRIPTS_DIR/setup_enterprise_ai_bash.sh" ] && TRACK_FILES+=("$SCRIPTS_DIR/setup_enterprise_ai_bash.sh")
[ -f "$SCRIPTS_DIR/bootstrap.sh" ] && TRACK_FILES+=("$SCRIPTS_DIR/bootstrap.sh")
# NOTE: ~/.bashrc.local intentionally excluded — it is machine-specific
if [ ${#TRACK_FILES[@]} -gt 0 ]; then
DOTFILES_DIR="$DOTFILES_DIR" DOTFILES_REMOTE="$DOTFILES_REMOTE" \
bash "$DFM" add "${TRACK_FILES[@]}"
else
echo " No standard config files found to track."
fi
echo
read -p "Set up SSH config and keys now? (y/n): " DO_SSH
if [[ "$DO_SSH" == "y" ]]; then
DOTFILES_DIR="$DOTFILES_DIR" DOTFILES_REMOTE="$DOTFILES_REMOTE" \
bash "$DFM" ssh-setup
echo
read -p "GPG-encrypt and store private SSH keys in dotfiles? (y/n): " DO_EXPORT
if [[ "$DO_EXPORT" == "y" ]]; then
DOTFILES_DIR="$DOTFILES_DIR" DOTFILES_REMOTE="$DOTFILES_REMOTE" \
bash "$DFM" ssh-export
fi
fi
echo
read -p "Push initial dotfiles to $DOTFILES_REMOTE now? (y/n): " DO_PUSH
if [[ "$DO_PUSH" == "y" ]]; then
DOTFILES_DIR="$DOTFILES_DIR" DOTFILES_REMOTE="$DOTFILES_REMOTE" \
bash "$DFM" push "initial dotfiles migration from ${MACHINE_TAG}"
fi
else
echo " Skipped. Run manually:"
echo " dotfiles add ~/.bashrc ~/.bash_profile ~/.gitconfig"
echo " dotfiles ssh-setup"
echo " dotfiles push"
fi
# ------------------------------------------------------
# 8⃣ OPTIONAL TIME MACHINE EXCLUSIONS
# ------------------------------------------------------
echo
read -p "Exclude large AI folders from Time Machine? (y/n): " EXCLUDE_TM
if [[ "$EXCLUDE_TM" == "y" ]]; then
sudo tmutil addexclusion "$HOME_DIR/data/raw"
sudo tmutil addexclusion "$HOME_DIR/models"
echo "✅ Time Machine exclusions added."
else
echo " Skipped Time Machine exclusions."
fi
# ------------------------------------------------------
# DONE
# ------------------------------------------------------
# ------------------------------------------------------
# 9⃣ REMOTE BOOTSTRAP (optional)
# ------------------------------------------------------
echo
read -r -p "Bootstrap a remote machine over SSH now? (y/n): " DO_REMOTE
if [[ "$DO_REMOTE" == "y" ]] && [ -f "$DFM" ]; then
read -r -p "Remote target (user@host): " REMOTE_TARGET
read -r -p "Profile for remote machine (work/personal) [personal]: " REMOTE_PROFILE
REMOTE_PROFILE="${REMOTE_PROFILE:-personal}"
DOTFILES_DIR="$DOTFILES_DIR" DOTFILES_REMOTE="$DOTFILES_REMOTE" \
bash "$DFM" remote-bootstrap "$REMOTE_TARGET" --profile "$REMOTE_PROFILE"
else
echo " To bootstrap a remote machine later:"
echo " dotfiles remote-bootstrap user@hostname"
echo " dotfiles remote-bootstrap user@hostname --profile work"
fi
# ------------------------------------------------------
# DONE
# ------------------------------------------------------
echo
echo "🎉 Enterprise + AI Bash Environment Setup Complete!"
echo " Profile : $MACHINE_PROFILE"
echo " Host : $(hostname -s)"
echo
echo "👉 Run : source ~/.bash_profile"
echo "👉 Spaces : ws | src | data | models"
if [[ "$MACHINE_PROFILE" == "work" ]]; then
echo "👉 Cloud : onedrive"
else
echo "👉 Cloud : cloud | proton | gdrive"
fi
echo "👉 Dotfiles: dotfiles status"
echo "👉 Sync : dotfiles sync"
echo "👉 SSH keys: dotfiles ssh-setup (then: dotfiles ssh-export)"
echo "👉 Remote : dotfiles remote-bootstrap user@personal-mac"
echo "👉 Restore : git clone $DOTFILES_REMOTE ~/dotfiles && ~/dotfiles/install.sh"
echo