109 lines
2.9 KiB
Python
109 lines
2.9 KiB
Python
|
import zipfile
|
||
|
import contextlib
|
||
|
import shutil
|
||
|
import sys
|
||
|
from pathlib import Path
|
||
|
|
||
|
import bpy
|
||
|
import addon_utils
|
||
|
|
||
|
PATH_ROOT = Path(__file__).resolve().parent
|
||
|
|
||
|
####################
|
||
|
# - Defined Constants
|
||
|
####################
|
||
|
ADDON_NAME = "blender_maxwell"
|
||
|
PATH_BLEND = PATH_ROOT / "demo.blend"
|
||
|
PATH_ADDON_DEPS = PATH_ROOT / ".cached-dependencies"
|
||
|
|
||
|
####################
|
||
|
# - Computed Constants
|
||
|
####################
|
||
|
PATH_ADDON = PATH_ROOT / ADDON_NAME
|
||
|
PATH_ADDON_ZIP = PATH_ROOT / (ADDON_NAME + ".zip")
|
||
|
|
||
|
####################
|
||
|
# - Utilities
|
||
|
####################
|
||
|
@contextlib.contextmanager
|
||
|
def zipped_directory(path_dir: Path, path_zip: Path):
|
||
|
"""Context manager that exposes a zipped version of a directory,
|
||
|
then deletes the .zip file afterwards.
|
||
|
"""
|
||
|
# Delete Existing ZIP file (if exists)
|
||
|
if path_zip.is_file(): path_zip.unlink()
|
||
|
|
||
|
# Create a (new) ZIP file of the addon directory
|
||
|
with zipfile.ZipFile(path_zip, 'w', zipfile.ZIP_DEFLATED) as f_zip:
|
||
|
for file_to_zip in path_dir.rglob('*'):
|
||
|
f_zip.write(file_to_zip, file_to_zip.relative_to(path_dir.parent))
|
||
|
|
||
|
# Delete the ZIP
|
||
|
try:
|
||
|
yield path_zip
|
||
|
finally:
|
||
|
path_zip.unlink()
|
||
|
|
||
|
####################
|
||
|
# - main()
|
||
|
####################
|
||
|
if __name__ == "__main__":
|
||
|
# Check and uninstall the addon if it's enabled
|
||
|
is_loaded_by_default, is_loaded_now = addon_utils.check(ADDON_NAME)
|
||
|
if is_loaded_now:
|
||
|
# Disable the Addon
|
||
|
addon_utils.disable(ADDON_NAME, default_set=True, handle_error=None)
|
||
|
|
||
|
# Completey Delete the Addon
|
||
|
for mod in addon_utils.modules():
|
||
|
if mod.__name__ == ADDON_NAME:
|
||
|
# Delete Addon from Blender Python Tree
|
||
|
shutil.rmtree(Path(mod.__file__).parent)
|
||
|
|
||
|
# Reset All Addons
|
||
|
addon_utils.reset_all()
|
||
|
|
||
|
# Save User Preferences & Break
|
||
|
bpy.ops.wm.save_userpref()
|
||
|
break
|
||
|
|
||
|
# Quit Blender (hard-flush Python environment)
|
||
|
## - Python environments are not made to be partially flushed.
|
||
|
## - This is the only truly reliable way to avoid all bugs.
|
||
|
## - See https://github.com/JacquesLucke/blender_vscode
|
||
|
bpy.ops.wm.quit_blender()
|
||
|
try:
|
||
|
raise RuntimeError
|
||
|
except:
|
||
|
sys.exit(42)
|
||
|
|
||
|
with zipped_directory(PATH_ADDON, PATH_ADDON_ZIP) as path_zipped:
|
||
|
# Install the ZIPped Addon
|
||
|
bpy.ops.preferences.addon_install(filepath=str(path_zipped))
|
||
|
|
||
|
# Enable the Addon
|
||
|
addon_utils.enable(
|
||
|
ADDON_NAME,
|
||
|
default_set=True,
|
||
|
persistent=True,
|
||
|
handle_error=None,
|
||
|
)
|
||
|
|
||
|
# Save User Preferences
|
||
|
bpy.ops.wm.save_userpref()
|
||
|
|
||
|
# Load the .blend
|
||
|
bpy.ops.wm.open_mainfile(filepath=str(PATH_BLEND))
|
||
|
|
||
|
# Ensure Addon-Specific Dependency Cache is Importable
|
||
|
## - In distribution, the addon keeps this folder in the Blender script tree.
|
||
|
## - For testing, we need to hack sys.path here.
|
||
|
## - This avoids having to install all deps with every reload.
|
||
|
if str(PATH_ADDON_DEPS) not in sys.path:
|
||
|
sys.path.insert(0, str(PATH_ADDON_DEPS))
|
||
|
|
||
|
# Modify any specific settings, if needed
|
||
|
# Example: bpy.context.preferences.addons[addon_name].preferences.your_setting = "your_value"
|
||
|
|
||
|
|