refactor: replace jq usage with orjson helpers #217

Merged
Boria138 merged 1 commits from drop-jq into main 2026-07-08 13:59:52 +00:00
9 changed files with 122 additions and 12 deletions

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@ arch=('any')
url="https://git.linux-gaming.ru/Linux-Gaming/PortProtonQt"
license=('GPL-3.0')
depends=('python-requests' 'python-babel' 'python-evdev' 'python-pygame' 'python-orjson'
'python-psutil' 'python-tqdm' 'python-vdf' 'python-libarchive-c' 'pyside6' 'python-rapidfuzz' 'python-pefile' 'python-pillow' 'perl-image-exiftool' 'python-websocket-client' 'cabextract' 'unzip' 'curl' 'jq' 'file' 'findutils' 'gawk' 'grep' 'tar' 'xz' 'zstd' 'gzip' 'unrar' 'qt6-svg' 'qt6-imageformats' 'pciutils' 'mesa-utils' 'vulkan-icd-loader' 'procps-ng' 'psmisc' '7zip' 'python-dbus-fast' 'sdl3')
'python-psutil' 'python-tqdm' 'python-vdf' 'python-libarchive-c' 'pyside6' 'python-rapidfuzz' 'python-pefile' 'python-pillow' 'perl-image-exiftool' 'python-websocket-client' 'cabextract' 'unzip' 'curl' 'file' 'findutils' 'gawk' 'grep' 'tar' 'xz' 'zstd' 'gzip' 'unrar' 'qt6-svg' 'qt6-imageformats' 'pciutils' 'mesa-utils' 'vulkan-icd-loader' 'procps-ng' 'psmisc' '7zip' 'python-dbus-fast' 'sdl3')
makedepends=('meson' 'ninja' 'vulkan-headers' 'gettext')
conflicts=("portprotonqt-steam-compat")
provides=('portprotonqt-steam-compat')
+1 -1
View File
@@ -6,7 +6,7 @@ arch=('any')
url="https://git.linux-gaming.ru/Linux-Gaming/PortProtonQt"
license=('GPL-3.0')
depends=('python-requests' 'python-babel' 'python-evdev' 'python-pygame' 'python-orjson'
'python-psutil' 'python-tqdm' 'python-vdf' 'python-libarchive-c' 'pyside6' 'python-rapidfuzz' 'python-pefile' 'python-pillow' 'perl-image-exiftool' 'python-websocket-client' 'cabextract' 'unzip' 'curl' 'jq' 'file' 'findutils' 'gawk' 'grep' 'tar' 'xz' 'zstd' 'gzip' 'unrar' 'qt6-svg' 'qt6-imageformats' 'pciutils' 'mesa-utils' 'vulkan-icd-loader' 'procps-ng' 'psmisc' '7zip' 'python-dbus-fast' 'sdl3')
'python-psutil' 'python-tqdm' 'python-vdf' 'python-libarchive-c' 'pyside6' 'python-rapidfuzz' 'python-pefile' 'python-pillow' 'perl-image-exiftool' 'python-websocket-client' 'cabextract' 'unzip' 'curl' 'file' 'findutils' 'gawk' 'grep' 'tar' 'xz' 'zstd' 'gzip' 'unrar' 'qt6-svg' 'qt6-imageformats' 'pciutils' 'mesa-utils' 'vulkan-icd-loader' 'procps-ng' 'psmisc' '7zip' 'python-dbus-fast' 'sdl3')
makedepends=('meson' 'ninja' 'vulkan-headers' 'gettext')
conflicts=("portprotonqt-steam-compat")
provides=('portprotonqt-steam-compat')
-1
View File
@@ -50,7 +50,6 @@ Requires: cabextract
Requires: gzip
Requires: unzip
Requires: curl
Requires: jq
Requires: file
Requires: findutils
Requires: gawk
-1
View File
@@ -47,7 +47,6 @@ Requires: cabextract
Requires: gzip
Requires: unzip
Requires: curl
Requires: jq
Requires: file
Requires: findutils
Requires: gawk
@@ -4222,11 +4222,8 @@ gui_proton_downloader () {
pw_download_get_wine () {
local URL_VERSION_PROTON_GIT
local VERSION="$1"
local ALL_CATEGORIES=$(echo "$METADATA" | jq -r 'keys[]' 2>/dev/null)
print_info "Download and install ${VERSION}..."
URL_VERSION_PROTON_GIT=$(echo "$METADATA" | jq -r --arg version "$VERSION" '
to_entries[] | .value[]? | select((.name | ascii_downcase) == ($version | ascii_downcase)) | .url
' 2>/dev/null | head -n 1)
URL_VERSION_PROTON_GIT=$(python_module json_tools wine-url "$VERSION" <<< "$METADATA" 2>/dev/null)
if [[ -z "$URL_VERSION_PROTON_GIT" ]]; then
fatal "no URL found for version ${VERSION}"
fi
@@ -4751,14 +4748,18 @@ pw_auto_create_shortcut () {
if [[ "${PW_EXE_FILE}" =~ EpicGamesLauncher.exe$ ]]; then
for item_file in "${PORT_DATA_PATH}/data/prefixes/${PW_PREFIX_NAME}/drive_c/ProgramData/Epic/EpicGamesLauncher/Data/Manifests/"*".item"; do
if [[ -f "${item_file}" ]]; then
exe_path=$(jq -r '.InstallLocation + "\\" + .LaunchExecutable' "${item_file}")
IFS=$'\t' read -r exe_path PORTWINE_CREATE_SHORTCUT_NAME item_id < <(
python_module json_tools epic-manifest "${item_file}" 2>/dev/null
)
if [[ -z "${exe_path}" ]]; then
print_warning "Failed to parse Epic manifest: ${item_file}"
continue
fi
get_lnk_path "${exe_path}"
PORTWINE_CREATE_SHORTCUT_NAME=$(jq -r '.DisplayName' "${item_file}")
if ! exe_path="$(realpath "${link_path}" 2>/dev/null)" || [[ ! -f "${exe_path}" ]]; then
print_warning "Link broken for: ${PORTWINE_CREATE_SHORTCUT_NAME}"
elif [[ ! -f "${exe_path}.ppdb" ]]; then
unset FILE_SHA256SUM DESKTOP_NAME_FILE DESKTOP_CORRECT_FILE
item_id=$(jq -r '.AppName' "${item_file}")
PW_EXE_FILE="${exe_path}"
PORTWINE_DB_FILE="${PW_EXE_FILE}.ppdb"
LAUNCH_URI="com.epicgames.launcher://apps/${item_id}?action=launch&silent=true"
-1
View File
@@ -22,7 +22,6 @@ Depends:
curl,
file,
gawk,
jq,
libimage-exiftool-perl,
libsdl3-0,
mesa-utils,
+1
View File
@@ -139,6 +139,7 @@ install_data(
'scripts_utils/easyterm.py',
'scripts_utils/graphics_detector.py',
'scripts_utils/idle_inhibit.py',
'scripts_utils/json_tools.py',
'scripts_utils/mount_points.py',
'scripts_utils/prefix_backup.py',
'scripts_utils/power_profiles.py',
+67
View File
@@ -0,0 +1,67 @@
"""JSON helpers for PortProton shell scripts."""
import argparse
import sys
from pathlib import Path
from typing import Any
import orjson
def _load_json_file(path: str) -> Any:
with Path(path).open("rb") as f:
return orjson.loads(f.read())
def _wine_url(metadata: dict[str, Any], version: str) -> str:
version_lower = version.lower()
for items in metadata.values():
if not isinstance(items, list):
continue
for item in items:
if not isinstance(item, dict):
continue
if str(item.get("name", "")).lower() == version_lower:
return str(item.get("url", ""))
return ""
def _epic_manifest_fields(manifest: dict[str, Any]) -> tuple[str, str, str]:
install_location = str(manifest.get("InstallLocation", ""))
launch_executable = str(manifest.get("LaunchExecutable", ""))
exe_path = f"{install_location}\\{launch_executable}"
return exe_path, str(manifest.get("DisplayName", "")), str(manifest.get("AppName", ""))
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="PortProton JSON tools")
subparsers = parser.add_subparsers(dest="command", required=True)
wine_parser = subparsers.add_parser("wine-url")
wine_parser.add_argument("version")
epic_parser = subparsers.add_parser("epic-manifest")
epic_parser.add_argument("manifest_path")
return parser.parse_args()
def main() -> int:
args = parse_args()
try:
if args.command == "wine-url":
metadata = orjson.loads(sys.stdin.buffer.read())
sys.stdout.write(_wine_url(metadata, args.version))
return 0
if args.command == "epic-manifest":
fields = _epic_manifest_fields(_load_json_file(args.manifest_path))
sys.stdout.write("\t".join(fields))
return 0
except (OSError, orjson.JSONDecodeError) as error:
sys.stderr.write(f"Failed to parse JSON: {error}\n")
return 1
return 1
if __name__ == "__main__":
sys.exit(main())
+44
View File
@@ -0,0 +1,44 @@
"""Tests for JSON helpers used by PortProton shell scripts."""
from pathlib import Path
import orjson
from portprotonqt.scripts_utils import json_tools
def test_wine_url_matches_version_case_insensitive() -> None:
metadata = {
"proton": [
{"name": "GE-Proton10-15", "url": "https://example.org/proton.tar.gz"},
],
}
assert json_tools._wine_url(metadata, "ge-proton10-15") == "https://example.org/proton.tar.gz"
def test_wine_url_ignores_unexpected_metadata() -> None:
metadata = {
"broken": {"name": "GE-Proton10-15"},
"wine": [{"name": "Wine", "url": "https://example.org/wine.tar.gz"}],
}
assert json_tools._wine_url(metadata, "missing") == ""
def test_epic_manifest_fields_reads_launcher_values(tmp_path: Path) -> None:
manifest_path = tmp_path / "game.item"
manifest_path.write_bytes(orjson.dumps({
"InstallLocation": "C:\\Games\\Demo",
"LaunchExecutable": "Demo.exe",
"DisplayName": "Demo Game",
"AppName": "demo-app",
}))
manifest = json_tools._load_json_file(str(manifest_path))
assert json_tools._epic_manifest_fields(manifest) == (
"C:\\Games\\Demo\\Demo.exe",
"Demo Game",
"demo-app",
)