Repository: Cog-Creators/Red-DiscordBot

Issue:
Add a `--unload-cog [UNLOAD_COGS...]` cli flag 
### Type of feature request

Other

### Description of the feature you're suggesting

Adds a way to unload a cog when starting red using the cli - `--unload-cog [UNLOAD_COGS...]`
Kinda similar to `--load-cogs [LOAD_COGS...]` but does the opposite, instead of loading the cogs, it unloads the specified cog.

### Anything else?

So I was having some issues lately with a third party cog which was not letting my bot start and was crashing it on boot, and it was impossible to unload that single cog before starting up the bot, and it's hard to remember what cogs I have loaded at times, and using the `--no-cogs` flag just starts the bot without any cog being loaded on start. It'll be really convenient to have a cli option to unload one or more cogs at boot if some cog is causing the bot to not boot up or similar issue to what I've faced in the past.


Discussion:

Resolving patch:
diff --git a/redbot/core/bot.py b/redbot/core/bot.py
--- a/redbot/core/bot.py
+++ b/redbot/core/bot.py
@@ -8,7 +8,7 @@
 import contextlib
 import weakref
 import functools
-from collections import namedtuple
+from collections import namedtuple, OrderedDict
 from datetime import datetime
 from enum import IntEnum
 from importlib.machinery import ModuleSpec
@@ -1109,7 +1109,7 @@ async def _pre_connect(self) -> None:
         await modlog._init(self)
         await bank._init()
 
-        packages = []
+        packages = OrderedDict()
 
         last_system_info = await self._config.last_system_info()
 
@@ -1135,10 +1135,13 @@ async def _pre_connect(self) -> None:
                 python_version_changed = True
         else:
             if self._cli_flags.no_cogs is False:
-                packages.extend(await self._config.packages())
+                packages.update(dict.fromkeys(await self._config.packages()))
 
             if self._cli_flags.load_cogs:
-                packages.extend(self._cli_flags.load_cogs)
+                packages.update(dict.fromkeys(self._cli_flags.load_cogs))
+            if self._cli_flags.unload_cogs:
+                for package in self._cli_flags.unload_cogs:
+                    packages.pop(package, None)
 
         system_changed = False
         machine = platform.machine()
@@ -1169,11 +1172,9 @@ async def _pre_connect(self) -> None:
         if packages:
             # Load permissions first, for security reasons
             try:
-                packages.remove("permissions")
-            except ValueError:
+                packages.move_to_end("permissions", last=False)
+            except KeyError:
                 pass
-            else:
-                packages.insert(0, "permissions")
 
             to_remove = []
             log.info("Loading packages...")
@@ -1197,9 +1198,11 @@ async def _pre_connect(self) -> None:
                     await self.remove_loaded_package(package)
                     to_remove.append(package)
             for package in to_remove:
-                packages.remove(package)
-            if packages:
-                log.info("Loaded packages: " + ", ".join(packages))
+                del packages[package]
+        if packages:
+            log.info("Loaded packages: " + ", ".join(packages))
+        else:
+            log.info("No packages were loaded.")
 
         if self.rpc_enabled:
             await self.rpc.initialize(self.rpc_port)
diff --git a/redbot/core/cli.py b/redbot/core/cli.py
--- a/redbot/core/cli.py
+++ b/redbot/core/cli.py
@@ -185,6 +185,9 @@ def parse_cli_flags(args):
         help="Force loading specified cogs from the installed packages. "
         "Can be used with the --no-cogs flag to load these cogs exclusively.",
     )
+    parser.add_argument(
+        "--unload-cogs", type=str, nargs="+", help="Force unloading specified cogs."
+    )
     parser.add_argument(
         "--dry-run",
         action="store_true",


Test patch: