File size: 4,007 Bytes
6a1cba7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""Build pure-Python wheel and sdist artifacts with only the Python stdlib.

This is used by local release validation in environments where the setuptools
build frontend hangs before reaching the project backend.
"""

from __future__ import annotations

import base64
import csv
import hashlib
import io
import tarfile
import tomllib
import zipfile
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]


def _hash_record(data: bytes) -> tuple[str, str]:
    digest = base64.urlsafe_b64encode(hashlib.sha256(data).digest()).decode().rstrip("=")
    return f"sha256={digest}", str(len(data))


def _metadata(project: dict) -> str:
    lines = [
        "Metadata-Version: 2.4",
        f"Name: {project['name']}",
        f"Version: {project['version']}",
        f"Summary: {project.get('description', '')}",
        "License-Expression: Apache-2.0",
        f"Requires-Python: {project.get('requires-python', '')}",
        "Description-Content-Type: text/markdown",
        "License-File: LICENSE",
    ]
    for extra, deps in project.get("optional-dependencies", {}).items():
        lines.append(f"Provides-Extra: {extra}")
        for dep in deps:
            lines.append(f'Requires-Dist: {dep}; extra == "{extra}"')
    lines.append("")
    lines.append((ROOT / "README.md").read_text(encoding="utf-8"))
    return "\n".join(lines) + "\n"


def _build_wheel(out_dir: Path, project: dict) -> Path:
    name = project["name"]
    version = project["version"]
    dist_name = name.replace("-", "_")
    dist_info = f"{dist_name}-{version}.dist-info"

    entries: dict[str, bytes] = {}
    for path in sorted((ROOT / "stem_ai").glob("*.py")):
        entries[f"stem_ai/{path.name}"] = path.read_bytes()
    entries[f"{dist_info}/METADATA"] = _metadata(project).encode("utf-8")
    entries[f"{dist_info}/WHEEL"] = (
        b"Wheel-Version: 1.0\n"
        b"Generator: stem-ai-stdlib-build\n"
        b"Root-Is-Purelib: true\n"
        b"Tag: py3-none-any\n"
    )
    entries[f"{dist_info}/entry_points.txt"] = b"[console_scripts]\nstem = stem_ai.cli:main\n"
    entries[f"{dist_info}/top_level.txt"] = b"stem_ai\n"
    entries[f"{dist_info}/licenses/LICENSE"] = (ROOT / "LICENSE").read_bytes()

    rows = []
    for arcname, data in entries.items():
        digest, size = _hash_record(data)
        rows.append([arcname, digest, size])
    rows.append([f"{dist_info}/RECORD", "", ""])
    record = io.StringIO()
    csv.writer(record, lineterminator="\n").writerows(rows)
    entries[f"{dist_info}/RECORD"] = record.getvalue().encode("utf-8")

    wheel_path = out_dir / f"{dist_name}-{version}-py3-none-any.whl"
    with zipfile.ZipFile(wheel_path, "w", compression=zipfile.ZIP_DEFLATED) as wheel:
        for arcname, data in entries.items():
            wheel.writestr(arcname, data)
    return wheel_path


def _build_sdist(out_dir: Path, project: dict) -> Path:
    name = project["name"].replace("-", "_")
    version = project["version"]
    prefix = f"{name}-{version}"
    files = [
        "CHANGELOG.md",
        "CONTRIBUTING.md",
        "LICENSE",
        "MANIFEST.in",
        "README.md",
        "pyproject.toml",
        "requirements.txt",
    ]
    files += [str(p.relative_to(ROOT)).replace("\\", "/") for p in sorted((ROOT / "stem_ai").glob("*.py"))]
    files += [str(p.relative_to(ROOT)).replace("\\", "/") for p in sorted((ROOT / "tests").glob("*.py"))]

    sdist_path = out_dir / f"{prefix}.tar.gz"
    with tarfile.open(sdist_path, "w:gz") as sdist:
        for rel in files:
            path = ROOT / rel
            if path.exists():
                sdist.add(path, arcname=f"{prefix}/{rel}")
    return sdist_path


def main() -> None:
    project = tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8"))["project"]
    out_dir = ROOT / "dist"
    out_dir.mkdir(exist_ok=True)
    wheel = _build_wheel(out_dir, project)
    sdist = _build_sdist(out_dir, project)
    print(wheel)
    print(sdist)


if __name__ == "__main__":
    main()