diff --git a/build-aux/share/portproton/scripts/functions_helper b/build-aux/share/portproton/scripts/functions_helper index 10f8594b..2ee9ec1e 100755 --- a/build-aux/share/portproton/scripts/functions_helper +++ b/build-aux/share/portproton/scripts/functions_helper @@ -4215,8 +4215,13 @@ gui_proton_downloader () { return 0 fi - METADATA_URL="https://git.linux-gaming.ru/Boria138/PortProton-Wine-Metadata/raw/branch/main/wine_metadata_all.json" - METADATA=$(curl -A 'PortProton' -s "$METADATA_URL") + METADATA_CLOUD_URL="https://git.linux-gaming.ru/Boria138/PortProton-Wine-Metadata/raw/branch/main/wine_metadata_all.json" + METADATA_GITHUB_URL="https://raw.githubusercontent.com/Boria138/PortProton-Wine-Metadata/main/wine_metadata_all.json" + if [[ "${MIRROR}" == CLOUD ]] ; then + METADATA=$(curl -fL -A 'PortProton' -s "$METADATA_CLOUD_URL") + else + METADATA=$(curl -fL -s "$METADATA_GITHUB_URL") + fi if [[ -z "$METADATA" ]] ; then fatal "failed to fetch metadata" fi diff --git a/portprotonqt/appimage_updater.py b/portprotonqt/appimage_updater.py index 71d82ccb..5efe2d96 100644 --- a/portprotonqt/appimage_updater.py +++ b/portprotonqt/appimage_updater.py @@ -28,14 +28,14 @@ APPIMAGE_UPDATE_CHECK_TIMEOUT = 120 APPIMAGE_UPDATE_TIMEOUT = 900 APPIMAGE_UPDATE_START_DELAY_MS = 5000 EXECUTABLE_MODE = 0o755 -FALLBACK_UPDATE_INFO = ( +GITHUB_UPDATE_INFO = ( "gh-releases-zsync|Boria138|PortProtonQt|latest|*x86_64.AppImage.zsync" ) CHANGELOG_URL = ( "https://git.linux-gaming.ru/Linux-Gaming/PortProtonQt/raw/branch/main/" "CHANGELOG.md" ) -CHANGELOG_FALLBACK_URL = ( +CHANGELOG_GITHUB_URL = ( "https://raw.githubusercontent.com/Boria138/PortProtonQt/refs/heads/main/" "CHANGELOG.md" ) @@ -129,16 +129,22 @@ def _run_appimageupdatetool( def _download_changelog() -> str: + from portprotonqt.portproton_api import get_user_conf_setting + session = get_requests_session() - for url in (CHANGELOG_URL, CHANGELOG_FALLBACK_URL): - try: - with session.get(url, timeout=CHANGELOG_TIMEOUT) as response: - response.raise_for_status() - data = response.content[:CHANGELOG_MAX_CHARS] - return data.decode("utf-8", errors="replace") - except (OSError, requests.RequestException) as error: - logger.debug("Failed to download changelog from %s: %s", url, error) - return "" + url = ( + CHANGELOG_URL + if get_user_conf_setting("MIRROR") == "CLOUD" + else CHANGELOG_GITHUB_URL + ) + try: + with session.get(url, timeout=CHANGELOG_TIMEOUT) as response: + response.raise_for_status() + data = response.content[:CHANGELOG_MAX_CHARS] + return data.decode("utf-8", errors="replace") + except (OSError, requests.RequestException) as error: + logger.debug("Failed to download changelog from %s: %s", url, error) + return "" def _extract_latest_version_changelog(changelog: str, current_version: str = "") -> str: @@ -306,15 +312,9 @@ class AppImageUpdateWorker(QThread): self.update_info = previous_info return result - def _is_check_failure(self, result: subprocess.CompletedProcess[str] | None) -> bool: - if result is None: - return True - if result.returncode not in (0, 1): - return True - output = f"{result.stdout}\n{result.stderr}" - return " Error:" in output or "Failed to fetch" in output - def run(self) -> None: + from portprotonqt.portproton_api import get_user_conf_setting + appimage_path = _appimage_path() if not ui_config.get_auto_appimage_updates() or not appimage_path: return @@ -330,14 +330,10 @@ class AppImageUpdateWorker(QThread): self._run_update(tool_path, appimage_path) return - update_infos = ["", FALLBACK_UPDATE_INFO] - check_code = None - selected_info = "" - for update_info in update_infos: - check_code = self._check_for_update(tool_path, appimage_path, update_info) - if not self._is_check_failure(check_code): - selected_info = update_info - break + selected_info = ( + "" if get_user_conf_setting("MIRROR") == "CLOUD" else GITHUB_UPDATE_INFO + ) + check_code = self._check_for_update(tool_path, appimage_path, selected_info) if check_code is None or check_code.returncode != 1: return diff --git a/portprotonqt/dialogs/wine_loader.py b/portprotonqt/dialogs/wine_loader.py index c7879269..ebd92b72 100644 --- a/portprotonqt/dialogs/wine_loader.py +++ b/portprotonqt/dialogs/wine_loader.py @@ -91,7 +91,15 @@ class WineLoadingThread(QThread): def run(self): try: - json_url = "https://git.linux-gaming.ru/Boria138/PortProton-Wine-Metadata/raw/branch/main/wine_metadata_all.json" + cloud_url = "https://git.linux-gaming.ru/Boria138/PortProton-Wine-Metadata/raw/branch/main/wine_metadata_all.json" + github_url = "https://raw.githubusercontent.com/Boria138/PortProton-Wine-Metadata/main/wine_metadata_all.json" + from portprotonqt.portproton_api import get_user_conf_setting + + json_url = ( + cloud_url + if get_user_conf_setting("MIRROR") == "CLOUD" + else github_url + ) with tempfile.NamedTemporaryFile(delete=False, suffix='.json') as tmp: temp_path = tmp.name diff --git a/tests/test_appimage_updater.py b/tests/test_appimage_updater.py index e5969170..68a3f23c 100644 --- a/tests/test_appimage_updater.py +++ b/tests/test_appimage_updater.py @@ -2,6 +2,7 @@ import subprocess from pathlib import Path from typing import Any +from unittest.mock import MagicMock import pytest from PySide6.QtWidgets import QApplication, QWidget @@ -9,6 +10,7 @@ from PySide6.QtWidgets import QApplication, QWidget from portprotonqt.config.ui import UIConfig from portprotonqt import appimage_updater from portprotonqt.dialogs.appimage_update import AppImageUpdateDialog +from portprotonqt import portproton_api FAKE_UPDATE_MARKER = "FAKE_UPDATE_APPLIED" @@ -90,6 +92,32 @@ def test_parse_appimage_update_progress_line() -> None: assert progress == (42, "42% \u2193 54.0 MB/128.0 MB") +@pytest.mark.parametrize( + ("mirror", "expected_url"), + ( + ("CLOUD", appimage_updater.CHANGELOG_URL), + ("GITHUB", appimage_updater.CHANGELOG_GITHUB_URL), + ), +) +def test_download_changelog_uses_selected_mirror( + mirror: str, + expected_url: str, + monkeypatch: pytest.MonkeyPatch, +) -> None: + response = MagicMock() + response.content = b"changelog" + session = MagicMock() + session.get.return_value.__enter__.return_value = response + monkeypatch.setattr(portproton_api, "get_user_conf_setting", lambda _key: mirror) + monkeypatch.setattr(appimage_updater, "get_requests_session", lambda: session) + + assert appimage_updater._download_changelog() == "changelog" + session.get.assert_called_once_with( + expected_url, + timeout=appimage_updater.CHANGELOG_TIMEOUT, + ) + + def test_appimage_update_worker_skips_when_disabled( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, @@ -118,6 +146,11 @@ def test_appimage_update_worker_runs_update( appimage = tmp_path / "PortProtonQt.AppImage" appimage.write_text("", encoding="utf-8") monkeypatch.setenv("APPIMAGE", str(appimage)) + monkeypatch.setattr( + portproton_api, + "get_user_conf_setting", + lambda _key: "CLOUD", + ) monkeypatch.setattr( appimage_updater.ui_config, "get_auto_appimage_updates", @@ -151,13 +184,18 @@ def test_appimage_update_worker_runs_update( assert available == [("Repo changelog", "")] -def test_appimage_update_worker_uses_fallback_mirror( +def test_appimage_update_worker_uses_github_mirror( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: appimage = tmp_path / "PortProtonQt.AppImage" appimage.write_text("", encoding="utf-8") monkeypatch.setenv("APPIMAGE", str(appimage)) + monkeypatch.setattr( + portproton_api, + "get_user_conf_setting", + lambda _key: "GITHUB", + ) monkeypatch.setattr( appimage_updater.ui_config, "get_auto_appimage_updates", @@ -169,8 +207,6 @@ def test_appimage_update_worker_uses_fallback_mirror( def run_tool(args: list[str], timeout: int) -> subprocess.CompletedProcess[str]: calls.append(args) - if "-u" not in args: - return subprocess.CompletedProcess(args, 0, stderr=" Error: primary failed") return subprocess.CompletedProcess(args, 1) monkeypatch.setattr(appimage_updater, "_run_appimageupdatetool", run_tool) @@ -188,16 +224,15 @@ def test_appimage_update_worker_uses_fallback_mirror( worker.run() assert calls == [ - ["/tool", "-j", str(appimage)], [ "/tool", "-j", "-u", - appimage_updater.FALLBACK_UPDATE_INFO, + appimage_updater.GITHUB_UPDATE_INFO, str(appimage), ], ] - assert available == [("Repo changelog", appimage_updater.FALLBACK_UPDATE_INFO)] + assert available == [("Repo changelog", appimage_updater.GITHUB_UPDATE_INFO)] def test_appimage_update_worker_emits_pty_progress(