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
5 changed files with 78 additions and 45 deletions
Showing only changes of commit 4ed9415165 - Show all commits

View File

@ -177,7 +177,7 @@ class SVN_OT_download_file_revision(May_Modifiy_Current_Blend, Operator):
missing_file_allowed = True
revision: IntProperty()
revision: IntProperty(default=0)
def invoke(self, context, event):
file_entry = context.scene.svn.get_repo(
@ -198,18 +198,24 @@ class SVN_OT_download_file_revision(May_Modifiy_Current_Blend, Operator):
"Cancelled: You have local modifications to this file. You must revert or commit it first!")
return {'CANCELLED'}
self.execute_svn_command(
context,
["svn", "up", f"-r{self.revision}",
f"{self.file_rel_path}", "--accept", "postpone"],
use_cred=True
)
self.svn_download_file_revision(context, self.file_rel_path, self.revision)
self.report({'INFO'},
f"Checked out revision {self.revision} of {self.file_rel_path}")
return {"FINISHED"}
def svn_download_file_revision(self, context, svn_file_path: str, revision=0):
commands = ["svn", "up", f"{self.file_rel_path}", "--accept", "postpone"]
if self.revision > 0:
commands.insert(2, f"-r{self.revision}")
self.execute_svn_command(
context,
commands,
use_cred=True
)
def set_predicted_file_status(self, repo, file_entry: "SVN_file"):
file_entry['revision'] = self.revision
latest_rev = repo.get_latest_revision_of_file(self.file_rel_path)
@ -229,13 +235,14 @@ class SVN_OT_restore_file(May_Modifiy_Current_Blend, Operator):
missing_file_allowed = True
def _execute(self, context: Context) -> Set[str]:
def svn_revert(self, context, svn_file_path):
self.execute_svn_command(
context,
["svn", "revert", f"{self.file_rel_path}"]
["svn", "revert", f"{svn_file_path}"]
)
f = self.get_file(context)
def _execute(self, context: Context) -> Set[str]:
self.svn_revert(context, self.file_rel_path)
return {"FINISHED"}
def set_predicted_file_status(self, repo, file_entry: "SVN_file"):
@ -250,15 +257,35 @@ class SVN_OT_revert_file(SVN_OT_restore_file):
missing_file_allowed = False
def _execute(self, context: Context) -> Set[str]:
super()._execute(context)
return {"FINISHED"}
def get_warning_text(self, context) -> str:
return "You will irreversibly and permanently lose the changes you've made to this file:\n " + self.file_rel_path
class SVN_OT_revert_and_update(SVN_OT_download_file_revision, SVN_OT_revert_file):
"""Convenience operator for the "This file is outdated" warning message. Normally, these two operations should be done separately!"""
bl_idname = "svn.revert_and_update_file"
bl_label = "Revert And Update File"
bl_description = "The currently opened .blend file has a newer version available on the remote repository. Click to PERMANENTLY DISCARD local changes to this file and update it to the latest revision. Cannot be undone"
bl_options = {'INTERNAL'}
missing_file_allowed = False
def invoke(self, context, event):
return super(May_Modifiy_Current_Blend, self).invoke(context, event)
def get_warning_text(self, context) -> str:
if self.get_file(context).status != 'normal':
return "You will irreversibly and permanently lose the changes you've made to this file:\n " + self.file_rel_path
else:
return "File will be updated to latest revision."
def _execute(self, context: Context) -> Set[str]:
self.svn_revert(context, self.file_rel_path)
self.svn_download_file_revision(context, self.file_rel_path, self.revision)
return {"FINISHED"}
class SVN_OT_add_file(SVN_Operator_Single_File, Operator):
bl_idname = "svn.add_file"
bl_label = "Add File"
@ -411,15 +438,13 @@ class SVN_OT_cleanup(SVN_Operator, Operator):
self.execute_svn_command(context, ["svn", "cleanup"])
repo.reload_svn_log(context)
Processes.kill('Status')
Processes.kill('Log')
Processes.kill('Commit')
Processes.kill('Update')
Processes.kill('Authenticate')
Processes.kill('Activate File')
Processes.start('Status')
Processes.start('Log')
Processes.restart('Status')
Processes.restart('Log')
self.report({'INFO'}, "SVN Cleanup complete.")
@ -428,13 +453,14 @@ class SVN_OT_cleanup(SVN_Operator, Operator):
registry = [
SVN_OT_update_single,
SVN_OT_download_file_revision,
SVN_OT_revert_file,
SVN_OT_revert_and_update,
SVN_OT_restore_file,
SVN_OT_unadd_file,
SVN_OT_revert_file,
SVN_OT_download_file_revision,
SVN_OT_add_file,
SVN_OT_unadd_file,
SVN_OT_trash_file,
SVN_OT_remove_file,
SVN_OT_cleanup,
SVN_OT_resolve_conflict,
SVN_OT_cleanup,
]

