Merge branch 'blender-v4.2-release'

This commit is contained in:
Campbell Barton
2024-06-20 15:17:57 +10:00
5 changed files with 101 additions and 56 deletions

View File

@@ -195,8 +195,9 @@ class subcmd_query:
def list_item(
pkg_id: str,
item_remote: Optional[PkgManifest_Normalized],
item_local: Optional[PkgManifest_Normalized],
item_remote: Optional[PkgManifest_Normalized],
has_remote: bool,
) -> None:
# Both can't be None.
assert item_remote is not None or item_local is not None
@@ -222,8 +223,12 @@ class subcmd_query:
status_info = ""
item = item_remote
else:
# All local-only packages are installed.
status_info = " [{:s}]".format(colorize("installed", "green"))
# All local-only packages are installed,
# if they're in a repository with a remote but no remote info - they're "orphan".
status_info = " [{:s}]".format(
colorize("orphan", "yellow") if has_remote else
colorize("installed", "green")
)
assert isinstance(item_local, PkgManifest_Normalized)
item = item_local
@@ -248,26 +253,23 @@ class subcmd_query:
repo_cache_store = repo_cache_store_ensure()
for repo_index, (
pkg_manifest_remote,
pkg_manifest_local,
pkg_manifest_remote,
) in enumerate(zip(
repo_cache_store.pkg_manifest_from_remote_ensure(error_fn=print),
repo_cache_store.pkg_manifest_from_local_ensure(error_fn=print),
repo_cache_store.pkg_manifest_from_remote_ensure(error_fn=print),
strict=True,
)):
# Show any exceptions created while accessing the JSON,
repo = repos_all[repo_index]
print("Repository: \"{:s}\" (id={:s})".format(repo.name, repo.module))
if pkg_manifest_remote is not None:
for pkg_id, item_remote in pkg_manifest_remote.items():
if pkg_manifest_local is not None:
item_local = pkg_manifest_local.get(pkg_id)
else:
item_local = None
list_item(pkg_id, item_remote, item_local)
else:
for pkg_id, item_local in pkg_manifest_local.items():
list_item(pkg_id, None, item_local)
has_remote = repo.remote_url and (pkg_manifest_remote is not None)
pkg_id_set = set((pkg_manifest_local or {}).keys()) | set((pkg_manifest_remote or {}).keys())
for pkg_id in sorted(pkg_id_set):
item_local = pkg_manifest_local.get(pkg_id) if (pkg_manifest_local is not None) else None
item_remote = pkg_manifest_remote.get(pkg_id) if (pkg_manifest_remote is not None) else None
list_item(pkg_id, item_local, item_remote, has_remote)
return True

View File

@@ -99,7 +99,7 @@ def sync_apply_locked(repos_notify, repos_notify_files, unique_ext):
repo_directories=repo_directories,
cookie=cookie_from_session(),
) as lock_result:
for directory, repo_files in zip(repo_directories, repos_notify_files):
for directory, repo_files in zip(repo_directories, repos_notify_files, strict=True):
repo_files = [os.path.join(directory, filepath_rel) for filepath_rel in repo_files]
# If locking failed, remove the temporary files that were written to.

View File

@@ -179,11 +179,12 @@ def extension_url_find_repo_index_and_pkg_id(url):
repo_cache_store = repo_cache_store_ensure()
for repo_index, (
pkg_manifest_remote,
pkg_manifest_local,
pkg_manifest_remote,
) in enumerate(zip(
repo_cache_store.pkg_manifest_from_remote_ensure(error_fn=print),
repo_cache_store.pkg_manifest_from_local_ensure(error_fn=print),
repo_cache_store.pkg_manifest_from_remote_ensure(error_fn=print),
strict=True,
)):
# It's possible the remote repo could not be connected to when syncing.
# Allow it to be None without raising an exception.
@@ -500,11 +501,12 @@ def _preferences_ensure_sync():
repo_cache_store = repo_cache_store_ensure()
sync_required = False
for (
pkg_manifest_remote,
pkg_manifest_local,
pkg_manifest_remote,
) in zip(
repo_cache_store.pkg_manifest_from_remote_ensure(error_fn=print),
repo_cache_store.pkg_manifest_from_local_ensure(error_fn=print),
repo_cache_store.pkg_manifest_from_remote_ensure(error_fn=print),
strict=True,
):
if pkg_manifest_remote is None:
sync_required = True

