Cleanup:
* 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:
parent
75c8e8d817
commit
89df9806b5
|
@ -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)
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"]
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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:
|
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_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 ""
|
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_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
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue