Move [p]backup command to cli command - redbot-setup backup (#3235)

* refactor: replace backup command with cli command

* chore(changelog): add towncrier entries
This commit is contained in:
jack1142 2020-01-02 15:03:32 +01:00 committed by Michael H
parent f3e7c2028c
commit 36e2cde04d
4 changed files with 23 additions and 73 deletions

View File

@ -0,0 +1 @@
Added ``redbot-setup backup`` command.

View File

@ -0,0 +1 @@
Removed ``[p]backup`` command. Use ``redbot-setup backup`` cli command instead.

View File

@ -31,7 +31,6 @@ from . import (
i18n, i18n,
config, config,
) )
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,
@ -1390,75 +1389,6 @@ class Core(commands.Cog, CoreLogic):
await ctx.send_interactive(pages, box_lang="Available Locales:") await ctx.send_interactive(pages, box_lang="Available Locales:")
@commands.command()
@checks.is_owner()
async def backup(self, ctx: commands.Context, *, backup_dir: str = None):
"""Creates a backup of all data for this bot instance.
This backs up the bot's data and settings.
You may provide a path to a directory for the backup archive to
be placed in. If the directory does not exist, the bot will
attempt to create it.
"""
if backup_dir is None:
dest = Path.home()
else:
dest = Path(backup_dir)
driver_cls = drivers.get_driver_class()
if driver_cls != drivers.JsonDriver:
await ctx.send(_("Converting data to JSON for backup..."))
async with ctx.typing():
await config.migrate(driver_cls, drivers.JsonDriver)
log.info("Creating backup for this instance...")
try:
backup_fpath = await create_backup(dest)
except OSError as exc:
await ctx.send(
_(
"Creating the backup archive failed! Please check your console or logs for "
"details."
)
)
log.exception("Failed to create backup archive", exc_info=exc)
return
if backup_fpath is None:
await ctx.send(_("Your datapath appears to be empty."))
return
log.info("Backup archive created successfully at '%s'", backup_fpath)
await ctx.send(
_("A backup has been made of this instance. It is located at `{path}`.").format(
path=backup_fpath
)
)
if backup_fpath.stat().st_size > 8_000_000:
await ctx.send(_("This backup is too large to send via DM."))
return
await ctx.send(_("Would you like to receive a copy via DM? (y/n)"))
pred = MessagePredicate.yes_or_no(ctx)
try:
await ctx.bot.wait_for("message", check=pred, timeout=60)
except asyncio.TimeoutError:
await ctx.send(_("Response timed out."))
else:
if pred.result is True:
await ctx.send(_("OK, it's on its way!"))
try:
async with ctx.author.typing():
await ctx.author.send(
_("Here's a copy of the backup"), file=discord.File(str(backup_fpath))
)
except discord.Forbidden:
await ctx.send(_("I don't seem to be able to DM you. Do you have closed DMs?"))
except discord.HTTPException:
await ctx.send(_("I could not send the backup file."))
else:
await ctx.send(_("OK then."))
@commands.command() @commands.command()
@commands.cooldown(1, 60, commands.BucketType.user) @commands.cooldown(1, 60, commands.BucketType.user)
async def contact(self, ctx: commands.Context, *, message: str): async def contact(self, ctx: commands.Context, *, message: str):

View File

@ -7,7 +7,7 @@ import sys
import re import re
from copy import deepcopy from copy import deepcopy
from pathlib import Path from pathlib import Path
from typing import Dict, Any, Optional from typing import Dict, Any, Optional, Union
import appdirs import appdirs
import click import click
@ -213,13 +213,13 @@ async def do_migration(
return new_storage_details return new_storage_details
async def create_backup(instance: str) -> None: async def create_backup(instance: str, destination_folder: Path = Path.home()) -> None:
data_manager.load_basic_configuration(instance) data_manager.load_basic_configuration(instance)
backend_type = get_current_backend(instance) backend_type = get_current_backend(instance)
if backend_type != BackendType.JSON: if backend_type != BackendType.JSON:
await do_migration(backend_type, BackendType.JSON) await do_migration(backend_type, BackendType.JSON)
print("Backing up the instance's data...") print("Backing up the instance's data...")
backup_fpath = await red_create_backup() backup_fpath = await red_create_backup(destination_folder)
if backup_fpath is not None: if backup_fpath is not None:
print(f"A backup of {instance} has been made. It is at {backup_fpath}") print(f"A backup of {instance} has been made. It is at {backup_fpath}")
else: else:
@ -293,6 +293,7 @@ async def remove_instance_interaction():
@click.option("--debug", type=bool) @click.option("--debug", type=bool)
@click.pass_context @click.pass_context
def cli(ctx, debug): def cli(ctx, debug):
"""Create a new instance."""
level = logging.DEBUG if debug else logging.INFO level = logging.DEBUG if debug else logging.INFO
redbot.logging.init_logging(level=level, location=Path.cwd() / "red_setup_logs") redbot.logging.init_logging(level=level, location=Path.cwd() / "red_setup_logs")
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
@ -356,6 +357,7 @@ def delete(
drop_db: Optional[bool], drop_db: Optional[bool],
remove_datapath: Optional[bool], remove_datapath: Optional[bool],
): ):
"""Removes an instance."""
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
loop.run_until_complete( loop.run_until_complete(
remove_instance( remove_instance(
@ -368,6 +370,7 @@ def delete(
@click.argument("instance", type=click.Choice(instance_list)) @click.argument("instance", type=click.Choice(instance_list))
@click.argument("backend", type=click.Choice(["json", "postgres"])) @click.argument("backend", type=click.Choice(["json", "postgres"]))
def convert(instance, backend): def convert(instance, backend):
"""Convert data backend of an instance."""
current_backend = get_current_backend(instance) current_backend = get_current_backend(instance)
target = get_target_backend(backend) target = get_target_backend(backend)
data_manager.load_basic_configuration(instance) data_manager.load_basic_configuration(instance)
@ -393,6 +396,21 @@ def convert(instance, backend):
) )
@cli.command()
@click.argument("instance", type=click.Choice(instance_list))
@click.argument(
"destination_folder",
type=click.Path(
exists=False, dir_okay=True, file_okay=False, resolve_path=True, writable=True
),
default=Path.home(),
)
def backup(instance: str, destination_folder: Union[str, Path]) -> None:
"""Backup instance's data."""
loop = asyncio.get_event_loop()
loop.run_until_complete(create_backup(instance, Path(destination_folder)))
if __name__ == "__main__": if __name__ == "__main__":
try: try:
cli() # pylint: disable=no-value-for-parameter # click cli() # pylint: disable=no-value-for-parameter # click