Ejemplo n.º 1
0
    def func(name,
             appid,
             compat_tool_name=None,
             library_dir=None,
             add_prefix=True,
             required_tool_app=None):
        if not library_dir:
            steamapps_dir = steam_dir / "steamapps"
        else:
            steamapps_dir = library_dir / "steamapps"

        install_path = steamapps_dir / "common" / name
        install_path.mkdir(parents=True)

        if required_tool_app:
            (install_path / "toolmanifest.vdf").write_text(
                vdf.dumps({
                    "manifest": {
                        "require_tool_appid": required_tool_app.appid
                    }
                }))

        (steamapps_dir / "appmanifest_{}.acf".format(appid)).write_text(
            vdf.dumps({
                "AppState": {
                    "appid": str(appid),
                    "name": name,
                    "installdir": name
                }
            }))

        # Add Wine prefix
        if add_prefix:
            (steamapps_dir / "compatdata" / str(appid) /
             "pfx").mkdir(parents=True)
            (steamapps_dir / "compatdata" / str(appid) / "pfx.lock").touch()

        # Set the preferred Proton installation for the app if provided
        if compat_tool_name:
            steam_config = vdf.loads(steam_config_path.read_text())
            steam_config["InstallConfigStore"]["Software"]["Valve"]["Steam"][
                "CompatToolMapping"][str(appid)] = {
                    "name": compat_tool_name,
                    "config": "",
                    "Priority": "250"
                }
            steam_config_path.write_text(vdf.dumps(steam_config))

        steam_app = SteamApp(name=name,
                             appid=appid,
                             install_path=str(steamapps_dir / "common" / name),
                             prefix_path=str(steamapps_dir / "compatdata" /
                                             str(appid) / "pfx"))
        if required_tool_app:
            # In actual code, `required_tool_app` attribute is populated later
            # when we have retrieved all Steam apps and can find the
            # corresponding app using its app ID
            steam_app.required_tool_app = required_tool_app

        return steam_app
Ejemplo n.º 2
0
    def func(name, compat_tool_dir=None):
        if not compat_tool_dir:
            compat_tool_dir = \
                steam_dir.parent / "root" / "compatibilitytools.d" / name
        else:
            compat_tool_dir = compat_tool_dir / name
        compat_tool_dir.mkdir(parents=True, exist_ok=True)
        (compat_tool_dir / "proton").touch()
        (compat_tool_dir / "proton").chmod(0o744)
        (compat_tool_dir / "dist" / "bin").mkdir(parents=True)
        (compat_tool_dir / "dist" / "bin" / "wine").touch()
        (compat_tool_dir / "dist" / "bin" / "wineserver").touch()
        (compat_tool_dir / "compatibilitytool.vdf").write_text(
            vdf.dumps({
                "compatibilitytools": {
                    "compat_tools": {
                        name: {
                            "install_path": ".",
                            "display_name": name,
                            "from_oslist": "windows",
                            "to_oslist": "linux"
                        }
                    }
                }
            })
        )

        return SteamApp(
            name=name,
            install_path=str(compat_tool_dir)
        )
Ejemplo n.º 3
0
    def test_steam_app_from_appmanifest_permission_denied(
            self, steam_app_factory, caplog, monkeypatch):
        """
        Test trying to read a SteamApp manifest that the user doesn't
        have read permission for
        """
        def _mock_read_text(self, encoding=None):
            """
            Mock `pathlib.Path.read_text` that mimics a failure due to
            insufficient permissions
            """
            raise PermissionError("Permission denied")

        steam_app = steam_app_factory(name="Fake game", appid=10)

        appmanifest_path = \
            Path(steam_app.install_path).parent.parent / "appmanifest_10.acf"

        monkeypatch.setattr("pathlib.Path.read_text", _mock_read_text)

        assert not SteamApp.from_appmanifest(path=appmanifest_path,
                                             steam_lib_paths=[])

        record = caplog.records[-1]
        assert record.getMessage() == (
            "Skipping appmanifest {} due to insufficient permissions".format(
                str(appmanifest_path)))
Ejemplo n.º 4
0
    def test_steam_app_from_appmanifest_empty(self, steam_app_factory):
        steam_app = steam_app_factory(name="Fake game", appid=10)

        appmanifest_path = \
            Path(steam_app.install_path).parent.parent / "appmanifest_10.acf"
        appmanifest_path.write_text("")

        # Empty appmanifest file is ignored
        assert not SteamApp.from_appmanifest(path=str(appmanifest_path),
                                             steam_lib_paths=[])
Ejemplo n.º 5
0
    def test_steam_app_from_appmanifest_invalid(self, steam_app_factory,
                                                content):
        steam_app = steam_app_factory(name="Fake game", appid=10)

        appmanifest_path = \
            Path(steam_app.install_path).parent.parent / "appmanifest_10.acf"
        appmanifest_path.write_bytes(content)

        # Invalid appmanifest file is ignored
        assert not SteamApp.from_appmanifest(path=appmanifest_path,
                                             steam_lib_paths=[])
