Extensions: enable extensions.blender.org, adjust welcome screen
Splash screen notification text: - When starting in "Offline mode" with repositories with installed packages enabled, the text is clickable unless launched with `--offline-mode`, the tooltip notes that the command line setting can't be changed at run-time. - Don's show anything if there are not extensions installed. Preferences: - Don't show the welcome message on preferences if: - Blender is online. - The message was dismissed. - There are no enabled remote repositories. - The option to enable extensions.blender.org has been replaced with a button that switches to the "System" tab where Online Access can be enabled. Also expose bpy.app.online_access_override needed for the UI to check if online access was disabled using command line arguments.
This commit is contained in:
@@ -149,7 +149,6 @@ def repos_to_notify():
|
||||
# Since it's not all that common to disable the status bar just run notifications
|
||||
# if any repositories are marked to run notifications.
|
||||
|
||||
online_access = bpy.app.online_access
|
||||
prefs = bpy.context.preferences
|
||||
extension_repos = prefs.extensions.repos
|
||||
for repo_item in extension_repos:
|
||||
@@ -164,14 +163,6 @@ def repos_to_notify():
|
||||
if not remote_url:
|
||||
continue
|
||||
|
||||
if online_access:
|
||||
# All URL's may be accessed.
|
||||
pass
|
||||
else:
|
||||
# Allow remote file-system repositories even when online access is disabled.
|
||||
if not remote_url.startswith("file://"):
|
||||
continue
|
||||
|
||||
# WARNING: this could be a more expensive check, use a "reasonable" guess.
|
||||
# This is technically incorrect because knowing if a repository has any installed
|
||||
# packages requires reading it's meta-data and comparing it with the directory contents.
|
||||
@@ -195,6 +186,7 @@ def repos_to_notify():
|
||||
if repo_is_empty:
|
||||
continue
|
||||
|
||||
# NOTE: offline checks are handled by the notification (not here).
|
||||
repos_notify.append(repo_item)
|
||||
return repos_notify
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ from . import bl_extension_utils
|
||||
# only keep this as a reference and in case we can speed up forcing them to exit.
|
||||
USE_GRACEFUL_EXIT = False
|
||||
|
||||
# Special value to signal no packages can be updated because all repositories are blocked by being offline.
|
||||
STATE_DATA_ALL_OFFLINE = object()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Internal Utilities
|
||||
@@ -140,8 +143,19 @@ def sync_status_generator(repos_notify):
|
||||
# Setup The Update #
|
||||
# ################ #
|
||||
|
||||
repos_notify_orig = repos_notify
|
||||
if not bpy.app.online_access:
|
||||
repos_notify = [repo for repo in repos_notify if repo.remote_url.startswith("file://")]
|
||||
if not repos_notify:
|
||||
# Special case, early exit.
|
||||
yield (STATE_DATA_ALL_OFFLINE, 0, ())
|
||||
return
|
||||
|
||||
yield None
|
||||
|
||||
any_offline = len(repos_notify) != len(repos_notify_orig)
|
||||
del repos_notify_orig
|
||||
|
||||
# An extension unique to this session.
|
||||
unique_ext = "@{:x}".format(os.getpid())
|
||||
|
||||
@@ -244,10 +258,15 @@ def sync_status_generator(repos_notify):
|
||||
# TODO: more elegant way to detect changes.
|
||||
# Re-calculating the same information each time then checking if it's different isn't great.
|
||||
if command_result.status_data_changed:
|
||||
extra_warnings = []
|
||||
if command_result.all_complete:
|
||||
any_lock_errors = sync_apply_locked(repos_notify, repos_notify_files, unique_ext)
|
||||
update_total = sync_status_count_outdated_extensions(repos_notify)
|
||||
yield (cmd_batch.calc_status_data(), update_total, any_lock_errors)
|
||||
if any_lock_errors:
|
||||
extra_warnings.append(" Failed to acquire lock!")
|
||||
if any_offline:
|
||||
extra_warnings.append(" Skipping online repositories!")
|
||||
yield (cmd_batch.calc_status_data(), update_total, extra_warnings)
|
||||
else:
|
||||
yield None
|
||||
|
||||
@@ -294,7 +313,7 @@ class NotifyHandle:
|
||||
self.state = 0
|
||||
# We could start the generator separately, this seems OK here for now.
|
||||
self.sync_generator = iter(sync_status_generator(repos_notify))
|
||||
# TEXT/ICON_ID/COUNT
|
||||
# status_data, update_count, extra_warnings.
|
||||
self.sync_info = None
|
||||
|
||||
|
||||
@@ -354,11 +373,15 @@ def splash_draw_status_fn(self, context):
|
||||
|
||||
if _notify.sync_info is None:
|
||||
self.layout.label(text="Updates starting...")
|
||||
elif _notify.sync_info[0] is STATE_DATA_ALL_OFFLINE:
|
||||
# The special case is ugly but showing this operator doesn't fit well with other kinds of status updates.
|
||||
self.layout.operator("bl_pkg.extensions_show_online_prefs", text="Offline mode", icon='ORPHAN_DATA')
|
||||
else:
|
||||
status_data, update_count, any_lock_errors = _notify.sync_info
|
||||
status_data, update_count, extra_warnings = _notify.sync_info
|
||||
text, icon = bl_extension_utils.CommandBatch.calc_status_text_icon_from_data(status_data, update_count)
|
||||
if any_lock_errors:
|
||||
text = text + " - failed to acquire lock!"
|
||||
# Not more than 1-2 of these (failed to lock, some repositories offline .. etc).
|
||||
for warning in extra_warnings:
|
||||
text = text + warning
|
||||
row = self.layout.row(align=True)
|
||||
if update_count > 0:
|
||||
row.operator("bl_pkg.extensions_show_for_update", text=text, icon=icon)
|
||||
|
||||
@@ -2245,42 +2245,27 @@ class BlPkgShowUpgrade(Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class BlPkgOnlineAccess(Operator):
|
||||
"""Handle online access"""
|
||||
bl_idname = "bl_pkg.extension_online_access"
|
||||
# NOTE: this is a wrapper for `SCREEN_OT_userpref_show`.
|
||||
# It exists *only* to add a poll function which sets a message when offline mode is forced.
|
||||
class BlPkgShowOnlinePreference(Operator):
|
||||
"""Show system preferences "Network" panel to allow online access"""
|
||||
bl_idname = "bl_pkg.extensions_show_online_prefs"
|
||||
bl_label = ""
|
||||
bl_options = {'INTERNAL'}
|
||||
|
||||
enable: BoolProperty(
|
||||
name="Enable",
|
||||
default=False,
|
||||
)
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if bpy.app.online_access_override:
|
||||
if not bpy.app.online_access:
|
||||
cls.poll_message_set("Blender was launched in offline-mode which cannot be changed at runtime")
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
wm = context.window_manager
|
||||
prefs = context.preferences
|
||||
|
||||
remote_url = "https://extensions.blender.org/api/v1/extensions"
|
||||
|
||||
if self.enable:
|
||||
extension_repos = prefs.extensions.repos
|
||||
repo_found = None
|
||||
for repo in extension_repos:
|
||||
if repo.remote_url == remote_url:
|
||||
repo_found = repo
|
||||
break
|
||||
if repo_found:
|
||||
repo_found.enabled = True
|
||||
else:
|
||||
# While not expected, we want to know if this ever occurs, don't fail silently.
|
||||
self.report({'WARNING'}, "Repository \"{:s}\" not found!".format(remote_url))
|
||||
|
||||
if bpy.app.online_access:
|
||||
# Run the first check for updates automatically.
|
||||
# Invoke the modal operator so users can cancel by pressing "Escape".
|
||||
assert bpy.ops.bl_pkg.repo_sync_all.poll()
|
||||
bpy.ops.bl_pkg.repo_sync_all('INVOKE_DEFAULT')
|
||||
|
||||
prefs.extensions.use_online_access_handled = True
|
||||
bpy.ops.screen.userpref_show('INVOKE_DEFAULT', section='SYSTEM')
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
@@ -2334,7 +2319,7 @@ classes = (
|
||||
BlPkgRepoUnlock,
|
||||
|
||||
BlPkgShowUpgrade,
|
||||
BlPkgOnlineAccess,
|
||||
BlPkgShowOnlinePreference,
|
||||
|
||||
# Dummy, just shows a message.
|
||||
BlPkgEnableNotInstalled,
|
||||
|
||||
@@ -296,16 +296,21 @@ def extensions_panel_draw_online_extensions_request_impl(
|
||||
if layout_panel is not None:
|
||||
# Text wrapping isn't supported, manually wrap.
|
||||
for line in (
|
||||
"Welcome! Access community-made add-ons and themes from the",
|
||||
"Welcome! Access community-made add-ons and themes from the ",
|
||||
"extensions.blender.org repository.",
|
||||
"",
|
||||
"This also requires internet access which must be enabled in \"System\" preferences.",
|
||||
"This requires online access which must be enabled in \"System\" preferences.",
|
||||
):
|
||||
layout_panel.label(text=line)
|
||||
|
||||
row = layout.row()
|
||||
row.operator("bl_pkg.extension_online_access", text="Dismiss", icon='X').enable = False
|
||||
row.operator("bl_pkg.extension_online_access", text="Enable Repository", icon='CHECKMARK').enable = True
|
||||
props = row.operator("wm.context_set_boolean", text="Dismiss", icon='X')
|
||||
props.data_path = "preferences.extensions.use_online_access_handled"
|
||||
props.value = True
|
||||
|
||||
# The only reason to prefer this over `screen.userpref_show`
|
||||
# is it will be disabled when `--offline-mode` is forced with a useful error for why.
|
||||
row.operator("bl_pkg.extensions_show_online_prefs", text="Go to System")
|
||||
|
||||
|
||||
def extensions_panel_draw_impl(
|
||||
@@ -833,7 +838,16 @@ def extensions_panel_draw(panel, context):
|
||||
if repo_status_text.running:
|
||||
return
|
||||
|
||||
if not prefs.extensions.use_online_access_handled:
|
||||
# Check if the extensions "Welcome" panel should be displayed.
|
||||
# Even though it can be dismissed it's quite "in-your-face" so only show when it's needed.
|
||||
if (
|
||||
# The user didn't dismiss.
|
||||
(not prefs.extensions.use_online_access_handled) and
|
||||
# Running offline.
|
||||
(not bpy.app.online_access) and
|
||||
# There is one or more repositories that require remote access.
|
||||
any(repo for repo in prefs.extensions.repos if repo.enabled and repo.use_remote_url)
|
||||
):
|
||||
extensions_panel_draw_online_extensions_request_impl(panel, context)
|
||||
|
||||
extensions_panel_draw_impl(
|
||||
|
||||
@@ -204,8 +204,7 @@ bUserExtensionRepo *BKE_preferences_extension_repo_add_default(UserDef *userdef)
|
||||
STRNCPY(repo->remote_url, "https://extensions.blender.org/api/v1/extensions");
|
||||
/* Disable `blender.org` by default, the initial "Online Preferences" section gives
|
||||
* the option to enable this. */
|
||||
repo->flag |= USER_EXTENSION_REPO_FLAG_USE_REMOTE_URL | USER_EXTENSION_REPO_FLAG_DISABLED |
|
||||
USER_EXTENSION_REPO_FLAG_SYNC_ON_STARTUP;
|
||||
repo->flag |= USER_EXTENSION_REPO_FLAG_USE_REMOTE_URL | USER_EXTENSION_REPO_FLAG_SYNC_ON_STARTUP;
|
||||
return repo;
|
||||
}
|
||||
|
||||
|
||||
@@ -454,7 +454,34 @@ static void rna_userdef_script_autoexec_update(Main * /*bmain*/,
|
||||
USERDEF_TAG_DIRTY;
|
||||
}
|
||||
|
||||
int rna_userdef_use_online_access_editable(const PointerRNA * /*ptr*/, const char **r_info)
|
||||
static void rna_userdef_use_online_access_set(PointerRNA *ptr, bool value)
|
||||
{
|
||||
/* A `set` function is needed to clear the override flags. */
|
||||
UserDef *userdef = (UserDef *)ptr->data;
|
||||
|
||||
if ((G.f & G_FLAG_INTERNET_ALLOW) == 0) {
|
||||
if (G.f & G_FLAG_INTERNET_OVERRIDE_PREF_OFFLINE) {
|
||||
/* The `editable` check should account for this, assert since this is security related. */
|
||||
BLI_assert_unreachable();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (value) {
|
||||
userdef->flag |= USER_INTERNET_ALLOW;
|
||||
G.f |= G_FLAG_INTERNET_ALLOW;
|
||||
}
|
||||
else {
|
||||
userdef->flag &= ~USER_INTERNET_ALLOW;
|
||||
G.f &= ~G_FLAG_INTERNET_ALLOW;
|
||||
}
|
||||
|
||||
/* Once the user edits this option (even to set it to the value it was)
|
||||
* it's no longer considered overridden. */
|
||||
G.f &= ~G_FLAG_INTERNET_OVERRIDE_PREF_ANY;
|
||||
}
|
||||
|
||||
static int rna_userdef_use_online_access_editable(const PointerRNA * /*ptr*/, const char **r_info)
|
||||
{
|
||||
if ((G.f & G_FLAG_INTERNET_ALLOW) == 0) {
|
||||
/* Return 0 when blender was invoked with `--offline-mode` "forced". */
|
||||
@@ -466,21 +493,6 @@ int rna_userdef_use_online_access_editable(const PointerRNA * /*ptr*/, const cha
|
||||
return PROP_EDITABLE;
|
||||
}
|
||||
|
||||
static void rna_userdef_use_online_access_update(Main * /*bmain*/,
|
||||
Scene * /*scene*/,
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
UserDef *userdef = (UserDef *)ptr->data;
|
||||
if (userdef->flag & USER_INTERNET_ALLOW) {
|
||||
G.f |= G_FLAG_INTERNET_ALLOW;
|
||||
}
|
||||
else {
|
||||
G.f &= ~G_FLAG_INTERNET_ALLOW;
|
||||
}
|
||||
|
||||
USERDEF_TAG_DIRTY;
|
||||
}
|
||||
|
||||
static void rna_userdef_script_directory_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
bUserScriptDirectory *script_dir = static_cast<bUserScriptDirectory *>(ptr->data);
|
||||
@@ -6175,13 +6187,14 @@ static void rna_def_userdef_system(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "use_online_access", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", USER_INTERNET_ALLOW);
|
||||
RNA_def_property_boolean_funcs(prop, nullptr, "rna_userdef_use_online_access_set");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Allow Online Access",
|
||||
"Allow internet access. Blender may access configured online extension repositories. "
|
||||
"Installed third party add-ons may access the internet for their own functionality");
|
||||
RNA_def_property_editable_func(prop, "rna_userdef_use_online_access_editable");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_use_online_access_update");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
|
||||
/* Audio */
|
||||
|
||||
|
||||
@@ -257,6 +257,10 @@ PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
bpy_app_internet_offline_doc,
|
||||
"Boolean, true when internet access is allowed by Blender & 3rd party scripts (read-only)");
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
bpy_app_internet_offline_override_doc,
|
||||
"Boolean, true when internet access preference is overridden by the command line (read-only)");
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
@@ -497,6 +501,11 @@ static PyGetSetDef bpy_app_getsets[] = {
|
||||
nullptr,
|
||||
bpy_app_internet_offline_doc,
|
||||
(void *)G_FLAG_INTERNET_ALLOW},
|
||||
{"online_access_override",
|
||||
bpy_app_global_flag_get,
|
||||
nullptr,
|
||||
bpy_app_internet_offline_override_doc,
|
||||
(void *)G_FLAG_INTERNET_OVERRIDE_PREF_ANY},
|
||||
|
||||
/* security */
|
||||
{"autoexec_fail",
|
||||
|
||||
Reference in New Issue
Block a user