jekyll-theme-zer0 0.22.0 → 0.22.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +236 -0
  3. data/README.md +66 -19
  4. data/_data/navigation/admin.yml +53 -0
  5. data/_data/theme_backgrounds.yml +121 -0
  6. data/_includes/components/admin-tabs.html +59 -0
  7. data/_includes/components/analytics-dashboard.html +232 -0
  8. data/_includes/components/background-customizer.html +159 -0
  9. data/_includes/components/background-settings.html +137 -0
  10. data/_includes/components/collection-manager.html +151 -0
  11. data/_includes/components/component-showcase.html +452 -0
  12. data/_includes/components/config-editor.html +207 -0
  13. data/_includes/components/config-viewer.html +479 -0
  14. data/_includes/components/env-dashboard.html +154 -0
  15. data/_includes/components/feature-card.html +94 -0
  16. data/_includes/components/info-section.html +172 -149
  17. data/_includes/components/js-cdn.html +4 -1
  18. data/_includes/components/nav-editor.html +99 -0
  19. data/_includes/components/setup-banner.html +28 -0
  20. data/_includes/components/setup-check.html +53 -0
  21. data/_includes/components/svg-background.html +42 -0
  22. data/_includes/components/theme-customizer.html +46 -0
  23. data/_includes/content/seo.html +68 -135
  24. data/_includes/core/footer.html +1 -1
  25. data/_includes/core/head.html +3 -2
  26. data/_includes/core/header.html +14 -7
  27. data/_includes/landing/landing-install-cards.html +18 -7
  28. data/_includes/navigation/admin-nav.html +95 -0
  29. data/_includes/navigation/navbar.html +43 -5
  30. data/_includes/navigation/sidebar-left.html +1 -1
  31. data/_includes/setup/wizard.html +330 -0
  32. data/_layouts/admin.html +166 -0
  33. data/_layouts/landing.html +23 -9
  34. data/_layouts/root.html +12 -6
  35. data/_layouts/setup.html +73 -0
  36. data/_plugins/preview_image_generator.rb +26 -12
  37. data/_sass/core/_navbar.scss +2 -2
  38. data/_sass/custom.scss +28 -6
  39. data/_sass/theme/_background-mixins.scss +95 -0
  40. data/_sass/theme/_backgrounds.scss +156 -0
  41. data/_sass/theme/_color-modes.scss +2 -1
  42. data/assets/backgrounds/gradients/air.svg +15 -0
  43. data/assets/backgrounds/gradients/aqua.svg +15 -0
  44. data/assets/backgrounds/gradients/contrast.svg +15 -0
  45. data/assets/backgrounds/gradients/dark.svg +15 -0
  46. data/assets/backgrounds/gradients/dirt.svg +15 -0
  47. data/assets/backgrounds/gradients/mint.svg +15 -0
  48. data/assets/backgrounds/gradients/neon.svg +15 -0
  49. data/assets/backgrounds/gradients/plum.svg +15 -0
  50. data/assets/backgrounds/gradients/sunrise.svg +15 -0
  51. data/assets/backgrounds/noise/air.svg +8 -0
  52. data/assets/backgrounds/noise/aqua.svg +8 -0
  53. data/assets/backgrounds/noise/contrast.svg +8 -0
  54. data/assets/backgrounds/noise/dark.svg +8 -0
  55. data/assets/backgrounds/noise/dirt.svg +8 -0
  56. data/assets/backgrounds/noise/mint.svg +8 -0
  57. data/assets/backgrounds/noise/neon.svg +8 -0
  58. data/assets/backgrounds/noise/plum.svg +8 -0
  59. data/assets/backgrounds/noise/sunrise.svg +8 -0
  60. data/assets/backgrounds/patterns/air.svg +7 -0
  61. data/assets/backgrounds/patterns/aqua.svg +7 -0
  62. data/assets/backgrounds/patterns/contrast.svg +4 -0
  63. data/assets/backgrounds/patterns/dark.svg +5 -0
  64. data/assets/backgrounds/patterns/dirt.svg +5 -0
  65. data/assets/backgrounds/patterns/mint.svg +6 -0
  66. data/assets/backgrounds/patterns/neon.svg +6 -0
  67. data/assets/backgrounds/patterns/plum.svg +6 -0
  68. data/assets/backgrounds/patterns/sunrise.svg +5 -0
  69. data/assets/js/background-customizer.js +73 -0
  70. data/assets/js/code-copy.js +18 -47
  71. data/assets/js/config-utility.js +307 -0
  72. data/assets/js/nav-editor.js +39 -0
  73. data/assets/js/palette-generator.js +415 -0
  74. data/assets/js/search-modal.js +31 -11
  75. data/assets/js/setup-wizard.js +306 -0
  76. data/assets/js/skin-editor.js +645 -0
  77. data/assets/js/theme-customizer.js +102 -0
  78. data/assets/js/ui-enhancements.js +15 -24
  79. data/assets/vendor/bootstrap/css/bootstrap.min.css +1 -0
  80. data/assets/vendor/bootstrap/js/bootstrap.bundle.min.js +1 -0
  81. data/scripts/README.md +45 -0
  82. data/scripts/features/generate-preview-images +297 -7
  83. data/scripts/features/install-preview-generator +51 -33
  84. data/scripts/fork-cleanup.sh +92 -19
  85. data/scripts/github-setup.sh +284 -0
  86. data/scripts/init_setup.sh +0 -1
  87. data/scripts/lib/frontmatter.sh +543 -0
  88. data/scripts/lib/migrate.sh +265 -0
  89. data/scripts/lib/preview_generator.py +607 -32
  90. data/scripts/lint-pages +505 -0
  91. data/scripts/migrate.sh +201 -0
  92. data/scripts/platform/setup-linux.sh +244 -0
  93. data/scripts/platform/setup-macos.sh +187 -0
  94. data/scripts/platform/setup-wsl.sh +196 -0
  95. metadata +71 -6
