mirror of
https://github.com/derrod/legendary.git
synced 2025-02-26 15:36:45 +00:00
Also make verification and uninstallation case-insensitive if necessary
This also only enables case-insensitive file tasks if installing a Windows game
This commit is contained in:
parent
f08dbc4a62
commit
48b37d47cf
|
@ -1268,7 +1268,8 @@ class LegendaryCLI:
|
||||||
|
|
||||||
logger.info(f'Verifying "{igame.title}" version "{manifest.meta.build_version}"')
|
logger.info(f'Verifying "{igame.title}" version "{manifest.meta.build_version}"')
|
||||||
repair_file = []
|
repair_file = []
|
||||||
for result, path, result_hash, bytes_read in validate_files(igame.install_path, file_list):
|
for result, path, result_hash, bytes_read in validate_files(igame.install_path, file_list,
|
||||||
|
case_insensitive=igame.platform.startswith('Win')):
|
||||||
processed += bytes_read
|
processed += bytes_read
|
||||||
percentage = (processed / total_size) * 100.0
|
percentage = (processed / total_size) * 100.0
|
||||||
num += 1
|
num += 1
|
||||||
|
|
|
@ -1498,7 +1498,7 @@ class LegendaryCore:
|
||||||
|
|
||||||
dlm = DLManager(install_path, base_url, resume_file=resume_file, status_q=status_q,
|
dlm = DLManager(install_path, base_url, resume_file=resume_file, status_q=status_q,
|
||||||
max_shared_memory=max_shm * 1024 * 1024, max_workers=max_workers,
|
max_shared_memory=max_shm * 1024 * 1024, max_workers=max_workers,
|
||||||
dl_timeout=dl_timeout, bind_ip=bind_ip)
|
dl_timeout=dl_timeout, bind_ip=bind_ip, case_insensitive=platform.startswith('Win'))
|
||||||
anlres = dlm.run_analysis(manifest=new_manifest, old_manifest=old_manifest,
|
anlres = dlm.run_analysis(manifest=new_manifest, old_manifest=old_manifest,
|
||||||
patch=not disable_patching, resume=not force,
|
patch=not disable_patching, resume=not force,
|
||||||
file_prefix_filter=file_prefix_filter,
|
file_prefix_filter=file_prefix_filter,
|
||||||
|
@ -1697,7 +1697,8 @@ class LegendaryCore:
|
||||||
fm.filename for fm in manifest.file_manifest_list.elements if
|
fm.filename for fm in manifest.file_manifest_list.elements if
|
||||||
not fm.install_tags or any(t in installed_game.install_tags for t in fm.install_tags)
|
not fm.install_tags or any(t in installed_game.install_tags for t in fm.install_tags)
|
||||||
]
|
]
|
||||||
if not delete_filelist(installed_game.install_path, filelist, delete_root_directory):
|
if not delete_filelist(installed_game.install_path, filelist, delete_root_directory,
|
||||||
|
case_insensitive=installed_game.platform.startswith('Win')):
|
||||||
self.log.error(f'Deleting "{installed_game.install_path}" failed, please remove manually.')
|
self.log.error(f'Deleting "{installed_game.install_path}" failed, please remove manually.')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.error(f'Deleting failed with {e!r}, please remove {installed_game.install_path} manually.')
|
self.log.error(f'Deleting failed with {e!r}, please remove {installed_game.install_path} manually.')
|
||||||
|
@ -1717,7 +1718,10 @@ class LegendaryCore:
|
||||||
and os.path.exists(os.path.join(installed_game.install_path, fm.filename))
|
and os.path.exists(os.path.join(installed_game.install_path, fm.filename))
|
||||||
]
|
]
|
||||||
|
|
||||||
if not delete_filelist(installed_game.install_path, filelist):
|
if not delete_filelist(
|
||||||
|
installed_game.install_path, filelist,
|
||||||
|
case_insensitive=installed_game.platform.startswith('Win')
|
||||||
|
):
|
||||||
self.log.warning(f'Deleting some deselected files failed, please check/remove manually.')
|
self.log.warning(f'Deleting some deselected files failed, please check/remove manually.')
|
||||||
|
|
||||||
def prereq_installed(self, app_name):
|
def prereq_installed(self, app_name):
|
||||||
|
|
|
@ -22,7 +22,7 @@ from legendary.models.manifest import ManifestComparison, Manifest
|
||||||
class DLManager(Process):
|
class DLManager(Process):
|
||||||
def __init__(self, download_dir, base_url, cache_dir=None, status_q=None,
|
def __init__(self, download_dir, base_url, cache_dir=None, status_q=None,
|
||||||
max_workers=0, update_interval=1.0, dl_timeout=10, resume_file=None,
|
max_workers=0, update_interval=1.0, dl_timeout=10, resume_file=None,
|
||||||
max_shared_memory=1024 * 1024 * 1024, bind_ip=None):
|
max_shared_memory=1024 * 1024 * 1024, bind_ip=None, case_insensitive=True):
|
||||||
super().__init__(name='DLManager')
|
super().__init__(name='DLManager')
|
||||||
self.log = logging.getLogger('DLM')
|
self.log = logging.getLogger('DLM')
|
||||||
self.proc_debug = False
|
self.proc_debug = False
|
||||||
|
@ -42,6 +42,7 @@ class DLManager(Process):
|
||||||
self.max_workers = max_workers or min(cpu_count() * 2, 16)
|
self.max_workers = max_workers or min(cpu_count() * 2, 16)
|
||||||
self.dl_timeout = dl_timeout
|
self.dl_timeout = dl_timeout
|
||||||
self.bind_ips = [] if not bind_ip else bind_ip.split(',')
|
self.bind_ips = [] if not bind_ip else bind_ip.split(',')
|
||||||
|
self.case_insensitive = case_insensitive
|
||||||
|
|
||||||
# Analysis stuff
|
# Analysis stuff
|
||||||
self.analysis = None
|
self.analysis = None
|
||||||
|
@ -672,7 +673,8 @@ class DLManager(Process):
|
||||||
|
|
||||||
self.log.info('Starting file writing worker...')
|
self.log.info('Starting file writing worker...')
|
||||||
writer_p = FileWorker(self.writer_queue, self.writer_result_q, self.dl_dir,
|
writer_p = FileWorker(self.writer_queue, self.writer_result_q, self.dl_dir,
|
||||||
self.shared_memory.name, self.cache_dir, self.logging_queue)
|
self.shared_memory.name, self.cache_dir, self.logging_queue,
|
||||||
|
self.case_insensitive)
|
||||||
self.children.append(writer_p)
|
self.children.append(writer_p)
|
||||||
writer_p.start()
|
writer_p.start()
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,8 @@ class DLWorker(Process):
|
||||||
|
|
||||||
|
|
||||||
class FileWorker(Process):
|
class FileWorker(Process):
|
||||||
def __init__(self, queue, out_queue, base_path, shm, cache_path=None, logging_queue=None):
|
def __init__(self, queue, out_queue, base_path, shm, cache_path=None, logging_queue=None,
|
||||||
|
case_insensitive: bool = True):
|
||||||
super().__init__(name='FileWorker')
|
super().__init__(name='FileWorker')
|
||||||
self.q = queue
|
self.q = queue
|
||||||
self.o_q = out_queue
|
self.o_q = out_queue
|
||||||
|
@ -157,6 +158,7 @@ class FileWorker(Process):
|
||||||
self.shm = SharedMemory(name=shm)
|
self.shm = SharedMemory(name=shm)
|
||||||
self.log_level = logging.getLogger().level
|
self.log_level = logging.getLogger().level
|
||||||
self.logging_queue = logging_queue
|
self.logging_queue = logging_queue
|
||||||
|
self.case_insensitive = case_insensitive
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# we have to fix up the logger before we can start
|
# we have to fix up the logger before we can start
|
||||||
|
@ -189,7 +191,9 @@ class FileWorker(Process):
|
||||||
|
|
||||||
# make directories if required
|
# make directories if required
|
||||||
path, filename = os.path.split(j.filename)
|
path, filename = os.path.split(j.filename)
|
||||||
file_dir = case_insensitive_file_search(os.path.join(self.base_path, path))
|
file_dir = os.path.join(self.base_path, path)
|
||||||
|
if self.case_insensitive:
|
||||||
|
file_dir = case_insensitive_file_search(file_dir)
|
||||||
if not os.path.exists(file_dir):
|
if not os.path.exists(file_dir):
|
||||||
os.makedirs(file_dir)
|
os.makedirs(file_dir)
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ from typing import List, Iterator
|
||||||
|
|
||||||
from filelock import FileLock
|
from filelock import FileLock
|
||||||
|
|
||||||
|
from legendary.lfs.wine_helpers import case_insensitive_file_search
|
||||||
from legendary.models.game import VerifyResult
|
from legendary.models.game import VerifyResult
|
||||||
|
|
||||||
logger = logging.getLogger('LFS Utils')
|
logger = logging.getLogger('LFS Utils')
|
||||||
|
@ -34,7 +35,7 @@ def delete_folder(path: str, recursive=True) -> bool:
|
||||||
|
|
||||||
def delete_filelist(path: str, filenames: List[str],
|
def delete_filelist(path: str, filenames: List[str],
|
||||||
delete_root_directory: bool = False,
|
delete_root_directory: bool = False,
|
||||||
silent: bool = False) -> bool:
|
silent: bool = False, case_insensitive: bool = True) -> bool:
|
||||||
dirs = set()
|
dirs = set()
|
||||||
no_error = True
|
no_error = True
|
||||||
|
|
||||||
|
@ -45,7 +46,10 @@ def delete_filelist(path: str, filenames: List[str],
|
||||||
dirs.add(_dir)
|
dirs.add(_dir)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.remove(os.path.join(path, _dir, _fn))
|
full_path = os.path.join(path, _dir, _fn)
|
||||||
|
if case_insensitive:
|
||||||
|
full_path = case_insensitive_file_search(full_path)
|
||||||
|
os.remove(full_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if not silent:
|
if not silent:
|
||||||
logger.error(f'Failed deleting file {filename} with {e!r}')
|
logger.error(f'Failed deleting file {filename} with {e!r}')
|
||||||
|
@ -61,7 +65,10 @@ def delete_filelist(path: str, filenames: List[str],
|
||||||
# remove all directories
|
# remove all directories
|
||||||
for _dir in sorted(dirs, key=len, reverse=True):
|
for _dir in sorted(dirs, key=len, reverse=True):
|
||||||
try:
|
try:
|
||||||
os.rmdir(os.path.join(path, _dir))
|
dir_path = os.path.join(path, _dir)
|
||||||
|
if case_insensitive:
|
||||||
|
dir_path = case_insensitive_file_search(dir_path)
|
||||||
|
os.rmdir(dir_path)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
# directory has already been deleted, ignore that
|
# directory has already been deleted, ignore that
|
||||||
continue
|
continue
|
||||||
|
@ -81,7 +88,7 @@ def delete_filelist(path: str, filenames: List[str],
|
||||||
|
|
||||||
|
|
||||||
def validate_files(base_path: str, filelist: List[tuple], hash_type='sha1',
|
def validate_files(base_path: str, filelist: List[tuple], hash_type='sha1',
|
||||||
large_file_threshold=1024 * 1024 * 512) -> Iterator[tuple]:
|
large_file_threshold=1024 * 1024 * 512, case_insensitive: bool = True) -> Iterator[tuple]:
|
||||||
"""
|
"""
|
||||||
Validates the files in filelist in path against the provided hashes
|
Validates the files in filelist in path against the provided hashes
|
||||||
|
|
||||||
|
@ -89,6 +96,7 @@ def validate_files(base_path: str, filelist: List[tuple], hash_type='sha1',
|
||||||
:param filelist: list of tuples in format (path, hash [hex])
|
:param filelist: list of tuples in format (path, hash [hex])
|
||||||
:param hash_type: (optional) type of hash, default is sha1
|
:param hash_type: (optional) type of hash, default is sha1
|
||||||
:param large_file_threshold: (optional) threshold for large files, default is 512 MiB
|
:param large_file_threshold: (optional) threshold for large files, default is 512 MiB
|
||||||
|
:param case_insensitive: (optional) whether to search for files case insensitively
|
||||||
:return: yields tuples in format (VerifyResult, path, hash [hex], bytes read)
|
:return: yields tuples in format (VerifyResult, path, hash [hex], bytes read)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -100,6 +108,8 @@ def validate_files(base_path: str, filelist: List[tuple], hash_type='sha1',
|
||||||
|
|
||||||
for file_path, file_hash in filelist:
|
for file_path, file_hash in filelist:
|
||||||
full_path = os.path.join(base_path, file_path)
|
full_path = os.path.join(base_path, file_path)
|
||||||
|
if case_insensitive:
|
||||||
|
full_path = case_insensitive_file_search(full_path)
|
||||||
# logger.debug(f'Checking "{file_path}"...')
|
# logger.debug(f'Checking "{file_path}"...')
|
||||||
|
|
||||||
if not os.path.exists(full_path):
|
if not os.path.exists(full_path):
|
||||||
|
|
Loading…
Reference in a new issue