mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 03:08:55 -05:00
[Utils] Privatize internal utils (#3240)
* refactor(utils): privatize some utils * chore(changelog): add towncrier entry * refactor: update internal utils imports
This commit is contained in:
parent
debed501b2
commit
ab747d2432
1
changelog.d/3240.removal.rst
Normal file
1
changelog.d/3240.removal.rst
Normal file
@ -0,0 +1 @@
|
|||||||
|
Removed ``safe_delete``, ``fuzzy_command_search``, ``format_fuzzy_results`` and ``create_backup`` functions from ``redbot.core.utils``.
|
||||||
@ -28,7 +28,7 @@ from typing import (
|
|||||||
|
|
||||||
import discord
|
import discord
|
||||||
from redbot.core import data_manager, commands, Config
|
from redbot.core import data_manager, commands, Config
|
||||||
from redbot.core.utils import safe_delete
|
from redbot.core.utils._internal_utils import safe_delete
|
||||||
from redbot.core.i18n import Translator
|
from redbot.core.i18n import Translator
|
||||||
|
|
||||||
from . import errors
|
from . import errors
|
||||||
|
|||||||
@ -43,7 +43,8 @@ from discord.ext import commands as dpy_commands
|
|||||||
from . import commands
|
from . import commands
|
||||||
from .context import Context
|
from .context import Context
|
||||||
from ..i18n import Translator
|
from ..i18n import Translator
|
||||||
from ..utils import menus, fuzzy_command_search, format_fuzzy_results
|
from ..utils import menus
|
||||||
|
from ..utils._internal_utils import fuzzy_command_search, format_fuzzy_results
|
||||||
from ..utils.chat_formatting import box, pagify
|
from ..utils.chat_formatting import box, pagify
|
||||||
|
|
||||||
__all__ = ["red_help", "RedHelpFormatter", "HelpSettings"]
|
__all__ = ["red_help", "RedHelpFormatter", "HelpSettings"]
|
||||||
|
|||||||
@ -31,7 +31,7 @@ from . import (
|
|||||||
i18n,
|
i18n,
|
||||||
config,
|
config,
|
||||||
)
|
)
|
||||||
from .utils import create_backup
|
from .utils._internal_utils import create_backup
|
||||||
from .utils.predicates import MessagePredicate
|
from .utils.predicates import MessagePredicate
|
||||||
from .utils.chat_formatting import (
|
from .utils.chat_formatting import (
|
||||||
box,
|
box,
|
||||||
|
|||||||
@ -16,8 +16,8 @@ from redbot.core.commands import RedHelpFormatter
|
|||||||
from .. import __version__ as red_version, version_info as red_version_info, VersionInfo
|
from .. import __version__ as red_version, version_info as red_version_info, VersionInfo
|
||||||
from . import commands
|
from . import commands
|
||||||
from .config import get_latest_confs
|
from .config import get_latest_confs
|
||||||
|
from .utils._internal_utils import fuzzy_command_search, format_fuzzy_results
|
||||||
from .utils.chat_formatting import inline, bordered, format_perms_list, humanize_timedelta
|
from .utils.chat_formatting import inline, bordered, format_perms_list, humanize_timedelta
|
||||||
from .utils import fuzzy_command_search, format_fuzzy_results
|
|
||||||
|
|
||||||
log = logging.getLogger("red")
|
log = logging.getLogger("red")
|
||||||
init()
|
init()
|
||||||
|
|||||||
@ -1,13 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import tarfile
|
|
||||||
from asyncio import AbstractEventLoop, as_completed, Semaphore
|
from asyncio import AbstractEventLoop, as_completed, Semaphore
|
||||||
from asyncio.futures import isfuture
|
from asyncio.futures import isfuture
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from pathlib import Path
|
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
AsyncIterator,
|
AsyncIterator,
|
||||||
@ -25,24 +19,7 @@ from typing import (
|
|||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
)
|
)
|
||||||
|
|
||||||
import discord
|
__all__ = ("bounded_gather", "deduplicate_iterables")
|
||||||
from datetime import datetime
|
|
||||||
from fuzzywuzzy import fuzz, process
|
|
||||||
|
|
||||||
from .. import commands, data_manager
|
|
||||||
from .chat_formatting import box
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from ..commands import Command, Context
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
"bounded_gather",
|
|
||||||
"safe_delete",
|
|
||||||
"fuzzy_command_search",
|
|
||||||
"format_fuzzy_results",
|
|
||||||
"deduplicate_iterables",
|
|
||||||
"create_backup",
|
|
||||||
]
|
|
||||||
|
|
||||||
_T = TypeVar("_T")
|
_T = TypeVar("_T")
|
||||||
|
|
||||||
@ -57,27 +34,6 @@ def deduplicate_iterables(*iterables):
|
|||||||
return list(dict.fromkeys(chain.from_iterable(iterables)))
|
return list(dict.fromkeys(chain.from_iterable(iterables)))
|
||||||
|
|
||||||
|
|
||||||
def _fuzzy_log_filter(record):
|
|
||||||
return record.funcName != "extractWithoutOrder"
|
|
||||||
|
|
||||||
|
|
||||||
logging.getLogger().addFilter(_fuzzy_log_filter)
|
|
||||||
|
|
||||||
|
|
||||||
def safe_delete(pth: Path):
|
|
||||||
if pth.exists():
|
|
||||||
for root, dirs, files in os.walk(str(pth)):
|
|
||||||
os.chmod(root, 0o700)
|
|
||||||
|
|
||||||
for d in dirs:
|
|
||||||
os.chmod(os.path.join(root, d), 0o700)
|
|
||||||
|
|
||||||
for f in files:
|
|
||||||
os.chmod(os.path.join(root, f), 0o700)
|
|
||||||
|
|
||||||
shutil.rmtree(str(pth), ignore_errors=True)
|
|
||||||
|
|
||||||
|
|
||||||
# https://github.com/PyCQA/pylint/issues/2717
|
# https://github.com/PyCQA/pylint/issues/2717
|
||||||
class AsyncFilter(AsyncIterator[_T], Awaitable[List[_T]]): # pylint: disable=duplicate-bases
|
class AsyncFilter(AsyncIterator[_T], Awaitable[List[_T]]): # pylint: disable=duplicate-bases
|
||||||
"""Class returned by `async_filter`. See that function for details.
|
"""Class returned by `async_filter`. See that function for details.
|
||||||
@ -188,124 +144,6 @@ async def async_enumerate(
|
|||||||
start += 1
|
start += 1
|
||||||
|
|
||||||
|
|
||||||
async def fuzzy_command_search(
|
|
||||||
ctx: "Context",
|
|
||||||
term: Optional[str] = None,
|
|
||||||
*,
|
|
||||||
commands: Optional[Set["Command"]] = None,
|
|
||||||
min_score: int = 80,
|
|
||||||
) -> Optional[List["Command"]]:
|
|
||||||
"""Search for commands which are similar in name to the one invoked.
|
|
||||||
|
|
||||||
Returns a maximum of 5 commands which must all be at least matched
|
|
||||||
greater than ``min_score``.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
ctx : `commands.Context <redbot.core.commands.Context>`
|
|
||||||
The command invocation context.
|
|
||||||
term : Optional[str]
|
|
||||||
The name of the invoked command. If ``None``,
|
|
||||||
`Context.invoked_with` will be used instead.
|
|
||||||
commands : Optional[Set[commands.Command]]
|
|
||||||
The commands available to choose from when doing a fuzzy match.
|
|
||||||
When omitted, `Bot.walk_commands` will be used instead.
|
|
||||||
min_score : int
|
|
||||||
The minimum score for matched commands to reach. Defaults to 80.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
Optional[List[`commands.Command <redbot.core.commands.Command>`]]
|
|
||||||
A list of commands which were fuzzily matched with the invoked
|
|
||||||
command.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if ctx.guild is not None:
|
|
||||||
enabled = await ctx.bot._config.guild(ctx.guild).fuzzy()
|
|
||||||
else:
|
|
||||||
enabled = await ctx.bot._config.fuzzy()
|
|
||||||
|
|
||||||
if not enabled:
|
|
||||||
return
|
|
||||||
|
|
||||||
if term is None:
|
|
||||||
term = ctx.invoked_with
|
|
||||||
|
|
||||||
# If the term is an alias or CC, we don't want to send a supplementary fuzzy search.
|
|
||||||
alias_cog = ctx.bot.get_cog("Alias")
|
|
||||||
if alias_cog is not None:
|
|
||||||
is_alias, alias = await alias_cog.is_alias(ctx.guild, term)
|
|
||||||
|
|
||||||
if is_alias:
|
|
||||||
return
|
|
||||||
customcom_cog = ctx.bot.get_cog("CustomCommands")
|
|
||||||
if customcom_cog is not None:
|
|
||||||
cmd_obj = customcom_cog.commandobj
|
|
||||||
|
|
||||||
try:
|
|
||||||
await cmd_obj.get(ctx.message, term)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Do the scoring. `extracted` is a list of tuples in the form `(command, score)`
|
|
||||||
extracted = process.extract(
|
|
||||||
term, (commands or set(ctx.bot.walk_commands())), limit=5, scorer=fuzz.QRatio
|
|
||||||
)
|
|
||||||
if not extracted:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Filter through the fuzzy-matched commands.
|
|
||||||
matched_commands = []
|
|
||||||
for command, score in extracted:
|
|
||||||
if score < min_score:
|
|
||||||
# Since the list is in decreasing order of score, we can exit early.
|
|
||||||
break
|
|
||||||
if await command.can_see(ctx):
|
|
||||||
matched_commands.append(command)
|
|
||||||
|
|
||||||
return matched_commands
|
|
||||||
|
|
||||||
|
|
||||||
async def format_fuzzy_results(
|
|
||||||
ctx: "Context", matched_commands: List["Command"], *, embed: Optional[bool] = None
|
|
||||||
) -> Union[str, discord.Embed]:
|
|
||||||
"""Format the result of a fuzzy command search.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
ctx : `commands.Context <redbot.core.commands.Context>`
|
|
||||||
The context in which this result is being displayed.
|
|
||||||
matched_commands : List[`commands.Command <redbot.core.commands.Command>`]
|
|
||||||
A list of commands which have been matched by the fuzzy search, sorted
|
|
||||||
in order of decreasing similarity.
|
|
||||||
embed : bool
|
|
||||||
Whether or not the result should be an embed. If set to ``None``, this
|
|
||||||
will default to the result of `ctx.embed_requested`.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
Union[str, discord.Embed]
|
|
||||||
The formatted results.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if embed is not False and (embed is True or await ctx.embed_requested()):
|
|
||||||
lines = []
|
|
||||||
for cmd in matched_commands:
|
|
||||||
lines.append(f"**{ctx.clean_prefix}{cmd.qualified_name}** {cmd.short_doc}")
|
|
||||||
return discord.Embed(
|
|
||||||
title="Perhaps you wanted one of these?",
|
|
||||||
colour=await ctx.embed_colour(),
|
|
||||||
description="\n".join(lines),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
lines = []
|
|
||||||
for cmd in matched_commands:
|
|
||||||
lines.append(f"{ctx.clean_prefix}{cmd.qualified_name} -- {cmd.short_doc}")
|
|
||||||
return "Perhaps you wanted one of these? " + box("\n".join(lines), lang="vhdl")
|
|
||||||
|
|
||||||
|
|
||||||
async def _sem_wrapper(sem, task):
|
async def _sem_wrapper(sem, task):
|
||||||
async with sem:
|
async with sem:
|
||||||
return await task
|
return await task
|
||||||
@ -402,45 +240,3 @@ def bounded_gather(
|
|||||||
tasks = (_sem_wrapper(semaphore, task) for task in coros_or_futures)
|
tasks = (_sem_wrapper(semaphore, task) for task in coros_or_futures)
|
||||||
|
|
||||||
return asyncio.gather(*tasks, loop=loop, return_exceptions=return_exceptions)
|
return asyncio.gather(*tasks, loop=loop, return_exceptions=return_exceptions)
|
||||||
|
|
||||||
|
|
||||||
async def create_backup(dest: Path = Path.home()) -> Optional[Path]:
|
|
||||||
data_path = Path(data_manager.core_data_path().parent)
|
|
||||||
if not data_path.exists():
|
|
||||||
return
|
|
||||||
|
|
||||||
dest.mkdir(parents=True, exist_ok=True)
|
|
||||||
timestr = datetime.utcnow().strftime("%Y-%m-%dT%H-%M-%S")
|
|
||||||
backup_fpath = dest / f"redv3_{data_manager.instance_name}_{timestr}.tar.gz"
|
|
||||||
|
|
||||||
to_backup = []
|
|
||||||
exclusions = [
|
|
||||||
"__pycache__",
|
|
||||||
"Lavalink.jar",
|
|
||||||
os.path.join("Downloader", "lib"),
|
|
||||||
os.path.join("CogManager", "cogs"),
|
|
||||||
os.path.join("RepoManager", "repos"),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Avoiding circular imports
|
|
||||||
from ...cogs.downloader.repo_manager import RepoManager
|
|
||||||
|
|
||||||
repo_mgr = RepoManager()
|
|
||||||
await repo_mgr.initialize()
|
|
||||||
repo_output = []
|
|
||||||
for repo in repo_mgr.repos:
|
|
||||||
repo_output.append({"url": repo.url, "name": repo.name, "branch": repo.branch})
|
|
||||||
repos_file = data_path / "cogs" / "RepoManager" / "repos.json"
|
|
||||||
with repos_file.open("w") as fs:
|
|
||||||
json.dump(repo_output, fs, indent=4)
|
|
||||||
instance_file = data_path / "instance.json"
|
|
||||||
with instance_file.open("w") as fs:
|
|
||||||
json.dump({data_manager.instance_name: data_manager.basic_config}, fs, indent=4)
|
|
||||||
for f in data_path.glob("**/*"):
|
|
||||||
if not any(ex in str(f) for ex in exclusions) and f.is_file():
|
|
||||||
to_backup.append(f)
|
|
||||||
|
|
||||||
with tarfile.open(str(backup_fpath), "w:gz") as tar:
|
|
||||||
for f in to_backup:
|
|
||||||
tar.add(str(f), arcname=f.relative_to(data_path), recursive=False)
|
|
||||||
return backup_fpath
|
|
||||||
|
|||||||
202
redbot/core/utils/_internal_utils.py
Normal file
202
redbot/core/utils/_internal_utils.py
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import tarfile
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import List, Optional, Set, Union, TYPE_CHECKING
|
||||||
|
|
||||||
|
import discord
|
||||||
|
from fuzzywuzzy import fuzz, process
|
||||||
|
|
||||||
|
from redbot.core import data_manager
|
||||||
|
from redbot.core.utils.chat_formatting import box
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from redbot.core.commands import Command, Context
|
||||||
|
|
||||||
|
__all__ = ("safe_delete", "fuzzy_command_search", "format_fuzzy_results", "create_backup")
|
||||||
|
|
||||||
|
|
||||||
|
def safe_delete(pth: Path):
|
||||||
|
if pth.exists():
|
||||||
|
for root, dirs, files in os.walk(str(pth)):
|
||||||
|
os.chmod(root, 0o700)
|
||||||
|
|
||||||
|
for d in dirs:
|
||||||
|
os.chmod(os.path.join(root, d), 0o700)
|
||||||
|
|
||||||
|
for f in files:
|
||||||
|
os.chmod(os.path.join(root, f), 0o700)
|
||||||
|
|
||||||
|
shutil.rmtree(str(pth), ignore_errors=True)
|
||||||
|
|
||||||
|
|
||||||
|
def _fuzzy_log_filter(record):
|
||||||
|
return record.funcName != "extractWithoutOrder"
|
||||||
|
|
||||||
|
|
||||||
|
logging.getLogger().addFilter(_fuzzy_log_filter)
|
||||||
|
|
||||||
|
|
||||||
|
async def fuzzy_command_search(
|
||||||
|
ctx: Context,
|
||||||
|
term: Optional[str] = None,
|
||||||
|
*,
|
||||||
|
commands: Optional[Set[Command]] = None,
|
||||||
|
min_score: int = 80,
|
||||||
|
) -> Optional[List[Command]]:
|
||||||
|
"""Search for commands which are similar in name to the one invoked.
|
||||||
|
|
||||||
|
Returns a maximum of 5 commands which must all be at least matched
|
||||||
|
greater than ``min_score``.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
ctx : `commands.Context <redbot.core.commands.Context>`
|
||||||
|
The command invocation context.
|
||||||
|
term : Optional[str]
|
||||||
|
The name of the invoked command. If ``None``,
|
||||||
|
`Context.invoked_with` will be used instead.
|
||||||
|
commands : Optional[Set[commands.Command]]
|
||||||
|
The commands available to choose from when doing a fuzzy match.
|
||||||
|
When omitted, `Bot.walk_commands` will be used instead.
|
||||||
|
min_score : int
|
||||||
|
The minimum score for matched commands to reach. Defaults to 80.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Optional[List[`commands.Command <redbot.core.commands.Command>`]]
|
||||||
|
A list of commands which were fuzzily matched with the invoked
|
||||||
|
command.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if ctx.guild is not None:
|
||||||
|
enabled = await ctx.bot._config.guild(ctx.guild).fuzzy()
|
||||||
|
else:
|
||||||
|
enabled = await ctx.bot._config.fuzzy()
|
||||||
|
|
||||||
|
if not enabled:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if term is None:
|
||||||
|
term = ctx.invoked_with
|
||||||
|
|
||||||
|
# If the term is an alias or CC, we don't want to send a supplementary fuzzy search.
|
||||||
|
alias_cog = ctx.bot.get_cog("Alias")
|
||||||
|
if alias_cog is not None:
|
||||||
|
is_alias, alias = await alias_cog.is_alias(ctx.guild, term)
|
||||||
|
|
||||||
|
if is_alias:
|
||||||
|
return None
|
||||||
|
customcom_cog = ctx.bot.get_cog("CustomCommands")
|
||||||
|
if customcom_cog is not None:
|
||||||
|
cmd_obj = customcom_cog.commandobj
|
||||||
|
|
||||||
|
try:
|
||||||
|
await cmd_obj.get(ctx.message, term)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Do the scoring. `extracted` is a list of tuples in the form `(command, score)`
|
||||||
|
extracted = process.extract(
|
||||||
|
term, (commands or set(ctx.bot.walk_commands())), limit=5, scorer=fuzz.QRatio
|
||||||
|
)
|
||||||
|
if not extracted:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Filter through the fuzzy-matched commands.
|
||||||
|
matched_commands = []
|
||||||
|
for command, score in extracted:
|
||||||
|
if score < min_score:
|
||||||
|
# Since the list is in decreasing order of score, we can exit early.
|
||||||
|
break
|
||||||
|
if await command.can_see(ctx):
|
||||||
|
matched_commands.append(command)
|
||||||
|
|
||||||
|
return matched_commands
|
||||||
|
|
||||||
|
|
||||||
|
async def format_fuzzy_results(
|
||||||
|
ctx: Context, matched_commands: List[Command], *, embed: Optional[bool] = None
|
||||||
|
) -> Union[str, discord.Embed]:
|
||||||
|
"""Format the result of a fuzzy command search.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
ctx : `commands.Context <redbot.core.commands.Context>`
|
||||||
|
The context in which this result is being displayed.
|
||||||
|
matched_commands : List[`commands.Command <redbot.core.commands.Command>`]
|
||||||
|
A list of commands which have been matched by the fuzzy search, sorted
|
||||||
|
in order of decreasing similarity.
|
||||||
|
embed : bool
|
||||||
|
Whether or not the result should be an embed. If set to ``None``, this
|
||||||
|
will default to the result of `ctx.embed_requested`.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Union[str, discord.Embed]
|
||||||
|
The formatted results.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if embed is not False and (embed is True or await ctx.embed_requested()):
|
||||||
|
lines = []
|
||||||
|
for cmd in matched_commands:
|
||||||
|
lines.append(f"**{ctx.clean_prefix}{cmd.qualified_name}** {cmd.short_doc}")
|
||||||
|
return discord.Embed(
|
||||||
|
title="Perhaps you wanted one of these?",
|
||||||
|
colour=await ctx.embed_colour(),
|
||||||
|
description="\n".join(lines),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
lines = []
|
||||||
|
for cmd in matched_commands:
|
||||||
|
lines.append(f"{ctx.clean_prefix}{cmd.qualified_name} -- {cmd.short_doc}")
|
||||||
|
return "Perhaps you wanted one of these? " + box("\n".join(lines), lang="vhdl")
|
||||||
|
|
||||||
|
|
||||||
|
async def create_backup(dest: Path = Path.home()) -> Optional[Path]:
|
||||||
|
data_path = Path(data_manager.core_data_path().parent)
|
||||||
|
if not data_path.exists():
|
||||||
|
return None
|
||||||
|
|
||||||
|
dest.mkdir(parents=True, exist_ok=True)
|
||||||
|
timestr = datetime.utcnow().strftime("%Y-%m-%dT%H-%M-%S")
|
||||||
|
backup_fpath = dest / f"redv3_{data_manager.instance_name}_{timestr}.tar.gz"
|
||||||
|
|
||||||
|
to_backup = []
|
||||||
|
exclusions = [
|
||||||
|
"__pycache__",
|
||||||
|
"Lavalink.jar",
|
||||||
|
os.path.join("Downloader", "lib"),
|
||||||
|
os.path.join("CogManager", "cogs"),
|
||||||
|
os.path.join("RepoManager", "repos"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Avoiding circular imports
|
||||||
|
from ...cogs.downloader.repo_manager import RepoManager
|
||||||
|
|
||||||
|
repo_mgr = RepoManager()
|
||||||
|
await repo_mgr.initialize()
|
||||||
|
repo_output = []
|
||||||
|
for repo in repo_mgr.repos:
|
||||||
|
repo_output.append({"url": repo.url, "name": repo.name, "branch": repo.branch})
|
||||||
|
repos_file = data_path / "cogs" / "RepoManager" / "repos.json"
|
||||||
|
with repos_file.open("w") as fs:
|
||||||
|
json.dump(repo_output, fs, indent=4)
|
||||||
|
instance_file = data_path / "instance.json"
|
||||||
|
with instance_file.open("w") as fs:
|
||||||
|
json.dump({data_manager.instance_name: data_manager.basic_config}, fs, indent=4)
|
||||||
|
for f in data_path.glob("**/*"):
|
||||||
|
if not any(ex in str(f) for ex in exclusions) and f.is_file():
|
||||||
|
to_backup.append(f)
|
||||||
|
|
||||||
|
with tarfile.open(str(backup_fpath), "w:gz") as tar:
|
||||||
|
for f in to_backup:
|
||||||
|
tar.add(str(f), arcname=str(f.relative_to(data_path)), recursive=False)
|
||||||
|
return backup_fpath
|
||||||
@ -12,7 +12,7 @@ import appdirs
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
import redbot.logging
|
import redbot.logging
|
||||||
from redbot.core.utils import safe_delete, create_backup as red_create_backup
|
from redbot.core.utils._internal_utils import safe_delete, create_backup as red_create_backup
|
||||||
from redbot.core import config, data_manager, drivers
|
from redbot.core import config, data_manager, drivers
|
||||||
from redbot.core.drivers import BackendType, IdentifierData
|
from redbot.core.drivers import BackendType, IdentifierData
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user