Files
CapacityReport/scripts/build_tauri.py
T
nixevol 98f03b3e0e refactor: 统一运行/编译脚本为 scripts/ 下纯 Python(自动 venv,傻瓜式)
新增 _env.py 共享工具与 dev/run/tauri_dev/build_server/build_tauri/build_docker/clean 脚本,
删除旧 build.{sh,ps1,bat}、根 run.bat/debug.bat/start.sh/dev.py、supervisord.conf、packaging/Dockerfile,
Docker 改以根 Dockerfile 为准并重写 compose(/data 卷)。
2026-06-26 11:03:19 +08:00

219 lines
7.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.
"""Tauri 桌面版编译脚本。
用法:
python scripts/build_tauri.py # 编译当前系统的桌面版
python scripts/build_tauri.py --platform windows # 指定平台(windows/linux/macos)
特性:
- Windows 安装包内置 WebView2 离线安装器(tauri.conf.json 已配置 offlineInstaller),
适合无外网、未预装 WebView2 Runtime 的机器。
- Windows NSIS 安装器默认安装到 D:\\Program Files\\CapacityReport(无 D 盘时回落系统盘)。
- 跨平台限制:Tauri 无法可靠跨系统交叉编译,--platform 必须与当前系统一致,否则会提示需在目标系统本机构建。
产物:dist/desktop/ 下的安装包(Windows: .msi/.exe;Linux: .deb/.AppImage;macOS: .dmg)。
"""
from __future__ import annotations
import argparse
import json
import shutil
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
import _env # noqa: E402
TAURI_CONF = _env.SRC_TAURI_DIR / "tauri.conf.json"
NSIS_HOOK = _env.SRC_TAURI_DIR / "windows" / "nsis-hooks.nsh"
INSTALLER_EXTS = {
"windows": (".msi", ".exe"),
"linux": (".deb", ".AppImage", ".rpm"),
"macos": (".dmg", ".app.tar.gz"),
}
# --------------------------------------------------------------------------- NSIS 定制(Windows 默认装 D 盘)
_RESTORE_LINE = " Call RestorePreviousInstallLocation"
_INSTALL_DIR_OVERRIDE = """ Call RestorePreviousInstallLocation
!if "${INSTALLMODE}" == "perMachine"
${If} ${FileExists} "D:\\*.*"
StrCpy $INSTDIR "D:\\Program Files\\${PRODUCTNAME}"
${Else}
${If} ${RunningX64}
StrCpy $INSTDIR "$PROGRAMFILES64\\${PRODUCTNAME}"
${Else}
StrCpy $INSTDIR "$PROGRAMFILES\\${PRODUCTNAME}"
${EndIf}
${EndIf}
!endif
"""
_ON_INIT_TAIL = """ !if "${INSTALLMODE}" == "both"
!insertmacro MULTIUSER_INIT
!endif
FunctionEnd"""
_ON_INIT_OVERRIDE = """ !if "${INSTALLMODE}" == "both"
!insertmacro MULTIUSER_INIT
!endif
!if "${INSTALLMODE}" == "perMachine"
${If} ${FileExists} "D:\\*.*"
StrCpy $INSTDIR "D:\\Program Files\\${PRODUCTNAME}"
${Else}
${If} ${RunningX64}
StrCpy $INSTDIR "$PROGRAMFILES64\\${PRODUCTNAME}"
${Else}
StrCpy $INSTDIR "$PROGRAMFILES\\${PRODUCTNAME}"
${EndIf}
${EndIf}
!endif
FunctionEnd"""
_RESTORE_FUNCTION = """Function RestorePreviousInstallLocation
ReadRegStr $4 SHCTX "${MANUPRODUCTKEY}" ""
StrCmp $4 "" +2 0
StrCpy $INSTDIR $4
FunctionEnd"""
_RESTORE_OVERRIDE = """Function RestorePreviousInstallLocation
!if "${INSTALLMODE}" == "perMachine"
${If} ${FileExists} "D:\\*.*"
StrCpy $INSTDIR "D:\\Program Files\\${PRODUCTNAME}"
Return
${EndIf}
!endif
ReadRegStr $4 SHCTX "${MANUPRODUCTKEY}" ""
StrCmp $4 "" +2 0
StrCpy $INSTDIR $4
FunctionEnd"""
def find_nsis_template() -> Path:
registry = Path.home() / ".cargo" / "registry" / "src"
if not registry.exists():
_env.die(f"未找到 Cargo registry:{registry}", "先运行一次 cargo tauri build 拉取 tauri-bundler。")
candidates = [
path
for path in registry.rglob("installer.nsi")
if "tauri-bundler-" in str(path) and path.parts[-4:] == ("bundle", "windows", "nsis", "installer.nsi")
]
if not candidates:
_env.die("未找到 Tauri NSIS 模板(installer.nsi)", "先运行一次 cargo tauri build 拉取 tauri-bundler。")
return sorted(candidates, reverse=True)[0]
def make_nsis_template(tmp_dir: Path) -> Path:
source = find_nsis_template()
content = source.read_text(encoding="utf-8")
import re
hook_path = str(NSIS_HOOK.resolve())
content, n = re.subn(
r'\{\{#if installer_hooks\}\}\s*!include "\{\{installer_hooks\}\}"\s*\{\{/if\}\}',
f'!include "{hook_path}"',
content,
)
if n == 0:
_env.die("Tauri NSIS 模板已变化:installer_hooks 标记未找到")
for marker, replacement, label in (
(_RESTORE_LINE, _INSTALL_DIR_OVERRIDE, "RestorePreviousInstallLocation 调用点"),
(_ON_INIT_TAIL, _ON_INIT_OVERRIDE, ".onInit 结尾"),
(_RESTORE_FUNCTION, _RESTORE_OVERRIDE, "RestorePreviousInstallLocation 函数"),
):
if marker not in content:
_env.die(f"Tauri NSIS 模板已变化:{label}标记未找到")
content = content.replace(marker, replacement)
target = tmp_dir / "tauri-nsis-installer.nsi"
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(content.replace("\r\n", "\n"), encoding="utf-8", newline="\n")
return target
def build_with_windows_nsis(tmp_dir: Path) -> None:
template = make_nsis_template(tmp_dir)
original = TAURI_CONF.read_text(encoding="utf-8")
try:
config = json.loads(original)
config["bundle"]["windows"]["nsis"]["template"] = str(template)
TAURI_CONF.write_text(json.dumps(config, ensure_ascii=False, indent=2), encoding="utf-8")
_env.remove_path(_env.SRC_TAURI_DIR / "target" / "release" / "bundle")
_env.step("编译 Tauri 桌面版(cargo tauri build)")
_env.run(["cargo", "tauri", "build"], cwd=_env.SRC_TAURI_DIR)
finally:
TAURI_CONF.write_text(original, encoding="utf-8")
def collect_installers(platform: str) -> None:
bundle_dir = _env.SRC_TAURI_DIR / "target" / "release" / "bundle"
out_dir = _env.DIST_DIR / "desktop"
_env.remove_path(out_dir)
out_dir.mkdir(parents=True, exist_ok=True)
exts = INSTALLER_EXTS[platform]
found = 0
for path in bundle_dir.rglob("*"):
if path.is_file() and path.name.endswith(exts):
shutil.copy2(path, out_dir / path.name)
found += 1
_env.info(f"安装包:{path.name}")
if found == 0:
_env.warn(f"未在 {bundle_dir} 找到安装包产物")
_env.step(f"桌面版完成:{out_dir}")
def main() -> int:
_env.setup_console()
parser = argparse.ArgumentParser(description="编译 Tauri 桌面版")
parser.add_argument(
"--platform",
choices=["current", "windows", "linux", "macos"],
default="current",
help="目标平台(默认当前系统)",
)
args = parser.parse_args()
host = _env.host_platform()
platform = host if args.platform == "current" else args.platform
if platform != host:
_env.die(
f"无法在 {host} 上交叉编译 {platform} 桌面版。",
f"Tauri 需要在目标系统本机构建,请在 {platform} 机器上运行本脚本。",
)
_env.ensure_rust()
python = _env.ensure_venv(extra_packages=["pyinstaller"])
_env.build_frontend(api_base=_env.DESKTOP_API_BASE)
tmp = _env.DIST_DIR / ".tmp"
_env.build_tauri_sidecar(python, tmp / "pyinstaller" / "work", tmp / "pyinstaller" / "dist")
_env.ensure_tauri_cli()
if platform == "windows":
build_with_windows_nsis(tmp)
else:
_env.remove_path(_env.SRC_TAURI_DIR / "target" / "release" / "bundle")
_env.step("编译 Tauri 桌面版(cargo tauri build)")
_env.run(["cargo", "tauri", "build"], cwd=_env.SRC_TAURI_DIR)
collect_installers(platform)
_env.step("清理中间产物")
_env.remove_path(tmp)
_env.remove_path(_env.FRONTEND_DIR / "dist")
_env.remove_path(_env.SRC_TAURI_DIR / "binaries")
return 0
if __name__ == "__main__":
raise SystemExit(main())