Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev' into 570-launchers-menu-gaz
Browse files Browse the repository at this point in the history
# Conflicts:
#	requirements.txt
  • Loading branch information
BGazotti committed May 4, 2024
2 parents 2676bd9 + 31cab09 commit b974fb9
Show file tree
Hide file tree
Showing 17 changed files with 136 additions and 113 deletions.
24 changes: 11 additions & 13 deletions Mopy/bash/basher/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
from collections import OrderedDict, defaultdict, namedtuple
from collections.abc import Iterable
from functools import partial
from itertools import chain
from itertools import chain, repeat

import wx

Expand Down Expand Up @@ -520,21 +520,19 @@ def SetFileInfo(self,fileInfo):
#--Fill data and populate
self._update_real_indices(fileInfo)
self.is_inaccurate = fileInfo.has_inaccurate_masters
if isinstance(fileInfo, bosh.ModInfo):
can_have_sizes = bush.game.Esp.check_master_sizes
can_have_esl = False
else:
can_have_sizes = False
can_have_esl = bush.game.has_esl
# info attributes?
can_have_sizes = (is_mod := isinstance(fileInfo, bosh.ModInfo)) and \
bush.game.Esp.check_master_sizes
can_have_esl = (not is_mod) and bush.game.has_esl
all_esl_masters = (set(fileInfo.header.masters_esl) if can_have_esl
else None)
else set())
all_master_sizes = (fileInfo.header.master_sizes if can_have_sizes
else None)
for mi, ma_name in enumerate(fileInfo.masterNames):
ma_size = all_master_sizes[mi] if can_have_sizes else 0
ma_esl = can_have_esl and ma_name in all_esl_masters
else repeat(0))
for mi, (ma_name, ma_size) in enumerate(
zip(fileInfo.masterNames, all_master_sizes)):
self.data_store[mi] = bosh.MasterInfo(parent_minf=fileInfo,
master_name=ma_name, master_size=ma_size, was_esl=ma_esl)
master_name=ma_name, master_size=ma_size,
was_esl=ma_name in all_esl_masters)
self._reList()

def set_item_format(self, item_key, item_format, target_ini_setts):
Expand Down
18 changes: 8 additions & 10 deletions Mopy/bash/basher/installer_links.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ def _apply_tweaks(self, installer, ret, ui_refresh):
# actually installed. Since BAIN is setup to not auto
# install after the wizard, we'll show a message telling
# the User what tweaks to apply manually.
manuallyApply.append((outFile, iniFile))
manuallyApply.append((outFile.stail, iniFile))
continue
target_ini_file = bosh.BestIniFile(target_path)
if INIList.apply_tweaks((bosh.iniInfos[outFile.stail],),
Expand All @@ -423,15 +423,13 @@ def _apply_tweaks(self, installer, ret, ui_refresh):
target_path.stail, reset_choices=target_updated)
ini_uilist.panel.ShowPanel(focus_list=False,
detail_item=lastApplied)
ui_refresh[Store.INIS] = False
if len(manuallyApply) > 0:
message = _('The following INI Tweaks were not automatically '
'applied. Be sure to apply them after installing the '
'package.')
message += u'\n\n'
message += u'\n'.join([u' * %s\n TO: %s' % (x[0].stail, x[1])
for x in manuallyApply])
self._showInfo(message)
ui_refresh[Store.INIS] = False # None or we refreshed in ShowPanel
if manuallyApply:
message = [_('The following INI Tweaks were not automatically '
'applied. Be sure to apply them after installing the '
'package.'), '', '']
message.extend(f' * {x}\n TO: {y}' for x, y in manuallyApply)
self._showInfo('\n'.join(message))

class Installer_OpenReadme(_SingleInstallable):
"""Opens the installer's readme if BAIN can find one."""
Expand Down
9 changes: 4 additions & 5 deletions Mopy/bash/basher/mod_links.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,8 @@ class Mod_CreateDummyMasters(OneItemLink, _LoadLink):
'ck_name': bush.game.Ck.long_name,
}

def _enable(self):
return super(Mod_CreateDummyMasters, self)._enable() and \
self._selected_info.getStatus() == 30 # Missing masters
def _enable(self): # enable if there are missing masters
return super()._enable() and self._selected_info.getStatus() == 30

def Execute(self):
"""Create Dummy Masters"""
Expand All @@ -207,7 +206,7 @@ def Execute(self):
continue
# Missing master, create a dummy plugin for it
newInfo = bosh.ModInfo(self._selected_info.info_dir.join(master))
to_refresh.append((master, newInfo, previous_master))
to_refresh.append((master, previous_master))
previous_master = master
newFile = ModFile(newInfo, self._load_fact()) ###
newFile.tes4.author = u'BASHED DUMMY'
Expand All @@ -221,7 +220,7 @@ def Execute(self):
newFile.tes4.flags1.esl_flag = True
newFile.safeSave()
to_select = []
for mod, info, previous in to_refresh:
for mod, previous in to_refresh:
# add it to modInfos or lo_insert_after blows for timestamp games
bosh.modInfos.new_info(mod, notify_bain=True, _in_refresh=True)
bosh.modInfos.cached_lo_insert_after(previous, mod)
Expand Down
4 changes: 2 additions & 2 deletions Mopy/bash/basher/saves_links.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ def Execute(self):
else:
message = u''
if missing:
message += u'=== '+_(u'Removed Masters')+u' (%s):\n* ' % oldName
message += '=== ' + _('Removed Masters') + f' ({oldName}):\n* '
message += u'\n* '.join(load_order.get_ordered(missing))
if added: message += u'\n\n'
if added:
Expand Down Expand Up @@ -698,7 +698,7 @@ def _move_saves(self, destDir, profile: str | None):
if not result: continue
ask = ask and result != 2 # so don't warn for rest of operation
if self.copyMode:
bosh.saveInfos.copy_info(fileName, destDir)
bosh.saveInfos.copy_info(fileName, destDir, fileName)
if fileName in savesTable:
destTable[fileName] = savesTable[fileName]
else:
Expand Down
8 changes: 4 additions & 4 deletions Mopy/bash/bolt.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,10 +433,10 @@ def __init__(self, wrapped_func):
self._wrapped_func = wrapped_func
self._wrapped_attr = None # set later

def __set_name__(self, owner, name):
def __set_name__(self, owner_, name):
self._wrapped_attr = name

def __get__(self, instance, owner=None):
def __get__(self, instance, owner_=None):
try:
wrapped_val = instance.__dict__[self._wrapped_attr]
except KeyError:
Expand All @@ -450,8 +450,8 @@ class classproperty:
def __init__(self, fget):
self.fget = fget

def __get__(self, obj, owner):
return self.fget(owner)
def __get__(self, obj, owner_):
return self.fget(owner_)

# JSON parsing ----------------------------------------------------------------
class JsonParsable:
Expand Down
62 changes: 27 additions & 35 deletions Mopy/bash/bosh/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,12 @@ class MasterInfo:
__slots__ = ('is_ghost', 'curr_name', 'mod_info', 'old_name',
'stored_size', '_was_esl', 'parent_mod_info')

def __init__(self, *, parent_minf, master_name, master_size, was_esl):
def __init__(self, *, parent_minf, master_name: FName, master_size,
was_esl):
self.parent_mod_info = parent_minf
self.stored_size = master_size
self._was_esl = was_esl
self.old_name = FName(master_name)
self.old_name = master_name
self.mod_info = self.rename_if_present(master_name)
if self.mod_info is None:
self.curr_name = FName(master_name)
Expand Down Expand Up @@ -213,7 +214,6 @@ def _stat_tuple(self): return self.abs_path.size_mtime_ctime()
def __init__(self, fullpath, load_cache=False, **kwargs):
self.header = None
self.masterNames: tuple[FName, ...] = ()
self.masterOrder: tuple[FName, ...] = ()
self.madeBackup = False
# True if the masters for this file are not reliable
self.has_inaccurate_masters = False
Expand All @@ -224,7 +224,6 @@ def __init__(self, fullpath, load_cache=False, **kwargs):
def _reset_masters(self):
#--Master Names/Order
self.masterNames = tuple(self._get_masters())
self.masterOrder = tuple() #--Reset to empty for now

def _file_changed(self, stat_tuple):
return (self.fsize, self.ftime, self.ctime) != stat_tuple
Expand Down Expand Up @@ -295,25 +294,22 @@ def makeBackup(self, forceBackup=False):
if self.madeBackup and not forceBackup: return
#--Backup
cop = self.get_store().copy_info
cop(self.fn_key, self.backup_dir)
cop(self.fn_key, self.backup_dir, self.fn_key)
#--First backup
firstBackup = self.backup_dir.join(self.fn_key) + 'f'
if not firstBackup.exists():
cop(self.fn_key, self.backup_dir, firstBackup.tail)
self.madeBackup = True

def backup_restore_paths(self, first=False, fname=None):
def backup_restore_paths(self, first, fname=None) -> list[tuple[Path, Path]]:
"""Return a list of tuples, mapping backup paths to their restore
destinations. If fname is not given returns the (first) backup
filename corresponding to self.abs_path, else the backup filename
for fname mapped to its restore location in data_store.store_dir
:rtype: list[tuple]
"""
for fname mapped to its restore location in data_store.store_dir."""
restore_path = (fname and self.get_store().store_dir.join(
fname)) or self.abs_path
fname = fname or self.fn_key
return [(self.backup_dir.join(fname) + (u'f' if first else u''),
restore_path)]
return [(self.backup_dir.join(fname + 'f' * first), restore_path)]

def all_backup_paths(self, fname=None):
"""Return the list of all possible paths a backup operation may create.
Expand Down Expand Up @@ -1041,15 +1037,14 @@ def get_rename_paths(self, newName):
return old_new_paths

def _masters_order_status(self, status):
self.masterOrder = tuple(load_order.get_ordered(self.masterNames))
loads_before_its_masters = self.masterOrder and \
load_order.cached_lo_index(
self.masterOrder[-1]) > load_order.cached_lo_index(self.fn_key)
if self.masterOrder != self.masterNames and loads_before_its_masters:
mo = tuple(load_order.get_ordered(self.masterNames)) # masterOrder
loads_before_its_masters = mo and load_order.cached_lo_index(
mo[-1]) > load_order.cached_lo_index(self.fn_key)
if mo != self.masterNames and loads_before_its_masters:
return 21
elif loads_before_its_masters:
return 20
elif self.masterOrder != self.masterNames:
elif mo != self.masterNames:
return 10
else:
return status
Expand Down Expand Up @@ -1271,17 +1266,17 @@ def __init__(self, fullpath, load_cache=False, **kwargs):
def get_store(cls): return saveInfos

def _masters_order_status(self, status):
self.masterOrder = tuple(load_order.get_ordered(self.masterNames))
if self.masterOrder != self.masterNames:
mo = tuple(load_order.get_ordered(self.masterNames))
if mo != self.masterNames:
return 20 # Reordered masters are far more important in saves
elif status > 0:
# Missing or reordered masters -> orange or red
return status
active_tuple = load_order.cached_active_tuple()
if self.masterOrder == active_tuple:
if mo == active_tuple:
# Exact match with LO -> purple
return -20
if self.masterOrder == active_tuple[:len(self.masterOrder)]:
if mo == active_tuple[:len(mo)]:
# Matches LO except for new plugins at the end -> blue
return -10
else:
Expand Down Expand Up @@ -1355,7 +1350,7 @@ def get_cosave_tags(self):
abs(inst.abs_path.mtime - self.ftime) < 10]
return u'\n'.join(co_ui_strings)

def backup_restore_paths(self, first=False, fname=None):
def backup_restore_paths(self, first, fname=None):
"""Return as parent and in addition back up paths for the cosaves."""
back_to_dest = super(SaveInfo, self).backup_restore_paths(first, fname)
# see if we have cosave backups - we must delete cosaves when restoring
Expand Down Expand Up @@ -1410,7 +1405,7 @@ def _get_masters(self):
return [*map(FName, xse_cosave.get_master_list())]
# Fall back on the regular masters - either the cosave is unnecessary,
# doesn't exist or isn't accurate
return self.header.masters
return [*map(FName, self.header.masters)]

def has_circular_masters(self, *, fake_masters: list[FName] | None = None):
return False # Saves can't have circular masters
Expand Down Expand Up @@ -1608,7 +1603,8 @@ def refresh(self, refresh_infos=True, booting=False):
self.corrupted[new] = cor = Corrupted(cor_path, er, **kws)
deprint(f'Failed to load {new} from {cor.abs_path}: {er}',
traceback=True)
self.pop(new, None)
if new := self.pop(new, None): # effectively deleted
del_infos.add(new)
rdata.to_del = {d.fn_key for d in del_infos}
self.delete_refresh(del_infos, check_existence=False)
if rdata.redraw:
Expand Down Expand Up @@ -1712,7 +1708,7 @@ def rename_operation(self, member_info, newName):
return res

