diff --git a/d2ypp2/live-platform/scripts/doctor.sh b/d2ypp2/live-platform/scripts/doctor.sh index 9712324..9277705 100644 --- a/d2ypp2/live-platform/scripts/doctor.sh +++ b/d2ypp2/live-platform/scripts/doctor.sh @@ -26,13 +26,22 @@ MDNS_HOST="${HOSTNAME_ALIAS:-live}.local" getent hosts "$MDNS_HOST" >/dev/null 2>&1 && echo "$MDNS_HOST resolves: yes" || echo "$MDNS_HOST resolves: fail" section "config" +if [[ -f "$REPO/config/system-stack.env" ]]; then + echo "repo stack env: present ($REPO/config/system-stack.env)" +else + echo "repo stack env: missing" +fi if [[ -f /opt/live/config/system.json ]]; then echo "system.json: present" +elif [[ -f "$REPO/config/system-stack.env" ]]; then + echo "system.json: not used by repo-managed install" else echo "system.json: MISSING (run install-core)" fi if [[ -f /opt/live/generated/system-stack.env ]]; then echo "generated env: present" +elif [[ -f "$REPO/config/system-stack.env" ]]; then + echo "generated env: repo-managed via config/system-stack.env" else echo "generated env: missing" fi diff --git a/d2ypp2/requirements.txt b/d2ypp2/requirements.txt index 9e1c9ff..d711db5 100644 --- a/d2ypp2/requirements.txt +++ b/d2ypp2/requirements.txt @@ -6,5 +6,6 @@ tqdm>=4.67.1 httpx[http2]>=0.28.1 PyExecJS>=1.5.1 fastapi>=0.115.0 +eval-type-backport>=0.2.0 uvicorn[standard]>=0.30.0 -python-multipart>=0.0.9 \ No newline at end of file +python-multipart>=0.0.9 diff --git a/d2ypp2/scripts/launch.py b/d2ypp2/scripts/launch.py index 91c29b9..5d3286d 100644 --- a/d2ypp2/scripts/launch.py +++ b/d2ypp2/scripts/launch.py @@ -262,6 +262,9 @@ def _try_local_console_build() -> tuple[bool, str]: return True, "up-to-date" print("[launch] 正在构建 Web 控制台…") + for path in (CONSOLE / "node_modules", CONSOLE / ".next"): + if path.exists(): + shutil.rmtree(path, ignore_errors=True) lock = CONSOLE / "package-lock.json" if lock.is_file(): rc = _run_console_cmd([npm, "ci"], cwd=CONSOLE, env=env) @@ -290,9 +293,18 @@ def _docker_console_build() -> bool: print(f"[launch] 本机 Node 不足,改用 Docker 构建: {DOCKER_NODE_IMAGE}") script = ( "set -e; " + "rm -rf /tmp/web-console; " + "mkdir -p /tmp/web-console; " "cd /workspace/web-console; " - "if [ ! -d node_modules ]; then npm ci || npm install; fi; " - "npm run build" + "tar --exclude=node_modules --exclude=.next --exclude=out -cf - . | tar -C /tmp/web-console -xf -; " + "cd /tmp/web-console; " + "rm -rf node_modules .next out; " + "export HOME=/tmp npm_config_cache=/tmp/npm-cache; " + "if [ -f package-lock.json ]; then npm ci || npm install; else npm install; fi; " + "test -x node_modules/.bin/next; " + "npm run build; " + "rm -rf /workspace/web-console/out; " + "cp -a out /workspace/web-console/out" ) cmd = [ docker, @@ -300,6 +312,10 @@ def _docker_console_build() -> bool: "--rm", "-u", f"{os.getuid()}:{os.getgid()}", + "-e", + "HOME=/tmp", + "-e", + "npm_config_cache=/tmp/npm-cache", "-v", f"{ROOT}:/workspace", "-w", @@ -390,7 +406,10 @@ def _start_docker_console_dev(*, host: str, port: str, next_port: str) -> subpro script = ( "set -e; " "cd /workspace/web-console; " - "if [ ! -d node_modules ]; then npm ci || npm install; fi; " + "if [ ! -x node_modules/.bin/next ]; then rm -rf node_modules .next; fi; " + "if [ ! -d node_modules ]; then " + "if [ -f package-lock.json ]; then npm ci || npm install; else npm install; fi; " + "fi; " "npm run dev -- --hostname 0.0.0.0 --port 3000" ) cmd = [ @@ -404,6 +423,10 @@ def _start_docker_console_dev(*, host: str, port: str, next_port: str) -> subpro "-e", f"API_PROXY_TARGET={proxy_target}", "-e", + "HOME=/tmp", + "-e", + "npm_config_cache=/tmp/npm-cache", + "-e", "HOST=0.0.0.0", "-e", "PORT=3000", diff --git a/d2ypp2/scripts/linux/install_all.sh b/d2ypp2/scripts/linux/install_all.sh new file mode 100644 index 0000000..8fa8a05 --- /dev/null +++ b/d2ypp2/scripts/linux/install_all.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +SELF_DIR="$(cd "$(dirname "$0")" && pwd)" +INSTALL_TAG="all" +. "$SELF_DIR/lib/common.sh" + +ensure_root "$@" +load_env + +ensure_live_user +normalize_repo_root +ensure_runtime_dirs_owned_by_live +install_base_packages +install_media_packages +configure_adb_udev +install_nodejs +install_docker_stack +install_android_panel +prepare_python_runtime +prepare_web_console +install_live_console_service +configure_sudoers +configure_mdns +configure_wifi_profile +install_shellcrash +install_browser_stack +install_neko_browser +install_redroid +prepare_mitmproxy +prepare_vscode_server +prepare_uptime_kuma +prepare_openclaw +install_pulseaudio_service +install_kmscube_service +install_webtty +install_cockpit +install_netdata +prepare_homepage +prepare_filebrowser +prepare_srs +run_hardware_probe +install_live_edge_proxy +ensure_runtime_dirs_owned_by_live +print_summary "all" diff --git a/d2ypp2/scripts/linux/install_stack.sh b/d2ypp2/scripts/linux/install_stack.sh index 923d846..e182e65 100644 --- a/d2ypp2/scripts/linux/install_stack.sh +++ b/d2ypp2/scripts/linux/install_stack.sh @@ -12,8 +12,7 @@ case "$PROFILE" in exec bash "$ROOT_DIR/scripts/linux/install_business.sh" "${@:2}" ;; all|full) - bash "$ROOT_DIR/scripts/linux/install_hub.sh" "${@:2}" - bash "$ROOT_DIR/scripts/linux/install_business.sh" "${@:2}" + exec bash "$ROOT_DIR/scripts/linux/install_all.sh" "${@:2}" ;; *) cat </dev/null | sha256sum | awk '{print $1}')" + if ! as_live "test -x .venv/bin/python && .venv/bin/python -V >/dev/null 2>&1"; then rm -rf "$ROOT_DIR/.venv" - if ! as_live "python3 -m venv .venv"; then - log "WARN: venv still failed; using a shim over the system Python" + as_live "python3 -m venv .venv" || { + log "venv create failed; retry once with --clear" rm -rf "$ROOT_DIR/.venv" - create_python_venv_shim "$ROOT_DIR/.venv" - fi - } - if ! as_live ". .venv/bin/activate && pip install --upgrade pip && pip install -r requirements.txt"; then - log "pip install failed; retry with --no-cache-dir" - as_live ". .venv/bin/activate && pip install --upgrade pip && pip install --no-cache-dir -r requirements.txt" || \ - log "WARN: Python deps incomplete; control plane may fail until fixed manually" + if ! as_live "python3 -m venv .venv"; then + log "WARN: venv still failed; using a shim over the system Python" + rm -rf "$ROOT_DIR/.venv" + create_python_venv_shim "$ROOT_DIR/.venv" + fi + } + else + log "Reusing existing Python virtual environment" fi + if [ -f "$req_stamp" ] && [ "$(cat "$req_stamp" 2>/dev/null)" = "$req_hash" ]; then + log "Python requirements unchanged; skipping pip install" + return 0 + fi + if ! as_live ". .venv/bin/activate && python -m pip install --upgrade pip && python -m pip install -r requirements.txt"; then + log "pip install failed; retry with --no-cache-dir" + if ! as_live ". .venv/bin/activate && python -m pip install --upgrade pip && python -m pip install --no-cache-dir -r requirements.txt"; then + log "WARN: Python deps incomplete; control plane may fail until fixed manually" + return 0 + fi + fi + printf '%s\n' "$req_hash" >"$req_stamp" + chown live:live "$req_stamp" 2>/dev/null || true } prepare_web_console() { log "Building web console" - if as_live "cd web-console && if [ -f package-lock.json ]; then npm ci; else npm install; fi && npm run build"; then + if as_live ". .venv/bin/activate && python scripts/launch.py --build-only --no-env-check"; then return 0 fi - log "web console build failed; cleaning node_modules and retrying" - as_live "cd web-console && rm -rf node_modules .next && npm install && npm run build" || \ + log "web console build failed; cleaning artifacts and retrying" + as_live "cd web-console && rm -rf node_modules .next out" || true + if ! as_live ". .venv/bin/activate && python scripts/launch.py --build-only --no-env-check"; then log "WARN: web console build still failed — service may serve stale assets until rebuilt" + fi } install_live_console_service() { @@ -736,6 +753,8 @@ install_live_console_service() { Description=Live Super Hub Control Plane After=network-online.target docker.service Wants=network-online.target +# 避免构建/依赖短暂失败时触发 systemd 默认「5 次/10s」后永久停跑(表现为 live-edge 502、:8001 无监听) +StartLimitIntervalSec=0 [Service] User=live @@ -747,8 +766,6 @@ LimitNOFILE=$LIVE_NOFILE_SOFT ExecStart=$ROOT_DIR/start.sh Restart=always RestartSec=5 -# 避免构建/依赖短暂失败时触发 systemd 默认「5 次/10s」后永久停跑(表现为 live-edge 502、:8001 无监听) -StartLimitIntervalSec=0 # 首次 npm build / 冷启动较慢;过小会导致主进程在 listen 前被 SIGTERM TimeoutStartSec=300 TimeoutStopSec=30 @@ -1338,14 +1355,27 @@ else: path.write_text(text, encoding="utf-8") PY chown -R live:live "$ANDROID_PANEL_DIR" - rm -rf "$ANDROID_PANEL_DIR/.venv" - if ! runuser -u live -- bash -lc "python3 -m venv '$ANDROID_PANEL_DIR/.venv'"; then - log "WARN: Android panel venv failed; using a shim over the system Python" + local panel_req_hash panel_req_stamp + panel_req_stamp="$ANDROID_PANEL_DIR/.venv/.requirements.sha256" + panel_req_hash="$(sha256sum "$ANDROID_PANEL_DIR/requirements.txt" 2>/dev/null | awk '{print $1}')" + if ! runuser -u live -- bash -lc "test -x '$ANDROID_PANEL_DIR/.venv/bin/python' && '$ANDROID_PANEL_DIR/.venv/bin/python' -V >/dev/null 2>&1"; then rm -rf "$ANDROID_PANEL_DIR/.venv" - create_python_venv_shim "$ANDROID_PANEL_DIR/.venv" - chown -R live:live "$ANDROID_PANEL_DIR/.venv" + if ! runuser -u live -- bash -lc "python3 -m venv '$ANDROID_PANEL_DIR/.venv'"; then + log "WARN: Android panel venv failed; using a shim over the system Python" + rm -rf "$ANDROID_PANEL_DIR/.venv" + create_python_venv_shim "$ANDROID_PANEL_DIR/.venv" + chown -R live:live "$ANDROID_PANEL_DIR/.venv" + fi + else + log "Reusing Android panel virtual environment" + fi + if [ ! -f "$panel_req_stamp" ] || [ "$(cat "$panel_req_stamp" 2>/dev/null)" != "$panel_req_hash" ]; then + runuser -u live -- bash -lc ". '$ANDROID_PANEL_DIR/.venv/bin/activate' && python -m pip install --upgrade pip && python -m pip install -r '$ANDROID_PANEL_DIR/requirements.txt'" + printf '%s\n' "$panel_req_hash" >"$panel_req_stamp" + chown live:live "$panel_req_stamp" 2>/dev/null || true + else + log "Android panel requirements unchanged; skipping pip install" fi - runuser -u live -- bash -lc ". '$ANDROID_PANEL_DIR/.venv/bin/activate' && pip install --upgrade pip && pip install -r '$ANDROID_PANEL_DIR/requirements.txt'" allow_tcp_port_if_firewall_active "$ANDROID_PANEL_PORT" cat >/etc/systemd/system/live-android-panel.service <