scripts cleanup & better all-in-one deploy

build flutter ui -> deploy backend -> uv sync -> deploy ui
This commit is contained in:
Mikkeli Matlock
2026-01-26 16:50:21 +09:00
parent 46ac9d3123
commit 62eaaff88e
5 changed files with 44 additions and 182 deletions

View File

@@ -13,6 +13,7 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
from build import build
from deploy import deploy
from deploy_backend import deploy as deploy_backend
def main():
@@ -39,21 +40,44 @@ def main():
action="store_true",
help="Only deploy, don't build",
)
parser.add_argument(
"--ui",
action="store_true",
help="Build/deploy UI only (no backend)",
)
parser.add_argument(
"--backend",
action="store_true",
help="Deploy backend only (no UI, no build)",
)
args = parser.parse_args()
# Build
if not args.deploy_only:
# Default: both UI and backend if neither flag specified
do_ui = args.ui or not args.backend
do_backend = args.backend or not args.ui
restart = not args.no_restart
# Build UI (only if doing UI and not deploy-only)
if do_ui and not args.deploy_only:
print()
if not build(clean=args.clean):
print("Build failed!")
print("UI build failed!")
sys.exit(1)
# Deploy
if not args.build_only:
# Deploy backend FIRST (no build step needed - it's Python)
# Backend must be up before UI connects to WebSocket
if do_backend and not args.build_only:
print()
if not deploy_backend(restart=restart):
print("Backend deploy failed!")
sys.exit(1)
# Deploy UI after backend is ready
if do_ui and not args.build_only:
print()
restart = not args.no_restart
if not deploy(restart=restart):
print("Deploy failed!")
print("UI deploy failed!")
sys.exit(1)
print()

View File

@@ -1,6 +0,0 @@
#!/bin/bash
# Wrapper for build-deploy.py
# Usage: ./build-deploy.sh [options]
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec python3 "$SCRIPT_DIR/build-deploy.py" "$@"

View File

@@ -1,81 +0,0 @@
#!/bin/bash
# Build script for Smart Serow Flutter UI
# Run this in WSL2 with flutter-elinux installed
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
UI_DIR="$PROJECT_ROOT/pi/ui"
echo "=== Smart Serow Build ==="
echo "Project: $UI_DIR"
# Check for flutter-elinux
if ! command -v flutter-elinux &> /dev/null; then
echo "ERROR: flutter-elinux not found in PATH"
echo "Install it or check your PATH"
echo ""
echo "Current PATH: $PATH"
which flutter 2>/dev/null && echo "Found flutter at: $(which flutter)"
exit 1
fi
echo "Using: $(which flutter-elinux)"
# Cross-compilation toolchain for ARM64
export CC=aarch64-linux-gnu-gcc
export CXX=aarch64-linux-gnu-g++
export AR=aarch64-linux-gnu-ar
export LD=aarch64-linux-gnu-ld
# CMake-specific vars
export CMAKE_C_COMPILER=aarch64-linux-gnu-gcc
export CMAKE_CXX_COMPILER=aarch64-linux-gnu-g++
echo "Cross-compiler: $CXX"
cd "$UI_DIR"
# Initialize elinux project if not already configured
if [ ! -d "elinux" ]; then
echo "Initializing elinux project structure..."
flutter-elinux create . --project-name smartserow_ui --org com.smartserow
fi
# Clean CMake cache on --clean flag
# (CMake caches compiler choice, so stale cache = wrong linker)
if [ "${1:-}" = "--clean" ]; then
echo "Cleaning CMake cache..."
rm -rf build/elinux/arm64
fi
echo "Fetching dependencies..."
flutter-elinux pub get
echo "Building for ARM64 (elinux) with DRM-GBM backend..."
# Use Pi sysroot if available (for proper cross-linking)
SYSROOT_FLAG=""
if [ -d "$PROJECT_ROOT/pi_sysroot" ]; then
echo "Using Pi sysroot: $PROJECT_ROOT/pi_sysroot"
SYSROOT_FLAG="--target-sysroot=$PROJECT_ROOT/pi_sysroot"
fi
flutter-elinux build elinux \
--target-arch=arm64 \
--target-backend-type=gbm \
--target-compiler-triple=aarch64-linux-gnu \
$SYSROOT_FLAG \
--release
BUILD_OUTPUT="$UI_DIR/build/elinux/arm64/release/bundle"
if [ -d "$BUILD_OUTPUT" ]; then
echo ""
echo "=== Build Complete ==="
echo "Output: $BUILD_OUTPUT"
ls -lh "$BUILD_OUTPUT"
else
echo "ERROR: Build output not found at $BUILD_OUTPUT"
exit 1
fi

