165 lines
5.7 KiB
Python
165 lines
5.7 KiB
Python
import bpy # type: ignore
|
|
|
|
RAINYS_EXTENSIONS_REPO_NAME = "Rainy's Extensions"
|
|
RAINYS_EXTENSIONS_REPO_URL = (
|
|
"https://raw.githubusercontent.com/RaincloudTheDragon/rainys-blender-extensions/refs/heads/main/index.json"
|
|
)
|
|
|
|
_BOOTSTRAP_DONE = False
|
|
|
|
|
|
def _log(message: str) -> None:
|
|
print(f"RainysExtensionsCheck: {message}")
|
|
|
|
|
|
def ensure_rainys_extensions_repo(_deferred: bool = False) -> None:
|
|
"""
|
|
Ensure the Rainy's Extensions repository is registered in Blender.
|
|
|
|
Safe to import and call from multiple add-ons; the helper guards against doing the
|
|
work more than once per Blender session.
|
|
"""
|
|
global _BOOTSTRAP_DONE
|
|
|
|
if _BOOTSTRAP_DONE:
|
|
return
|
|
|
|
_log("starting repository verification")
|
|
|
|
context_class_name = type(bpy.context).__name__
|
|
if context_class_name == "_RestrictContext":
|
|
if _deferred:
|
|
_log("context still restricted after deferral; aborting repo check")
|
|
return
|
|
|
|
_log("context restricted; scheduling repo check retry")
|
|
|
|
def _retry():
|
|
ensure_rainys_extensions_repo(_deferred=True)
|
|
return None
|
|
|
|
bpy.app.timers.register(_retry, first_interval=0.5)
|
|
return
|
|
|
|
prefs = getattr(bpy.context, "preferences", None)
|
|
if prefs is None:
|
|
_log("no preferences available on context; skipping")
|
|
return
|
|
|
|
preferences_changed = False
|
|
addon_prefs = None
|
|
addon_entry = None
|
|
if hasattr(getattr(prefs, "addons", None), "get"):
|
|
addon_entry = prefs.addons.get(__name__)
|
|
elif hasattr(prefs, "addons"):
|
|
try:
|
|
addon_entry = prefs.addons[__name__]
|
|
except Exception:
|
|
addon_entry = None
|
|
if addon_entry:
|
|
addon_prefs = getattr(addon_entry, "preferences", None)
|
|
addon_repo_initialized = bool(
|
|
addon_prefs and getattr(addon_prefs, "repo_initialized", False)
|
|
)
|
|
|
|
experimental = getattr(prefs, "experimental", None)
|
|
if experimental and hasattr(experimental, "use_extension_platform"):
|
|
if not experimental.use_extension_platform:
|
|
experimental.use_extension_platform = True
|
|
preferences_changed = True
|
|
_log("enabled experimental extension platform")
|
|
|
|
repositories = None
|
|
extensions_obj = getattr(prefs, "extensions", None)
|
|
if extensions_obj:
|
|
if hasattr(extensions_obj, "repos"):
|
|
repositories = extensions_obj.repos
|
|
elif hasattr(extensions_obj, "repositories"):
|
|
repositories = extensions_obj.repositories
|
|
|
|
if repositories is None:
|
|
filepaths = getattr(prefs, "filepaths", None)
|
|
repositories = getattr(filepaths, "extension_repos", None) if filepaths else None
|
|
|
|
if repositories is None:
|
|
_log("extension repositories collection missing; skipping")
|
|
return
|
|
|
|
def _repo_matches(repo) -> bool:
|
|
return getattr(repo, "remote_url", "") == RAINYS_EXTENSIONS_REPO_URL or getattr(
|
|
repo, "url", ""
|
|
) == RAINYS_EXTENSIONS_REPO_URL
|
|
|
|
matching_indices = [idx for idx, repo in enumerate(repositories) if _repo_matches(repo)]
|
|
|
|
target_repo = None
|
|
if matching_indices:
|
|
target_repo = repositories[matching_indices[0]]
|
|
if len(matching_indices) > 1 and hasattr(repositories, "remove"):
|
|
for dup_idx in reversed(matching_indices[1:]):
|
|
try:
|
|
repositories.remove(dup_idx)
|
|
_log(f"removed duplicate repository entry at index {dup_idx}")
|
|
except Exception as exc:
|
|
_log(f"could not remove duplicate repository at index {dup_idx}: {exc}")
|
|
else:
|
|
target_repo = next(
|
|
(
|
|
repo
|
|
for repo in repositories
|
|
if getattr(repo, "name", "") == RAINYS_EXTENSIONS_REPO_NAME
|
|
),
|
|
None,
|
|
)
|
|
|
|
if target_repo is None:
|
|
_log("repo missing; creating new entry")
|
|
if hasattr(repositories, "new"):
|
|
target_repo = repositories.new()
|
|
elif hasattr(repositories, "add"):
|
|
target_repo = repositories.add()
|
|
else:
|
|
_log("repository collection does not support creation; aborting")
|
|
return
|
|
else:
|
|
_log("repo entry already present; validating fields")
|
|
|
|
changed = preferences_changed
|
|
|
|
def _ensure_attr(obj, attr, value):
|
|
if hasattr(obj, attr) and getattr(obj, attr) != value:
|
|
setattr(obj, attr, value)
|
|
return True
|
|
if not hasattr(obj, attr):
|
|
_log(f"repository entry missing attribute '{attr}', skipping field")
|
|
return False
|
|
|
|
changed |= _ensure_attr(target_repo, "name", RAINYS_EXTENSIONS_REPO_NAME)
|
|
changed |= _ensure_attr(target_repo, "module", "rainys_extensions")
|
|
changed |= _ensure_attr(target_repo, "use_remote_url", True)
|
|
changed |= _ensure_attr(target_repo, "remote_url", RAINYS_EXTENSIONS_REPO_URL)
|
|
changed |= _ensure_attr(target_repo, "use_sync_on_startup", True)
|
|
changed |= _ensure_attr(target_repo, "use_cache", True)
|
|
changed |= _ensure_attr(target_repo, "use_access_token", False)
|
|
|
|
if addon_prefs and hasattr(addon_prefs, "repo_initialized") and not addon_prefs.repo_initialized:
|
|
addon_prefs.repo_initialized = True
|
|
changed = True
|
|
|
|
if not changed:
|
|
_log("repository already configured; skipping preference save")
|
|
_BOOTSTRAP_DONE = True
|
|
return
|
|
|
|
if hasattr(bpy.ops, "wm") and hasattr(bpy.ops.wm, "save_userpref"):
|
|
try:
|
|
bpy.ops.wm.save_userpref()
|
|
_log("preferences updated and saved")
|
|
except Exception as exc: # pragma: no cover
|
|
print(f"RainysExtensionsCheck: could not save preferences after repo update -> {exc}")
|
|
else:
|
|
_log("preferences API unavailable; changes not persisted")
|
|
|
|
_BOOTSTRAP_DONE = True
|
|
|