Ejemplo n.º 6
0
    def test_steam_app_from_appmanifest_empty(self, steam_app_factory):
        """
        Try to deserialize an empty appmanifest and check that no SteamApp
        is returned
        """
        steam_app = steam_app_factory(name="Fake game", appid=10)

        appmanifest_path = \
            Path(steam_app.install_path).parent.parent / "appmanifest_10.acf"
        appmanifest_path.write_text("")

        # Empty appmanifest file is ignored
        assert not SteamApp.from_appmanifest(path=appmanifest_path,
                                             steam_lib_paths=[])
Ejemplo n.º 7
0
    def test_steam_app_from_appmanifest(self, steam_app_factory, steam_dir):
        """
        Create a SteamApp from an appmanifest file
        """
        steam_app = steam_app_factory(name="Fake game", appid=10)

        appmanifest_path = \
            Path(steam_app.install_path).parent.parent / "appmanifest_10.acf"

        steam_app = SteamApp.from_appmanifest(
            path=str(appmanifest_path),
            steam_lib_paths=[str(steam_dir / "steam" / "steamapps")])

        assert steam_app.name == "Fake game"
        assert steam_app.appid == 10
Ejemplo n.º 8
0
    def func(name,
             appid,
             compat_tool_name=None,
             library_dir=None,
             add_prefix=True):
        if not library_dir:
            steamapps_dir = steam_dir / "steamapps"
        else:
            steamapps_dir = library_dir / "steamapps"

        (steamapps_dir / "common" / name).mkdir(parents=True)

        (steamapps_dir / "appmanifest_{}.acf".format(appid)).write_text(
            vdf.dumps({
                "AppState": {
                    "appid": str(appid),
                    "name": name,
                    "installdir": name
                }
            }))

        # Add Wine prefix
        if add_prefix:
            (steamapps_dir / "compatdata" / str(appid) /
             "pfx").mkdir(parents=True)
            (steamapps_dir / "compatdata" / str(appid) / "pfx.lock").touch()

        # Set the preferred Proton installation for the app if provided
        if compat_tool_name:
            steam_config = vdf.loads(steam_config_path.read_text())
            steam_config["InstallConfigStore"]["Software"]["Valve"]["Steam"][
                "CompatToolMapping"][str(appid)] = {
                    "name": compat_tool_name,
                    "config": "",
                    "Priority": "250"
                }
            steam_config_path.write_text(vdf.dumps(steam_config))

        return SteamApp(name=name,
                        appid=appid,
                        install_path=str(steamapps_dir / "common" / name),
                        prefix_path=str(steamapps_dir / "compatdata" /
                                        str(appid) / "pfx"))
Ejemplo n.º 9
0
    def func(name):
        tool_dir = steam_dir.parent / "root" / "compatibilitytools.d" / name
        tool_dir.mkdir(parents=True)
        (tool_dir / "proton").touch()
        (tool_dir / "proton").chmod(0o744)
        (tool_dir / "compatibilitytool.vdf").write_text(
            vdf.dumps({
                "compatibilitytools": {
                    "compat_tools": {
                        name: {
                            "install_path": ".",
                            "display_name": name,
                            "from_oslist": "windows",
                            "to_oslist": "linux"
                        }
                    }
                }
            }))

        return SteamApp(name=name, install_path=str(tool_dir))
Ejemplo n.º 10
0
    def test_steam_app_from_appmanifest_corrupted_toolmanifest(
            self, steam_runtime_soldier, proton_factory, caplog, content):
        """
        Test trying to a SteamApp manifest from an incomplete
        Proton installation with an empty or corrupted toolmanifest.vdf file
        """
        proton_app = proton_factory(name="Proton 5.13",
                                    appid=10,
                                    compat_tool_name="proton_513",
                                    required_tool_app=steam_runtime_soldier)
        # Empty the "toolmanifest.vdf" file
        (proton_app.install_path / "toolmanifest.vdf").write_bytes(content)

        assert not SteamApp.from_appmanifest(
            path=proton_app.install_path.parent.parent / "appmanifest_10.acf",
            steam_lib_paths=[])

        assert len(caplog.records) == 1
        record = caplog.records[0]

        assert "Tool manifest for Proton 5.13 is empty" in record.message
Ejemplo n.º 11
0
    def test_steam_app_userconfig_name(self, steam_app_factory):
        """
        Try creating a SteamApp from an older version of the app manifest
        which contains the application name in a different field

        See GitHub issue #103 for details
        """
        steam_app = steam_app_factory(name="Fake game", appid=10)

        appmanifest_path = \
            Path(steam_app.install_path).parent.parent / "appmanifest_10.acf"
        data = vdf.loads(appmanifest_path.read_text())

        # Older installations store the name in `userconfig/name` instead
        del data["AppState"]["name"]
        data["AppState"]["userconfig"] = {"name": "Fake game"}

        appmanifest_path.write_text(vdf.dumps(data))

        app = SteamApp.from_appmanifest(path=appmanifest_path,
                                        steam_lib_paths=[])

        assert app.name == "Fake game"