Skip to content

Commit 52aa23c

Browse files
authored
Merges newly downloaded packages into existing index.json. (#132)
Fixes #131
1 parent 6d8c627 commit 52aa23c

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

src/manage/install_command.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,26 @@ def _install_one(cmd, source, install, *, target=None):
534534
LOGGER.verbose("Install complete")
535535

536536

537+
def _merge_existing_index(versions, index_json):
538+
try:
539+
with open(index_json, "r", encoding="utf-8") as f:
540+
existing_index = json.load(f)
541+
list(existing_index["versions"])
542+
except FileNotFoundError:
543+
pass
544+
except (json.JSONDecodeError, KeyError, ValueError):
545+
LOGGER.warn("Existing index file appeared invalid and was overwritten.")
546+
LOGGER.debug("TRACEBACK", exc_info=True)
547+
else:
548+
LOGGER.debug("Merging into existing %s", index_json)
549+
current = {i["url"].casefold() for i in versions}
550+
added = []
551+
for install in existing_index["versions"]:
552+
if install.get("url", "").casefold() not in current:
553+
LOGGER.debug("Merging %s", install.get("url", "<unspecified>"))
554+
versions.append(install)
555+
556+
537557
def _fatal_install_error(cmd, ex):
538558
logfile = cmd.get_log_file()
539559
if logfile:
@@ -753,6 +773,7 @@ def execute(cmd):
753773
return _fatal_install_error(cmd, ex)
754774

755775
if cmd.download:
776+
_merge_existing_index(download_index["versions"], cmd.download / "index.json")
756777
with open(cmd.download / "index.json", "w", encoding="utf-8") as f:
757778
json.dump(download_index, f, indent=2, default=str)
758779
LOGGER.info("Offline index has been generated at !Y!%s!W!.", cmd.download)

tests/test_install_command.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
import os
23
import pytest
34
import secrets
@@ -131,3 +132,60 @@ def get_installs(self):
131132
assert_log(
132133
assert_log.skip_until(".*Global shortcuts directory is not on PATH")
133134
)
135+
136+
137+
def test_merge_existing_index(tmp_path):
138+
# This function is for multiple downloaded index.jsons, so it merges based
139+
# on the url property, which should usually be a local file.
140+
existing = tmp_path / "index.json"
141+
with open(existing, "w", encoding="utf-8") as f:
142+
json.dump({"versions": [
143+
{"id": "test-1", "url": "test-file-1.zip"},
144+
{"id": "test-2", "url": "test-file-2.zip"},
145+
{"id": "test-3", "url": "test-file-3.zip"},
146+
]}, f)
147+
148+
new = [
149+
# Ensure new versions appear first
150+
{"id": "test-4", "url": "test-file-4.zip"},
151+
# Ensure matching ID doesn't result in overwrite
152+
{"id": "test-1", "url": "test-file-1b.zip"},
153+
# Ensure matching URL excludes original entry
154+
{"id": "test-2b", "url": "test-file-2.zip"},
155+
]
156+
157+
IC._merge_existing_index(new, existing)
158+
159+
assert new == [
160+
{"id": "test-4", "url": "test-file-4.zip"},
161+
{"id": "test-1", "url": "test-file-1b.zip"},
162+
{"id": "test-2b", "url": "test-file-2.zip"},
163+
{"id": "test-1", "url": "test-file-1.zip"},
164+
{"id": "test-3", "url": "test-file-3.zip"},
165+
]
166+
167+
168+
def test_merge_existing_index_not_found(tmp_path):
169+
existing = tmp_path / "index.json"
170+
try:
171+
existing.unlink()
172+
except FileNotFoundError:
173+
pass
174+
175+
# Expect no failure and no change
176+
new = [1, 2, 3]
177+
IC._merge_existing_index(new, existing)
178+
assert new == [1, 2, 3]
179+
180+
181+
def test_merge_existing_index_not_valid(tmp_path):
182+
existing = tmp_path / "index.json"
183+
with open(existing, "w", encoding="utf-8") as f:
184+
print("It's not a list of installs", file=f)
185+
print("But more importantly,", file=f)
186+
print("it's not valid JSON!", file=f)
187+
188+
# Expect no failure and no change
189+
new = [1, 2, 3]
190+
IC._merge_existing_index(new, existing)
191+
assert new == [1, 2, 3]

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy