From a5444f7c91db8b15225d54ef263a5151828f801f Mon Sep 17 00:00:00 2001 From: InfinityPacer <160988576+InfinityPacer@users.noreply.github.com> Date: Tue, 25 Aug 2026 21:23:28 +0800 Subject: [PATCH] fix(update): preserve proxy for prepared releases (#6457) --- app/cli.py | 36 ++++++++++++++++++------------- tests/test_cli_auto_update.py | 40 +++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/app/cli.py b/app/cli.py index 4b62d0634..3f1ab593f 100644 --- a/app/cli.py +++ b/app/cli.py @@ -263,6 +263,25 @@ def _mark_prepared_update_failed(message: str) -> None: _clear_json_file(PREPARED_UPDATE_MANIFEST) +def _local_update_env() -> dict[str, str]: + """构造本地更新子进程使用的包缓存、代理和认证环境。""" + update_env = os.environ.copy() + package_cache_root = Path( + update_env.get("PACKAGE_CACHE_ROOT", "").strip() or settings.PACKAGE_CACHE_PATH + ) + update_env.setdefault("PACKAGE_CACHE_ROOT", str(package_cache_root)) + update_env.setdefault("UV_CACHE_DIR", str(package_cache_root / "uv")) + if settings.PIP_PROXY: + update_env["PIP_PROXY"] = settings.PIP_PROXY + if settings.PROXY_HOST: + update_env["PROXY_HOST"] = settings.PROXY_HOST + for key in ("http_proxy", "https_proxy", "HTTP_PROXY", "HTTPS_PROXY"): + update_env[key] = settings.PROXY_HOST + if settings.GITHUB_TOKEN: + update_env.setdefault("GITHUB_TOKEN", settings.GITHUB_TOKEN) + return update_env + + def _apply_prepared_release_update() -> bool: """本地 CLI 重启时离线安装已校验的 Release;返回是否发现安装意图。""" manifest = _read_json_file(PREPARED_UPDATE_MANIFEST) @@ -309,7 +328,7 @@ def _apply_prepared_release_update() -> bool: result = subprocess.run( update_command, cwd=str(_repo_root()), - env=os.environ.copy(), + env=_local_update_env(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, @@ -375,24 +394,11 @@ def _best_effort_auto_update() -> None: str(settings.CONFIG_PATH), ] - update_env = os.environ.copy() - package_cache_root = Path(update_env.get("PACKAGE_CACHE_ROOT", "").strip() or settings.PACKAGE_CACHE_PATH) - update_env.setdefault("PACKAGE_CACHE_ROOT", str(package_cache_root)) - update_env.setdefault("UV_CACHE_DIR", str(package_cache_root / "uv")) - if settings.PIP_PROXY: - update_env["PIP_PROXY"] = settings.PIP_PROXY - if settings.PROXY_HOST: - update_env["PROXY_HOST"] = settings.PROXY_HOST - for key in ("http_proxy", "https_proxy", "HTTP_PROXY", "HTTPS_PROXY"): - update_env[key] = settings.PROXY_HOST - if settings.GITHUB_TOKEN: - update_env.setdefault("GITHUB_TOKEN", settings.GITHUB_TOKEN) - click.echo(f"检测到 MOVIEPILOT_AUTO_UPDATE={mode},启动前执行本地自动更新") result = subprocess.run( update_command, cwd=str(_repo_root()), - env=update_env, + env=_local_update_env(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, diff --git a/tests/test_cli_auto_update.py b/tests/test_cli_auto_update.py index b24b6d6fc..7c02b863d 100644 --- a/tests/test_cli_auto_update.py +++ b/tests/test_cli_auto_update.py @@ -142,6 +142,46 @@ def test_prepared_release_uses_downloaded_package_before_dev_mode(): mode.assert_not_called() +def test_prepared_release_passes_package_env_and_overrides_proxy(): + module = load_cli_module() + module.settings.PROXY_HOST = "http://proxy.example:7890" + module.settings.PIP_PROXY = "https://mirror.example/simple" + module.PREPARED_UPDATE_ROOT.mkdir(parents=True, exist_ok=True) + backend = module.PREPARED_UPDATE_ROOT / "backend.zip" + frontend = module.PREPARED_UPDATE_ROOT / "frontend.zip" + backend.write_bytes(b"backend") + frontend.write_bytes(b"frontend") + module.PREPARED_UPDATE_MANIFEST.write_text( + json.dumps( + { + "version": "v3.1.0", + "frontend_version": "v3.1.0", + "backend_archive": str(backend), + "frontend_archive": str(frontend), + "backend_sha256": hashlib.sha256(backend.read_bytes()).hexdigest(), + "frontend_sha256": hashlib.sha256(frontend.read_bytes()).hexdigest(), + } + ), + encoding="utf-8", + ) + run_result = SimpleNamespace(returncode=0, stdout="ok") + + with patch.dict( + module.os.environ, + {"HTTPS_PROXY": "http://old.example:8080"}, + clear=True, + ), patch.object( + module.subprocess, "run", return_value=run_result + ) as run_mock, patch.object(module.click, "echo"): + assert module._apply_prepared_release_update() is True + + env = run_mock.call_args.kwargs["env"] + assert env["HTTPS_PROXY"] == "http://proxy.example:7890" + assert env["PIP_PROXY"] == "https://mirror.example/simple" + assert env["PACKAGE_CACHE_ROOT"] == str(module.settings.PACKAGE_CACHE_PATH) + assert env["UV_CACHE_DIR"] == str(module.settings.PACKAGE_CACHE_PATH / "uv") + + def test_best_effort_auto_update_does_not_pass_frontend_version_override(): module = load_cli_module() run_result = SimpleNamespace(returncode=0, stdout="ok")