Sprinkle os.path.expanduser all over

Yes, it's ugly and inelegant. But we've got many users with ~ in the paths in their config files.

This plops a bunch of expanduser calls in an effort to make games like that at least work.

It's unlikely this covers everything, but hopefully it will handle the most important cases.
This commit is contained in:
Daniel Johnson 2023-10-25 19:25:12 -04:00
parent 9965b9de60
commit 5c7e2bc945
8 changed files with 38 additions and 20 deletions

View file

@ -306,7 +306,7 @@ class Game(GObject.Object):
"""Return the game's directory; if it is not known this will try to find
it. This can still return an empty string if it can't do that."""
if self.directory:
return self.directory
return os.path.expanduser(self.directory) # expanduser just in case!
if self.runner:
return self.runner.resolve_game_path()
return ""

View file

@ -111,10 +111,13 @@ class dosbox(Runner):
"""Return a guaranteed absolute path"""
if not path:
return ""
path = os.path.expanduser(path)
if os.path.isabs(path):
return path
if self.game_data.get("directory"):
return os.path.join(self.game_data.get("directory"), path)
directory = self.game_data.get("directory")
if directory:
directory = os.path.expanduser(directory)
return os.path.join(directory, path)
return ""
@property

View file

@ -422,7 +422,7 @@ class easyrpg(Runner):
def game_path(self):
game_path = self.game_data.get("directory")
if game_path:
return game_path
return path.expanduser(game_path) # just in case
# Default to the directory of the entry point
entry_point = self.game_config.get(self.entry_point_option)

View file

@ -80,6 +80,7 @@ class linux(Runner):
exe = self.game_config.get("exe")
if not exe:
return None
exe = os.path.expanduser(exe) # just in case!
if os.path.isabs(exe):
return exe
if self.game_path:
@ -130,10 +131,11 @@ class linux(Runner):
else:
command = []
working_dir = launch_config.get("working_dir") or self.working_dir
working_dir = os.path.expanduser(launch_config.get("working_dir") or self.working_dir)
if "exe" in launch_config:
command.append(self.get_relative_exe(launch_config["exe"], working_dir))
config_exe = os.path.expanduser(launch_config["exe"] or '')
command.append(self.get_relative_exe(config_exe, working_dir))
elif len(command) == 0:
raise GameConfigError(_("The runner could not find a command or exe to use for this configuration."))

View file

@ -105,7 +105,7 @@ class Runner: # pylint: disable=too-many-public-methods
"""Return the directory where the game is installed."""
game_path = self.game_data.get("directory")
if game_path:
return game_path
return os.path.expanduser(game_path) # expanduser just in case!
if self.has_explicit_config:
# Default to the directory where the entry point is located.
@ -297,14 +297,17 @@ class Runner: # pylint: disable=too-many-public-methods
exe = launch_config.get("exe")
config_working_dir = self.get_launch_config_working_dir(launch_config)
if exe and config_working_dir and not os.path.isabs(exe):
exe_from_config = self.resolve_config_path(exe, config_working_dir)
exe_from_game = self.resolve_config_path(exe)
if exe:
exe = os.path.expanduser(exe) # just in case!
if os.path.exists(exe_from_game) and not os.path.exists(exe_from_config):
relative = os.path.relpath(exe_from_game, start=config_working_dir)
if not relative.startswith("../"):
return relative
if config_working_dir and not os.path.isabs(exe):
exe_from_config = self.resolve_config_path(exe, config_working_dir)
exe_from_game = self.resolve_config_path(exe)
if os.path.exists(exe_from_game) and not os.path.exists(exe_from_config):
relative = os.path.relpath(exe_from_game, start=config_working_dir)
if not relative.startswith("../"):
return relative
return exe
@ -324,11 +327,14 @@ class Runner: # pylint: disable=too-many-public-methods
def resolve_config_path(self, path, relative_to=None):
"""Interpret a path taken from the launch_config relative to
a working directory, using the game's working_dir if that is omitted.
a working directory, using the game's working_dir if that is omitted,
and expanding the '~' if we get one.
This is provided as a method so the WINE runner can try to convert
Windows-style paths to usable paths.
"""
path = os.path.expanduser(path)
if not os.path.isabs(path):
if not relative_to:
relative_to = self.working_dir

View file

@ -612,6 +612,7 @@ class wine(Runner):
if not _prefix_path and self.game_config.get("exe"):
# Find prefix from game if we have one
_prefix_path = find_prefix(self.game_exe)
_prefix_path = os.path.expanduser(_prefix_path) # just in case!
return _prefix_path
@property
@ -622,6 +623,7 @@ class wine(Runner):
if not exe:
logger.error("The game doesn't have an executable")
return None
exe = os.path.expanduser(exe) # just in case!
if os.path.isabs(exe):
return system.fix_path_case(exe)
if not self.game_path:
@ -634,7 +636,7 @@ class wine(Runner):
"""Return the working directory to use when running the game."""
_working_dir = self._working_dir or self.game_config.get("working_dir")
if _working_dir:
return _working_dir
return os.path.expanduser(_working_dir)
if self.game_exe:
game_dir = os.path.dirname(self.game_exe)
if os.path.isdir(game_dir):

View file

@ -121,9 +121,13 @@ def get_path_from_config(game):
path = game_config[key]
if key == "files":
path = path[0]
if not path.startswith("/"):
path = os.path.join(game.directory, path)
return path
if path:
path = os.path.expanduser(path)
if not path.startswith("/"):
path = os.path.join(game.directory, path)
return path
logger.warning("No path found in %s", game.config)
return ""
@ -210,4 +214,4 @@ def get_missing_game_ids():
def is_game_missing(game_id):
cache = get_path_cache()
path = cache.get(str(game_id))
return path and not os.path.exists(path)
return path and not os.path.exists(os.path.expanduser(path))

View file

@ -28,6 +28,7 @@ def find_prefix(path):
if not dir_path:
logger.info("No path given, unable to guess prefix location")
return
dir_path = os.path.expanduser(dir_path)
while dir_path != "/" and dir_path:
dir_path = os.path.dirname(dir_path)
if is_prefix(dir_path):