@@ -0,0 +1,201 @@
1
+ #!/bin/bash
2
+
3
+ # =========================================================================
4
+ # Zer0-Mistakes Theme — Migration Utility
5
+ # =========================================================================
6
+ # Install optional theme features (admin settings UI, etc.) into a
7
+ # consumer Jekyll site that uses the zer0-mistakes theme.
8
+ #
9
+ # Usage:
10
+ # ./scripts/migrate.sh [options] [target_dir]
11
+ #
12
+ # Options:
13
+ # --admin Install admin settings pages (default action)
14
+ # --force Overwrite existing files
15
+ # --verify Verify an existing installation
16
+ # --dry-run Show what would be done without making changes
17
+ # --verbose Enable verbose output
18
+ # --non-interactive Skip confirmation prompts
19
+ # -h, --help Show this help message
20
+ #
21
+ # Examples:
22
+ # # Install admin pages into current directory
23
+ # ./scripts/migrate.sh .
24
+ #
25
+ # # Install into another site with force overwrite
26
+ # ./scripts/migrate.sh --force /path/to/my-site
27
+ #
28
+ # # Verify existing installation
29
+ # ./scripts/migrate.sh --verify /path/to/my-site
30
+ #
31
+ # # Preview changes without writing
32
+ # ./scripts/migrate.sh --dry-run /path/to/my-site
33
+ # =========================================================================
34
+
35
+ set -euo pipefail
36
+
37
+ # -------------------------------------------------------------------------
38
+ # Resolve script location and load libraries
39
+ # -------------------------------------------------------------------------
40
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
41
+
42
+ # Source shared libraries
43
+ # shellcheck source=lib/common.sh
44
+ source "$SCRIPT_DIR/lib/common.sh"
45
+ # shellcheck source=lib/template.sh
46
+ source "$SCRIPT_DIR/lib/template.sh"
47
+ # shellcheck source=lib/migrate.sh
48
+ source "$SCRIPT_DIR/lib/migrate.sh"
49
+
50
+ # -------------------------------------------------------------------------
51
+ # Defaults
52
+ # -------------------------------------------------------------------------
53
+ ACTION="install" # install | verify
54
+ INSTALL_ADMIN=true
55
+ FORCE=false
56
+ TARGET_DIR=""
57
+
58
+ # -------------------------------------------------------------------------
59
+ # Usage
60
+ # -------------------------------------------------------------------------
61
+ usage() {
62
+ cat <<EOF
63
+ Usage: $(basename "$0") [options] [target_dir]
64
+
65
+ Install optional zer0-mistakes theme features into a consumer Jekyll site.
66
+
67
+ Options:
68
+ --admin Install admin settings pages (default)
69
+ --force Overwrite existing files
70
+ --verify Verify an existing installation
71
+ --dry-run Show what would be done without writing files
72
+ --verbose Enable verbose/debug output
73
+ --non-interactive Skip confirmation prompts
74
+ -h, --help Show this help message
75
+
76
+ Arguments:
77
+ target_dir Path to the Jekyll site (default: current directory)
78
+
79
+ Examples:
80
+ $(basename "$0") . # Install admin pages here
81
+ $(basename "$0") --force ../my-site # Force overwrite in another site
82
+ $(basename "$0") --verify . # Verify current installation
83
+ $(basename "$0") --dry-run ../my-site # Preview changes
84
+ EOF
85
+ exit 0
86
+ }
87
+
88
+ # -------------------------------------------------------------------------
89
+ # Parse arguments
90
+ # -------------------------------------------------------------------------
91
+ while [[ $# -gt 0 ]]; do
92
+ case "$1" in
93
+ --admin) INSTALL_ADMIN=true; shift ;;
94
+ --force) FORCE=true; shift ;;
95
+ --verify) ACTION="verify"; shift ;;
96
+ --dry-run) DRY_RUN=true; shift ;;
97
+ --verbose) VERBOSE=true; shift ;;
98
+ --non-interactive) INTERACTIVE=false; shift ;;
99
+ -h|--help) usage ;;
100
+ -*) error "Unknown option: $1" ;;
101
+ *) TARGET_DIR="$1"; shift ;;
102
+ esac
103
+ done
104
+
105
+ TARGET_DIR="${TARGET_DIR:-.}"
106
+ TARGET_DIR="$(cd "$TARGET_DIR" 2>/dev/null && pwd)" || error "Directory not found: $TARGET_DIR"
107
+
108
+ # -------------------------------------------------------------------------
109
+ # Main
110
+ # -------------------------------------------------------------------------
111
+
112
+ main() {
113
+ echo ""
114
+ echo "╔══════════════════════════════════════════════════╗"
115
+ echo "║ Zer0-Mistakes Theme — Migration Utility ║"
116
+ echo "╚══════════════════════════════════════════════════╝"
117
+ echo ""
118
+
119
+ info "Target site: $TARGET_DIR"
120
+ [[ "$DRY_RUN" == "true" ]] && info "Mode: DRY RUN (no files will be written)"
121
+ echo ""
122
+
123
+ # --- Step 1: Validate target ---
124
+ step "Detecting Jekyll site..."
125
+ if ! detect_jekyll_site "$TARGET_DIR"; then
126
+ error "Target does not appear to be a Jekyll site: $TARGET_DIR"
127
+ fi
128
+ success "Jekyll site detected"
129
+
130
+ # --- Step 2: Check theme connection ---
131
+ step "Checking theme connection..."
132
+ if validate_theme_connection "$TARGET_DIR"; then
133
+ success "Theme connection: $THEME_CONNECTION_TYPE"
134
+ else
135
+ warn "Could not confirm zer0-mistakes theme connection."
136
+ warn "Admin pages require the zer0-mistakes theme (layout: admin, includes, JS/CSS)."
137
+ if [[ "$INTERACTIVE" == "true" ]]; then
138
+ if ! confirm "Continue anyway?"; then
139
+ info "Aborted."
140
+ exit 0
141
+ fi
142
+ fi
143
+ fi
144
+
145
+ # --- Step 3: Check theme version ---
146
+ detect_version_gap "$TARGET_DIR" || true
147
+
148
+ # --- Step 4: Load template config ---
149
+ step "Loading template configuration..."
150
+ load_config || true
151
+ export CURRENT_DATE="${CURRENT_DATE:-$(date +%Y-%m-%d)}"
152
+
153
+ # --- Step 5: Execute action ---
154
+ case "$ACTION" in
155
+ install)
156
+ if [[ "$INSTALL_ADMIN" == "true" ]]; then
157
+ echo ""
158
+ if [[ "$FORCE" == "true" ]]; then
159
+ info "Force mode enabled — existing files will be overwritten"
160
+ fi
161
+
162
+ if [[ "$INTERACTIVE" == "true" ]] && [[ "$DRY_RUN" != "true" ]]; then
163
+ echo ""
164
+ info "This will install admin settings pages to:"
165
+ info " $TARGET_DIR/$ADMIN_OUTPUT_DIR/"
166
+ echo ""
167
+ if ! confirm "Proceed with installation?"; then
168
+ info "Aborted."
169
+ exit 0
170
+ fi
171
+ fi
172
+
173
+ install_admin_pages "$TARGET_DIR" "$FORCE"
174
+ fi
175
+ ;;
176
+ verify)
177
+ verify_admin_pages "$TARGET_DIR"
178
+ ;;
179
+ esac
180
+
181
+ # --- Step 6: Summary ---
182
+ echo ""
183
+ echo "────────────────────────────────────────────────────"
184
+ if [[ "$ACTION" == "install" ]]; then
185
+ success "Migration complete!"
186
+ echo ""
187
+ info "Next steps:"
188
+ info " 1. Start your Jekyll server and visit the admin pages"
189
+ info " 2. Theme Customizer: /about/settings/theme/"
190
+ info " 3. Configuration: /about/config/"
191
+ info " 4. Navigation Editor: /about/settings/navigation/"
192
+ info " 5. Collection Manager:/about/settings/collections/"
193
+ info " 6. Analytics: /about/settings/analytics/"
194
+ info " 7. Environment: /about/settings/environment/"
195
+ else
196
+ success "Verification complete."
197
+ fi
198
+ echo ""
199
+ }
200
+
201
+ main
@@ -0,0 +1,244 @@
1
+ #!/bin/bash
2
+ # =========================================================================
3
+ # Zer0-Mistakes Platform Setup: Linux
4
+ # =========================================================================
5
+ # Detects distro and installs prerequisites for Linux.
6
+ # Supports Debian/Ubuntu (apt), Fedora/RHEL (dnf), and Arch (pacman).
7
+ #
8
+ # Usage: source scripts/platform/setup-linux.sh
9
+ # setup_linux [--install-missing]
10
+ # =========================================================================
11
+
12
+ # Only enable strict mode when executed directly (not sourced), so we don't
13
+ # mutate the caller's shell options.
14
+ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
15
+ set -euo pipefail
16
+ fi
17
+
18
+ # ── Fallback logging helpers (used when not sourced from install.sh) ─────
19
+ if ! declare -F log_info >/dev/null 2>&1; then
20
+ log_info() { echo "[INFO] $*"; }
21
+ log_success() { echo "[SUCCESS] $*"; }
22
+ log_warning() { echo "[WARNING] $*"; }
23
+ log_error() { echo "[ERROR] $*" >&2; }
24
+ fi
25
+
26
+ # -------------------------------------------------------------------------
27
+ # Detect Linux distribution
28
+ # -------------------------------------------------------------------------
29
+ detect_linux_distro() {
30
+ if [[ -f /etc/os-release ]]; then
31
+ # shellcheck source=/dev/null
32
+ source /etc/os-release
33
+ case "$ID" in
34
+ ubuntu|debian|pop|linuxmint|elementary)
35
+ echo "debian"
36
+ ;;
37
+ fedora|rhel|centos|rocky|alma)
38
+ echo "fedora"
39
+ ;;
40
+ arch|manjaro|endeavouros)
41
+ echo "arch"
42
+ ;;
43
+ opensuse*|sles)
44
+ echo "suse"
45
+ ;;
46
+ *)
47
+ echo "unknown"
48
+ ;;
49
+ esac
50
+ else
51
+ echo "unknown"
52
+ fi
53
+ }
54
+
55
+ get_distro_name() {
56
+ if [[ -f /etc/os-release ]]; then
57
+ # shellcheck source=/dev/null
58
+ source /etc/os-release
59
+ echo "${PRETTY_NAME:-Linux}"
60
+ else
61
+ echo "Linux"
62
+ fi
63
+ }
64
+
65
+ # -------------------------------------------------------------------------
66
+ # Check prerequisites
67
+ # -------------------------------------------------------------------------
68
+ check_git_linux() {
69
+ command -v git &>/dev/null
70
+ }
71
+
72
+ check_docker_linux() {
73
+ command -v docker &>/dev/null && docker info &>/dev/null 2>&1
74
+ }
75
+
76
+ check_docker_installed_linux() {
77
+ command -v docker &>/dev/null
78
+ }
79
+
80
+ check_docker_compose_linux() {
81
+ # Docker Compose v2 (plugin) or v1 (standalone)
82
+ docker compose version &>/dev/null 2>&1 || command -v docker-compose &>/dev/null
83
+ }
84
+
85
+ check_ruby_linux() {
86
+ command -v ruby &>/dev/null && [[ "$(ruby -e 'puts RUBY_VERSION')" > "3.0" ]]
87
+ }
88
+
89
+ # -------------------------------------------------------------------------
90
+ # Install prerequisites by distro
91
+ # -------------------------------------------------------------------------
92
+ install_git_linux() {
93
+ local distro
94
+ distro="$(detect_linux_distro)"
95
+ case "$distro" in
96
+ debian) sudo apt-get update -qq && sudo apt-get install -y -qq git ;;
97
+ fedora) sudo dnf install -y git ;;
98
+ arch) sudo pacman -S --noconfirm git ;;
99
+ suse) sudo zypper install -y git ;;
100
+ *) log_error "Unsupported distro. Install git manually."; return 1 ;;
101
+ esac
102
+ }
103
+
104
+ install_docker_linux() {
105
+ local distro
106
+ distro="$(detect_linux_distro)"
107
+
108
+ log_info "Installing Docker Engine..."
109
+ case "$distro" in
110
+ debian)
111
+ # Determine the correct distro ID for the Docker repo URL
112
+ local docker_distro_id
113
+ # shellcheck source=/dev/null
114
+ docker_distro_id="$(. /etc/os-release 2>/dev/null && echo "${ID:-ubuntu}")"
115
+ # Docker only publishes repos for 'ubuntu' and 'debian'; other
116
+ # derivatives (pop, linuxmint, etc.) should use their base distro.
117
+ case "$docker_distro_id" in
118
+ debian) ;; # already 'debian', use Docker's debian repo
119
+ *) docker_distro_id="ubuntu" ;; # fallback for Ubuntu derivatives
120
+ esac
121
+
122
+ sudo apt-get update -qq
123
+ sudo apt-get install -y -qq ca-certificates curl gnupg
124
+ sudo install -m 0755 -d /etc/apt/keyrings
125
+ curl -fsSL "https://download.docker.com/linux/${docker_distro_id}/gpg" | \
126
+ sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 2>/dev/null || true
127
+ sudo chmod a+r /etc/apt/keyrings/docker.gpg
128
+ # shellcheck source=/dev/null
129
+ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/${docker_distro_id} $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
130
+ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
131
+ sudo apt-get update -qq
132
+ sudo apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
133
+ ;;
134
+ fedora)
135
+ sudo dnf -y install dnf-plugins-core
136
+ sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
137
+ sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
138
+ ;;
139
+ arch)
140
+ sudo pacman -S --noconfirm docker docker-compose
141
+ ;;
142
+ *)
143
+ log_error "Auto-install not supported for this distro."
144
+ log_info "See https://docs.docker.com/engine/install/ for manual instructions."
145
+ return 1
146
+ ;;
147
+ esac
148
+
149
+ # Start Docker and enable on boot
150
+ sudo systemctl start docker 2>/dev/null || true
151
+ sudo systemctl enable docker 2>/dev/null || true
152
+
153
+ # Add current user to docker group (avoids sudo)
154
+ if ! groups | grep -q docker; then
155
+ sudo usermod -aG docker "$USER"
156
+ log_warning "Added $USER to docker group. Log out and back in for this to take effect."
157
+ log_info "Or run: newgrp docker"
158
+ fi
159
+ }
160
+
161
+ install_ruby_linux() {
162
+ local distro
163
+ distro="$(detect_linux_distro)"
164
+ case "$distro" in
165
+ debian) sudo apt-get install -y -qq ruby-full build-essential ;;
166
+ fedora) sudo dnf install -y ruby ruby-devel gcc make ;;
167
+ arch) sudo pacman -S --noconfirm ruby base-devel ;;
168
+ *) log_info "Install Ruby 3.0+ manually for your distribution." ;;
169
+ esac
170
+ }
171
+
172
+ # -------------------------------------------------------------------------
173
+ # Main setup function
174
+ # -------------------------------------------------------------------------
175
+ setup_linux() {
176
+ local install_missing="${1:-false}"
177
+ local distro
178
+ distro="$(detect_linux_distro)"
179
+ local distro_name
180
+ distro_name="$(get_distro_name)"
181
+ local all_ok=true
182
+
183
+ log_info "Linux detected: ${distro_name} (family: ${distro})"
184
+ echo
185
+
186
+ # --- Git ---
187
+ if check_git_linux; then
188
+ log_success "Git: $(git --version)"
189
+ else
190
+ log_warning "Git: not installed"
191
+ if [[ "$install_missing" == "--install-missing" ]]; then
192
+ install_git_linux
193
+ else
194
+ log_info " Install: sudo apt-get install git (or equivalent)"
195
+ all_ok=false
196
+ fi
197
+ fi
198
+
199
+ # --- Docker ---
200
+ if check_docker_linux; then
201
+ log_success "Docker: $(docker --version)"
202
+ elif check_docker_installed_linux; then
203
+ log_warning "Docker: installed but daemon not running"
204
+ log_info " Start: sudo systemctl start docker"
205
+ all_ok=false
206
+ else
207
+ log_warning "Docker: not installed"
208
+ if [[ "$install_missing" == "--install-missing" ]]; then
209
+ install_docker_linux
210
+ else
211
+ log_info " Install: https://docs.docker.com/engine/install/"
212
+ all_ok=false
213
+ fi
214
+ fi
215
+
216
+ # --- Docker Compose ---
217
+ if check_docker_compose_linux; then
218
+ log_success "Docker Compose: available"
219
+ else
220
+ log_warning "Docker Compose: not found (installed with Docker Engine on most distros)"
221
+ all_ok=false
222
+ fi
223
+
224
+ # --- Ruby (optional) ---
225
+ if check_ruby_linux; then
226
+ log_success "Ruby: $(ruby --version)"
227
+ else
228
+ log_info "Ruby 3.0+: not found (only needed for native development, Docker works without it)"
229
+ fi
230
+
231
+ echo
232
+ if [[ "$all_ok" == true ]]; then
233
+ log_success "All Linux prerequisites satisfied."
234
+ return 0
235
+ else
236
+ log_warning "Some prerequisites are missing. Use --install-missing to auto-install."
237
+ return 1
238
+ fi
239
+ }
240
+
241
+ # ── Entrypoint (when executed directly, not sourced) ─────────────────────
242
+ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
243
+ setup_linux "$@"
244
+ fi
@@ -0,0 +1,187 @@
1
+ #!/bin/bash
2
+ # =========================================================================
3
+ # Zer0-Mistakes Platform Setup: macOS
4
+ # =========================================================================
5
+ # Detects and installs prerequisites for macOS (Intel & Apple Silicon).
6
+ # Called by install.sh during platform detection phase.
7
+ #
8
+ # Usage: source scripts/platform/setup-macos.sh
9
+ # setup_macos [--install-missing]
10
+ # =========================================================================
11
+
12
+ # Only enable strict mode when executed directly (not sourced), so we don't
13
+ # mutate the caller's shell options.
14
+ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
15
+ set -euo pipefail
16
+ fi
17
+
18
+ # ── Fallback logging helpers (used when not sourced from install.sh) ─────
19
+ if ! declare -F log_info >/dev/null 2>&1; then
20
+ log_info() { echo "[INFO] $*"; }
21
+ log_success() { echo "[SUCCESS] $*"; }
22
+ log_warning() { echo "[WARNING] $*"; }
23
+ log_error() { echo "[ERROR] $*" >&2; }
24
+ fi
25
+
26
+ # -------------------------------------------------------------------------
27
+ # Detect macOS architecture
28
+ # -------------------------------------------------------------------------
29
+ detect_macos_arch() {
30
+ local arch
31
+ arch="$(uname -m)"
32
+ case "$arch" in
33
+ arm64) echo "apple-silicon" ;;
34
+ x86_64) echo "intel" ;;
35
+ *) echo "unknown" ;;
36
+ esac
37
+ }
38
+
39
+ # -------------------------------------------------------------------------
40
+ # Check if Homebrew is installed
41
+ # -------------------------------------------------------------------------
42
+ check_homebrew() {
43
+ if command -v brew &>/dev/null; then
44
+ return 0
45
+ fi
46
+ return 1
47
+ }
48
+
49
+ install_homebrew() {
50
+ log_info "Installing Homebrew..."
51
+ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
52
+
53
+ # Add Homebrew to PATH for Apple Silicon
54
+ if [[ "$(detect_macos_arch)" == "apple-silicon" ]]; then
55
+ eval "$(/opt/homebrew/bin/brew shellenv)"
56
+ fi
57
+ }
58
+
59
+ # -------------------------------------------------------------------------
60
+ # Check individual prerequisites
61
+ # -------------------------------------------------------------------------
62
+ check_git_macos() {
63
+ command -v git &>/dev/null
64
+ }
65
+
66
+ check_docker_macos() {
67
+ command -v docker &>/dev/null && docker info &>/dev/null 2>&1
68
+ }
69
+
70
+ check_docker_installed_macos() {
71
+ command -v docker &>/dev/null
72
+ }
73
+
74
+ check_ruby_macos() {
75
+ command -v ruby &>/dev/null && [[ "$(ruby -e 'puts RUBY_VERSION')" > "3.0" ]]
76
+ }
77
+
78
+ # -------------------------------------------------------------------------
79
+ # Install prerequisites
80
+ # -------------------------------------------------------------------------
81
+ install_git_macos() {
82
+ if check_homebrew; then
83
+ brew install git
84
+ else
85
+ log_info "Install Xcode Command Line Tools for git:"
86
+ xcode-select --install 2>/dev/null || true
87
+ fi
88
+ }
89
+
90
+ install_docker_macos() {
91
+ if check_homebrew; then
92
+ log_info "Installing Docker Desktop via Homebrew..."
93
+ brew install --cask docker
94
+ log_warning "Docker Desktop installed. Please open it from Applications to complete setup."
95
+ log_info "After Docker Desktop starts, re-run this installer."
96
+ else
97
+ log_info "Download Docker Desktop from: https://www.docker.com/products/docker-desktop"
98
+ log_info "Choose the $(detect_macos_arch) version for your Mac."
99
+ fi
100
+ }
101
+
102
+ install_ruby_macos() {
103
+ if check_homebrew; then
104
+ log_info "Installing Ruby via Homebrew..."
105
+ brew install ruby
106
+ log_info "Add Ruby to PATH: export PATH=\"/opt/homebrew/opt/ruby/bin:\$PATH\""
107
+ else
108
+ log_info "Install Homebrew first, then run: brew install ruby"
109
+ fi
110
+ }
111
+
112
+ # -------------------------------------------------------------------------
113
+ # Main setup function
114
+ # -------------------------------------------------------------------------
115
+ setup_macos() {
116
+ local install_missing="${1:-false}"
117
+ local arch
118
+ arch="$(detect_macos_arch)"
119
+ local all_ok=true
120
+
121
+ log_info "macOS detected (${arch})"
122
+ echo
123
+
124
+ # --- Homebrew ---
125
+ if check_homebrew; then
126
+ log_success "Homebrew: $(brew --version | head -1)"
127
+ else
128
+ log_warning "Homebrew: not installed"
129
+ if [[ "$install_missing" == "--install-missing" ]]; then
130
+ install_homebrew
131
+ else
132
+ log_info " Install: /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
133
+ all_ok=false
134
+ fi
135
+ fi
136
+
137
+ # --- Git ---
138
+ if check_git_macos; then
139
+ log_success "Git: $(git --version)"
140
+ else
141
+ log_warning "Git: not installed"
142
+ if [[ "$install_missing" == "--install-missing" ]]; then
143
+ install_git_macos
144
+ else
145
+ log_info " Install: brew install git"
146
+ all_ok=false
147
+ fi
148
+ fi
149
+
150
+ # --- Docker ---
151
+ if check_docker_macos; then
152
+ log_success "Docker: $(docker --version)"
153
+ elif check_docker_installed_macos; then
154
+ log_warning "Docker: installed but not running"
155
+ log_info " Start Docker Desktop from Applications, then re-run."
156
+ all_ok=false
157
+ else
158
+ log_warning "Docker: not installed"
159
+ if [[ "$install_missing" == "--install-missing" ]]; then
160
+ install_docker_macos
161
+ else
162
+ log_info " Install: brew install --cask docker"
163
+ all_ok=false
164
+ fi
165
+ fi
166
+
167
+ # --- Ruby (optional — only needed for non-Docker) ---
168
+ if check_ruby_macos; then
169
+ log_success "Ruby: $(ruby --version)"
170
+ else
171
+ log_info "Ruby 3.0+: not found (only needed for native development, Docker works without it)"
172
+ fi
173
+
174
+ echo
175
+ if [[ "$all_ok" == true ]]; then
176
+ log_success "All macOS prerequisites satisfied."
177
+ return 0
178
+ else
179
+ log_warning "Some prerequisites are missing. Use --install-missing to auto-install."
180
+ return 1
181
+ fi
182
+ }
183
+
184
+ # ── Entrypoint (when executed directly, not sourced) ─────────────────────
185
+ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
186
+ setup_macos "$@"
187
+ fi