diff --git a/Addon.py b/Addon.py
index edea74f3..1710b935 100644
--- a/Addon.py
+++ b/Addon.py
@@ -688,7 +688,7 @@ def get_zip_url(self) -> str:
else:
# The ZIP url is based on the location of the main cache file:
if self.relative_cache_path:
- cache_file_url = fci.Preferences().get("addon_catalog_cache_url")
+ cache_file_url = fci.Preferences().get("addon_index_cache_url")
parsed_url = urlparse(cache_file_url)
path_parts = parsed_url.path.rpartition("/")
new_path = path_parts[0] + "/" + self.relative_cache_path
diff --git a/AddonManagerTest/app/test_workers_startup.py b/AddonManagerTest/app/test_workers_startup.py
index 13097a4d..49955a91 100644
--- a/AddonManagerTest/app/test_workers_startup.py
+++ b/AddonManagerTest/app/test_workers_startup.py
@@ -42,9 +42,9 @@ def test_no_new_catalog_available(self, mock_network_manager, mock_preferences_c
)
def get_side_effect(key):
- if key == "last_fetched_addon_catalog_cache_hash":
+ if key == "last_fetched_addon_index_cache_hash":
return "1234567890abcdef"
- elif key == "addon_catalog_cache_url":
+ elif key == "addon_index_cache_url":
return "https://some.url"
return None
@@ -52,7 +52,7 @@ def get_side_effect(key):
# Act
result = addonmanager_workers_startup.CreateAddonListWorker.new_cache_available(
- "addon_catalog"
+ "addon_index"
)
# Assert
@@ -71,9 +71,9 @@ def test_new_catalog_is_available(self, mock_network_manager, mock_preferences_c
)
def get_side_effect(key):
- if key == "last_fetched_addon_catalog_cache_hash":
+ if key == "last_fetched_addon_index_cache_hash":
return "fedcba0987654321" # NOT the same hash
- elif key == "addon_catalog_cache_url":
+ elif key == "addon_index_cache_url":
return "https://some.url"
return None
@@ -81,7 +81,7 @@ def get_side_effect(key):
# Act
result = addonmanager_workers_startup.CreateAddonListWorker.new_cache_available(
- "addon_catalog"
+ "addon_index"
)
# Assert
@@ -155,3 +155,44 @@ def test_process_addon_catalog_with_user_override(
# Assert
self.assertEqual(8, mock_addon_repo_signal.emit.call_count)
+
+ @patch("addonmanager_workers_startup.fci.Preferences")
+ @patch("addonmanager_workers_startup.fci.Console")
+ def test_migrate_catalog_to_index_no_custom_data(self, mock_console, mock_preferences_class):
+ # Arrange
+ def return_no_custom_data(key):
+ return None if key != "addon_catalog_cache_url" else "obsolete"
+
+ mock_preferences_instance = MagicMock()
+ mock_preferences_instance.get = return_no_custom_data
+ mock_preferences_class.return_value = mock_preferences_instance
+ worker = addonmanager_workers_startup.CreateAddonListWorker()
+
+ # Act
+ worker.migrate_catalog_to_index()
+
+ # Assert
+ mock_preferences_instance.set.assert_not_called()
+ mock_console.PrintWarning.assert_not_called()
+
+ @patch("addonmanager_workers_startup.fci.Preferences")
+ @patch("addonmanager_workers_startup.fci.Console")
+ def test_migrate_catalog_to_index_custom_data(self, mock_console, mock_preferences_class):
+
+ # Arrange
+ def return_custom_data(key):
+ return None if key != "addon_catalog_cache_url" else "some custom url"
+
+ mock_preferences_instance = MagicMock()
+ mock_preferences_instance.get = return_custom_data
+ mock_preferences_class.return_value = mock_preferences_instance
+ worker = addonmanager_workers_startup.CreateAddonListWorker()
+
+ # Act
+ worker.migrate_catalog_to_index()
+
+ # Assert
+ mock_preferences_instance.set.assert_called_once_with(
+ "addon_index_cache_url", "some custom url"
+ )
+ mock_console.PrintWarning.assert_called()
diff --git a/addonmanager_preferences_defaults.json b/addonmanager_preferences_defaults.json
index 05665994..cc75e044 100644
--- a/addonmanager_preferences_defaults.json
+++ b/addonmanager_preferences_defaults.json
@@ -24,12 +24,13 @@
"ViewStyle": 1,
"WindowHeight": 600,
"WindowWidth": 800,
- "addon_catalog_cache_url": "https://addons.freecad.org/addon_catalog_cache.zip",
+ "addon_catalog_cache_url": "obsolete, replaced by addon_index_cache_url",
+ "addon_index_cache_url": "https://addons.freecad.org/addon_index_cache.zip",
"alwaysAskForToolbar": true,
"dontShowAddMacroButtonDialog": false,
"force_git_in_repos": "parts_library",
"ignored_missing_deps": "",
- "last_fetched_addon_catalog_cache_hash": "Cache never fetched, no hash available",
+ "last_fetched_addon_index_cache_hash": "Cache never fetched, no hash available",
"last_fetched_macro_cache_hash": "Cache never fetched, no hash available",
"macro_cache_url": "https://addons.freecad.org/macro_cache.zip",
"old_backup_handling": "ask",
diff --git a/addonmanager_workers_startup.py b/addonmanager_workers_startup.py
index b100afde..019f1e1a 100644
--- a/addonmanager_workers_startup.py
+++ b/addonmanager_workers_startup.py
@@ -75,10 +75,12 @@ def run(self):
self._get_custom_addons()
self.progress_made.emit("Custom addons loaded", 5, 100)
- addon_cache = self.get_cache("addon_catalog")
+ CreateAddonListWorker.migrate_catalog_to_index()
+
+ addon_cache = self.get_cache("addon_index")
if addon_cache:
self.process_addon_cache(addon_cache)
- self.progress_made.emit("Addon catalog loaded", 20, 100)
+ self.progress_made.emit("Addon index loaded", 20, 100)
macro_cache = self.get_cache("macro")
if macro_cache:
@@ -90,6 +92,15 @@ def run(self):
fci.Console.PrintError(str(e) + "\n")
return
+ @staticmethod
+ def migrate_catalog_to_index():
+ old_catalog_url = fci.Preferences().get("addon_catalog_cache_url")
+ if old_catalog_url.startswith("obsolete"):
+ return # Nothing to migrate, it was never set to anything else
+ fci.Console.PrintWarning("Custom catalog URL was detected: using as the index URL now\n")
+ fci.Console.PrintWarning(f"URL: {old_catalog_url}\n")
+ fci.Preferences().set("addon_index_cache_url", old_catalog_url)
+
def _get_custom_addons(self):
# querying custom addons first
diff --git a/package.xml b/package.xml
index f7f210e4..046d60dd 100644
--- a/package.xml
+++ b/package.xml
@@ -5,8 +5,8 @@
Addon Manager
Development branch of a tool to install workbenches, macros, themes, etc.
Resources/icons/addon_manager.svg
- 2026.2.9dev
- 2026-02-09
+ 2026.2.11dev
+ 2026-02-11
Chris Hennes
Yorik van Havre
Jonathan Wiedemann