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 卷)。
This commit is contained in:
2026-06-26 11:03:19 +08:00
parent 54b40ca46b
commit 98f03b3e0e
19 changed files with 1076 additions and 1133 deletions
+218
View File
@@ -0,0 +1,218 @@
"""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())