SVN: UX improvements #136

Merged
Demeter Dzadik merged 15 commits from Mets/blender-studio-pipeline:svn_ux_improvements into main 2023-08-01 15:39:18 +02:00
10 changed files with 56 additions and 131 deletions
Showing only changes of commit cbdb3e14a3 - Show all commits

View File

@ -445,6 +445,7 @@ class SVN_OT_cleanup(SVN_Operator, Operator):
Processes.restart('Status')
Processes.restart('Log')
Processes.restart('Redraw Viewport')
self.report({'INFO'}, "SVN Cleanup complete.")

View File

@ -28,7 +28,6 @@ class SVN_OT_checkout_initiate(Operator):
def execute(self, context):
prefs = get_addon_prefs(context)
prefs.active_repo_mode = 'SELECTED_REPO'
if self.create:
prefs.repositories.add()
prefs.active_repo_idx = len(prefs.repositories)-1

View File

@ -46,39 +46,29 @@ class SVN_addon_preferences(AddonPreferences):
repo = self.repositories.add()
repo.initialize(root_dir, base_url)
self.active_repo_idx = len(self.repositories)-1
return repo
def update_active_repo_idx(self, context):
if self.idx_updating or len(self.repositories) == 0:
if len(self.repositories) == 0:
return
self.idx_updating = True
active_repo = self.active_repo
if self.active_repo_mode == 'CURRENT_BLEND':
scene_svn = context.scene.svn
scene_svn_idx = self.repositories.find(scene_svn.svn_directory)
if scene_svn_idx == -1:
self.idx_updating = False
return
self.active_repo_idx = scene_svn_idx
self.idx_updating = False
return
# Authenticate when switching repos.
if (
active_repo and
not active_repo.authenticated and
not active_repo.auth_failed and
active_repo.is_cred_entered
):
active_repo.authenticate(context)
Processes.start('Redraw Viewport')
if active_repo.authenticated:
Processes.restart('Status')
else:
active_repo.authenticate(context)
else:
Processes.kill('Status')
self.idx_updating = False
def update_active_repo_mode(self, context):
if self.active_repo_mode == 'CURRENT_BLEND':
scene_svn = context.scene.svn
scene_svn_idx = self.repositories.find(scene_svn.svn_directory)
self.active_repo_idx = scene_svn_idx
checkout_mode: BoolProperty(
name="Checkout In Progress",
@ -86,30 +76,16 @@ class SVN_addon_preferences(AddonPreferences):
default=False
)
active_repo_mode: EnumProperty(
name="Choose Repository",
description="Whether the add-on should communicate with the repository of the currently opened .blend file, or the repository selected in the list below",
items=[
('CURRENT_BLEND', "Current Blend", "Check if the current .blend file is in an SVN repository, and communicate with that if that is the case. The file list will display only the files of the repository of the current .blend file. If the current .blend is not in a repository, do nothing"),
('SELECTED_REPO', "Selected Repo",
"Communicate with the selected repository")
],
default='CURRENT_BLEND',
update=update_active_repo_mode
)
active_repo_idx: IntProperty(
name="SVN Repositories",
options=set(),
update=update_active_repo_idx
)
idx_updating: BoolProperty(
name="Index is Updating",
description="Helper flag to avoid infinite looping update callbacks",
)
@property
def active_repo(self) -> SVN_repository:
def active_repo(self) -> Optional[SVN_repository]:
if not self.is_svn_installed:
return
if 0 <= self.active_repo_idx <= len(self.repositories)-1:
return self.repositories[self.active_repo_idx]

View File