#--Copy
def copy_info(self, fileName, destDir, destName=empty_path, set_mtime=None,
def copy_info(self, fileName, destDir, destName, set_mtime=None,
save_lo_cache=False):
"""Copies member file to destDir. Will overwrite! Will update
internal self._data for the file if copied inside self.store_dir but the
Expand All @@ -1723,18 +1719,16 @@ def copy_info(self, fileName, destDir, destName=empty_path, set_mtime=None,
:param set_mtime: if None self[fileName].ftime is copied to destination
"""
destDir.makedirs()
if not destName: destName = fileName
src_info = self[fileName]
if destDir == self.store_dir and destName in self:
destPath = self[destName].abs_path
else:
destPath = destDir.join(destName)
self._do_copy(src_info, destPath)
if destDir == self.store_dir:
self._add_info(destDir, destName, set_mtime, fileName,
save_lo_cache)
self._add_info(destName, set_mtime, fileName, save_lo_cache)

def _add_info(self, destDir, destName, set_mtime, fileNam, save_lo_cache):
def _add_info(self, destName, set_mtime, fileNam, save_lo_cache):
# TODO(ut) : in duplicate pass the info in and load_cache=False
return self.new_info(destName, notify_bain=True)

Expand Down Expand Up @@ -3172,9 +3166,8 @@ def move_infos(self, sources, destinations, window, bash_frame):
bash_frame.warn_corrupted(warn_mods=True, warn_strings=True)
return moved

def _add_info(self, destDir, destName, set_mtime, fileName,
save_lo_cache=None):
inf = super()._add_info(destDir, destName, set_mtime, fileName, save_lo_cache)
def _add_info(self, destName, set_mtime, fileName, save_lo_cache):
inf = super()._add_info(destName, set_mtime, fileName, save_lo_cache)
if set_mtime is not None:
inf.setmtime(set_mtime) # correctly update table
self.cached_lo_insert_after(fileName, destName)
Expand Down Expand Up @@ -3414,12 +3407,12 @@ def rename_operation(self, member_info, newName):
co_file.abs_path = co_type.get_cosave_path(self[newName].abs_path)
return old_key

def copy_info(self, fileName, destDir, destName=empty_path, set_mtime=None,
def copy_info(self, fileName, destDir, destName, set_mtime=None,
save_lo_cache=False):
"""Copies savefile and associated cosaves file(s)."""
super().copy_info(fileName, destDir, destName, set_mtime)
self.co_copy_or_move(self[fileName]._co_saves,
destDir.join(destName or fileName))
destDir.join(destName))

@staticmethod
def co_copy_or_move(co_instances, dest_path: Path, move_cosave=False):
Expand All @@ -3439,7 +3432,6 @@ def move_infos(self, sources, destinations, window, bash_frame):
if FName(d.stail) in moved:
co_instances = SaveInfo.get_cosaves_for_path(s)
self.co_copy_or_move(co_instances, d, move_cosave=True)
break
for m in moved:
try:
self.new_info(m, notify_bain=True) ##: why True??
Expand Down
14 changes: 6 additions & 8 deletions Mopy/bash/bosh/bain.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,17 @@ def _remove_empty_dirs(root_dir):
root_dir, folders, files = next(os.walk(root_dir))
if not files and not folders:
return True # empty
possible_empty = []
empty_dirs = []
if folders:
# root_dir should be an absolute path
root_gpath = GPath_no_norm(root_dir)
for fol in folders:
if _remove_empty_dirs(fol_abs := root_gpath.join(fol)):
possible_empty.append(fol_abs)
empty_dirs.append(fol_abs)
else: files = True
if files:
for empty in possible_empty:
empty.removedirs()
return False
return True
for empty in empty_dirs:
empty.removedirs()
return not files

def _scandir_walk(apath, *, __root_len=None, __folders_times=None):
"""Recursively walk the project dir - only used in InstallerProject."""
Expand Down Expand Up @@ -2922,7 +2920,7 @@ def clean_data_dir(self, ci_removes, refresh_ui):
try:
full_path.moveTo(destDir.join(ci_rel_path)) # will drop .ghost
if store is not None:
store_del[store].add(store_inf.fn_key)
store_del[store].add(store_inf)
self.data_sizeCrcDate.pop(ci_rel_path, None)
emptyDirs.add(full_path.head)
except (StateError, OSError):
Expand Down
Loading

0 comments on commit b974fb9

Please sign in to comment.