Files
timmy-home/scripts/evennia/bootstrap_local_evennia.py

121 lines
3.9 KiB
Python
Executable File

#!/usr/bin/env python3
from __future__ import annotations
import json
import os
import subprocess
import sys
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
RUNTIME_ROOT = Path.home() / ".timmy" / "evennia"
GAME_DIR = RUNTIME_ROOT / "timmy_world"
VENV_DIR = RUNTIME_ROOT / "venv"
EVENNIA_BIN = VENV_DIR / "bin" / "evennia"
PYTHON_BIN = VENV_DIR / "bin" / "python3"
OPERATOR_USER = os.environ.get("TIMMY_EVENNIA_OPERATOR", "Alexander")
OPERATOR_EMAIL = os.environ.get("TIMMY_EVENNIA_OPERATOR_EMAIL", "alexpaynex@gmail.com")
OPERATOR_PASSWORD = os.environ.get("TIMMY_EVENNIA_OPERATOR_PASSWORD", "timmy-local-dev")
TIMMY_PASSWORD = os.environ.get("TIMMY_EVENNIA_TIMMY_PASSWORD", "timmy-world-dev")
def ensure_venv():
if not PYTHON_BIN.exists():
subprocess.run([sys.executable, "-m", "venv", str(VENV_DIR)], check=True)
subprocess.run([str(PYTHON_BIN), "-m", "pip", "install", "--upgrade", "pip"], check=True)
subprocess.run([str(PYTHON_BIN), "-m", "pip", "install", "evennia"], check=True)
def ensure_game_dir():
if not GAME_DIR.exists():
RUNTIME_ROOT.mkdir(parents=True, exist_ok=True)
subprocess.run([str(EVENNIA_BIN), "--init", "timmy_world"], cwd=RUNTIME_ROOT, check=True)
def run_evennia(args, env=None, timeout=600):
result = subprocess.run([str(EVENNIA_BIN), *args], cwd=GAME_DIR, env=env, timeout=timeout, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(result.stderr or result.stdout)
return result.stdout
def ensure_db_and_owner():
run_evennia(["migrate"])
env = os.environ.copy()
env.update(
{
"EVENNIA_SUPERUSER_USERNAME": OPERATOR_USER,
"EVENNIA_SUPERUSER_EMAIL": OPERATOR_EMAIL,
"EVENNIA_SUPERUSER_PASSWORD": OPERATOR_PASSWORD,
}
)
run_evennia(["shell", "-c", "from evennia.accounts.models import AccountDB; print(AccountDB.objects.count())"], env=env)
def ensure_server_started():
run_evennia(["start"], timeout=240)
def run_shell(code: str):
env = os.environ.copy()
env["PYTHONPATH"] = str(REPO_ROOT) + os.pathsep + env.get("PYTHONPATH", "")
return run_evennia(["shell", "-c", code], env=env)
def ensure_timmy_and_world():
code = f'''
import sys
sys.path.insert(0, {str(REPO_ROOT)!r})
from evennia.accounts.models import AccountDB
from evennia.accounts.accounts import DefaultAccount
from evennia import DefaultRoom, DefaultExit, create_object
from evennia.utils.search import search_object
from evennia_tools.layout import ROOMS, EXITS, OBJECTS
from typeclasses.objects import Object
AGENTS = ["Timmy", "Allegro", "Hermes", "Gemma"]
for agent_name in AGENTS:
acc = AccountDB.objects.filter(username__iexact=agent_name).first()
if not acc:
acc, errs = DefaultAccount.create(username=agent_name, password=TIMMY_PASSWORD)
char = list(acc.characters)[0]
if agent_name == "Timmy":
char.location = room_map["Gate"]
char.home = room_map["Gate"]
else:
char.location = room_map["Courtyard"]
char.home = room_map["Courtyard"]
char.save()
print(f"PROVISIONED {agent_name} at {char.location.key}")
'''
return run_shell(code)
def verify():
status = run_evennia(["status"], timeout=120)
info = run_evennia(["info"], timeout=120)
web = subprocess.run(
[sys.executable, "-c", "import urllib.request; r=urllib.request.urlopen('http://127.0.0.1:4001', timeout=10); print(r.status); print(r.headers.get('Content-Type'))"],
timeout=30,
capture_output=True,
text=True,
check=True,
)
return {"status": status.strip(), "info": info.strip(), "web": web.stdout.strip()}
def main():
ensure_venv()
ensure_game_dir()
ensure_db_and_owner()
ensure_server_started()
provision = ensure_timmy_and_world()
proof = verify()
print(json.dumps({"provision_stdout": provision, "verification": proof}, indent=2))
if __name__ == "__main__":
main()