From bf0b8517e414966458f1649bb2a62e7e9e362852 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Mon, 9 Jun 2025 21:48:19 +0100 Subject: [PATCH 1/2] Merges newly downloaded packages into existing index.json. Fixes #131 --- src/manage/install_command.py | 21 +++++++++++++++++++++ tests/test_install_command.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/manage/install_command.py b/src/manage/install_command.py index a1a8e60..0f955df 100644 --- a/src/manage/install_command.py +++ b/src/manage/install_command.py @@ -534,6 +534,26 @@ def _install_one(cmd, source, install, *, target=None): LOGGER.verbose("Install complete") +def _merge_existing_index(versions, index_json): + try: + with open(index_json, "r", encoding="utf-8") as f: + existing_index = json.load(f) + list(existing_index["versions"]) + except FileNotFoundError: + pass + except (json.JSONDecodeError, KeyError, ValueError): + LOGGER.warn("Existing index file appeared invalid and was overwritten.") + LOGGER.debug(exc_info=True) + else: + LOGGER.debug("Merging into existing %s", index_json) + current = {i["url"].casefold() for i in versions} + added = [] + for install in existing_index["versions"]: + if install.get("url", "").casefold() not in current: + LOGGER.debug("Merging %s", install.get("url", "")) + versions.append(install) + + def _fatal_install_error(cmd, ex): logfile = cmd.get_log_file() if logfile: @@ -753,6 +773,7 @@ def execute(cmd): return _fatal_install_error(cmd, ex) if cmd.download: + _merge_existing_index(download_index["versions"], cmd.download / "index.json") with open(cmd.download / "index.json", "w", encoding="utf-8") as f: json.dump(download_index, f, indent=2, default=str) LOGGER.info("Offline index has been generated at !Y!%s!W!.", cmd.download) diff --git a/tests/test_install_command.py b/tests/test_install_command.py index 0e15dfd..db7ec94 100644 --- a/tests/test_install_command.py +++ b/tests/test_install_command.py @@ -1,3 +1,4 @@ +import json import os import pytest import secrets @@ -131,3 +132,34 @@ def get_installs(self): assert_log( assert_log.skip_until(".*Global shortcuts directory is not on PATH") ) + + +def test_merge_existing_index(tmp_path): + # This function is for multiple downloaded index.jsons, so it merges based + # on the url property, which should usually be a local file. + existing = tmp_path / "index.json" + with open(existing, "w", encoding="utf-8") as f: + json.dump({"versions": [ + {"id": "test-1", "url": "test-file-1.zip"}, + {"id": "test-2", "url": "test-file-2.zip"}, + {"id": "test-3", "url": "test-file-3.zip"}, + ]}, f) + + new = [ + # Ensure new versions appear first + {"id": "test-4", "url": "test-file-4.zip"}, + # Ensure matching ID doesn't result in overwrite + {"id": "test-1", "url": "test-file-1b.zip"}, + # Ensure matching URL excludes original entry + {"id": "test-2b", "url": "test-file-2.zip"}, + ] + + IC._merge_existing_index(new, existing) + + assert new == [ + {"id": "test-4", "url": "test-file-4.zip"}, + {"id": "test-1", "url": "test-file-1b.zip"}, + {"id": "test-2b", "url": "test-file-2.zip"}, + {"id": "test-1", "url": "test-file-1.zip"}, + {"id": "test-3", "url": "test-file-3.zip"}, + ] From cb8a637c76f373dde7b345feb005d58a63d5ead6 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Mon, 9 Jun 2025 22:03:43 +0100 Subject: [PATCH 2/2] Add more tests and fix bad log call --- src/manage/install_command.py | 2 +- tests/test_install_command.py | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/manage/install_command.py b/src/manage/install_command.py index 0f955df..c89afb2 100644 --- a/src/manage/install_command.py +++ b/src/manage/install_command.py @@ -543,7 +543,7 @@ def _merge_existing_index(versions, index_json): pass except (json.JSONDecodeError, KeyError, ValueError): LOGGER.warn("Existing index file appeared invalid and was overwritten.") - LOGGER.debug(exc_info=True) + LOGGER.debug("TRACEBACK", exc_info=True) else: LOGGER.debug("Merging into existing %s", index_json) current = {i["url"].casefold() for i in versions} diff --git a/tests/test_install_command.py b/tests/test_install_command.py index db7ec94..50a485b 100644 --- a/tests/test_install_command.py +++ b/tests/test_install_command.py @@ -163,3 +163,29 @@ def test_merge_existing_index(tmp_path): {"id": "test-1", "url": "test-file-1.zip"}, {"id": "test-3", "url": "test-file-3.zip"}, ] + + +def test_merge_existing_index_not_found(tmp_path): + existing = tmp_path / "index.json" + try: + existing.unlink() + except FileNotFoundError: + pass + + # Expect no failure and no change + new = [1, 2, 3] + IC._merge_existing_index(new, existing) + assert new == [1, 2, 3] + + +def test_merge_existing_index_not_valid(tmp_path): + existing = tmp_path / "index.json" + with open(existing, "w", encoding="utf-8") as f: + print("It's not a list of installs", file=f) + print("But more importantly,", file=f) + print("it's not valid JSON!", file=f) + + # Expect no failure and no change + new = [1, 2, 3] + IC._merge_existing_index(new, existing) + assert new == [1, 2, 3]