updated deploy scripts and locations

This commit is contained in:
buenosairesam
2025-12-31 08:21:07 -03:00
parent 9e9e0a5a25
commit fc63e9010c
33 changed files with 160283 additions and 758 deletions

192
build.py
View File

@@ -4,31 +4,29 @@ Soleprint Build Tool
Builds the soleprint instance using modelgen for model generation.
Modes:
- dev: Uses symlinks for quick development (edit source, run from gen/)
- deploy: Copies everything for production deployment (no symlinks)
Both dev and deploy modes copy files (no symlinks) for Docker compatibility.
After editing source files, re-run `python build.py dev` to update gen/.
Usage:
python build.py dev
python build.py dev --cfg amar
python build.py deploy --output /path/to/deploy/
python build.py models
python build.py dev # Build gen/ from source
python build.py dev --cfg amar # Include amar room config
python build.py deploy --output /path/ # Build for production
python build.py models # Only regenerate models
Examples:
# Set up dev environment (soleprint only)
# Set up dev environment
python build.py dev
cd gen && .venv/bin/python run.py
# Set up dev environment with amar room config
# With room config
python build.py dev --cfg amar
# Build for deployment
python build.py deploy --output ../deploy/soleprint/
# Only regenerate models
python build.py models
"""
import argparse
import logging
import os
import shutil
import subprocess
@@ -38,31 +36,24 @@ from pathlib import Path
# SPR root is where this script lives
SPR_ROOT = Path(__file__).resolve().parent
# Configure logging
logging.basicConfig(
level=logging.INFO,
format="%(message)s",
)
log = logging.getLogger(__name__)
def ensure_dir(path: Path):
"""Create directory if it doesn't exist."""
path.mkdir(parents=True, exist_ok=True)
def create_symlink(source: Path, target: Path):
"""Create a symlink, removing existing if present."""
if target.exists() or target.is_symlink():
if target.is_symlink():
target.unlink()
elif target.is_dir():
shutil.rmtree(target)
else:
target.unlink()
# Make relative symlink
rel_source = os.path.relpath(source, target.parent)
target.symlink_to(rel_source)
print(f" Linked: {target.name} -> {rel_source}")
def copy_path(source: Path, target: Path):
"""Copy file or directory, resolving symlinks."""
if target.exists():
if target.is_symlink():
target.unlink()
elif target.exists():
if target.is_dir():
shutil.rmtree(target)
else:
@@ -70,10 +61,10 @@ def copy_path(source: Path, target: Path):
if source.is_dir():
shutil.copytree(source, target, symlinks=False)
print(f" Copied: {target.name}/ ({count_files(target)} files)")
log.info(f" Copied: {target.name}/ ({count_files(target)} files)")
else:
shutil.copy2(source, target)
print(f" Copied: {target.name}")
log.info(f" Copied: {target.name}")
def count_files(path: Path) -> int:
@@ -90,7 +81,7 @@ def generate_models(output_dir: Path):
config_path = SPR_ROOT / "cfg" / "soleprint.config.json"
if not config_path.exists():
print(f"Warning: Config not found at {config_path}")
log.warning(f"Config not found at {config_path}")
return False
# Soleprint-specific: models go in models/pydantic/__init__.py
@@ -134,7 +125,7 @@ def copy_cfg(output_dir: Path, cfg_name: str | None):
if cfg_name:
room_cfg = SPR_ROOT / "cfg" / cfg_name
if room_cfg.exists() and room_cfg.is_dir():
print(f"\nCopying {cfg_name} room config...")
log.info(f"\nCopying {cfg_name} room config...")
for item in room_cfg.iterdir():
if item.name == ".env.example":
# Copy .env.example to output root as template
@@ -145,97 +136,100 @@ def copy_cfg(output_dir: Path, cfg_name: str | None):
ensure_dir(cfg_dir / cfg_name)
copy_path(item, cfg_dir / cfg_name / item.name)
else:
print(f"Warning: Room config '{cfg_name}' not found at {room_cfg}")
log.warning(f"Room config '{cfg_name}' not found at {room_cfg}")
def build_dev(output_dir: Path, cfg_name: str | None = None):
"""
Build for development using symlinks.
Build for development using copies (Docker-compatible).
Structure:
gen/
├── main.py -> ../soleprint/main.py
├── run.py -> ../soleprint/run.py
├── index.html -> ../soleprint/index.html
├── requirements.txt -> ../soleprint/requirements.txt
├── dataloader/ -> ../soleprint/dataloader/
├── artery/ -> ../artery/
├── atlas/ -> ../atlas/
├── station/ -> ../station/
├── data/ -> ../data/
├── cfg/ # Copied config
├── main.py
├── run.py
├── index.html
├── requirements.txt
├── Dockerfile
├── dataloader/
├── artery/
├── atlas/
├── station/
├── data/
├── cfg/
├── .env.example # From cfg/<room>/.env.example
└── models/ # Generated
After editing source files, re-run `python build.py dev` to update gen/.
"""
print(f"\n=== Building DEV environment ===")
print(f"SPR root: {SPR_ROOT}")
print(f"Output: {output_dir}")
log.info("\n=== Building DEV environment ===")
log.info(f"SPR root: {SPR_ROOT}")
log.info(f"Output: {output_dir}")
if cfg_name:
print(f"Room cfg: {cfg_name}")
log.info(f"Room cfg: {cfg_name}")
ensure_dir(output_dir)
# Soleprint core files (symlinks)
print("\nLinking soleprint files...")
# Soleprint core files
log.info("\nCopying soleprint files...")
soleprint = SPR_ROOT / "soleprint"
create_symlink(soleprint / "main.py", output_dir / "main.py")
create_symlink(soleprint / "run.py", output_dir / "run.py")
create_symlink(soleprint / "index.html", output_dir / "index.html")
create_symlink(soleprint / "requirements.txt", output_dir / "requirements.txt")
create_symlink(soleprint / "dataloader", output_dir / "dataloader")
copy_path(soleprint / "main.py", output_dir / "main.py")
copy_path(soleprint / "run.py", output_dir / "run.py")
copy_path(soleprint / "index.html", output_dir / "index.html")
copy_path(soleprint / "requirements.txt", output_dir / "requirements.txt")
copy_path(soleprint / "dataloader", output_dir / "dataloader")
if (soleprint / "Dockerfile").exists():
create_symlink(soleprint / "Dockerfile", output_dir / "Dockerfile")
copy_path(soleprint / "Dockerfile", output_dir / "Dockerfile")
# System directories (symlinks)
print("\nLinking systems...")
# System directories
log.info("\nCopying systems...")
for system in ["artery", "atlas", "station"]:
source = SPR_ROOT / system
if source.exists():
create_symlink(source, output_dir / system)
copy_path(source, output_dir / system)
# Data directory (symlink)
print("\nLinking data...")
create_symlink(SPR_ROOT / "data", output_dir / "data")
# Data directory
log.info("\nCopying data...")
copy_path(SPR_ROOT / "data", output_dir / "data")
# Config (copy, not symlink - may be customized)
print("\nCopying config...")
# Config
log.info("\nCopying config...")
copy_cfg(output_dir, cfg_name)
# Models (generated) - pass output_dir, modelgen adds models/pydantic
print("\nGenerating models...")
# Models (generated)
log.info("\nGenerating models...")
if not generate_models(output_dir):
print(" Warning: Model generation failed, you may need to run it manually")
log.warning("Model generation failed, you may need to run it manually")
print("\n✓ Dev build complete!")
print(f"\nTo run:")
print(f" cd {output_dir}")
print(f" python3 -m venv .venv")
print(f" .venv/bin/pip install -r requirements.txt")
print(f" .venv/bin/python main.py # Multi-port (production-like)")
print(f" .venv/bin/python run.py # Single-port (bare-metal dev)")
log.info("\n✓ Dev build complete!")
log.info(f"\nTo run:")
log.info(f" cd {output_dir}")
log.info(f" python3 -m venv .venv")
log.info(f" .venv/bin/pip install -r requirements.txt")
log.info(f" .venv/bin/python run.py # Single-port bare-metal dev")
log.info(f"\nAfter editing source, rebuild with: python build.py dev")
def build_deploy(output_dir: Path, cfg_name: str | None = None):
"""
Build for deployment by copying all files (no symlinks).
"""
print(f"\n=== Building DEPLOY package ===")
print(f"SPR root: {SPR_ROOT}")
print(f"Output: {output_dir}")
log.info("\n=== Building DEPLOY package ===")
log.info(f"SPR root: {SPR_ROOT}")
log.info(f"Output: {output_dir}")
if cfg_name:
print(f"Room cfg: {cfg_name}")
log.info(f"Room cfg: {cfg_name}")
if output_dir.exists():
response = input(f"\nOutput directory exists. Overwrite? [y/N] ")
if response.lower() != "y":
print("Aborted.")
log.info("Aborted.")
return
shutil.rmtree(output_dir)
ensure_dir(output_dir)
# Soleprint core files (copy)
print("\nCopying soleprint files...")
log.info("\nCopying soleprint files...")
soleprint = SPR_ROOT / "soleprint"
copy_path(soleprint / "main.py", output_dir / "main.py")
copy_path(soleprint / "run.py", output_dir / "run.py")
@@ -246,31 +240,31 @@ def build_deploy(output_dir: Path, cfg_name: str | None = None):
copy_path(soleprint / "Dockerfile", output_dir / "Dockerfile")
# System directories (copy)
print("\nCopying systems...")
log.info("\nCopying systems...")
for system in ["artery", "atlas", "station"]:
source = SPR_ROOT / system
if source.exists():
copy_path(source, output_dir / system)
# Data directory (copy)
print("\nCopying data...")
log.info("\nCopying data...")
copy_path(SPR_ROOT / "data", output_dir / "data")
# Config (copy)
print("\nCopying config...")
log.info("\nCopying config...")
copy_cfg(output_dir, cfg_name)
# Models (generate fresh) - pass output_dir, modelgen adds models/pydantic
print("\nGenerating models...")
log.info("\nGenerating models...")
if not generate_models(output_dir):
# Fallback: copy from gen if exists
existing = SPR_ROOT / "gen" / "models"
if existing.exists():
print(" Using existing models from gen/")
log.info(" Using existing models from gen/")
copy_path(existing, output_dir / "models")
# Copy schema.json for reference
print("\nCopying schema...")
log.info("\nCopying schema...")
copy_path(SPR_ROOT / "schema.json", output_dir / "schema.json")
# Create run script
@@ -289,29 +283,29 @@ echo "Starting soleprint on http://localhost:12000"
.venv/bin/python main.py
""")
run_script.chmod(0o755)
print(" Created: start.sh")
log.info(" Created: start.sh")
total_files = count_files(output_dir)
print(f"\n✓ Deploy build complete! ({total_files} files)")
print(f"\nTo run:")
print(f" cd {output_dir}")
print(f" ./start.sh")
print(f"\nOr deploy to server:")
print(f" rsync -av {output_dir}/ server:/app/soleprint/")
print(f" ssh server 'cd /app/soleprint && ./start.sh'")
log.info(f"\n✓ Deploy build complete! ({total_files} files)")
log.info(f"\nTo run:")
log.info(f" cd {output_dir}")
log.info(f" ./start.sh")
log.info(f"\nOr deploy to server:")
log.info(f" rsync -av {output_dir}/ server:/app/soleprint/")
log.info(f" ssh server 'cd /app/soleprint && ./start.sh'")
def build_models():
"""Only regenerate models."""
print(f"\n=== Generating models only ===")
log.info("\n=== Generating models only ===")
output_dir = SPR_ROOT / "gen"
ensure_dir(output_dir)
if generate_models(output_dir):
print("\n✓ Models generated!")
log.info("\n✓ Models generated!")
else:
print("\nError: Model generation failed", file=sys.stderr)
log.error("Model generation failed")
sys.exit(1)
@@ -325,7 +319,7 @@ def main():
subparsers = parser.add_subparsers(dest="command", required=True)
# dev command
dev_parser = subparsers.add_parser("dev", help="Build for development (symlinks)")
dev_parser = subparsers.add_parser("dev", help="Build for development (copies)")
dev_parser.add_argument(
"--output",
"-o",