Can't Open CtInfo or Games List Dialog for Lutris
Closed this issue · 3 comments
Please fill out following when reporting a new bug:
Describe the bug
When trying to open the CtInfo or Games List for Lutris, ProtonUp-Qt crashes because it cannot find the Lutris games folder.
ProtonUp-Qt is searching for the Lutris games folder in ~/.config/lutris/games (iirc to parse the game's yaml file), however on my laptop, it appears that this folder is at ~/.local/share/lutris/games.
While the quick-fix would be to return an empty dict in datastructures.py:187, I am opening an issue because there may be a broader problem here. Did the Lutris game folder path change, and if so, when? This is more of a wider question, and something I plan to look into if I have time and no one beats me to it, but something I wanted to report all the same.
If the path has changed, we should investigate if Lutris migrates existing game yml's over and if it that is the case, I don't know if we need to worry about "backwards compatibility" on our part; we can just expect users to upgrade their Lutris version and have launched it in order to migrate the yml's over.
If Lutris does not, we may need to look into checking both paths; the ~/.config/lutris/games path and the ~/.local/share/lutris/games path (and the Flatpak equivalents).
Either way, too, the check in datastructures.py is probably a bit naive to begin with. We assume that os.path.join(os.path.expanduser(lutris_config_dir), 'games') will exist when we pass it to os.listdir, which we probably shouldn't do. We can address this as part of this issue when resolving it though; whether the path has changed or not we should probably store os.path.join(os.path.expanduser(lutris_config_dir), 'games') in a variable and return an empty dict if it doesn't exist.
To Reproduce
Steps to reproduce the behavior:
- Select the "Lutris" launcher from ProtonUp-Qt.
- Attempt to open the CtInfo or Games List dialog.
- ProtonUp-Qt will crash if
~/.config/lutris/gamesdoes not exist.
Expected behavior
ProtonUp-Qt should not crash, but more specifically we should investigate the exact cause here and see if we need any code changes beyond just checking if the path exists. We may need to tell ProtonUp-Qt to check both ~/.config/lutris/games and ~/.local/share/lutris/games, or we may be safe to simply move to whichever is the newest if Lutris did indeed specifically change this path.
And as part of this change, whether we need to change the path or check both, we should make our os.listdir parameter safer by checking that the folder(s) actually exist before we attempt to search them.
Desktop (please complete the following information):
- Platform: Laptop (did not verify on my Desktop PC yet, which has a 5+ year old Lutris installation)
- System: Arch Linux
- Version: ProtonUp-Qt @ 71885f6
- How did you install ProtonUp-Qt?: Running from source using Python 3.10 and a pyenv-virtualenv
Additional context
Plan to check the paths and behaviour on my Desktop PC in the future.
Terminal output
ProtonUp-Qt 2.11.1 by DavidoTek. Build Info: built from source.
Python 3.10.14 (main, Jun 21 2024, 21:57:01) [GCC 14.1.1 20240522], PySide 6.8.2.1
Platform: EndeavourOS rolling Linux-6.13.5-arch1-1-x86_64-with-glibc2.41
Loading locale en / en_GB
Loaded ctmod GE-Proton
Loaded ctmod Wine-GE
Loaded ctmod Boxtron
Loaded ctmod Kron4ek Wine-Builds Vanilla
Loaded ctmod Lutris-Wine
Loaded ctmod Luxtorpeda
Loaded ctmod Northstar Proton (Titanfall 2)
Loaded ctmod Proton-CachyOS
Loaded ctmod Proton Tkg
Loaded ctmod Proton Tkg (Wine Master)
Loaded ctmod Roberta
Loaded ctmod RTSP Proton
Loaded ctmod Steam-Play-None
Loaded ctmod SteamTinkerLaunch
Loaded ctmod SteamTinkerLaunch-git
Loaded ctmod vkd3d-lutris
Loaded ctmod vkd3d-proton
Loaded ctmod Wine Tkg (Valve Wine Bleeding Edge)
Loaded ctmod Wine Tkg (Wine Master)
Loaded ctmod DXVK
Loaded ctmod DXVK Async
Loaded ctmod DXVK (nightly)
Attribute Qt::AA_ShareOpenGLContexts must be set before QCoreApplication is created.
Traceback (most recent call last):
File "/home/emma/Programming/ProtonUp-Qt/pupgui2/pupgui2.py", line 387, in btn_show_game_list_clicked
gl_dialog = PupguiGameListDialog(install_directory(), self.ui)
File "/home/emma/Programming/ProtonUp-Qt/pupgui2/pupgui2gamelistdialog.py", line 41, in __init__
self.setup_ui()
File "/home/emma/Programming/ProtonUp-Qt/pupgui2/pupgui2gamelistdialog.py", line 53, in setup_ui
self.setup_lutris_list_ui()
File "/home/emma/Programming/ProtonUp-Qt/pupgui2/pupgui2gamelistdialog.py", line 94, in setup_lutris_list_ui
self.update_game_list_lutris()
File "/home/emma/Programming/ProtonUp-Qt/pupgui2/pupgui2gamelistdialog.py", line 200, in update_game_list_lutris
game_cfg = game.get_game_config()
File "/home/emma/Programming/ProtonUp-Qt/pupgui2/datastructures.py", line 187, in get_game_config
for game_cfg_file in os.listdir(os.path.join(os.path.expanduser(lutris_config_dir), 'games')):
FileNotFoundError: [Errno 2] No such file or directory: '/home/emma/.config/lutris/games'
Just checked and just downloaded a fresh game on my Desktop PC, and Lutris used ~/.config/lutris/games. The folder ~/.local/share/lutris/games does not exist on my PC.
Also, when removing ~/.config/lutris/games, Lutris re-created the folder in ~/.config/lutris/games. In other words, I could not get my Desktop PC installation to use ~/.local/share/lutris/games.
Interesting. It seems like Lutris will use ~/.local/share/lutris if ~/.config/lutris does not exist. Actually, the later one seems to be deprecated.
Also, when removing ~/.config/lutris/games, Lutris re-created the folder in ~/.config/lutris/games. In other words, I could not get my Desktop PC installation to use ~/.local/share/lutris/games.
I wonder where and when that folder is created, I haven't checked. I only tested the Flatpak version and there it stores everything in the data folder.
Are you using a different version on the laptop or a different distribution (deb, AUR, ...)?
If Lutris does not, we may need to look into checking both paths; the ~/.config/lutris/games path and the ~/.local/share/lutris/games path (and the Flatpak equivalents).
It seems like Lutris will use the old location if it is not reinstalled or manually changed. So we have to support both.
Regarding the Flatpak, the games folder is stored under ~/.var/app/net.lutris.Lutris/data/lutris on my computer, so we need to change that from ~/.var/app/net.lutris.Lutris/config/lutris:
ProtonUp-Qt/pupgui2/constants.py
Lines 68 to 69 in 913c7a6
NOTE: For this reply, I referred to paths with the non-Flatpak folders. But for implementation we would use whatever comes from install_loc, not hardcoded paths :-)
Beat me to digging around the Lutris codebase :-) Although strangely I can't help but feel a strange sense that I saw that code before...
The blame says that section noting ~/.config/lutris being deprecated was added 2 years ago (lutris/lutris@7af680d). I would've expected Lutris to have some migration path, but that could probably be quite messy, so I guess it's understandable.
It seems like Lutris will use the old location if it is not reinstalled or manually changed. So we have to support both.
Damn, but I think we should be able to do this. I'm pretty sure we've had to access the "main" Lutris folder before (i.e. go from lutris/runners/wine to ../../). There should be some precedent for it in the codebase. We'll just need to be smart about rewiring the code in the relevant places to achieve this. I think LutrisGame#get_game_config is the main way we interface with this?
But we'll need to check the Lutris usages of its install_loc.get(config_dir) and make sure whatever we look for there in the context of Lutris is available there.
I wonder if we should have LutrisGame#get_game_config prefer ~/.config/lutris if it exists. No Lutris install should be using both at the same time. There should not be a case where ~/.config/lutris/games (older Lutris installations, like my Desktop PC) exists and ~/.local/share/lutris/games (newer Lutris installations, like my laptop) exists, even if a user manually creates it, Lutris should still prefer ~/.config/lutris/games.
From this, in my mind, it should be safe to assume that if ~/.config/lutris/games does not exist, that Lutris should be using ~/.local/share/lutris/games. So to support indexing both paths, and to fix the crash described in this issue, we can have LutrisGame#get_game_config do something like this:
- Rename
lutris_config_dirtolutris_game_config_dir. - Instead of setting it to the config folder, set it to
os.path.join(os.path.expanduser(lutris_config_dir), 'games')(i.e./home/gaben/.config/lutris/games).- This
os.path.joinis done in theforloops later on inLutrisGame#get_game_config, that's where I got it from :-)
- This
- If this path doesn't exist, set
lutris_game_config_dirto the path like~/.local/share/lutris/games.- Of course we wouldn't hardcode this, we'd want it to be set to something like
os.path.abspath(os.path.join(install_loc.get('install_dir'), '..', '..'))to go a couple folders up from the install location (from~/.local/share/lutris/runners/wineto~/.local/share/lutris/runners/wine). - I can't remember the exact way we'd implement this, or if it's done elsewhere in the codebase (maybe we do something like this for Heroic?) so I'd need to look around to see either how we'd do this, or if we currently do this and how that precedent was set in the codebase.
- Of course we wouldn't hardcode this, we'd want it to be set to something like
- If the new path we check at
~/.local/share/lutris/gamesdoes not exist, then we should bail out and return an empty dict ({}) like we do ifinstall_loc.get('config_dir')is not set and like we do if the game config file itself was not found. - If either folder is found, loop over
lutris_game_config_dirinstead of ouros.listdir(os.path.join(...))that we currently do, which causes a crash because the config folder is not found.
These changes allow us to default to ~/.config/lutris/games (since Lutris should prefer that if it exists), and if that is not found then we should check for ~/.local/share/lutris/games. If that is also not found, meaning both possible folders for game config yamls are not found, then bail out. This means our os.listdir should never get a path that doesn't exist, thus fixing the crash and allowing us to get game configs from the newer ~/.local/share/lutris/games path.
Whew, I hope that made sense!
Are you using a different version on the laptop or a different distribution (deb, AUR, ...)?
I installed Lutris from the Arch repos on both my Desktop PC and laptop (or AUR, if it's not in the official Arch repos). My PC was using lutris-git for a while but I can't remember when I switched back to stable Lutris.
The reason my laptop may be using ~/.local/share/lutris is that it is significantly newer, I think my Lutris installation is only around 6 months old. Whereas the one on my Desktop PC is from at least December 2019 (the oldest files I can find - woah, that's 5+ years ago).
I can take a look at implementing these changes to fix the crash, which is ultimately going to be fixed by checking for both ~/.config/lutris//games and ~/.local/share/lutris/games, and bailing out before os.listdir(...) if the game config folder path doesn't exist. This has the added benefit of not only fixing the crash, but actually fixing a bug where we would not have found files in ~/.local/share/lutris/games.
Let me know if my explanation of why we would only need to do one or the other makes sense. I think I have it right, since Lutris should only use one and prefer ~/.config/lutris if it exists, so we should be able to do the same and only check for ~/.local/share/lutris/games if it doesn't. But I could be misunderstanding, so correct me if we do need to actually loop over both folders.
