diff --git a/.claude/settings.json b/.claude/settings.json index ac9bb12..813b8d2 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -9,7 +9,8 @@ "env": { "ORION_PROJECT": "true", "TERRAFORM_LOG": "INFO", - "ANSIBLE_STDOUT_CALLBACK": "yaml" + "ANSIBLE_STDOUT_CALLBACK": "yaml", + "SHELL": "/bin/zsh" }, "permissions": { diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 10d6695..bafa707 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -461,6 +461,7 @@ make k8s-deploy - **[Helper Scripts Integration](docs/HELPER_SCRIPTS_INTEGRATION.md)** - LXC deployment guide - **[IPv6 Routing](docs/IPV6_ROUTING_INTEGRATION.md)** - BGP configuration - **[Claude Code Integration](docs/CLAUDE_CODE_INTEGRATION.md)** - AI-assisted development setup +- **[Development Environment](docs/DEVELOPMENT_ENVIRONMENT.md)** - Zsh, Oh My Zsh, Antigen setup - **[Architecture Review](ARCHITECTURE_REVIEW.md)** - AI engineering analysis --- diff --git a/README.md b/README.md index c4072d0..1ed30b5 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ make k8s-deploy # Deploy K8s workloads - πŸ€– **[Helper Scripts Integration](docs/HELPER_SCRIPTS_INTEGRATION.md)** - LXC deployment guide - 🌐 **[IPv6 Routing](docs/IPV6_ROUTING_INTEGRATION.md)** - BGP configuration - πŸ€– **[Claude Code Integration](docs/CLAUDE_CODE_INTEGRATION.md)** - AI-assisted development setup +- πŸ’» **[Development Environment](docs/DEVELOPMENT_ENVIRONMENT.md)** - Zsh, Oh My Zsh, Antigen setup - πŸ—οΈ **[Terraform Guide](terraform/README.md)** - Infrastructure deployment - πŸ“š **[Reference Docs](docs/reference/)** - Archived v1.0 documentation diff --git a/docs/DEVELOPMENT_ENVIRONMENT.md b/docs/DEVELOPMENT_ENVIRONMENT.md new file mode 100644 index 0000000..e191061 --- /dev/null +++ b/docs/DEVELOPMENT_ENVIRONMENT.md @@ -0,0 +1,596 @@ +# ORION Development Environment Setup + +**Complete guide for setting up Zsh, Oh My Zsh, Antigen, and Claude Code for ORION infrastructure development** + +--- + +## 🎯 Overview + +This guide covers the complete development environment setup for ORION infrastructure, including: + +1. **Zsh Shell** - Modern shell with powerful features +2. **Oh My Zsh** - Framework for managing Zsh configuration +3. **Antigen** - Plugin manager for Zsh +4. **zsh-users plugins** - Essential productivity plugins +5. **Claude Code Integration** - AI-assisted development with local server connectivity + +--- + +## πŸ“‹ Table of Contents + +1. [Quick Start](#quick-start) +2. [Zsh Installation](#zsh-installation) +3. [Plugin Configuration](#plugin-configuration) +4. [ORION-Specific Features](#orion-specific-features) +5. [Claude Code Local Server Setup](#claude-code-local-server-setup) +6. [SSH Tunneling for Remote Development](#ssh-tunneling-for-remote-development) +7. [Customization](#customization) +8. [Troubleshooting](#troubleshooting) + +--- + +## πŸš€ Quick Start + +### Automated Installation + +```bash +cd /home/user/luci-macOSX-PROXMOX/shell-config +./install-zsh.sh +``` + +This script will: +- βœ… Install Zsh +- βœ… Install Oh My Zsh +- βœ… Install Antigen +- βœ… Install zsh-users plugins +- βœ… Configure ORION-specific aliases and functions +- βœ… (Optional) Change your default shell to zsh + +--- + +## πŸ”§ Zsh Installation + +### What Gets Installed + +#### 1. **Zsh 5.9** - Modern Shell + +```bash +# Installed via apt/yum/dnf +zsh --version +# Output: zsh 5.9 (x86_64-ubuntu-linux-gnu) +``` + +#### 2. **Oh My Zsh** - Framework + +**URL**: https://github.com/ohmyzsh/ohmyzsh + +**Included Plugins**: +- `git` - Git aliases and functions +- `docker` - Docker completions and aliases +- `terraform` - Terraform completions +- `ansible` - Ansible completions +- `kubectl` - Kubernetes completions +- `helm` - Helm completions +- `sudo` - Double ESC to prepend sudo +- `command-not-found` - Suggests package for missing commands +- `history` - History management +- `z` - Jump to frequently used directories +- `colored-man-pages` - Colored man pages +- `extract` - Extract any archive with `extract ` +- `web-search` - Search from terminal (`google query`) + +#### 3. **Antigen** - Plugin Manager + +**URL**: https://github.com/zsh-users/antigen + +**Purpose**: Manages Zsh plugins from GitHub repositories + +#### 4. **zsh-users Plugins** + +**Repository**: https://github.com/orgs/zsh-users/repositories + +**Installed Plugins**: + +| Plugin | Purpose | Example | +|--------|---------|---------| +| **zsh-syntax-highlighting** | Fish-like syntax highlighting | Commands turn green when valid | +| **zsh-autosuggestions** | Fish-like autosuggestions | Shows gray suggestions from history | +| **zsh-completions** | Additional completions | More tab-completion options | +| **zsh-history-substring-search** | Better history search | Press ↑ to search history by substring | + +--- + +## 🎨 Plugin Configuration + +### zsh-autosuggestions + +**Features**: +- Suggests commands from history as you type +- Press `β†’` (right arrow) to accept suggestion +- Press `Ctrl+F` to accept word-by-word + +**Configuration**: +```bash +ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#6c757d" +ZSH_AUTOSUGGEST_STRATEGY=(history completion) +ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20 +``` + +### zsh-syntax-highlighting + +**Features**: +- Green: Valid command +- Red: Invalid command +- Magenta: Path +- Cyan: Alias + +**Color Scheme**: +```bash +ZSH_HIGHLIGHT_STYLES[command]='fg=green,bold' +ZSH_HIGHLIGHT_STYLES[alias]='fg=cyan,bold' +ZSH_HIGHLIGHT_STYLES[builtin]='fg=yellow,bold' +ZSH_HIGHLIGHT_STYLES[function]='fg=blue,bold' +ZSH_HIGHLIGHT_STYLES[path]='fg=magenta' +ZSH_HIGHLIGHT_STYLES[error]='fg=red,bold' +``` + +### zsh-history-substring-search + +**Keybindings**: +```bash +↑ / ↓ # Search history by substring +Ctrl+P / Ctrl+N # Alternative bindings +``` + +--- + +## πŸš€ ORION-Specific Features + +### Environment Variables + +```bash +ORION_ROOT="/home/user/luci-macOSX-PROXMOX" +TF_LOG="INFO" +TF_LOG_PATH="/tmp/terraform.log" +ANSIBLE_STDOUT_CALLBACK="yaml" +ANSIBLE_FORCE_COLOR=true +KUBECONFIG="$HOME/.kube/config" +``` + +### Navigation Aliases + +| Alias | Command | Description | +|-------|---------|-------------| +| `orion` | `cd $ORION_ROOT` | Jump to ORION root | +| `tf` | `cd $ORION_ROOT/terraform` | Jump to Terraform | +| `ans` | `cd $ORION_ROOT/ansible` | Jump to Ansible | +| `k8s` | `cd $ORION_ROOT/kubernetes` | Jump to Kubernetes | + +### Infrastructure Aliases + +#### Terraform +```bash +tfi # terraform init +tfp # terraform plan +tfa # terraform apply +tfd # terraform destroy +tfo # terraform output +tfs # terraform show +``` + +#### Ansible +```bash +ap # ansible-playbook +ai # ansible-inventory +ag # ansible-galaxy +``` + +#### Kubernetes +```bash +k # kubectl +kgp # kubectl get pods +kgs # kubectl get svc +kgn # kubectl get nodes +kd # kubectl describe +kl # kubectl logs +ke # kubectl exec -it +``` + +#### Docker +```bash +d # docker +dc # docker-compose +dps # docker ps +dim # docker images +``` + +#### Make +```bash +m # make +mh # make help +mdeploy # make deploy-full +mverify # make verify +``` + +### Custom Functions + +#### `deploy()` +Quick deployment of entire ORION stack + +```bash +deploy +# Output: πŸš€ Deploying ORION infrastructure... +# Runs: make deploy-full +``` + +#### `orion-status()` +Comprehensive status check + +```bash +orion-status +# Shows: +# - Git status +# - Terraform VMs +# - Kubernetes nodes +``` + +#### SSH Functions +```bash +ssh-router # SSH to VM 200 (Router) +ssh-coordinator # SSH to VM 300 (AI Coordinator) +ssh-netbox # SSH to VM 500 (NetBox) +ssh-k8s-master # SSH to VM 600 (K8s Master) +``` + +#### Proxmox Functions +```bash +proxmox-vms # List Proxmox VMs +proxmox-lxc # List Proxmox LXC containers +``` + +--- + +## 🌐 Claude Code Local Server Setup + +### Overview + +Claude Code can connect to your local ORION infrastructure server for dependency management, allowing you to: +- Run package managers remotely +- Execute infrastructure commands +- Access local services + +### Method 1: SSH Tunneling (Recommended) + +**Use Case**: Develop locally while executing commands on remote Proxmox host + +#### 1. Setup SSH Tunnel + +On your **local machine**: + +```bash +# SSH to Proxmox host with port forwarding +ssh -L 8006:192.168.1.100:8006 \ + -L 8000:192.168.100.50:8000 \ + -L 6443:192.168.100.60:6443 \ + root@your-proxmox-host.com +``` + +**Port Mapping**: +- `8006` β†’ Proxmox Web UI +- `8000` β†’ NetBox +- `6443` β†’ Kubernetes API + +#### 2. Configure Claude Code + +Add to `.claude/settings.local.json`: + +```json +{ + "env": { + "PROXMOX_API_URL": "https://localhost:8006/api2/json", + "NETBOX_URL": "http://localhost:8000", + "KUBECONFIG": "/path/to/local/kubeconfig" + } +} +``` + +#### 3. Update Terraform Variables + +```bash +# terraform/terraform.tfvars +pm_api_url = "https://localhost:8006/api2/json" +``` + +### Method 2: Direct Remote Execution + +**Use Case**: Execute commands directly on Proxmox host + +#### 1. Setup SSH Key Authentication + +On your **local machine**: + +```bash +# Generate SSH key (if not exists) +ssh-keygen -t ed25519 -C "orion-development" + +# Copy to Proxmox host +ssh-copy-id root@your-proxmox-host.com +``` + +#### 2. Configure Claude Code Remote Execution + +Add to `.claude/settings.json`: + +```json +{ + "hooks": { + "preBash": { + "enabled": true, + "command": "ssh root@proxmox-host.com 'cd /root/orion && {command}'", + "description": "Execute commands on remote Proxmox host" + } + } +} +``` + +### Method 3: VS Code Remote - SSH + +**Use Case**: Full remote development experience + +#### 1. Install VS Code Remote - SSH Extension + +```bash +code --install-extension ms-vscode-remote.remote-ssh +``` + +#### 2. Configure SSH Connection + +Add to `~/.ssh/config`: + +``` +Host orion-proxmox + HostName your-proxmox-host.com + User root + ForwardAgent yes + LocalForward 8006 192.168.1.100:8006 + LocalForward 8000 192.168.100.50:8000 + LocalForward 6443 192.168.100.60:6443 +``` + +#### 3. Connect to Remote Host + +```bash +# In VS Code: +# 1. Cmd/Ctrl + Shift + P +# 2. "Remote-SSH: Connect to Host" +# 3. Select "orion-proxmox" +``` + +--- + +## πŸ”Œ SSH Tunneling for Remote Development + +### Persistent SSH Tunnel with autossh + +#### Install autossh + +```bash +# Ubuntu/Debian +sudo apt-get install autossh + +# macOS +brew install autossh +``` + +#### Create Persistent Tunnel + +```bash +autossh -M 0 -f -N \ + -L 8006:192.168.1.100:8006 \ + -L 8000:192.168.100.50:8000 \ + -L 6443:192.168.100.60:6443 \ + -o "ServerAliveInterval 30" \ + -o "ServerAliveCountMax 3" \ + root@your-proxmox-host.com +``` + +#### Systemd Service (Linux) + +Create `/etc/systemd/system/orion-tunnel.service`: + +```ini +[Unit] +Description=ORION SSH Tunnel +After=network.target + +[Service] +Type=simple +User=youruser +ExecStart=/usr/bin/autossh -M 0 -N \ + -L 8006:192.168.1.100:8006 \ + -L 8000:192.168.100.50:8000 \ + -L 6443:192.168.100.60:6443 \ + -o "ServerAliveInterval 30" \ + -o "ServerAliveCountMax 3" \ + root@your-proxmox-host.com +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +``` + +Enable and start: + +```bash +sudo systemctl enable orion-tunnel +sudo systemctl start orion-tunnel +sudo systemctl status orion-tunnel +``` + +--- + +## 🎨 Customization + +### Personal Overrides + +Create `.claude/settings.local.json` for personal preferences: + +```json +{ + "model": "opus", + "statusLine": "πŸ—οΈ {user}@ORION | {model}", + + "env": { + "MY_PROXMOX_HOST": "192.168.1.100", + "MY_CUSTOM_VAR": "value" + }, + + "permissions": { + "defaultMode": "allow" + } +} +``` + +### Custom Zsh Aliases + +Add to `~/.zshrc` (at the end): + +```bash +# Your custom aliases +alias myalias='your-command' + +# Your custom functions +my-function() { + echo "My custom function" +} +``` + +Or create `~/.zshrc.local` and source it: + +```bash +# Add to ~/.zshrc +[ -f ~/.zshrc.local ] && source ~/.zshrc.local +``` + +--- + +## πŸ”§ Troubleshooting + +### Issue: Plugins not loading + +**Symptom**: zsh-autosuggestions or syntax-highlighting not working + +**Solution**: + +```bash +# Reinstall Antigen plugins +rm -rf ~/.antigen +zsh # Restart zsh - plugins will reinstall +``` + +### Issue: Slow shell startup + +**Symptom**: Zsh takes several seconds to start + +**Solution**: + +```bash +# Disable unnecessary plugins in ~/.zshrc +# Comment out plugins you don't need +plugins=( + git + # docker # Disabled for faster startup + terraform + # ... +) +``` + +### Issue: SSH tunnel disconnects + +**Symptom**: Local services become unreachable + +**Solution**: + +```bash +# Check tunnel status +ps aux | grep ssh + +# Restart autossh service +sudo systemctl restart orion-tunnel + +# Or manually reconnect +ssh -L 8006:192.168.1.100:8006 root@proxmox-host.com +``` + +### Issue: Claude Code can't connect to local server + +**Symptom**: Connection refused errors + +**Solution**: + +1. **Verify tunnel is active**: + ```bash + curl -k https://localhost:8006/api2/json/version + ``` + +2. **Check firewall**: + ```bash + # Allow local binding + ufw allow from 127.0.0.1 + ``` + +3. **Verify settings**: + ```bash + cat .claude/settings.local.json + ``` + +--- + +## πŸ“š Additional Resources + +### Documentation + +- **[ARCHITECTURE.md](../ARCHITECTURE.md)** - Main infrastructure documentation +- **[CLAUDE_CODE_INTEGRATION.md](CLAUDE_CODE_INTEGRATION.md)** - Claude Code configuration +- **[Makefile](../Makefile)** - Deployment commands + +### External Resources + +- **[Oh My Zsh](https://ohmyz.sh/)** - Framework homepage +- **[Antigen](https://github.com/zsh-users/antigen)** - Plugin manager +- **[zsh-users](https://github.com/orgs/zsh-users/repositories)** - Plugin repositories +- **[Claude Code Docs](https://code.claude.com/docs/)** - Official documentation + +--- + +## 🎯 Quick Reference + +### Zsh Shortcuts + +```bash +Ctrl+A # Move to beginning of line +Ctrl+E # Move to end of line +Ctrl+U # Delete from cursor to beginning +Ctrl+K # Delete from cursor to end +Ctrl+R # Reverse search history +Ctrl+L # Clear screen +Alt+. # Insert last argument +``` + +### ORION Quick Commands + +```bash +orion-status # Full status check +deploy # Deploy everything +orion # cd to ORION root +m help # Show make targets +k get pods # List K8s pods +tfp # Terraform plan +``` + +--- + +**Last Updated**: 2025-11-22 +**Status**: Active +**Maintained By**: ORION Infrastructure Team diff --git a/shell-config/.zshrc b/shell-config/.zshrc new file mode 100644 index 0000000..a05ff54 --- /dev/null +++ b/shell-config/.zshrc @@ -0,0 +1,252 @@ +# ORION Infrastructure - Zsh Configuration +# Optimized for infrastructure development with Oh My Zsh + Antigen + +# ============================================================================ +# Oh My Zsh Base Configuration +# ============================================================================ + +# Path to your Oh My Zsh installation +export ZSH="$HOME/.oh-my-zsh" + +# Theme +ZSH_THEME="agnoster" # Better theme for infrastructure work + +# Update behavior +zstyle ':omz:update' mode auto +zstyle ':omz:update' frequency 7 + +# Completion waiting dots +COMPLETION_WAITING_DOTS="true" + +# Command execution timestamp +HIST_STAMPS="yyyy-mm-dd" + +# Plugins from Oh My Zsh +plugins=( + git + docker + terraform + ansible + kubectl + helm + sudo + command-not-found + history + z + colored-man-pages + extract + web-search +) + +# Load Oh My Zsh +source $ZSH/oh-my-zsh.sh + +# ============================================================================ +# Antigen Configuration (zsh-users plugins) +# ============================================================================ + +# Load Antigen +source ~/antigen.zsh + +# Load oh-my-zsh library +antigen use oh-my-zsh + +# zsh-users plugins (https://github.com/orgs/zsh-users/repositories) +antigen bundle zsh-users/zsh-syntax-highlighting # Fish-like syntax highlighting +antigen bundle zsh-users/zsh-autosuggestions # Fish-like autosuggestions +antigen bundle zsh-users/zsh-completions # Additional completions +antigen bundle zsh-users/zsh-history-substring-search # Better history search + +# Apply Antigen configuration +antigen apply + +# ============================================================================ +# zsh-users Plugin Configuration +# ============================================================================ + +# zsh-autosuggestions +ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#6c757d" +ZSH_AUTOSUGGEST_STRATEGY=(history completion) +ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20 + +# zsh-syntax-highlighting +typeset -A ZSH_HIGHLIGHT_STYLES +ZSH_HIGHLIGHT_STYLES[command]='fg=green,bold' +ZSH_HIGHLIGHT_STYLES[alias]='fg=cyan,bold' +ZSH_HIGHLIGHT_STYLES[builtin]='fg=yellow,bold' +ZSH_HIGHLIGHT_STYLES[function]='fg=blue,bold' +ZSH_HIGHLIGHT_STYLES[path]='fg=magenta' +ZSH_HIGHLIGHT_STYLES[error]='fg=red,bold' + +# zsh-history-substring-search (bind keys) +bindkey '^[[A' history-substring-search-up +bindkey '^[[B' history-substring-search-down +bindkey '^P' history-substring-search-up +bindkey '^N' history-substring-search-down + +# ============================================================================ +# Environment Variables for ORION +# ============================================================================ + +# ORION project root +export ORION_ROOT="/home/user/luci-macOSX-PROXMOX" + +# Terraform +export TF_LOG="INFO" +export TF_LOG_PATH="/tmp/terraform.log" + +# Ansible +export ANSIBLE_STDOUT_CALLBACK="yaml" +export ANSIBLE_FORCE_COLOR=true + +# Kubernetes +export KUBECONFIG="$HOME/.kube/config" + +# ============================================================================ +# Aliases for ORION Infrastructure +# ============================================================================ + +# Navigation +alias orion='cd $ORION_ROOT' +alias tf='cd $ORION_ROOT/terraform' +alias ans='cd $ORION_ROOT/ansible' +alias k8s='cd $ORION_ROOT/kubernetes' + +# Terraform shortcuts +alias tfi='terraform init' +alias tfp='terraform plan' +alias tfa='terraform apply' +alias tfd='terraform destroy' +alias tfo='terraform output' +alias tfs='terraform show' + +# Ansible shortcuts +alias ap='ansible-playbook' +alias ai='ansible-inventory' +alias ag='ansible-galaxy' + +# Kubectl shortcuts +alias k='kubectl' +alias kgp='kubectl get pods' +alias kgs='kubectl get svc' +alias kgn='kubectl get nodes' +alias kd='kubectl describe' +alias kl='kubectl logs' +alias ke='kubectl exec -it' + +# Docker shortcuts +alias d='docker' +alias dc='docker-compose' +alias dps='docker ps' +alias dim='docker images' + +# Make shortcuts +alias m='make' +alias mh='make help' +alias mdeploy='make deploy-full' +alias mverify='make verify' + +# Git shortcuts (enhanced) +alias gs='git status' +alias ga='git add' +alias gc='git commit' +alias gp='git push' +alias gl='git log --oneline --graph --decorate' +alias gd='git diff' + +# System shortcuts +alias ll='ls -lah' +alias la='ls -A' +alias l='ls -CF' +alias ..='cd ..' +alias ...='cd ../..' +alias ....='cd ../../..' + +# ============================================================================ +# Functions for ORION Infrastructure +# ============================================================================ + +# Quick deploy function +deploy() { + echo "πŸš€ Deploying ORION infrastructure..." + cd $ORION_ROOT + make deploy-full +} + +# Quick status check +orion-status() { + echo "πŸ“Š ORION Infrastructure Status" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + cd $ORION_ROOT + echo "\nπŸ“ Git Status:" + git status --short + echo "\nπŸ—οΈ Terraform Status:" + cd terraform && terraform show -json 2>/dev/null | jq -r '.values.root_module.resources[] | select(.type == "proxmox_vm_qemu") | "\(.values.name) (VM \(.values.vmid))"' || echo "No Terraform state" + echo "\n☸️ Kubernetes Status (if running):" + kubectl get nodes 2>/dev/null || echo "K8s cluster not accessible" +} + +# SSH to VMs +ssh-router() { + ssh root@192.168.100.1 +} + +ssh-coordinator() { + ssh root@192.168.100.30 +} + +ssh-netbox() { + ssh root@192.168.100.50 +} + +ssh-k8s-master() { + ssh root@192.168.100.60 +} + +# Proxmox helper +proxmox-vms() { + echo "πŸ“¦ Proxmox VMs:" + qm list 2>/dev/null || echo "Not connected to Proxmox host" +} + +# LXC helper +proxmox-lxc() { + echo "πŸ“¦ Proxmox LXC Containers:" + pct list 2>/dev/null || echo "Not connected to Proxmox host" +} + +# ============================================================================ +# User Configuration +# ============================================================================ + +# Preferred editor +export EDITOR='nano' +export VISUAL='nano' + +# Language environment +export LANG=en_US.UTF-8 + +# Compilation flags +export ARCHFLAGS="-arch x86_64" + +# History settings +HISTSIZE=10000 +SAVEHIST=10000 +setopt HIST_IGNORE_ALL_DUPS +setopt HIST_FIND_NO_DUPS +setopt SHARE_HISTORY + +# ============================================================================ +# Welcome Message +# ============================================================================ + +echo "╔═══════════════════════════════════════════════════════════════╗" +echo "β•‘ πŸš€ ORION Infrastructure Development Shell β•‘" +echo "β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•" +echo "" +echo "πŸ“˜ Main docs: ARCHITECTURE.md" +echo "πŸ”§ Deploy: make deploy-full or deploy" +echo "πŸ“Š Status: orion-status" +echo "πŸ’‘ Quick nav: orion, tf, ans, k8s" +echo "⚑ Shortcuts: m (make), k (kubectl), tf* (terraform)" +echo "" diff --git a/shell-config/README.md b/shell-config/README.md new file mode 100644 index 0000000..35858fa --- /dev/null +++ b/shell-config/README.md @@ -0,0 +1,131 @@ +# ORION Shell Configuration + +**Zsh + Oh My Zsh + Antigen + zsh-users plugins for infrastructure development** + +--- + +## πŸš€ Quick Start + +```bash +# Run the installation script +./install-zsh.sh + +# Start zsh +zsh + +# Or set as default shell (requires logout) +chsh -s $(which zsh) +``` + +--- + +## πŸ“¦ What's Included + +- **Zsh 5.9** - Modern shell +- **Oh My Zsh** - Framework with 14+ infrastructure plugins +- **Antigen** - Plugin manager +- **zsh-users plugins**: + - `zsh-syntax-highlighting` - Fish-like syntax highlighting + - `zsh-autosuggestions` - Fish-like autosuggestions + - `zsh-completions` - Additional completions + - `zsh-history-substring-search` - Better history search + +--- + +## πŸ“ Files + +``` +shell-config/ +β”œβ”€β”€ .zshrc # Complete Zsh configuration +β”œβ”€β”€ antigen.zsh # Antigen plugin manager +β”œβ”€β”€ install-zsh.sh # Automated installation script +└── README.md # This file +``` + +--- + +## 🎯 Features + +### Infrastructure Aliases + +```bash +# Navigation +orion, tf, ans, k8s + +# Terraform +tfi, tfp, tfa, tfd, tfo, tfs + +# Kubernetes +k, kgp, kgs, kgn, kd, kl, ke + +# Make +m, mh, mdeploy, mverify +``` + +### Custom Functions + +```bash +deploy() # Quick deploy ORION stack +orion-status() # Complete infrastructure status +ssh-router() # SSH to router VM +ssh-coordinator() # SSH to AI coordinator +ssh-netbox() # SSH to NetBox +ssh-k8s-master() # SSH to K8s master +proxmox-vms() # List Proxmox VMs +proxmox-lxc() # List LXC containers +``` + +--- + +## πŸ“š Documentation + +See **[docs/DEVELOPMENT_ENVIRONMENT.md](../docs/DEVELOPMENT_ENVIRONMENT.md)** for complete documentation including: + +- Detailed installation guide +- Plugin configuration +- Claude Code integration +- SSH tunneling for remote development +- Customization options +- Troubleshooting + +--- + +## πŸ”§ Manual Installation + +If you prefer manual installation: + +```bash +# 1. Install Zsh +sudo apt-get install zsh git curl wget + +# 2. Install Oh My Zsh +sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" + +# 3. Install Antigen +curl -L git.io/antigen > ~/antigen.zsh + +# 4. Copy configuration +cp .zshrc ~/.zshrc +cp antigen.zsh ~/antigen.zsh + +# 5. Start zsh +zsh +``` + +--- + +## πŸ’‘ Quick Tips + +**Autosuggestions**: Type a few letters, press `β†’` to accept + +**Syntax Highlighting**: Green = valid command, Red = invalid + +**History Search**: Press `↑` to search history by substring + +**Quick Deploy**: Just type `deploy` + +**Status Check**: Type `orion-status` for complete overview + +--- + +**Last Updated**: 2025-11-22 diff --git a/shell-config/antigen.zsh b/shell-config/antigen.zsh new file mode 100644 index 0000000..e813207 --- /dev/null +++ b/shell-config/antigen.zsh @@ -0,0 +1,2057 @@ +###################################################################### +# This file was autogenerated by `make`. Do not edit it directly! +###################################################################### +# Antigen: A simple plugin manager for zsh + # Authors: Shrikant Sharat Kandula + # and Contributors + # Homepage: http://antigen.sharats.me + # License: MIT License +zmodload zsh/parameter +autoload -U is-at-least + +# While boot.zsh is part of the ext/cache functionallity it may be disabled +# with ANTIGEN_CACHE flag, and it's always compiled with antigen.zsh +if [[ $ANTIGEN_CACHE != false ]]; then + ANTIGEN_CACHE="${ANTIGEN_CACHE:-${ADOTDIR:-$HOME/.antigen}/init.zsh}" + ANTIGEN_RSRC="${ANTIGEN_RSRC:-${ADOTDIR:-$HOME/.antigen}/.resources}" + + # It may not be necessary to check ANTIGEN_AUTO_CONFIG. + if [[ $ANTIGEN_AUTO_CONFIG != false && -f $ANTIGEN_RSRC ]]; then + # Check the list of files for configuration changes (uses -nt comp) + ANTIGEN_CHECK_FILES=$(cat $ANTIGEN_RSRC 2> /dev/null) + ANTIGEN_CHECK_FILES=(${(@f)ANTIGEN_CHECK_FILES}) + + for config in $ANTIGEN_CHECK_FILES; do + if [[ "$config" -nt "$config.zwc" ]]; then + # Flag configuration file as newer + { zcompile "$config" } &! + # Kill cache file in order to force full loading (see a few lines below) + [[ -f "$ANTIGEN_CACHE" ]] && rm -f "$ANTIGEN_CACHE" + fi + done + fi + + # If there is a cache file do load from it + if [[ -f $ANTIGEN_CACHE && ! $_ANTIGEN_CACHE_LOADED == true ]]; then + # Wrap antigen in order to defer cache source until `antigen-apply` + antigen() { + if [[ $1 == "apply" ]]; then + source "$ANTIGEN_CACHE" + # Handle `antigen-init` command properly + elif [[ $1 == "init" ]]; then + source "$2" + fi + } + # Do not continue loading antigen as cache bundle takes care of it. + return 0 + fi +fi +[[ -z "$_ANTIGEN_INSTALL_DIR" ]] && _ANTIGEN_INSTALL_DIR=${0:A:h} + +# Each line in this string has the following entries separated by a space +# character. +# , , , +[[ $_ANTIGEN_CACHE_LOADED != true ]] && typeset -aU _ANTIGEN_BUNDLE_RECORD + +# Do not load anything if git is not available. +if (( ! $+commands[git] )); then + echo 'Antigen: Please install git to use Antigen.' >&2 + return 1 +fi + +# Used to defer compinit/compdef +typeset -a __deferred_compdefs +compdef () { __deferred_compdefs=($__deferred_compdefs "$*") } + +# A syntax sugar to avoid the `-` when calling antigen commands. With this +# function, you can write `antigen-bundle` as `antigen bundle` and so on. +antigen () { + local cmd="$1" + if [[ -z "$cmd" ]]; then + echo 'Antigen: Please give a command to run.' >&2 + return 1 + fi + shift + + if (( $+functions[antigen-$cmd] )); then + "antigen-$cmd" "$@" + return $? + else + echo "Antigen: Unknown command: $cmd" >&2 + return 1 + fi +} +# Returns the bundle's git revision +# +# Usage +# -antigen-bundle-rev bundle-name [is_local_clone] +# +# Returns +# Bundle rev-parse output (branch name or short ref name) +-antigen-bundle-rev () { + local bundle=$1 + local is_local_clone=$2 + + local bundle_path=$bundle + # Get bunde path inside $ADOTDIR if bundle was effectively cloned + if [[ "$is_local_clone" == "true" ]]; then + bundle_path=$(-antigen-get-clone-dir $bundle) + fi + + local ref + ref=$(git --git-dir="$bundle_path/.git" rev-parse --abbrev-ref '@' 2>/dev/null) + + # Avoid 'HEAD' when in detached mode + if [[ $ref == "HEAD" ]]; then + ref=$(git --git-dir="$bundle_path/.git" describe --tags --exact-match 2>/dev/null \ + || git --git-dir="$bundle_path/.git" rev-parse --short '@' 2>/dev/null || "-") + fi + echo $ref +} +# Usage: +# -antigen-bundle-short-name "https://github.com/user/repo.git[|*]" "[branch/name]" +# Returns: +# user/repo@branch/name +-antigen-bundle-short-name () { + local bundle_name="${1%|*}" + local bundle_branch="$2" + local match mbegin mend MATCH MBEGIN MEND + + [[ "$bundle_name" =~ '.*/(.*/.*).*$' ]] && bundle_name=$match[1] + bundle_name="${bundle_name%.git*}" + + if [[ -n $bundle_branch ]]; then + bundle_name="$bundle_name@$bundle_branch" + fi + + echo $bundle_name +} +# Echo the bundle specs as in the record. The first line is not echoed since it +# is a blank line. +-antigen-echo-record () { + echo ${(j:\n:)_ANTIGEN_BUNDLE_RECORD} +} +# Filters _ANTIGEN_BUNDLE_RECORD for $1 +# +# Usage +# -antigen-find-bundle example/bundle +# +# Returns +# String if bundle is found +-antigen-find-bundle () { + echo $(-antigen-find-record $1 | cut -d' ' -f1) +} + +# Filters _ANTIGEN_BUNDLE_RECORD for $1 +# +# Usage +# -antigen-find-record example/bundle +# +# Returns +# String if record is found +-antigen-find-record () { + local bundle=$1 + + if [[ $# -eq 0 ]]; then + return 1 + fi + + local record=${bundle/\|/\\\|} + echo "${_ANTIGEN_BUNDLE_RECORD[(r)*$record*]}" +} +# Returns bundle names from _ANTIGEN_BUNDLE_RECORD +# +# Usage +# -antigen-get-bundles [--short|--simple|--long] +# +# Returns +# List of bundles installed +-antigen-get-bundles () { + local mode revision url bundle_name bundle_entry loc no_local_clone + local record bundle make_local_clone + mode=${1:-"--short"} + + for record in $_ANTIGEN_BUNDLE_RECORD; do + bundle=(${(@s/ /)record}) + url=$bundle[1] + loc=$bundle[2] + make_local_clone=$bundle[4] + + bundle_name=$(-antigen-bundle-short-name $url) + + case "$mode" in + --short) + # Only check revision for bundle with a requested branch + if [[ $url == *\|* ]]; then + revision=$(-antigen-bundle-rev $url $make_local_clone) + else + revision="master" + fi + + if [[ $loc != '/' ]]; then + bundle_name="$bundle_name ~ $loc" + fi + echo "$bundle_name @ $revision" + ;; + --simple) + echo "$bundle_name" + ;; + --long) + echo "$record" + ;; + esac + done +} +# Usage: +# -antigen-get-clone-dir "https://github.com/zsh-users/zsh-syntax-highlighting.git[|feature/branch]" +# Returns: +# $ANTIGEN_BUNDLES/zsh-users/zsh-syntax-highlighting[-feature-branch] +-antigen-get-clone-dir () { + local bundle="$1" + local url="${bundle%|*}" + local branch match mbegin mend MATCH MBEGIN MEND + [[ "$bundle" =~ "\|" ]] && branch="${bundle#*|}" + + # Takes a repo url and mangles it, giving the path that this url will be + # cloned to. Doesn't actually clone anything. + local clone_dir="$ANTIGEN_BUNDLES" + + url=$(-antigen-bundle-short-name $url) + + # Suffix with branch/tag name + [[ -n "$branch" ]] && url="$url-${branch//\//-}" + url=${url//\*/x} + + echo "$clone_dir/$url" +} +# Returns bundles flagged as make_local_clone +# +# Usage +# -antigen-cloned-bundles +# +# Returns +# Bundle metadata +-antigen-get-cloned-bundles() { + -antigen-echo-record | + awk '$4 == "true" {print $1}' | + sort -u +} +# Returns a list of themes from a default library (omz) +# +# Usage +# -antigen-get-themes +# +# Returns +# List of themes by name +-antigen-get-themes () { + local library='robbyrussell/oh-my-zsh' + local bundle=$(-antigen-find-bundle $library) + + if [[ -n "$bundle" ]]; then + local dir=$(-antigen-get-clone-dir $ANTIGEN_DEFAULT_REPO_URL) + echo $(ls $dir/themes/ | grep '.zsh-theme$' | sed 's/.zsh-theme//') + fi + + return 0 +} + +# This function check ZSH_EVAL_CONTEXT to determine if running in interactive shell. +# +# Usage +# -antigen-interactive-mode +# +# Returns +# Either true or false depending if we are running in interactive mode +-antigen-interactive-mode () { + WARN "-antigen-interactive-mode: $ZSH_EVAL_CONTEXT \$_ANTIGEN_INTERACTIVE = $_ANTIGEN_INTERACTIVE" + if [[ $_ANTIGEN_INTERACTIVE != "" ]]; then + [[ $_ANTIGEN_INTERACTIVE == true ]]; + return + fi + + [[ "$ZSH_EVAL_CONTEXT" == toplevel* || "$ZSH_EVAL_CONTEXT" == cmdarg* ]]; +} +# Parses and retrieves a remote branch given a branch name. +# +# If the branch name contains '*' it will retrieve remote branches +# and try to match against tags and heads, returning the latest matching. +# +# Usage +# -antigen-parse-branch https://github.com/user/repo.git x.y.z +# +# Returns +# Branch name +-antigen-parse-branch () { + local url="$1" branch="$2" branches + + local match mbegin mend MATCH MBEGIN MEND + + if [[ "$branch" =~ '\*' ]]; then + branches=$(git ls-remote --tags -q "$url" "$branch"|cut -d'/' -f3|sort -n|tail -1) + # There is no --refs flag in git 1.8 and below, this way we + # emulate this flag -- also git 1.8 ref order is undefined. + branch=${${branches#*/*/}%^*} # Why you are like this? + fi + + echo $branch +} +-antigen-update-repos () { + local repo bundle url target + local log=/tmp/antigen-v2-migrate.log + + echo "It seems you have bundles cloned with Antigen v1.x." + echo "We'll try to convert directory structure to v2." + echo + + echo -n "Moving bundles to '\$ADOTDIR/bundles'... " + + # Migrate old repos -> bundles + local errors=0 + for repo in $ADOTDIR/repos/*; do + bundle=${repo/$ADOTDIR\/repos\//} + bundle=${bundle//-SLASH-/\/} + bundle=${bundle//-COLON-/\:} + bundle=${bundle//-STAR-/\*} + url=${bundle//-PIPE-/\|} + target=$(-antigen-get-clone-dir $url) + mkdir -p "${target:A:h}" + echo " ---> ${repo/$ADOTDIR\/} -> ${target/$ADOTDIR\/}" | tee > $log + mv "$repo" "$target" &> $log + if [[ $? != 0 ]]; then + echo "Failed to migrate '$repo'!." + errors+=1 + fi + done + + if [[ $errors == 0 ]]; then + echo "Done." + else + echo "An error ocurred!" + fi + echo + + if [[ "$(ls -A $ADOTDIR/repos | wc -l | xargs)" == 0 ]]; then + echo "You can safely remove \$ADOTDIR/repos." + else + echo "Some bundles couldn't be migrated. See \$ADOTDIR/repos." + fi + + echo + if [[ $errors == 0 ]]; then + echo "Bundles migrated successfuly." + rm $log + else + echo "Some errors occured. Review migration log in '$log'." + fi + antigen-reset +} +# Ensure that a clone exists for the given repo url and branch. If the first +# argument is `update` and if a clone already exists for the given repo +# and branch, it is pull-ed, i.e., updated. +# +# This function expects three arguments in order: +# - 'url=' +# - 'update=true|false' +# - 'verbose=true|false' +# +# Returns true|false Whether cloning/pulling was succesful +-antigen-ensure-repo () { + # Argument defaults. Previously using ${1:?"missing url argument"} format + # but it seems to mess up with cram + if (( $# < 1 )); then + echo "Antigen: Missing url argument." + return 1 + fi + + # The url. No sane default for this, so just empty. + local url=$1 + # Check if we have to update. + local update=${2:-false} + # Verbose output. + local verbose=${3:-false} + + shift $# + + # Get the clone's directory as per the given repo url and branch. + local clone_dir=$(-antigen-get-clone-dir $url) + if [[ -d "$clone_dir" && $update == false ]]; then + return true + fi + + # A temporary function wrapping the `git` command with repeated arguments. + --plugin-git () { + (\cd -q "$clone_dir" && eval ${ANTIGEN_CLONE_ENV} git --git-dir="$clone_dir/.git" --no-pager "$@" &>>! $ANTIGEN_LOG) + } + + local success=false + + # If its a specific branch that we want, checkout that branch. + local branch="master" # TODO FIX THIS + if [[ $url == *\|* ]]; then + branch="$(-antigen-parse-branch ${url%|*} ${url#*|})" + fi + + if [[ ! -d $clone_dir ]]; then + eval ${ANTIGEN_CLONE_ENV} git clone ${=ANTIGEN_CLONE_OPTS} --branch "$branch" -- "${url%|*}" "$clone_dir" &>> $ANTIGEN_LOG + success=$? + elif $update; then + # Save current revision. + local old_rev="$(--plugin-git rev-parse HEAD)" + # Pull changes if update requested. + --plugin-git checkout "$branch" + --plugin-git pull origin "$branch" + success=$? + + # Update submodules. + --plugin-git submodule update ${=ANTIGEN_SUBMODULE_OPTS} + # Get the new revision. + local new_rev="$(--plugin-git rev-parse HEAD)" + fi + + if [[ -n $old_rev && $old_rev != $new_rev ]]; then + echo Updated from $old_rev[0,7] to $new_rev[0,7]. + if $verbose; then + --plugin-git log --oneline --reverse --no-merges --stat '@{1}..' + fi + fi + + # Remove the temporary git wrapper function. + unfunction -- --plugin-git + + return $success +} +# Helper function: Same as `$1=$2`, but will only happen if the name +# specified by `$1` is not already set. +-antigen-set-default () { + local arg_name="$1" + local arg_value="$2" + eval "test -z \"\$$arg_name\" && typeset -g $arg_name='$arg_value'" +} + +-antigen-env-setup () { + typeset -gU fpath path + + # Pre-startup initializations. + -antigen-set-default ANTIGEN_OMZ_REPO_URL \ + https://github.com/robbyrussell/oh-my-zsh.git + -antigen-set-default ANTIGEN_PREZTO_REPO_URL \ + https://github.com/sorin-ionescu/prezto.git + -antigen-set-default ANTIGEN_DEFAULT_REPO_URL $ANTIGEN_OMZ_REPO_URL + + # Default Antigen directory. + -antigen-set-default ADOTDIR $HOME/.antigen + [[ ! -d $ADOTDIR ]] && mkdir -p $ADOTDIR + + # Defaults bundles directory. + -antigen-set-default ANTIGEN_BUNDLES $ADOTDIR/bundles + + # If there is no bundles directory, create it. + if [[ ! -d $ANTIGEN_BUNDLES ]]; then + mkdir -p $ANTIGEN_BUNDLES + # Check for v1 repos directory, transform it to v2 format. + [[ -d $ADOTDIR/repos ]] && -antigen-update-repos + fi + + -antigen-set-default ANTIGEN_COMPDUMP "${ADOTDIR:-$HOME}/.zcompdump" + -antigen-set-default ANTIGEN_LOG /dev/null + + # CLONE_OPTS uses ${=CLONE_OPTS} expansion so don't use spaces + # for arguments that can be passed as `--key=value`. + -antigen-set-default ANTIGEN_CLONE_ENV "GIT_TERMINAL_PROMPT=0" + -antigen-set-default ANTIGEN_CLONE_OPTS "--single-branch --recursive --depth=1" + -antigen-set-default ANTIGEN_SUBMODULE_OPTS "--recursive --depth=1" + + # Complain when a bundle is already installed. + -antigen-set-default _ANTIGEN_WARN_DUPLICATES true + + # Compatibility with oh-my-zsh themes. + -antigen-set-default _ANTIGEN_THEME_COMPAT true + + # Add default built-in extensions to load at start up + -antigen-set-default _ANTIGEN_BUILTIN_EXTENSIONS 'lock parallel defer cache' + + # Setup antigen's own completion. + if -antigen-interactive-mode; then + TRACE "Gonna create compdump file @ env-setup" COMPDUMP + autoload -Uz compinit + compinit -d "$ANTIGEN_COMPDUMP" + compdef _antigen antigen + else + (( $+functions[antigen-ext-init] )) && antigen-ext-init + fi +} +# Load a given bundle by sourcing it. +# +# The function also modifies fpath to add the bundle path. +# +# Usage +# -antigen-load "bundle-url" ["location"] ["make_local_clone"] ["btype"] +# +# Returns +# Integer. 0 if success 1 if an error ocurred. +-antigen-load () { + local bundle list + typeset -A bundle; bundle=($@) + + typeset -Ua list; list=() + local location="${bundle[dir]}/${bundle[loc]}" + + # Prioritize location when given. + if [[ -f "${location}" ]]; then + list=(${location}) + else + # Directory locations must be suffixed with slash + location="$location/" + + # Prioritize theme with antigen-theme + if [[ ${bundle[btype]} == "theme" ]]; then + list=(${location}*.zsh-theme(N[1])) + fi + + # Common frameworks + if [[ $#list == 0 ]]; then + # dot-plugin, init and functions support (omz, prezto) + # Support prezto function loading. See https://github.com/zsh-users/antigen/pull/428 + list=(${location}*.plugin.zsh(N[1]) ${location}init.zsh(N[1]) ${location}/functions(N[1])) + fi + + # Default to zsh and sh + if [[ $#list == 0 ]]; then + list=(${location}*.zsh(N) ${location}*.sh(N)) + fi + fi + + -antigen-load-env ${(kv)bundle} + + # If there is any sourceable try to load it + if ! -antigen-load-source "${list[@]}" && [[ ! -d ${location} ]]; then + return 1 + fi + + return 0 +} + +-antigen-load-env () { + typeset -A bundle; bundle=($@) + local location=${bundle[dir]}/${bundle[loc]} + + # Load to path if there is no sourceable + if [[ -d ${location} ]]; then + PATH="$PATH:${location:A}" + fpath+=("${location:A}") + return + fi + + PATH="$PATH:${location:A:h}" + fpath+=("${location:A:h}") +} + +-antigen-load-source () { + typeset -a list + list=($@) + local src match mbegin mend MATCH MBEGIN MEND + + # Return error when we're given an empty list + if [[ $#list == 0 ]]; then + return 1 + fi + + # Using a for rather than `source $list` as we need to check for zsh-themes + # In order to create antigen-compat file. This is only needed for interactive-mode + # theme switching, for static loading (cache) there is no need. + for src in $list; do + if [[ $_ANTIGEN_THEME_COMPAT == true && -f "$src" && "$src" == *.zsh-theme* ]]; then + local compat="${src:A}.antigen-compat" + echo "# Generated by Antigen. Do not edit!" >! "$compat" + cat $src | sed -Ee '/\{$/,/^\}/!{ + s/^local // + }' >>! "$compat" + src="$compat" + fi + + if ! source "$src" 2>/dev/null; then + return 1 + fi + done +} +# Usage: +# -antigen-parse-args output_assoc_arr +-antigen-parse-args () { + local argkey key value index=0 args + local match mbegin mend MATCH MBEGIN MEND + + local var=$1 + shift + + # Bundle spec arguments' default values. + #setopt XTRACE VERBOSE + builtin typeset -A args + args[url]="$ANTIGEN_DEFAULT_REPO_URL" + #unsetopt XTRACE VERBOSE + args[loc]=/ + args[make_local_clone]=true + args[btype]=plugin + #args[branch]= # commented out as it may cause assoc array kv mismatch + + while [[ $# -gt 0 ]]; do + argkey="${1%\=*}" + key="${argkey//--/}" + value="${1#*=}" + + case "$argkey" in + --url|--loc|--branch|--btype) + if [[ "$value" == "$argkey" ]]; then + printf "Required argument for '%s' not provided.\n" $key >&2 + else + args[$key]="$value" + fi + ;; + --no-local-clone) + args[make_local_clone]=false + ;; + --*) + printf "Unknown argument '%s'.\n" $key >&2 + ;; + *) + value=$key + case $index in + 0) + key=url + local domain="" + local url_path=$value + # Full url with protocol or ssh github url (github.com:org/repo) + if [[ "$value" =~ "://" || "$value" =~ ":" ]]; then + if [[ "$value" =~ [@.][^/:]+[:]?[0-9]*[:/]?(.*)@?$ ]]; then + url_path=$match[1] + domain=${value/$url_path/} + fi + fi + + if [[ "$url_path" =~ '@' ]]; then + args[branch]="${url_path#*@}" + value="$domain${url_path%@*}" + else + value="$domain$url_path" + fi + ;; + 1) key=loc ;; + esac + let index+=1 + args[$key]="$value" + ;; + esac + + shift + done + + # Check if url is just the plugin name. Super short syntax. + if [[ "${args[url]}" != */* ]]; then + case "$ANTIGEN_DEFAULT_REPO_URL" in + "$ANTIGEN_OMZ_REPO_URL") + args[loc]="plugins/${args[url]}" + ;; + "$ANTIGEN_PREZTO_REPO_URL") + args[loc]="modules/${args[url]}" + ;; + *) + args[loc]="${args[url]}" + ;; + esac + args[url]="$ANTIGEN_DEFAULT_REPO_URL" + fi + + # Resolve the url. + # Expand short github url syntax: `username/reponame`. + local url="${args[url]}" + if [[ $url != git://* && + $url != https://* && + $url != http://* && + $url != ssh://* && + $url != /* && + $url != *github.com:*/* + ]]; then + url="https://github.com/${url%.git}.git" + fi + args[url]="$url" + + # Ignore local clone if url given is not a git directory + if [[ ${args[url]} == /* && ! -d ${args[url]}/.git ]]; then + args[make_local_clone]=false + fi + + # Add the branch information to the url if we need to create a local clone. + # Format url in bundle-metadata format: url[|branch] + if [[ ! -z "${args[branch]}" && ${args[make_local_clone]} == true ]]; then + args[url]="${args[url]}|${args[branch]}" + fi + + # Add the theme extension to `loc`, if this is a theme, but only + # if it's especified, ie, --loc=theme-name, in case when it's not + # specified antige-load-list will look for *.zsh-theme files + if [[ ${args[btype]} == "theme" && + ${args[loc]} != "/" && ${args[loc]} != *.zsh-theme ]]; then + args[loc]="${args[loc]}.zsh-theme" + fi + + local name="${args[url]%|*}" + local branch="${args[branch]}" + + # Extract bundle name. + if [[ "$name" =~ '.*/(.*/.*).*$' ]]; then + name="${match[1]}" + fi + name="${name%.git*}" + + # Format bundle name with optional branch. + if [[ -n "${branch}" ]]; then + args[name]="${name}@${branch}" + else + args[name]="${name}" + fi + + # Format bundle path. + if [[ ${args[make_local_clone]} == true ]]; then + local bpath="$name" + # Suffix with branch/tag name + if [[ -n "$branch" ]]; then + # bpath is in the form of repo/name@version => repo/name-version + # Replace / with - in bundle branch. + local bbranch=${branch//\//-} + # If branch/tag is semver-like do replace * by x. + bbranch=${bbranch//\*/x} + bpath="${name}-${bbranch}" + fi + + bpath="$ANTIGEN_BUNDLES/$bpath" + args[dir]="${(qq)bpath}" + else + # if it's local then path is just the "url" argument, loc remains the same + args[dir]=${args[url]} + fi + + # Escape url and branch (may contain semver-like and pipe characters) + args[url]="${(qq)args[url]}" + if [[ -n "${args[branch]}" ]]; then + args[branch]="${(qq)args[branch]}" + fi + + # Escape bundle name (may contain semver-like characters) + args[name]="${(qq)args[name]}" + + eval "${var}=(${(kv)args})" + + return 0 +} +# Updates revert-info data with git hash. +# +# This does process only cloned bundles. +# +# Usage +# -antigen-revert-info +# +# Returns +# Nothing. Generates/updates $ADOTDIR/revert-info. +-antigen-revert-info() { + local url + # Update your bundles, i.e., `git pull` in all the plugin repos. + date >! $ADOTDIR/revert-info + + -antigen-get-cloned-bundles | while read url; do + local clone_dir="$(-antigen-get-clone-dir "$url")" + if [[ -d "$clone_dir" ]]; then + (echo -n "$clone_dir:" + \cd -q "$clone_dir" + git rev-parse HEAD) >> $ADOTDIR/revert-info + fi + done +} +-antigen-use-oh-my-zsh () { + typeset -g ZSH ZSH_CACHE_DIR + ANTIGEN_DEFAULT_REPO_URL=$ANTIGEN_OMZ_REPO_URL + if [[ -z "$ZSH" ]]; then + ZSH="$(-antigen-get-clone-dir "$ANTIGEN_DEFAULT_REPO_URL")" + fi + if [[ -z "$ZSH_CACHE_DIR" ]]; then + ZSH_CACHE_DIR="$ZSH/cache/" + fi + antigen-bundle --loc=lib +} +-antigen-use-prezto () { + ANTIGEN_DEFAULT_REPO_URL=$ANTIGEN_PREZTO_REPO_URL + antigen-bundle "$ANTIGEN_PREZTO_REPO_URL" +} +# Initialize completion +antigen-apply () { + LOG "Called antigen-apply" + + # Load the compinit module. This will readefine the `compdef` function to + # the one that actually initializes completions. + TRACE "Gonna create compdump file @ apply" COMPDUMP + autoload -Uz compinit + compinit -d "$ANTIGEN_COMPDUMP" + + # Apply all `compinit`s that have been deferred. + local cdef + for cdef in "${__deferred_compdefs[@]}"; do + compdef "$cdef" + done + + { zcompile "$ANTIGEN_COMPDUMP" } &! + + unset __deferred_compdefs +} +# Syntaxes +# antigen-bundle [=/] +# Keyword only arguments: +# branch - The branch of the repo to use for this bundle. +antigen-bundle () { + TRACE "Called antigen-bundle with $@" BUNDLE + if [[ -z "$1" ]]; then + printf "Antigen: Must provide a bundle url or name.\n" >&2 + return 1 + fi + + builtin typeset -A bundle; -antigen-parse-args 'bundle' ${=@} + if [[ -z ${bundle[btype]} ]]; then + bundle[btype]=bundle + fi + + local record="${bundle[url]} ${bundle[loc]} ${bundle[btype]} ${bundle[make_local_clone]}" + if [[ $_ANTIGEN_WARN_DUPLICATES == true && ! ${_ANTIGEN_BUNDLE_RECORD[(I)$record]} == 0 ]]; then + printf "Seems %s is already installed!\n" ${bundle[name]} + return 1 + fi + + # Clone bundle if we haven't done do already. + if [[ ! -d "${bundle[dir]}" ]]; then + if ! -antigen-bundle-install ${(kv)bundle}; then + return 1 + fi + fi + + # Load the plugin. + if ! -antigen-load ${(kv)bundle}; then + TRACE "-antigen-load failed to load ${bundle[name]}" BUNDLE + printf "Antigen: Failed to load %s.\n" ${bundle[btype]} >&2 + return 1 + fi + + # Only add it to the record if it could be installed and loaded. + _ANTIGEN_BUNDLE_RECORD+=("$record") +} + +# +# Usage: +# -antigen-bundle-install +# Returns: +# 1 if it fails to install bundle +-antigen-bundle-install () { + typeset -A bundle; bundle=($@) + + # Ensure a clone exists for this repo, if needed. + # Get the clone's directory as per the given repo url and branch. + local bpath="${bundle[dir]}" + # Clone if it doesn't already exist. + local start=$(date +'%s') + + printf "Installing %s... " "${bundle[name]}" + + if ! -antigen-ensure-repo "${bundle[url]}"; then + # Return immediately if there is an error cloning + TRACE "-antigen-bundle-instal failed to clone ${bundle[url]}" BUNDLE + printf "Error! Activate logging and try again.\n" >&2 + return 1 + fi + + local took=$(( $(date +'%s') - $start )) + printf "Done. Took %ds.\n" $took +} +antigen-bundles () { + # Bulk add many bundles at one go. Empty lines and lines starting with a `#` + # are ignored. Everything else is given to `antigen-bundle` as is, no + # quoting rules applied. + local line + setopt localoptions no_extended_glob # See https://github.com/zsh-users/antigen/issues/456 + grep '^[[:space:]]*[^[:space:]#]' | while read line; do + antigen-bundle ${=line%#*} + done +} +# Cleanup unused repositories. +antigen-cleanup () { + local force=false + if [[ $1 == --force ]]; then + force=true + fi + + if [[ ! -d "$ANTIGEN_BUNDLES" || -z "$(\ls -A "$ANTIGEN_BUNDLES")" ]]; then + echo "You don't have any bundles." + return 0 + fi + + # Find directores in ANTIGEN_BUNDLES, that are not in the bundles record. + typeset -a unused_clones clones + + local url record clone + for record in $(-antigen-get-cloned-bundles); do + url=${record% /*} + clones+=("$(-antigen-get-clone-dir $url)") + done + + for clone in $ANTIGEN_BUNDLES/*/*(/); do + if [[ $clones[(I)$clone] == 0 ]]; then + unused_clones+=($clone) + fi + done + + if [[ -z $unused_clones ]]; then + echo "You don't have any unidentified bundles." + return 0 + fi + + echo 'You have clones for the following repos, but are not used.' + echo "\n${(j:\n:)unused_clones}" + + if $force || (echo -n '\nDelete them all? [y/N] '; read -q); then + echo + echo + for clone in $unused_clones; do + echo -n "Deleting clone \"$clone\"..." + \rm -rf "$clone" + + echo ' done.' + done + else + echo + echo "Nothing deleted." + fi +} +antigen-help () { + antigen-version + + cat < [args] + +Commands: + apply Must be called in the zshrc after all calls to 'antigen bundle'. + bundle Install and load a plugin. + cache-gen Generate Antigen's cache with currently loaded bundles. + cleanup Remove clones of repos not used by any loaded plugins. + init Use caching to quickly load bundles. + list List currently loaded plugins. + purge Remove a bundle from the filesystem. + reset Clean the generated cache. + restore Restore plugin state from a snapshot file. + revert Revert plugins to their state prior to the last time 'antigen + update' was run. + selfupdate Update antigen. + snapshot Create a snapshot of all active plugin repos and save it to a + snapshot file. + update Update plugins. + use Load a supported zsh pre-packaged framework. + +For further details and complete documentation, visit the project's page at +'http://antigen.sharats.me'. +EOF +} +# Antigen command to load antigen configuration +# +# This method is slighlty more performing than using various antigen-* methods. +# +# Usage +# Referencing an antigen configuration file: +# +# antigen-init "/path/to/antigenrc" +# +# or using HEREDOCS: +# +# antigen-init <&2 + return 1 + fi + fi + + # Otherwise we expect it to be a heredoc + grep '^[[:space:]]*[^[:space:]#]' | while read -r line; do + eval $line + done +} +# List instaled bundles either in long (record), short or simple format. +# +# Usage +# antigen-list [--short|--long|--simple] +# +# Returns +# List of bundles +antigen-list () { + local format=$1 + + # List all currently installed bundles. + if [[ -z $_ANTIGEN_BUNDLE_RECORD ]]; then + echo "You don't have any bundles." >&2 + return 1 + fi + + -antigen-get-bundles $format +} +# Remove a bundle from filesystem +# +# Usage +# antigen-purge example/bundle [--force] +# +# Returns +# Nothing. Removes bundle from filesystem. +antigen-purge () { + local bundle=$1 + local force=$2 + + if [[ $# -eq 0 ]]; then + echo "Antigen: Missing argument." >&2 + return 1 + fi + + if -antigen-purge-bundle $bundle $force; then + antigen-reset + else + return $? + fi + + return 0 +} + +# Remove a bundle from filesystem +# +# Usage +# antigen-purge example/bundle [--force] +# +# Returns +# Nothing. Removes bundle from filesystem. +-antigen-purge-bundle () { + local bundle=$1 + local force=$2 + local clone_dir="" + + local record="" + local url="" + local make_local_clone="" + + if [[ $# -eq 0 ]]; then + echo "Antigen: Missing argument." >&2 + return 1 + fi + + # local keyword doesn't work on zsh <= 5.0.0 + record=$(-antigen-find-record $bundle) + + if [[ ! -n "$record" ]]; then + echo "Bundle not found in record. Try 'antigen bundle $bundle' first." >&2 + return 1 + fi + + url="$(echo "$record" | cut -d' ' -f1)" + make_local_clone=$(echo "$record" | cut -d' ' -f4) + + if [[ $make_local_clone == "false" ]]; then + echo "Bundle has no local clone. Will not be removed." >&2 + return 1 + fi + + clone_dir=$(-antigen-get-clone-dir "$url") + if [[ $force == "--force" ]] || read -q "?Remove '$clone_dir'? (y/n) "; then + # Need empty line after read -q + [[ ! -n $force ]] && echo "" || echo "Removing '$clone_dir'."; + rm -rf "$clone_dir" + return $? + fi + + return 1 +} +# Removes cache payload and metadata if available +# +# Usage +# antigen-reset +# +# Returns +# Nothing +antigen-reset () { + [[ -f "$ANTIGEN_CACHE" ]] && rm -f "$ANTIGEN_CACHE" "$ANTIGEN_CACHE.zwc" 1> /dev/null + [[ -f "$ANTIGEN_RSRC" ]] && rm -f "$ANTIGEN_RSRC" 1> /dev/null + [[ -f "$ANTIGEN_COMPDUMP" ]] && rm -f "$ANTIGEN_COMPDUMP" "$ANTIGEN_COMPDUMP.zwc" 1> /dev/null + [[ -f "$ANTIGEN_LOCK" ]] && rm -f "$ANTIGEN_LOCK" 1> /dev/null + echo 'Done. Please open a new shell to see the changes.' +} +antigen-restore () { + local line + if [[ $# == 0 ]]; then + echo 'Please provide a snapshot file to restore from.' >&2 + return 1 + fi + + local snapshot_file="$1" + + # TODO: Before doing anything with the snapshot file, verify its checksum. + # If it fails, notify this to the user and confirm if restore should + # proceed. + + echo -n "Restoring from $snapshot_file..." + + sed -n '1!p' "$snapshot_file" | + while read line; do + local version_hash="${line%% *}" + local url="${line##* }" + local clone_dir="$(-antigen-get-clone-dir "$url")" + + if [[ ! -d $clone_dir ]]; then + git clone "$url" "$clone_dir" &> /dev/null + fi + + (\cd -q "$clone_dir" && git checkout $version_hash) &> /dev/null + done + + echo ' done.' + echo 'Please open a new shell to get the restored changes.' +} +# Reads $ADORDIR/revert-info and restores bundles' revision +antigen-revert () { + local line + if [[ -f $ADOTDIR/revert-info ]]; then + cat $ADOTDIR/revert-info | sed -n '1!p' | while read line; do + local dir="$(echo "$line" | cut -d: -f1)" + git --git-dir="$dir/.git" --work-tree="$dir" \ + checkout "$(echo "$line" | cut -d: -f2)" 2> /dev/null + done + + echo "Reverted to state before running -update on $( + cat $ADOTDIR/revert-info | sed -n '1p')." + + else + echo 'No revert information available. Cannot revert.' >&2 + return 1 + fi +} +# Update (with `git pull`) antigen itself. +# TODO: Once update is finished, show a summary of the new commits, as a kind of +# "what's new" message. +antigen-selfupdate () { + (\cd -q $_ANTIGEN_INSTALL_DIR + if [[ ! ( -d .git || -f .git ) ]]; then + echo "Your copy of antigen doesn't appear to be a git clone. " \ + "The 'selfupdate' command cannot work in this case." + return 1 + fi + local head="$(git rev-parse --abbrev-ref HEAD)" + if [[ $head == "HEAD" ]]; then + # If current head is detached HEAD, checkout to master branch. + git checkout master + fi + git pull + + # TODO Should be transparently hooked by zcache + antigen-reset &>> /dev/null + ) +} +antigen-snapshot () { + local snapshot_file="${1:-antigen-shapshot}" + local urls url dir version_hash snapshot_content + local -a bundles + + # The snapshot content lines are pairs of repo-url and git version hash, in + # the form: + # + urls=$(-antigen-echo-record | awk '$4 == "true" {print $1}' | sort -u) + for url in ${(f)urls}; do + dir="$(-antigen-get-clone-dir "$url")" + version_hash="$(\cd -q "$dir" && git rev-parse HEAD)" + bundles+=("$version_hash $url"); + done + snapshot_content=${(j:\n:)bundles} + + { + # The first line in the snapshot file is for metadata, in the form: + # key='value'; key='value'; key='value'; + # Where `key`s are valid shell variable names. + + # Snapshot version. Has no relation to antigen version. If the snapshot + # file format changes, this number can be incremented. + echo -n "version='1';" + + # Snapshot creation date+time. + echo -n " created_on='$(date)';" + + # Add a checksum with the md5 checksum of all the snapshot lines. + chksum() { (md5sum; test $? = 127 && md5) 2>/dev/null | cut -d' ' -f1 } + local checksum="$(echo "$snapshot_content" | chksum)" + unset -f chksum; + echo -n " checksum='${checksum%% *}';" + + # A newline after the metadata and then the snapshot lines. + echo "\n$snapshot_content" + + } > "$snapshot_file" +} +# Loads a given theme. +# +# Shares the same syntax as antigen-bundle command. +# +# Usage +# antigen-theme zsh/theme[.zsh-theme] +# +# Returns +# 0 if everything was succesfully +antigen-theme () { + local name=$1 result=0 record + local match mbegin mend MATCH MBEGIN MEND + + if [[ -z "$1" ]]; then + printf "Antigen: Must provide a theme url or name.\n" >&2 + return 1 + fi + + -antigen-theme-reset-hooks + + record=$(-antigen-find-record "theme") + if [[ "$1" != */* && "$1" != --* ]]; then + # The first argument is just a name of the plugin, to be picked up from + # the default repo. + antigen-bundle --loc=themes/$name --btype=theme + + else + antigen-bundle "$@" --btype=theme + + fi + result=$? + + # Remove a theme from the record if the following conditions apply: + # - there was no error in bundling the given theme + # - there is a theme registered + # - registered theme is not the same as the current one + if [[ $result == 0 && -n $record ]]; then + # http://zsh-workers.zsh.narkive.com/QwfCWpW8/what-s-wrong-with-this-expression + if [[ "$record" =~ "$@" ]]; then + return $result + else + _ANTIGEN_BUNDLE_RECORD[$_ANTIGEN_BUNDLE_RECORD[(I)$record]]=() + fi + fi + + return $result +} + +-antigen-theme-reset-hooks () { + # This is only needed on interactive mode + autoload -U add-zsh-hook is-at-least + local hook + + # Clear out prompts + PROMPT="" + if [[ -n $RPROMPT ]]; then + RPROMPT="" + fi + + for hook in chpwd precmd preexec periodic; do + add-zsh-hook -D "${hook}" "prompt_*" + # common in omz themes + add-zsh-hook -D "${hook}" "*_${hook}" + add-zsh-hook -d "${hook}" "vcs_info" + done +} +# Updates the bundles or a single bundle. +# +# Usage +# antigen-update [example/bundle] +# +# Returns +# Nothing. Performs a `git pull`. +antigen-update () { + local bundle=$1 url + + # Clear log + :> $ANTIGEN_LOG + + # Update revert-info data + -antigen-revert-info + + # If no argument is given we update all bundles + if [[ $# -eq 0 ]]; then + # Here we're ignoring all non cloned bundles (ie, --no-local-clone) + -antigen-get-cloned-bundles | while read url; do + -antigen-update-bundle $url + done + # TODO next minor version + # antigen-reset + else + if -antigen-update-bundle $bundle; then + # TODO next minor version + # antigen-reset + else + return $? + fi + fi +} + +# Updates a bundle performing a `git pull`. +# +# Usage +# -antigen-update-bundle example/bundle +# +# Returns +# Nothing. Performs a `git pull`. +-antigen-update-bundle () { + local bundle="$1" + local record="" + local url="" + local make_local_clone="" + local start=$(date +'%s') + + if [[ $# -eq 0 ]]; then + printf "Antigen: Missing argument.\n" >&2 + return 1 + fi + + record=$(-antigen-find-record $bundle) + if [[ ! -n "$record" ]]; then + printf "Bundle not found in record. Try 'antigen bundle %s' first.\n" $bundle >&2 + return 1 + fi + + url="$(echo "$record" | cut -d' ' -f1)" + make_local_clone=$(echo "$record" | cut -d' ' -f4) + + local branch="master" + if [[ $url == *\|* ]]; then + branch="$(-antigen-parse-branch ${url%|*} ${url#*|})" + fi + + printf "Updating %s... " $(-antigen-bundle-short-name "$url" "$branch") + + if [[ $make_local_clone == "false" ]]; then + printf "Bundle has no local clone. Will not be updated.\n" >&2 + return 1 + fi + + # update=true verbose=false + if ! -antigen-ensure-repo "$url" true false; then + printf "Error! Activate logging and try again.\n" >&2 + return 1 + fi + + local took=$(( $(date +'%s') - $start )) + printf "Done. Took %ds.\n" $took +} +antigen-use () { + if [[ $1 == oh-my-zsh ]]; then + -antigen-use-oh-my-zsh + elif [[ $1 == prezto ]]; then + -antigen-use-prezto + elif [[ $1 != "" ]]; then + ANTIGEN_DEFAULT_REPO_URL=$1 + antigen-bundle $@ + else + echo 'Usage: antigen-use ' >&2 + echo 'Where is any one of the following:' >&2 + echo ' * oh-my-zsh' >&2 + echo ' * prezto' >&2 + echo ' is the full url.' >&2 + return 1 + fi +} +antigen-version () { + local version="v2.2.2" + local extensions revision="" + if [[ -d $_ANTIGEN_INSTALL_DIR/.git ]]; then + revision=" ($(git --git-dir=$_ANTIGEN_INSTALL_DIR/.git rev-parse --short '@'))" + fi + + printf "Antigen %s%s\n" $version $revision + if (( $+functions[antigen-ext] )); then + typeset -a extensions; extensions=($(antigen-ext-list)) + if [[ $#extensions -gt 0 ]]; then + printf "Extensions loaded: %s\n" ${(j:, :)extensions} + fi + fi +} +typeset -Ag _ANTIGEN_HOOKS; _ANTIGEN_HOOKS=() +typeset -Ag _ANTIGEN_HOOKS_META; _ANTIGEN_HOOKS_META=() +typeset -g _ANTIGEN_HOOK_PREFIX="-antigen-hook-" +typeset -g _ANTIGEN_EXTENSIONS; _ANTIGEN_EXTENSIONS=() + +# -antigen-add-hook antigen-apply antigen-apply-hook replace +# - Replaces hooked function with hook, do not call hooked function +# - Return -1 to stop calling further hooks +# -antigen-add-hook antigen-apply antigen-apply-hook pre (pre-call) +# - By default it will call hooked function +# -antigen-add-hook antigen-pply antigen-apply-hook post (post-call) +# - Calls antigen-apply and then calls hook function +# Usage: +# -antigen-add-hook antigen-apply antigen-apply-hook ["replace"|"pre"|"post"] ["once"|"repeat"] +antigen-add-hook () { + local target="$1" hook="$2" type="$3" mode="${4:-repeat}" + + if (( ! $+functions[$target] )); then + printf "Antigen: Function %s doesn't exist.\n" $target + return 1 + fi + + if (( ! $+functions[$hook] )); then + printf "Antigen: Function %s doesn't exist.\n" $hook + return 1 + fi + + if [[ "${_ANTIGEN_HOOKS[$target]}" == "" ]]; then + _ANTIGEN_HOOKS[$target]="${hook}" + else + _ANTIGEN_HOOKS[$target]="${_ANTIGEN_HOOKS[$target]}:${hook}" + fi + + _ANTIGEN_HOOKS_META[$hook]="target $target type $type mode $mode called 0" + + # Do shadow for this function if there is none already + local hook_function="${_ANTIGEN_HOOK_PREFIX}$target" + if (( ! $+functions[$hook_function] )); then + # Preserve hooked function + eval "function ${_ANTIGEN_HOOK_PREFIX}$(functions -- $target)" + + # Create hook, call hook-handler to further process hook functions + eval "function $target () { + noglob -antigen-hook-handler $target \$@ + return \$? + }" + fi + + return 0 +} + +# Private function to handle multiple hooks in a central point. +-antigen-hook-handler () { + local target="$1" args hook called + local hooks meta + shift + typeset -a args; args=(${@}) + + typeset -a pre_hooks replace_hooks post_hooks; + typeset -a hooks; hooks=(${(s|:|)_ANTIGEN_HOOKS[$target]}) + + typeset -A meta; + for hook in $hooks; do + meta=(${(s: :)_ANTIGEN_HOOKS_META[$hook]}) + if [[ ${meta[mode]} == "once" && ${meta[called]} == 1 ]]; then + WARN "Ignoring hook due to mode ${meta[mode]}: $hook" + continue + fi + + let called=${meta[called]}+1 + meta[called]=$called + _ANTIGEN_HOOKS_META[$hook]="${(kv)meta}" + WARN "Updated meta: "${(kv)meta} + + case "${meta[type]}" in + "pre") + pre_hooks+=($hook) + ;; + "replace") + replace_hooks+=($hook) + ;; + "post") + post_hooks+=($hook) + ;; + esac + done + + WARN "Processing hooks: ${hooks}" + + for hook in $pre_hooks; do + WARN "Pre hook:" $hook $args + noglob $hook $args + [[ $? == -1 ]] && WARN "$hook shortcircuited" && return $ret + done + + # A replace hook will return inmediately + local replace_hook=0 ret=0 + for hook in $replace_hooks; do + replace_hook=1 + # Should not be needed if `antigen-remove-hook` removed unneeded hooks. + if (( $+functions[$hook] )); then + WARN "Replace hook:" $hook $args + noglob $hook $args + [[ $? == -1 ]] && WARN "$hook shortcircuited" && return $ret + fi + done + + if [[ $replace_hook == 0 ]]; then + WARN "${_ANTIGEN_HOOK_PREFIX}$target $args" + noglob ${_ANTIGEN_HOOK_PREFIX}$target $args + ret=$? + else + WARN "Replaced hooked function." + fi + + for hook in $post_hooks; do + WARN "Post hook:" $hook $args + noglob $hook $args + [[ $? == -1 ]] && WARN "$hook shortcircuited" && return $ret + done + + LOG "Return from hook ${target} with ${ret}" + + return $ret +} + +# Usage: +# -antigen-remove-hook antigen-apply-hook +antigen-remove-hook () { + local hook="$1" + typeset -A meta; meta=(${(s: :)_ANTIGEN_HOOKS_META[$hook]}) + local target="${meta[target]}" + local -a hooks; hooks=(${(s|:|)_ANTIGEN_HOOKS[$target]}) + + # Remove registered hook + if [[ $#hooks > 0 ]]; then + hooks[$hooks[(I)$hook]]=() + fi + _ANTIGEN_HOOKS[${target}]="${(j|:|)hooks}" + + if [[ $#hooks == 0 ]]; then + # Destroy base hook + eval "function $(functions -- ${_ANTIGEN_HOOK_PREFIX}$target | sed s/${_ANTIGEN_HOOK_PREFIX}//)" + if (( $+functions[${_ANTIGEN_HOOK_PREFIX}$target] )); then + unfunction -- "${_ANTIGEN_HOOK_PREFIX}$target" + fi + fi + + unfunction -- $hook 2> /dev/null +} + +# Remove all defined hooks. +-antigen-reset-hooks () { + local target + + for target in ${(k)_ANTIGEN_HOOKS}; do + # Release all hooked functions + eval "function $(functions -- ${_ANTIGEN_HOOK_PREFIX}$target | sed s/${_ANTIGEN_HOOK_PREFIX}//)" + unfunction -- "${_ANTIGEN_HOOK_PREFIX}$target" 2> /dev/null + done + + _ANTIGEN_HOOKS=() + _ANTIGEN_HOOKS_META=() + _ANTIGEN_EXTENSIONS=() +} + +# Initializes an extension +# Usage: +# antigen-ext ext-name +antigen-ext () { + local ext=$1 + local func="-antigen-$ext-init" + if (( $+functions[$func] && $_ANTIGEN_EXTENSIONS[(I)$ext] == 0 )); then + eval $func + local ret=$? + WARN "$func return code was $ret" + if (( $ret == 0 )); then + LOG "LOADED EXTENSION $ext" EXT + -antigen-$ext-execute && _ANTIGEN_EXTENSIONS+=($ext) + else + WARN "IGNORING EXTENSION $func" EXT + return 1 + fi + + else + printf "Antigen: No extension defined or already loaded: %s\n" $func >&2 + return 1 + fi +} + +# List installed extensions +# Usage: +# antigen ext-list +antigen-ext-list () { + echo $_ANTIGEN_EXTENSIONS +} + +# Initializes built-in extensions +# Usage: +# antigen-ext-init +antigen-ext-init () { + # Initialize extensions. unless in interactive mode. + local ext + for ext in ${(s/ /)_ANTIGEN_BUILTIN_EXTENSIONS}; do + # Check if extension is loaded before intializing it + (( $+functions[-antigen-$ext-init] )) && antigen-ext $ext + done +} +# Initialize defer lib +-antigen-defer-init () { + typeset -ga _DEFERRED_BUNDLE; _DEFERRED_BUNDLE=() + if -antigen-interactive-mode; then + return 1 + fi +} + +-antigen-defer-execute () { + # Hooks antigen-bundle in order to defer its execution. + antigen-bundle-defer () { + _DEFERRED_BUNDLE+=("${(j: :)${@}}") + return -1 # Stop right there + } + antigen-add-hook antigen-bundle antigen-bundle-defer replace + + # Hooks antigen-apply in order to release hooked functions + antigen-apply-defer () { + WARN "Defer pre-apply" DEFER PRE-APPLY + antigen-remove-hook antigen-bundle-defer + + # Process all deferred bundles. + local bundle + for bundle in ${_DEFERRED_BUNDLE[@]}; do + LOG "Processing deferred bundle: ${bundle}" DEFER + antigen-bundle $bundle + done + + unset _DEFERRED_BUNDLE + } + antigen-add-hook antigen-apply antigen-apply-defer pre once +} +# Initialize lock lib +-antigen-lock-init () { + # Default lock path. + -antigen-set-default ANTIGEN_LOCK $ADOTDIR/.lock + typeset -g _ANTIGEN_LOCK_PROCESS=false + + # Use env variable to determine if we should load this extension + -antigen-set-default ANTIGEN_MUTEX true + # Set ANTIGEN_MUTEX to false to avoid loading this extension + if [[ $ANTIGEN_MUTEX == true ]]; then + return 0; + fi + + # Do not use mutex + return 1; +} + +-antigen-lock-execute () { + # Hook antigen command in order to check/create a lock file. + # This hook is only run once then releases itself. + antigen-lock () { + LOG "antigen-lock called" + # If there is a lock set up then we won't process anything. + if [[ -f $ANTIGEN_LOCK ]]; then + # Set up flag do the message is not repeated for each antigen-* command + [[ $_ANTIGEN_LOCK_PROCESS == false ]] && printf "Antigen: Another process in running.\n" + _ANTIGEN_LOCK_PROCESS=true + # Do not further process hooks. For this hook to properly work it + # should be registered first. + return -1 + fi + + WARN "Creating antigen-lock file at $ANTIGEN_LOCK" + touch $ANTIGEN_LOCK + } + antigen-add-hook antigen antigen-lock pre once + + # Hook antigen-apply in order to release .lock file. + antigen-apply-lock () { + WARN "Freeing antigen-lock file at $ANTIGEN_LOCK" + unset _ANTIGEN_LOCK_PROCESS + rm -f $ANTIGEN_LOCK &> /dev/null + } + antigen-add-hook antigen-apply antigen-apply-lock post once +} +# Initialize parallel lib +-antigen-parallel-init () { + WARN "Init parallel extension" PARALLEL + typeset -ga _PARALLEL_BUNDLE; _PARALLEL_BUNDLE=() + if -antigen-interactive-mode; then + return 1 + fi +} + +-antigen-parallel-execute() { + WARN "Exec parallel extension" PARALLEL + # Install bundles in parallel + antigen-bundle-parallel-execute () { + WARN "Parallel antigen-bundle-parallel-execute" PARALLEL + typeset -a pids; pids=() + local args pid + + WARN "Gonna install in parallel ${#_PARALLEL_BUNDLE} bundles." PARALLEL + # Do ensure-repo in parallel + WARN "${_PARALLEL_BUNDLE}" PARALLEL + typeset -Ua repositories # Used to keep track of cloned repositories to avoid + # trying to clone it multiple times. + for args in ${_PARALLEL_BUNDLE}; do + typeset -A bundle; -antigen-parse-args 'bundle' ${=args} + + if [[ ! -d ${bundle[dir]} && $repositories[(I)${bundle[url]}] == 0 ]]; then + WARN "Install in parallel ${bundle[name]}." PARALLEL + echo "Installing ${bundle[name]}!..." + # $bundle[url]'s format is "url|branch" as to create "$ANTIGEN_BUNDLES/bundle/name-branch", + # this way you may require multiple branches from the same repository. + -antigen-ensure-repo "${bundle[url]}" > /dev/null &! + pids+=($!) + else + WARN "Bundle ${bundle[name]} already cloned locally." PARALLEL + fi + + repositories+=(${bundle[url]}) + done + + # Wait for all background processes to end + while [[ $#pids > 0 ]]; do + for pid in $pids; do + # `ps` may diplay an error message such "Signal 18 (CONT) caught by ps + # (procps-ng version 3.3.9).", see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=732410 + if [[ $(ps -o pid= -p $pid 2>/dev/null) == "" ]]; then + pids[$pids[(I)$pid]]=() + fi + done + sleep .5 + done + + builtin local bundle &> /dev/null + for bundle in ${_PARALLEL_BUNDLE[@]}; do + antigen-bundle $bundle + done + + + WARN "Parallel install done" PARALLEL + } + + # Hooks antigen-apply in order to release hooked functions + antigen-apply-parallel () { + WARN "Parallel pre-apply" PARALLEL PRE-APPLY + #antigen-remove-hook antigen-pre-apply-parallel + # Hooks antigen-bundle in order to parallel its execution. + antigen-bundle-parallel () { + TRACE "antigen-bundle-parallel: $@" PARALLEL + _PARALLEL_BUNDLE+=("${(j: :)${@}}") + } + antigen-add-hook antigen-bundle antigen-bundle-parallel replace + } + antigen-add-hook antigen-apply antigen-apply-parallel pre once + + antigen-apply-parallel-execute () { + WARN "Parallel replace-apply" PARALLEL REPLACE-APPLY + antigen-remove-hook antigen-bundle-parallel + # Process all parallel bundles. + antigen-bundle-parallel-execute + + unset _PARALLEL_BUNDLE + antigen-remove-hook antigen-apply-parallel-execute + antigen-apply + } + antigen-add-hook antigen-apply antigen-apply-parallel-execute replace once +} +typeset -ga _ZCACHE_BUNDLE_SOURCE _ZCACHE_CAPTURE_BUNDLE +typeset -g _ZCACHE_CAPTURE_PREFIX + +# Generates cache from listed bundles. +# +# Iterates over _ANTIGEN_BUNDLE_RECORD and join all needed sources into one, +# if this is done through -antigen-load-list. +# Result is stored in ANTIGEN_CACHE. +# +# _ANTIGEN_BUNDLE_RECORD and fpath is stored in cache. +# +# Usage +# -zcache-generate-cache +# +# Returns +# Nothing. Generates ANTIGEN_CACHE +-antigen-cache-generate () { + local -aU _fpath _PATH _sources + local record + + LOG "Gonna generate cache for $_ZCACHE_BUNDLE_SOURCE" + for record in $_ZCACHE_BUNDLE_SOURCE; do + record=${record:A} + # LOG "Caching $record" + if [[ -f $record ]]; then + # Adding $'\n' as a suffix as j:\n: doesn't work inside a heredoc. + if [[ $_ANTIGEN_THEME_COMPAT == true && "$record" == *.zsh-theme* ]]; then + local compat="${record:A}.antigen-compat" + echo "# Generated by Antigen. Do not edit!" >! "$compat" + cat $record | sed -Ee '/\{$/,/^\}/!{ + s/^local // + }' >>! "$compat" + record="$compat" + fi + _sources+=("source '${record}';"$'\n') + elif [[ -d $record ]]; then + _PATH+=("${record}") + _fpath+=("${record}") + fi + done + +cat > $ANTIGEN_CACHE <! "$ANTIGEN_RSRC" + for rsrc in $ANTIGEN_CHECK_FILES; do + zcompile $rsrc + done + } &! + + return true +} + +# Initializes caching mechanism. +# +# Hooks `antigen-bundle` and `antigen-apply` in order to defer bundle install +# and load. All bundles are loaded from generated cache rather than dynamically +# as these are bundled. +# +# Usage +# -antigen-cache-init +# Returns +# Nothing +-antigen-cache-init () { + if -antigen-interactive-mode; then + return 1 + fi + + _ZCACHE_CAPTURE_PREFIX=${_ZCACHE_CAPTURE_PREFIX:-"--zcache-"} + _ZCACHE_BUNDLE_SOURCE=(); _ZCACHE_CAPTURE_BUNDLE=() + + # Cache auto config files to check for changes (.zshrc, .antigenrc etc) + -antigen-set-default ANTIGEN_AUTO_CONFIG true + + # Default cache path. + -antigen-set-default ANTIGEN_CACHE $ADOTDIR/init.zsh + -antigen-set-default ANTIGEN_RSRC $ADOTDIR/.resources + if [[ $ANTIGEN_CACHE == false ]]; then + return 1 + fi + + return 0 +} + +-antigen-cache-execute () { + # Main function. Deferred antigen-apply. + antigen-apply-cached () { + # TRACE "APPLYING CACHE" EXT + # Auto determine check_files + # There always should be 5 steps from original source as the correct way is to use + # `antigen` wrapper not `antigen-apply` directly and it's called by an extension. + LOG "TRACE: ${funcfiletrace}" + if [[ $ANTIGEN_AUTO_CONFIG == true && $#ANTIGEN_CHECK_FILES -eq 0 ]]; then + ANTIGEN_CHECK_FILES+=(~/.zshrc) + if [[ $#funcfiletrace -ge 6 ]]; then + ANTIGEN_CHECK_FILES+=("${${funcfiletrace[6]%:*}##* }") + fi + fi + + # Generate and compile cache + -antigen-cache-generate + [[ -f "$ANTIGEN_CACHE" ]] && source "$ANTIGEN_CACHE"; + + # Commented out in order to have a working `cache-gen` command + #unset _ZCACHE_BUNDLE_SOURCE + unset _ZCACHE_CAPTURE_BUNDLE _ZCACHE_CAPTURE_FUNCTIONS + + # Release all hooked functions + antigen-remove-hook -antigen-load-env-cached + antigen-remove-hook -antigen-load-source-cached + antigen-remove-hook antigen-bundle-cached + } + + antigen-add-hook antigen-apply antigen-apply-cached post once + + # Defer antigen-bundle. + antigen-bundle-cached () { + _ZCACHE_CAPTURE_BUNDLE+=("${(j: :)${@}}") + } + antigen-add-hook antigen-bundle antigen-bundle-cached pre + + # Defer loading. + -antigen-load-env-cached () { + local bundle + typeset -A bundle; bundle=($@) + local location=${bundle[dir]}/${bundle[loc]} + + # Load to path if there is no sourceable + if [[ ${bundle[loc]} == "/" ]]; then + _ZCACHE_BUNDLE_SOURCE+=("${location}") + return + fi + + _ZCACHE_BUNDLE_SOURCE+=("${location}") + } + antigen-add-hook -antigen-load-env -antigen-load-env-cached replace + + # Defer sourcing. + -antigen-load-source-cached () { + _ZCACHE_BUNDLE_SOURCE+=($@) + } + antigen-add-hook -antigen-load-source -antigen-load-source-cached replace + + return 0 +} + +# Generate static-cache file at $ANTIGEN_CACHE using currently loaded +# bundles from $_ANTIGEN_BUNDLE_RECORD +# +# Usage +# antigen-cache-gen +# +# Returns +# Nothing +antigen-cache-gen () { + -antigen-cache-generate +} +#compdef _antigen +# Setup antigen's autocompletion +_antigen () { + local -a _1st_arguments + _1st_arguments=( + 'apply:Load all bundle completions' + 'bundle:Install and load the given plugin' + 'bundles:Bulk define bundles' + 'cleanup:Clean up the clones of repos which are not used by any bundles currently loaded' + 'cache-gen:Generate cache' + 'init:Load Antigen configuration from file' + 'list:List out the currently loaded bundles' + 'purge:Remove a cloned bundle from filesystem' + 'reset:Clears cache' + 'restore:Restore the bundles state as specified in the snapshot' + 'revert:Revert the state of all bundles to how they were before the last antigen update' + 'selfupdate:Update antigen itself' + 'snapshot:Create a snapshot of all the active clones' + 'theme:Switch the prompt theme' + 'update:Update all bundles' + 'use:Load any (supported) zsh pre-packaged framework' + ); + + _1st_arguments+=( + 'help:Show this message' + 'version:Display Antigen version' + ) + + __bundle() { + _arguments \ + '--loc[Path to the location ]' \ + '--url[Path to the repository ]' \ + '--branch[Git branch name]' \ + '--no-local-clone[Do not create a clone]' + } + __list() { + _arguments \ + '--simple[Show only bundle name]' \ + '--short[Show only bundle name and branch]' \ + '--long[Show bundle records]' + } + + + __cleanup() { + _arguments \ + '--force[Do not ask for confirmation]' + } + + _arguments '*:: :->command' + + if (( CURRENT == 1 )); then + _describe -t commands "antigen command" _1st_arguments + return + fi + + local -a _command_args + case "$words[1]" in + bundle) + __bundle + ;; + use) + compadd "$@" "oh-my-zsh" "prezto" + ;; + cleanup) + __cleanup + ;; + (update|purge) + compadd $(type -f \-antigen-get-bundles &> /dev/null || antigen &> /dev/null; -antigen-get-bundles --simple 2> /dev/null) + ;; + theme) + compadd $(type -f \-antigen-get-themes &> /dev/null || antigen &> /dev/null; -antigen-get-themes 2> /dev/null) + ;; + list) + __list + ;; + esac +} +zmodload zsh/datetime +ANTIGEN_DEBUG_LOG=${ANTIGEN_DEBUG_LOG:-${ADOTDIR:-$HOME/.antigen}/debug.log} +LOG () { + local PREFIX="[LOG][${EPOCHREALTIME}]" + echo "${PREFIX} ${funcfiletrace[1]}\n${PREFIX} $@" >> $ANTIGEN_DEBUG_LOG +} + +ERR () { + local PREFIX="[ERR][${EPOCHREALTIME}]" + echo "${PREFIX} ${funcfiletrace[1]}\n${PREFIX} $@" >> $ANTIGEN_DEBUG_LOG +} + +WARN () { + local PREFIX="[WRN][${EPOCHREALTIME}]" + echo "${PREFIX} ${funcfiletrace[1]}\n${PREFIX} $@" >> $ANTIGEN_DEBUG_LOG +} + +TRACE () { + local PREFIX="[TRA][${EPOCHREALTIME}]" + echo "${PREFIX} ${funcfiletrace[1]}\n${PREFIX} $@\n${PREFIX} ${(j:\n:)funcstack}" >> $ANTIGEN_DEBUG_LOG +} +-antigen-env-setup diff --git a/shell-config/install-zsh.sh b/shell-config/install-zsh.sh new file mode 100755 index 0000000..c5e9fb2 --- /dev/null +++ b/shell-config/install-zsh.sh @@ -0,0 +1,108 @@ +#!/bin/bash +# ORION Infrastructure - Zsh Setup Script +# Installs Oh My Zsh + Antigen + zsh-users plugins + +set -e + +echo "╔═══════════════════════════════════════════════════════════════╗" +echo "β•‘ πŸš€ ORION Infrastructure - Zsh Setup β•‘" +echo "β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•" +echo "" + +# Check if running as root +if [ "$EUID" -ne 0 ]; then + SUDO="sudo" +else + SUDO="" +fi + +# 1. Install Zsh +echo "πŸ“¦ Installing Zsh..." +if ! command -v zsh &> /dev/null; then + if command -v apt-get &> /dev/null; then + $SUDO apt-get update && $SUDO apt-get install -y zsh git curl wget jq + elif command -v yum &> /dev/null; then + $SUDO yum install -y zsh git curl wget jq + elif command -v dnf &> /dev/null; then + $SUDO dnf install -y zsh git curl wget jq + else + echo "❌ Unsupported package manager. Please install zsh manually." + exit 1 + fi +else + echo "βœ… Zsh already installed: $(zsh --version)" +fi + +# 2. Install Oh My Zsh +echo "" +echo "πŸ“¦ Installing Oh My Zsh..." +if [ ! -d "$HOME/.oh-my-zsh" ]; then + sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended + echo "βœ… Oh My Zsh installed" +else + echo "βœ… Oh My Zsh already installed" +fi + +# 3. Install Antigen +echo "" +echo "πŸ“¦ Installing Antigen..." +if [ ! -f "$HOME/antigen.zsh" ]; then + curl -L git.io/antigen > "$HOME/antigen.zsh" + echo "βœ… Antigen installed" +else + echo "βœ… Antigen already installed" +fi + +# 4. Backup existing .zshrc +if [ -f "$HOME/.zshrc" ]; then + echo "" + echo "πŸ“ Backing up existing .zshrc to .zshrc.backup.$(date +%Y%m%d_%H%M%S)" + cp "$HOME/.zshrc" "$HOME/.zshrc.backup.$(date +%Y%m%d_%H%M%S)" +fi + +# 5. Install ORION .zshrc +echo "" +echo "πŸ“ Installing ORION .zshrc configuration..." +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cp "$SCRIPT_DIR/.zshrc" "$HOME/.zshrc" +cp "$SCRIPT_DIR/antigen.zsh" "$HOME/antigen.zsh" +echo "βœ… Configuration installed" + +# 6. Change default shell to zsh (optional) +echo "" +read -p "⚠️ Change default shell to zsh? (requires logout to take effect) [y/N]: " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + if command -v chsh &> /dev/null; then + $SUDO chsh -s $(which zsh) $USER + echo "βœ… Default shell changed to zsh (restart your session)" + else + echo "⚠️ chsh command not found. Add 'exec zsh' to your .bashrc to auto-switch" + fi +fi + +echo "" +echo "╔═══════════════════════════════════════════════════════════════╗" +echo "β•‘ βœ… Installation Complete! β•‘" +echo "β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•" +echo "" +echo "🎯 Next steps:" +echo " 1. Start zsh: zsh" +echo " 2. Or logout and login again if you changed default shell" +echo " 3. Plugins will auto-install on first run" +echo "" +echo "πŸ“š Included features:" +echo " βœ… Oh My Zsh with 14+ plugins" +echo " βœ… Antigen plugin manager" +echo " βœ… zsh-users/zsh-syntax-highlighting" +echo " βœ… zsh-users/zsh-autosuggestions" +echo " βœ… zsh-users/zsh-completions" +echo " βœ… zsh-users/zsh-history-substring-search" +echo " βœ… Custom ORION aliases and functions" +echo "" +echo "πŸ’‘ Try these commands:" +echo " orion-status # Check ORION infrastructure status" +echo " deploy # Quick deploy" +echo " orion # cd to ORION root" +echo " tf, ans, k8s # Navigate to directories" +echo ""