File size: 11,178 Bytes
a1efcaf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
#!/usr/bin/env bash
# ---------------------------------------------------------------------------
# DEX Studio β€” System Dependencies Installer
# ---------------------------------------------------------------------------
# Installs all Linux/macOS system-level packages required to develop and
# run DEX Studio, including the pywebview native-window backend (GTK/WebKit
# on Linux, WebKit on macOS β€” bundled).
#
# Usage:
#   uv run poe setup-system          # via poe task (recommended)
#   bash scripts/setup-system.sh     # direct execution
#
# Supports: Ubuntu/Debian, Fedora/RHEL, Arch Linux, macOS (Homebrew)
# ---------------------------------------------------------------------------

set -euo pipefail

# ── Colour helpers ──────────────────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m' # No Colour

info()  { echo -e "${CYAN}[INFO]${NC}  $*"; }
ok()    { echo -e "${GREEN}[OK]${NC}    $*"; }
warn()  { echo -e "${YELLOW}[WARN]${NC}  $*"; }
fail()  { echo -e "${RED}[FAIL]${NC}  $*"; }

# ── Sudo pre-check ─────────────────────────────────────────────────────────
ensure_sudo() {
    if [[ "$OS" == "macos" ]]; then
        return 0  # Homebrew doesn't need sudo
    fi

    if [[ $EUID -eq 0 ]]; then
        return 0  # Already root
    fi

    # Not root β€” print the command and exit
    echo ""
    warn "This script needs root to install system packages."
    echo ""
    info "Run directly:"
    echo ""
    echo "    sudo bash scripts/setup-system.sh"
    echo ""
    exit 1
}

# ── Detect OS / package manager ────────────────────────────────────────────
detect_os() {
    if [[ "$OSTYPE" == "darwin"* ]]; then
        OS="macos"
    elif command -v apt-get &>/dev/null; then
        OS="debian"
    elif command -v dnf &>/dev/null; then
        OS="fedora"
    elif command -v pacman &>/dev/null; then
        OS="arch"
    else
        fail "Unsupported OS. Install the packages listed below manually."
        echo ""
        echo "Required packages:"
        echo "  - git, curl, build tools (gcc, make)"
        echo "  - Python 3.11+"
        echo "  - GTK 3/4 + WebKitGTK + PyGObject (for pywebview native mode)"
        echo ""
        echo "  OR skip native mode and run in browser:"
        echo "    dex-studio --no-native"
        echo ""
        exit 1
    fi
}

# ── Package lists per OS ───────────────────────────────────────────────────

install_debian() {
    info "Updating apt package index..."
    sudo apt-get update -qq

    info "Installing core build tools..."
    sudo apt-get install -y --no-install-recommends \
        git \
        curl \
        ca-certificates \
        build-essential \
        libffi-dev \
        libssl-dev \
        pkg-config

    info "Installing GTK + WebKitGTK + PyGObject (pywebview backend)..."
    sudo apt-get install -y --no-install-recommends \
        python3-gi \
        python3-gi-cairo \
        gir1.2-gtk-3.0 \
        gir1.2-webkit2-4.1 \
        libgirepository1.0-dev \
        libcairo2-dev

    info "Installing additional Python development headers..."
    sudo apt-get install -y --no-install-recommends \
        python3-dev
}

install_fedora() {
    info "Installing core build tools..."
    sudo dnf install -y \
        git \
        curl \
        gcc \
        gcc-c++ \
        make \
        libffi-devel \
        openssl-devel \
        pkg-config

    info "Installing GTK + WebKitGTK + PyGObject (pywebview backend)..."
    sudo dnf install -y \
        python3-gobject \
        gtk3 \
        webkit2gtk4.1 \
        gobject-introspection-devel \
        cairo-gobject-devel

    info "Installing additional Python development headers..."
    sudo dnf install -y \
        python3-devel
}

install_arch() {
    info "Installing core build tools..."
    sudo pacman -Syu --noconfirm \
        git \
        curl \
        base-devel \
        openssl \
        pkgconf

    info "Installing GTK + WebKitGTK + PyGObject (pywebview backend)..."
    sudo pacman -S --noconfirm \
        python-gobject \
        gtk3 \
        webkit2gtk-4.1 \
        gobject-introspection \
        cairo
}

install_macos() {
    if ! command -v brew &>/dev/null; then
        fail "Homebrew not found. Install from https://brew.sh"
        exit 1
    fi

    info "Installing core packages via Homebrew..."
    brew install git curl

    # macOS uses native WebKit β€” no GTK needed
    # pywebview uses pyobjc (installed via pip/uv as a Python dependency)
    info "Installing PyObjC bridge for macOS native window..."
    ok "macOS uses built-in WebKit β€” no GTK/QT needed for pywebview"
    ok "pyobjc will be installed automatically via 'uv sync'"
}