View File

@ -214,6 +214,7 @@ class ProcessManager:
def processes(self):
# I tried to implement this thing as a Singleton that inherits from the `dict` class,
# I tried having the `processes` dict on the class level,
# I tried having it on the instance level,
# and it just refuses to work properly. I add an instance to the dictionary,
# I print it, I can see that it's there, I make sure it absolutely doesn't get removed,
# but when I try to access it from anywhere, it's just empty. My mind is boggled.
@ -260,6 +261,12 @@ class ProcessManager:
if process:
process.stop()
del self.processes[proc_name]
def restart(self, proc_name: str):
"""Destroy a process, then start it again.
Useful to skip the repeat_delay timer of infinite processes like Status or Log."""
self.kill(proc_name)
self.start(proc_name)
# I named this variable with title-case, to indicate that it's a Singleton.

View File

@ -55,8 +55,9 @@ class SVN_OT_explain_status(Operator):
@bpy.app.handlers.persistent
def init_svn_of_current_file(_scene=None):
"""When opening or saving a .blend file:
def ensure_svn_of_current_file(_scene=None):
"""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
@ -68,6 +69,17 @@ def init_svn_of_current_file(_scene=None):
prefs = get_addon_prefs(context)
prefs.sync_repo_info_file()
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
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.
@ -338,22 +350,22 @@ def mark_current_file_as_modified(_dummy1=None, _dummy2=None):
def delayed_init_svn(delay=1):
bpy.app.timers.register(init_svn_of_current_file, first_interval=delay)
bpy.app.timers.register(ensure_svn_of_current_file, first_interval=delay)
def register():
bpy.app.handlers.load_post.append(init_svn_of_current_file)
bpy.app.handlers.load_post.append(ensure_svn_of_current_file)
bpy.app.handlers.save_post.append(init_svn_of_current_file)
bpy.app.handlers.save_post.append(ensure_svn_of_current_file)
bpy.app.handlers.save_post.append(mark_current_file_as_modified)
delayed_init_svn()
def unregister():
bpy.app.handlers.load_post.remove(init_svn_of_current_file)
bpy.app.handlers.load_post.remove(ensure_svn_of_current_file)
bpy.app.handlers.save_post.remove(init_svn_of_current_file)
bpy.app.handlers.save_post.remove(ensure_svn_of_current_file)
bpy.app.handlers.save_post.remove(mark_current_file_as_modified)

View File

@ -114,6 +114,7 @@ class SVN_UL_file_list(UIList):
explainer.status = status
explainer.file_rel_path = file_entry.svn_path
@classmethod
def cls_filter_items(cls, context, data, propname):
"""By moving all of this logic to a classmethod (and all the filter
@ -188,13 +189,6 @@ def draw_repo_file_list(context, layout, repo):
return
main_col = layout.column()
main_col.enabled = False
status_proc = Processes.get('Status')
time_since_last_update = 1000
if status_proc:
time_since_last_update = time.time() - status_proc.timestamp_last_update
if time_since_last_update < 30:
main_col.enabled = True
main_row = main_col.row()
split = main_row.split(factor=0.6)
filepath_row = split.row()
@ -207,11 +201,6 @@ def draw_repo_file_list(context, layout, repo):
ops_row.alignment = 'RIGHT'
ops_row.label(text="Operations")
timer_row = main_row.row()
timer_row.alignment = 'RIGHT'
timer_row.operator("svn.custom_tooltip", icon='BLANK1', text="",
emboss=False).tooltip = "Time since last file status update: " + str(time_since_last_update) + 's'
row = main_col.row()
row.template_list(
"SVN_UL_file_list",

View File

@ -28,9 +28,8 @@ def draw_outdated_file_warning(self, context):
row.operator('svn.resolve_conflict',
text="SVN: This .blend file is conflicted.", icon='ERROR')
elif current_file.repos_status != 'none':
warning = row.operator(
'svn.custom_tooltip', text="SVN: This .blend file is outdated.", icon='ERROR')
warning.tooltip = "The currently opened .blend file has a newer version available on the remote repository. This means any changes in this file will result in a conflict, and potential loss of data. See the SVN panel for info"
op = row.operator('svn.revert_and_update_file', text="SVN: This .blend file is outdated.", icon='ERROR')
op.file_rel_path = repo.current_blend_file.svn_path
def register():