View File

@@ -1,85 +0,0 @@
#!/bin/bash
# Deploy script for Smart Serow Flutter UI
# Pushes build bundle to Pi and optionally restarts service
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
CONFIG_FILE="$SCRIPT_DIR/deploy_target.json"
# You'll need to create this file based on deploy_target.sample.json
# Parse config
if [ ! -f "$CONFIG_FILE" ]; then
echo "ERROR: Config file not found: $CONFIG_FILE"
exit 1
fi
# Parse JSON with Python (more universal than jq)
read_json() {
python3 -c "import json; print(json.load(open('$CONFIG_FILE'))['$1'])"
}
PI_USER=$(read_json user)
PI_HOST=$(read_json host)
REMOTE_PATH=$(read_json remote_path)
SERVICE_NAME=$(read_json service_name)
SSH_TARGET="$PI_USER@$PI_HOST"
BUILD_DIR="$PROJECT_ROOT/pi/ui/build/elinux/arm64/release/bundle"
CONFIG_SRC="$PROJECT_ROOT/pi/ui/config.json"
IMAGES_SRC="$PROJECT_ROOT/extra/images"
echo "=== Smart Serow Deploy ==="
echo "Target: $SSH_TARGET:$REMOTE_PATH"
echo "Source: $BUILD_DIR"
if [ ! -d "$BUILD_DIR" ]; then
echo "ERROR: Build directory not found. Run build.sh first."
exit 1
fi
# Sync build to Pi
echo ""
echo "Syncing files..."
rsync -avz --delete \
"$BUILD_DIR/" \
"$SSH_TARGET:$REMOTE_PATH/bundle/"
# Sync config.json (sits next to executable in bundle)
if [ -f "$CONFIG_SRC" ]; then
echo ""
echo "Syncing config.json..."
rsync -avz "$CONFIG_SRC" "$SSH_TARGET:$REMOTE_PATH/bundle/config.json"
else
echo ""
echo "Note: No config.json found, using defaults"
fi
# Sync images to assets path
if [ -d "$IMAGES_SRC" ]; then
# Read assets_path from config, fall back to default
ASSETS_PATH=$(python3 -c "import json; print(json.load(open('$CONFIG_FILE')).get('assets_path', '$REMOTE_PATH/assets'))" 2>/dev/null || echo "$REMOTE_PATH/assets")
echo ""
echo "Syncing images to $ASSETS_PATH..."
rsync -avz "$IMAGES_SRC/" "$SSH_TARGET:$ASSETS_PATH/"
else
echo ""
echo "Note: No extra/images folder found, skipping image sync"
fi
# Restart service if requested
RESTART="${1:-}"
if [ "$RESTART" = "--restart" ] || [ "$RESTART" = "-r" ]; then
echo ""
echo "Restarting service: $SERVICE_NAME"
ssh "$SSH_TARGET" "sudo systemctl restart $SERVICE_NAME"
sleep 2
ssh "$SSH_TARGET" "systemctl status $SERVICE_NAME --no-pager"
else
echo ""
echo "Deploy complete. To restart service, run:"
echo " ssh $SSH_TARGET 'sudo systemctl restart $SERVICE_NAME'"
echo ""
echo "Or run this script with --restart flag"
fi

View File

@@ -76,6 +76,18 @@ def deploy(restart: bool = False) -> bool:
f"{ssh_target}:{remote_path}/",
])
# Run uv sync to install/update dependencies
# Use full path since non-interactive SSH doesn't load .bashrc
print()
print("Running uv sync...")
result = run(
["ssh", ssh_target, f"cd {remote_path} && ~/.local/bin/uv sync"],
check=False,
)
if result.returncode != 0:
print("WARNING: uv sync failed - dependencies may be out of date")
print("Make sure uv is installed on Pi: curl -LsSf https://astral.sh/uv/install.sh | sh")
# Restart service if requested
if restart:
print()
@@ -91,11 +103,9 @@ def deploy(restart: bool = False) -> bool:
print("Or run this script with --restart flag")
print()
print("Note: First-time setup on Pi requires:")
print("Note: First-time setup on Pi requires uv to be installed:")
print(f" ssh {ssh_target}")
print(f" cd {remote_path}")
print(" curl -LsSf https://astral.sh/uv/install.sh | sh")
print(" uv sync")
return True