summaryrefslogtreecommitdiffstats
path: root/packaging/build/build-client.sh
blob: d42000ad3abd2689c7149b64f7555132fa5d4cd2 (plain) (blame)
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
#!/usr/bin/env bash
# Build the meshbay-client package: Electron app + .desktop launcher.
#
# Usage: ./build-client.sh [staging-dir] [--arm64]
#
# Requires Node >= 22. If not in PATH, set NODEJS_DIR=/opt/nodejs or similar.
set -euo pipefail

REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
STAGING="${1:-/tmp/meshbay-build}"
ROOT="$STAGING/meshbay-client-root"
CLIENT="$REPO/packages/meshbay-client"

ARCH_FLAG=""
ELECTRON_ARCH="x64"
DEB_ARCH="amd64"
for arg in "$@"; do
    if [ "$arg" = "--arm64" ]; then
        ARCH_FLAG="--arm64"
        ELECTRON_ARCH="arm64"
        DEB_ARCH="arm64"
    fi
done

# Node.js version check
if [ -n "${NODEJS_DIR:-}" ]; then
    export PATH="$NODEJS_DIR/bin:$PATH"
fi
NODE_VER=$(node --version 2>/dev/null || echo "none")
echo "==> meshbay-client (Node $NODE_VER, arch=$ELECTRON_ARCH)"

if ! node --version >/dev/null 2>&1; then
    echo "!! Node.js not found. Set NODEJS_DIR or install Node >= 22." >&2
    exit 1
fi

NODE_MAJOR=$(node -e "process.stdout.write(String(process.versions.node.split('.')[0]))")
if [ "$NODE_MAJOR" -lt 22 ]; then
    echo "!! Node $NODE_VER is too old — need >= 22 for Electron" >&2
    exit 1
fi

rm -rf "$ROOT"
mkdir -p "$ROOT"

# --- Build the Electron app -----------------------------------------------
cd "$CLIENT"

echo "    npm ci"
npm ci --ignore-scripts 2>&1 | tail -3

echo "    approving + installing electron"
npm approve-scripts electron 2>/dev/null || true
node node_modules/electron/install.js 2>&1 | tail -1

echo "    syncing UI from hub package"
npm run sync-ui 2>&1 | tail -1

echo "    electron-builder --dir $ARCH_FLAG"
npx electron-builder --dir --linux $ARCH_FLAG 2>&1 | tail -5

# Determine the unpacked output directory
if [ "$ELECTRON_ARCH" = "arm64" ]; then
    UNPACKED="$CLIENT/dist/linux-arm64-unpacked"
else
    UNPACKED="$CLIENT/dist/linux-unpacked"
fi

[ -d "$UNPACKED" ] || { echo "!! electron-builder output not found at $UNPACKED" >&2; exit 1; }

# --- Assemble the package tree --------------------------------------------
echo "    assembling /opt/meshbay-client/"
mkdir -p "$ROOT/opt/meshbay-client"
cp -a "$UNPACKED"/* "$ROOT/opt/meshbay-client/"

# Rename the electron binary
if [ -f "$ROOT/opt/meshbay-client/meshbay-client" ]; then
    mv "$ROOT/opt/meshbay-client/meshbay-client" "$ROOT/opt/meshbay-client/meshbay"
elif [ -f "$ROOT/opt/meshbay-client/electron" ]; then
    mv "$ROOT/opt/meshbay-client/electron" "$ROOT/opt/meshbay-client/meshbay"
fi

# Symlink in PATH
mkdir -p "$ROOT/usr/bin"
ln -sf /opt/meshbay-client/meshbay "$ROOT/usr/bin/meshbay"

# --- Desktop launcher -----------------------------------------------------
mkdir -p "$ROOT/usr/share/applications"
cp "$REPO/packaging/desktop/meshbay.desktop" "$ROOT/usr/share/applications/"

# --- Icons ----------------------------------------------------------------
ICON_SRC="$CLIENT/build/icon.png"
if [ -f "$ICON_SRC" ]; then
    for size in 128 256 512; do
        ICON_DIR="$ROOT/usr/share/icons/hicolor/${size}x${size}/apps"
        mkdir -p "$ICON_DIR"
        if command -v convert >/dev/null 2>&1; then
            convert "$ICON_SRC" -resize "${size}x${size}" "$ICON_DIR/meshbay.png"
        elif command -v magick >/dev/null 2>&1; then
            magick "$ICON_SRC" -resize "${size}x${size}" "$ICON_DIR/meshbay.png"
        else
            # Fallback: copy the original at all sizes (better than no icon)
            cp "$ICON_SRC" "$ICON_DIR/meshbay.png"
        fi
    done
    echo "    icons installed"
else
    echo "    !! icon.png not found at $ICON_SRC — no icons" >&2
fi

# --- Firewall profile (Chromecast) ----------------------------------------
mkdir -p "$ROOT/usr/lib/firewalld/services"
cp "$REPO/packaging/firewall/firewalld/meshbay-cast.xml" \
   "$ROOT/usr/lib/firewalld/services/"

echo "==> meshbay-client staging ready at $ROOT ($DEB_ARCH)"

# `npm ci` above deletes node_modules wholesale and install.js re-extracts
# Electron's dist, so a chrome-sandbox that had been made root-owned 4755 for
# local development comes back 755, owned by whoever ran this build. Running
# the app straight from node_modules then aborts outright — Chromium refuses
# to run without its SUID helper rather than quietly dropping the sandbox,
# which is the right call and a baffling one if you have not connected the
# crash to a package build you ran minutes earlier.
#
# Said, not done: this script does not use sudo, and a build is not where a
# setuid bit should be set behind someone's back. The *packaged* app is
# unaffected — packaging/deb/meshbay-client/DEBIAN/postinst does it at
# install time, which is where it belongs.
SANDBOX="$CLIENT/node_modules/electron/dist/chrome-sandbox"
if [ -e "$SANDBOX" ] && [ ! -u "$SANDBOX" ]; then
    echo
    echo "    NOTE: this build reset $SANDBOX to $(stat -c '%a %U:%G' "$SANDBOX")."
    echo "    Running Electron from node_modules needs it back:"
    echo "      sudo chown root:root '$SANDBOX' && sudo chmod 4755 '$SANDBOX'"
fi