Skip to content

Commit 340e05b

Browse files
committed
docs: add macOS install script for Nucleus demo app
1 parent 8af0015 commit 340e05b

1 file changed

Lines changed: 205 additions & 0 deletions

File tree

docs/install.sh

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
# ─── Config ───────────────────────────────────────────────────────────
6+
repo="kdroidFilter/Nucleus"
7+
app_name="nucleusdemo"
8+
9+
# ─── Colors & Symbols ────────────────────────────────────────────────
10+
BOLD='\033[1m'
11+
DIM='\033[2m'
12+
RESET='\033[0m'
13+
GREEN='\033[1;32m'
14+
CYAN='\033[1;36m'
15+
YELLOW='\033[1;33m'
16+
RED='\033[1;31m'
17+
MAGENTA='\033[1;35m'
18+
BLUE='\033[1;34m'
19+
WHITE='\033[1;37m'
20+
BG_GREEN='\033[42m'
21+
BG_DARK='\033[48;5;236m'
22+
23+
CHECK="${GREEN}${RESET}"
24+
CROSS="${RED}${RESET}"
25+
ARROW="${CYAN}${RESET}"
26+
SPARKLE="${MAGENTA}${RESET}"
27+
28+
# ─── Banner ───────────────────────────────────────────────────────────
29+
print_banner() {
30+
echo ""
31+
echo -e "${CYAN}${BOLD}"
32+
echo " ╔╗╔╦ ╦╔═╗╦ ╔═╗╦ ╦╔═╗"
33+
echo " ║║║║ ║║ ║ ║╣ ║ ║╚═╗"
34+
echo " ╝╚╝╚═╝╚═╝╩═╝╚═╝╚═╝╚═╝"
35+
echo -e "${RESET}"
36+
echo -e " ${DIM}Installer for macOS${RESET}"
37+
echo ""
38+
}
39+
40+
# ─── Helpers ──────────────────────────────────────────────────────────
41+
step() {
42+
echo -e " ${ARROW} ${BOLD}$1${RESET}"
43+
}
44+
45+
success() {
46+
echo -e " ${CHECK} ${GREEN}$1${RESET}"
47+
}
48+
49+
fail() {
50+
echo -e " ${CROSS} ${RED}$1${RESET}"
51+
exit 1
52+
}
53+
54+
spin() {
55+
local pid=$1
56+
local msg=$2
57+
local frames=("" "" "" "" "" "" "" "" "" "")
58+
local i=0
59+
60+
tput civis 2>/dev/null || true
61+
while kill -0 "$pid" 2>/dev/null; do
62+
printf "\r ${CYAN}${frames[$i]}${RESET} ${DIM}%s${RESET}" "$msg"
63+
i=$(( (i + 1) % ${#frames[@]} ))
64+
sleep 0.08
65+
done
66+
printf "\r\033[2K"
67+
tput cnorm 2>/dev/null || true
68+
}
69+
70+
download_with_progress() {
71+
local url="$1"
72+
local output="$2"
73+
local bar_width=40
74+
75+
# Get total file size via HEAD request (follow redirects)
76+
local total_size
77+
total_size=$(curl -sIL "$url" | grep -i '^content-length:' | tail -1 | tr -dc '0-9')
78+
79+
if [ -z "$total_size" ] || [ "$total_size" -eq 0 ]; then
80+
# Fallback: download with spinner if size unknown
81+
curl -sL --output "$output" "$url" &
82+
spin $! "Downloading"
83+
return
84+
fi
85+
86+
# Download silently in background
87+
curl -sL --output "$output" "$url" &
88+
local curl_pid=$!
89+
90+
tput civis 2>/dev/null || true
91+
92+
while kill -0 "$curl_pid" 2>/dev/null; do
93+
if [ -f "$output" ]; then
94+
local current_size
95+
current_size=$(stat -f%z "$output" 2>/dev/null || echo 0)
96+
local pct=$((current_size * 100 / total_size))
97+
[ "$pct" -gt 100 ] && pct=100
98+
local filled=$((pct * bar_width / 100))
99+
local empty=$((bar_width - filled))
100+
local bar=""
101+
for ((j=0; j<filled; j++)); do bar+=""; done
102+
for ((j=0; j<empty; j++)); do bar+=""; done
103+
local mb_done mb_total
104+
mb_done=$(echo "scale=1; $current_size / 1048576" | bc)
105+
mb_total=$(echo "scale=1; $total_size / 1048576" | bc)
106+
printf "\r \033[1;35m✦\033[0m \033[2mDownloading\033[0m \033[1;34m%s\033[0m \033[1;37m%3d%%\033[0m \033[2m(%s / %s MB)\033[0m" "$bar" "$pct" "$mb_done" "$mb_total"
107+
fi
108+
sleep 0.15
109+
done
110+
111+
# Final 100%
112+
local bar=""
113+
for ((j=0; j<bar_width; j++)); do bar+=""; done
114+
local mb_total
115+
mb_total=$(echo "scale=1; $total_size / 1048576" | bc)
116+
printf "\r \033[1;35m✦\033[0m \033[2mDownloading\033[0m \033[1;34m%s\033[0m \033[1;37m100%%\033[0m \033[2m(%s / %s MB)\033[0m" "$bar" "$mb_total" "$mb_total"
117+
echo ""
118+
119+
tput cnorm 2>/dev/null || true
120+
wait "$curl_pid"
121+
}
122+
123+
# ─── Main ─────────────────────────────────────────────────────────────
124+
print_banner
125+
126+
# Resolve latest version
127+
step "Fetching latest release ..."
128+
version=$(curl -sI "https://github.com/${repo}/releases/latest" | grep -i '^location:' | sed 's/.*tag\///' | tr -d '\r\n')
129+
130+
if [ -z "$version" ]; then
131+
fail "Could not determine latest version"
132+
fi
133+
134+
version_number="${version#v}"
135+
success "Found ${BOLD}${YELLOW}${version}${RESET}"
136+
137+
# Detect architecture
138+
arch=$(arch)
139+
if [[ "$arch" == "i386" ]]; then
140+
mac_zip_url="https://github.com/${repo}/releases/download/${version}/${app_name}-${version_number}-mac-x64.zip"
141+
arch_label="Intel (x64)"
142+
elif [[ "$arch" == "arm64" ]]; then
143+
mac_zip_url="https://github.com/${repo}/releases/download/${version}/${app_name}-${version_number}-mac-arm64.zip"
144+
arch_label="Apple Silicon (arm64)"
145+
else
146+
fail "Unsupported CPU architecture: $arch"
147+
fi
148+
149+
success "Architecture: ${BOLD}${arch_label}${RESET}"
150+
echo ""
151+
152+
# Temp directory
153+
tmpdir="$(mktemp -d -t nucleus-install)"
154+
tmpfile="$tmpdir/app.zip"
155+
156+
cleanup() {
157+
cd "$HOME" || true
158+
[ -e "$tmpfile" ] && rm -f "$tmpfile"
159+
rmdir "$tmpdir" 2>/dev/null || true
160+
}
161+
trap cleanup EXIT
162+
163+
# Download
164+
step "Downloading ${YELLOW}${app_name}${RESET} ${DIM}(${version_number})${RESET} ..."
165+
download_with_progress "$mac_zip_url" "$tmpfile"
166+
success "Download complete"
167+
echo ""
168+
169+
# Install location
170+
if [ -w /Applications ]; then
171+
install_dir="/Applications"
172+
else
173+
install_dir="$HOME/Applications"
174+
[ ! -d "$install_dir" ] && mkdir "$install_dir"
175+
fi
176+
177+
if [ -d "${install_dir}/${app_name}.app" ]; then
178+
step "Replacing existing installation ..."
179+
rm -rf "${install_dir}/${app_name}.app"
180+
fi
181+
182+
# Extract
183+
step "Extracting to ${DIM}${install_dir}${RESET} ..."
184+
(cd "$install_dir" && ditto -x -k "$tmpfile" .) &
185+
spin $! "Unpacking application bundle"
186+
success "Installed to ${BOLD}${install_dir}/${app_name}.app${RESET}"
187+
188+
# Remove quarantine
189+
if command -v xattr >/dev/null 2>&1; then
190+
xattr -r -d com.apple.quarantine "${install_dir}/${app_name}.app" 2>/dev/null || true
191+
fi
192+
193+
# Launch
194+
echo ""
195+
step "Launching ${YELLOW}${app_name}${RESET} ..."
196+
open "${install_dir}/${app_name}.app"
197+
success "Application started"
198+
199+
# Done
200+
echo ""
201+
echo -e " ${SPARKLE}${SPARKLE}${SPARKLE} ${GREEN}${BOLD}All done!${RESET} ${SPARKLE}${SPARKLE}${SPARKLE}"
202+
echo ""
203+
204+
cleanup
205+
exit 0

0 commit comments

Comments
 (0)