mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 19:28:54 -05:00
[V3 Launcher] Reinstall Red option (#1536)
* [V3 Launcher] Reinstall Red option * [V3 Setup] Divided remove_instance function * Removing changes from another PR * Indent fails fix * use remove_instance_interaction for --delete * Fix some issues with remove_instance removed `index: int` because what's being passed there is a string data -> instance_data * bug fixes, working version
This commit is contained in:
parent
23192b9ef6
commit
95ef5d6348
@ -7,7 +7,10 @@ import argparse
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
from redbot.setup import basic_setup, load_existing_config, remove_instance
|
from pathlib import Path
|
||||||
|
from redbot.setup import basic_setup, load_existing_config, remove_instance, remove_instance_interaction, create_backup, save_config
|
||||||
|
from redbot.core.utils import safe_delete
|
||||||
|
from redbot.core.cli import confirm
|
||||||
|
|
||||||
if sys.platform == "linux":
|
if sys.platform == "linux":
|
||||||
import distro
|
import distro
|
||||||
@ -60,7 +63,7 @@ def parse_cli_args():
|
|||||||
return parser.parse_known_args()
|
return parser.parse_known_args()
|
||||||
|
|
||||||
|
|
||||||
def update_red(dev=False, voice=False, mongo=False, docs=False, test=False):
|
def update_red(dev=False, reinstall=False, voice=False, mongo=False, docs=False, test=False):
|
||||||
interpreter = sys.executable
|
interpreter = sys.executable
|
||||||
print("Updating Red...")
|
print("Updating Red...")
|
||||||
# If the user ran redbot-launcher.exe, updating with pip will fail
|
# If the user ran redbot-launcher.exe, updating with pip will fail
|
||||||
@ -93,6 +96,15 @@ def update_red(dev=False, voice=False, mongo=False, docs=False, test=False):
|
|||||||
package = "Red-DiscordBot"
|
package = "Red-DiscordBot"
|
||||||
if egg_l:
|
if egg_l:
|
||||||
package += "[{}]".format(", ".join(egg_l))
|
package += "[{}]".format(", ".join(egg_l))
|
||||||
|
if reinstall:
|
||||||
|
code = subprocess.call([
|
||||||
|
interpreter, "-m",
|
||||||
|
"pip", "install", "-U", "-I",
|
||||||
|
"--force-reinstall", "--no-cache-dir",
|
||||||
|
"--process-dependency-links",
|
||||||
|
package
|
||||||
|
])
|
||||||
|
else:
|
||||||
code = subprocess.call([
|
code = subprocess.call([
|
||||||
interpreter, "-m",
|
interpreter, "-m",
|
||||||
"pip", "install", "-U",
|
"pip", "install", "-U",
|
||||||
@ -223,6 +235,37 @@ def instance_menu():
|
|||||||
return name_num_map[str(selection)]
|
return name_num_map[str(selection)]
|
||||||
|
|
||||||
|
|
||||||
|
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 Red 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 clear_screen():
|
def clear_screen():
|
||||||
if IS_WINDOWS:
|
if IS_WINDOWS:
|
||||||
os.system("cls")
|
os.system("cls")
|
||||||
@ -247,6 +290,33 @@ def extras_selector():
|
|||||||
return selected
|
return selected
|
||||||
|
|
||||||
|
|
||||||
|
def development_choice(reinstall = False):
|
||||||
|
while True:
|
||||||
|
print("\n")
|
||||||
|
print("Do you want to install stable or development version?")
|
||||||
|
print("1. Stable version")
|
||||||
|
print("2. Development version")
|
||||||
|
choice = user_choice()
|
||||||
|
print("\n")
|
||||||
|
selected = extras_selector()
|
||||||
|
if choice == "1":
|
||||||
|
update_red(
|
||||||
|
dev=False, reinstall=reinstall, voice=True if "voice" in selected else False,
|
||||||
|
docs=True if "docs" in selected else False,
|
||||||
|
test=True if "test" in selected else False,
|
||||||
|
mongo=True if "mongo" in selected else False
|
||||||
|
)
|
||||||
|
break
|
||||||
|
elif choice == "2":
|
||||||
|
update_red(
|
||||||
|
dev=True, reinstall=reinstall, voice=True if "voice" in selected else False,
|
||||||
|
docs=True if "docs" in selected else False,
|
||||||
|
test=True if "test" in selected else False,
|
||||||
|
mongo=True if "mongo" in selected else False
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
def debug_info():
|
def debug_info():
|
||||||
pyver = sys.version
|
pyver = sys.version
|
||||||
redver = pkg_resources.get_distribution("Red-DiscordBot").version
|
redver = pkg_resources.get_distribution("Red-DiscordBot").version
|
||||||
@ -275,55 +345,64 @@ def debug_info():
|
|||||||
def main_menu():
|
def main_menu():
|
||||||
if IS_WINDOWS:
|
if IS_WINDOWS:
|
||||||
os.system("TITLE Red - Discord Bot V3 Launcher")
|
os.system("TITLE Red - Discord Bot V3 Launcher")
|
||||||
|
clear_screen()
|
||||||
while True:
|
while True:
|
||||||
print(INTRO)
|
print(INTRO)
|
||||||
print("1. Run Red w/ autorestart in case of issues")
|
print("1. Run Red w/ autorestart in case of issues")
|
||||||
print("2. Run Red")
|
print("2. Run Red")
|
||||||
print("3. Update Red")
|
print("3. Update Red")
|
||||||
print("4. Update Red (development version)")
|
print("4. Create Instance")
|
||||||
print("5. Create Instance")
|
print("5. Remove Instance")
|
||||||
print("6. Remove Instance")
|
print("6. Debug information (use this if having issues with the launcher or bot)")
|
||||||
print("7. Debug information (use this if having issues with the launcher or bot)")
|
print("7. Reinstall Red")
|
||||||
print("0. Exit")
|
print("0. Exit")
|
||||||
choice = user_choice()
|
choice = user_choice()
|
||||||
if choice == "1":
|
if choice == "1":
|
||||||
instance = instance_menu()
|
instance = instance_menu()
|
||||||
if instance:
|
|
||||||
cli_flags = cli_flag_getter()
|
cli_flags = cli_flag_getter()
|
||||||
|
if instance:
|
||||||
run_red(instance, autorestart=True, cliflags=cli_flags)
|
run_red(instance, autorestart=True, cliflags=cli_flags)
|
||||||
wait()
|
wait()
|
||||||
elif choice == "2":
|
elif choice == "2":
|
||||||
instance = instance_menu()
|
instance = instance_menu()
|
||||||
if instance:
|
|
||||||
cli_flags = cli_flag_getter()
|
cli_flags = cli_flag_getter()
|
||||||
|
if instance:
|
||||||
run_red(instance, autorestart=False, cliflags=cli_flags)
|
run_red(instance, autorestart=False, cliflags=cli_flags)
|
||||||
wait()
|
wait()
|
||||||
elif choice == "3":
|
elif choice == "3":
|
||||||
selected = extras_selector()
|
development_choice()
|
||||||
update_red(
|
|
||||||
dev=False, voice=True if "voice" in selected else False,
|
|
||||||
docs=True if "docs" in selected else False,
|
|
||||||
test=True if "test" in selected else False,
|
|
||||||
mongo=True if "mongo" in selected else False
|
|
||||||
)
|
|
||||||
wait()
|
wait()
|
||||||
elif choice == "4":
|
elif choice == "4":
|
||||||
selected = extras_selector()
|
|
||||||
update_red(
|
|
||||||
dev=True, voice=True if "voice" in selected else False,
|
|
||||||
docs=True if "docs" in selected else False,
|
|
||||||
test=True if "test" in selected else False,
|
|
||||||
mongo=True if "mongo" in selected else False
|
|
||||||
)
|
|
||||||
wait()
|
|
||||||
elif choice == "5":
|
|
||||||
basic_setup()
|
basic_setup()
|
||||||
wait()
|
wait()
|
||||||
elif choice == "6":
|
elif choice == "5":
|
||||||
asyncio.get_event_loop().run_until_complete(remove_instance())
|
asyncio.get_event_loop().run_until_complete(remove_instance_interaction())
|
||||||
wait()
|
wait()
|
||||||
elif choice == "7":
|
elif choice == "6":
|
||||||
debug_info()
|
debug_info()
|
||||||
|
elif choice == "7":
|
||||||
|
while True:
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
clear_screen()
|
||||||
|
print("==== Reinstall Red ====")
|
||||||
|
print("1. Reinstall Red requirements (discard code changes, keep data and 3rd party cogs)")
|
||||||
|
print("2. Reset all data")
|
||||||
|
print("3. Factory reset (discard code changes, reset all data)")
|
||||||
|
print("\n")
|
||||||
|
print("0. Back")
|
||||||
|
choice = user_choice()
|
||||||
|
if choice == "1":
|
||||||
|
development_choice(reinstall=True)
|
||||||
|
wait()
|
||||||
|
elif choice == "2":
|
||||||
|
loop.run_until_complete(reset_red())
|
||||||
|
wait()
|
||||||
|
elif choice == "3":
|
||||||
|
loop.run_until_complete(reset_red())
|
||||||
|
development_choice(reinstall=True)
|
||||||
|
wait()
|
||||||
|
elif choice == "0":
|
||||||
|
break
|
||||||
elif choice == "0":
|
elif choice == "0":
|
||||||
break
|
break
|
||||||
clear_screen()
|
clear_screen()
|
||||||
|
|||||||
126
redbot/setup.py
126
redbot/setup.py
@ -302,7 +302,61 @@ async def edit_instance():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def remove_instance():
|
async def create_backup(selected, instance_data):
|
||||||
|
if confirm("Would you like to make a backup of the data for this instance? (y/n)"):
|
||||||
|
if instance_data["STORAGE_TYPE"] == "MongoDB":
|
||||||
|
print("Backing up the instance's data...")
|
||||||
|
await mongo_to_json(instance_data["DATA_PATH"], instance_data["STORAGE_DETAILS"])
|
||||||
|
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():
|
||||||
|
home = pth.home()
|
||||||
|
backup_file = home / backup_filename
|
||||||
|
os.chdir(str(pth.parent))
|
||||||
|
with tarfile.open(str(backup_file), "w:gz") as tar:
|
||||||
|
tar.add(pth.stem)
|
||||||
|
print("A backup of {} has been made. It is at {}".format(
|
||||||
|
selected, backup_file
|
||||||
|
))
|
||||||
|
|
||||||
|
else:
|
||||||
|
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():
|
||||||
|
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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def remove_instance(selected, instance_data):
|
||||||
|
instance_list = load_existing_config()
|
||||||
|
if instance_data["STORAGE_TYPE"] == "MongoDB":
|
||||||
|
m = Mongo("Core", **instance_data["STORAGE_DETAILS"])
|
||||||
|
db = m.db
|
||||||
|
collections = await db.collection_names(include_system_collections=False)
|
||||||
|
for name in collections:
|
||||||
|
collection = await db.get_collection(name)
|
||||||
|
await collection.drop()
|
||||||
|
else:
|
||||||
|
pth = Path(instance_data["DATA_PATH"])
|
||||||
|
safe_delete(pth)
|
||||||
|
save_config(selected, {}, remove=True)
|
||||||
|
print("The instance {} has been removed\n".format(selected))
|
||||||
|
|
||||||
|
|
||||||
|
async def remove_instance_interaction():
|
||||||
instance_list = load_existing_config()
|
instance_list = load_existing_config()
|
||||||
if not instance_list:
|
if not instance_list:
|
||||||
print("No instances have been set up!")
|
print("No instances have been set up!")
|
||||||
@ -322,78 +376,14 @@ async def remove_instance():
|
|||||||
return
|
return
|
||||||
instance_data = instance_list[selected]
|
instance_data = instance_list[selected]
|
||||||
|
|
||||||
if confirm("Would you like to make a backup of the data for this instance? (y/n)"):
|
await create_backup(selected, instance_data)
|
||||||
if instance_data["STORAGE_TYPE"] == "MongoDB":
|
await remove_instance(selected, instance_data)
|
||||||
print("Backing up the instance's data...")
|
|
||||||
await mongo_to_json(instance_data["DATA_PATH"], instance_data["STORAGE_DETAILS"])
|
|
||||||
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():
|
|
||||||
home = pth.home()
|
|
||||||
backup_file = home / backup_filename
|
|
||||||
os.chdir(str(pth.parent))
|
|
||||||
with tarfile.open(str(backup_file), "w:gz") as tar:
|
|
||||||
tar.add(pth.stem)
|
|
||||||
print("A backup of {} has been made. It is at {}".format(
|
|
||||||
selected, backup_file
|
|
||||||
))
|
|
||||||
print("Removing the instance...")
|
|
||||||
|
|
||||||
m = Mongo("Core", **instance_data["STORAGE_DETAILS"])
|
|
||||||
db = m.db
|
|
||||||
collections = await db.collection_names(include_system_collections=False)
|
|
||||||
for name in collections:
|
|
||||||
collection = await db.get_collection(name)
|
|
||||||
await collection.drop()
|
|
||||||
safe_delete(pth)
|
|
||||||
save_config(selected, {}, remove=True)
|
|
||||||
print("The instance has been removed.")
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
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():
|
|
||||||
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...")
|
|
||||||
safe_delete(pth)
|
|
||||||
save_config(selected, {}, remove=True)
|
|
||||||
print("The instance has been removed")
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
print("Removing the instance...")
|
|
||||||
if instance_data["STORAGE_TYPE"] == "MongoDB":
|
|
||||||
m = Mongo("Core", **instance_data["STORAGE_DETAILS"])
|
|
||||||
db = m.db
|
|
||||||
collections = await db.collection_names(include_system_collections=False)
|
|
||||||
for name in collections:
|
|
||||||
collection = await db.get_collection(name)
|
|
||||||
await collection.drop()
|
|
||||||
else:
|
|
||||||
pth = Path(instance_data["DATA_PATH"])
|
|
||||||
safe_delete(pth)
|
|
||||||
save_config(selected, {}, remove=True)
|
|
||||||
print("The instance has been removed")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if args.delete:
|
if args.delete:
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
loop.run_until_complete(remove_instance())
|
loop.run_until_complete(remove_instance_interaction())
|
||||||
elif args.edit:
|
elif args.edit:
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
loop.run_until_complete(edit_instance())
|
loop.run_until_complete(edit_instance())
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user