From 36e2cde04d3732121342196ee657602d4dfe9663 Mon Sep 17 00:00:00 2001 From: jack1142 <6032823+jack1142@users.noreply.github.com> Date: Thu, 2 Jan 2020 15:03:32 +0100 Subject: [PATCH] Move `[p]backup` command to cli command - `redbot-setup backup` (#3235) * refactor: replace backup command with cli command * chore(changelog): add towncrier entries --- changelog.d/3235.feature.rst | 1 + changelog.d/3235.removal.rst | 1 + redbot/core/core_commands.py | 70 ------------------------------------ redbot/setup.py | 24 +++++++++++-- 4 files changed, 23 insertions(+), 73 deletions(-) create mode 100644 changelog.d/3235.feature.rst create mode 100644 changelog.d/3235.removal.rst diff --git a/changelog.d/3235.feature.rst b/changelog.d/3235.feature.rst new file mode 100644 index 000000000..ce6512ddc --- /dev/null +++ b/changelog.d/3235.feature.rst @@ -0,0 +1 @@ +Added ``redbot-setup backup`` command. \ No newline at end of file diff --git a/changelog.d/3235.removal.rst b/changelog.d/3235.removal.rst new file mode 100644 index 000000000..65662c937 --- /dev/null +++ b/changelog.d/3235.removal.rst @@ -0,0 +1 @@ +Removed ``[p]backup`` command. Use ``redbot-setup backup`` cli command instead. \ No newline at end of file diff --git a/redbot/core/core_commands.py b/redbot/core/core_commands.py index fef089b07..66fdcbc6b 100644 --- a/redbot/core/core_commands.py +++ b/redbot/core/core_commands.py @@ -31,7 +31,6 @@ from . import ( i18n, config, ) -from .utils._internal_utils import create_backup from .utils.predicates import MessagePredicate from .utils.chat_formatting import ( box, @@ -1390,75 +1389,6 @@ class Core(commands.Cog, CoreLogic): 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.cooldown(1, 60, commands.BucketType.user) async def contact(self, ctx: commands.Context, *, message: str): diff --git a/redbot/setup.py b/redbot/setup.py index ebec96f17..1bb6379ae 100644 --- a/redbot/setup.py +++ b/redbot/setup.py @@ -7,7 +7,7 @@ import sys import re from copy import deepcopy from pathlib import Path -from typing import Dict, Any, Optional +from typing import Dict, Any, Optional, Union import appdirs import click @@ -213,13 +213,13 @@ async def do_migration( 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) backend_type = get_current_backend(instance) if backend_type != BackendType.JSON: await do_migration(backend_type, BackendType.JSON) 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: print(f"A backup of {instance} has been made. It is at {backup_fpath}") else: @@ -293,6 +293,7 @@ async def remove_instance_interaction(): @click.option("--debug", type=bool) @click.pass_context def cli(ctx, debug): + """Create a new instance.""" level = logging.DEBUG if debug else logging.INFO redbot.logging.init_logging(level=level, location=Path.cwd() / "red_setup_logs") if ctx.invoked_subcommand is None: @@ -356,6 +357,7 @@ def delete( drop_db: Optional[bool], remove_datapath: Optional[bool], ): + """Removes an instance.""" loop = asyncio.get_event_loop() loop.run_until_complete( remove_instance( @@ -368,6 +370,7 @@ def delete( @click.argument("instance", type=click.Choice(instance_list)) @click.argument("backend", type=click.Choice(["json", "postgres"])) def convert(instance, backend): + """Convert data backend of an instance.""" current_backend = get_current_backend(instance) target = get_target_backend(backend) 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__": try: cli() # pylint: disable=no-value-for-parameter # click