1
0
Fork 0
mirror of synced 2024-06-26 18:20:50 +12:00
* Use `vars()` instead of directly accessing `__dict__`
* Remove `auto_update` from RareGame's metadata
* Correct check for updating the Steam App ID (We want to keep any changes from the user)
* Collect both Wine and Proton prefixes when removing overlay registry keys.
* Add few convenience functions in config_helper and paths.
This commit is contained in:
loathingKernel 2023-09-20 01:39:15 +03:00
parent 75c8e8d817
commit 89df9806b5
No known key found for this signature in database
GPG key ID: CE0C72D0B53821FD
8 changed files with 78 additions and 35 deletions

View file

@ -83,7 +83,7 @@ class GameMetadataView(QTreeView, SideTabContents):
self.set_title.emit(self.rgame.app_title) self.set_title.emit(self.rgame.app_title)
self.model.clear() self.model.clear()
try: try:
self.model.load(view.__dict__) self.model.load(vars(view))
except Exception as e: except Exception as e:
pass pass
self.resizeColumnToContents(0) self.resizeColumnToContents(0)

View file

@ -201,7 +201,7 @@ class RareLauncher(RareApp):
def send_message(self, message: BaseModel): def send_message(self, message: BaseModel):
if self.socket: if self.socket:
self.socket.write(json.dumps(message.__dict__).encode("utf-8")) self.socket.write(json.dumps(vars(message)).encode("utf-8"))
self.socket.flush() self.socket.flush()
else: else:
self.logger.error("Can't send message") self.logger.error("Can't send message")

View file

