Files
NX2navi/launcher/context.py
chrg6 c9f75ad0b2 Read launcher.json saved with a BOM, and keep a copy of one that is not valid JSON.
The docs ask players to edit the file by hand (github_token, feed_repo). A BOM, which an editor may add, made the
file unreadable and every setting, the game folder included, fell back to its default, so the launcher showed the
first run again; a typo did the same and the next save overwrote what the player wrote. The file is now read with
utf-8-sig, and a file that is still no JSON is copied to launcher.json.bad and named in the log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 15:51:48 -05:00

52 lines
1.8 KiB
Python

"""What every part of the launcher shares: the folder layout, the settings and the log (data/logs/launcher.log,
the run before it in launcher.1.log)."""
import os
import threading
import time
from .paths import Layout
from .settings import Settings
LOG_LIMIT = 4 << 20
class Context:
def __init__(self, layout=None, echo=False):
self.layout = (layout or Layout()).ensure()
self.settings = Settings(self.layout.settings)
self.version = self.layout.version
self.echo = echo
self._lock = threading.Lock()
path = self.layout.logs / 'launcher.log'
try:
if path.is_file() and path.stat().st_size > LOG_LIMIT:
os.replace(path, path.with_name('launcher.1.log'))
except OSError:
pass
try:
self._file = open(path, 'a', encoding='utf-8', errors='replace')
except OSError:
self._file = None
self.log(f'--- NX2navi launcher {self.version} ({"checkout" if self.layout.dev else "release"}) in '
f'{self.layout.root}')
if self.settings.unreadable:
self.log(f'{self.layout.settings} is not valid JSON: the settings start from their defaults; the file as '
'it was is kept as launcher.json.bad')
def log(self, line):
stamp = time.strftime('%H:%M:%S')
with self._lock:
if self._file:
for part in str(line).splitlines() or ['']:
self._file.write(f'{stamp} {part}\n')
self._file.flush()
if self.echo:
print(line, flush=True)
def log_tail(self, n=80):
try:
with open(self.layout.logs / 'launcher.log', encoding='utf-8', errors='replace') as f:
return f.readlines()[-n:]
except OSError:
return []