Sync from development - prepare for v0.3.0

This commit is contained in:
Omni
2026-02-07 18:26:54 +00:00
parent b55e1cf768
commit 12294d3186
169 changed files with 31749 additions and 33649 deletions

View File

@@ -0,0 +1,106 @@
"""
Install Wabbajack Application Command
Provides CLI interface for automated Wabbajack installation
Uses backend service for complete workflow orchestration
"""
import logging
from pathlib import Path
from jackify.backend.services.wabbajack_installer_service import WabbajackInstallerService
from jackify.shared.colors import COLOR_PROMPT, COLOR_RESET, COLOR_INFO, COLOR_SUCCESS, COLOR_ERROR
class InstallWabbajackCommand:
"""CLI command for installing Wabbajack application"""
def __init__(self):
self.logger = logging.getLogger(__name__)
def run(self):
"""Execute Wabbajack installation workflow using backend service"""
print(f"\n{COLOR_INFO}=== Install Wabbajack Application ==={COLOR_RESET}\n")
print("This will download and configure Wabbajack.exe via Proton.")
print("Wabbajack will be added to your Steam library as a non-Steam game.\n")
# Prompt for installation directory
default_dir = str(Path.home() / "Games" / "Wabbajack")
install_dir_input = input(
f"{COLOR_PROMPT}Installation directory [{default_dir}]: {COLOR_RESET}"
).strip()
install_dir = Path(install_dir_input) if install_dir_input else Path(default_dir)
# Prompt for shortcut name
shortcut_name = "Wabbajack"
shortcut_input = input(
f"{COLOR_PROMPT}Shortcut name [{shortcut_name}]: {COLOR_RESET}"
).strip()
if shortcut_input:
shortcut_name = shortcut_input
# Confirm installation with Steam restart warning
print(f"\n{COLOR_INFO}Installation directory: {install_dir}{COLOR_RESET}")
print(f"{COLOR_INFO}Shortcut name: {shortcut_name}{COLOR_RESET}")
print(f"\n{COLOR_PROMPT}{'='*60}{COLOR_RESET}")
print(f"{COLOR_PROMPT}Important: Steam will be restarted during installation.{COLOR_RESET}")
print(f"{COLOR_PROMPT}Please do not manually start or close Steam until installation is complete.{COLOR_RESET}")
print(f"{COLOR_PROMPT}{'='*60}{COLOR_RESET}")
confirm = input(f"\n{COLOR_PROMPT}Proceed with installation? (Y/n): {COLOR_RESET}").strip().lower()
if confirm == 'n':
print("Installation cancelled.")
return
# Execute installation using backend service
print(f"\n{COLOR_INFO}Starting Wabbajack installation...{COLOR_RESET}\n")
service = WabbajackInstallerService()
def progress_callback(message: str, percentage: int):
step_num = int((percentage / 100) * 12) if percentage < 100 else 12
print(f"{COLOR_INFO}[{step_num}/12] {message}{COLOR_RESET}")
def log_callback(message: str):
if "ERROR" in message or "WARNING" in message or "Failed" in message:
print(f"{COLOR_ERROR}{message}{COLOR_RESET}")
elif "successfully" in message.lower() or "created" in message.lower() or "installed" in message.lower():
print(f"{COLOR_SUCCESS}{message}{COLOR_RESET}")
else:
print(f"{COLOR_INFO}{message}{COLOR_RESET}")
success, app_id, launch_options, gog_count, time_taken, error_msg = service.install_wabbajack(
install_folder=install_dir,
shortcut_name=shortcut_name,
enable_gog=True,
progress_callback=progress_callback,
log_callback=log_callback
)
if success:
print(f"\n{COLOR_SUCCESS}{'='*60}{COLOR_RESET}")
print(f"{COLOR_SUCCESS}Wabbajack installation complete!{COLOR_RESET}")
print(f"{COLOR_SUCCESS}{'='*60}{COLOR_RESET}\n")
print(f"{COLOR_INFO}Installation directory: {install_dir}{COLOR_RESET}")
print(f"{COLOR_INFO}Steam AppID: {app_id}{COLOR_RESET}")
if time_taken:
print(f"{COLOR_INFO}Time taken: {time_taken}{COLOR_RESET}")
# Show launch options note (matches GUI)
if launch_options and "STEAM_COMPAT_MOUNTS" in launch_options:
print(f"\n{COLOR_INFO}Note: To access other drives, add paths to launch options (Steam → Properties).{COLOR_RESET}")
print(f"{COLOR_INFO}Append with colons: STEAM_COMPAT_MOUNTS=\"/existing:/new/path\" %command%{COLOR_RESET}")
elif not launch_options:
print(f"\n{COLOR_INFO}Note: To access other drives, add to launch options (Steam → Properties):{COLOR_RESET}")
print(f"{COLOR_INFO}STEAM_COMPAT_MOUNTS=\"/path/to/directory\" %command%{COLOR_RESET}")
print(f"\n{COLOR_INFO}Next steps:{COLOR_RESET}")
print(f" 1. Find '{shortcut_name}' in your Steam library")
print(f" 2. Launch Wabbajack from Steam")
else:
print(f"\n{COLOR_ERROR}Installation failed: {error_msg}{COLOR_RESET}")
print(f"{COLOR_INFO}Check logs for details{COLOR_RESET}")
input(f"\n{COLOR_PROMPT}Press Enter to continue...{COLOR_RESET}")