@ -28,33 +28,10 @@ class SVN_scene_properties(PropertyGroup):
)
def get_repo(self, context) -> Optional['SVN_repository']:
"""Return the current repository.
Depending on preferences, this is either the repo the current .blend file is in,
or whatever repo is selected in the preferences UI.
"""
"""Return the active repository."""
prefs = get_addon_prefs(context)
if not prefs.is_svn_installed:
return
return prefs.active_repo
if prefs.active_repo_mode == 'CURRENT_BLEND':
return self.get_scene_repo(context)
else:
return prefs.active_repo
def get_scene_repo(self, context) -> Optional['SVN_repository']:
"""Return the repository of the current file, even if the add-on is
configured to another repository.
"""
prefs = get_addon_prefs(context)
if not prefs.is_svn_installed:
return
if not self.svn_url or not self.svn_directory:
return
for repo in prefs.repositories:
if (repo.url == self.svn_url) and (Path(repo.directory) == Path(self.svn_directory)):
return repo
registry = [
SVN_scene_properties,

View File

@ -305,9 +305,9 @@ class SVN_repository(PropertyGroup):
)
@property
def is_cred_entered(self):
def is_cred_entered(self) -> bool:
"""Check if there's a username and password entered at all."""
return self.username and self.password
return bool(self.username and self.password)
authenticated: BoolProperty(
name="Authenticated",

View File

@ -44,7 +44,7 @@ class BackgroundProcess:
# Displayed in the tooltip on mouse-hover in the error message when an error occurs.
error_description = "SVN Error:"
debug = True
debug = False
def debug_print(self, msg: str):
if self.debug:
@ -82,7 +82,7 @@ class BackgroundProcess:
def handle_error(self, context, error):
self.output = ""
self.error = error.stderr.decode()
self.is_running = False
self.stop()
def process_output(self, context, prefs):
"""
@ -113,7 +113,7 @@ class BackgroundProcess:
repo = context.scene.svn.get_repo(context)
if not repo:
self.debug_print("Shutdown: Not in repo.")
self.is_running = False
self.stop()
return
prefs = get_addon_prefs(context)
@ -127,7 +127,7 @@ class BackgroundProcess:
if self.needs_authentication and not repo.authenticated:
self.debug_print("Shutdown: Authentication needed.")
self.is_running = False
self.stop()
return
if not self.thread or not self.thread.is_alive() and not self.output and not self.error:
@ -146,15 +146,14 @@ class BackgroundProcess:
self.output = ""
redraw_viewport()
if self.repeat_delay == 0:
self.debug_print(
"Shutdown: Output was processed, repeat_delay==0.")
self.is_running = False
self.debug_print("Shutdown: Output was processed, repeat_delay==0.")
self.stop()
return
self.debug_print(f"Processed output. Waiting {self.repeat_delay}")
return self.repeat_delay
elif not self.thread and not self.thread.is_alive() and self.repeat_delay == 0:
self.debug_print("Shutdown: Finished.\n")
self.is_running = False
self.stop()
return
self.debug_print(f"Tick delay: {self.tick_delay}")
@ -188,6 +187,7 @@ class BackgroundProcess:
def stop(self):
"""Stop the process if it isn't running, by unregistering its timer function"""
self.debug_print("stop() function was called.")
self.is_running = False
if bpy.app.timers.is_registered(self.timer_function):
# This won't work if the timer has returned None at any point, as that

View File

@ -7,6 +7,7 @@ class BGP_SVN_Redraw_Viewport(BackgroundProcess):
repeat_delay = 1
debug = False
tick_delay = 1
needs_authentication = False
def tick(self, context, prefs):
redraw_viewport()

View File

@ -56,13 +56,12 @@ class SVN_OT_explain_status(Operator):
@bpy.app.handlers.persistent
def ensure_svn_of_current_file(_scene=None):
"""When opening or saving a .blend file, it's possible that the new .blend
"""When opening or saving a .blend file, it's possible that the new .blend
is part of an SVN repository. If this is the case, do the following:
- Initialize SVN Scene info
- Initialize Repository
- Try to authenticate
- Check if this file's repository is already in our database
- If not, create it
- Switch to that repo
"""
context = bpy.context
prefs = get_addon_prefs(context)
prefs.is_svn_installed = check_svn_installed()
@ -71,52 +70,42 @@ def ensure_svn_of_current_file(_scene=None):
scene_svn = context.scene.svn
# If we have any repository entries, make sure at least one is active.
prefs.sync_repo_info_file()
if prefs.active_repo_idx == -1 and len(prefs.repositories) > 0:
prefs.active_repo_idx = 0
elif prefs.active_repo_idx > len(prefs.repositories)-1:
prefs.active_repo_idx = 0
else:
prefs.active_repo_idx = prefs.active_repo_idx
repo = prefs.active_repo
if repo and repo.is_cred_entered and repo.authenticated:
status = Processes.get('Status')
if status and time.time() - status.timestamp_last_update < status.repeat_delay + 5:
# If the SVN Status background process has recently processed data,
# there is no need to re-initialize everything.
# This happens when a file that was already saved is saved again,
# or a file from the same repository as the previous one is loaded.
Processes.restart('Status')
return
# If the file is unsaved, nothing more to do.
if not bpy.data.filepath:
scene_svn.svn_url = ""
return
# If file is not in a repo, nothing more to do.
is_in_repo = set_scene_svn_info(context)
if not is_in_repo:
return
# If we switched repos, reset auth flags and authenticate the new repo.
for repo in prefs.repositories:
# This would ideally only run when opening Blender for the first
# time, but there is no app handler for that, sadly.
repo.authenticated = False
repo.auth_failed = False
if prefs.active_repo_mode == 'CURRENT_BLEND':
if not bpy.data.filepath:
scene_svn.svn_url = ""
return
is_in_repo = set_scene_svn_info(context)
if not is_in_repo:
return
repo = scene_svn.get_scene_repo(context)
if not repo:
repo = prefs.init_repo(context, scene_svn.svn_directory)
for i, other_repo in enumerate(prefs.repositories):
if other_repo == repo:
prefs.active_repo_idx = i
# If file is in an existing repo, we should switch over to that repo.
for i, existing_repo in enumerate(prefs.repositories):
if ( existing_repo.url == scene_svn.svn_url and
existing_repo.directory == scene_svn.svn_directory
):
prefs.active_repo_idx = i
break
else:
repo = prefs.active_repo
if not repo:
return
if repo.is_cred_entered:
repo.authenticate(context)
# If file is in a non-existing repo, initialize that repo.
repo = prefs.init_repo(context, scene_svn.svn_directory)
def set_scene_svn_info(context) -> bool:

View File

@ -18,9 +18,6 @@ class SVN_UL_repositories(UIList):
repo = item
row = layout.row()
prefs = get_addon_prefs(context)
if prefs.active_repo_mode == 'CURRENT_BLEND' and repo != context.scene.svn.get_repo(context):
row.enabled = False
row.label(text=repo.display_name)
if not repo.dir_exists:
@ -198,10 +195,6 @@ def draw_prefs_checkout(self, context):
def draw_prefs_repos(self, context) -> None:
layout = self.layout
row = layout.row()
row.use_property_split = True
row.prop(self, 'active_repo_mode', expand=True)
auth_in_progress = False
auth_error = False
auth_proc = Processes.get('Authenticate')
@ -209,12 +202,6 @@ def draw_prefs_repos(self, context) -> None:
auth_in_progress = auth_proc.is_running
auth_error = auth_proc.error
if self.active_repo_mode == 'CURRENT_BLEND' and not context.scene.svn.get_repo(context):
split = layout.split(factor=0.4)
split.row()
split.row().label(text="Current file is not in a repository.")
return
repo_col = layout.column()
split = repo_col.row().split()
split.row().label(text="SVN Repositories:")

View File

@ -16,12 +16,7 @@ class VIEW3D_PT_svn_credentials(Panel):
@classmethod
def poll(cls, context):
prefs = get_addon_prefs(context)
if prefs.active_repo_mode == 'CURRENT_BLEND':
repo = context.scene.svn.get_scene_repo(context)
else:
repo = context.scene.svn.get_repo(context)
repo = context.scene.svn.get_repo(context)
return repo and not repo.authenticated
def draw(self, context):