diff --git a/redbot/cogs/downloader/repo_manager.py b/redbot/cogs/downloader/repo_manager.py index c18086ee6..788a34923 100644 --- a/redbot/cogs/downloader/repo_manager.py +++ b/redbot/cogs/downloader/repo_manager.py @@ -13,6 +13,7 @@ from discord.ext import commands from redbot.core import Config from redbot.core import data_manager +from redbot.core.utils import safe_delete from .errors import * from .installable import Installable, InstallableType from .json_mixins import RepoJSONMixin @@ -614,7 +615,7 @@ class RepoManager: if repo is None: raise MissingGitRepo("There is no repo with the name {}".format(name)) - shutil.rmtree(str(repo.folder_path)) + safe_delete(repo.folder_path) try: del self._repos[name] diff --git a/redbot/core/utils/__init__.py b/redbot/core/utils/__init__.py index 3b8197b8c..665389a3e 100644 --- a/redbot/core/utils/__init__.py +++ b/redbot/core/utils/__init__.py @@ -1,4 +1,8 @@ -__all__ = ['TYPE_CHECKING', 'NewType'] +__all__ = ['TYPE_CHECKING', 'NewType', 'safe_delete'] + +from pathlib import Path +import os +import shutil try: from typing import TYPE_CHECKING @@ -10,3 +14,12 @@ try: except ImportError: def NewType(name, tp): return type(name, (tp,), {}) + + +def safe_delete(pth: Path): + if pth.exists(): + for root, dirs, files in os.walk(str(pth)): + os.chmod(root, 0o755) + for d in dirs: + os.chmod(os.path.join(root, d), 0o755) + shutil.rmtree(str(pth), ignore_errors=True) diff --git a/redbot/setup.py b/redbot/setup.py index f519d3bf0..3223d9704 100644 --- a/redbot/setup.py +++ b/redbot/setup.py @@ -15,6 +15,7 @@ import appdirs from redbot.core.cli import confirm from redbot.core.data_manager import basic_config_default from redbot.core.json_io import JsonIO +from redbot.core.utils import safe_delete config_dir = None appdir = appdirs.AppDirs("Red-DiscordBot") @@ -310,31 +311,26 @@ def remove_instance(): selected, dt.utcnow().strftime("%Y-%m-%d %H-%M-%S") ) pth = Path(instance_data["DATA_PATH"]) - home = pth.home() - backup_file = home / backup_filename - os.chdir(str(pth.parent)) # str is used here because 3.5 support - with tarfile.open(str(backup_file), "w:gz") as tar: - tar.add(pth.stem) # add all files in that directory - print( - "A backup of {} has been made. It is at {}".format( - selected, backup_file + if pth.exists(): + home = pth.home() + backup_file = home / backup_filename + os.chdir(str(pth.parent)) # str is used here because 3.5 support + with tarfile.open(str(backup_file), "w:gz") as tar: + tar.add(pth.stem) # add all files in that directory + print( + "A backup of {} has been made. It is at {}".format( + selected, backup_file + ) ) - ) - print("Removing the instance...") - try: - shutil.rmtree(str(pth)) - except FileNotFoundError: - pass # data dir was removed manually + print("Removing the instance...") + safe_delete(pth) save_config(selected, {}, remove=True) print("The instance has been removed") return else: pth = Path(instance_data["DATA_PATH"]) print("Removing the instance...") - try: - shutil.rmtree(str(pth)) - except FileNotFoundError: - pass # data dir was removed manually + safe_delete(pth) save_config(selected, {}, remove=True) print("The instance has been removed") return