# ── Install uv (if not present) ───────────────────────────────────────────
install_uv() {
    # Check as the real user, not root
    local real_user="${SUDO_USER:-$USER}"

    if command -v uv &>/dev/null; then
        ok "uv already installed ($(uv --version))"
        return 0
    fi

    # Also check the real user's PATH (uv installs to ~/.local/bin)
    local user_uv="$(eval echo ~"$real_user")/.local/bin/uv"
    if [[ -x "$user_uv" ]]; then
        ok "uv already installed at $user_uv"
        return 0
    fi

    info "Installing uv for user $real_user..."
    if [[ $EUID -eq 0 && -n "${SUDO_USER:-}" ]]; then
        # Running as root via sudo β€” install as the calling user so uv
        # lands in ~user/.local/bin, not /root/.local/bin
        sudo -u "$SUDO_USER" bash -c 'curl -LsSf https://astral.sh/uv/install.sh | sh'
    else
        curl -LsSf https://astral.sh/uv/install.sh | sh
    fi
    ok "uv installed"
}

# ── Python deps ────────────────────────────────────────────────────────────
install_python_deps() {
    echo ""
    local real_user="${SUDO_USER:-$USER}"
    local user_uv="$(eval echo ~"$real_user")/.local/bin/uv"

    # Resolve a working uv binary (might not be in root's PATH)
    local uv_bin=""
    if command -v uv &>/dev/null; then
        uv_bin="uv"
    elif [[ -x "$user_uv" ]]; then
        uv_bin="$user_uv"
    fi

    if [[ -z "$uv_bin" ]]; then
        warn "uv not found β€” run 'curl -LsSf https://astral.sh/uv/install.sh | sh' then 'uv sync'"
        return 0
    fi

    info "Installing Python dependencies via uv..."
    if [[ $EUID -eq 0 && -n "${SUDO_USER:-}" ]]; then
        # Run uv sync as the real user so deps go into the project venv, not root's
        sudo -u "$SUDO_USER" "$uv_bin" sync --all-groups
    else
        "$uv_bin" sync --all-groups
    fi
    ok "Python dependencies installed"
}

# ── Verification ───────────────────────────────────────────────────────────
verify() {
    echo ""
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    info "Verifying installation..."
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    local status=0
    local real_user="${SUDO_USER:-$USER}"
    local user_uv="$(eval echo ~"$real_user")/.local/bin/uv"

    # Required tools
    for cmd in git curl python3; do
        if command -v "$cmd" &>/dev/null; then
            ver=$("$cmd" --version 2>&1 | head -1)
            ok "$cmd β€” $ver"
        else
            fail "$cmd β€” NOT FOUND"
            status=1
        fi
    done

    # uv β€” check both system PATH and user's ~/.local/bin
    if command -v uv &>/dev/null; then
        ok "uv β€” $(uv --version 2>&1 | head -1)"
    elif [[ -x "$user_uv" ]]; then
        ok "uv β€” $("$user_uv" --version 2>&1 | head -1) (at $user_uv)"
    else
        fail "uv β€” NOT FOUND"
        status=1
    fi

    # Python version check
    python_ver=$(python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" 2>/dev/null || echo "unknown")
    if [[ "$python_ver" < "3.11" ]]; then
        fail "Python $python_ver found β€” requires 3.11+"
        status=1
    else
        ok "Python version β€” $python_ver"
    fi

    # pywebview native backend check
    if [[ "$OS" != "macos" ]]; then
        if python3 -c "import gi" &>/dev/null 2>&1; then
            ok "PyGObject (gi) β€” available"
        else
            warn "PyGObject (gi) β€” not importable (native mode will fall back to browser)"
        fi
    else
        ok "macOS β€” native WebKit available"
    fi

    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

    if [[ $status -eq 0 ]]; then
        echo ""
        ok "All system dependencies installed!"
        echo ""
        info "Next steps:"
        echo "  1. uv sync                        # Install Python deps"
        echo "  2. uv run poe check-all            # Verify everything works"
        echo "  3. uv run dex-studio               # Launch DEX Studio"
        echo "  4. uv run dex-studio --no-native   # Launch in browser mode"
        echo ""
    else
        echo ""
        fail "Some dependencies are missing β€” see above"
        exit 1
    fi
}

# ── Main ───────────────────────────────────────────────────────────────────
main() {
    echo ""
    echo "╔══════════════════════════════════════════════════════════════════╗"
    echo "β•‘       DEX Studio β€” System Dependencies Installer               β•‘"
    echo "β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•"
    echo ""

    detect_os
    info "Detected OS: $OS"
    echo ""

    ensure_sudo

    case "$OS" in
        debian) install_debian ;;
        fedora) install_fedora ;;
        arch)   install_arch ;;
        macos)  install_macos ;;
    esac

    install_uv
    install_python_deps
    verify
}

main "$@"