"""One-shot deploy to https://cyd.smallzhiyuns.com. See DEPLOY.md.""" from __future__ import annotations import io import os import sys import tarfile from pathlib import Path import paramiko sys.stdout.reconfigure(encoding="utf-8", errors="replace") # Defaults match DEPLOY.md (overridable via env). HOST = os.environ.get("CYD_DEPLOY_HOST", "192.227.152.110") USER = os.environ.get("CYD_DEPLOY_USER", "root") PASSWORD = os.environ.get("CYD_DEPLOY_PASS", "Leaf448772566@") REMOTE_DIR = "/home/dsx2016/docker/cydweb" CADDY_DIR = "/home/dsx2016/docker/caddy" DOMAIN = "cyd.smallzhiyuns.com" ROOT = Path(__file__).resolve().parents[1] EXCLUDE_DIRS = {"node_modules", ".next", ".git", ".cursor", "__pycache__"} def should_skip(rel: str) -> bool: parts = Path(rel).parts if any(p in EXCLUDE_DIRS for p in parts): return True if rel.replace("\\", "/").startswith("scripts/_"): return True return False def make_tarball() -> bytes: buf = io.BytesIO() with tarfile.open(fileobj=buf, mode="w:gz") as tar: for path in ROOT.rglob("*"): if not path.is_file(): continue rel = path.relative_to(ROOT).as_posix() if should_skip(rel): continue tar.add(path, arcname=rel) return buf.getvalue() def main() -> None: if not PASSWORD: raise SystemExit("Set CYD_DEPLOY_PASS (see DEPLOY.md)") print(f"Deploy target: {USER}@{HOST} -> {REMOTE_DIR} ({DOMAIN})") print("Creating archive…") data = make_tarball() print(f"Archive size: {len(data) / 1024 / 1024:.1f} MB") client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(HOST, username=USER, password=PASSWORD, timeout=30) def run(cmd: str, timeout: int = 600) -> str: print(f"$ {cmd}") stdin, stdout, stderr = client.exec_command(cmd, timeout=timeout) out = stdout.read().decode("utf-8", errors="replace") err = stderr.read().decode("utf-8", errors="replace") code = stdout.channel.recv_exit_status() text = (out + err).encode("ascii", errors="replace").decode("ascii") if text.strip(): print(text) if code != 0: raise RuntimeError(f"cmd failed ({code}): {cmd}") return out run(f"mkdir -p {REMOTE_DIR}") sftp = client.open_sftp() remote_tar = "/tmp/cydweb-deploy.tar.gz" print(f"Uploading to {remote_tar}…") with sftp.file(remote_tar, "wb") as rf: rf.write(data) sftp.close() run(f"find {REMOTE_DIR} -mindepth 1 -maxdepth 1 -exec rm -rf {{}} +") run(f"tar -xzf {remote_tar} -C {REMOTE_DIR} && rm -f {remote_tar}") run(f"find {REMOTE_DIR}/firmware -name firmware.bin | wc -l") run(f"find {REMOTE_DIR}/firmware -name preview.html | wc -l") run(f"cd {REMOTE_DIR} && docker compose build", timeout=1800) run(f"cd {REMOTE_DIR} && docker compose up -d") run( f"cd {CADDY_DIR} && docker compose exec -T caddy " f"caddy reload --config /etc/caddy/Caddyfile || true" ) run("sleep 4; curl -sI http://127.0.0.1:3020/en | head -15") run(f"curl -sI https://{DOMAIN}/en | head -20") run( f"curl -s https://{DOMAIN}/en | grep -o 'umami.dsx2020.com/script.js' | head -3 || true" ) client.close() print(f"DONE — https://{DOMAIN}") if __name__ == "__main__": main()