mirror of
https://github.com/Shu-Ying/noname-shuying.git
synced 2026-10-18 05:10:00 +08:00
fixed # 补全部分卡牌
fixed # 修复部分已知BUG
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
"""Generate release manifests from committed Git bytes, without creating a tag."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def git(root: Path, *args: str) -> bytes:
|
||||
return subprocess.run(["git", "-c", "core.autocrlf=false", *args], cwd=root,
|
||||
check=True, stdout=subprocess.PIPE).stdout
|
||||
|
||||
|
||||
def prepare(root: Path, version: str) -> None:
|
||||
if not re.fullmatch(r"\d+\.\d+\.\d+\.\d+(?:-rc\.\d+)?", version):
|
||||
raise ValueError("Invalid release version")
|
||||
repository = Path(git(root, "rev-parse", "--show-toplevel").decode("utf-8").strip()).resolve()
|
||||
if repository != root:
|
||||
raise ValueError("Run this tool from the extension repository")
|
||||
rows = git(root, "status", "--porcelain=v1", "-z", "--untracked-files=all").decode("utf-8").split("\0")
|
||||
dirty = []
|
||||
i = 0
|
||||
while i < len(rows):
|
||||
row = rows[i]
|
||||
if row:
|
||||
path = row[3:]
|
||||
if not path.startswith("dist/"):
|
||||
dirty.append(path)
|
||||
if "R" in row[:2] or "C" in row[:2]:
|
||||
i += 1
|
||||
if i < len(rows) and not rows[i].startswith("dist/"):
|
||||
dirty.append(rows[i])
|
||||
i += 1
|
||||
if dirty:
|
||||
raise ValueError("Commit source and new runtime files first; pending files: " + ", ".join(dirty[:8]))
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="shuying-release-") as temporary:
|
||||
workspace = Path(temporary)
|
||||
archive = workspace / "source.zip"
|
||||
stage = workspace / "source"
|
||||
git(root, "archive", "--format=zip", f"--output={archive}", "HEAD")
|
||||
with zipfile.ZipFile(archive) as source:
|
||||
# Git trees cannot contain traversal paths; still check before extracting.
|
||||
for item in source.infolist():
|
||||
path = stage / item.filename
|
||||
if not path.resolve().is_relative_to(stage.resolve()):
|
||||
raise ValueError("Unsafe archive path")
|
||||
source.extractall(stage)
|
||||
subprocess.run([sys.executable, str(stage / "tools/generate_manifest.py"),
|
||||
"--root", str(stage), "--version", version], check=True)
|
||||
subprocess.run([sys.executable, str(stage / "tools/verify_manifest.py"),
|
||||
"--root", str(stage), "--version", version], check=True)
|
||||
output = root / "dist"
|
||||
output.mkdir(exist_ok=True)
|
||||
shutil.copyfile(stage / "dist/manifest.json", output / "manifest.json")
|
||||
components = output / "modules"
|
||||
components.mkdir(exist_ok=True)
|
||||
generated = list((stage / "dist/modules").glob("*.json"))
|
||||
expected = {path.name for path in generated}
|
||||
for path in generated:
|
||||
shutil.copyfile(path, components / path.name)
|
||||
for stale in components.glob("*.json"):
|
||||
if stale.name not in expected:
|
||||
stale.unlink()
|
||||
print("Manifests are ready. Commit dist/manifest.json and dist/modules/*.json before creating the release tag.")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--root", default=".")
|
||||
parser.add_argument("--version", default=os.environ.get("SHUYING_RELEASE_VERSION"))
|
||||
args = parser.parse_args()
|
||||
if not args.version:
|
||||
parser.error("--version is required")
|
||||
prepare(Path(args.root).resolve(), args.version)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user