124 lines
3.2 KiB
Bash
Executable File
124 lines
3.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
WEB_SRC_DIR="$ROOT_DIR/web/src"
|
|
MAC_SRC_DIR="${MAC_SRC_DIR:-$ROOT_DIR/mac/src}"
|
|
PYTHON_BIN="$ROOT_DIR/.venv/bin/python"
|
|
LAUNCHER="$WEB_SRC_DIR/backend_embedded_launcher.py"
|
|
BACKEND_BIN_NAME="${BACKEND_BIN_NAME:-WebBackend}"
|
|
BUILD_ROOT="$ROOT_DIR/dist-backend-build"
|
|
DIST_PATH="$BUILD_ROOT/dist"
|
|
WORK_PATH="$BUILD_ROOT/build"
|
|
SPEC_PATH="$BUILD_ROOT/spec"
|
|
PROJECT_PATH="${MAC_PROJECT_PATH:-}"
|
|
SCHEME="${MAC_SCHEME:-}"
|
|
TARGET_DIR="${EMBEDDED_BACKEND_DIR:-}"
|
|
|
|
discover_scheme() {
|
|
local project_path="$1"
|
|
python3 - "$project_path" <<'PY'
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
|
|
project = sys.argv[1]
|
|
try:
|
|
output = subprocess.check_output(
|
|
["xcodebuild", "-list", "-project", project, "-json"],
|
|
text=True,
|
|
stderr=subprocess.DEVNULL,
|
|
)
|
|
payload = json.loads(output)
|
|
except Exception:
|
|
print("")
|
|
raise SystemExit(0)
|
|
|
|
project_data = payload.get("project", {})
|
|
schemes = project_data.get("schemes") or []
|
|
print(schemes[0] if schemes else "")
|
|
PY
|
|
}
|
|
|
|
if [[ ! -x "$PYTHON_BIN" ]]; then
|
|
echo "Missing virtual environment. Run ./run.sh --setup-only first." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "$LAUNCHER" ]]; then
|
|
echo "Missing launcher file: $LAUNCHER" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -z "$PROJECT_PATH" ]]; then
|
|
PROJECT_PATH="$(find "$MAC_SRC_DIR" -maxdepth 4 -name "*.xcodeproj" | sort | head -n 1)"
|
|
fi
|
|
if [[ -z "$PROJECT_PATH" ]]; then
|
|
echo "No .xcodeproj found under: $MAC_SRC_DIR" >&2
|
|
echo "Set MAC_PROJECT_PATH to the project you want to build." >&2
|
|
exit 1
|
|
fi
|
|
|
|
PROJECT_DIR="$(dirname "$PROJECT_PATH")"
|
|
if [[ -z "$SCHEME" ]]; then
|
|
SCHEME="$(discover_scheme "$PROJECT_PATH")"
|
|
fi
|
|
if [[ -z "$SCHEME" ]]; then
|
|
SCHEME="$(basename "$PROJECT_PATH" .xcodeproj)"
|
|
fi
|
|
|
|
if [[ -z "$TARGET_DIR" ]]; then
|
|
DEFAULT_TARGET_DIR="$PROJECT_DIR/$SCHEME/EmbeddedBackend"
|
|
if [[ -d "$DEFAULT_TARGET_DIR" ]]; then
|
|
TARGET_DIR="$DEFAULT_TARGET_DIR"
|
|
else
|
|
TARGET_DIR="$(find "$PROJECT_DIR" -maxdepth 4 -type d -name EmbeddedBackend | sort | head -n 1)"
|
|
fi
|
|
fi
|
|
if [[ -z "$TARGET_DIR" ]]; then
|
|
TARGET_DIR="$PROJECT_DIR/$SCHEME/EmbeddedBackend"
|
|
fi
|
|
|
|
mkdir -p "$DIST_PATH" "$WORK_PATH" "$SPEC_PATH" "$TARGET_DIR"
|
|
|
|
"$PYTHON_BIN" -m pip install -q pyinstaller
|
|
|
|
PYI_ARGS=(
|
|
--noconfirm
|
|
--clean
|
|
--onefile
|
|
--name "$BACKEND_BIN_NAME"
|
|
--distpath "$DIST_PATH"
|
|
--workpath "$WORK_PATH"
|
|
--specpath "$SPEC_PATH"
|
|
--add-data "$WEB_SRC_DIR/app.py:."
|
|
--collect-all streamlit
|
|
--collect-all streamlit_autorefresh
|
|
--hidden-import yfinance
|
|
--hidden-import pandas
|
|
--collect-all plotly
|
|
--collect-all kaleido
|
|
)
|
|
|
|
for source_dir in "$WEB_SRC_DIR"/*; do
|
|
source_name="$(basename "$source_dir")"
|
|
if [[ ! -d "$source_dir" ]]; then
|
|
continue
|
|
fi
|
|
if [[ "$source_name" == "tests" ]] || [[ "$source_name" == "__pycache__" ]]; then
|
|
continue
|
|
fi
|
|
PYI_ARGS+=(--add-data "$source_dir:$source_name")
|
|
done
|
|
|
|
if [[ -f "$WEB_SRC_DIR/ONBOARDING.md" ]]; then
|
|
PYI_ARGS+=(--add-data "$WEB_SRC_DIR/ONBOARDING.md:.")
|
|
fi
|
|
|
|
"$PYTHON_BIN" -m PyInstaller "${PYI_ARGS[@]}" "$LAUNCHER"
|
|
|
|
cp "$DIST_PATH/$BACKEND_BIN_NAME" "$TARGET_DIR/$BACKEND_BIN_NAME"
|
|
chmod +x "$TARGET_DIR/$BACKEND_BIN_NAME"
|
|
|
|
echo "Embedded backend updated: $TARGET_DIR/$BACKEND_BIN_NAME"
|