forked from wrenn/wrenn
127 lines
3.9 KiB
Python
127 lines
3.9 KiB
Python
import os
|
|
import sys
|
|
|
|
from wrenn import Capsule, StreamExitEvent, StreamStderrEvent, StreamStdoutEvent
|
|
from wrenn._git import GitCommandError
|
|
from wrenn.models import FileEntry
|
|
|
|
GO_VERSION = os.getenv("GO_VERSION", "1.25.8")
|
|
REPO_URL = "https://git.omukk.dev/wrenn/wrenn.git"
|
|
REPO_DIR = "/opt/wrenn"
|
|
BUILDS_DIR = os.path.join(os.path.dirname(__file__), "..", "..", "builds")
|
|
|
|
|
|
def run(capsule: Capsule, cmd: str, timeout: int = 30) -> int:
|
|
result = capsule.commands.run(cmd, timeout=timeout)
|
|
if result.exit_code != 0:
|
|
print(f"FAIL [{cmd.split()[0]}]: exit={result.exit_code}", file=sys.stderr)
|
|
if result.stderr:
|
|
print(result.stderr.strip(), file=sys.stderr)
|
|
return result.exit_code
|
|
print(f"OK [{cmd.split()[0]}]")
|
|
return 0
|
|
|
|
|
|
def install_go(capsule: Capsule) -> bool:
|
|
tarball = f"go{GO_VERSION}.linux-amd64.tar.gz"
|
|
url = f"https://go.dev/dl/{tarball}"
|
|
|
|
if run(capsule, "apt update") != 0:
|
|
return False
|
|
if run(capsule, "apt install -y make build-essential file") != 0:
|
|
return False
|
|
if run(capsule, f"curl -LO {url}", timeout=120) != 0:
|
|
return False
|
|
if run(capsule, f"tar -C /usr/local -xzf {tarball}", timeout=60) != 0:
|
|
return False
|
|
if run(capsule, 'echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.profile') != 0:
|
|
return False
|
|
if run(capsule, "rm -f " + tarball) != 0:
|
|
return False
|
|
|
|
result = capsule.commands.run("/usr/local/go/bin/go version")
|
|
print(result.stdout.strip())
|
|
return result.exit_code == 0
|
|
|
|
|
|
def clone_repo(capsule: Capsule) -> bool:
|
|
try:
|
|
capsule.git.clone(REPO_URL, REPO_DIR)
|
|
print("OK [git clone]")
|
|
return True
|
|
except GitCommandError as e:
|
|
print(f"FAIL [git clone]: {e}", file=sys.stderr)
|
|
return False
|
|
|
|
|
|
def build_app(capsule: Capsule) -> bool:
|
|
handle = capsule.commands.run(
|
|
"CGO_ENABLED=1 make build",
|
|
background=True,
|
|
cwd=REPO_DIR,
|
|
envs={
|
|
"PATH": "/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
},
|
|
)
|
|
print(f"make build started (pid={handle.pid}), streaming output...")
|
|
|
|
exit_code = 0
|
|
for event in capsule.commands.connect(handle.pid):
|
|
if isinstance(event, StreamStdoutEvent):
|
|
print(event.data, end="")
|
|
elif isinstance(event, StreamStderrEvent):
|
|
print(event.data, end="", file=sys.stderr)
|
|
elif isinstance(event, StreamExitEvent):
|
|
exit_code = event.exit_code
|
|
|
|
if exit_code != 0:
|
|
print(f"FAIL [make build]: exit={exit_code}", file=sys.stderr)
|
|
return False
|
|
print("OK [make build]")
|
|
return True
|
|
|
|
|
|
def download_artifacts(capsule: Capsule) -> bool:
|
|
remote_dir = f"{REPO_DIR}/builds"
|
|
entries = capsule.files.list(remote_dir, depth=1)
|
|
files = [e for e in entries if e.type != "directory"]
|
|
|
|
if not files:
|
|
print("FAIL [download]: no files found in builds/", file=sys.stderr)
|
|
return False
|
|
|
|
local_dir = os.path.normpath(BUILDS_DIR)
|
|
os.makedirs(local_dir, exist_ok=True)
|
|
|
|
for entry in files:
|
|
name = entry.name or "unknown"
|
|
remote_path = f"{remote_dir}/{name}"
|
|
local_path = os.path.join(local_dir, name)
|
|
print(f"Downloading {name} ({entry.size or '?'} bytes)...")
|
|
|
|
with open(local_path, "wb") as f:
|
|
for chunk in capsule.files.download_stream(remote_path):
|
|
f.write(chunk)
|
|
|
|
print(f"OK [download {name}]")
|
|
|
|
return True
|
|
|
|
|
|
def main() -> None:
|
|
with Capsule(wait=True, vcpus=4, memory_mb=4096) as capsule:
|
|
print(f"Capsule: {capsule.capsule_id}")
|
|
if not install_go(capsule):
|
|
sys.exit(1)
|
|
if not clone_repo(capsule):
|
|
sys.exit(1)
|
|
if not build_app(capsule):
|
|
sys.exit(1)
|
|
if not download_artifacts(capsule):
|
|
sys.exit(1)
|
|
print("Done.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|