← Source tree

build_release.py

"""Build public source, cloneable Git mirror and a static demo; no secrets."""
import hashlib
import html
import json
import re
import shutil
import subprocess
import tempfile
import zipfile
from pathlib import Path

ROOT = Path(__file__).resolve().parent


def markdown_page(text):
    # Small build-only renderer for the project's known markdown subset.
    out, code, listing = [], False, False
    for line in text.splitlines():
        if line.startswith('---') and not out:
            continue
        if line.startswith(('title:', 'published:', 'tags:')):
            continue
        if line.startswith('```'):
            out.append('</code></pre>' if code else '<pre><code>')
            code = not code
            continue
        if code:
            out.append(html.escape(line)+'\n')
            continue
        if not line:
            continue
        escaped=html.escape(line)
        escaped=re.sub(r'\[([^\]]+)\]\((https://[^\s)]+)\)',r'<a href="\2">\1</a>',escaped)
        escaped=re.sub(r'\*\*(.+?)\*\*',r'<strong>\1</strong>',escaped)
        escaped=re.sub(r'`([^`]+)`',r'<code>\1</code>',escaped)
        if line.startswith('#'):
            level=min(len(line)-len(line.lstrip('#')),3)
            out.append(f'<h{level}>{escaped[level:].strip()}</h{level}>')
        else:
            out.append('<p>'+escaped+'</p>')
    return '\n'.join(out)


def page(title, content, css='../style.css'):
    return ('<!doctype html><html lang="en"><head><meta charset="utf-8">'
            '<meta name="viewport" content="width=device-width,initial-scale=1">'
            '<meta http-equiv="Content-Security-Policy" content="default-src \'none\'; style-src \'self\'; base-uri \'none\'">'
            f'<title>{html.escape(title)}</title><link rel="stylesheet" href="{css}"></head>'
            f'<body><main class="build-story">{content}</main></body></html>')


def build():
    dist=ROOT/'dist'
    if dist.exists(): shutil.rmtree(dist)
    dist.mkdir()
    source_files=[]
    for path in sorted(ROOT.rglob('*')):
        rel=path.relative_to(ROOT)
        if not path.is_file() or any(part.startswith('.') or part in {'dist','__pycache__'} for part in rel.parts): continue
        if path.suffix in {'.py','.md','.json','.txt','.js','.cjs','.html','.css'} or path.name=='LICENSE': source_files.append((path,rel))
    # Keep the downloadable source free of hosting identity and infrastructure.
    with zipfile.ZipFile(dist/'ReviewQueue-0.6.zip','w',zipfile.ZIP_DEFLATED) as archive:
        for path,rel in source_files: archive.write(path,Path('reviewqueue')/rel)
    for path in (ROOT/'web_demo').iterdir():
        if path.suffix in {'.js','.css','.html'}: shutil.copy2(path,dist/path.name)
    source=dist/'source';source.mkdir()
    index=['<p><a href="../index.html">← Interactive demo</a></p><h1>ReviewQueue source repository</h1>',
           '<p>Original BSD-3-Clause project, started 14 October 2026. This public source browser and the Git mirror contain the same release files.</p>',
           '<p><a href="../ReviewQueue-0.6.zip" download>Download ZIP</a> · <a href="../ReviewQueue.bundle" download>Download Git bundle</a> · <a href="../repository.git/info/refs">Git refs</a></p>',
           '<p>Clone the public read-only repository:</p><pre>git clone https://reviewqueue.rahmat19800402.chatgpt.site/repository.git</pre>',
           '<p>Alternatively, download the bundle and run:</p><pre>git clone ReviewQueue.bundle reviewqueue</pre>']
    for number,(path,rel) in enumerate(source_files):
        dest=f'{number:03}.html'
        content='<p><a href="index.html">← Source tree</a></p><h1>'+html.escape(str(rel))+'</h1><pre>'+html.escape(path.read_text())+'</pre>'
        (source/dest).write_text(page(str(rel),content))
        index.append(f'<p><a href="{dest}">{html.escape(str(rel))}</a></p>')
    with tempfile.TemporaryDirectory() as tmp:
        repo=Path(tmp)/'repo';repo.mkdir()
        for path,rel in source_files:
            (repo/rel).parent.mkdir(parents=True,exist_ok=True);shutil.copy2(path,repo/rel)
        def git(*args):
            return subprocess.run(['git','-C',str(repo),*args],check=True,capture_output=True,text=True).stdout.strip()
        git('init','-b','main')
        git('config','user.name','ReviewQueue contributors')
        git('config','user.email','contributors@reviewqueue.invalid')
        git('add','.')
        git('commit','-m','Release ReviewQueue 0.6: local inference, conservative hints and reproducible checks')
        commit=git('rev-parse','HEAD')
        git('bundle','create',str(dist/'ReviewQueue.bundle'),'--all')
        subprocess.run(['git','clone','--bare',str(repo),str(dist/'repository.git')],check=True,capture_output=True)
        subprocess.run(['git','--git-dir',str(dist/'repository.git'),'update-server-info'],check=True,capture_output=True)
        # No local checkout source paths in the public mirror's config.
        config=dist/'repository.git'/'config'
        config.write_text('[core]\n\trepositoryformatversion = 0\n\tfilemode = true\n\tbare = true\n')
    index.insert(2,f'<p>Release commit: <code>{commit}</code></p>')
    (source/'index.html').write_text(page('ReviewQueue source repository','\n'.join(index)))
    (dist/'article.html').write_text(page('Building ReviewQueue', '<p><a href="index.html">← Interactive demo</a></p><h1>Building ReviewQueue</h1>'+markdown_page((ROOT/'SUBMISSION.md').read_text()),'style.css'))
    manifest=dict(version='0.6',public_repository_commit=commit,
                  source_archive_sha256=hashlib.sha256((dist/'ReviewQueue-0.6.zip').read_bytes()).hexdigest(),
                  browser_visual_qa='not_available_in_this_environment',
                  dev_submission='not_yet_published')
    (dist/'release.json').write_text(json.dumps(manifest,indent=2)+'\n')
    print(json.dumps(manifest))


if __name__=='__main__': build()