Skip to content

Commit

Permalink
Consolidate all launcher scripts into one
Browse files Browse the repository at this point in the history
Consolidate all Wine launcher scripts into one script instead of having
two different Wine launcher scripts for bwrap and legacy Steam Runtimes.

This fixes the wineserver detection not working when Steam Runtime
wasn't used at all. This also reduces duplicate code and also makes
future features related to Wine configuration easier to implement.
  • Loading branch information
Matoking committed Jan 31, 2022
1 parent fa6b488 commit d6972e0
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 118 deletions.
41 changes: 0 additions & 41 deletions src/protontricks/data/scripts/runtime_launch_legacy.sh

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,67 @@ WINESERVER_ENV_VARS_TO_COPY=(
WINEESYNC WINEFSYNC
)

if [[ -n "$PROTONTRICKS_INSIDE_STEAM_RUNTIME" ]]; then
# Command is being executed inside Steam Runtime
# LD_LIBRARY_PATH can now be set.
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH":"$PROTON_LD_LIBRARY_PATH"
"$PROTON_DIST_PATH"/bin/@@name@@ "$@"
else
# Command is being executed outside Steam Runtime. Determine mount points
# and configure our Wine environment before running bwrap and continuing
# execution inside the sandbox.
if [[ -z "$PROTONTRICKS_FIRST_START" ]]; then
# Try to detect if wineserver is already running, and if so, copy a few
# environment variables from it to ensure our own Wine processes
# are able to run at the same time without any issues.
# This usually happens when the user is running the Steam app and
# Protontricks at the same time.
wineserver_found=false

# Find the correct Wineserver that's using the same prefix
while read -r pid; do
if [[ $(xargs -0 -L1 -a "/proc/${pid}/environ" | grep "^WINEPREFIX=${WINEPREFIX}") ]] &> /dev/null; then
if [[ "$pid" = "$$" ]]; then
# Don't mistake this very script for a wineserver instance
continue
fi
wineserver_found=true
wineserver_pid="$pid"
fi
done < <(pgrep wineserver)

if [[ "$wineserver_found" = true ]]; then
# wineserver found, retrieve its environment variables
wineserver_env_vars=$(xargs -0 -L1 -a "/proc/${wineserver_pid}/environ")

# Copy the required environment variables found in the
# existing wineserver process
for env_name in "${WINESERVER_ENV_VARS_TO_COPY[@]}"; do
env_declr=$(echo "$wineserver_env_vars" | grep "^${env_name}=" || :)
if [[ -n "$env_declr" ]]; then
export "${env_declr?}"
fi
done
fi

export PROTONTRICKS_FIRST_START=1
fi

# PROTONTRICKS_STEAM_RUNTIME values:
# bwrap: Run Wine binaries inside Steam Runtime's bwrap sandbox,
# modify LD_LIBRARY_PATH to include Proton libraries
#
# legacy: Modify LD_LIBRARY_PATH to include Steam Runtime *and* Proton
# libraries. Host library order is adjusted as well.
#
# off: Just run the binaries as-is.
if [[ -n "$PROTONTRICKS_INSIDE_STEAM_RUNTIME"
|| "$PROTONTRICKS_STEAM_RUNTIME" = "legacy"
|| "$PROTONTRICKS_STEAM_RUNTIME" = "off"
]]; then

# If either Steam Runtime is enabled, change LD_LIBRARY_PATH
if [[ "$PROTONTRICKS_STEAM_RUNTIME" = "bwrap" ]]; then
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH":"$PROTON_LD_LIBRARY_PATH"
elif [[ "$PROTONTRICKS_STEAM_RUNTIME" = "legacy" ]]; then
export LD_LIBRARY_PATH="$PROTON_LD_LIBRARY_PATH"
fi
exec "$PROTON_DIST_PATH"/bin/@@name@@ "$@" || :
elif [[ "$PROTONTRICKS_STEAM_RUNTIME" = "bwrap" ]]; then
# Command is being executed outside Steam Runtime and bwrap is enabled.
# Determine mount point and configure our Wine environment before running
# bwrap and continuing execution inside the sandbox.

mount_dirs=()

Expand Down Expand Up @@ -73,32 +125,6 @@ else
mount_params+=(--filesystem "${mount}")
done

# Try to detect if wineserver is already running, and if so, copy a few
# environment variables from it to ensure our own Wine processes
# are able to run at the same time without any issues.
# This usually happens when the user is running the Steam app and
# Protontricks at the same time.
wineserver_found=false

