Add-on: show warning when versions are not matching
Before submitting a job, the add-on now checks the version of the Manager. If this is not the same version of the add-on, a warning is shown and a "Force Submit" button appears. This makes it both explicit that something is iffy and still allows for pushing forward. This is important when upgrading Flamenco, because I'm sure many people will forget to actually redownload and reinstall the add-on.
This commit is contained in:
parent
2eae682b9a
commit
59f41d0546
@ -37,6 +37,8 @@ def discard_global_flamenco_data(_):
|
|||||||
job_types.discard_flamenco_data()
|
job_types.discard_flamenco_data()
|
||||||
comms.discard_flamenco_data()
|
comms.discard_flamenco_data()
|
||||||
|
|
||||||
|
bpy.context.WindowManager.flamenco_version_mismatch = False
|
||||||
|
|
||||||
|
|
||||||
def redraw(self, context):
|
def redraw(self, context):
|
||||||
if context.area is None:
|
if context.area is None:
|
||||||
@ -118,6 +120,11 @@ def register() -> None:
|
|||||||
max=100,
|
max=100,
|
||||||
update=redraw,
|
update=redraw,
|
||||||
)
|
)
|
||||||
|
bpy.types.WindowManager.flamenco_version_mismatch = bpy.props.BoolProperty(
|
||||||
|
name="Flamenco Ignore Version Mismatch",
|
||||||
|
default=False,
|
||||||
|
description="Ignore version mismatch between add-on and Manager when submitting a job",
|
||||||
|
)
|
||||||
|
|
||||||
# Placeholder to contain the result of a 'ping' to Flamenco Manager,
|
# Placeholder to contain the result of a 'ping' to Flamenco Manager,
|
||||||
# so that it can be shown in the preferences panel.
|
# so that it can be shown in the preferences panel.
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
# <pep8 compliant>
|
# <pep8 compliant>
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import dataclasses
|
||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from urllib3.exceptions import HTTPError, MaxRetryError
|
from urllib3.exceptions import HTTPError, MaxRetryError
|
||||||
@ -25,6 +26,23 @@ else:
|
|||||||
_ManagerConfiguration = object
|
_ManagerConfiguration = object
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(frozen=True)
|
||||||
|
class ManagerInfo:
|
||||||
|
version: Optional[_FlamencoVersion] = None
|
||||||
|
config: Optional[_ManagerConfiguration] = None
|
||||||
|
error: str = ""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def with_error(cls, error: str) -> "ManagerInfo":
|
||||||
|
return cls(error=error)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def with_info(
|
||||||
|
cls, version: _FlamencoVersion, config: _ManagerConfiguration
|
||||||
|
) -> "ManagerInfo":
|
||||||
|
return cls(version=version, config=config)
|
||||||
|
|
||||||
|
|
||||||
def flamenco_api_client(manager_url: str) -> _ApiClient:
|
def flamenco_api_client(manager_url: str) -> _ApiClient:
|
||||||
"""Returns an API client for communicating with a Manager."""
|
"""Returns an API client for communicating with a Manager."""
|
||||||
global _flamenco_client
|
global _flamenco_client
|
||||||
@ -45,6 +63,18 @@ def flamenco_api_client(manager_url: str) -> _ApiClient:
|
|||||||
return _flamenco_client
|
return _flamenco_client
|
||||||
|
|
||||||
|
|
||||||
|
def flamenco_client_version() -> str:
|
||||||
|
"""Return the version of the Flamenco OpenAPI client."""
|
||||||
|
|
||||||
|
from . import dependencies
|
||||||
|
|
||||||
|
dependencies.preload_modules()
|
||||||
|
|
||||||
|
from . import manager
|
||||||
|
|
||||||
|
return manager.__version__
|
||||||
|
|
||||||
|
|
||||||
def discard_flamenco_data():
|
def discard_flamenco_data():
|
||||||
global _flamenco_client
|
global _flamenco_client
|
||||||
|
|
||||||
@ -57,7 +87,9 @@ def discard_flamenco_data():
|
|||||||
|
|
||||||
|
|
||||||
def ping_manager_with_report(
|
def ping_manager_with_report(
|
||||||
context: bpy.types.Context, api_client: _ApiClient, prefs: _FlamencoPreferences
|
window_manager: bpy.types.WindowManager,
|
||||||
|
api_client: _ApiClient,
|
||||||
|
prefs: _FlamencoPreferences,
|
||||||
) -> tuple[str, str]:
|
) -> tuple[str, str]:
|
||||||
"""Ping the Manager, update preferences, and return a report as string.
|
"""Ping the Manager, update preferences, and return a report as string.
|
||||||
|
|
||||||
@ -67,26 +99,23 @@ def ping_manager_with_report(
|
|||||||
`Operator.report()`.
|
`Operator.report()`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
context.window_manager.flamenco_status_ping = "..."
|
info = ping_manager(window_manager, api_client, prefs)
|
||||||
|
if info.error:
|
||||||
|
return info.error, "ERROR"
|
||||||
|
|
||||||
version, _, err = ping_manager(api_client, prefs)
|
assert info.version is not None
|
||||||
if err:
|
report = "%s version %s found" % (info.version.name, info.version.version)
|
||||||
context.window_manager.flamenco_status_ping = err
|
|
||||||
return err, "ERROR"
|
|
||||||
|
|
||||||
assert version is not None
|
|
||||||
report = "%s version %s found" % (version.name, version.version)
|
|
||||||
context.window_manager.flamenco_status_ping = report
|
|
||||||
return report, "INFO"
|
return report, "INFO"
|
||||||
|
|
||||||
|
|
||||||
def ping_manager(
|
def ping_manager(
|
||||||
api_client: _ApiClient, prefs: _FlamencoPreferences
|
window_manager: bpy.types.WindowManager,
|
||||||
) -> tuple[Optional[_FlamencoVersion], Optional[_ManagerConfiguration], str]:
|
api_client: _ApiClient,
|
||||||
"""Fetch Manager config & version, and update preferences.
|
prefs: _FlamencoPreferences,
|
||||||
|
) -> ManagerInfo:
|
||||||
|
"""Fetch Manager config & version, and update cached preferences."""
|
||||||
|
|
||||||
:returns: tuple (version, config, error).
|
window_manager.flamenco_status_ping = "..."
|
||||||
"""
|
|
||||||
|
|
||||||
# Do a late import, so that the API is only imported when actually used.
|
# Do a late import, so that the API is only imported when actually used.
|
||||||
from flamenco.manager import ApiException
|
from flamenco.manager import ApiException
|
||||||
@ -94,21 +123,29 @@ def ping_manager(
|
|||||||
from flamenco.manager.models import FlamencoVersion, ManagerConfiguration
|
from flamenco.manager.models import FlamencoVersion, ManagerConfiguration
|
||||||
|
|
||||||
meta_api = MetaApi(api_client)
|
meta_api = MetaApi(api_client)
|
||||||
|
error = ""
|
||||||
try:
|
try:
|
||||||
version: FlamencoVersion = meta_api.get_version()
|
version: FlamencoVersion = meta_api.get_version()
|
||||||
config: ManagerConfiguration = meta_api.get_configuration()
|
config: ManagerConfiguration = meta_api.get_configuration()
|
||||||
except ApiException as ex:
|
except ApiException as ex:
|
||||||
return (None, None, "Manager cannot be reached: %s" % ex)
|
error = "Manager cannot be reached: %s" % ex
|
||||||
except MaxRetryError as ex:
|
except MaxRetryError as ex:
|
||||||
# This is the common error, when for example the port number is
|
# This is the common error, when for example the port number is
|
||||||
# incorrect and nothing is listening. The exception text is not included
|
# incorrect and nothing is listening. The exception text is not included
|
||||||
# because it's very long and confusing.
|
# because it's very long and confusing.
|
||||||
return (None, None, "Manager cannot be reached")
|
error = "Manager cannot be reached"
|
||||||
except HTTPError as ex:
|
except HTTPError as ex:
|
||||||
return (None, None, "Manager cannot be reached: %s" % ex)
|
error = "Manager cannot be reached: %s" % ex
|
||||||
|
|
||||||
|
if error:
|
||||||
|
window_manager.flamenco_status_ping = error
|
||||||
|
return ManagerInfo.with_error(error)
|
||||||
|
|
||||||
# Store whether this Manager supports the Shaman API.
|
# Store whether this Manager supports the Shaman API.
|
||||||
prefs.is_shaman_enabled = config.shaman_enabled
|
prefs.is_shaman_enabled = config.shaman_enabled
|
||||||
prefs.job_storage = config.storage_location
|
prefs.job_storage = config.storage_location
|
||||||
|
|
||||||
return version, config, ""
|
report = "%s version %s found" % (version.name, version.version)
|
||||||
|
window_manager.flamenco_status_ping = report
|
||||||
|
|
||||||
|
return ManagerInfo.with_info(version, config)
|
||||||
|
@ -133,13 +133,7 @@ class FLAMENCO_PT_job_submission(bpy.types.Panel):
|
|||||||
# Show current status of Flamenco.
|
# Show current status of Flamenco.
|
||||||
flamenco_status = context.window_manager.flamenco_bat_status
|
flamenco_status = context.window_manager.flamenco_bat_status
|
||||||
if flamenco_status in {"IDLE", "ABORTED", "DONE"}:
|
if flamenco_status in {"IDLE", "ABORTED", "DONE"}:
|
||||||
ui = layout
|
self.draw_submit_button(context, layout)
|
||||||
props = ui.operator(
|
|
||||||
"flamenco.submit_job",
|
|
||||||
text="Submit to Flamenco",
|
|
||||||
icon="RENDER_ANIMATION",
|
|
||||||
)
|
|
||||||
props.job_name = context.scene.flamenco_job_name
|
|
||||||
elif flamenco_status == "INVESTIGATING":
|
elif flamenco_status == "INVESTIGATING":
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text="Investigating your files")
|
row.label(text="Investigating your files")
|
||||||
@ -163,6 +157,28 @@ class FLAMENCO_PT_job_submission(bpy.types.Panel):
|
|||||||
):
|
):
|
||||||
layout.label(text=context.window_manager.flamenco_bat_status_txt)
|
layout.label(text=context.window_manager.flamenco_bat_status_txt)
|
||||||
|
|
||||||
|
def draw_submit_button(
|
||||||
|
self, context: bpy.types.Context, layout: bpy.types.UILayout
|
||||||
|
) -> None:
|
||||||
|
row = layout.row(align=True)
|
||||||
|
|
||||||
|
props = row.operator(
|
||||||
|
"flamenco.submit_job",
|
||||||
|
text="Submit to Flamenco",
|
||||||
|
icon="RENDER_ANIMATION",
|
||||||
|
)
|
||||||
|
props.job_name = context.scene.flamenco_job_name
|
||||||
|
props.ignore_version_mismatch = False
|
||||||
|
|
||||||
|
if context.window_manager.flamenco_version_mismatch:
|
||||||
|
props = row.operator(
|
||||||
|
"flamenco.submit_job",
|
||||||
|
text="Force Submit",
|
||||||
|
icon="NONE",
|
||||||
|
)
|
||||||
|
props.job_name = context.scene.flamenco_job_name
|
||||||
|
props.ignore_version_mismatch = True
|
||||||
|
|
||||||
|
|
||||||
classes = (FLAMENCO_PT_job_submission,)
|
classes = (FLAMENCO_PT_job_submission,)
|
||||||
register, unregister = bpy.utils.register_classes_factory(classes)
|
register, unregister = bpy.utils.register_classes_factory(classes)
|
||||||
|
@ -86,7 +86,9 @@ class FLAMENCO_OT_ping_manager(FlamencoOpMixin, bpy.types.Operator):
|
|||||||
api_client = self.get_api_client(context)
|
api_client = self.get_api_client(context)
|
||||||
prefs = preferences.get(context)
|
prefs = preferences.get(context)
|
||||||
|
|
||||||
report, level = comms.ping_manager_with_report(context, api_client, prefs)
|
report, level = comms.ping_manager_with_report(
|
||||||
|
context.window_manager, api_client, prefs
|
||||||
|
)
|
||||||
self.report({level}, report)
|
self.report({level}, report)
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@ -122,6 +124,10 @@ class FLAMENCO_OT_submit_job(FlamencoOpMixin, bpy.types.Operator):
|
|||||||
job_name: bpy.props.StringProperty(name="Job Name") # type: ignore
|
job_name: bpy.props.StringProperty(name="Job Name") # type: ignore
|
||||||
job: Optional[_SubmittedJob] = None
|
job: Optional[_SubmittedJob] = None
|
||||||
temp_blendfile: Optional[Path] = None
|
temp_blendfile: Optional[Path] = None
|
||||||
|
ignore_version_mismatch: bpy.props.BoolProperty( # type: ignore
|
||||||
|
name="Ignore Version Mismatch",
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
|
||||||
timer: Optional[bpy.types.Timer] = None
|
timer: Optional[bpy.types.Timer] = None
|
||||||
packthread: Optional[_PackThread] = None
|
packthread: Optional[_PackThread] = None
|
||||||
@ -135,6 +141,16 @@ class FLAMENCO_OT_submit_job(FlamencoOpMixin, bpy.types.Operator):
|
|||||||
return job_type is not None
|
return job_type is not None
|
||||||
|
|
||||||
def invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> set[str]:
|
def invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> set[str]:
|
||||||
|
# Before doing anything, make sure the info we cached about the Manager
|
||||||
|
# is up to date. A change in job storage directory on the Manager can
|
||||||
|
# cause nasty error messages when we submit, and it's better to just be
|
||||||
|
# ahead of the curve and refresh first. This also allows for checking
|
||||||
|
# the actual Manager version before submitting.
|
||||||
|
err = self._check_manager(context)
|
||||||
|
if err:
|
||||||
|
self.report({"WARNING"}, err)
|
||||||
|
return {"CANCELLED"}
|
||||||
|
|
||||||
filepath = self._save_blendfile(context)
|
filepath = self._save_blendfile(context)
|
||||||
|
|
||||||
# Construct the Job locally before trying to pack. If any validations fail, better fail early.
|
# Construct the Job locally before trying to pack. If any validations fail, better fail early.
|
||||||
@ -160,6 +176,51 @@ class FLAMENCO_OT_submit_job(FlamencoOpMixin, bpy.types.Operator):
|
|||||||
|
|
||||||
return self._on_bat_pack_msg(context, msg)
|
return self._on_bat_pack_msg(context, msg)
|
||||||
|
|
||||||
|
def _check_manager(self, context: bpy.types.Context) -> str:
|
||||||
|
"""Check the Manager version & fetch the job storage directory.
|
||||||
|
|
||||||
|
:return: an error string when something went wrong.
|
||||||
|
"""
|
||||||
|
from . import comms, preferences
|
||||||
|
|
||||||
|
# Get the manager's info. This is cached in the preferences, so
|
||||||
|
# regardless of whether this function actually responds to version
|
||||||
|
# mismatches, it has to be called to also refresh the shared storage
|
||||||
|
# location.
|
||||||
|
api_client = self.get_api_client(context)
|
||||||
|
prefs = preferences.get(context)
|
||||||
|
mgrinfo = comms.ping_manager(context.window_manager, api_client, prefs)
|
||||||
|
if mgrinfo.error:
|
||||||
|
return mgrinfo.error
|
||||||
|
|
||||||
|
# Check the Manager's version.
|
||||||
|
if not self.ignore_version_mismatch:
|
||||||
|
my_version = comms.flamenco_client_version()
|
||||||
|
assert mgrinfo.version is not None
|
||||||
|
|
||||||
|
try:
|
||||||
|
mgrversion = mgrinfo.version.shortversion
|
||||||
|
except AttributeError:
|
||||||
|
# shortversion was introduced in Manager version 3.0-beta2, which
|
||||||
|
# may not be running here yet.
|
||||||
|
mgrversion = mgrinfo.version.version
|
||||||
|
if mgrversion != my_version:
|
||||||
|
context.window_manager.flamenco_version_mismatch = True
|
||||||
|
return (
|
||||||
|
f"Manager ({mgrversion}) and this add-on ({my_version}) version "
|
||||||
|
+ "mismatch, either update the add-on or force the submission"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Un-set the 'flamenco_version_mismatch' when the versions match or when
|
||||||
|
# one forced submission is done. Each submission has to go through the
|
||||||
|
# same cycle of submitting, seeing the warning, then explicitly ignoring
|
||||||
|
# the mismatch, to make it a concious decision to keep going with
|
||||||
|
# potentially incompatible versions.
|
||||||
|
context.window_manager.flamenco_version_mismatch = False
|
||||||
|
|
||||||
|
# Empty error message indicates 'ok'.
|
||||||
|
return ""
|
||||||
|
|
||||||
def _save_blendfile(self, context):
|
def _save_blendfile(self, context):
|
||||||
"""Save to a different file, specifically for Flamenco.
|
"""Save to a different file, specifically for Flamenco.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user