@ -20,7 +20,7 @@ from rare.shared.game_process import GameProcess
from rare.shared.image_manager import ImageManager from rare.shared.image_manager import ImageManager
from rare.utils.paths import data_dir, get_rare_executable from rare.utils.paths import data_dir, get_rare_executable
from rare.utils.steam_grades import get_rating from rare.utils.steam_grades import get_rating
from rare.utils.config_helper import add_envvar, remove_envvar from rare.utils.config_helper import add_envvar
logger = getLogger("RareGame") logger = getLogger("RareGame")
@ -28,7 +28,6 @@ logger = getLogger("RareGame")
class RareGame(RareGameSlim): class RareGame(RareGameSlim):
@dataclass @dataclass
class Metadata: class Metadata:
auto_update: bool = False
queued: bool = False queued: bool = False
queue_pos: Optional[int] = None queue_pos: Optional[int] = None
last_played: datetime = datetime.min last_played: datetime = datetime.min
@ -41,20 +40,19 @@ class RareGame(RareGameSlim):
@classmethod @classmethod
def from_dict(cls, data: Dict): def from_dict(cls, data: Dict):
return cls( return cls(
auto_update=data.get("auto_update", False),
queued=data.get("queued", False), queued=data.get("queued", False),
queue_pos=data.get("queue_pos", None), queue_pos=data.get("queue_pos", None),
last_played=datetime.fromisoformat(data["last_played"]) if data.get("last_played", None) else datetime.min, last_played=datetime.fromisoformat(x) if (x := data.get("last_played", None)) else datetime.min,
grant_date=datetime.fromisoformat(data["grant_date"]) if data.get("grant_date", None) else None, grant_date=datetime.fromisoformat(x) if (x := data.get("grant_date", None)) else None,
steam_appid=data.get("steam_appid", None), steam_appid=data.get("steam_appid", None),
steam_grade=data.get("steam_grade", None), steam_grade=data.get("steam_grade", None),
steam_date=datetime.fromisoformat(data["steam_date"]) if data.get("steam_date", None) else datetime.min, steam_date=datetime.fromisoformat(x) if (x := data.get("steam_date", None)) else datetime.min,
tags=data.get("tags", []), tags=data.get("tags", []),
) )
def as_dict(self): @property
def __dict__(self):
return dict( return dict(
auto_update=self.auto_update,
queued=self.queued, queued=self.queued,
queue_pos=self.queue_pos, queue_pos=self.queue_pos,
last_played=self.last_played.isoformat() if self.last_played else datetime.min, last_played=self.last_played.isoformat() if self.last_played else datetime.min,
@ -144,13 +142,14 @@ class RareGame(RareGameSlim):
def __load_metadata_json() -> Dict: def __load_metadata_json() -> Dict:
if RareGame.__metadata_json is None: if RareGame.__metadata_json is None:
metadata = {} metadata = {}
file = os.path.join(data_dir(), "game_meta.json")
try: try:
with open(os.path.join(data_dir(), "game_meta.json"), "r") as metadata_fh: with open(file, "r") as f:
metadata = json.load(metadata_fh) metadata = json.load(f)
except FileNotFoundError: except FileNotFoundError:
logger.info("Game metadata json file does not exist.") logger.info("%s does not exist", file)
except json.JSONDecodeError: except json.JSONDecodeError:
logger.warning("Game metadata json file is corrupt.") logger.warning("%s is corrupt", file)
finally: finally:
RareGame.__metadata_json = metadata RareGame.__metadata_json = metadata
return RareGame.__metadata_json return RareGame.__metadata_json
@ -167,9 +166,9 @@ class RareGame(RareGameSlim):
with RareGame.__metadata_lock: with RareGame.__metadata_lock:
metadata: Dict = self.__load_metadata_json() metadata: Dict = self.__load_metadata_json()
# pylint: disable=unsupported-assignment-operation # pylint: disable=unsupported-assignment-operation
metadata[self.app_name] = self.metadata.as_dict() metadata[self.app_name] = vars(self.metadata)
with open(os.path.join(data_dir(), "game_meta.json"), "w") as metadata_json: with open(os.path.join(data_dir(), "game_meta.json"), "w+") as file:
json.dump(metadata, metadata_json, indent=2) json.dump(metadata, file, indent=2)
def update_game(self): def update_game(self):
self.game = self.core.get_game( self.game = self.core.get_game(
@ -468,8 +467,10 @@ class RareGame(RareGameSlim):
return self.metadata.steam_appid return self.metadata.steam_appid
def set_steam_grade(self, appid: int, grade: str) -> None: def set_steam_grade(self, appid: int, grade: str) -> None:
if appid or self.steam_appid is None: if appid and self.steam_appid is None:
add_envvar(self.app_name, "SteamAppId", str(appid)) add_envvar(self.app_name, "SteamAppId", str(appid))
add_envvar(self.app_name, "SteamGameId", str(appid))
add_envvar(self.app_name, "STEAM_COMPAT_APP_ID", str(appid))
self.metadata.steam_appid = appid self.metadata.steam_appid = appid
self.metadata.steam_grade = grade self.metadata.steam_grade = grade
self.metadata.steam_date = datetime.utcnow() self.metadata.steam_date = datetime.utcnow()

View file

@ -42,7 +42,7 @@ class InstallOptionsModel:
def as_install_kwargs(self) -> Dict: def as_install_kwargs(self) -> Dict:
return { return {
k: getattr(self, k) k: getattr(self, k)
for k in self.__dict__ for k in vars(self)
if k not in ["update", "silent", "create_shortcut", "overlay", "install_prereqs"] if k not in ["update", "silent", "create_shortcut", "overlay", "install_prereqs"]
} }

View file

@ -1,4 +1,5 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import Dict
class Actions: class Actions:
@ -15,7 +16,7 @@ class BaseModel:
app_name: str app_name: str
@classmethod @classmethod
def from_json(cls, data: dict): def from_json(cls, data: Dict):
return cls( return cls(
action=data["action"], action=data["action"],
app_name=data["app_name"] app_name=data["app_name"]
@ -28,9 +29,9 @@ class FinishedModel(BaseModel):
playtime: int # seconds playtime: int # seconds
@classmethod @classmethod
def from_json(cls, data): def from_json(cls, data: Dict):
return cls( return cls(
**BaseModel.from_json(data).__dict__, **vars(BaseModel.from_json(data)),
exit_code=data["exit_code"], exit_code=data["exit_code"],
playtime=data["playtime"], playtime=data["playtime"],
) )
@ -47,7 +48,7 @@ class StateChangedModel(BaseModel):
new_state: int new_state: int
@classmethod @classmethod
def from_json(cls, data): def from_json(cls, data: Dict):
return cls( return cls(
action=data["action"], action=data["action"],
app_name=data["app_name"], app_name=data["app_name"],
@ -60,8 +61,8 @@ class ErrorModel(BaseModel):
error_string: str error_string: str
@classmethod @classmethod
def from_json(cls, data): def from_json(cls, data: Dict):
return cls( return cls(
**BaseModel.from_json(data).__dict__, **vars(BaseModel.from_json(data)),
error_string=data["error_string"] error_string=data["error_string"]
) )

View file

@ -11,7 +11,7 @@ from rare.lgndr.glue.arguments import LgndrUninstallGameArgs
from rare.lgndr.glue.monkeys import LgndrIndirectStatus from rare.lgndr.glue.monkeys import LgndrIndirectStatus
from rare.models.game import RareGame from rare.models.game import RareGame
from rare.models.install import UninstallOptionsModel from rare.models.install import UninstallOptionsModel
from rare.utils import config_helper from rare.utils import config_helper as config
from rare.utils.paths import desktop_links_supported, desktop_link_types, desktop_link_path from rare.utils.paths import desktop_links_supported, desktop_link_types, desktop_link_path
from .worker import Worker from .worker import Worker
@ -31,7 +31,7 @@ def uninstall_game(
logger.info('Removing registry entries...') logger.info('Removing registry entries...')
if platform.system() != "Window": if platform.system() != "Window":
prefixes = config_helper.get_wine_prefixes() prefixes = config.get_prefixes()
if platform.system() == "Darwin": if platform.system() == "Darwin":
# TODO: add crossover support # TODO: add crossover support
pass pass
@ -65,10 +65,10 @@ def uninstall_game(
) )
if not keep_config: if not keep_config:
logger.info("Removing sections in config file") logger.info("Removing sections in config file")
config_helper.remove_section(rgame.app_name) config.remove_section(rgame.app_name)
config_helper.remove_section(f"{rgame.app_name}.env") config.remove_section(f"{rgame.app_name}.env")
config_helper.save_config() config.save_config()
return status.success, status.message return status.success, status.message

View file

@ -67,9 +67,7 @@ def get_game_envvar(option: str, app_name: Optional[str] = None, fallback: Any =
def get_proton_compat_data(app_name: Optional[str] = None, fallback: Any = None) -> str: def get_proton_compat_data(app_name: Optional[str] = None, fallback: Any = None) -> str:
_compat = _config.get("default.env", "STEAM_COMPAT_DATA_PATH", fallback=fallback) _compat = get_game_envvar("STEAM_COMPAT_DATA_PATH", app_name, fallback=fallback)
if app_name is not None:
_compat = _config.get(f'{app_name}.env', "STEAM_COMPAT_DATA_PATH", fallback=_compat)
# return os.path.join(_compat, "pfx") if _compat else fallback # return os.path.join(_compat, "pfx") if _compat else fallback
return _compat return _compat
@ -87,10 +85,47 @@ def get_wine_prefixes() -> Set[str]:
_prefixes = [] _prefixes = []
for name, section in _config.items(): for name, section in _config.items():
pfx = section.get("WINEPREFIX") or section.get("wine_prefix") pfx = section.get("WINEPREFIX") or section.get("wine_prefix")
if not pfx:
pfx = os.path.join(compatdata, "pfx") if (compatdata := section.get("STEAM_COMPAT_DATA_PATH")) else ""
if pfx: if pfx:
_prefixes.append(pfx) _prefixes.append(pfx)
_prefixes = [os.path.expanduser(prefix) for prefix in _prefixes] _prefixes = [os.path.expanduser(prefix) for prefix in _prefixes]
return {p for p in _prefixes if os.path.isdir(p)} return {p for p in _prefixes if os.path.isdir(p)}
def get_proton_prefixes() -> Set[str]:
_prefixes = []
for name, section in _config.items():
pfx = os.path.join(compatdata, "pfx") if (compatdata := section.get("STEAM_COMPAT_DATA_PATH")) else ""
if pfx:
_prefixes.append(pfx)
_prefixes = [os.path.expanduser(prefix) for prefix in _prefixes]
return {p for p in _prefixes if os.path.isdir(p)}
def get_prefixes() -> Set[str]:
return get_wine_prefixes().union(get_proton_prefixes())
def prefix_exists(pfx: str) -> bool:
return os.path.isdir(pfx) and os.path.isfile(os.path.join(pfx, "user.reg"))
def get_prefix(app_name: str = "default") -> Optional[str]:
_compat_path = _config.get(f"{app_name}.env", "STEAM_COMPAT_DATA_PATH", fallback=None)
if _compat_path and prefix_exists(_compat_prefix := os.path.join(_compat_path, "pfx")):
return _compat_prefix
_wine_prefix = _config.get(f"{app_name}.env", "WINEPREFIX", fallback=None)
_wine_prefix = _config.get(app_name, "wine_prefix", fallback=_wine_prefix)
if _wine_prefix and prefix_exists(_wine_prefix):
return _wine_prefix
_compat_path = _config.get(f"default.env", "STEAM_COMPAT_DATA_PATH", fallback=None)
if _compat_path and prefix_exists(_compat_prefix := os.path.join(_compat_path, "pfx")):
return _compat_prefix
_wine_prefix = _config.get(f"default.env", "WINEPREFIX", fallback=None)
_wine_prefix = _config.get("default", "wine_prefix", fallback=_wine_prefix)
if _wine_prefix and prefix_exists(_wine_prefix):
return _wine_prefix
return None

View file

@ -36,6 +36,12 @@ def lock_file() -> Path:
return Path(QStandardPaths.writableLocation(QStandardPaths.TempLocation), "Rare.lock") return Path(QStandardPaths.writableLocation(QStandardPaths.TempLocation), "Rare.lock")
def config_dir() -> Path:
# FIXME: This returns ~/.config/Rare/Rare/ for some reason while the settings are in ~/.config/Rare/Rare.conf
# Take the parent for now, but this should be investigated
return Path(QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation)).parent
def data_dir() -> Path: def data_dir() -> Path:
return Path(QStandardPaths.writableLocation(QStandardPaths.AppDataLocation)) return Path(QStandardPaths.writableLocation(QStandardPaths.AppDataLocation))