mirror of
https://github.com/Omni-guides/Jackify.git
synced 2026-08-14 02:33:42 +02:00
Release v0.6.0
This commit is contained in:
+13
-13
@@ -136,7 +136,7 @@ def _logs_dir_display() -> str:
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Factory functions for known failure modes.
|
||||
# No GUI imports allowed here — backend code raises these directly.
|
||||
# No GUI imports allowed here - backend code raises these directly.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def steam_still_running() -> SteamError:
|
||||
@@ -280,8 +280,8 @@ def ttw_install_failed(detail: str) -> TTWError:
|
||||
solutions=[
|
||||
"Confirm vanilla Fallout 3 and Fallout New Vegas are both installed and launch correctly.",
|
||||
"If either game was previously modded, restore a clean vanilla install before retrying TTW.",
|
||||
"Ensure TTW_Linux_Installer is installed — use 'Install TTW Installer' in Additional Tasks.",
|
||||
"Check available disk space — TTW requires ~15GB free.",
|
||||
"Ensure TTW_Linux_Installer is installed - use 'Install TTW Installer' in Additional Tasks.",
|
||||
"Check available disk space - TTW requires ~15GB free.",
|
||||
"Verify the TTW .mpi file is not corrupted (try re-downloading it).",
|
||||
f"Check Jackify logs ({_logs_dir_display()}) and TTW_Install_workflow.log for the specific failure.",
|
||||
f"If this still fails, open a GitHub issue and include logs from {_logs_dir_display()}.",
|
||||
@@ -296,10 +296,10 @@ def wabbajack_install_failed(detail: str, context: Optional[dict] = None) -> Ins
|
||||
message="The modlist installation did not complete successfully.",
|
||||
suggestion=f"Check the console output and Jackify logs ({_logs_dir_display()}) for the failure reason.",
|
||||
solutions=[
|
||||
"Ensure you are logged in to Nexus Mods — check Settings > OAuth.",
|
||||
"Ensure you are logged in to Nexus Mods - check Settings > OAuth.",
|
||||
"Confirm your Nexus account has Premium access for automated downloads.",
|
||||
"Check available disk space on both the install and download drives.",
|
||||
"Re-run the install — Wabbajack resumes from where it stopped.",
|
||||
"Re-run the install - Wabbajack resumes from where it stopped.",
|
||||
"If a specific file failed repeatedly, try downloading it manually from Nexus.",
|
||||
"Check Modlist_Install_workflow.log for the specific file that failed.",
|
||||
"If the same failure repeats with no clear workaround, open a GitHub issue with logs.",
|
||||
@@ -333,7 +333,7 @@ def install_dir_create_failed(path: str, detail: str) -> InstallError:
|
||||
"Confirm the target drive is mounted and writable.",
|
||||
"Check available disk space: df -h",
|
||||
"Try creating the folder manually first, then retry.",
|
||||
"On Steam Deck, avoid paths under /usr or /var — use /home/deck or an SD card.",
|
||||
"On Steam Deck, avoid paths under /usr or /var - use /home/deck or an SD card.",
|
||||
],
|
||||
technical=format_technical_context(detail=detail, context={"path": path}),
|
||||
)
|
||||
@@ -368,7 +368,7 @@ def cc_content_missing(filename: str = "") -> InstallError:
|
||||
"From the Skyrim main menu, go into Creations and select 'Download All'.",
|
||||
"If specific files are still missing, search for and download them individually from the Creations menu.",
|
||||
"If problems persist, uninstall and reinstall Skyrim, then launch once to trigger the AE download.",
|
||||
"Note: Skyrim AE via Steam Family Sharing does not transfer DLC content — you must own AE directly.",
|
||||
"Note: Skyrim AE via Steam Family Sharing does not transfer DLC content - you must own AE directly.",
|
||||
],
|
||||
technical=format_technical_context(detail=detail) if detail else None,
|
||||
)
|
||||
@@ -386,9 +386,9 @@ def creation_kit_missing() -> InstallError:
|
||||
"In Steam, search for 'Skyrim Special Edition: Creation Kit' and install it.",
|
||||
"Right-click it in Steam > Properties > Compatibility and set a Proton version.",
|
||||
"Click Play to launch the Creation Kit.",
|
||||
"When asked whether to unzip Scripts.zip, select NO — unzipping will cause the CK to crash.",
|
||||
"When asked whether to unzip Scripts.zip, select NO - unzipping will cause the CK to crash.",
|
||||
"Once the Creation Kit opens successfully, close it.",
|
||||
"Re-run the modlist install in Jackify — the required files will now be in place.",
|
||||
"Re-run the modlist install in Jackify - the required files will now be in place.",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -399,7 +399,7 @@ def mo2_setup_failed(detail: str) -> InstallError:
|
||||
message="Jackify could not complete the Mod Organizer 2 setup.",
|
||||
suggestion=f"Check Jackify logs ({_logs_dir_display()}) for the specific failure.",
|
||||
solutions=[
|
||||
"Ensure you have an active internet connection — MO2 is downloaded from GitHub.",
|
||||
"Ensure you have an active internet connection - MO2 is downloaded from GitHub.",
|
||||
"Check available disk space in the install directory.",
|
||||
"Try selecting a different install directory with full write permissions.",
|
||||
"If the download failed, check GitHub is accessible (try opening it in a browser).",
|
||||
@@ -423,10 +423,10 @@ _PATTERNS: List[tuple] = [
|
||||
("no such file or directory.*compatdata", lambda d: proton_not_found()),
|
||||
("proton.*not found|no proton", lambda d: proton_not_found()),
|
||||
("vdf.*error|binary_vdf|invalid vdf", lambda d: SteamError("Steam VDF File Error", "A Steam configuration file (VDF) could not be read or written.", suggestion="Ensure Steam is closed and try again.", solutions=["Close Steam completely before retrying.", "Restart Steam and retry the same action.", f"Check Jackify logs ({_logs_dir_display()}) for the specific VDF path.", f"If this still fails, open a GitHub issue and include logs from {_logs_dir_display()}."], technical=format_technical_context(detail=d))),
|
||||
("connection.*refused|connection.*timed out|network.*unreachable", lambda d: InstallError("Network Error", "Jackify could not reach a required network resource.", suggestion="Check your internet connection and retry.", solutions=["Verify your internet connection is active.", "Check if Nexus Mods is reachable at nexusmods.com.", "Disable VPN or proxy if active.", "Retry — transient network errors often resolve on the second attempt."], technical=format_technical_context(detail=d))),
|
||||
("connection.*refused|connection.*timed out|network.*unreachable", lambda d: InstallError("Network Error", "Jackify could not reach a required network resource.", suggestion="Check your internet connection and retry.", solutions=["Verify your internet connection is active.", "Check if Nexus Mods is reachable at nexusmods.com.", "Disable VPN or proxy if active.", "Retry - transient network errors often resolve on the second attempt."], technical=format_technical_context(detail=d))),
|
||||
("401|unauthorized|forbidden.*nexus", lambda d: oauth_expired()),
|
||||
("7z.*error|bad archive|cannot open.*archive", lambda d: InstallError("Archive Error", "A downloaded archive file is corrupted or unreadable.", suggestion="Delete the corrupted file and re-run the install to re-download it.", solutions=["Re-run the install — Wabbajack will re-download files that fail verification.", "Check available disk space (partial downloads look corrupt).", "Check Modlist_Install_workflow.log for the specific file name."], technical=format_technical_context(detail=d))),
|
||||
("timeout", lambda d: SteamError("Operation Timed Out", "An operation took longer than expected and was stopped.", suggestion="Retry — timeouts are often transient.", solutions=["Retry the operation.", "If Steam is slow to start, give it more time before retrying.", "Check system load: close other applications.", f"Check Jackify logs ({_logs_dir_display()}) for which step timed out."], technical=format_technical_context(detail=d))),
|
||||
("7z.*error|bad archive|cannot open.*archive", lambda d: InstallError("Archive Error", "A downloaded archive file is corrupted or unreadable.", suggestion="Delete the corrupted file and re-run the install to re-download it.", solutions=["Re-run the install - Wabbajack will re-download files that fail verification.", "Check available disk space (partial downloads look corrupt).", "Check Modlist_Install_workflow.log for the specific file name."], technical=format_technical_context(detail=d))),
|
||||
("timeout", lambda d: SteamError("Operation Timed Out", "An operation took longer than expected and was stopped.", suggestion="Retry - timeouts are often transient.", solutions=["Retry the operation.", "If Steam is slow to start, give it more time before retrying.", "Check system load: close other applications.", f"Check Jackify logs ({_logs_dir_display()}) for which step timed out."], technical=format_technical_context(detail=d))),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -214,4 +214,56 @@ class LoggingHandler:
|
||||
|
||||
def get_general_logger(self):
|
||||
"""Get the general CLI logger ({jackify_data_dir}/logs/jackify-cli.log)."""
|
||||
return self.setup_logger('jackify_cli', is_general=True)
|
||||
return self.setup_logger('jackify_cli', is_general=True)
|
||||
|
||||
def setup_application_logging(self, debug_mode: bool = False) -> logging.Logger:
|
||||
"""Configure the root logger for the application.
|
||||
|
||||
Always-on: jackify.log at INFO level.
|
||||
Debug mode only: jackify-debug.log at DEBUG level.
|
||||
Console: WARNING in both modes.
|
||||
|
||||
Call once at application startup before any other loggers are created.
|
||||
"""
|
||||
root = logging.getLogger()
|
||||
# Clear any handlers set by basicConfig or previous calls
|
||||
root.handlers.clear()
|
||||
# Root must pass everything through - handlers do the filtering
|
||||
root.setLevel(logging.DEBUG)
|
||||
root.propagate = False
|
||||
|
||||
file_formatter = logging.Formatter(
|
||||
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
console_formatter = logging.Formatter('%(levelname)s: %(message)s')
|
||||
|
||||
# Always-on application log at INFO - rotate on every startup, keep 5
|
||||
app_log_path = self.log_dir / 'jackify.log'
|
||||
self.rotate_log_file_per_run(app_log_path)
|
||||
app_handler = logging.handlers.RotatingFileHandler(
|
||||
app_log_path, mode='a', encoding='utf-8',
|
||||
maxBytes=10 * 1024 * 1024, backupCount=5
|
||||
)
|
||||
app_handler.setLevel(logging.INFO)
|
||||
app_handler.setFormatter(file_formatter)
|
||||
root.addHandler(app_handler)
|
||||
|
||||
# Debug log only when explicitly enabled
|
||||
if debug_mode:
|
||||
debug_log_path = self.log_dir / 'jackify-debug.log'
|
||||
self.rotate_log_file_per_run(debug_log_path)
|
||||
debug_handler = logging.handlers.RotatingFileHandler(
|
||||
debug_log_path, mode='a', encoding='utf-8',
|
||||
maxBytes=100 * 1024 * 1024, backupCount=5
|
||||
)
|
||||
debug_handler.setLevel(logging.DEBUG)
|
||||
debug_handler.setFormatter(file_formatter)
|
||||
root.addHandler(debug_handler)
|
||||
|
||||
# Console: errors only - warnings and below go to jackify.log
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setLevel(logging.ERROR)
|
||||
console_handler.setFormatter(console_formatter)
|
||||
root.addHandler(console_handler)
|
||||
|
||||
return root
|
||||
@@ -74,18 +74,17 @@ def cleanup_stale_tmp() -> None:
|
||||
The engine writes TTW working files (xd3 patches, patch manifests) into
|
||||
UUID-named subdirectories under <data_dir>/.tmp/ during TTW installation.
|
||||
These are never cleaned up on failure or interruption and can accumulate
|
||||
several GB per run. Any such directory present at startup is always stale —
|
||||
several GB per run. Any such directory present at startup is always stale -
|
||||
no TTW install can be in flight before the application has started.
|
||||
|
||||
Only removes directories matching known engine temp prefixes. The
|
||||
jackify-proton-extraction prefix is intentionally reused by the engine
|
||||
across runs and is left in place.
|
||||
jackify-proton-extraction is also cleaned up - the engine no longer uses it
|
||||
and it can accumulate ~700MB.
|
||||
"""
|
||||
tmp_dir = get_jackify_data_dir() / ".tmp"
|
||||
if not tmp_dir.is_dir():
|
||||
return
|
||||
|
||||
stale_prefixes = ("ttw_mpi_", "ttw_ogg_")
|
||||
stale_prefixes = ("ttw_mpi_", "ttw_ogg_", "jackify-proton-extraction")
|
||||
removed = 0
|
||||
freed = 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user