From dc0e559cbb5daaf885892eee0ed2d91025a14823 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 7 Jun 2024 16:30:31 +1000 Subject: [PATCH] Extensions: remove intermediate operators for upgrade and sync The buttons to upgrade or sync extensions called extension operators via bpy.app.handlers, requiring awkward glue-code which didn't show error reports in to the user. Remove these operators and call the upgrade & sync operators directly. --- scripts/addons_core/bl_pkg/__init__.py | 27 ---- .../addons_core/bl_pkg/bl_extension_ops.py | 26 +++- scripts/addons_core/bl_pkg/bl_extension_ui.py | 16 +++ scripts/startup/bl_ui/space_userpref.py | 14 +- source/blender/blenkernel/BKE_callbacks.hh | 1 - .../editors/space_userpref/userpref_ops.cc | 133 ------------------ .../blender/python/intern/bpy_app_handlers.cc | 1 - 7 files changed, 49 insertions(+), 169 deletions(-) diff --git a/scripts/addons_core/bl_pkg/__init__.py b/scripts/addons_core/bl_pkg/__init__.py index 7987da69221..ebe6abd861c 100644 --- a/scripts/addons_core/bl_pkg/__init__.py +++ b/scripts/addons_core/bl_pkg/__init__.py @@ -300,26 +300,6 @@ def extenion_repos_sync(*_): repo_status_text.from_message("Sync \"{:s}\"".format(active_repo.name), text) -@bpy.app.handlers.persistent -def extenion_repos_upgrade(*_): - # This is called from operators (create or an explicit call to sync) - # so calling a modal operator is "safe". - if (active_repo := repo_active_or_none()) is None: - return - - print_debug("UPGRADE:", active_repo.name) - - from contextlib import redirect_stdout - import io - stdout = io.StringIO() - - with redirect_stdout(stdout): - bpy.ops.extensions.package_upgrade_all('INVOKE_DEFAULT', use_active_only=True) - - if text := stdout.getvalue(): - repo_status_text.from_message("Upgrade \"{:s}\"".format(active_repo.name), text) - - @bpy.app.handlers.persistent def extenion_repos_files_clear(directory, _): # Perform a "safe" file deletion by only removing files known to be either @@ -601,9 +581,6 @@ def register(): handlers = bpy.app.handlers._extension_repos_sync handlers.append(extenion_repos_sync) - handlers = bpy.app.handlers._extension_repos_upgrade - handlers.append(extenion_repos_upgrade) - handlers = bpy.app.handlers._extension_repos_files_clear handlers.append(extenion_repos_files_clear) @@ -653,10 +630,6 @@ def unregister(): if extenion_repos_sync in handlers: handlers.remove(extenion_repos_sync) - handlers = bpy.app.handlers._extension_repos_upgrade - if extenion_repos_upgrade in handlers: - handlers.remove(extenion_repos_upgrade) - handlers = bpy.app.handlers._extension_repos_files_clear if extenion_repos_files_clear in handlers: handlers.remove(extenion_repos_files_clear) diff --git a/scripts/addons_core/bl_pkg/bl_extension_ops.py b/scripts/addons_core/bl_pkg/bl_extension_ops.py index 86360c25af7..6bf00505f9b 100644 --- a/scripts/addons_core/bl_pkg/bl_extension_ops.py +++ b/scripts/addons_core/bl_pkg/bl_extension_ops.py @@ -916,7 +916,17 @@ def _repo_dir_and_index_get(repo_index, directory, report_fn): return directory -def _extensions_maybe_online_action_poll_impl(cls, action_text): +def _extensions_maybe_online_action_poll_impl(cls, repo, action_text): + + # Only operating on the active repository. + if repo is not None: + if not repo.enabled: + cls.poll_message_set("Active repository is disabled") + return False + if not repo.use_remote_url: + cls.poll_message_set("Local repositories do not support: {:s}".format(action_text)) + return False + if not bpy.app.online_access: cls.poll_message_set( "Online access required to {:s}. {:s}".format( @@ -1087,6 +1097,8 @@ class EXTENSIONS_OT_repo_sync(Operator, _ExtCmdMixIn): class EXTENSIONS_OT_repo_sync_all(Operator, _ExtCmdMixIn): + # TODO: this text should be dynamic, changing when `use_active_only is True`. + # """Refresh the list of extensions for the active repository""" """Refresh the list of extensions for all the remote repositories""" bl_idname = "extensions.repo_sync_all" bl_label = "Check for Updates" @@ -1098,8 +1110,9 @@ class EXTENSIONS_OT_repo_sync_all(Operator, _ExtCmdMixIn): ) @classmethod - def poll(cls, _context): - return _extensions_maybe_online_action_poll_impl(cls, "check for updates") + def poll(cls, context): + repo = getattr(context, "extension_repo", None) + return _extensions_maybe_online_action_poll_impl(cls, repo, "check for updates") def exec_command_iter(self, is_modal): use_active_only = self.use_active_only @@ -1168,6 +1181,8 @@ class EXTENSIONS_OT_repo_sync_all(Operator, _ExtCmdMixIn): class EXTENSIONS_OT_package_upgrade_all(Operator, _ExtCmdMixIn): + # TODO: this text should be dynamic, changing when `use_active_only is True`. + # """Upgrade all the extensions to their latest version for the active repository""" """Upgrade all the extensions to their latest version for all the remote repositories""" bl_idname = "extensions.package_upgrade_all" bl_label = "Ext Package Upgrade All" @@ -1182,8 +1197,9 @@ class EXTENSIONS_OT_package_upgrade_all(Operator, _ExtCmdMixIn): ) @classmethod - def poll(cls, _context): - return _extensions_maybe_online_action_poll_impl(cls, "install updates") + def poll(cls, context): + repo = getattr(context, "extension_repo", None) + return _extensions_maybe_online_action_poll_impl(cls, repo, "install updates") def exec_command_iter(self, is_modal): from . import repo_cache_store diff --git a/scripts/addons_core/bl_pkg/bl_extension_ui.py b/scripts/addons_core/bl_pkg/bl_extension_ui.py index b59d23cb17e..353296068ff 100644 --- a/scripts/addons_core/bl_pkg/bl_extension_ui.py +++ b/scripts/addons_core/bl_pkg/bl_extension_ui.py @@ -22,6 +22,7 @@ from bpy.types import ( from bl_ui.space_userpref import ( USERPREF_PT_addons, + USERPREF_MT_extensions_active_repo, ) from . import repo_status_text @@ -1195,6 +1196,19 @@ def tags_panel_draw(panel, context): col.prop(wm.extension_tags, "[\"{:s}\"]".format(escape_identifier(t))) +def extensions_repo_active_draw(self, context): + # Draw icon buttons on the right hand side of the UI-list. + from . import repo_active_or_none + layout = self.layout + + # Allow the poll functions to only check against the active repository. + if (repo := repo_active_or_none()) is not None: + layout.context_pointer_set("extension_repo", repo) + + layout.operator("extensions.repo_sync_all", text="", icon='FILE_REFRESH').use_active_only = True + layout.operator("extensions.package_upgrade_all", text="", icon='IMPORT').use_active_only = True + + classes = ( # Pop-overs. USERPREF_PT_extensions_filter, @@ -1206,6 +1220,7 @@ classes = ( def register(): USERPREF_PT_addons.append(extensions_panel_draw) USERPREF_PT_extensions_tags.append(tags_panel_draw) + USERPREF_MT_extensions_active_repo.append(extensions_repo_active_draw) for cls in classes: bpy.utils.register_class(cls) @@ -1214,6 +1229,7 @@ def register(): def unregister(): USERPREF_PT_addons.remove(extensions_panel_draw) USERPREF_PT_extensions_tags.remove(tags_panel_draw) + USERPREF_MT_extensions_active_repo.remove(extensions_repo_active_draw) for cls in reversed(classes): bpy.utils.unregister_class(cls) diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py index 8b63faec90a..e02352666b7 100644 --- a/scripts/startup/bl_ui/space_userpref.py +++ b/scripts/startup/bl_ui/space_userpref.py @@ -2122,6 +2122,15 @@ class USERPREF_PT_keymap(KeymapPanel, Panel): # ----------------------------------------------------------------------------- # Extension Panels + +class USERPREF_MT_extensions_active_repo(Menu): + bl_label = "Active Repository" + + def draw(self, _context): + # Add-ons may extend. + pass + + class USERPREF_PT_extensions_repos(Panel): bl_label = "Repositories" bl_options = {'HIDE_HEADER'} @@ -2154,8 +2163,8 @@ class USERPREF_PT_extensions_repos(Panel): props.index = active_repo_index col.separator() - col.operator("preferences.extension_repo_sync", text="", icon='FILE_REFRESH') - col.operator("preferences.extension_repo_upgrade", text="", icon='IMPORT') + + col.menu_contents("USERPREF_MT_extensions_active_repo") try: active_repo = None if active_repo_index < 0 else extensions.repos[active_repo_index] @@ -2922,6 +2931,7 @@ classes = ( USERPREF_PT_addons, + USERPREF_MT_extensions_active_repo, USERPREF_PT_extensions_repos, USERPREF_PT_studiolight_lights, diff --git a/source/blender/blenkernel/BKE_callbacks.hh b/source/blender/blenkernel/BKE_callbacks.hh index 5f77cebcb11..002c2d332fe 100644 --- a/source/blender/blenkernel/BKE_callbacks.hh +++ b/source/blender/blenkernel/BKE_callbacks.hh @@ -109,7 +109,6 @@ enum eCbEvent { BKE_CB_EVT_EXTENSION_REPOS_UPDATE_PRE, BKE_CB_EVT_EXTENSION_REPOS_UPDATE_POST, BKE_CB_EVT_EXTENSION_REPOS_SYNC, - BKE_CB_EVT_EXTENSION_REPOS_UPGRADE, BKE_CB_EVT_EXTENSION_REPOS_FILES_CLEAR, BKE_CB_EVT_TOT, }; diff --git a/source/blender/editors/space_userpref/userpref_ops.cc b/source/blender/editors/space_userpref/userpref_ops.cc index 68223e66e81..6e73a3da970 100644 --- a/source/blender/editors/space_userpref/userpref_ops.cc +++ b/source/blender/editors/space_userpref/userpref_ops.cc @@ -577,86 +577,6 @@ static void PREFERENCES_OT_extension_repo_add(wmOperatorType *ot) /** \} */ -/* -------------------------------------------------------------------- */ -/** \name Generic Extension Repository Utilities - * \{ */ - -static bool preferences_extension_check_for_updates_enabled_poll(bContext *C) -{ - const bUserExtensionRepo *repo = BKE_preferences_extension_repo_find_index( - &U, U.active_extension_repo); - - if ((G.f & G_FLAG_INTERNET_ALLOW) == 0) { - if ((G.f & G_FLAG_INTERNET_OVERRIDE_PREF_OFFLINE) != 0) { - CTX_wm_operator_poll_msg_set( - C, "Online access required to check for updates. Launch Blender without --offline-mode"); - } - else { - CTX_wm_operator_poll_msg_set(C, - "Online access required to check for updates. Enable online " - "access in System preferences"); - } - return false; - } - - if (repo == nullptr) { - CTX_wm_operator_poll_msg_set(C, "No repositories available"); - return false; - } - - if ((repo->flag & USER_EXTENSION_REPO_FLAG_USE_REMOTE_URL) == 0) { - CTX_wm_operator_poll_msg_set(C, "Local repositories do not require refreshing"); - return false; - } - - if ((repo->flag & USER_EXTENSION_REPO_FLAG_DISABLED) != 0) { - CTX_wm_operator_poll_msg_set(C, "Active repository is disabled"); - return false; - } - - return true; -} - -static bool preferences_extension_install_updates_enabled_poll(bContext *C) -{ - const bUserExtensionRepo *repo = BKE_preferences_extension_repo_find_index( - &U, U.active_extension_repo); - - if ((G.f & G_FLAG_INTERNET_ALLOW) == 0) { - if ((G.f & G_FLAG_INTERNET_OVERRIDE_PREF_OFFLINE) != 0) { - CTX_wm_operator_poll_msg_set( - C, "Online access required to install updates. Launch Blender without --offline-mode"); - } - else { - CTX_wm_operator_poll_msg_set(C, - "Online access required to install updates. Enable online " - "access in System preferences"); - } - return false; - } - - if (repo == nullptr) { - CTX_wm_operator_poll_msg_set(C, "No repositories available"); - return false; - } - - if ((repo->flag & USER_EXTENSION_REPO_FLAG_USE_REMOTE_URL) == 0) { - CTX_wm_operator_poll_msg_set(C, - "Local repositories do not require manual update. Reload scripts " - "or restart Blender to see any updates"); - return false; - } - - if ((repo->flag & USER_EXTENSION_REPO_FLAG_DISABLED) != 0) { - CTX_wm_operator_poll_msg_set(C, "Active repository is disabled"); - return false; - } - - return true; -} - -/** \} */ - /* -------------------------------------------------------------------- */ /** \name Remove Extension Repository Operator * \{ */ @@ -801,57 +721,6 @@ static void PREFERENCES_OT_extension_repo_remove(wmOperatorType *ot) /** \} */ -/* -------------------------------------------------------------------- */ -/** \name Check for Extension Repository Updates Operator - * \{ */ - -static int preferences_extension_repo_sync_exec(bContext *C, wmOperator * /*op*/) -{ - Main *bmain = CTX_data_main(C); - BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_SYNC); - WM_event_add_notifier(C, NC_WINDOW, nullptr); - return OPERATOR_FINISHED; -} - -static void PREFERENCES_OT_extension_repo_sync(wmOperatorType *ot) -{ - ot->name = "Check for Updates"; - ot->idname = "PREFERENCES_OT_extension_repo_sync"; - ot->description = "Refresh the list of extensions for the active repository"; - - ot->exec = preferences_extension_repo_sync_exec; - ot->poll = preferences_extension_check_for_updates_enabled_poll; - - ot->flag = OPTYPE_INTERNAL; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Update Extension Repository Operator - * \{ */ - -static int preferences_extension_repo_upgrade_exec(bContext *C, wmOperator * /*op*/) -{ - Main *bmain = CTX_data_main(C); - BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_UPGRADE); - WM_event_add_notifier(C, NC_WINDOW, nullptr); - return OPERATOR_FINISHED; -} - -static void PREFERENCES_OT_extension_repo_upgrade(wmOperatorType *ot) -{ - ot->name = "Install Available Updates for Repository"; - ot->idname = "PREFERENCES_OT_extension_repo_upgrade"; - ot->description = "Upgrade all the extensions to their latest version for the active repository"; - ot->exec = preferences_extension_repo_upgrade_exec; - ot->poll = preferences_extension_install_updates_enabled_poll; - - ot->flag = OPTYPE_INTERNAL; -} - -/** \} */ - /* -------------------------------------------------------------------- */ /** \name Drop Extension Operator * \{ */ @@ -1171,8 +1040,6 @@ void ED_operatortypes_userpref() WM_operatortype_append(PREFERENCES_OT_extension_repo_add); WM_operatortype_append(PREFERENCES_OT_extension_repo_remove); - WM_operatortype_append(PREFERENCES_OT_extension_repo_sync); - WM_operatortype_append(PREFERENCES_OT_extension_repo_upgrade); WM_operatortype_append(PREFERENCES_OT_extension_url_drop); WM_operatortype_append(PREFERENCES_OT_associate_blend); diff --git a/source/blender/python/intern/bpy_app_handlers.cc b/source/blender/python/intern/bpy_app_handlers.cc index 949af521e13..d62da0ab77a 100644 --- a/source/blender/python/intern/bpy_app_handlers.cc +++ b/source/blender/python/intern/bpy_app_handlers.cc @@ -97,7 +97,6 @@ static PyStructSequence_Field app_cb_info_fields[] = { {"_extension_repos_update_pre", "on changes to extension repos (before)"}, {"_extension_repos_update_post", "on changes to extension repos (after)"}, {"_extension_repos_sync", "on creating or synchronizing the active repository"}, - {"_extension_repos_upgrade", "on upgrading the active repository"}, {"_extension_repos_files_clear", "remove files from the repository directory (uses as a string argument)"},