OneLauncher-Cracked/distribution/windows/bundle-crt.py

117 lines
3.5 KiB
Python

#!/usr/bin/env python3
import argparse
import re
import shutil
import subprocess
import sys
from pathlib import Path
BEGIN_RES = "# >>> CRT_RESOURCES >>>"
END_RES = "# <<< CRT_RESOURCES <<<"
BEGIN_SEC = "; >>> VC_REDIST_SECTION >>>"
END_SEC = "; <<< VC_REDIST_SECTION <<<"
REPO_ROOT = Path(__file__).resolve().parents[2]
DEFAULT_CARGO_TOML = REPO_ROOT / "packages" / "oneclient_app" / "Cargo.toml"
DEFAULT_OUT = REPO_ROOT / "target" / "crt"
VSWHERE = Path(
r"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"
)
CRT_GLOB = r"VC\Redist\MSVC\**\x64\Microsoft.VC*.CRT\*.dll"
SECTION_REPLACEMENT = """; >>> VC_REDIST_SECTION >>>
; <<< VC_REDIST_SECTION <<<"""
def region(begin: str, end: str) -> re.Pattern:
return re.compile(
r"^[ \t]*" + re.escape(begin) + r".*?^[ \t]*" + re.escape(end) + r"[ \t]*$",
re.DOTALL | re.MULTILINE,
)
REGION_RES = region(BEGIN_RES, END_RES)
REGION_SEC = region(BEGIN_SEC, END_SEC)
def find_crt_dir() -> Path:
"""Locate the newest x64 Microsoft.VC*.CRT redist directory via vswhere."""
if not VSWHERE.is_file():
sys.exit(f"error: vswhere not found at {VSWHERE}; pass --crt-dir explicitly")
out = subprocess.run(
[str(VSWHERE), "-latest", "-products", "*", "-find", CRT_GLOB],
capture_output=True,
text=True,
check=True,
).stdout
dirs = {Path(line).parent for line in out.splitlines() if line.strip()}
if not dirs:
sys.exit(f"error: vswhere found no DLLs matching {CRT_GLOB}")
newest = sorted(dirs, key=lambda p: p.parts)[-1]
print(f"CRT redist dir: {newest}")
return newest
def collect(crt_dir: Path, out_dir: Path) -> list[Path]:
dlls = sorted(crt_dir.glob("*.dll"))
if not dlls:
sys.exit(f"error: no DLLs in {crt_dir}")
if out_dir.exists():
shutil.rmtree(out_dir)
out_dir.mkdir(parents=True)
copied = []
for dll in dlls:
dest = out_dir / dll.name
shutil.copy2(dll, dest)
copied.append(dest)
print(f" {dll.name} ({dest.stat().st_size} bytes)")
return copied
def patch(cargo_toml: Path, dlls: list[Path]) -> None:
text = cargo_toml.read_text(encoding="utf-8")
for pat, name in ((REGION_RES, "CRT_RESOURCES"), (REGION_SEC, "VC_REDIST_SECTION")):
if not pat.search(text):
sys.exit(f"error: {name} region not found in {cargo_toml}")
entries = "\n".join(
f' {{ src = "{str(d).replace(chr(92), chr(92) * 2)}", target = "{d.name}" }},'
for d in dlls
)
block = (
f" {BEGIN_RES}\n"
f" # Generated by distribution/windows/bundle-crt.py -- do not edit by hand.\n"
f"{entries}\n"
f" {END_RES}"
)
text = REGION_RES.sub(lambda _: block, text, count=1)
text = REGION_SEC.sub(lambda _: SECTION_REPLACEMENT, text, count=1)
cargo_toml.write_text(text, encoding="utf-8")
print(f"patched {cargo_toml} with {len(dlls)} app-local CRT DLLs")
def main() -> None:
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("--cargo-toml", type=Path, default=DEFAULT_CARGO_TOML)
ap.add_argument("--out-dir", type=Path, default=DEFAULT_OUT)
ap.add_argument(
"--crt-dir",
type=Path,
help="Microsoft.VC*.CRT directory to copy from (default: ask vswhere)",
)
args = ap.parse_args()
crt_dir = args.crt_dir.resolve() if args.crt_dir else find_crt_dir()
dlls = collect(crt_dir, args.out_dir.resolve())
patch(args.cargo_toml.resolve(), dlls)
if __name__ == "__main__":
main()