From bdd53fb8f8c4acd61e053a522c8b07de5ef18eee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathis=20Dr=C3=B6ge?= Date: Tue, 7 Feb 2023 00:07:10 +0100 Subject: [PATCH] [cli] Search for game executable case-insensitively --- legendary/cli.py | 4 +++- legendary/lfs/wine_helpers.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/legendary/cli.py b/legendary/cli.py index 075d7fa..83e06be 100644 --- a/legendary/cli.py +++ b/legendary/cli.py @@ -28,7 +28,7 @@ from legendary.utils.env import is_windows_mac_or_pyi from legendary.lfs.eos import add_registry_entries, query_registry_entries, remove_registry_entries from legendary.lfs.utils import validate_files, clean_filename from legendary.utils.selective_dl import get_sdl_appname -from legendary.lfs.wine_helpers import read_registry, get_shell_folders +from legendary.lfs.wine_helpers import read_registry, get_shell_folders, case_insensitive_file_search # todo custom formatter for cli logger (clean info, highlighted error/warning) logging.basicConfig( @@ -1297,6 +1297,8 @@ class LegendaryCLI: # get everything needed for import from core, then run additional checks. manifest, igame = self.core.import_game(game, args.app_path, platform=args.platform) exe_path = os.path.join(args.app_path, manifest.meta.launch_exe.lstrip('/')) + if os.name != 'nt': + exe_path = case_insensitive_file_search(exe_path) # check if most files at least exist or if user might have specified the wrong directory total = len(manifest.file_manifest_list.elements) found = sum(os.path.exists(os.path.join(args.app_path, f.filename)) diff --git a/legendary/lfs/wine_helpers.py b/legendary/lfs/wine_helpers.py index 1fd4fc3..e884a90 100644 --- a/legendary/lfs/wine_helpers.py +++ b/legendary/lfs/wine_helpers.py @@ -20,6 +20,37 @@ def get_shell_folders(registry, wine_pfx): return folders +def case_insensitive_file_search(path: str) -> str: + """ + Similar to case_insensitive_path_search: Finds a file case-insensitively + Note that this *does* work on Windows, although it's rather pointless + """ + path_parts = os.path.normpath(path).split(os.sep) + # If path_parts[0] is empty, we're on Unix and thus start searching at / + if not path_parts[0]: + path_parts[0] = '/' + + computed_path = path_parts[0] + for part in path_parts[1:]: + # If the computed directory does not exist, add all remaining parts as-is to at least return a valid path + # at the end + if not os.path.exists(computed_path): + computed_path = os.path.join(computed_path, part) + continue + + # First try to find an exact match + actual_file_or_dirname = part if os.path.exists(os.path.join(computed_path, part)) else None + + # If there is no case-sensitive match, find a case-insensitive one + if not actual_file_or_dirname: + actual_file_or_dirname = next(( + x for x in os.listdir(computed_path) + if x.lower() == part.lower() + ), part) + computed_path = os.path.join(computed_path, actual_file_or_dirname) + return computed_path + + def case_insensitive_path_search(path): """ Attempts to find a path case-insensitively