[cli] Add support for launching with CrossOver on macOS

This commit is contained in:
derrod 2021-12-29 12:56:00 +01:00
parent f0f4b545f5
commit a0da79bc2c

View file

@ -21,7 +21,8 @@ from legendary import __version__, __codename__
from legendary.core import LegendaryCore from legendary.core import LegendaryCore
from legendary.models.exceptions import InvalidCredentialsError from legendary.models.exceptions import InvalidCredentialsError
from legendary.models.game import SaveGameStatus, VerifyResult, Game from legendary.models.game import SaveGameStatus, VerifyResult, Game
from legendary.utils.cli import get_boolean_choice, sdl_prompt, strtobool from legendary.utils.cli import get_boolean_choice, get_int_choice, sdl_prompt, strtobool
from legendary.utils.crossover import mac_find_crossover_apps, mac_get_crossover_bottles, mac_is_valid_bottle
from legendary.utils.custom_parser import AliasedSubParsersAction from legendary.utils.custom_parser import AliasedSubParsersAction
from legendary.utils.env import is_windows_mac_or_pyi from legendary.utils.env import is_windows_mac_or_pyi
from legendary.utils.eos import add_registry_entries, query_registry_entries, remove_registry_entries from legendary.utils.eos import add_registry_entries, query_registry_entries, remove_registry_entries
@ -568,6 +569,72 @@ class LegendaryCLI:
self.core.lgd.config.remove_section(app_name) self.core.lgd.config.remove_section(app_name)
return return
# Interactive CrossOver setup
if args.crossover and sys_platform == 'darwin':
logger.info('Looking for CrossOver installs...')
apps = mac_find_crossover_apps()
if len(apps) > 1:
print('Found multiple CrossOver installs, please select one:')
for i, (ver, path) in enumerate(apps, start=1):
print(f'\t{i:2d}. {ver} ({path})')
choice = get_int_choice(f'Select a CrossOver install', 1, 1, len(apps))
if choice is None:
logger.error(f'No valid choice made, aborting.')
exit(1)
cx_version, args.crossover_app = apps[choice-1]
elif len(apps) == 1:
cx_version, args.crossover_app = apps[0]
logger.info(f'Found CrossOver {cx_version} at {args.crossover_app}')
else:
logger.error(f'No CrossOver installs found, see https://legendary.gl/crossover-setup '
f'for setup instructions')
return
bottles = mac_get_crossover_bottles()
if 'Legendary' not in bottles:
logger.info('It is recommended to set up a bottle specifically for Legendary, see '
'https://legendary.gl/crossover-setup for setup instructions.')
if len(bottles) > 1:
print('Found multiple CrossOver bottles, please select one:')
if 'Legendary' in bottles:
default_choice = bottles.index('Legendary') + 1
elif 'Heroic' in bottles:
default_choice = bottles.index('Heroic') + 1
elif 'default' in bottles:
default_choice = bottles.index('default') + 1
else:
default_choice = 1
for i, bottle in enumerate(bottles, start=1):
if i == default_choice:
print(f'\t{i:2d}. {bottle} (default)')
else:
print(f'\t{i:2d}. {bottle}')
choice = get_int_choice(f'Select a bottle', default_choice, 1, len(bottles))
if choice is None:
logger.error(f'No valid choice made, aborting.')
exit(1)
args.crossover_bottle = bottles[choice-1]
elif len(bottles) == 1:
logger.info(f'Found only one bottle: {bottles[0]}')
args.crossover_bottle = bottles[0]
else:
logger.error('No Bottles found, see https://legendary.gl/crossover-setup for setup instructions.')
return
logger.info(f'Current launch configuration: '
f'--crossover-bottle "{args.crossover_bottle}" '
f'--crossover-app "{args.crossover_app}" ')
y_n = get_boolean_choice('Would you like to save these choices for this application?')
if y_n:
self.core.lgd.config.set(app_name, 'crossover_app', args.crossover_app)
self.core.lgd.config.set(app_name, 'crossover_bottle', args.crossover_bottle)
# override with config value # override with config value
args.offline = self.core.is_offline_game(app_name) or args.offline args.offline = self.core.is_offline_game(app_name) or args.offline
if not args.offline: if not args.offline:
@ -593,7 +660,9 @@ class LegendaryCLI:
wine_bin=args.wine_bin, wine_pfx=args.wine_pfx, wine_bin=args.wine_bin, wine_pfx=args.wine_pfx,
language=args.language, wrapper=args.wrapper, language=args.language, wrapper=args.wrapper,
disable_wine=args.no_wine, disable_wine=args.no_wine,
executable_override=args.executable_override) executable_override=args.executable_override,
crossover_app=args.crossover_app,
crossover_bottle=args.crossover_bottle)
if args.set_defaults: if args.set_defaults:
self.core.lgd.config[app_name] = dict() self.core.lgd.config[app_name] = dict()
@ -615,6 +684,11 @@ class LegendaryCLI:
self.core.lgd.config[app_name]['language'] = args.language self.core.lgd.config[app_name]['language'] = args.language
if args.wrapper: if args.wrapper:
self.core.lgd.config[app_name]['wrapper'] = args.wrapper self.core.lgd.config[app_name]['wrapper'] = args.wrapper
if sys_platform == 'darwin':
if args.crossover_app:
self.core.lgd.config[app_name]['crossover_app'] = args.crossover_app
if args.crossover_bottle:
self.core.lgd.config[app_name]['crossover_bottle'] = args.crossover_bottle
if args.json: if args.json:
return self._print_json(vars(params), args.pretty_json) return self._print_json(vars(params), args.pretty_json)
@ -629,6 +703,19 @@ class LegendaryCLI:
full_env = os.environ.copy() full_env = os.environ.copy()
full_env.update(params.environment) full_env.update(params.environment)
if 'CX_BOTTLE' in full_env:
# if using crossover, unset WINEPREFIX
full_env.pop('WINEPREFIX', None)
# check that bottle is valid, show error otherwise
bottle_name = full_env["CX_BOTTLE"].strip()
if not mac_is_valid_bottle(bottle_name):
if bottle_name == 'Legendary':
logger.error('Attempted to use default CrossOver bottle ("Legendary"), but it does not exist, '
'see https://legendary.gl/crossover-setup for setup instructions.')
else:
logger.error(f'Specified CrossOver bottle {bottle_name} does not exist, cannot launch.')
exit(1)
if args.dry_run: if args.dry_run:
logger.info(f'Not Launching {app_name} (dry run)') logger.info(f'Not Launching {app_name} (dry run)')
logger.info(f'Launch parameters: {shlex.join(full_params)}') logger.info(f'Launch parameters: {shlex.join(full_params)}')
@ -2232,6 +2319,21 @@ def main():
launch_parser.add_argument('--no-wine', dest='no_wine', help=argparse.SUPPRESS, launch_parser.add_argument('--no-wine', dest='no_wine', help=argparse.SUPPRESS,
action='store_true', default=True) action='store_true', default=True)
if sys_platform == 'darwin':
launch_parser.add_argument('--crossover', dest='crossover', action='store_true',
help='Interactively configure CrossOver for this application.')
launch_parser.add_argument('--crossover-app', dest='crossover_app', action='store',
help='Specify which App to use for CrossOver (e.g. "/Applications/CrossOver.app")')
launch_parser.add_argument('--crossover-bottle', dest='crossover_bottle', action='store',
help='Specify which bottle to use for CrossOver')
else:
launch_parser.add_argument('--crossover', dest='crossover', action='store_true',
help=argparse.SUPPRESS)
launch_parser.add_argument('--crossover-app', dest='crossover_app', action='store',
help=argparse.SUPPRESS)
launch_parser.add_argument('--crossover-bottle', dest='crossover_bottle', action='store',
help=argparse.SUPPRESS)
list_parser.add_argument('--platform', dest='platform', action='store', metavar='<Platform>', type=str, list_parser.add_argument('--platform', dest='platform', action='store', metavar='<Platform>', type=str,
help='Platform to fetch game list for (default: Mac on macOS, otherwise Windows)') help='Platform to fetch game list for (default: Mac on macOS, otherwise Windows)')
list_parser.add_argument('--include-ue', dest='include_ue', action='store_true', list_parser.add_argument('--include-ue', dest='include_ue', action='store_true',