"""Fast deploy: upload only book CSS + rebuild web (no full file dump).""" from __future__ import annotations import sys import time from pathlib import Path import paramiko sys.stdout.reconfigure(encoding="utf-8", errors="replace") HOST = "107.173.30.245" USER = "root" PASS = "Xiao4669805" REMOTE = "/opt/nomadweb" DOMAIN = "nomadweb.nomadro.com" FILES = [ "frontend/src/app/globals.css", "frontend/src/components/SiteShell.tsx", "frontend/src/app/book/ebook-globals.css", "frontend/src/components/ebook/ScrollReaderShell.tsx", ] BUILD = f""" set -euo pipefail exec 9>/var/lock/nomadro-deploy.lock if ! flock -n 9; then echo LOCK_BUSY exit 75 fi REMOTE={REMOTE} DOMAIN={DOMAIN} export NEXT_TELEMETRY_DISABLED=1 export NEXT_PUBLIC_API_URL=https://${{DOMAIN}}/api/v1 export NEXT_PUBLIC_SITE_URL=https://${{DOMAIN}} export NODE_ENV=production echo BUILD_START cd "$REMOTE/frontend" # keep node_modules; only rebuild rm -rf .next NPM_CONFIG_PRODUCTION=false npm run build mkdir -p .next/standalone/.next rm -rf .next/standalone/public .next/standalone/.next/static cp -a public .next/standalone/public cp -a .next/static .next/standalone/.next/static rm -rf .next/standalone/content mkdir -p .next/standalone/content cp -a content .next/standalone/content systemctl restart nomadro-web ok=0 for i in $(seq 1 40); do web=$(curl -s -o /dev/null -w '%{{http_code}}' http://127.0.0.1:3055/ || true) echo "try=$i web=$web" if [ "$web" = "200" ]; then ok=1; break; fi sleep 1 done echo FAST_CSS_SYNC=1 [ "$ok" = 1 ] """ def ensure_dir(sftp: paramiko.SFTPClient, path: str) -> None: parts = path.strip("/").split("/") cur = "" for p in parts: cur += "/" + p try: sftp.stat(cur) except FileNotFoundError: try: sftp.mkdir(cur) except OSError: pass def main() -> int: root = Path(__file__).resolve().parents[1] t0 = time.time() client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) print("Connecting...", flush=True) client.connect(HOST, username=USER, password=PASS, timeout=30) sftp = client.open_sftp() for rel in FILES: local = root / rel remote = f"{REMOTE}/{rel}" print(f"UPLOAD {rel}", flush=True) ensure_dir(sftp, str(Path(remote).parent).replace("\\", "/")) sftp.put(str(local), remote) sftp.close() print("Uploaded. Building...", flush=True) _, stdout, stderr = client.exec_command( f"cat > /tmp/nomadro-fast.sh <<'EOF'\n{BUILD}\nEOF\nbash /tmp/nomadro-fast.sh", timeout=900, ) while True: line = stdout.readline() if not line: break print(line.rstrip(), flush=True) err = stderr.read().decode("utf-8", "replace") if err.strip(): print("LOG:", err[-800:], flush=True) code = stdout.channel.recv_exit_status() client.close() print(f"exit: {code}", flush=True) print(f"Done in {time.time() - t0:.0f}s", flush=True) return code if __name__ == "__main__": raise SystemExit(main())