mirror of
https://github.com/derrod/legendary.git
synced 2024-12-22 17:55:27 +00:00
[cli/core/utils] Only remove files in manifest during uninstall
Some games are using the installation directory to store savegames. To avoid deleting those, only remove files that are actually in the manifest and only delete the directory if it is empty.
This commit is contained in:
parent
2647fa4915
commit
0a5b53ab6f
|
@ -697,17 +697,15 @@ class LegendaryCLI:
|
|||
exit(0)
|
||||
|
||||
try:
|
||||
logger.info(f'Removing "{igame.title}" from "{igame.install_path}"...')
|
||||
self.core.uninstall_game(igame)
|
||||
|
||||
# DLCs are already removed once we delete the main game, so this just removes them from the list
|
||||
# Remove DLC first so directory is empty when game uninstall runs
|
||||
dlcs = self.core.get_dlc_for_game(igame.app_name)
|
||||
for dlc in dlcs:
|
||||
idlc = self.core.get_installed_game(dlc.app_name)
|
||||
if self.core.is_installed(dlc.app_name):
|
||||
if (idlc := self.core.get_installed_game(dlc.app_name)) is not None:
|
||||
logger.info(f'Uninstalling DLC "{dlc.app_name}"...')
|
||||
self.core.uninstall_game(idlc, delete_files=False)
|
||||
self.core.uninstall_game(idlc)
|
||||
|
||||
logger.info(f'Removing "{igame.title}" from "{igame.install_path}"...')
|
||||
self.core.uninstall_game(igame, delete_root_directory=True)
|
||||
logger.info('Game has been uninstalled.')
|
||||
except Exception as e:
|
||||
logger.warning(f'Removing game failed: {e!r}, please remove {igame.install_path} manually.')
|
||||
|
|
|
@ -21,7 +21,7 @@ from legendary.api.egs import EPCAPI
|
|||
from legendary.downloader.manager import DLManager
|
||||
from legendary.lfs.egl import EPCLFS
|
||||
from legendary.lfs.lgndry import LGDLFS
|
||||
from legendary.utils.lfs import clean_filename, delete_folder
|
||||
from legendary.utils.lfs import clean_filename, delete_folder, delete_filelist
|
||||
from legendary.models.downloading import AnalysisResult, ConditionCheckResult
|
||||
from legendary.models.egl import EGLManifest
|
||||
from legendary.models.exceptions import *
|
||||
|
@ -828,14 +828,20 @@ class LegendaryCore:
|
|||
|
||||
return dict()
|
||||
|
||||
def uninstall_game(self, installed_game: InstalledGame, delete_files=True):
|
||||
self.lgd.remove_installed_game(installed_game.app_name)
|
||||
def uninstall_game(self, installed_game: InstalledGame, delete_files=True, delete_root_directory=False):
|
||||
if installed_game.egl_guid:
|
||||
self.egl_uninstall(installed_game, delete_files=delete_files)
|
||||
|
||||
if delete_files:
|
||||
if not delete_folder(installed_game.install_path, recursive=True):
|
||||
self.log.error(f'Unable to delete "{installed_game.install_path}" from disk, please remove manually.')
|
||||
try:
|
||||
manifest = self.load_manifest(self.get_installed_manifest(installed_game.app_name)[0])
|
||||
filelist = [fm.filename for fm in manifest.file_manifest_list.elements]
|
||||
if not delete_filelist(installed_game.install_path, filelist, delete_root_directory):
|
||||
self.log.error(f'Deleting "{installed_game.install_path}" failed, please remove manually.')
|
||||
except Exception as e:
|
||||
self.log.error(f'Deleting failed with {e!r}, please remove {installed_game.install_path} manually.')
|
||||
|
||||
self.lgd.remove_installed_game(installed_game.app_name)
|
||||
|
||||
def prereq_installed(self, app_name):
|
||||
igame = self.lgd.get_installed_game(app_name)
|
||||
|
|
|
@ -26,6 +26,50 @@ def delete_folder(path: str, recursive=True) -> bool:
|
|||
return True
|
||||
|
||||
|
||||
def delete_filelist(path: str, filenames: List[str],
|
||||
delete_root_directory: bool = False) -> bool:
|
||||
dirs = set()
|
||||
no_error = True
|
||||
|
||||
# delete all files that were installed
|
||||
for filename in filenames:
|
||||
_dir, _fn = os.path.split(filename)
|
||||
if _dir:
|
||||
dirs.add(_dir)
|
||||
|
||||
try:
|
||||
os.remove(os.path.join(path, _dir, _fn))
|
||||
except Exception as e:
|
||||
logger.error(f'Failed deleting file {filename} with {e!r}')
|
||||
no_error = False
|
||||
|
||||
# add intermediate directories that would have been missed otherwise
|
||||
for _dir in sorted(dirs):
|
||||
head, _ = os.path.split(_dir)
|
||||
while head:
|
||||
dirs.add(head)
|
||||
head, _ = os.path.split(head)
|
||||
|
||||
# remove all directories
|
||||
for _dir in sorted(dirs, key=len, reverse=True):
|
||||
try:
|
||||
os.rmdir(os.path.join(path, _dir))
|
||||
except FileNotFoundError:
|
||||
# directory has already been deleted, ignore that
|
||||
continue
|
||||
except Exception as e:
|
||||
logger.error(f'Failed removing directory "{_dir}" with {e!r}')
|
||||
no_error = False
|
||||
|
||||
if delete_root_directory:
|
||||
try:
|
||||
os.rmdir(path)
|
||||
except Exception as e:
|
||||
logger.error(f'Removing game directory failed with {e!r}')
|
||||
|
||||
return no_error
|
||||
|
||||
|
||||
def validate_files(base_path: str, filelist: List[tuple], hash_type='sha1') -> Iterator[tuple]:
|
||||
"""
|
||||
Validates the files in filelist in path against the provided hashes
|
||||
|
|
Loading…
Reference in a new issue