View File

@@ -495,6 +495,27 @@ def extensions_panel_draw_missing_impl(
row_right.operator("preferences.addon_disable", text="", icon="X", emboss=False).module = addon_module_name
def pkg_manifest_zip_all_items(pkg_manifest_local, pkg_manifest_remote):
if pkg_manifest_remote is None:
if pkg_manifest_local is not None:
for pkg_id, item_local in pkg_manifest_local.items():
yield pkg_id, (item_local, None)
# If both are none, there are no items, that's OK.
return
elif pkg_manifest_local is None:
for pkg_id, item_remote in pkg_manifest_remote.items():
yield pkg_id, (None, item_remote)
return
assert (pkg_manifest_remote is not None) and (pkg_manifest_local is not None)
pkg_manifest_local_copy = pkg_manifest_local.copy()
for pkg_id, item_remote in pkg_manifest_remote.items():
yield pkg_id, (pkg_manifest_local_copy.pop(pkg_id, None), item_remote)
# Orphan packages (if they exist).
for pkg_id, item_local in pkg_manifest_local_copy.items():
yield pkg_id, (item_local, None)
def extensions_panel_draw_impl(
self,
context,
@@ -568,23 +589,24 @@ def extensions_panel_draw_impl(
# Collect exceptions accessing repositories, and optionally show them.
errors_on_draw = []
remote_ex = None
local_ex = None
def error_fn_remote(ex):
nonlocal remote_ex
remote_ex = ex
remote_ex = None
def error_fn_local(ex):
nonlocal local_ex
local_ex = ex
def error_fn_remote(ex):
nonlocal remote_ex
remote_ex = ex
for repo_index, (
pkg_manifest_remote,
pkg_manifest_local,
pkg_manifest_remote,
) in enumerate(zip(
repo_cache_store.pkg_manifest_from_remote_ensure(error_fn=error_fn_remote),
repo_cache_store.pkg_manifest_from_local_ensure(error_fn=error_fn_local),
repo_cache_store.pkg_manifest_from_remote_ensure(error_fn=error_fn_remote),
strict=True,
)):
# Show any exceptions created while accessing the JSON,
# if the JSON has an IO error while being read or if the directory doesn't exist.
@@ -622,25 +644,25 @@ def extensions_panel_draw_impl(
repos_all[repo_index].name,
)
)
continue
continue
# Read-only.
is_system_repo = repos_all[repo_index].source == 'SYSTEM'
for pkg_id, item_remote in pkg_manifest_remote.items():
if filter_by_type and (filter_by_type != item_remote.type):
for pkg_id, (item_local, item_remote) in pkg_manifest_zip_all_items(pkg_manifest_local, pkg_manifest_remote):
item = item_local or item_remote
if filter_by_type and (filter_by_type != item.type):
continue
if search_lower and (not pkg_info_check_exclude_filter(item_remote, search_lower)):
if search_lower and (not pkg_info_check_exclude_filter(item, search_lower)):
continue
item_local = pkg_manifest_local.get(pkg_id)
is_installed = item_local is not None
if installed_only and (is_installed == 0):
continue
if extension_tags:
if tags := item_remote.tags:
if tags := item.tags:
if not any(True for t in tags if extension_tags.get(t, True)):
continue
else:
@@ -649,7 +671,7 @@ def extensions_panel_draw_impl(
is_addon = False
is_theme = False
match item_remote.type:
match item.type:
case "add-on":
is_addon = True
case "theme":
@@ -677,7 +699,7 @@ def extensions_panel_draw_impl(
if enabled_only and (not is_enabled):
continue
item_version = item_remote.version
item_version = item.version
if item_local is None:
item_local_version = None
is_outdated = False
@@ -751,13 +773,13 @@ def extensions_panel_draw_impl(
sub = row.row()
sub.active = is_enabled
sub.label(text=item_remote.name, translate=False)
sub.label(text=item.name, translate=False)
del sub
row_right = row.row()
row_right = row.row(align=True)
row_right.alignment = 'RIGHT'
if has_remote:
if has_remote and (item_remote is not None):
if is_installed:
# Include uninstall below.
if is_outdated:
@@ -776,7 +798,13 @@ def extensions_panel_draw_impl(
del props
else:
# Right space for alignment with the button.
row_right.label(text="Installed ")
if item_remote is None:
# There is a local item with no remote
row_right.label(text="Orphan")
row_right.label(text="", icon='ORPHAN_DATA')
else:
row_right.label(text="Installed ")
row_right.active = False
if show:
@@ -785,9 +813,9 @@ def extensions_panel_draw_impl(
col_b = split.column()
# The full tagline may be multiple lines (not yet supported by Blender's UI).
col_a.label(text="{:s}.".format(tip_(item_remote.tagline)), translate=False)
col_a.label(text="{:s}.".format(tip_(item.tagline)), translate=False)
if value := item_remote.website:
if value := item.website:
# Use half size button, for legacy add-ons there are two, here there is one
# however one large button looks silly, so use a half size still.
col_a.split(factor=0.5).operator(
@@ -825,14 +853,14 @@ def extensions_panel_draw_impl(
# WARNING: while this is documented to be a dict, old packages may contain a list of strings.
# As it happens dictionary keys & list values both iterate over string,
# however we will want to show the dictionary values eventually.
if (value := item_remote.permissions):
if (value := item.permissions):
col_b.label(text=", ".join([iface_(x).title() for x in value]), translate=False)
else:
col_b.label(text="No permissions specified")
del value
col_a.label(text="Maintainer")
col_b.label(text=item_remote.maintainer, translate=False)
col_b.label(text=item.maintainer, translate=False)
col_a.label(text="Version")
if is_outdated:
@@ -843,12 +871,12 @@ def extensions_panel_draw_impl(
else:
col_b.label(text=item_version, translate=False)
if has_remote:
if has_remote and (item_remote is not None):
col_a.label(text="Size")
col_b.label(text=size_as_fmt_string(item_remote.archive_size), translate=False)
col_a.label(text="License")
col_b.label(text=item_remote.license, translate=False)
col_b.label(text=item.license, translate=False)
if len(repos_all) > 1:
col_a.label(text="Repository")
@@ -1131,13 +1159,20 @@ def tags_current(wm):
filter_by_type = blender_filter_by_type_map[wm.extension_type]
tags = set()
for pkg_manifest_remote in repo_cache_store.pkg_manifest_from_remote_ensure(error_fn=print):
if pkg_manifest_remote is None:
continue
for item_remote in pkg_manifest_remote.values():
if filter_by_type != item_remote.type:
for (
pkg_manifest_local,
pkg_manifest_remote,
) in zip(
repo_cache_store.pkg_manifest_from_local_ensure(error_fn=print),
repo_cache_store.pkg_manifest_from_remote_ensure(error_fn=print),
strict=True,
):
for pkg_id, (item_local, item_remote) in pkg_manifest_zip_all_items(pkg_manifest_local, pkg_manifest_remote):
item = item_local or item_remote
if filter_by_type != item.type:
continue
if pkg_tags := item_remote.tags:
if pkg_tags := item.tags:
tags.update(pkg_tags)
if filter_by_type == "add-on":

View File

@@ -1617,6 +1617,7 @@ class _RepoCacheEntry:
self.directory = directory
self.remote_url = remote_url
# Manifest data per package loaded from the packages local JSON.
# TODO(@ideasman42): use `_RepoDataSouce_ABC` for `pkg_manifest_local`.
self._pkg_manifest_local: Optional[Dict[str, PkgManifest_Normalized]] = None
self._pkg_manifest_remote: Optional[Dict[str, PkgManifest_Normalized]] = None
self._pkg_manifest_remote_data_source: _RepoDataSouce_ABC = (
@@ -1837,11 +1838,16 @@ class RepoCacheStore:
if repo_entry.directory not in directory_subset:
continue
yield repo_entry._json_data_ensure(
check_files=check_files,
ignore_missing=ignore_missing,
error_fn=error_fn,
)
# While we could yield a valid manifest here,
# leave it to the caller to skip "remote" data for local-only repositories.
if repo_entry.remote_url:
yield repo_entry._json_data_ensure(
check_files=check_files,
ignore_missing=ignore_missing,
error_fn=error_fn,
)
else:
yield None
def pkg_manifest_from_local_ensure(
self,