diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ecf799..266f170 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] ### Added - Add desktop file associations for batch files and Internet shortcuts + - Add support for passing Winetricks arguments after `--` when using the Protontricks GUI ### Changed - Ignore duplicate Steam apps and only list the most recently updated app diff --git a/README.md b/README.md index 8b0598a..bb1da7b 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,10 @@ protontricks -c # Run the Protontricks GUI protontricks --gui +# Pass arguments to Winetricks when using the Protontricks GUI. +# Everything after "--" is passed directly to Winetricks. +protontricks --gui -- + # Launch a Windows program (executable or command) using Protontricks protontricks-launch diff --git a/src/protontricks/cli/main.py b/src/protontricks/cli/main.py index d1ac0e4..41b477b 100755 --- a/src/protontricks/cli/main.py +++ b/src/protontricks/cli/main.py @@ -54,6 +54,10 @@ def main(args=None, steam_path=None, steam_root=None): "Use Protontricks GUI to select the game\n" "$ protontricks --gui\n" "\n" + "Pass arguments to Winetricks when using the Protontricks GUI. " + "Arguments after '--' are passed to Winetricks as-is.\n" + "$ protontricks --gui -- WINETRICKS_ARGUMENTS\n" + "\n" "Environment variables:\n" "\n" "PROTON_VERSION: name of the preferred Proton installation\n" @@ -122,7 +126,22 @@ def main(args=None, steam_path=None, steam_root=None): # No arguments were provided, default to GUI args = ["--gui"] - args = parser.parse_args(args) + # When using the GUI, allow Winetricks arguments to be passed after a + # delimiter. + winetricks_args = [] + if "--" in args: + delimiter_idx = args.index("--") + args_before_delimiter = parser.parse_args(args[:delimiter_idx]) + + if args_before_delimiter.gui: + winetricks_args = list(args[delimiter_idx + 1:]) + args = args_before_delimiter + else: + args = parser.parse_args(args) + else: + args = parser.parse_args(args) + + args.winetricks_command += winetricks_args # 'cli_error_handler' relies on this to know whether to use error dialog or # not @@ -209,7 +228,10 @@ def run(self): steam_app=self.steam_app, use_steam_runtime=self.use_steam_runtime, legacy_steam_runtime_path=self.legacy_steam_runtime_path, - command=[str(self.winetricks_path), "--gui"], + command=( + [str(self.winetricks_path), "--gui"] + + self.cli_args.winetricks_command + ), use_bwrap=self.use_bwrap, start_wineserver=self.start_background_wineserver, cwd=cwd diff --git a/tests/cli/test_main.py b/tests/cli/test_main.py index 02b52af..46c8794 100644 --- a/tests/cli/test_main.py +++ b/tests/cli/test_main.py @@ -40,6 +40,18 @@ def test_run_winetricks( str(proton_install_path / "dist" / "lib" / "wine") ) + def test_run_winetricks_with_options( + self, cli, steam_app_factory, default_proton, command_mock): + """ + Pass Winetricks options after an app ID + """ + steam_app_factory(name="Fake game 1", appid=10) + + cli(["10", "-q", "--force", "vcrun2019"]) + + command = command_mock.commands[-1] + assert command.args[1:] == ["-q", "--force", "vcrun2019"] + def test_run_winetricks_shortcut( self, cli, shortcut_factory, default_proton, command_mock, steam_dir): @@ -367,11 +379,18 @@ def test_run_returncode_passed(self, cli, steam_app_factory): steam_app_factory(name="Fake game", appid=10) cli(["-c", "exit 5", "10"], expect_returncode=5) - def test_run_multiple_command_mock(self, cli): + @pytest.mark.parametrize( + "cli_args", + [ + ["--gui", "-s", "game"], + ["--gui", "10", "--", "-q"] + ] + ) + def test_run_multiple_command_mock(self, cli, cli_args): """ Try performing multiple command_mock at once """ - result = cli(["--gui", "-s", "game"]) + result = cli(cli_args) assert "Only one action can be performed" in result @@ -741,9 +760,24 @@ def test_steam_installation_not_selected(self, cli, gui_provider): class TestCLIGUI: + @pytest.mark.parametrize( + "cli_args,expected_winetricks_args", + [ + (["--gui"], ["--gui"]), + (["--no-term", "--gui", "--", "-q"], ["--gui", "-q"]), + ( + ["--gui", "--", "-q", "--force", "--country=US"], + ["--gui", "-q", "--force", "--country=US"] + ), + ( + ["--gui", "--", "--verbose", "--version"], + ["--gui", "--verbose", "--version"] + ) + ] + ) def test_run_gui( self, cli, default_proton, steam_app_factory, gui_provider, - command_mock, home_dir): + command_mock, home_dir, cli_args, expected_winetricks_args): """ Start the GUI and fake selecting a game """ @@ -753,13 +787,13 @@ def test_run_gui( # Fake the user selecting the game gui_provider.mock_stdout = "Fake game 1: 10" - cli(["--gui"]) + cli(cli_args) command = command_mock.commands[-1] # 'winetricks --gui' was run for the game selected by user assert str(command.args[0]) == \ str(home_dir / ".local" / "bin" / "winetricks") - assert command.args[1] == "--gui" + assert command.args[1:] == expected_winetricks_args # Correct environment vars were set assert command.env["WINE"] == str( @@ -777,6 +811,16 @@ def test_run_gui( str(proton_install_path / "dist" / "lib" / "wine") ) + def test_run_gui_winetricks_args_require_delimiter(self, cli): + """ + Require a delimiter before Winetricks arguments in GUI mode + """ + _, stderr = cli( + ["--gui", "-q"], expect_returncode=2, include_stderr=True + ) + + assert "unrecognized arguments: -q" in stderr + def test_run_gui_no_games(self, cli, default_proton): """ Try starting the GUI when no games are installed