mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-07-23 05:27:17 +08:00
feat: add Rust acceleration for core parsing
This commit is contained in:
@@ -17,6 +17,7 @@ SUPERUSER_PASSWORD=""
|
||||
OS_NAME="Unknown"
|
||||
PYTHON_BIN=""
|
||||
BREW_BIN=""
|
||||
RUSTUP_BIN=""
|
||||
PACKAGE_MANAGER=""
|
||||
PACKAGE_INDEX_UPDATED="false"
|
||||
PROMPT_INPUT="/dev/stdin"
|
||||
@@ -227,20 +228,20 @@ find_uv_python() {
|
||||
python_install_hint() {
|
||||
case "$OS_NAME" in
|
||||
macOS)
|
||||
echo "脚本已尝试自动安装 Git、curl 和 Python 3.11+。" >&2
|
||||
echo "如果自动安装失败,请先安装 Homebrew,或手动执行:brew install git curl python@3.11" >&2
|
||||
echo "脚本已尝试自动安装 Git、curl、Python 3.11+、Rust toolchain 和构建工具。" >&2
|
||||
echo "如果自动安装失败,请先安装 Homebrew 和 Xcode Command Line Tools,或手动执行:brew install git curl python@3.11 rustup-init" >&2
|
||||
;;
|
||||
Linux*)
|
||||
echo "脚本已尝试自动安装 Git、curl 和 Python 3.11+。" >&2
|
||||
echo "如果自动安装失败,请先安装 Git、curl 和 Python 3.11+,并确保包含 venv 模块。" >&2
|
||||
echo "例如 Debian/Ubuntu: sudo apt install git curl python3.11 python3.11-venv" >&2
|
||||
echo "例如 Fedora/RHEL: sudo dnf install git curl python3.11" >&2
|
||||
echo "脚本已尝试自动安装 Git、curl、Python 3.11+、Rust toolchain 和构建工具。" >&2
|
||||
echo "如果自动安装失败,请先安装 Git、curl、Python 3.11+、cargo,并确保包含 venv 模块。" >&2
|
||||
echo "例如 Debian/Ubuntu: sudo apt install git curl python3.11 python3.11-venv build-essential" >&2
|
||||
echo "例如 Fedora/RHEL: sudo dnf install git curl python3.11 gcc gcc-c++ make" >&2
|
||||
;;
|
||||
Windows)
|
||||
echo "推荐在 WSL、Linux 或 macOS 终端中运行此脚本。" >&2
|
||||
;;
|
||||
*)
|
||||
echo "请先安装 Git、curl 和 Python 3.11 或更高版本。" >&2
|
||||
echo "请先安装 Git、curl、Python 3.11 或更高版本、cargo 和 C 编译器。" >&2
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@@ -270,6 +271,74 @@ ensure_brew() {
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查 cargo 是否已可用,兼容 rustup 安装后 PATH 尚未刷新。
|
||||
find_cargo() {
|
||||
local cargo_bin=""
|
||||
cargo_bin="$(command -v cargo 2>/dev/null || true)"
|
||||
if [[ -n "$cargo_bin" ]]; then
|
||||
printf '%s\n' "$cargo_bin"
|
||||
return 0
|
||||
fi
|
||||
if [[ -x "$HOME/.cargo/bin/cargo" ]]; then
|
||||
printf '%s\n' "$HOME/.cargo/bin/cargo"
|
||||
fi
|
||||
}
|
||||
|
||||
# 判断是否显式跳过 Rust 加速扩展,避免一键安装继续准备构建工具链。
|
||||
rust_accel_should_skip() {
|
||||
case "${MOVIEPILOT_SKIP_RUST_ACCEL:-}" in
|
||||
1|true|TRUE|yes|YES|on|ON)
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 为 CLI 一键安装准备 Rust toolchain,后续 setup 会用它构建加速扩展。
|
||||
ensure_rust_toolchain() {
|
||||
if rust_accel_should_skip; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -n "$(find_cargo)" ]]; then
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "==> 自动安装 Rust toolchain,用于构建 MoviePilot 加速扩展"
|
||||
case "$PACKAGE_MANAGER" in
|
||||
brew)
|
||||
ensure_brew
|
||||
"$BREW_BIN" install rustup-init
|
||||
RUSTUP_BIN="$(command -v rustup-init 2>/dev/null || true)"
|
||||
;;
|
||||
*)
|
||||
RUSTUP_BIN="$(command -v rustup 2>/dev/null || true)"
|
||||
if [[ -z "$RUSTUP_BIN" ]]; then
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal
|
||||
else
|
||||
"$RUSTUP_BIN" toolchain install stable --profile minimal
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
if [[ "$PACKAGE_MANAGER" == "brew" ]]; then
|
||||
RUSTUP_BIN="$(command -v rustup-init 2>/dev/null || true)"
|
||||
if [[ -n "$RUSTUP_BIN" ]]; then
|
||||
"$RUSTUP_BIN" -y --profile minimal
|
||||
fi
|
||||
fi
|
||||
|
||||
hash -r
|
||||
if [[ -z "$(find_cargo)" ]]; then
|
||||
echo "Rust toolchain 安装失败,请手动安装 cargo 后重试。" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_privileged() {
|
||||
if [[ "$(id -u)" -eq 0 ]]; then
|
||||
"$@"
|
||||
@@ -383,6 +452,54 @@ ensure_base_tools() {
|
||||
fi
|
||||
}
|
||||
|
||||
# 安装 Rust 扩展构建需要的本机编译器和链接器。
|
||||
ensure_build_tools() {
|
||||
if rust_accel_should_skip; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "$OS_NAME" == "macOS" ]]; then
|
||||
if xcode-select -p >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
echo "当前 macOS 缺少 Command Line Tools,请先执行:xcode-select --install" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if command -v cc >/dev/null 2>&1 || command -v gcc >/dev/null 2>&1 || command -v clang >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "==> 自动安装系统构建工具,用于编译 Rust 加速扩展"
|
||||
case "$PACKAGE_MANAGER" in
|
||||
apt-get)
|
||||
install_system_packages build-essential
|
||||
;;
|
||||
dnf|yum)
|
||||
install_system_packages gcc gcc-c++ make
|
||||
;;
|
||||
zypper)
|
||||
install_system_packages gcc gcc-c++ make
|
||||
;;
|
||||
pacman)
|
||||
install_system_packages base-devel
|
||||
;;
|
||||
apk)
|
||||
install_system_packages build-base
|
||||
;;
|
||||
*)
|
||||
echo "当前系统暂不支持自动安装构建工具,请手动安装 C 编译器后重试。" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
hash -r
|
||||
if ! command -v cc >/dev/null 2>&1 && ! command -v gcc >/dev/null 2>&1 && ! command -v clang >/dev/null 2>&1; then
|
||||
echo "系统构建工具安装失败,请确认 C 编译器可用后重试。" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_uv() {
|
||||
if command -v uv >/dev/null 2>&1; then
|
||||
return 0
|
||||
@@ -427,7 +544,7 @@ ensure_prereqs() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! ensure_base_tools || ! ensure_python || ! ensure_uv; then
|
||||
if ! ensure_base_tools || ! ensure_build_tools || ! ensure_python || ! ensure_uv || ! ensure_rust_toolchain; then
|
||||
python_install_hint
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -45,6 +45,9 @@ COOKIE_DIR = CONFIG_DIR / "cookies"
|
||||
ENV_FILE = CONFIG_DIR / "app.env"
|
||||
|
||||
DEFAULT_NODE_VERSION = "20.12.1"
|
||||
RUST_ACCEL_DIR = ROOT / "rust" / "moviepilot_rust"
|
||||
RUST_ACCEL_MANIFEST = RUST_ACCEL_DIR / "Cargo.toml"
|
||||
RUST_ACCEL_SKIP_ENV = "MOVIEPILOT_SKIP_RUST_ACCEL"
|
||||
FRONTEND_LATEST_API = (
|
||||
"https://api.github.com/repos/jxxghp/MoviePilot-Frontend/releases/latest"
|
||||
)
|
||||
@@ -475,10 +478,17 @@ def print_step(message: str) -> None:
|
||||
print(f"==> {message}")
|
||||
|
||||
|
||||
def run(command: list[str], cwd: Optional[Path] = None) -> None:
|
||||
def run(
|
||||
command: list[str],
|
||||
cwd: Optional[Path] = None,
|
||||
env: Optional[dict[str, str]] = None,
|
||||
) -> None:
|
||||
"""
|
||||
执行安装步骤中的外部命令,并在失败时让调用方中断流程。
|
||||
"""
|
||||
pretty = " ".join(command)
|
||||
print(f"+ {pretty}")
|
||||
subprocess.run(command, cwd=str(cwd or ROOT), check=True)
|
||||
subprocess.run(command, cwd=str(cwd or ROOT), check=True, env=env)
|
||||
|
||||
|
||||
def capture(command: list[str], cwd: Optional[Path] = None) -> str:
|
||||
@@ -579,6 +589,9 @@ def _ensure_uv_available_for_venv(venv_dir: Path, venv_python: Path) -> Optional
|
||||
|
||||
|
||||
def configure_venv_pip_compat(venv_dir: Path, venv_python: Path) -> Path:
|
||||
"""
|
||||
在虚拟环境中安装 uv 并保持 pip 命令兼容,供现有安装流程复用。
|
||||
"""
|
||||
if os.name == "nt":
|
||||
return get_venv_pip(venv_dir)
|
||||
|
||||
@@ -606,6 +619,93 @@ def configure_venv_pip_compat(venv_dir: Path, venv_python: Path) -> Path:
|
||||
return get_venv_pip(venv_dir)
|
||||
|
||||
|
||||
def _rust_accel_should_skip() -> bool:
|
||||
"""
|
||||
判断当前安装是否显式跳过 Rust 加速扩展构建。
|
||||
"""
|
||||
raw_value = os.getenv(RUST_ACCEL_SKIP_ENV, "").strip().lower()
|
||||
return raw_value in {"1", "true", "yes", "on"}
|
||||
|
||||
|
||||
def _cargo_env_path() -> str:
|
||||
"""
|
||||
组合 PATH,兼容 rustup 默认安装到用户目录但当前 shell 未刷新环境的场景。
|
||||
"""
|
||||
extra_paths = [str(Path.home() / ".cargo" / "bin")]
|
||||
current_path = os.environ.get("PATH", "")
|
||||
return os.pathsep.join([*extra_paths, current_path])
|
||||
|
||||
|
||||
def _find_cargo() -> Optional[str]:
|
||||
"""
|
||||
查找 Rust cargo 可执行文件,供本地 CLI 安装构建 PyO3 扩展。
|
||||
"""
|
||||
return shutil.which("cargo", path=_cargo_env_path())
|
||||
|
||||
|
||||
def _find_native_linker() -> Optional[str]:
|
||||
"""
|
||||
查找 Rust 扩展构建所需的本机链接器。
|
||||
"""
|
||||
if os.name == "nt":
|
||||
return "windows-msvc"
|
||||
for candidate in ("cc", "gcc", "clang"):
|
||||
linker = shutil.which(candidate)
|
||||
if linker:
|
||||
return linker
|
||||
return None
|
||||
|
||||
|
||||
def ensure_rust_accel_ready() -> None:
|
||||
"""
|
||||
确认 Rust 加速扩展源码存在且本机具备 cargo 与链接器。
|
||||
"""
|
||||
if not RUST_ACCEL_MANIFEST.exists():
|
||||
return
|
||||
if _rust_accel_should_skip():
|
||||
print_step(f"已跳过 Rust 加速扩展构建:{RUST_ACCEL_SKIP_ENV}=1")
|
||||
return
|
||||
if not _find_cargo():
|
||||
raise RuntimeError(
|
||||
"未找到 Rust cargo,无法构建 MoviePilot Rust 加速扩展。"
|
||||
"请先安装 Rust toolchain 后重试,或临时设置 "
|
||||
f"{RUST_ACCEL_SKIP_ENV}=1 跳过加速扩展。"
|
||||
)
|
||||
if not _find_native_linker():
|
||||
raise RuntimeError(
|
||||
"未找到本机 C 编译器/链接器,无法构建 MoviePilot Rust 加速扩展。"
|
||||
"请先安装系统构建工具后重试,或临时设置 "
|
||||
f"{RUST_ACCEL_SKIP_ENV}=1 跳过加速扩展。"
|
||||
)
|
||||
|
||||
|
||||
def install_rust_accel(venv_python: Path) -> None:
|
||||
"""
|
||||
构建并安装 MoviePilot Rust 加速扩展到当前虚拟环境。
|
||||
"""
|
||||
if not RUST_ACCEL_MANIFEST.exists():
|
||||
return
|
||||
if _rust_accel_should_skip():
|
||||
return
|
||||
|
||||
ensure_rust_accel_ready()
|
||||
print_step("构建并安装 Rust 加速扩展")
|
||||
env = os.environ.copy()
|
||||
env["PATH"] = _cargo_env_path()
|
||||
run(
|
||||
[
|
||||
str(venv_python),
|
||||
"-m",
|
||||
"maturin",
|
||||
"develop",
|
||||
"--release",
|
||||
"--manifest-path",
|
||||
str(RUST_ACCEL_MANIFEST),
|
||||
],
|
||||
env=env,
|
||||
)
|
||||
|
||||
|
||||
def ensure_supported_python(python_bin: str) -> None:
|
||||
version = get_python_version(python_bin)
|
||||
if version < MIN_PYTHON_VERSION:
|
||||
@@ -2628,7 +2728,11 @@ def init_local(
|
||||
|
||||
|
||||
def install_deps(*, python_bin: str, venv_dir: Path, recreate: bool) -> Path:
|
||||
"""
|
||||
创建或复用本地虚拟环境,并安装后端依赖、Rust 扩展和浏览器运行时。
|
||||
"""
|
||||
ensure_supported_python(python_bin)
|
||||
ensure_rust_accel_ready()
|
||||
venv_dir = venv_dir.expanduser().resolve()
|
||||
venv_python = get_venv_python(venv_dir)
|
||||
venv_pip = get_venv_pip(venv_dir)
|
||||
@@ -2653,6 +2757,7 @@ def install_deps(*, python_bin: str, venv_dir: Path, recreate: bool) -> Path:
|
||||
|
||||
print_step("安装项目依赖")
|
||||
run([str(venv_pip), "install", "-r", str(ROOT / "requirements.txt")])
|
||||
install_rust_accel(venv_python)
|
||||
install_browser_runtime(venv_python)
|
||||
return venv_python
|
||||
|
||||
|
||||
Reference in New Issue
Block a user