Extensions: support replacing missing legacy add-ons with extensions
This groups all the add-ons from 4.1 which were enabled but are no longer distributed with Blender and provides an easy way for users to install them. This panel is collapsed by default. Ref !122727 Co-authored-by: Dalai Felinto <dalai@blender.org>
This commit is contained in:
@@ -1901,6 +1901,14 @@ class EXTENSIONS_OT_package_install(Operator, _ExtCmdMixIn):
|
||||
# Only used for code-path for dropping an extension.
|
||||
url: rna_prop_url
|
||||
|
||||
# NOTE: this can be removed once upgrading from 4.1 is no longer relevant.
|
||||
# Only used when moving from previously built-in add-ons to extensions.
|
||||
do_legacy_replace: BoolProperty(
|
||||
name="Do Legacy Replace",
|
||||
default=False,
|
||||
options={'HIDDEN', 'SKIP_SAVE'}
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not bpy.app.online_access:
|
||||
@@ -2013,6 +2021,10 @@ class EXTENSIONS_OT_package_install(Operator, _ExtCmdMixIn):
|
||||
_preferences_ui_redraw()
|
||||
_preferences_ui_refresh_addons()
|
||||
|
||||
# NOTE: this can be removed once upgrading from 4.1 is no longer relevant.
|
||||
if self.do_legacy_replace and (not canceled):
|
||||
self._do_legacy_replace(self.pkg_id, pkg_manifest_local)
|
||||
|
||||
def invoke(self, context, event):
|
||||
# Only for drop logic!
|
||||
if self.properties.is_property_set("url"):
|
||||
@@ -2080,6 +2092,30 @@ class EXTENSIONS_OT_package_install(Operator, _ExtCmdMixIn):
|
||||
|
||||
layout.prop(self, "enable_on_install", text=rna_prop_enable_on_install_type_map[item_remote["type"]])
|
||||
|
||||
@staticmethod
|
||||
def _do_legacy_replace(pkg_id, pkg_manifest_local):
|
||||
# Disables and add-on that was replaced by an extension,
|
||||
# use for upgrading 4.1 preferences or older.
|
||||
|
||||
# Ensure the local meta-data exists, else there may have been a problem installing,
|
||||
# note that this does *not* check if the add-on could be enabled which is intentional.
|
||||
# It's only important the add-on installs to justify disabling the old add-on.
|
||||
# Note that there is no need to report if this was not found as failing to install will
|
||||
# already have reported.
|
||||
if not pkg_manifest_local.get(pkg_id):
|
||||
return
|
||||
|
||||
from .bl_extension_ui import extensions_map_from_legacy_addons_reverse_lookup
|
||||
addon_module_name = extensions_map_from_legacy_addons_reverse_lookup(pkg_id)
|
||||
if not addon_module_name:
|
||||
# This shouldn't happen unless someone goes out of there way
|
||||
# to enable `do_legacy_replace` for a non-legacy extension.
|
||||
# Use a print here as it's such a corner case and harmless.
|
||||
print("Internal error, legacy lookup failed:", addon_module_name)
|
||||
return
|
||||
|
||||
bpy.ops.preferences.addon_disable(module=addon_module_name)
|
||||
|
||||
|
||||
class EXTENSIONS_OT_package_uninstall(Operator, _ExtCmdMixIn):
|
||||
bl_idname = "extensions.package_uninstall"
|
||||
|
||||
@@ -386,6 +386,103 @@ def extensions_panel_draw_online_extensions_request_impl(
|
||||
row.operator("extensions.userpref_allow_online", text="Allow Online Access", icon='CHECKMARK')
|
||||
|
||||
|
||||
# NOTE: this can be removed once upgrading from 4.1 is no longer relevant.
|
||||
def extensions_map_from_legacy_addons_ensure():
|
||||
import os
|
||||
global extensions_map_from_legacy_addons
|
||||
global extensions_map_from_legacy_addons_url
|
||||
if extensions_map_from_legacy_addons is not None:
|
||||
return
|
||||
|
||||
filepath = os.path.join(os.path.dirname(__file__), "extensions_map_from_legacy_addons.py")
|
||||
with open(filepath, "rb") as fh:
|
||||
data = eval(compile(fh.read(), filepath, "eval"), {})
|
||||
extensions_map_from_legacy_addons = data["extensions"]
|
||||
extensions_map_from_legacy_addons_url = data["remote_url"]
|
||||
|
||||
|
||||
def extensions_map_from_legacy_addons_reverse_lookup(pkg_id):
|
||||
# Return the old name from the package ID.
|
||||
extensions_map_from_legacy_addons_ensure()
|
||||
for key_addon_module_name, (value_pkg_id, _) in extensions_map_from_legacy_addons.items():
|
||||
if pkg_id == value_pkg_id:
|
||||
return key_addon_module_name
|
||||
return ""
|
||||
|
||||
|
||||
extensions_map_from_legacy_addons = None
|
||||
extensions_map_from_legacy_addons_url = None
|
||||
|
||||
|
||||
# NOTE: this can be removed once upgrading from 4.1 is no longer relevant.
|
||||
def extensions_panel_draw_missing_with_extension_impl(
|
||||
*,
|
||||
context,
|
||||
layout,
|
||||
missing_modules,
|
||||
):
|
||||
layout_header, layout_panel = layout.panel("builtin_addons", default_closed=True)
|
||||
layout_header.label(text="Missing Built-in Add-ons", icon='ERROR')
|
||||
|
||||
if layout_panel is None:
|
||||
return
|
||||
|
||||
prefs = context.preferences
|
||||
extensions_map_from_legacy_addons_ensure()
|
||||
|
||||
repo_index = -1
|
||||
repo = None
|
||||
for repo_test_index, repo_test in enumerate(prefs.extensions.repos):
|
||||
if (
|
||||
repo_test.use_remote_url and
|
||||
(repo_test.remote_url.rstrip("/") == extensions_map_from_legacy_addons_url)
|
||||
):
|
||||
repo_index = repo_test_index
|
||||
repo = repo_test
|
||||
break
|
||||
|
||||
box = layout_panel.box()
|
||||
box.label(text="Add-ons previously shipped with Blender are now available from extensions.blender.org.")
|
||||
can_install = True
|
||||
|
||||
if repo is None:
|
||||
# Most likely the user manually removed this.
|
||||
box.label(text="Blender's extension repository not found!", icon='ERROR')
|
||||
elif not repo.enabled:
|
||||
box.label(text="Blender's extension repository must be enabled to install extensions!", icon='ERROR')
|
||||
repo_index = -1
|
||||
del repo
|
||||
|
||||
for addon_module_name in sorted(missing_modules):
|
||||
addon_pkg_id, addon_name = extensions_map_from_legacy_addons[addon_module_name]
|
||||
|
||||
boxsub = box.column().box()
|
||||
colsub = boxsub.column()
|
||||
row = colsub.row()
|
||||
|
||||
row_left = row.row()
|
||||
row_left.alignment = 'LEFT'
|
||||
|
||||
row_left.label(text=addon_name, translate=False)
|
||||
|
||||
row_right = row.row()
|
||||
row_right.alignment = 'RIGHT'
|
||||
|
||||
if repo_index != -1:
|
||||
# NOTE: it's possible this extension is already installed.
|
||||
# the user could have installed it manually, then opened this popup.
|
||||
# This is enough of a corner case that it's not especially worth detecting
|
||||
# and communicating this particular state of affairs to the user.
|
||||
# Worst case, they install and it will re-install an already installed extension.
|
||||
props = row_right.operator("extensions.package_install", text="Install")
|
||||
props.repo_index = repo_index
|
||||
props.pkg_id = addon_pkg_id
|
||||
props.do_legacy_replace = True
|
||||
del props
|
||||
|
||||
row_right.operator("preferences.addon_disable", text="", icon="X", emboss=False).module = addon_module_name
|
||||
|
||||
|
||||
def extensions_panel_draw_missing_impl(
|
||||
*,
|
||||
layout,
|
||||
@@ -792,6 +889,30 @@ def extensions_panel_draw_impl(
|
||||
if addon_module_name not in module_names
|
||||
}
|
||||
|
||||
# NOTE: this can be removed once upgrading from 4.1 is no longer relevant.
|
||||
if missing_modules:
|
||||
# Split the missing modules into two groups, ones which can be upgraded and ones that can't.
|
||||
extensions_map_from_legacy_addons_ensure()
|
||||
|
||||
missing_modules_with_extension = set()
|
||||
missing_modules_without_extension = set()
|
||||
|
||||
for addon_module_name in missing_modules:
|
||||
if addon_module_name in extensions_map_from_legacy_addons:
|
||||
missing_modules_with_extension.add(addon_module_name)
|
||||
else:
|
||||
missing_modules_without_extension.add(addon_module_name)
|
||||
if missing_modules_with_extension:
|
||||
extensions_panel_draw_missing_with_extension_impl(
|
||||
context=context,
|
||||
layout=layout_topmost,
|
||||
missing_modules=missing_modules_with_extension,
|
||||
)
|
||||
|
||||
# Pretend none of these shenanigans ever occurred (to simplify removal).
|
||||
missing_modules = missing_modules_without_extension
|
||||
# End code-path for 4.1x migration.
|
||||
|
||||
if missing_modules:
|
||||
extensions_panel_draw_missing_impl(
|
||||
layout=layout_topmost,
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
# This is a data file that is evaluated directly (not imported).
|
||||
# NOTE: this can be removed once upgrading from 4.1 is no longer relevant.
|
||||
{
|
||||
"remote_url": "https://extensions.blender.org/api/v1/extensions",
|
||||
"extensions": {
|
||||
# The first value is the extension ID, the second is it's name.
|
||||
"add_camera_rigs": ("add_camera_rigs", "Add Camera Rigs"),
|
||||
"add_curve_extra_objects": ("extra_curve_objectes", "Extra Curve Objectes"),
|
||||
"add_curve_ivygen": ("ivygen", "IvyGen"),
|
||||
"add_curve_sapling": ("sapling_tree_gen", "Sapling Tree Gen"),
|
||||
"add_mesh_BoltFactory": ("boltfactory", "BoltFactory"),
|
||||
"add_mesh_discombobulator": ("discombobulator", "Discombobulator"),
|
||||
"add_mesh_extra_objects": ("extra_mesh_objects", "Extra Mesh Objects"),
|
||||
"add_mesh_geodesic_domes": ("geodesic_domes", "Geodesic Domes"),
|
||||
"amaranth": ("amaranth", "Amaranth Toolset"),
|
||||
"animation_add_corrective_shape_key": ("corrective_shape_keys", "Corrective Shape Keys"),
|
||||
"animation_animall": ("animall", "AnimAll"),
|
||||
"ant_landscape": ("antlandscape", "A.N.T.Landscape"),
|
||||
"archimesh": ("archimesh", "Archimesh"),
|
||||
"blender_id": ("blender_id_authentication", "Blender ID authentication"),
|
||||
"bone_selection_sets": ("bone_selection_sets", "Bone Selection Sets"),
|
||||
"btrace": ("btracer", "BTracer"),
|
||||
"camera_turnaround": ("turnaround_camera", "Turnaround Camera"),
|
||||
"curve_assign_shapekey": ("assign_shape_keys", "Assign Shape Keys"),
|
||||
"curve_simplify": ("simplify_curves_plus", "Simplify Curves+"),
|
||||
"curve_tools": ("curve_tools", "Curve Tools"),
|
||||
"development_edit_operator": ("edit_operator_source", "Edit Operator Source"),
|
||||
"development_icon_get": ("icon_viewer", "Icon Viewer"),
|
||||
"development_iskeyfree": ("is_key_free", "Is key Free"),
|
||||
"greasepencil_tools": ("grease_pencil_tools", "Grease Pencil Tools"),
|
||||
"io_anim_camera": ("export_camera_animation", "Export Camera Animation"),
|
||||
"io_anim_nuke_chan": ("nuke_animation_format_chan", "Nuke Animation Format (.chan)"),
|
||||
"io_coat3D": ("coat_applink", "3D-Coat Applink"),
|
||||
"io_export_dxf": ("export_autocad_dxf_format_dxf", "Export Autocad DXF Format (.dxf)"),
|
||||
"io_export_paper_model": ("export_paper_model", "Export Paper Model"),
|
||||
"io_export_pc2": ("export_pointcache_formatpc2", "Export Pointcache Format(.pc2)"),
|
||||
"io_import_BrushSet": ("import_brushset", "Import BrushSet"),
|
||||
"io_import_dxf": ("import_autocad_dxf_format_dxf", "Import AutoCAD DXF Format (.dxf)"),
|
||||
"io_import_palette": ("import_palettes", "Import Palettes"),
|
||||
"io_mesh_atomic": ("atomic_blender_pdb_xyz", "Atomic Blender PDB/XYZ"),
|
||||
"io_scene_3ds": ("autodesk_3ds_format", "Autodesk 3DS format"),
|
||||
"io_shape_mdd": ("newtek_mdd_format", "NewTek MDD format"),
|
||||
"lighting_dynamic_sky": ("dynamic_sky", "Dynamic Sky"),
|
||||
"lighting_tri_lights": ("tri_lighting", "Tri-lighting"),
|
||||
"magic_uv": ("magic_uv", "Magic UV"),
|
||||
"materials_library_vx": ("material_library", "Material Library"),
|
||||
"materials_utils": ("material_utilities", "Material Utilities"),
|
||||
"measureit": ("measureit", "MeasureIt"),
|
||||
"mesh_auto_mirror": ("auto_mirror", "Auto Mirror"),
|
||||
"mesh_bsurfaces": ("bsurfaces_gpl_edition", "Bsurfaces GPL Edition"),
|
||||
"mesh_f2": ("f2", "F2"),
|
||||
"mesh_inset": ("inset_straight_skeleton", "Inset Straight Skeleton"),
|
||||
"mesh_looptools": ("looptools", "LoopTools"),
|
||||
"mesh_snap_utilities_line": ("snap_utilities_line", "Snap_Utilities_Line"),
|
||||
"mesh_tiny_cad": ("tinycad_mesh_tools", "tinyCAD Mesh tools"),
|
||||
"mesh_tissue": ("tissue", "Tissue"),
|
||||
"mesh_tools": ("edit_mesh_tools", "Edit Mesh Tools"),
|
||||
"node_arrange": ("node_arrange", "Node Arrange"),
|
||||
"node_presets": ("node_presets", "Node Presets"),
|
||||
"object_boolean_tools": ("bool_tool", "Bool Tool"),
|
||||
"object_carver": ("carver", "Carver"),
|
||||
"object_collection_manager": ("collection_manager", "Collection Manager"),
|
||||
"object_color_rules": ("object_color_rules", "Object Color Rules"),
|
||||
"object_edit_linked": ("edit_linked_library", "Edit Linked Library"),
|
||||
"object_fracture_cell": ("cell_fracture", "Cell Fracture"),
|
||||
"object_print3d_utils": ("print3d_toolbox", "3D-Print Toolbox"),
|
||||
"object_scatter": ("scatter_objects", "Scatter Objects"),
|
||||
"object_skinify": ("skinify_rig", "Skinify Rig"),
|
||||
"paint_palette": ("paint_palettes", "Paint Palettes"),
|
||||
"power_sequencer": ("power_sequencer", "Power Sequencer"),
|
||||
"precision_drawing_tools": ("precision_drawing_tools_pdt", "Precision Drawing Tools (PDT)"),
|
||||
"real_snow": ("real_snow", "Real Snow"),
|
||||
"render_copy_settings": ("copy_render_settings", "Copy Render Settings"),
|
||||
"render_freestyle_svg": ("freestyle_svg_exporter", "Freestyle SVG Exporter"),
|
||||
"render_povray": ("pov_at_ble", "POV@Ble"),
|
||||
"render_ui_animation_render": ("ui_animation_render", "UI Animation Render"),
|
||||
"rigify": ("rigify", "Rigify"),
|
||||
"space_clip_editor_refine_solution": ("refine_tracking_solution", "Refine tracking solution"),
|
||||
"space_view3d_3d_navigation": ("navigation", "3D Navigation"),
|
||||
"space_view3d_align_tools": ("align_tools", "Align Tools"),
|
||||
"space_view3d_brush_menus": ("dynamic_brush_menus", "Dynamic Brush Menus"),
|
||||
"space_view3d_copy_attributes": ("copy_attributes_menu", "Copy Attributes Menu"),
|
||||
"space_view3d_math_vis": ("math_vis_console", "Math Vis (Console)"),
|
||||
"space_view3d_modifier_tools": ("modifier_tools", "Modifier Tools"),
|
||||
"space_view3d_pie_menus": ("viewport_pie_menus", "3D Viewport Pie Menus"),
|
||||
"space_view3d_spacebar_menu": ("dynamic_context_menu", "Dynamic Context Menu"),
|
||||
"space_view3d_stored_views": ("stored_views", "Stored Views"),
|
||||
"storypencil": ("storypencil_storyboard_tools", "Storypencil - Storyboard Tools"),
|
||||
"sun_position": ("sun_position", "Sun Position"),
|
||||
"system_blend_info": ("scene_information", "Scene Information"),
|
||||
"system_demo_mode": ("demo_mode", "Demo Mode"),
|
||||
"system_property_chart": ("property_chart", "Property Chart"),
|
||||
"vdm_brush_baker": ("vdm_brush_baker", "VDM Brush Baker"),
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user