View File

@@ -423,8 +423,10 @@ class JackifyCLI:
elif command == "configure-modlist":
return self.commands['configure_modlist'].execute(args)
elif command == "install-wabbajack":
# Legacy functionality - TODO: extract to command handler
return self._handle_legacy_install_wabbajack()
print("Wabbajack installation is available through the interactive menu:")
print(" Run: jackify --cli")
print(" Then select: Additional Tasks > Install Wabbajack")
return 0
elif command == "install-mo2":
print("MO2 installation not yet implemented")
print("This functionality is coming soon!")
@@ -493,12 +495,6 @@ class JackifyCLI:
logger.error(f"Steam restart failed with exception: {e}")
return 1
def _handle_legacy_install_wabbajack(self):
"""Handle install-wabbajack command (legacy functionality)"""
print("Install Wabbajack functionality not yet migrated to new structure")
return 1
return 1
def _handle_legacy_recovery(self, args):
"""Handle recovery command (legacy functionality)"""
@@ -513,7 +509,10 @@ class JackifyCLI:
# LEGACY BRIDGE: Methods that menu handlers expect to find on cli_instance
def _cmd_install_wabbajack(self, args):
"""LEGACY BRIDGE: Install Wabbajack application"""
return self._handle_legacy_install_wabbajack()
from jackify.frontends.cli.commands.install_wabbajack import InstallWabbajackCommand
command_instance = InstallWabbajackCommand()
command_instance.run()
return 0
def main():
@@ -522,6 +521,6 @@ def main():
if __name__ == "__main__":
# This should not be called directly - use __main__.py instead
# Do not call directly -- use __main__.py
print("Please use: python -m jackify.frontends.cli")
sys.exit(1)

View File

