feat: add macmon + mactop build steps to install_services.sh
This commit is contained in:
324
release/system/v1.0/services/install_services.sh
Executable file
324
release/system/v1.0/services/install_services.sh
Executable file
@@ -0,0 +1,324 @@
|
||||
#!/bin/bash
|
||||
#===========================================================================
|
||||
# Momentry Core — Service Dependency Build Script
|
||||
# Builds all 14 service dependencies from source code.
|
||||
#
|
||||
# Usage: bash install_services.sh [--prefix $HOME] [--src-dir ./src]
|
||||
#===========================================================================
|
||||
set -euo pipefail
|
||||
|
||||
PREFIX="${PREFIX:-$HOME}"
|
||||
SRC_DIR="${SRC_DIR:-$(dirname "$0")/src}"
|
||||
BUILD_DIR="${BUILD_DIR:-$HOME/service_build}"
|
||||
LOG_DIR="${LOG_DIR:-$HOME/service_logs}"
|
||||
NCPU=$(sysctl -n hw.ncpu 2>/dev/null || echo 4)
|
||||
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
||||
|
||||
mkdir -p "$BUILD_DIR" "$LOG_DIR"
|
||||
|
||||
log() { echo -e "${GREEN}[$(date +%H:%M:%S)]${NC} $*" | tee -a "$LOG_DIR/build.log"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $*" | tee -a "$LOG_DIR/build.log"; }
|
||||
fail() { echo -e "${RED}[FAIL]${NC} $*" | tee -a "$LOG_DIR/build.log"; exit 1; }
|
||||
|
||||
# ---- Helper ----
|
||||
check_file() { [ -f "$1" ] || fail "Missing: $1"; }
|
||||
check_dir() { [ -d "$1" ] || fail "Missing: $1"; }
|
||||
check_bin() {
|
||||
if ! "$1" -version >/dev/null 2>&1 && ! "$1" --version >/dev/null 2>&1; then
|
||||
warn "$1: version check returned non-zero (may still be functional)"
|
||||
fi
|
||||
}
|
||||
|
||||
#===========================================================================
|
||||
# Phase 0: Pre-flight
|
||||
#===========================================================================
|
||||
log "=== Phase 0: Pre-flight Checks ==="
|
||||
command -v make >/dev/null || fail "make not found (install Xcode CLI: xcode-select --install)"
|
||||
command -v git >/dev/null || fail "git not found"
|
||||
command -v curl >/dev/null || fail "curl not found"
|
||||
command -v cc >/dev/null || fail "cc not found (install Xcode CLI)"
|
||||
log "Pre-flight OK (make, git, curl, cc available)"
|
||||
|
||||
#===========================================================================
|
||||
# Phase 1: Toolchain
|
||||
#===========================================================================
|
||||
log ""
|
||||
log "=== Phase 1: Toolchain ==="
|
||||
|
||||
# 1a. cmake
|
||||
log "[1/3] cmake..."
|
||||
if [ ! -f "$PREFIX/bin/cmake" ]; then
|
||||
tar xzf "$SRC_DIR/cmake-4.2.0-macos-universal.tar.gz" -C "$BUILD_DIR/"
|
||||
CMAKE_DIR=$(ls -d "$BUILD_DIR/cmake-"*"-macos-universal" | head -1)
|
||||
mkdir -p "$PREFIX/bin"
|
||||
cp "$CMAKE_DIR/CMake.app/Contents/bin/cmake" "$PREFIX/bin/"
|
||||
cp -r "$CMAKE_DIR/CMake.app/Contents/share" "$PREFIX/share" 2>/dev/null || true
|
||||
rm -rf "$CMAKE_DIR"
|
||||
log " cmake installed to $PREFIX/bin/cmake"
|
||||
else
|
||||
log " cmake already installed"
|
||||
fi
|
||||
check_bin "$PREFIX/bin/cmake"
|
||||
|
||||
# 1b. pyenv
|
||||
log "[2/3] pyenv..."
|
||||
if [ ! -d "$PREFIX/.pyenv" ]; then
|
||||
cp -r "$SRC_DIR/pyenv" "$PREFIX/.pyenv"
|
||||
log " pyenv installed to $PREFIX/.pyenv"
|
||||
else
|
||||
log " pyenv already installed"
|
||||
fi
|
||||
export PYENV_ROOT="$PREFIX/.pyenv"
|
||||
export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
|
||||
# 1c. Python (via pyenv)
|
||||
log "[3/3] Python 3.11.15..."
|
||||
if [ ! -f "$PYENV_ROOT/versions/3.11.15/bin/python3" ]; then
|
||||
log " Building Python 3.11.15 (this takes 5-10 min)..."
|
||||
PYTHON_CONFIGURE_OPTS="--enable-shared" \
|
||||
"$PYENV_ROOT/bin/pyenv" install 3.11.15 2>&1 | tail -3
|
||||
log " Python 3.11.15 built"
|
||||
else
|
||||
log " Python 3.11.15 already installed"
|
||||
fi
|
||||
export PATH="$PYENV_ROOT/versions/3.11.15/bin:$PATH"
|
||||
check_bin python3.11
|
||||
|
||||
#===========================================================================
|
||||
# Phase 2: Core Services
|
||||
#===========================================================================
|
||||
log ""
|
||||
log "=== Phase 2: Core Services ==="
|
||||
|
||||
# Make sure build tools are on PATH
|
||||
export PATH="$PREFIX/bin:$PATH"
|
||||
|
||||
# 2a. x264 (ffmpeg dependency)
|
||||
log "[1/5] x264..."
|
||||
if [ ! -f "$PREFIX/ffmpeg_build/lib/libx264.a" ]; then
|
||||
cd "$SRC_DIR/x264"
|
||||
./configure --prefix="$PREFIX/ffmpeg_build" --enable-static --disable-cli > "$LOG_DIR/x264_configure.log" 2>&1
|
||||
make -j$NCPU > "$LOG_DIR/x264_make.log" 2>&1
|
||||
make install > "$LOG_DIR/x264_install.log" 2>&1
|
||||
log " x264 installed to $PREFIX/ffmpeg_build"
|
||||
else
|
||||
log " x264 already installed"
|
||||
fi
|
||||
|
||||
# 2b. freetype (optional, for drawtext filter — not used by baseline pipeline)
|
||||
log "[2/5] freetype (optional)..."
|
||||
if [ ! -f "$PREFIX/ffmpeg_build/lib/libfreetype.a" ]; then
|
||||
tar xzf "$SRC_DIR/freetype-2.13.3.tar.gz" -C "$BUILD_DIR/"
|
||||
cd "$BUILD_DIR/freetype-2.13.3"
|
||||
./configure --prefix="$PREFIX/ffmpeg_build" --enable-static > "$LOG_DIR/freetype_configure.log" 2>&1
|
||||
make -j$NCPU > "$LOG_DIR/freetype_make.log" 2>&1
|
||||
make install > "$LOG_DIR/freetype_install.log" 2>&1
|
||||
rm -rf "$BUILD_DIR/freetype-2.13.3"
|
||||
log " freetype installed to $PREFIX/ffmpeg_build"
|
||||
else
|
||||
log " freetype already installed"
|
||||
fi
|
||||
|
||||
# 2c. ffmpeg
|
||||
log "[3/5] ffmpeg..."
|
||||
if [ ! -f "$PREFIX/ffmpeg_build/bin/ffmpeg" ]; then
|
||||
tar xf "$SRC_DIR/ffmpeg-7.1.1.tar.xz" -C "$BUILD_DIR/"
|
||||
cd "$BUILD_DIR/ffmpeg-7.1.1"
|
||||
# NOTE: drawtext filter needs BOTH libfreetype AND libharfbuzz.
|
||||
# Add --enable-libfreetype --enable-filter=drawtext after building harfbuzz.
|
||||
PKG_CONFIG_PATH="$PREFIX/ffmpeg_build/lib/pkgconfig" \
|
||||
./configure \
|
||||
--prefix="$PREFIX/ffmpeg_build" \
|
||||
--pkg-config-flags="--static" \
|
||||
--extra-cflags="-I$PREFIX/ffmpeg_build/include" \
|
||||
--extra-ldflags="-L$PREFIX/ffmpeg_build/lib" \
|
||||
--enable-gpl \
|
||||
--enable-libx264 \
|
||||
--enable-encoder=pcm_s16le \
|
||||
--enable-encoder=mjpeg \
|
||||
--enable-encoder=rawvideo \
|
||||
--enable-encoder=aac \
|
||||
--enable-encoder=libx264 \
|
||||
--enable-muxer=wav \
|
||||
--enable-muxer=mp4 \
|
||||
--enable-muxer=image2 \
|
||||
--enable-muxer=rawvideo \
|
||||
--enable-filter=drawbox \
|
||||
--enable-filter=scale \
|
||||
--enable-filter=select \
|
||||
--enable-filter=fps \
|
||||
--enable-filter=crop \
|
||||
--enable-filter=pad \
|
||||
--enable-filter=setpts \
|
||||
--enable-filter=format \
|
||||
--enable-demuxer=mov,mp4,m4a,avi,matroska,webm \
|
||||
--enable-decoder=h264,hevc,mpeg4,mjpeg,aac,mp3,pcm_s16le \
|
||||
--disable-doc > "$LOG_DIR/ffmpeg_configure.log" 2>&1
|
||||
make -j$NCPU > "$LOG_DIR/ffmpeg_make.log" 2>&1
|
||||
make install > "$LOG_DIR/ffmpeg_install.log" 2>&1
|
||||
rm -rf "$BUILD_DIR/ffmpeg-7.1.1"
|
||||
log " ffmpeg installed to $PREFIX/ffmpeg_build/bin"
|
||||
else
|
||||
log " ffmpeg already installed"
|
||||
fi
|
||||
check_bin "$PREFIX/ffmpeg_build/bin/ffmpeg"
|
||||
check_bin "$PREFIX/ffmpeg_build/bin/ffprobe"
|
||||
|
||||
# 2d. Redis
|
||||
log "[4/5] Redis..."
|
||||
if [ ! -f "$PREFIX/redis/bin/redis-server" ]; then
|
||||
tar xzf "$SRC_DIR/redis-7.4.3.tar.gz" -C "$BUILD_DIR/"
|
||||
cd "$BUILD_DIR/redis-7.4.3"
|
||||
make -j$NCPU > "$LOG_DIR/redis_make.log" 2>&1
|
||||
make PREFIX="$PREFIX/redis" install > "$LOG_DIR/redis_install.log" 2>&1
|
||||
rm -rf "$BUILD_DIR/redis-7.4.3"
|
||||
log " Redis installed to $PREFIX/redis"
|
||||
else
|
||||
log " Redis already installed"
|
||||
fi
|
||||
check_bin "$PREFIX/redis/bin/redis-server"
|
||||
|
||||
# 2e. PostgreSQL
|
||||
log "[5/5] PostgreSQL..."
|
||||
if [ ! -f "$PREFIX/pgsql/18.3/bin/postgres" ]; then
|
||||
tar xzf "$SRC_DIR/postgresql-18.3.tar.gz" -C "$BUILD_DIR/"
|
||||
cd "$BUILD_DIR/postgresql-18.3"
|
||||
./configure --prefix="$PREFIX/pgsql/18.3" > "$LOG_DIR/pg_configure.log" 2>&1
|
||||
make -j$NCPU > "$LOG_DIR/pg_make.log" 2>&1
|
||||
make install > "$LOG_DIR/pg_install.log" 2>&1
|
||||
rm -rf "$BUILD_DIR/postgresql-18.3"
|
||||
log " PostgreSQL installed to $PREFIX/pgsql/18.3"
|
||||
else
|
||||
log " PostgreSQL already installed"
|
||||
fi
|
||||
check_bin "$PREFIX/pgsql/18.3/bin/postgres"
|
||||
|
||||
#===========================================================================
|
||||
# Phase 3: llama.cpp
|
||||
#===========================================================================
|
||||
log ""
|
||||
log "=== Phase 3: llama.cpp ==="
|
||||
if [ ! -f "$PREFIX/llama/bin/llama-server" ]; then
|
||||
cd "$SRC_DIR/llama.cpp"
|
||||
cmake -B build -DCMAKE_INSTALL_PREFIX="$PREFIX/llama" > "$LOG_DIR/llama_cmake.log" 2>&1
|
||||
cmake --build build --config Release -j$NCPU > "$LOG_DIR/llama_build.log" 2>&1
|
||||
mkdir -p "$PREFIX/llama/bin" "$PREFIX/llama/lib"
|
||||
cp build/bin/llama-server "$PREFIX/llama/bin/" 2>/dev/null || true
|
||||
cp build/bin/llama-cli "$PREFIX/llama/bin/" 2>/dev/null || true
|
||||
log " llama.cpp installed to $PREFIX/llama"
|
||||
else
|
||||
log " llama.cpp already installed"
|
||||
fi
|
||||
[ -f "$PREFIX/llama/bin/llama-server" ] || fail "llama-server not built"
|
||||
|
||||
#===========================================================================
|
||||
# Phase 3b: Monitoring Tools
|
||||
#===========================================================================
|
||||
log ""
|
||||
log "=== Phase 3b: Monitoring Tools ==="
|
||||
|
||||
# macmon (Rust-based network monitor)
|
||||
log "[1/2] macmon..."
|
||||
if [ ! -f "$PREFIX/bin/macmon" ]; then
|
||||
tar xzf "$SRC_DIR/macmon-0.7.2.tar.gz" -C "$BUILD_DIR/"
|
||||
cd "$BUILD_DIR/macmon-0.7.2"
|
||||
cargo build --release > "$LOG_DIR/macmon_build.log" 2>&1
|
||||
cp target/release/macmon "$PREFIX/bin/macmon"
|
||||
log " macmon installed to $PREFIX/bin/macmon"
|
||||
else
|
||||
log " macmon already installed"
|
||||
fi
|
||||
[ -f "$PREFIX/bin/macmon" ] || fail "macmon not built"
|
||||
|
||||
# mactop (Go-based system monitor)
|
||||
log "[2/2] mactop..."
|
||||
if [ ! -f "$PREFIX/bin/mactop" ]; then
|
||||
tar xzf "$SRC_DIR/mactop-latest.tar.gz" -C "$BUILD_DIR/mactop-latest" 2>/dev/null || true
|
||||
mkdir -p "$BUILD_DIR/mactop"
|
||||
# Extract tarball (might create a subdirectory with the hash name)
|
||||
cd "$BUILD_DIR"
|
||||
if [ -d "$BUILD_DIR/mactop-main" ]; then
|
||||
rm -rf "$BUILD_DIR/mactop"
|
||||
mv "$BUILD_DIR/mactop-main" "$BUILD_DIR/mactop"
|
||||
fi
|
||||
cd "$BUILD_DIR/mactop"
|
||||
go build -o mactop . > "$LOG_DIR/mactop_build.log" 2>&1
|
||||
cp mactop "$PREFIX/bin/mactop"
|
||||
log " mactop installed to $PREFIX/bin/mactop"
|
||||
else
|
||||
log " mactop already installed"
|
||||
fi
|
||||
[ -f "$PREFIX/bin/mactop" ] || fail "mactop not built"
|
||||
|
||||
#===========================================================================
|
||||
# Phase 4: Verification
|
||||
#===========================================================================
|
||||
log ""
|
||||
log "=== Phase 4: Verification ==="
|
||||
echo ""
|
||||
|
||||
# Test each binary (inline to avoid bash -e/-u function quirks)
|
||||
PASS=0; FAIL=0
|
||||
|
||||
if "$PREFIX/bin/cmake" --version >/dev/null 2>&1; then echo " ✅ cmake: $($PREFIX/bin/cmake --version 2>&1 | head -1)"; PASS=$((PASS+1)); else echo " ❌ cmake"; FAIL=$((FAIL+1)); fi
|
||||
if "$PYENV_ROOT/versions/3.11.15/bin/python3.11" --version >/dev/null 2>&1; then echo " ✅ python3.11: $($PYENV_ROOT/versions/3.11.15/bin/python3.11 --version 2>&1)"; PASS=$((PASS+1)); else echo " ❌ python3.11"; FAIL=$((FAIL+1)); fi
|
||||
if "$PREFIX/ffmpeg_build/bin/ffmpeg" -version >/dev/null 2>&1; then echo " ✅ ffmpeg: $($PREFIX/ffmpeg_build/bin/ffmpeg -version 2>&1 | head -1)"; PASS=$((PASS+1)); else echo " ❌ ffmpeg"; FAIL=$((FAIL+1)); fi
|
||||
if "$PREFIX/ffmpeg_build/bin/ffprobe" -version >/dev/null 2>&1; then echo " ✅ ffprobe: $($PREFIX/ffmpeg_build/bin/ffprobe -version 2>&1 | head -1)"; PASS=$((PASS+1)); else echo " ❌ ffprobe"; FAIL=$((FAIL+1)); fi
|
||||
if "$PREFIX/redis/bin/redis-server" --version >/dev/null 2>&1; then echo " ✅ redis-server: $($PREFIX/redis/bin/redis-server --version 2>&1 | head -1)"; PASS=$((PASS+1)); else echo " ❌ redis-server"; FAIL=$((FAIL+1)); fi
|
||||
if "$PREFIX/pgsql/18.3/bin/postgres" --version >/dev/null 2>&1; then echo " ✅ postgres: $($PREFIX/pgsql/18.3/bin/postgres --version 2>&1)"; PASS=$((PASS+1)); else echo " ❌ postgres"; FAIL=$((FAIL+1)); fi
|
||||
if [ -f "$PREFIX/llama/bin/llama-server" ]; then echo " ✅ llama-server: binary exists"; PASS=$((PASS+1)); else echo " ❌ llama-server"; FAIL=$((FAIL+1)); fi
|
||||
if [ -f "$PYENV_ROOT/bin/pyenv" ]; then echo " ✅ pyenv: installed"; PASS=$((PASS+1)); else echo " ❌ pyenv"; FAIL=$((FAIL+1)); fi
|
||||
if "$PREFIX/bin/macmon" --version >/dev/null 2>&1; then echo " ✅ macmon: $($PREFIX/bin/macmon --version 2>&1)"; PASS=$((PASS+1)); else echo " ❌ macmon"; FAIL=$((FAIL+1)); fi
|
||||
if "$PREFIX/bin/mactop" --version >/dev/null 2>&1; then echo " ✅ mactop: $($PREFIX/bin/mactop --version 2>&1)"; PASS=$((PASS+1)); else echo " ❌ mactop"; FAIL=$((FAIL+1)); fi
|
||||
|
||||
echo ""
|
||||
log "=== Results: $PASS passed, $FAIL failed ==="
|
||||
[ "$FAIL" -eq 0 ] || exit 1
|
||||
|
||||
log "=== Build Complete ==="
|
||||
log ""
|
||||
log "Service binaries installed at:"
|
||||
log " cmake: $PREFIX/bin/cmake"
|
||||
log " python3.11: $PYENV_ROOT/versions/3.11.15/bin/python3.11"
|
||||
log " ffmpeg: $PREFIX/ffmpeg_build/bin/ffmpeg"
|
||||
log " ffprobe: $PREFIX/ffmpeg_build/bin/ffprobe"
|
||||
log " redis-server: $PREFIX/redis/bin/redis-server"
|
||||
log " postgres: $PREFIX/pgsql/18.3/bin/postgres"
|
||||
log " llama-server: $PREFIX/llama/bin/llama-server"
|
||||
log " pyenv: $PYENV_ROOT/bin/pyenv"
|
||||
log " macmon: $PREFIX/bin/macmon"
|
||||
log " mactop: $PREFIX/bin/mactop"
|
||||
log ""
|
||||
log "To use these tools, add to PATH:"
|
||||
log " export PATH=\"$PREFIX/bin:$PREFIX/ffmpeg_build/bin:$PREFIX/redis/bin:$PREFIX/pgsql/18.3/bin:$PREFIX/llama/bin:\$PATH\""
|
||||
|
||||
# ---- Timing Report ----
|
||||
log ""
|
||||
log "=== Build Timing ==="
|
||||
python3 -c "
|
||||
import re
|
||||
with open('$LOG_DIR/build.log') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
def ts(s):
|
||||
h,m,sec = s.split(':')
|
||||
return int(h)*3600 + int(m)*60 + int(sec)
|
||||
|
||||
events = []
|
||||
for line in lines:
|
||||
m = re.search(r'\[(\d{2}:\d{2}:\d{2})\]\s*(.*)', line)
|
||||
if not m: continue
|
||||
t, msg = m.group(1), m.group(2).strip()
|
||||
events.append((ts(t), msg))
|
||||
|
||||
if len(events) < 2:
|
||||
print('Not enough timestamps')
|
||||
exit()
|
||||
|
||||
total = events[-1][0] - events[0][0]
|
||||
print(f' Total wall-clock time: {total}s ({total/60:.1f} min)')
|
||||
print(f' Events logged: {len(events)}')
|
||||
print(f' First: {events[0][1][:60]}')
|
||||
print(f' Last: {events[-1][1][:60]}')
|
||||
" 2>/dev/null || true
|
||||
Reference in New Issue
Block a user