async def reset_red(): instances = load_existing_config() if not instances: print("No instance to delete.\n") return print( "WARNING: You are about to remove ALL bot instances on this computer.") print("If you want to reset data of only one instance, " "please select option 5 in the launcher.") await asyncio.sleep(2) print("\nIf you continue you will remove these instanes.\n") for instance in list(instances.keys()): print(" - {}".format(instance)) await asyncio.sleep(3) print('\nIf you want to reset all instances, type "I agree".') response = input("> ").strip() if response != "I agree": print("Cancelling...") return if confirm("\nDo you want to create a backup for an instance? (y/n) "): for index, instance in instances.items(): print("\nRemoving {}...".format(index)) await create_backup(index, instance) await remove_instance(index, instance) else: for index, instance in instances.items(): await remove_instance(index, instance) print("All instances have been removed.")
def save_config(name, data, remove=False): config = load_existing_config() if remove and name in config: config.pop(name) else: if name in config: print( "WARNING: An instance already exists with this name. " "Continuing will overwrite the existing instance config." ) if not confirm("Are you absolutely certain you want to continue (y/n)? "): print("Not continuing") sys.exit(0) config[name] = data JsonIO(config_file)._save_json(config)
async def create_backup(selected, instance_data): if confirm("Would you like to make a backup of the data for this instance? (y/n)"): load_basic_configuration(selected) if instance_data["STORAGE_TYPE"] == "MongoDB": await mongo_to_json(instance_data["DATA_PATH"], instance_data["STORAGE_DETAILS"]) print("Backing up the instance's data...") backup_filename = "redv3-{}-{}.tar.gz".format( selected, dt.utcnow().strftime("%Y-%m-%d %H-%M-%S") ) pth = Path(instance_data["DATA_PATH"]) if pth.exists(): backup_pth = pth.home() backup_file = backup_pth / backup_filename to_backup = [] exclusions = [ "__pycache__", "Lavalink.jar", os.path.join("Downloader", "lib"), os.path.join("CogManager", "cogs"), os.path.join("RepoManager", "repos"), ] from botbase.cogs.downloader.repo_manager import RepoManager repo_mgr = RepoManager() repo_output = [] for _, repo in repo_mgr._repos: repo_output.append({"url": repo.url, "name": repo.name, "branch": repo.branch}) repo_filename = pth / "cogs" / "RepoManager" / "repos.json" with open(str(repo_filename), "w") as f: f.write(json.dumps(repo_output, indent=4)) instance_data = {instance_name: basic_config} instance_file = pth / "instance.json" with open(str(instance_file), "w") as instance_out: instance_out.write(json.dumps(instance_data, indent=4)) for f in pth.glob("**/*"): if not any(ex in str(f) for ex in exclusions): to_backup.append(f) with tarfile.open(str(backup_file), "w:gz") as tar: for f in to_backup: tar.add(str(f), recursive=False) print("A backup of {} has been made. It is at {}".format(selected, backup_file))
def get_data_dir(): default_data_dir = Path(appdir.user_data_dir) print( "Hello! Before we begin the full configuration process we need to" " gather some initial information about where you'd like us" " to store your bot's data. We've attempted to figure out a" " sane default data location which is printed below. If you don't" " want to change this default please press [ENTER], otherwise" " input your desired data location." ) print() print("Default: {}".format(default_data_dir)) new_path = input("> ") if new_path != "": new_path = Path(new_path) default_data_dir = new_path if not default_data_dir.exists(): try: default_data_dir.mkdir(parents=True, exist_ok=True) except OSError: print( "We were unable to create your chosen directory." " You may need to restart this process with admin" " privileges." ) sys.exit(1) print("You have chosen {} to be your data directory.".format(default_data_dir)) if not confirm("Please confirm (y/n):"): print("Please start the process over.") sys.exit(0) return default_data_dir
async def edit_instance(): instance_list = load_existing_config() if not instance_list: print("No instances have been set up!") return print( "You have chosen to edit an instance. The following " "is a list of instances that currently exist:\n" ) for instance in instance_list.keys(): print("{}\n".format(instance)) print("Please select one of the above by entering its name") selected = input("> ") if selected not in instance_list.keys(): print("That isn't a valid instance!") return instance_data = instance_list[selected] default_dirs = deepcopy(basic_config_default) current_data_dir = Path(instance_data["DATA_PATH"]) print("You have selected '{}' as the instance to modify.".format(selected)) if not confirm("Please confirm (y/n):"): print("Ok, we will not continue then.") return print("Ok, we will continue on.") print() if confirm("Would you like to change the instance name? (y/n)"): name = get_name() else: name = selected if confirm("Would you like to change the data location? (y/n)"): default_data_dir = get_data_dir() default_dirs["DATA_PATH"] = str(default_data_dir.resolve()) else: default_dirs["DATA_PATH"] = str(current_data_dir.resolve()) if confirm("Would you like to change the storage type? (y/n):"): storage = get_storage_type() storage_dict = {1: "JSON", 2: "MongoDB"} default_dirs["STORAGE_TYPE"] = storage_dict[storage] if storage_dict.get(storage, 1) == "MongoDB": from botbase.core.drivers.red_mongo import get_config_details storage_details = get_config_details() default_dirs["STORAGE_DETAILS"] = storage_details if instance_data["STORAGE_TYPE"] == "JSON": if confirm("Would you like to import your data? (y/n) "): await json_to_mongo(current_data_dir, storage_details) else: storage_details = instance_data["STORAGE_DETAILS"] default_dirs["STORAGE_DETAILS"] = {} if instance_data["STORAGE_TYPE"] == "MongoDB": if confirm("Would you like to import your data? (y/n) "): await mongo_to_json(current_data_dir, storage_details) if name != selected: save_config(selected, {}, remove=True) save_config(name, default_dirs) print("Your basic configuration has been edited")
def main(): description = "Red - Version {}".format(__version__) cli_flags = parse_cli_flags(sys.argv[1:]) if cli_flags.list_instances: list_instances() elif cli_flags.version: print(description) sys.exit(0) elif not cli_flags.instance_name and not cli_flags.no_instance: print("Error: No instance name was provided!") sys.exit(1) if cli_flags.no_instance: print( "\033[1m" "Warning: The data will be placed in a temporary folder and removed on next system reboot." "\033[0m" ) cli_flags.instance_name = "temporary_red" create_temp_config() load_basic_configuration(cli_flags.instance_name) log, sentry_log = init_loggers(cli_flags) red = Red(cli_flags=cli_flags, description=description, pm_help=None) init_global_checks(red) init_events(red, cli_flags) red.add_cog(Core(red)) red.add_cog(CogManagerUI()) if cli_flags.dev: red.add_cog(Dev()) loop = asyncio.get_event_loop() tmp_data = {} loop.run_until_complete(_get_prefix_and_token(red, tmp_data)) token = os.environ.get("RED_TOKEN", tmp_data["token"]) if cli_flags.token: token = cli_flags.token prefix = cli_flags.prefix or tmp_data["prefix"] if not (token and prefix): if cli_flags.no_prompt is False: new_token = interactive_config(red, token_set=bool(token), prefix_set=bool(prefix)) if new_token: token = new_token else: log.critical("Token and prefix must be set in order to login.") sys.exit(1) loop.run_until_complete(_get_prefix_and_token(red, tmp_data)) if cli_flags.dry_run: loop.run_until_complete(red.http.close()) sys.exit(0) if tmp_data["enable_sentry"]: red.enable_sentry() try: loop.run_until_complete(red.start(token, bot=not cli_flags.not_bot)) except discord.LoginFailure: log.critical( "This token doesn't seem to be valid. If it belongs to " "a user account, remember that the --not-bot flag " "must be used. For self-bot functionalities instead, " "--self-bot" ) db_token = loop.run_until_complete(red.db.token()) if db_token and not cli_flags.no_prompt: print("\nDo you want to reset the token? (y/n)") if confirm("> "): loop.run_until_complete(red.db.token.set("")) print("Token has been reset.") except KeyboardInterrupt: log.info("Keyboard interrupt detected. Quitting...") loop.run_until_complete(red.logout()) red._shutdown_mode = ExitCodes.SHUTDOWN except Exception as e: log.critical("Fatal exception", exc_info=e) sentry_log.critical("Fatal Exception", exc_info=e) loop.run_until_complete(red.logout()) finally: pending = asyncio.Task.all_tasks(loop=red.loop) gathered = asyncio.gather(*pending, loop=red.loop, return_exceptions=True) gathered.cancel() try: red.rpc.server.close() except AttributeError: pass sys.exit(red._shutdown_mode.value)