124 lines
3.3 KiB
Python
124 lines
3.3 KiB
Python
"""Offline bundle builder for CadHubManage.
|
|
|
|
Creates a wheelhouse and pre-built virtual environment for deployment to
|
|
air-gapped Windows hosts.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def run(command: list[str], *, cwd: Path | None = None) -> None:
|
|
subprocess.check_call(command, cwd=cwd)
|
|
|
|
|
|
def ensure_empty_dir(path: Path) -> None:
|
|
if path.exists():
|
|
if not path.is_dir():
|
|
raise ValueError(f"路径 {path} 已存在且不是目录")
|
|
shutil.rmtree(path)
|
|
path.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
def build_wheelhouse(requirements: Path, wheelhouse: Path, python: str) -> None:
|
|
cmd = [
|
|
python,
|
|
"-m",
|
|
"pip",
|
|
"download",
|
|
"-r",
|
|
str(requirements),
|
|
"-d",
|
|
str(wheelhouse),
|
|
]
|
|
run(cmd)
|
|
|
|
|
|
def create_virtualenv(project_root: Path, venv_dir: Path, python: str) -> None:
|
|
run([python, "-m", "venv", str(venv_dir)])
|
|
pip_executable = venv_dir / ("Scripts" if os.name == "nt" else "bin") / "pip"
|
|
wheelhouse = project_root / "dist" / "wheelhouse"
|
|
cmd = [
|
|
str(pip_executable),
|
|
"install",
|
|
"--no-index",
|
|
"--find-links",
|
|
str(wheelhouse),
|
|
"-r",
|
|
str(project_root / "requirements.txt"),
|
|
]
|
|
run(cmd)
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description="构建离线部署所需资源")
|
|
parser.add_argument(
|
|
"--project-root",
|
|
default=Path(__file__).resolve().parents[1],
|
|
type=Path,
|
|
help="项目根目录",
|
|
)
|
|
parser.add_argument(
|
|
"--requirements",
|
|
default=None,
|
|
type=Path,
|
|
help="requirements.txt 路径,默认为项目根目录下的 requirements.txt",
|
|
)
|
|
parser.add_argument(
|
|
"--wheelhouse",
|
|
default=None,
|
|
type=Path,
|
|
help="离线 wheel 包存放目录,默认 dist/wheelhouse",
|
|
)
|
|
parser.add_argument(
|
|
"--venv-dir",
|
|
default=None,
|
|
type=Path,
|
|
help="预构建虚拟环境的输出目录,默认 .offline-venv",
|
|
)
|
|
parser.add_argument(
|
|
"--python",
|
|
default=sys.executable,
|
|
help="用于构建的 Python 解释器路径",
|
|
)
|
|
parser.add_argument(
|
|
"--skip-wheelhouse",
|
|
action="store_true",
|
|
help="跳过 wheelhouse 构建,仅重建虚拟环境",
|
|
)
|
|
parser.add_argument(
|
|
"--skip-venv",
|
|
action="store_true",
|
|
help="跳过虚拟环境构建,仅更新 wheelhouse",
|
|
)
|
|
return parser.parse_args()
|
|
|
|
|
|
def main() -> None:
|
|
args = parse_args()
|
|
project_root = args.project_root.resolve()
|
|
requirements = (args.requirements or project_root / "requirements.txt").resolve()
|
|
if not requirements.exists():
|
|
raise FileNotFoundError(f"未找到依赖清单: {requirements}")
|
|
|
|
wheelhouse = (args.wheelhouse or project_root / "dist" / "wheelhouse").resolve()
|
|
venv_dir = (args.venv_dir or project_root / ".offline-venv").resolve()
|
|
|
|
if not args.skip_wheelhouse:
|
|
ensure_empty_dir(wheelhouse)
|
|
build_wheelhouse(requirements, wheelhouse, args.python)
|
|
|
|
if not args.skip_venv:
|
|
ensure_empty_dir(venv_dir)
|
|
create_virtualenv(project_root, venv_dir, args.python)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|