Track deploy_remote.py and point docs at the committed entrypoint.
Keep ephemeral scripts/_*.py ignored while making one-shot production deploy reproducible from git. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
104
scripts/deploy_remote.py
Normal file
104
scripts/deploy_remote.py
Normal file
@@ -0,0 +1,104 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user