# Find the correct Wineserver that's using the same prefix
while read -r pid; do
if xargs -0 -L1 -a "/proc/${pid}/environ" | grep "^WINEPREFIX=${WINEPREFIX}" > /dev/null 2>&1; then
wineserver_found=true
wineserver_pid="$pid"
fi
done < <(pgrep wineserver)

if [[ "$wineserver_found" = true ]]; then
# wineserver found, retrieve its environment variables
wineserver_env_vars=$(xargs -0 -L1 -a "/proc/${wineserver_pid}/environ")

# Copy the required environment variables found in the
# existing wineserver process
for env_name in "${WINESERVER_ENV_VARS_TO_COPY[@]}"; do
env_declr=$(echo "$wineserver_env_vars" | grep "^${env_name}=")
export "${env_declr?}"
done
fi

exec "$STEAM_RUNTIME_PATH"/run --share-pid --batch \
"${mount_params[@]}" -- \
Expand Down
59 changes: 23 additions & 36 deletions src/protontricks/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
"get_running_flatpak_version", "lower_dict",
"get_legacy_runtime_library_paths", "get_host_library_paths",
"RUNTIME_ROOT_GLOB_PATTERNS", "get_runtime_library_paths",
"WINE_SCRIPT_RUNTIME_V1_TEMPLATE",
"WINE_SCRIPT_RUNTIME_V2_TEMPLATE",
"create_wine_bin_dir", "run_command"
"WINE_SCRIPT_TEMPLATE", "create_wine_bin_dir", "run_command"
)

logger = logging.getLogger("protontricks")
Expand Down Expand Up @@ -169,15 +167,9 @@ def find_runtime_app_root(runtime_app):
])


