From 78563e1955a61789fc751325b7c796bf585a7de5 Mon Sep 17 00:00:00 2001 From: David Monk Date: Fri, 8 May 2026 17:30:14 -0400 Subject: [PATCH] Fix five high-confidence bugs across countdown, sync, pocket, organizer, timeline - countdown: join the input-reader child before close() and recover from a race where close() raises ValueError, ensuring os_specifics.finalize() always runs and the terminal is restored from raw mode. - retroaccount: only persist save_user_json when the server returned a valid non-empty tokens dict; previously an empty/non-dict response could overwrite valid credentials and force an unnecessary logout. - pocket firmware: continue iterating after finding the matching firmware so older pocket_firmware*.bin files iterated after it are still removed. - arcade organizer: use os.scandir() as a context manager in _remove_broken_symlinks to release file descriptors on each recursion. - timeline: replace `formatted_category in ('system')` (a substring check due to the missing trailing comma) with `== 'system'`. Co-Authored-By: Claude Opus 4.7 --- src/update_all/analogue_pocket/firmware_update.py | 2 +- src/update_all/arcade_organizer/arcade_organizer.py | 11 ++++++----- src/update_all/countdown.py | 13 ++++++++++--- src/update_all/retroaccount.py | 8 +++++--- src/update_all/timeline.py | 2 +- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/update_all/analogue_pocket/firmware_update.py b/src/update_all/analogue_pocket/firmware_update.py index d6c80c559a..b021e2722f 100644 --- a/src/update_all/analogue_pocket/firmware_update.py +++ b/src/update_all/analogue_pocket/firmware_update.py @@ -56,7 +56,7 @@ def pocket_firmware_update(curl_ssl: str, local_repository: LocalRepository, log firmware_name = Path(firmware).name.lower() if firmware_name == firmware_info['file'].lower(): already_on_latest_firmware = True - break + continue logger.print(f'Removing old firmware file: {firmware_name}') os.remove(firmware) diff --git a/src/update_all/arcade_organizer/arcade_organizer.py b/src/update_all/arcade_organizer/arcade_organizer.py index ab6d11c1d7..025f909c17 100644 --- a/src/update_all/arcade_organizer/arcade_organizer.py +++ b/src/update_all/arcade_organizer/arcade_organizer.py @@ -703,11 +703,12 @@ def _remove_dir(self, directory): def _remove_broken_symlinks(self, directory): try: - for entry in os.scandir(directory): - if entry.is_dir(follow_symlinks=False): - self._remove_broken_symlinks(entry.path) - elif entry.is_symlink() and not os.path.exists(entry.path): - os.remove(entry.path) + with os.scandir(directory) as entries: + for entry in entries: + if entry.is_dir(follow_symlinks=False): + self._remove_broken_symlinks(entry.path) + elif entry.is_symlink() and not os.path.exists(entry.path): + os.remove(entry.path) except Exception as e: self._printer.print("Couldn't clean broken symlinks at " + directory) self._printer.print(str(e)) diff --git a/src/update_all/countdown.py b/src/update_all/countdown.py index 81097a382d..472a319c7c 100644 --- a/src/update_all/countdown.py +++ b/src/update_all/countdown.py @@ -87,9 +87,16 @@ def execute_count(self, count) -> CountdownOutcome: time.sleep(1.0 / 60.0) child_process.terminate() - time.sleep(1.0 / 60.0) - - child_process.close() + child_process.join(timeout=1.0) + try: + child_process.close() + except ValueError: + child_process.kill() + child_process.join(timeout=1.0) + try: + child_process.close() + except ValueError: + pass os_specifics.finalize() print('', flush=True) diff --git a/src/update_all/retroaccount.py b/src/update_all/retroaccount.py index 33b87224cb..1651afc4e8 100644 --- a/src/update_all/retroaccount.py +++ b/src/update_all/retroaccount.py @@ -242,10 +242,12 @@ def _build_mister_sync_transition(self) -> Optional[_SyncTransition]: self._logger.bench('RetroAccountService Gateway mister_sync end') if result == SessionResult.VALID and isinstance(response, dict): - new_user_json = response.get('tokens', None) - if isinstance(new_user_json, dict) and len(new_user_json) >= 1: + tokens = response.get('tokens', None) + new_user_json: Optional[dict[str, Any]] = None + if isinstance(tokens, dict) and len(tokens) >= 1: self._logger.debug(f'RetroAccountService: New token!') - new_user_json['device_id'] = device_id + tokens['device_id'] = device_id + new_user_json = tokens benefits = response.get('benefits', {}) self._logger.debug(f'RetroAccountService: Benefits after mister_sync ', benefits) diff --git a/src/update_all/timeline.py b/src/update_all/timeline.py index 240b456224..3aac9acf76 100644 --- a/src/update_all/timeline.py +++ b/src/update_all/timeline.py @@ -215,7 +215,7 @@ def add_doc_section(doc: list[str], section: dict[str, Any], names_dict: dict[st for category in categories: formatted_category = category['category'] - if formatted_category in ('system'): + if formatted_category == 'system': formatted_category = f"{formatted_category.capitalize()} file" else: formatted_category = formatted_category.capitalize()