oscillode/run.py

109 lines
2.9 KiB
Python
Raw Normal View History

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"