mirror of
https://github.com/Omni-guides/Jackify.git
synced 2026-08-14 00:23:42 +02:00
160 lines
6.2 KiB
Python
160 lines
6.2 KiB
Python
"""
|
|
.NET 10 SDK and Desktop Runtime installation for Synthesis patcher compilation.
|
|
|
|
Split out of tool_config_service.py to keep that file under the project's
|
|
line-count guardrail.
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
import subprocess
|
|
import urllib.request
|
|
import zipfile
|
|
from pathlib import Path
|
|
from typing import Callable, Optional
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# .NET 10 SDK - ZIP distribution, extracted directly to avoid running an EXE under Wine.
|
|
# Synthesis requires the SDK (not just runtime) for patcher compilation. A newer SDK can
|
|
# still build projects targeting older TFMs (net6/7/8/9) as long as the matching runtime is
|
|
# present - which the native/winetricks component pipeline already installs separately - but
|
|
# an older SDK cannot target a newer TFM it doesn't recognize. Some Synthesis patchers target
|
|
# net10.0, so the SDK itself must be 10, matching Fluorine's confirmed-working configuration.
|
|
# ZIP distribution: Microsoft's officially supported xcopy-deployable install method, no
|
|
# installer-side effects the CLI depends on. Confirmed sufficient for net10.0 patcher builds
|
|
# by Styyx (2026-07-14).
|
|
_DOTNET_SDK_URL = "https://builds.dotnet.microsoft.com/dotnet/Sdk/10.0.301/dotnet-sdk-10.0.301-win-x64.zip"
|
|
_DOTNET_SDK_FILENAME = "dotnet-sdk-10.0.301-win-x64.zip"
|
|
|
|
# .NET Desktop Runtime 10 - provides NETCore.App + WindowsDesktop.App 10.0.2.
|
|
# Covers Synthesis patchers targeting .NET 10 runtime. ZIP distribution, same rationale
|
|
# as the SDK above - avoids running an EXE installer under Wine.
|
|
_DOTNET10_DESKTOP_URL = "https://builds.dotnet.microsoft.com/dotnet/WindowsDesktop/10.0.2/windowsdesktop-runtime-10.0.2-win-x64.zip"
|
|
_DOTNET10_DESKTOP_FILENAME = "windowsdesktop-runtime-10.0.2-win-x64.zip"
|
|
|
|
|
|
def install_dotnet_sdk(
|
|
prefix_path: Path,
|
|
wine_bin: str,
|
|
log: Callable[[str], None],
|
|
) -> bool:
|
|
"""
|
|
Download and extract the .NET 10 SDK ZIP into the Wine prefix.
|
|
Uses the standalone ZIP distribution to avoid running an EXE under Wine.
|
|
Synthesis requires the full SDK (Roslyn compiler) for patcher compilation.
|
|
"""
|
|
try:
|
|
from jackify.shared.paths import get_jackify_data_dir
|
|
cache_dir = get_jackify_data_dir() / "cache"
|
|
cache_dir.mkdir(parents=True, exist_ok=True)
|
|
sdk_zip = cache_dir / _DOTNET_SDK_FILENAME
|
|
|
|
if not sdk_zip.exists():
|
|
log(f"Downloading .NET 10 SDK ({_DOTNET_SDK_FILENAME})...")
|
|
urllib.request.urlretrieve(_DOTNET_SDK_URL, sdk_zip)
|
|
log(".NET 10 SDK downloaded")
|
|
else:
|
|
log(".NET 10 SDK already cached, skipping download")
|
|
|
|
dest = prefix_path / "drive_c" / "Program Files" / "dotnet"
|
|
dest.mkdir(parents=True, exist_ok=True)
|
|
log("Extracting .NET 10 SDK...")
|
|
with zipfile.ZipFile(sdk_zip) as zf:
|
|
zf.extractall(dest)
|
|
log(".NET 10 SDK extracted successfully")
|
|
return True
|
|
|
|
except Exception as e:
|
|
log(f"Failed to install .NET 10 SDK: {e}")
|
|
return False
|
|
|
|
|
|
def find_winetricks_bin() -> Optional[str]:
|
|
"""Locate the bundled winetricks binary, checking APPDIR for the AppImage case."""
|
|
module_dir = Path(__file__).parent.parent.parent
|
|
winetricks_bin = str(module_dir / "tools" / "winetricks")
|
|
if not os.path.exists(winetricks_bin):
|
|
appdir = os.environ.get("APPDIR", "")
|
|
if appdir:
|
|
winetricks_bin = os.path.join(appdir, "opt", "jackify", "tools", "winetricks")
|
|
return winetricks_bin if os.path.exists(winetricks_bin) else None
|
|
|
|
|
|
def install_dotnet10_desktop_runtime(
|
|
prefix_path: Path,
|
|
wine_bin: str,
|
|
log: Callable[[str], None],
|
|
) -> bool:
|
|
"""
|
|
Download and extract the .NET Desktop Runtime 10 ZIP into the Wine prefix.
|
|
Provides NETCore.App and WindowsDesktop.App 10.x for patchers targeting .NET 10.
|
|
Falls back to the bundled winetricks dotnetdesktop10 verb if the ZIP install fails.
|
|
"""
|
|
try:
|
|
from jackify.shared.paths import get_jackify_data_dir
|
|
cache_dir = get_jackify_data_dir() / "cache"
|
|
cache_dir.mkdir(parents=True, exist_ok=True)
|
|
runtime_zip = cache_dir / _DOTNET10_DESKTOP_FILENAME
|
|
|
|
if not runtime_zip.exists():
|
|
log(f"Downloading .NET Desktop Runtime 10 ({_DOTNET10_DESKTOP_FILENAME})...")
|
|
urllib.request.urlretrieve(_DOTNET10_DESKTOP_URL, runtime_zip)
|
|
log(".NET Desktop Runtime 10 downloaded")
|
|
else:
|
|
log(".NET Desktop Runtime 10 already cached, skipping download")
|
|
|
|
dest = prefix_path / "drive_c" / "Program Files" / "dotnet"
|
|
dest.mkdir(parents=True, exist_ok=True)
|
|
log("Extracting .NET Desktop Runtime 10...")
|
|
with zipfile.ZipFile(runtime_zip) as zf:
|
|
zf.extractall(dest)
|
|
log(".NET Desktop Runtime 10 extracted successfully")
|
|
return True
|
|
|
|
except Exception as e:
|
|
log(f"Failed to install .NET Desktop Runtime 10 via ZIP: {e}")
|
|
return _install_dotnet10_desktop_runtime_winetricks(prefix_path, wine_bin, log)
|
|
|
|
|
|
def _install_dotnet10_desktop_runtime_winetricks(
|
|
prefix_path: Path,
|
|
wine_bin: str,
|
|
log: Callable[[str], None],
|
|
) -> bool:
|
|
"""Fallback: install the .NET Desktop Runtime 10 via the bundled winetricks verb."""
|
|
winetricks_bin = find_winetricks_bin()
|
|
if not winetricks_bin:
|
|
log("Bundled winetricks not found - cannot fall back for .NET Desktop Runtime 10")
|
|
return False
|
|
|
|
try:
|
|
log("Falling back to winetricks dotnetdesktop10...")
|
|
env = os.environ.copy()
|
|
env["WINEPREFIX"] = str(prefix_path)
|
|
env["WINE"] = wine_bin
|
|
env["WINEDEBUG"] = "-all"
|
|
env["DISPLAY"] = env.get("DISPLAY", ":0")
|
|
|
|
result = subprocess.run(
|
|
[winetricks_bin, "-q", "dotnetdesktop10"],
|
|
env=env,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=300,
|
|
)
|
|
|
|
if result.returncode != 0:
|
|
log(f"winetricks dotnetdesktop10 exited with code {result.returncode}")
|
|
return False
|
|
|
|
log(".NET Desktop Runtime 10 installed via winetricks fallback")
|
|
return True
|
|
|
|
except subprocess.TimeoutExpired:
|
|
log("winetricks dotnetdesktop10 timed out")
|
|
return False
|
|
except Exception as e:
|
|
log(f"winetricks dotnetdesktop10 fallback failed: {e}")
|
|
return False
|