WINE_SCRIPT_RUNTIME_V1_TEMPLATE = Path(
WINE_SCRIPT_TEMPLATE = Path(
pkg_resources.resource_filename(
"protontricks", "data/scripts/runtime_launch_legacy.sh"
)
).read_text(encoding="utf-8")

WINE_SCRIPT_RUNTIME_V2_TEMPLATE = Path(
pkg_resources.resource_filename(
"protontricks", "data/scripts/runtime_launch_bwrap.sh"
"protontricks", "data/scripts/wine_launch.sh"
)
).read_text(encoding="utf-8")

Expand All @@ -188,14 +180,6 @@ def create_wine_bin_dir(proton_app, use_bwrap=True):
using Steam Runtime and Proton's own libraries instead of the system
libraries
"""
# If the Proton installation uses a newer version of Steam Runtime,
# use a different template for the scripts
bin_template = (
WINE_SCRIPT_RUNTIME_V2_TEMPLATE
if proton_app.required_tool_app and use_bwrap
else WINE_SCRIPT_RUNTIME_V1_TEMPLATE
)

binaries = list((proton_app.proton_dist_path / "bin").iterdir())

# Create the base directory containing files for every Proton installation
Expand Down Expand Up @@ -223,7 +207,7 @@ def create_wine_bin_dir(proton_app, use_bwrap=True):
for binary in binaries:
proxy_script_path = bin_path / binary.name

content = bin_template.replace(
content = WINE_SCRIPT_TEMPLATE.replace(
"@@name@@", shlex.quote(binary.name),
)
content = content.replace(
Expand Down Expand Up @@ -318,6 +302,7 @@ def run_command(
os.environ.pop("WINEARCH", "")

wine_bin_dir = None
os.environ["PROTONTRICKS_STEAM_RUNTIME"] = "off"
if use_steam_runtime:
if proton_app.required_tool_app:
os.environ["STEAM_RUNTIME_PATH"] = \
Expand All @@ -332,43 +317,45 @@ def run_command(
)

if use_bwrap:
os.environ["PROTONTRICKS_STEAM_RUNTIME"] = "bwrap"
logger.info(
"Running Steam Runtime using bwrap containerization.\n"
"If any problems arise, please try running the command "
"again using the `--no-bwrap` flag and make an issue "
"report if the problem only occurs when bwrap is in use."
)
else:
os.environ["PROTONTRICKS_STEAM_RUNTIME"] = "legacy"

if runtime_name not in SUPPORTED_STEAM_RUNTIMES:
logger.warning(
"Current Steam Runtime not recognized by Protontricks."
)
else:
# Legacy Steam Runtime requires a different LD_LIBRARY_PATH
# that is produced by a script.
os.environ["PROTONTRICKS_STEAM_RUNTIME"] = "legacy"
os.environ["PROTON_LD_LIBRARY_PATH"] = \
get_legacy_runtime_library_paths(
legacy_steam_runtime_path, proton_app
)

# When Steam Runtime is enabled, create a set of helper scripts
# that load the underlying Proton Wine executables with Steam Runtime
# and Proton libraries instead of system libraries
wine_bin_dir = create_wine_bin_dir(
proton_app=proton_app, use_bwrap=use_bwrap
)
os.environ["LEGACY_STEAM_RUNTIME_PATH"] = \
str(legacy_steam_runtime_path)
# Configure the environment to use launch scripts that take care of
# configuring the environment and Wine before launching the underlying
# Wine binaries.
wine_bin_dir = create_wine_bin_dir(proton_app)
os.environ["LEGACY_STEAM_RUNTIME_PATH"] = str(legacy_steam_runtime_path)

os.environ["PATH"] = "".join([
str(wine_bin_dir), os.pathsep, os.environ["PATH"]
])
os.environ["PATH"] = os.pathsep.join(
[str(wine_bin_dir), os.environ["PATH"]]
)

if not user_provided_wine:
os.environ["WINE"] = str(wine_bin_dir / "wine")
os.environ["WINELOADER"] = os.environ["WINE"]
if not user_provided_wine:
os.environ["WINE"] = str(wine_bin_dir / "wine")
os.environ["WINELOADER"] = os.environ["WINE"]

if not user_provided_wineserver:
os.environ["WINESERVER"] = str(wine_bin_dir / "wineserver")
if not user_provided_wineserver:
os.environ["WINESERVER"] = str(wine_bin_dir / "wineserver")

logger.info("Attempting to run command %s", command)

Expand Down
11 changes: 5 additions & 6 deletions tests/cli/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def test_run_winetricks_steam_runtime_v1(

assert command.env["LEGACY_STEAM_RUNTIME_PATH"] == \
str(steam_runtime_dir / "steam-runtime")
assert command.env["PROTONTRICKS_STEAM_RUNTIME"] == "legacy"
assert "STEAM_RUNTIME_PATH" not in command.env

for name in ("wine", "wineserver"):
Expand All @@ -135,9 +136,8 @@ def test_run_winetricks_steam_runtime_v1(

content = path.read_text()

# The script template for legacy Steam Runtime is used
# Correct binary names used in the scripts
assert "\"$PROTON_DIST_PATH\"/bin/{}".format(name) in content
assert "PROTONTRICKS_INSIDE_STEAM_RUNTIME" not in content

def test_run_winetricks_steam_runtime_v2(
self, cli, home_dir, steam_app_factory, steam_runtime_dir,
Expand Down Expand Up @@ -177,6 +177,7 @@ def test_run_winetricks_steam_runtime_v2(
str(steam_runtime_dir / "steam-runtime")
assert command.env["STEAM_RUNTIME_PATH"] == \
str(steam_runtime_soldier.install_path)
assert command.env["PROTONTRICKS_STEAM_RUNTIME"] == "bwrap"

# No warning will be created since Steam Runtime Soldier is recognized
# by Protontricks
Expand All @@ -194,9 +195,8 @@ def test_run_winetricks_steam_runtime_v2(

content = path.read_text()

# The script template for bwrap-based Steam Runtime is used
# Correct binary names used in the scripts
assert "\"$PROTON_DIST_PATH\"/bin/{}".format(name) in content
assert "PROTONTRICKS_INSIDE_STEAM_RUNTIME" in content

def test_run_winetricks_steam_runtime_v2_no_bwrap(
self, cli, home_dir, steam_app_factory, steam_runtime_dir,
Expand Down Expand Up @@ -243,6 +243,7 @@ def test_run_winetricks_steam_runtime_v2_no_bwrap(
str(steam_runtime_dir / "steam-runtime")
assert command.env["STEAM_RUNTIME_PATH"] == \
str(steam_runtime_soldier.install_path)
assert command.env["PROTONTRICKS_STEAM_RUNTIME"] == "legacy"

# No warning will be created since Steam Runtime Soldier is recognized
# by Protontricks
Expand All @@ -260,9 +261,7 @@ def test_run_winetricks_steam_runtime_v2_no_bwrap(

content = path.read_text()

# The script template for normal Steam Runtime is used
assert "\"$PROTON_DIST_PATH\"/bin/{}".format(name) in content
assert "PROTONTRICKS_INSIDE_STEAM_RUNTIME" not in content

def test_run_winetricks_game_not_found(
self, cli, steam_app_factory, default_proton, command):
Expand Down

0 comments on commit d6972e0

Please sign in to comment.