Files
kadastr-nalog/fetch_vendor.py
2026-06-01 17:05:07 +05:00

122 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Скачивает портативный Firefox и geckodriver (Windows) в папку vendor/,
чтобы build.py / build_wine.sh встроили их в .exe. Тогда конечному
пользователю нужно установить только КриптоПро — Firefox и драйвер уже внутри.
Запуск (на машине сборки, можно на Linux):
python fetch_vendor.py # win64 (по умолчанию)
python fetch_vendor.py --arch win32
python fetch_vendor.py --lang en-US
Для распаковки Firefox нужен 7-Zip:
Linux: sudo apt install p7zip-full
Windows: установите 7-Zip и добавьте 7z в PATH
"""
from __future__ import annotations
import argparse
import io
import json
import shutil
import subprocess
import sys
import urllib.request
import zipfile
from pathlib import Path
ROOT = Path(__file__).parent
VENDOR = ROOT / "vendor"
GECKO_API = "https://api.github.com/repos/mozilla/geckodriver/releases/latest"
def _download(url: str) -> bytes:
print(f"{url}")
req = urllib.request.Request(url, headers={"User-Agent": "fetch-vendor"})
with urllib.request.urlopen(req, timeout=120) as resp:
return resp.read()
def _which_7z() -> str | None:
for name in ("7z", "7za", "7zr"):
if shutil.which(name):
return name
return None
def fetch_geckodriver(arch: str) -> None:
print("geckodriver:")
data = json.loads(_download(GECKO_API).decode("utf-8"))
asset = next(
(a for a in data["assets"] if f"{arch}.zip" in a["name"] and a["name"].endswith(".zip")),
None,
)
if not asset:
names = [a["name"] for a in data["assets"]]
sys.exit(f" Не найден ассет для {arch}. Доступно: {names}")
blob = _download(asset["browser_download_url"])
with zipfile.ZipFile(io.BytesIO(blob)) as z:
member = next(n for n in z.namelist() if n.endswith("geckodriver.exe"))
VENDOR.mkdir(exist_ok=True)
with z.open(member) as src, open(VENDOR / "geckodriver.exe", "wb") as dst:
shutil.copyfileobj(src, dst)
print(f"{VENDOR / 'geckodriver.exe'} ({data['tag_name']})")
def fetch_firefox(arch: str, lang: str) -> None:
print("Firefox (портативный):")
sevenzip = _which_7z()
if not sevenzip:
print(
" ✗ 7-Zip не найден — не могу распаковать установщик Firefox.\n"
" Установите 7-Zip (Linux: sudo apt install p7zip-full), либо вручную\n"
" распакуйте Firefox так, чтобы получилось vendor/firefox/firefox.exe"
)
return
os_param = "win64" if arch == "win64" else "win"
url = f"https://download.mozilla.org/?product=firefox-latest&os={os_param}&lang={lang}"
installer = VENDOR / "_firefox_setup.exe"
VENDOR.mkdir(exist_ok=True)
installer.write_bytes(_download(url))
extract_dir = VENDOR / "_ff_extract"
if extract_dir.exists():
shutil.rmtree(extract_dir)
# Установщик Firefox — это 7-Zip SFX; внутри папка core/ с firefox.exe.
subprocess.run(
[sevenzip, "x", "-y", f"-o{extract_dir}", str(installer)],
check=True, stdout=subprocess.DEVNULL,
)
core = extract_dir / "core"
if not (core / "firefox.exe").exists():
sys.exit(f" В установщике не найден core/firefox.exe (распаковано в {extract_dir})")
target = VENDOR / "firefox"
if target.exists():
shutil.rmtree(target)
shutil.move(str(core), str(target))
installer.unlink(missing_ok=True)
shutil.rmtree(extract_dir, ignore_errors=True)
print(f"{target / 'firefox.exe'}")
def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("--arch", choices=("win64", "win32"), default="win64")
ap.add_argument("--lang", default="ru")
args = ap.parse_args()
print(f"Папка: {VENDOR} (arch={args.arch}, lang={args.lang})\n")
fetch_geckodriver(args.arch)
print()
fetch_firefox(args.arch, args.lang)
print("\nГотово. Теперь соберите: python build.py")
if __name__ == "__main__":
main()