@@ -35,7 +35,8 @@ class AdditionalMenuHandler:
print(f" {COLOR_ACTION}→ Authorize with Nexus using OAuth or manage API key{COLOR_RESET}")
print(f"{COLOR_SELECTION}2.{COLOR_RESET} Tale of Two Wastelands (TTW) Installation")
print(f" {COLOR_ACTION}→ Install TTW using TTW_Linux_Installer{COLOR_RESET}")
print(f"{COLOR_SELECTION}3.{COLOR_RESET} Coming Soon...")
print(f"{COLOR_SELECTION}3.{COLOR_RESET} Install Wabbajack Application")
print(f" {COLOR_ACTION}→ Downloads and configures the Wabbajack app itself (via Proton){COLOR_RESET}")
print(f"{COLOR_SELECTION}0.{COLOR_RESET} Return to Main Menu")
selection = input(f"\n{COLOR_PROMPT}Enter your selection (0-3): {COLOR_RESET}").strip()
@@ -46,8 +47,7 @@ class AdditionalMenuHandler:
elif selection == "2":
self._execute_ttw_install(cli_instance)
elif selection == "3":
print(f"\n{COLOR_INFO}More features coming soon!{COLOR_RESET}")
input("\nPress Enter to return to menu...")
self._execute_install_wabbajack(cli_instance)
elif selection == "0":
break
else:
@@ -65,7 +65,7 @@ class AdditionalMenuHandler:
def _execute_legacy_recovery_menu(self, cli_instance):
"""LEGACY BRIDGE: Execute recovery menu"""
# This will be handled by the RecoveryMenuHandler
# Handled by RecoveryMenuHandler
from .recovery_menu import RecoveryMenuHandler
recovery_handler = RecoveryMenuHandler()
@@ -107,9 +107,25 @@ class AdditionalMenuHandler:
input("Press Enter to return to menu...")
return
# Prompt for TTW .mpi file
# Prompt for TTW .mpi file with tab completion
try:
import readline
from ....backend.handlers.completers import path_completer
READLINE_AVAILABLE = True
except ImportError:
READLINE_AVAILABLE = False
print(f"\n{COLOR_PROMPT}TTW Installer File (.mpi){COLOR_RESET}")
mpi_path = input(f"{COLOR_PROMPT}Path to TTW .mpi file: {COLOR_RESET}").strip()
if READLINE_AVAILABLE:
readline.set_completer_delims(' \t\n;')
readline.set_completer(path_completer)
readline.parse_and_bind("tab: complete")
try:
mpi_path = input(f"{COLOR_PROMPT}Path to TTW .mpi file: {COLOR_RESET}").strip()
finally:
if READLINE_AVAILABLE:
readline.set_completer(None)
if not mpi_path:
print(f"{COLOR_WARNING}No .mpi file specified. Cancelling.{COLOR_RESET}")
input("Press Enter to return to menu...")
@@ -121,10 +137,19 @@ class AdditionalMenuHandler:
input("Press Enter to return to menu...")
return
# Prompt for output directory
# Prompt for output directory with tab completion
print(f"\n{COLOR_PROMPT}TTW Installation Directory{COLOR_RESET}")
default_output = Path.home() / "ModdedGames" / "TTW"
output_path = input(f"{COLOR_PROMPT}TTW install directory (Enter for default: {default_output}): {COLOR_RESET}").strip()
if READLINE_AVAILABLE:
readline.set_completer_delims(' \t\n;')
readline.set_completer(path_completer)
readline.parse_and_bind("tab: complete")
try:
output_path = input(f"{COLOR_PROMPT}TTW install directory (Enter for default: {default_output}): {COLOR_RESET}").strip()
finally:
if READLINE_AVAILABLE:
readline.set_completer(None)
if not output_path:
output_path = default_output
else:
@@ -280,3 +305,12 @@ class AdditionalMenuHandler:
else:
print(f"\n{COLOR_ERROR}Invalid selection.{COLOR_RESET}")
time.sleep(1)
def _execute_install_wabbajack(self, cli_instance):
"""Execute Wabbajack application installation"""
from jackify.frontends.cli.commands.install_wabbajack import InstallWabbajackCommand
command = InstallWabbajackCommand()
if self.logger:
self.logger.debug("AdditionalMenuHandler: Executing Install Wabbajack command")
command.run()

View File

@@ -43,7 +43,7 @@ class MainMenuHandler:
print(f"{COLOR_SELECTION}1.{COLOR_RESET} Modlist Tasks")
print(f" {COLOR_ACTION}→ Install & Configure Modlists{COLOR_RESET}")
print(f"{COLOR_SELECTION}2.{COLOR_RESET} Additional Tasks & Tools")
print(f" {COLOR_ACTION}TTW automation, Wabbajack via Wine, MO2, NXM Handling, Recovery{COLOR_RESET}")
print(f" {COLOR_ACTION}Nexus OAuth, TTW Installation, Install Wabbajack{COLOR_RESET}")
print(f"{COLOR_SELECTION}0.{COLOR_RESET} Exit Jackify")
choice = input(f"\n{COLOR_PROMPT}Enter your selection (0-2): {COLOR_RESET}").strip()

View File

@@ -37,9 +37,6 @@ class WabbajackMenuHandler:
print(f" {COLOR_ACTION}→ Modlist already downloaded? Configure and add to Steam{COLOR_RESET}")
print(f"{COLOR_SELECTION}3.{COLOR_RESET} Configure Existing Modlist (In Steam)")
print(f" {COLOR_ACTION}→ Modlist already in Steam? Re-configure it here{COLOR_RESET}")
# HIDDEN FOR FIRST RELEASE - UNCOMMENT WHEN READY
# print(f"{COLOR_SELECTION}4.{COLOR_RESET} Install Wabbajack Application")
# print(f" {COLOR_ACTION}→ Downloads and configures the Wabbajack app itself (via WINE){COLOR_RESET}")
print(f"{COLOR_SELECTION}0.{COLOR_RESET} Return to Main Menu")
selection = input(f"\n{COLOR_PROMPT}Enter your selection (0-3): {COLOR_RESET}").strip()
@@ -52,9 +49,6 @@ class WabbajackMenuHandler:
self._execute_legacy_configure_new_modlist(cli_instance)
elif selection == "3":
self._execute_legacy_configure_existing_modlist(cli_instance)
# HIDDEN FOR FIRST RELEASE - UNCOMMENT WHEN READY
# elif selection == "4":
# self._execute_legacy_install_wabbajack(cli_instance)
elif selection == "0":
break
else: