mirror of
https://github.com/Omni-guides/Jackify.git
synced 2026-06-08 03:27:45 +02:00
Sync from development - prepare for v0.3.0
This commit is contained in:
140
jackify/backend/handlers/wine_wrapper.py
Normal file
140
jackify/backend/handlers/wine_wrapper.py
Normal file
@@ -0,0 +1,140 @@
|
||||
"""
|
||||
Wine wrapper script generation for winetricks.
|
||||
Creates wrapper scripts similar to protontricks to properly set up
|
||||
LD_LIBRARY_PATH and other environment variables before invoking wine/wineserver.
|
||||
"""
|
||||
|
||||
import os
|
||||
import stat
|
||||
import shutil
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from jackify.shared.paths import get_jackify_data_dir
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
WINE_WRAPPER_TEMPLATE = '''#!/bin/bash
|
||||
# Wine wrapper script generated by Jackify
|
||||
# Ensures proper LD_LIBRARY_PATH setup when calling Proton wine binaries
|
||||
|
||||
PROTON_DIST_PATH="@@PROTON_DIST_PATH@@"
|
||||
BINARY_NAME="@@BINARY_NAME@@"
|
||||
|
||||
# Set up LD_LIBRARY_PATH with Proton libraries first
|
||||
PROTON_LIB_PATH="${PROTON_DIST_PATH}/lib64:${PROTON_DIST_PATH}/lib"
|
||||
if [[ -n "$LD_LIBRARY_PATH" ]]; then
|
||||
export LD_LIBRARY_PATH="${PROTON_LIB_PATH}:${LD_LIBRARY_PATH}"
|
||||
else
|
||||
export LD_LIBRARY_PATH="${PROTON_LIB_PATH}"
|
||||
fi
|
||||
|
||||
# Enable fsync/esync by default if not already set
|
||||
if [[ -z "$WINEFSYNC" && -z "$PROTON_NO_FSYNC" ]]; then
|
||||
export WINEFSYNC=1
|
||||
fi
|
||||
if [[ -z "$WINEESYNC" && -z "$PROTON_NO_ESYNC" ]]; then
|
||||
export WINEESYNC=1
|
||||
fi
|
||||
|
||||
# Execute the actual Proton binary
|
||||
exec "${PROTON_DIST_PATH}/bin/${BINARY_NAME}" "$@"
|
||||
'''
|
||||
|
||||
|
||||
class WineWrapperManager:
|
||||
"""Manages creation of wine/wineserver wrapper scripts for winetricks."""
|
||||
|
||||
def __init__(self):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self._wrapper_dir: Optional[Path] = None
|
||||
|
||||
def get_wrapper_dir(self, proton_path: str) -> Path:
|
||||
"""Get or create the wrapper directory for a specific Proton version."""
|
||||
proton_name = Path(proton_path).name.replace(" ", "_")
|
||||
cache_dir = get_jackify_data_dir() / "wine_wrappers" / proton_name
|
||||
cache_dir.mkdir(parents=True, exist_ok=True)
|
||||
return cache_dir
|
||||
|
||||
def create_wrappers(self, proton_dist_path: str) -> Optional[Path]:
|
||||
"""
|
||||
Create wine and wineserver wrapper scripts for the given Proton dist path.
|
||||
|
||||
Args:
|
||||
proton_dist_path: Path to Proton's dist directory (containing bin/, lib/, lib64/)
|
||||
|
||||
Returns:
|
||||
Path to the wrapper directory, or None if creation failed
|
||||
"""
|
||||
try:
|
||||
proton_dist = Path(proton_dist_path)
|
||||
if not proton_dist.exists():
|
||||
self.logger.error(f"Proton dist path does not exist: {proton_dist_path}")
|
||||
return None
|
||||
|
||||
# Verify required binaries exist
|
||||
wine_bin = proton_dist / "bin" / "wine"
|
||||
wineserver_bin = proton_dist / "bin" / "wineserver"
|
||||
|
||||
if not wine_bin.exists():
|
||||
self.logger.error(f"Wine binary not found: {wine_bin}")
|
||||
return None
|
||||
if not wineserver_bin.exists():
|
||||
self.logger.error(f"Wineserver binary not found: {wineserver_bin}")
|
||||
return None
|
||||
|
||||
# Get wrapper directory based on Proton install path (parent of dist)
|
||||
proton_install_path = proton_dist.parent
|
||||
wrapper_dir = self.get_wrapper_dir(str(proton_install_path))
|
||||
|
||||
# Clean and recreate to ensure fresh scripts
|
||||
if wrapper_dir.exists():
|
||||
shutil.rmtree(str(wrapper_dir))
|
||||
wrapper_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Create wrapper for each binary in Proton's bin directory
|
||||
binaries_to_wrap = ["wine", "wine64", "wineserver", "wineboot", "winecfg"]
|
||||
created_wrappers = []
|
||||
|
||||
for binary_name in binaries_to_wrap:
|
||||
binary_path = proton_dist / "bin" / binary_name
|
||||
if not binary_path.exists():
|
||||
continue
|
||||
|
||||
wrapper_path = wrapper_dir / binary_name
|
||||
wrapper_content = WINE_WRAPPER_TEMPLATE.replace(
|
||||
"@@PROTON_DIST_PATH@@", str(proton_dist)
|
||||
).replace(
|
||||
"@@BINARY_NAME@@", binary_name
|
||||
)
|
||||
|
||||
wrapper_path.write_text(wrapper_content)
|
||||
wrapper_path.chmod(wrapper_path.stat().st_mode | stat.S_IEXEC)
|
||||
created_wrappers.append(binary_name)
|
||||
|
||||
self.logger.info(f"Created wine wrappers in {wrapper_dir}: {', '.join(created_wrappers)}")
|
||||
self._wrapper_dir = wrapper_dir
|
||||
return wrapper_dir
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to create wine wrappers: {e}", exc_info=True)
|
||||
return None
|
||||
|
||||
def get_wine_wrapper_path(self, proton_dist_path: str) -> Optional[str]:
|
||||
"""Get path to the wine wrapper script."""
|
||||
wrapper_dir = self.create_wrappers(proton_dist_path)
|
||||
if wrapper_dir:
|
||||
wine_wrapper = wrapper_dir / "wine"
|
||||
if wine_wrapper.exists():
|
||||
return str(wine_wrapper)
|
||||
return None
|
||||
|
||||
def get_wineserver_wrapper_path(self, proton_dist_path: str) -> Optional[str]:
|
||||
"""Get path to the wineserver wrapper script."""
|
||||
wrapper_dir = self.create_wrappers(proton_dist_path)
|
||||
if wrapper_dir:
|
||||
wineserver_wrapper = wrapper_dir / "wineserver"
|
||||
if wineserver_wrapper.exists():
|
||||
return str(wineserver_wrapper)
|
||||
return None
|
||||
Reference in New Issue
Block a user