Skip to content

Commit

Permalink
Merge branch 'ut-336-580-info-copy_to' into dev:
Browse files Browse the repository at this point in the history
WIP merge and hopefully the next to last one for wrye-bash#336. Renames was in
the way, this cleans up the situation a bit by moving some of the
copying logic to the info (copy_to), used essentially when we copy
inside the store dir - fs_copy is for the rest of the cases. The real
target here is new_info and friends so this is also about cleaning up
refresh satellites - wrye-bash#353.

Under wrye-bash#580
  • Loading branch information
Utumno committed Jul 26, 2024
2 parents 8e9289a + 2837e68 commit 0a69959
Show file tree
Hide file tree
Showing 11 changed files with 325 additions and 362 deletions.
6 changes: 3 additions & 3 deletions Mopy/bash/_games_lo.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def __write_plugins(self, lord, active):
def upd_on_swap(self, old_dir, new_dir):
pl_path = self.abs_path
# Save plugins.txt inside the old (saves) directory
try: pl_path.copyTo(self._resolve_case_ambiguity(
try: self.fs_copy(self._resolve_case_ambiguity(
old_dir.join(pl_path.stail)))
except FileNotFoundError: pass # no plugins.txt to save
# Move the new plugins.txt here for use
Expand All @@ -164,7 +164,7 @@ def upd_on_swap(self, old_dir, new_dir):
def create_backup(self):
pl_path = self.abs_path
try:
pl_path.copyTo(pl_path.backup)
self.fs_copy(pl_path.backup)
except FileNotFoundError:
bolt.deprint(f'Tried to back up {pl_path}, but it did not exist')
except OSError:
Expand Down Expand Up @@ -662,7 +662,7 @@ def upd_on_swap(self, old_dir, new_dir):
# If there's no INI inside the old (saves) directory, copy it
old_ini = self._resolve_case_ambiguity(old_dir.join(ini_key[0]))
if not old_ini.is_file():
self.abs_path.copyTo(old_ini)
self.fs_copy(old_ini)
# Read from the new INI if it exists and write to our main INI
move_ini = self._resolve_case_ambiguity(new_dir.join(ini_key[0]))
if move_ini.is_file():
Expand Down
23 changes: 8 additions & 15 deletions Mopy/bash/balt.py
Original file line number Diff line number Diff line change
Expand Up @@ -1097,30 +1097,23 @@ def _on_f2_handler(self, is_f2_down, ec_value, uilist_ctrl):
uilist_ctrl.ec_set_selection(*selection_span)
return EventResult.FINISH

def try_rename(self, info, newName, to_select=None, to_del=None,
item_edited=None): # Mods/BSAs
oldName = self._try_rename(info, newName)
if oldName:
if to_select is not None: to_select.add(newName)
if to_del is not None: to_del.add(oldName)
if item_edited and oldName == item_edited[0]:
item_edited[0] = newName
return newName # continue

# Renaming - note the @conversation, this needs to be atomic with respect
# to refreshes and ideally atomic short
# to refreshes and ideally atomic short - store_refr is Installers only
@conversation
def _try_rename(self, info, newFileName):
def try_rename(self, info, newName, store_refr=None):
"""Mods/BSAs - Inis won't be added and Screens/Installers/Saves
override - reduce this."""
try:
return self.data_store.rename_operation(info, newFileName)
return self.data_store.rename_operation(info, newName,
store_refr)[0] # return the renamed keys old -> new
except (CancelError, OSError):
deprint(f'Renaming {info} to {newFileName} failed', traceback=True)
deprint(f'Renaming {info} to {newName} failed', traceback=True)
# When using moveTo I would get "WindowsError:[Error 32]The process
# cannot access ..." - the code below was reverting the changes.
# With shellMove I mostly get CancelError so below not needed -
# except if a save is locked and user presses Skip - so cosaves are
# renamed! Error handling is still a WIP
for old, new in info.get_rename_paths(newFileName):
for old, new in info.get_rename_paths(newName):
if old == new: continue
if (nex := new.exists()) and not (oex := old.exists()):
# some cosave move failed, restore files
Expand Down
102 changes: 46 additions & 56 deletions Mopy/bash/basher/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2167,24 +2167,23 @@ def OnLabelEdited(self, is_edit_cancelled, evt_label, evt_index, evt_item):
if not root:
showError(self, newName)
return EventResult.CANCEL # validate_filename would Veto
item_edited = [self.panel.detailsPanel.displayed_item]
to_select = set()
to_del = set()
item_edited = self.panel.detailsPanel.displayed_item
ren_keys = {}
for saveInfo in self.get_selected_infos_filtered():
if not self.try_rename(saveInfo, root, to_select, to_del,
item_edited): break
if to_select:
self.RefreshUI(redraw=to_select, to_del=to_del, # to_add
detail_item=item_edited[0])
if (ren := self.try_rename(saveInfo, root)) is None: break
ren_keys.update(ren)
if ren_keys:
rdata = bosh.RefrData.from_renamed(ren_keys)
self.RefreshUI(redraw=rdata.redraw, to_del=rdata.to_del,
detail_item=ren_keys.get(item_edited))
#--Reselect the renamed items
self.SelectItemsNoCallback(to_select)
self.SelectItemsNoCallback(rdata.redraw)
return EventResult.CANCEL # needed ! clears new name from label on exception

def try_rename(self, saveinf, new_root, to_select=None, to_del=None,
item_edited=None, force_ext=''):
def try_rename(self, saveinf, new_root, rdata=None, item_edited=None,
force_ext=''):
newFileName = saveinf.unique_key(new_root, force_ext)
return super().try_rename(saveinf, newFileName, to_select, to_del,
item_edited)
return super().try_rename(saveinf, newFileName, rdata, item_edited)

@staticmethod
def _unhide_wildcard():
Expand Down Expand Up @@ -2221,9 +2220,10 @@ def _handle_left_down(self, wrapped_evt, lb_dex_and_flags):
return
do_enable = not sinf.is_save_enabled()
extension = enabled_ext if do_enable else disabled_ext
if rename_res := self.try_rename(sinf, fn_item.fn_body,
force_ext=extension):
self.RefreshUI(redraw=[rename_res], to_del=[fn_item])
if ren_keys := self.try_rename(sinf, fn_item.fn_body,
force_ext=extension):
rdata = bosh.RefrData.from_renamed(ren_keys)
self.RefreshUI(redraw=rdata.redraw, to_del=rdata.to_del)

# Save profiles
def set_local_save(self, new_saves, *, do_swap=None):
Expand Down Expand Up @@ -2397,15 +2397,14 @@ def DoSave(self):
saveInfo.makeBackup() ##: why backup when just renaming - #292
prevMTime = saveInfo.ftime
#--Change Name?
to_del = set()
if changeName:
newName = FName(self.fileStr.strip()).fn_body
# if you were wondering: OnFileEdited checked if file existed,
# and yes we recheck below in unique_key, in Mod/BsaDetails we
# don't - filesystem APIs might warn user (with a dialog hopefully)
# for an overwrite, otherwise we can have a race whatever we try
# here - an extra check can't harm nor makes a (any) difference
self.panel_uilist.try_rename(saveInfo, newName, to_del=to_del)
ren_keys = self.panel_uilist.try_rename(saveInfo, newName)
#--Change masters?
if changeMasters:
prev_masters = saveInfo.masterNames
Expand All @@ -2416,12 +2415,12 @@ def DoSave(self):
saveInfo.setmtime(prevMTime)
detail_item = self._refresh_detail_info()
else: detail_item = self.file_info.fn_key
kwargs = {u'to_del': to_del, u'detail_item': detail_item}
kwargs = {'to_del': set(ren_keys) if changeName else set()}
if detail_item is None:
kwargs[u'to_del'] = to_del | {self.file_info.fn_key}
kwargs['to_del'] |= {self.file_info.fn_key} # we failed rewriting
else:
kwargs[u'redraw'] = [detail_item]
self.panel_uilist.RefreshUI(**kwargs)
self.panel_uilist.RefreshUI(**kwargs, detail_item=detail_item)

def RefreshUIColors(self):
self._update_masters_warning()
Expand Down Expand Up @@ -2557,35 +2556,27 @@ def OnLabelEdited(self, is_edit_cancelled, evt_label, evt_index, evt_item):
if isinstance(root, tuple):
root = root[0]
with BusyCursor():
refreshes = [(False, False, False)]
newselected = []
refreshes = defaultdict(bool) # Store refreshes
ren_keys = {}
try:
for package in selected:
if fail := not self.try_rename(package, root, refreshes,
newselected):
break
finally:
refreshNeeded = modsRefresh = iniRefresh = False
if len(refreshes) > 1:
refreshNeeded, modsRefresh, iniRefresh = [
any(grouped) for grouped in zip(*refreshes)]
ren_keys.update(self.try_rename(package, root, refreshes))
except TypeError:
pass # ren_keys.update(None)
#--Refresh UI
if refreshNeeded or fail: # refresh the UI in case of an exception
self.RefreshUI(refresh_others=(Store.MODS.IF(modsRefresh) |
Store.INIS.IF(iniRefresh)))
if ren_keys:
rdata = bosh.RefrData.from_renamed(ren_keys)
self.RefreshUI(redraw=rdata.redraw, to_del=rdata.to_del,
refresh_others=refreshes)
#--Reselected the renamed items
self.SelectItemsNoCallback(newselected)
self.SelectItemsNoCallback(rdata.redraw)
return EventResult.CANCEL

def try_rename(self, inst_info, new_root, refreshes, newselected):
def try_rename(self, inst_info, new_root, refreshes):
newFileName = inst_info.unique_key(new_root) # preserve extension for installers
if newFileName is None: # just changed extension - continue
return False, False, False
result = self._try_rename(inst_info, newFileName)
if result:
refreshes.append(result)
if result[0]: newselected.append(newFileName)
return newFileName # continue
return {}, {}
return super().try_rename(inst_info, newFileName, refreshes)

@staticmethod
def _unhide_wildcard():
Expand Down Expand Up @@ -3468,28 +3459,27 @@ def OnLabelEdited(self, is_edit_cancelled, evt_label, evt_index, evt_item):
digits = len(f'{(num + len(selected) - 1)}')
numStr = numStr.zfill(digits) if numStr else ''
with BusyCursor():
to_select = set()
to_del = set()
item_edited = [self.panel.detailsPanel.displayed_item]
ren_keys = {}
item_edited = self.panel.detailsPanel.displayed_item
for scrinf in selected:
if not self.try_rename(scrinf, root + numStr, to_select,
to_del, item_edited): break
try:
ren_keys.update(self.try_rename(scrinf, root + numStr))
except TypeError: break
num += 1
numStr = str(num).zfill(digits)
if to_select:
self.RefreshUI(redraw=to_select, to_del=to_del,
detail_item=item_edited[0])
if ren_keys:
rdata = bosh.RefrData.from_renamed(ren_keys)
self.RefreshUI(redraw=rdata.redraw, to_del=rdata.to_del,
detail_item=ren_keys.get(item_edited))
#--Reselected the renamed items
self.SelectItemsNoCallback(to_select)
self.SelectItemsNoCallback(rdata.redraw)
return EventResult.CANCEL

def try_rename(self, scrinf, new_root, to_select=None, to_del=None,
item_edited=None):
def try_rename(self, scrinf, new_root, store_refr=None):
newName = FName(new_root + scrinf.fn_key.fn_ext) # TODO: add ScreenInfo.unique_key()
if scrinf.get_store().store_dir.join(newName).exists():
if scrinf._store().store_dir.join(newName).exists():
return None # break
return super().try_rename(scrinf, newName, to_select, to_del,
item_edited)
return super().try_rename(scrinf, newName, store_refr)

def _handle_key_down(self, wrapped_evt):
# Enter: Open selected screens
Expand Down
Loading

0 comments on commit 0a69959

Please sign in to comment.