Files
2026-06-09 18:31:59 +02:00

150 lines
5.8 KiB
Python

#!/usr/bin/env python3
"""
migrate.py — AM Stack A migration launcher.
Points at a .wpress file and runs all extraction phases automatically.
Phases 7+ require human/agent review of staged seed_databases.py.
Usage:
python3 migrate.py --wpress /path/to/backup.wpress --domain example.com [--project /path/to/project]
Output:
Runs phases 0-6, then prints agent breadcrumbs for phases 7-11.
"""
import argparse, os, sys, subprocess, json
SOPS = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SCRIPTS = os.path.join(SOPS, 'scripts')
def run(cmd: list, label: str) -> bool:
print(f"\n[{label}] Running: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=False)
if result.returncode != 0:
print(f"[{label}] FAILED (exit {result.returncode})")
return False
print(f"[{label}] OK")
return True
def phase_header(n: int, title: str):
print(f"\n{'='*60}")
print(f" Phase {n}{title}")
print(f"{'='*60}")
def main():
parser = argparse.ArgumentParser(description='AM Stack A migration launcher')
parser.add_argument('--wpress', required=True, help='Path to .wpress backup file')
parser.add_argument('--domain', required=True, help='Target domain (e.g. example.com)')
parser.add_argument('--project', help='Project directory (default: ~/arisingmedia-websites/{domain})')
args = parser.parse_args()
wpress = os.path.abspath(args.wpress)
domain = args.domain
project = args.project or os.path.expanduser(f'~/arisingmedia-websites/{domain}')
extract_dir = os.path.join(project, '.planning', 'wpress-extract')
data_dir = os.path.join(project, '.planning', 'data')
content_dir = os.path.join(data_dir, 'content')
if not os.path.exists(wpress):
print(f"ERROR: .wpress file not found: {wpress}")
sys.exit(1)
print(f"\nAM Stack A Migration Pipeline")
print(f" Domain: {domain}")
print(f" Project: {project}")
print(f" Archive: {wpress}")
# Phase 0 — Setup
phase_header(0, 'Setup')
for d in [extract_dir, data_dir, content_dir,
os.path.join(project, 'assets', 'images'),
os.path.join(project, 'build'),
os.path.join(project, 'src', 'api', 'data'),
os.path.join(project, 'src', 'api', 'templates'),
os.path.join(project, 'src', 'api', 'components')]:
os.makedirs(d, exist_ok=True)
print(f" mkdir {d}")
# Phase 1 — Extract
phase_header(1, 'Extract .wpress archive')
if not run(['python3', os.path.join(SCRIPTS, 'extract_wpress.py'), wpress, extract_dir], 'Phase 1'):
sys.exit(1)
# Phase 2 — DB Analysis
phase_header(2, 'Database analysis')
if not run(['python3', os.path.join(SCRIPTS, 'analyze_db.py'), extract_dir, data_dir], 'Phase 2'):
sys.exit(1)
# Detect Divi version
site_info_path = os.path.join(data_dir, 'site-info.json')
divi_version = 5
if os.path.exists(site_info_path):
with open(site_info_path) as f:
info = json.load(f)
divi_version = info.get('divi_version', 5)
print(f" Divi version detected: {divi_version}")
# Phase 3 — Nav extraction
phase_header(3, 'Extract navigation menus')
run(['python3', os.path.join(SCRIPTS, 'extract_nav.py'), extract_dir, data_dir], 'Phase 3 (nav)')
# Phase 3 — Content extraction
extract_script = f'extract_divi{divi_version}.py'
pages_json = os.path.join(data_dir, 'pages.json')
if not run(['python3', os.path.join(SCRIPTS, extract_script), pages_json, content_dir], f'Phase 3 (divi{divi_version})'):
print(f" WARNING: content extraction had errors — review {content_dir}")
# Phase 5 — Media
phase_header(5, 'Extract and convert media')
run(['python3', os.path.join(SCRIPTS, 'extract_media.py'), extract_dir, data_dir,
os.path.join(project, 'assets', 'images')], 'Phase 5')
# Phase 6 — Stage seed_databases.py
phase_header(6, 'Stage seed_databases.py skeleton')
seed_path = os.path.join(project, 'build', 'seed_databases.py')
# Check if stage_seed.py exists
stage_script = os.path.join(SCRIPTS, 'stage_seed.py')
if os.path.exists(stage_script):
run(['python3', stage_script, data_dir, seed_path, '--domain', domain], 'Phase 6')
else:
print(f" WARNING: stage_seed.py not found — seed_databases.py must be written manually")
print(f" Reference: /home/sirdrez/arisingmedia-websites/vibrantyou.yoga/build/seed_databases.py")
# Print agent breadcrumbs for remaining phases
print(f"\n{'='*60}")
print(" EXTRACTION COMPLETE — Manual/Agent phases follow")
print(f"{'='*60}")
print(f"""
Phases 0-6 complete. Staged content is at:
{data_dir}/content/ ← extracted page sections (JSON)
{data_dir}/nav.json ← navigation items
{data_dir}/media-manifest.json ← image URL mappings
{seed_path} ← seed_databases.py skeleton
Next steps (see 10-agent-breadcrumbs.md for full detail):
Phase 7 — REVIEW seed_databases.py
Open: {seed_path}
For each page: verify sections_json has correct section types
Replace em-dashes. Remove Divi shortcode residue. Review nav items.
Phase 8 — RUN seed_databases.py
cd {project} && python3 build/seed_databases.py
Verify: output shows all counts > 0
Phase 9 — SCAFFOLD PHP templates
Copy from reference: vibrantyou.yoga/src/api/
Update brand name and colors in _header.php + _footer.php
Phase 10 — BUILD
cd {project} && docker compose build --no-cache && docker compose up -d
Verify: curl -I http://localhost:PORT/
Phase 11 — QA
bash {SOPS}/../tools/verify-protection.sh http://localhost:PORT
Lighthouse in Firefox
Reference: {SOPS}/wp-divi-pipeline-to-am-stack/10-agent-breadcrumbs.md
""")
if __name__ == '__main__':
main()