Skip to content

Commit

Permalink
util: Check if Steam configuration files exist before marking as avai…
Browse files Browse the repository at this point in the history
…lable (#356)

* util: Check if Steam configuration files exist before marking as available

* constants: Move valid Steam install check to is_valid_launcher_installation

* constants: Use os.path.join for building Steam install location paths

* constants: Don't use os.path.join when building Steam POSSIBLE_INSTALL_LOCATIONS

Fixes a strange recusion depth crash.

* comment cleanup

* comment cleanup 2 electric boogaloo
  • Loading branch information
sonic2kk committed Mar 24, 2024
1 parent 6b87cab commit 7ef58ff
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 16 deletions.
36 changes: 24 additions & 12 deletions pupgui2/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,32 @@
TEMP_DIR = os.path.join(os.getenv('XDG_CACHE_HOME'), 'tmp', 'pupgui2.a70200/') if os.path.exists(os.getenv('XDG_CACHE_HOME', '')) else '/tmp/pupgui2.a70200/'
HOME_DIR = os.path.expanduser('~')

# support different Steam root directories
# valid install dir should have config.vdf and libraryfolders.vdf, to ensure it is not an unused folder with correct directory structure
_POSSIBLE_STEAM_ROOTS = ['~/.local/share/Steam', '~/.steam/root', '~/.steam/steam', '~/.steam/debian-installation']
_STEAM_ROOT = _POSSIBLE_STEAM_ROOTS[0]
for steam_root in _POSSIBLE_STEAM_ROOTS:
ct_dir = os.path.join(os.path.expanduser(steam_root), 'config')
config_vdf = os.path.join(ct_dir, 'config.vdf')
libraryfolders_vdf = os.path.join(ct_dir, 'libraryfolders.vdf')
if os.path.exists(config_vdf) and os.path.exists(libraryfolders_vdf):
_STEAM_ROOT = steam_root
break
# support different Steam root directories, building paths relative to HOME_DIR (i.e. /home/gaben/.local/share/Steam)
# Use os.path.realpath to expand all _STEAM_ROOT paths
_POSSIBLE_STEAM_ROOTS = [
os.path.realpath(os.path.join(HOME_DIR, _STEAM_ROOT)) for _STEAM_ROOT in ['.local/share/Steam', '.steam/root', '.steam/steam', '.steam/debian-installation']
]

# Remove duplicate paths while preserving order, as os.path.realpath may expand some symlinks to the real Steam root
_POSSIBLE_STEAM_ROOTS = list(dict.fromkeys(_POSSIBLE_STEAM_ROOTS))

# Steam can be installled in any of the locations at '_POSSIBLE_STEAM_ROOTS' - usually only one, and the others (if they exist) are typically symlinks,
# i.e. '~/.steam/root' is usually a symlink to '~/.local/share/Steam'
# These paths may still not be valid installations however, as they could be leftother paths from an old Steam installation without the data files we need ('config.vdf' and 'libraryfolders.vdf')
# We catch this later on in util#is_valid_launcher_installation though
POSSIBLE_INSTALL_LOCATIONS = [
{'install_dir': f'{_STEAM_ROOT}/compatibilitytools.d/', 'display_name': 'Steam', 'launcher': 'steam', 'type': 'native', 'icon': 'steam', 'vdf_dir': f'{_STEAM_ROOT}/config'},
{
'install_dir': f'{_STEAM_ROOT}/compatibilitytools.d/',
'display_name': 'Steam',
'launcher': 'steam',
'type': 'native',
'icon': 'steam',
'vdf_dir': f'{_STEAM_ROOT}/config'
} for _STEAM_ROOT in _POSSIBLE_STEAM_ROOTS if os.path.exists(_STEAM_ROOT)
]

# Possible install locations for all other launchers, ensuring Steam paths are at the top of the list
POSSIBLE_INSTALL_LOCATIONS += [
{'install_dir': '~/.var/app/com.valvesoftware.Steam/data/Steam/compatibilitytools.d/', 'display_name': 'Steam Flatpak', 'launcher': 'steam', 'type': 'flatpak', 'icon': 'steam', 'vdf_dir': '~/.var/app/com.valvesoftware.Steam/.local/share/Steam/config'},
{'install_dir': '~/snap/steam/common/.steam/root/compatibilitytools.d/', 'display_name': 'Steam Snap', 'launcher': 'steam', 'type': 'snap', 'icon': 'steam', 'vdf_dir': '~/snap/steam/common/.steam/root/config'},
{'install_dir': '~/.local/share/lutris/runners/wine/', 'display_name': 'Lutris', 'launcher': 'lutris', 'type': 'native', 'icon': 'lutris', 'config_dir': '~/.config/lutris'},
Expand Down
19 changes: 18 additions & 1 deletion pupgui2/steamutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -791,4 +791,21 @@ def determine_most_recent_steam_user(steam_users: List[SteamUser]) -> SteamUser:
return steam_users[0]

print('Warning: No Steam users found. Returning None')
return None
return None


def is_valid_steam_install(steam_path) -> bool:

"""
Return whether required Steam data files actually exist to determine if 'steam_path' is a valid Steam installation.
Return Type: bool
"""

ct_dir = os.path.join(os.path.expanduser(steam_path), 'config')

config_vdf = os.path.join(ct_dir, 'config.vdf')
libraryfolders_vdf = os.path.join(ct_dir, 'libraryfolders.vdf')

is_valid_steam_install = os.path.exists(config_vdf) and os.path.exists(libraryfolders_vdf)

return is_valid_steam_install
26 changes: 23 additions & 3 deletions pupgui2/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from pupgui2.constants import AWACY_GAME_LIST_URL, LOCAL_AWACY_GAME_LIST
from pupgui2.constants import GITHUB_API, GITLAB_API, GITLAB_API_RATELIMIT_TEXT
from pupgui2.datastructures import BasicCompatTool, CTType, Launcher, SteamApp, LutrisGame, HeroicGame
from pupgui2.steamutil import remove_steamtinkerlaunch
from pupgui2.steamutil import remove_steamtinkerlaunch, is_valid_steam_install


def create_msgbox(
Expand Down Expand Up @@ -196,6 +196,25 @@ def create_compatibilitytools_folder() -> None:
print(f'Error trying to create compatibility tools folder {str(install_dir)}: {str(e)}')


def is_valid_launcher_installation(loc) -> bool:

"""
Check whether a launcher installation is actually valid based on per-launcher criteria
Return Type: bool
"""

install_dir = os.path.expanduser(loc['install_dir'])

# Right now we only check to make sure regular Steam (not Flatpak or Snap) has config.vdf and libraryfolders.vdf
# because Steam can leave behind its directory structure when uninstalled, but not these files.
#
# In future we could expand this to other Steam flavours and other launchers.
if loc['display_name'] == 'Steam': # This seems to get called many times, why?
return is_valid_steam_install(os.path.realpath(os.path.join(install_dir, '..')))

return os.path.exists(install_dir) # Default to path check for all other launchers


def available_install_directories() -> List[str]:
"""
List available install directories
Expand All @@ -204,10 +223,11 @@ def available_install_directories() -> List[str]:
available_dirs = []
for loc in POSSIBLE_INSTALL_LOCATIONS:
install_dir = os.path.expanduser(loc['install_dir'])
if os.path.exists(install_dir):
# only add unique paths to available_dirs
if is_valid_launcher_installation(loc) and not install_dir in available_dirs:
available_dirs.append(install_dir)
install_dir = config_custom_install_location().get('install_dir')
if install_dir and os.path.exists(install_dir):
if install_dir and os.path.exists(install_dir) and not install_dir in available_dirs:
available_dirs.append(install_dir)
return available_dirs

Expand Down

0 comments on commit 7ef58ff

Please sign in to comment.