We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[V3 Core] Setup should warn if replacing existing instance.
Please be sure to read through other issues as well to make sure what you are suggesting/reporting has not already
been suggested/reported

### Type:

- [x] Suggestion
- [ ] Bug

### Brief description of the problem
Running redbot-setup with an existing redbot instance doesn't trigger any warnings, it just replaces it.
### Expected behavior
Warnings before anything is done and options to cancel or continuing.
### Actual behavior
Nothing, it continues as it is and replaces the existing instance values with the new instance values (same name)
### Steps to reproduce

1. Run redbot-setup
2. follow the instructions on creating a new instance.
3. Make a new instance
4. Check config.json or the flags for details on the instances...is there even one?
5. Repeat Steps 2-4 for another instance and check.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `redbot/setup.py`
Content:
```
1 #!/usr/bin/env python
2 
3 import argparse
4 import asyncio
5 import json
6 import os
7 import shutil
8 import sys
9 import tarfile
10 from copy import deepcopy
11 from datetime import datetime as dt
12 from pathlib import Path
13 
14 import appdirs
15 from redbot.core.cli import confirm
16 from redbot.core.data_manager import basic_config_default
17 from redbot.core.json_io import JsonIO
18 from redbot.core.utils import safe_delete
19 
20 config_dir = None
21 appdir = appdirs.AppDirs("Red-DiscordBot")
22 if sys.platform == 'linux':
23     if 0 < os.getuid() < 1000:
24         config_dir = Path(appdir.site_data_dir)
25 if not config_dir:
26     config_dir = Path(appdir.user_config_dir)
27 try:
28     config_dir.mkdir(parents=True, exist_ok=True)
29 except PermissionError:
30     print(
31         "You don't have permission to write to "
32         "'{}'\nExiting...".format(config_dir))
33     sys.exit(1)
34 config_file = config_dir / 'config.json'
35 
36 
37 def parse_cli_args():
38     parser = argparse.ArgumentParser(
39         description="Red - Discord Bot's instance manager (V3)"
40     )
41     parser.add_argument(
42         "--delete", "-d",
43         help="Interactively delete an instance",
44         action="store_true"
45     )
46     parser.add_argument(
47         "--edit", "-e",
48         help="Interactively edit an instance",
49         action="store_true"
50     )
51     return parser.parse_known_args()
52 
53 
54 def load_existing_config():
55     if not config_file.exists():
56         return {}
57 
58     return JsonIO(config_file)._load_json()
59 
60 
61 def save_config(name, data, remove=False):
62     config = load_existing_config()
63     if remove and name in config:
64         config.pop(name)
65     else:
66         config[name] = data
67     JsonIO(config_file)._save_json(config)
68 
69 
70 def get_data_dir():
71     default_data_dir = Path(appdir.user_data_dir)
72 
73     print("Hello! Before we begin the full configuration process we need to"
74           " gather some initial information about where you'd like us"
75           " to store your bot's data. We've attempted to figure out a"
76           " sane default data location which is printed below. If you don't"
77           " want to change this default please press [ENTER], otherwise"
78           " input your desired data location.")
79     print()
80     print("Default: {}".format(default_data_dir))
81 
82     new_path = input('> ')
83 
84     if new_path != '':
85         new_path = Path(new_path)
86         default_data_dir = new_path
87 
88     if not default_data_dir.exists():
89         try:
90             default_data_dir.mkdir(parents=True, exist_ok=True)
91         except OSError:
92             print("We were unable to create your chosen directory."
93                   " You may need to restart this process with admin"
94                   " privileges.")
95             sys.exit(1)
96 
97     print("You have chosen {} to be your data directory."
98           "".format(default_data_dir))
99     if not confirm("Please confirm (y/n):"):
100         print("Please start the process over.")
101         sys.exit(0)
102     return default_data_dir
103 
104 
105 def get_storage_type():
106     storage_dict = {
107         1: "JSON",
108         2: "MongoDB"
109     }
110     storage = None
111     while storage is None:
112         print()
113         print("Please choose your storage backend (if you're unsure, choose 1).")
114         print("1. JSON (file storage, requires no database).")
115         print("2. MongoDB")
116         storage = input("> ")
117         try:
118             storage = int(storage)
119         except ValueError:
120             storage = None
121         else:
122             if storage not in storage_dict:
123                 storage = None
124     return storage
125 
126 
127 def get_name():
128     name = ""
129     while len(name) == 0:
130         print()
131         print("Please enter a name for your instance, this name cannot include spaces"
132               " and it will be used to run your bot from here on out.")
133         name = input("> ")
134         if " " in name:
135             name = ""
136     return name
137 
138 
139 def basic_setup():
140     """
141     Creates the data storage folder.
142     :return:
143     """
144 
145     default_data_dir = get_data_dir()
146 
147     default_dirs = deepcopy(basic_config_default)
148     default_dirs['DATA_PATH'] = str(default_data_dir.resolve())
149 
150     storage = get_storage_type()
151 
152     storage_dict = {
153         1: "JSON",
154         2: "MongoDB"
155     }
156     default_dirs['STORAGE_TYPE'] = storage_dict.get(storage, 1)
157 
158     if storage_dict.get(storage, 1) == "MongoDB":
159         from redbot.core.drivers.red_mongo import get_config_details
160         default_dirs['STORAGE_DETAILS'] = get_config_details()
161     else:
162         default_dirs['STORAGE_DETAILS'] = {}
163 
164     name = get_name()
165     save_config(name, default_dirs)
166 
167     print()
168     print("Your basic configuration has been saved. Please run `redbot <name>` to"
169           " continue your setup process and to run the bot.")
170 
171 
172 async def edit_instance():
173     instance_list = load_existing_config()
174     if not instance_list:
175         print("No instances have been set up!")
176         return
177 
178     print(
179         "You have chosen to edit an instance. The following "
180         "is a list of instances that currently exist:\n"
181     )
182     for instance in instance_list.keys():
183         print("{}\n".format(instance))
184     print("Please select one of the above by entering its name")
185     selected = input("> ")
186 
187     if selected not in instance_list.keys():
188         print("That isn't a valid instance!")
189         return
190     instance_data = instance_list[selected]
191     default_dirs = deepcopy(basic_config_default)
192 
193     current_data_dir = Path(instance_data["DATA_PATH"])
194     print(
195         "You have selected '{}' as the instance to modify.".format(selected)
196     )
197     if not confirm("Please confirm (y/n):"):
198         print("Ok, we will not continue then.")
199         return
200 
201     print("Ok, we will continue on.")
202     print()
203     if confirm("Would you like to change the instance name? (y/n)"):
204         name = get_name()
205     else:
206         name = selected
207 
208     if confirm("Would you like to change the data location? (y/n)"):
209         default_data_dir = get_data_dir()
210         default_dirs["DATA_PATH"] = str(default_data_dir.resolve())
211     else:
212         default_dirs["DATA_PATH"] = str(current_data_dir.resolve())
213 
214     if confirm("Would you like to change the storage type? (y/n):"):
215         storage = get_storage_type()
216 
217         storage_dict = {
218             1: "JSON",
219             2: "MongoDB"
220         }
221         default_dirs["STORAGE_TYPE"] = storage_dict[storage]
222         if storage_dict.get(storage, 1) == "MongoDB":
223             from redbot.core.drivers.red_mongo import get_config_details, Mongo
224             storage_details = get_config_details()
225             default_dirs["STORAGE_DETAILS"] = storage_details
226 
227             if instance_data["STORAGE_TYPE"] == "JSON":
228                 if confirm("Would you like to import your data? (y/n)"):
229                     core_data_file = list(current_data_dir.glob("core/settings.json"))[0]
230                     m = Mongo("Core", **storage_details)
231                     with core_data_file.open(mode="r") as f:
232                         core_data = json.loads(f.read())
233                     m.unique_cog_identifier = "0"
234                     collection = m.get_collection()
235                     await collection.update_one(
236                         {'_id': m.unique_cog_identifier},
237                         update={"$set": core_data["0"]},
238                         upsert=True
239                     )
240                     for p in current_data_dir.glob("cogs/**/settings.json"):
241                         cog_m = Mongo(p.parent.stem, **storage_details)
242                         cog_c = cog_m.get_collection()
243                         with p.open(mode="r") as f:
244                             cog_data = json.loads(f.read())
245                         for ident in list(cog_data.keys()):
246                             cog_m.unique_cog_identifier = ident
247                             await cog_c.update_one(
248                                 {"_id": cog_m.unique_cog_identifier},
249                                 update={"$set": cog_data[ident]},
250                                 upsert=True
251                             )
252         else:
253             default_dirs["STORAGE_DETAILS"] = {}
254             if instance_data["STORAGE_TYPE"] == "MongoDB":
255                 from redbot.core.drivers.red_mongo import Mongo
256                 from redbot.core.drivers.red_json import JSON
257                 m = Mongo("Core", **instance_data["STORAGE_DETAILS"])
258                 db = m.db
259                 collection_names = await db.collection_names(include_system_collections=False)
260                 for c_name in collection_names:
261                     if c_name == "Core":
262                         c_data_path = current_data_dir / "core"
263                     else:
264                         c_data_path = current_data_dir / "cogs/{}".format(c_name)
265                     output = {}
266                     docs = await db[c_name].find().to_list(None)
267                     for item in docs:
268                         item_id = str(item.pop("_id"))
269                         output[item_id] = item
270                     target = JSON(c_name, data_path_override=c_data_path)
271                     await target.jsonIO._threadsafe_save_json(output)
272 
273     if name != selected:
274         save_config(selected, {}, remove=True)
275     save_config(name, default_dirs)
276 
277     print(
278         "Your basic configuration has been edited"
279     )
280 
281 
282 def remove_instance():
283     instance_list = load_existing_config()
284     if not instance_list:
285         print("No instances have been set up!")
286         return
287 
288     print(
289         "You have chosen to remove an instance. The following "
290         "is a list of instances that currently exist:\n"
291     )
292     for instance in instance_list.keys():
293         print("{}\n".format(instance))
294     print("Please select one of the above by entering its name")
295     selected = input("> ")
296     
297     if selected not in instance_list.keys():
298         print("That isn't a valid instance!")
299         return
300     instance_data = instance_list[selected]
301 
302     if confirm("Would you like to make a backup of the data for this instance? (y/n)"):
303         if instance_data["STORAGE_TYPE"] == "MongoDB":
304             raise NotImplementedError(
305                 "Support for removing instances with MongoDB as the storage "
306                 "is not implemented at this time due to backup support."
307             )
308         else:
309             print("Backing up the instance's data...")
310             backup_filename = "redv3-{}-{}.tar.gz".format(
311                 selected, dt.utcnow().strftime("%Y-%m-%d %H-%M-%S")
312             )
313             pth = Path(instance_data["DATA_PATH"])
314             if pth.exists():
315                 home = pth.home()
316                 backup_file = home / backup_filename
317                 os.chdir(str(pth.parent))  # str is used here because 3.5 support
318                 with tarfile.open(str(backup_file), "w:gz") as tar:
319                     tar.add(pth.stem)  # add all files in that directory
320                 print(
321                     "A backup of {} has been made. It is at {}".format(
322                         selected, backup_file
323                     )
324                 )
325                 print("Removing the instance...")
326                 safe_delete(pth)
327             save_config(selected, {}, remove=True)
328             print("The instance has been removed")
329             return
330     else:
331         pth = Path(instance_data["DATA_PATH"])
332         print("Removing the instance...")
333         safe_delete(pth)
334         save_config(selected, {}, remove=True)
335         print("The instance has been removed")
336         return
337 
338 
339 def main():
340     if args.delete:
341         try:
342             remove_instance()
343         except NotImplementedError as e:
344             print(str(e))
345     elif args.edit:
346         loop = asyncio.get_event_loop()
347         loop.run_until_complete(edit_instance())
348     else:
349         basic_setup()
350 
351 args, _ = parse_cli_args()
352 
353 if __name__ == "__main__":
354     try:
355         main()
356     except KeyboardInterrupt:
357         print("Exiting...")
358     else:
359         print("Exiting...")
360
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/redbot/setup.py b/redbot/setup.py
--- a/redbot/setup.py
+++ b/redbot/setup.py
@@ -63,6 +63,14 @@
     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)

{"golden_diff": "diff --git a/redbot/setup.py b/redbot/setup.py\n--- a/redbot/setup.py\n+++ b/redbot/setup.py\n@@ -63,6 +63,14 @@\n     if remove and name in config:\n         config.pop(name)\n     else:\n+        if name in config:\n+            print(\n+                \"WARNING: An instance already exists with this name. \"\n+                \"Continuing will overwrite the existing instance config.\"\n+            )\n+            if not confirm(\"Are you absolutely certain you want to continue (y/n)? \"):\n+                print(\"Not continuing\")\n+                sys.exit(0)\n         config[name] = data\n     JsonIO(config_file)._save_json(config)\n", "issue": "[V3 Core] Setup should warn if replacing existing instance.\nPlease be sure to read through other issues as well to make sure what you are suggesting/reporting has not already\r\nbeen suggested/reported\r\n\r\n### Type:\r\n\r\n- [x] Suggestion\r\n- [ ] Bug\r\n\r\n### Brief description of the problem\r\nRunning redbot-setup with an existing redbot instance doesn't trigger any warnings, it just replaces it.\r\n### Expected behavior\r\nWarnings before anything is done and options to cancel or continuing.\r\n### Actual behavior\r\nNothing, it continues as it is and replaces the existing instance values with the new instance values (same name)\r\n### Steps to reproduce\r\n\r\n1. Run redbot-setup\r\n2. follow the instructions on creating a new instance.\r\n3. Make a new instance\r\n4. Check config.json or the flags for details on the instances...is there even one?\r\n5. Repeat Steps 2-4 for another instance and check.\n", "before_files": [{"content": "#!/usr/bin/env python\n\nimport argparse\nimport asyncio\nimport json\nimport os\nimport shutil\nimport sys\nimport tarfile\nfrom copy import deepcopy\nfrom datetime import datetime as dt\nfrom pathlib import Path\n\nimport appdirs\nfrom redbot.core.cli import confirm\nfrom redbot.core.data_manager import basic_config_default\nfrom redbot.core.json_io import JsonIO\nfrom redbot.core.utils import safe_delete\n\nconfig_dir = None\nappdir = appdirs.AppDirs(\"Red-DiscordBot\")\nif sys.platform == 'linux':\n    if 0 < os.getuid() < 1000:\n        config_dir = Path(appdir.site_data_dir)\nif not config_dir:\n    config_dir = Path(appdir.user_config_dir)\ntry:\n    config_dir.mkdir(parents=True, exist_ok=True)\nexcept PermissionError:\n    print(\n        \"You don't have permission to write to \"\n        \"'{}'\\nExiting...\".format(config_dir))\n    sys.exit(1)\nconfig_file = config_dir / 'config.json'\n\n\ndef parse_cli_args():\n    parser = argparse.ArgumentParser(\n        description=\"Red - Discord Bot's instance manager (V3)\"\n    )\n    parser.add_argument(\n        \"--delete\", \"-d\",\n        help=\"Interactively delete an instance\",\n        action=\"store_true\"\n    )\n    parser.add_argument(\n        \"--edit\", \"-e\",\n        help=\"Interactively edit an instance\",\n        action=\"store_true\"\n    )\n    return parser.parse_known_args()\n\n\ndef load_existing_config():\n    if not config_file.exists():\n        return {}\n\n    return JsonIO(config_file)._load_json()\n\n\ndef save_config(name, data, remove=False):\n    config = load_existing_config()\n    if remove and name in config:\n        config.pop(name)\n    else:\n        config[name] = data\n    JsonIO(config_file)._save_json(config)\n\n\ndef get_data_dir():\n    default_data_dir = Path(appdir.user_data_dir)\n\n    print(\"Hello! Before we begin the full configuration process we need to\"\n          \" gather some initial information about where you'd like us\"\n          \" to store your bot's data. We've attempted to figure out a\"\n          \" sane default data location which is printed below. If you don't\"\n          \" want to change this default please press [ENTER], otherwise\"\n          \" input your desired data location.\")\n    print()\n    print(\"Default: {}\".format(default_data_dir))\n\n    new_path = input('> ')\n\n    if new_path != '':\n        new_path = Path(new_path)\n        default_data_dir = new_path\n\n    if not default_data_dir.exists():\n        try:\n            default_data_dir.mkdir(parents=True, exist_ok=True)\n        except OSError:\n            print(\"We were unable to create your chosen directory.\"\n                  \" You may need to restart this process with admin\"\n                  \" privileges.\")\n            sys.exit(1)\n\n    print(\"You have chosen {} to be your data directory.\"\n          \"\".format(default_data_dir))\n    if not confirm(\"Please confirm (y/n):\"):\n        print(\"Please start the process over.\")\n        sys.exit(0)\n    return default_data_dir\n\n\ndef get_storage_type():\n    storage_dict = {\n        1: \"JSON\",\n        2: \"MongoDB\"\n    }\n    storage = None\n    while storage is None:\n        print()\n        print(\"Please choose your storage backend (if you're unsure, choose 1).\")\n        print(\"1. JSON (file storage, requires no database).\")\n        print(\"2. MongoDB\")\n        storage = input(\"> \")\n        try:\n            storage = int(storage)\n        except ValueError:\n            storage = None\n        else:\n            if storage not in storage_dict:\n                storage = None\n    return storage\n\n\ndef get_name():\n    name = \"\"\n    while len(name) == 0:\n        print()\n        print(\"Please enter a name for your instance, this name cannot include spaces\"\n              \" and it will be used to run your bot from here on out.\")\n        name = input(\"> \")\n        if \" \" in name:\n            name = \"\"\n    return name\n\n\ndef basic_setup():\n    \"\"\"\n    Creates the data storage folder.\n    :return:\n    \"\"\"\n\n    default_data_dir = get_data_dir()\n\n    default_dirs = deepcopy(basic_config_default)\n    default_dirs['DATA_PATH'] = str(default_data_dir.resolve())\n\n    storage = get_storage_type()\n\n    storage_dict = {\n        1: \"JSON\",\n        2: \"MongoDB\"\n    }\n    default_dirs['STORAGE_TYPE'] = storage_dict.get(storage, 1)\n\n    if storage_dict.get(storage, 1) == \"MongoDB\":\n        from redbot.core.drivers.red_mongo import get_config_details\n        default_dirs['STORAGE_DETAILS'] = get_config_details()\n    else:\n        default_dirs['STORAGE_DETAILS'] = {}\n\n    name = get_name()\n    save_config(name, default_dirs)\n\n    print()\n    print(\"Your basic configuration has been saved. Please run `redbot <name>` to\"\n          \" continue your setup process and to run the bot.\")\n\n\nasync def edit_instance():\n    instance_list = load_existing_config()\n    if not instance_list:\n        print(\"No instances have been set up!\")\n        return\n\n    print(\n        \"You have chosen to edit an instance. The following \"\n        \"is a list of instances that currently exist:\\n\"\n    )\n    for instance in instance_list.keys():\n        print(\"{}\\n\".format(instance))\n    print(\"Please select one of the above by entering its name\")\n    selected = input(\"> \")\n\n    if selected not in instance_list.keys():\n        print(\"That isn't a valid instance!\")\n        return\n    instance_data = instance_list[selected]\n    default_dirs = deepcopy(basic_config_default)\n\n    current_data_dir = Path(instance_data[\"DATA_PATH\"])\n    print(\n        \"You have selected '{}' as the instance to modify.\".format(selected)\n    )\n    if not confirm(\"Please confirm (y/n):\"):\n        print(\"Ok, we will not continue then.\")\n        return\n\n    print(\"Ok, we will continue on.\")\n    print()\n    if confirm(\"Would you like to change the instance name? (y/n)\"):\n        name = get_name()\n    else:\n        name = selected\n\n    if confirm(\"Would you like to change the data location? (y/n)\"):\n        default_data_dir = get_data_dir()\n        default_dirs[\"DATA_PATH\"] = str(default_data_dir.resolve())\n    else:\n        default_dirs[\"DATA_PATH\"] = str(current_data_dir.resolve())\n\n    if confirm(\"Would you like to change the storage type? (y/n):\"):\n        storage = get_storage_type()\n\n        storage_dict = {\n            1: \"JSON\",\n            2: \"MongoDB\"\n        }\n        default_dirs[\"STORAGE_TYPE\"] = storage_dict[storage]\n        if storage_dict.get(storage, 1) == \"MongoDB\":\n            from redbot.core.drivers.red_mongo import get_config_details, Mongo\n            storage_details = get_config_details()\n            default_dirs[\"STORAGE_DETAILS\"] = storage_details\n\n            if instance_data[\"STORAGE_TYPE\"] == \"JSON\":\n                if confirm(\"Would you like to import your data? (y/n)\"):\n                    core_data_file = list(current_data_dir.glob(\"core/settings.json\"))[0]\n                    m = Mongo(\"Core\", **storage_details)\n                    with core_data_file.open(mode=\"r\") as f:\n                        core_data = json.loads(f.read())\n                    m.unique_cog_identifier = \"0\"\n                    collection = m.get_collection()\n                    await collection.update_one(\n                        {'_id': m.unique_cog_identifier},\n                        update={\"$set\": core_data[\"0\"]},\n                        upsert=True\n                    )\n                    for p in current_data_dir.glob(\"cogs/**/settings.json\"):\n                        cog_m = Mongo(p.parent.stem, **storage_details)\n                        cog_c = cog_m.get_collection()\n                        with p.open(mode=\"r\") as f:\n                            cog_data = json.loads(f.read())\n                        for ident in list(cog_data.keys()):\n                            cog_m.unique_cog_identifier = ident\n                            await cog_c.update_one(\n                                {\"_id\": cog_m.unique_cog_identifier},\n                                update={\"$set\": cog_data[ident]},\n                                upsert=True\n                            )\n        else:\n            default_dirs[\"STORAGE_DETAILS\"] = {}\n            if instance_data[\"STORAGE_TYPE\"] == \"MongoDB\":\n                from redbot.core.drivers.red_mongo import Mongo\n                from redbot.core.drivers.red_json import JSON\n                m = Mongo(\"Core\", **instance_data[\"STORAGE_DETAILS\"])\n                db = m.db\n                collection_names = await db.collection_names(include_system_collections=False)\n                for c_name in collection_names:\n                    if c_name == \"Core\":\n                        c_data_path = current_data_dir / \"core\"\n                    else:\n                        c_data_path = current_data_dir / \"cogs/{}\".format(c_name)\n                    output = {}\n                    docs = await db[c_name].find().to_list(None)\n                    for item in docs:\n                        item_id = str(item.pop(\"_id\"))\n                        output[item_id] = item\n                    target = JSON(c_name, data_path_override=c_data_path)\n                    await target.jsonIO._threadsafe_save_json(output)\n\n    if name != selected:\n        save_config(selected, {}, remove=True)\n    save_config(name, default_dirs)\n\n    print(\n        \"Your basic configuration has been edited\"\n    )\n\n\ndef remove_instance():\n    instance_list = load_existing_config()\n    if not instance_list:\n        print(\"No instances have been set up!\")\n        return\n\n    print(\n        \"You have chosen to remove an instance. The following \"\n        \"is a list of instances that currently exist:\\n\"\n    )\n    for instance in instance_list.keys():\n        print(\"{}\\n\".format(instance))\n    print(\"Please select one of the above by entering its name\")\n    selected = input(\"> \")\n    \n    if selected not in instance_list.keys():\n        print(\"That isn't a valid instance!\")\n        return\n    instance_data = instance_list[selected]\n\n    if confirm(\"Would you like to make a backup of the data for this instance? (y/n)\"):\n        if instance_data[\"STORAGE_TYPE\"] == \"MongoDB\":\n            raise NotImplementedError(\n                \"Support for removing instances with MongoDB as the storage \"\n                \"is not implemented at this time due to backup support.\"\n            )\n        else:\n            print(\"Backing up the instance's data...\")\n            backup_filename = \"redv3-{}-{}.tar.gz\".format(\n                selected, dt.utcnow().strftime(\"%Y-%m-%d %H-%M-%S\")\n            )\n            pth = Path(instance_data[\"DATA_PATH\"])\n            if pth.exists():\n                home = pth.home()\n                backup_file = home / backup_filename\n                os.chdir(str(pth.parent))  # str is used here because 3.5 support\n                with tarfile.open(str(backup_file), \"w:gz\") as tar:\n                    tar.add(pth.stem)  # add all files in that directory\n                print(\n                    \"A backup of {} has been made. It is at {}\".format(\n                        selected, backup_file\n                    )\n                )\n                print(\"Removing the instance...\")\n                safe_delete(pth)\n            save_config(selected, {}, remove=True)\n            print(\"The instance has been removed\")\n            return\n    else:\n        pth = Path(instance_data[\"DATA_PATH\"])\n        print(\"Removing the instance...\")\n        safe_delete(pth)\n        save_config(selected, {}, remove=True)\n        print(\"The instance has been removed\")\n        return\n\n\ndef main():\n    if args.delete:\n        try:\n            remove_instance()\n        except NotImplementedError as e:\n            print(str(e))\n    elif args.edit:\n        loop = asyncio.get_event_loop()\n        loop.run_until_complete(edit_instance())\n    else:\n        basic_setup()\n\nargs, _ = parse_cli_args()\n\nif __name__ == \"__main__\":\n    try:\n        main()\n    except KeyboardInterrupt:\n        print(\"Exiting...\")\n    else:\n        print(\"Exiting...\")\n", "path": "redbot/setup.py"}], "after_files": [{"content": "#!/usr/bin/env python\n\nimport argparse\nimport asyncio\nimport json\nimport os\nimport shutil\nimport sys\nimport tarfile\nfrom copy import deepcopy\nfrom datetime import datetime as dt\nfrom pathlib import Path\n\nimport appdirs\nfrom redbot.core.cli import confirm\nfrom redbot.core.data_manager import basic_config_default\nfrom redbot.core.json_io import JsonIO\nfrom redbot.core.utils import safe_delete\n\nconfig_dir = None\nappdir = appdirs.AppDirs(\"Red-DiscordBot\")\nif sys.platform == 'linux':\n    if 0 < os.getuid() < 1000:\n        config_dir = Path(appdir.site_data_dir)\nif not config_dir:\n    config_dir = Path(appdir.user_config_dir)\ntry:\n    config_dir.mkdir(parents=True, exist_ok=True)\nexcept PermissionError:\n    print(\n        \"You don't have permission to write to \"\n        \"'{}'\\nExiting...\".format(config_dir))\n    sys.exit(1)\nconfig_file = config_dir / 'config.json'\n\n\ndef parse_cli_args():\n    parser = argparse.ArgumentParser(\n        description=\"Red - Discord Bot's instance manager (V3)\"\n    )\n    parser.add_argument(\n        \"--delete\", \"-d\",\n        help=\"Interactively delete an instance\",\n        action=\"store_true\"\n    )\n    parser.add_argument(\n        \"--edit\", \"-e\",\n        help=\"Interactively edit an instance\",\n        action=\"store_true\"\n    )\n    return parser.parse_known_args()\n\n\ndef load_existing_config():\n    if not config_file.exists():\n        return {}\n\n    return JsonIO(config_file)._load_json()\n\n\ndef save_config(name, data, remove=False):\n    config = load_existing_config()\n    if remove and name in config:\n        config.pop(name)\n    else:\n        if name in config:\n            print(\n                \"WARNING: An instance already exists with this name. \"\n                \"Continuing will overwrite the existing instance config.\"\n            )\n            if not confirm(\"Are you absolutely certain you want to continue (y/n)? \"):\n                print(\"Not continuing\")\n                sys.exit(0)\n        config[name] = data\n    JsonIO(config_file)._save_json(config)\n\n\ndef get_data_dir():\n    default_data_dir = Path(appdir.user_data_dir)\n\n    print(\"Hello! Before we begin the full configuration process we need to\"\n          \" gather some initial information about where you'd like us\"\n          \" to store your bot's data. We've attempted to figure out a\"\n          \" sane default data location which is printed below. If you don't\"\n          \" want to change this default please press [ENTER], otherwise\"\n          \" input your desired data location.\")\n    print()\n    print(\"Default: {}\".format(default_data_dir))\n\n    new_path = input('> ')\n\n    if new_path != '':\n        new_path = Path(new_path)\n        default_data_dir = new_path\n\n    if not default_data_dir.exists():\n        try:\n            default_data_dir.mkdir(parents=True, exist_ok=True)\n        except OSError:\n            print(\"We were unable to create your chosen directory.\"\n                  \" You may need to restart this process with admin\"\n                  \" privileges.\")\n            sys.exit(1)\n\n    print(\"You have chosen {} to be your data directory.\"\n          \"\".format(default_data_dir))\n    if not confirm(\"Please confirm (y/n):\"):\n        print(\"Please start the process over.\")\n        sys.exit(0)\n    return default_data_dir\n\n\ndef get_storage_type():\n    storage_dict = {\n        1: \"JSON\",\n        2: \"MongoDB\"\n    }\n    storage = None\n    while storage is None:\n        print()\n        print(\"Please choose your storage backend (if you're unsure, choose 1).\")\n        print(\"1. JSON (file storage, requires no database).\")\n        print(\"2. MongoDB\")\n        storage = input(\"> \")\n        try:\n            storage = int(storage)\n        except ValueError:\n            storage = None\n        else:\n            if storage not in storage_dict:\n                storage = None\n    return storage\n\n\ndef get_name():\n    name = \"\"\n    while len(name) == 0:\n        print()\n        print(\"Please enter a name for your instance, this name cannot include spaces\"\n              \" and it will be used to run your bot from here on out.\")\n        name = input(\"> \")\n        if \" \" in name:\n            name = \"\"\n    return name\n\n\ndef basic_setup():\n    \"\"\"\n    Creates the data storage folder.\n    :return:\n    \"\"\"\n\n    default_data_dir = get_data_dir()\n\n    default_dirs = deepcopy(basic_config_default)\n    default_dirs['DATA_PATH'] = str(default_data_dir.resolve())\n\n    storage = get_storage_type()\n\n    storage_dict = {\n        1: \"JSON\",\n        2: \"MongoDB\"\n    }\n    default_dirs['STORAGE_TYPE'] = storage_dict.get(storage, 1)\n\n    if storage_dict.get(storage, 1) == \"MongoDB\":\n        from redbot.core.drivers.red_mongo import get_config_details\n        default_dirs['STORAGE_DETAILS'] = get_config_details()\n    else:\n        default_dirs['STORAGE_DETAILS'] = {}\n\n    name = get_name()\n    save_config(name, default_dirs)\n\n    print()\n    print(\"Your basic configuration has been saved. Please run `redbot <name>` to\"\n          \" continue your setup process and to run the bot.\")\n\n\nasync def edit_instance():\n    instance_list = load_existing_config()\n    if not instance_list:\n        print(\"No instances have been set up!\")\n        return\n\n    print(\n        \"You have chosen to edit an instance. The following \"\n        \"is a list of instances that currently exist:\\n\"\n    )\n    for instance in instance_list.keys():\n        print(\"{}\\n\".format(instance))\n    print(\"Please select one of the above by entering its name\")\n    selected = input(\"> \")\n\n    if selected not in instance_list.keys():\n        print(\"That isn't a valid instance!\")\n        return\n    instance_data = instance_list[selected]\n    default_dirs = deepcopy(basic_config_default)\n\n    current_data_dir = Path(instance_data[\"DATA_PATH\"])\n    print(\n        \"You have selected '{}' as the instance to modify.\".format(selected)\n    )\n    if not confirm(\"Please confirm (y/n):\"):\n        print(\"Ok, we will not continue then.\")\n        return\n\n    print(\"Ok, we will continue on.\")\n    print()\n    if confirm(\"Would you like to change the instance name? (y/n)\"):\n        name = get_name()\n    else:\n        name = selected\n\n    if confirm(\"Would you like to change the data location? (y/n)\"):\n        default_data_dir = get_data_dir()\n        default_dirs[\"DATA_PATH\"] = str(default_data_dir.resolve())\n    else:\n        default_dirs[\"DATA_PATH\"] = str(current_data_dir.resolve())\n\n    if confirm(\"Would you like to change the storage type? (y/n):\"):\n        storage = get_storage_type()\n\n        storage_dict = {\n            1: \"JSON\",\n            2: \"MongoDB\"\n        }\n        default_dirs[\"STORAGE_TYPE\"] = storage_dict[storage]\n        if storage_dict.get(storage, 1) == \"MongoDB\":\n            from redbot.core.drivers.red_mongo import get_config_details, Mongo\n            storage_details = get_config_details()\n            default_dirs[\"STORAGE_DETAILS\"] = storage_details\n\n            if instance_data[\"STORAGE_TYPE\"] == \"JSON\":\n                if confirm(\"Would you like to import your data? (y/n)\"):\n                    core_data_file = list(current_data_dir.glob(\"core/settings.json\"))[0]\n                    m = Mongo(\"Core\", **storage_details)\n                    with core_data_file.open(mode=\"r\") as f:\n                        core_data = json.loads(f.read())\n                    m.unique_cog_identifier = \"0\"\n                    collection = m.get_collection()\n                    await collection.update_one(\n                        {'_id': m.unique_cog_identifier},\n                        update={\"$set\": core_data[\"0\"]},\n                        upsert=True\n                    )\n                    for p in current_data_dir.glob(\"cogs/**/settings.json\"):\n                        cog_m = Mongo(p.parent.stem, **storage_details)\n                        cog_c = cog_m.get_collection()\n                        with p.open(mode=\"r\") as f:\n                            cog_data = json.loads(f.read())\n                        for ident in list(cog_data.keys()):\n                            cog_m.unique_cog_identifier = ident\n                            await cog_c.update_one(\n                                {\"_id\": cog_m.unique_cog_identifier},\n                                update={\"$set\": cog_data[ident]},\n                                upsert=True\n                            )\n        else:\n            default_dirs[\"STORAGE_DETAILS\"] = {}\n            if instance_data[\"STORAGE_TYPE\"] == \"MongoDB\":\n                from redbot.core.drivers.red_mongo import Mongo\n                from redbot.core.drivers.red_json import JSON\n                m = Mongo(\"Core\", **instance_data[\"STORAGE_DETAILS\"])\n                db = m.db\n                collection_names = await db.collection_names(include_system_collections=False)\n                for c_name in collection_names:\n                    if c_name == \"Core\":\n                        c_data_path = current_data_dir / \"core\"\n                    else:\n                        c_data_path = current_data_dir / \"cogs/{}\".format(c_name)\n                    output = {}\n                    docs = await db[c_name].find().to_list(None)\n                    for item in docs:\n                        item_id = str(item.pop(\"_id\"))\n                        output[item_id] = item\n                    target = JSON(c_name, data_path_override=c_data_path)\n                    await target.jsonIO._threadsafe_save_json(output)\n\n    if name != selected:\n        save_config(selected, {}, remove=True)\n    save_config(name, default_dirs)\n\n    print(\n        \"Your basic configuration has been edited\"\n    )\n\n\ndef remove_instance():\n    instance_list = load_existing_config()\n    if not instance_list:\n        print(\"No instances have been set up!\")\n        return\n\n    print(\n        \"You have chosen to remove an instance. The following \"\n        \"is a list of instances that currently exist:\\n\"\n    )\n    for instance in instance_list.keys():\n        print(\"{}\\n\".format(instance))\n    print(\"Please select one of the above by entering its name\")\n    selected = input(\"> \")\n    \n    if selected not in instance_list.keys():\n        print(\"That isn't a valid instance!\")\n        return\n    instance_data = instance_list[selected]\n\n    if confirm(\"Would you like to make a backup of the data for this instance? (y/n)\"):\n        if instance_data[\"STORAGE_TYPE\"] == \"MongoDB\":\n            raise NotImplementedError(\n                \"Support for removing instances with MongoDB as the storage \"\n                \"is not implemented at this time due to backup support.\"\n            )\n        else:\n            print(\"Backing up the instance's data...\")\n            backup_filename = \"redv3-{}-{}.tar.gz\".format(\n                selected, dt.utcnow().strftime(\"%Y-%m-%d %H-%M-%S\")\n            )\n            pth = Path(instance_data[\"DATA_PATH\"])\n            if pth.exists():\n                home = pth.home()\n                backup_file = home / backup_filename\n                os.chdir(str(pth.parent))  # str is used here because 3.5 support\n                with tarfile.open(str(backup_file), \"w:gz\") as tar:\n                    tar.add(pth.stem)  # add all files in that directory\n                print(\n                    \"A backup of {} has been made. It is at {}\".format(\n                        selected, backup_file\n                    )\n                )\n                print(\"Removing the instance...\")\n                safe_delete(pth)\n            save_config(selected, {}, remove=True)\n            print(\"The instance has been removed\")\n            return\n    else:\n        pth = Path(instance_data[\"DATA_PATH\"])\n        print(\"Removing the instance...\")\n        safe_delete(pth)\n        save_config(selected, {}, remove=True)\n        print(\"The instance has been removed\")\n        return\n\n\ndef main():\n    if args.delete:\n        try:\n            remove_instance()\n        except NotImplementedError as e:\n            print(str(e))\n    elif args.edit:\n        loop = asyncio.get_event_loop()\n        loop.run_until_complete(edit_instance())\n    else:\n        basic_setup()\n\nargs, _ = parse_cli_args()\n\nif __name__ == \"__main__\":\n    try:\n        main()\n    except KeyboardInterrupt:\n        print(\"Exiting...\")\n    else:\n        print(\"Exiting...\")\n", "path": "redbot/setup.py"}]}