Merge branch 'V3/develop' into V3/develop

This commit is contained in:
Predeactor
2021-01-17 00:28:59 +01:00
committed by GitHub
1148 changed files with 168717 additions and 108918 deletions

View File

@@ -40,7 +40,7 @@ class Downloader(commands.Cog):
Community cogs, also called third party cogs, are not included
in the default Red install.
Community cogs come in repositories. Repos are a group of cogs
you can install. You always need to add the creator's repository
using the `[p]repo` command before you can install one or more
@@ -478,13 +478,22 @@ class Downloader(commands.Cog):
for page in pagify(content):
await target.send(page)
@commands.command()
@commands.command(require_var_positional=True)
@checks.is_owner()
async def pipinstall(self, ctx: commands.Context, *deps: str) -> None:
"""Install a group of dependencies using pip."""
if not deps:
await ctx.send_help()
return
"""
Install a group of dependencies using pip.
Examples:
- `[p]pipinstall bs4`
- `[p]pipinstall py-cpuinfo psutil`
Improper usage of this command can break your bot, be careful.
**Arguments**
- `<deps...>` The package or packages you wish to install.
"""
repo = Repo("", "", "", "", Path.cwd())
async with ctx.typing():
success = await repo.install_raw_requirements(deps, self.LIB_PATH)
@@ -513,7 +522,7 @@ class Downloader(commands.Cog):
@commands.group()
@checks.is_owner()
async def repo(self, ctx: commands.Context) -> None:
"""Repo management commands."""
"""Base command for repository management."""
pass
@repo.command(name="add")
@@ -522,8 +531,18 @@ class Downloader(commands.Cog):
) -> None:
"""Add a new repo.
Examples:
- `[p]repo add 26-Cogs https://github.com/Twentysix26/x26-Cogs`
- `[p]repo add Laggrons-Dumb-Cogs https://github.com/retke/Laggrons-Dumb-Cogs v3`
Repo names can only contain characters A-z, numbers, underscores, and hyphens.
The branch will be the default branch if not specified.
**Arguments**
- `<name>` The name given to the repo.
- `<repo_url>` URL to the cog branch. Usually GitHub or GitLab.
- `[branch]` Optional branch to install cogs from.
"""
agreed = await do_install_agreement(ctx)
if not agreed:
@@ -556,7 +575,9 @@ class Downloader(commands.Cog):
)
except OSError:
log.exception(
"Something went wrong trying to add repo %s under name %s", repo_url, name,
"Something went wrong trying to add repo %s under name %s",
repo_url,
name,
)
await ctx.send(
_(
@@ -569,9 +590,18 @@ class Downloader(commands.Cog):
if repo.install_msg:
await ctx.send(repo.install_msg.replace("[p]", ctx.clean_prefix))
@repo.command(name="delete", aliases=["remove", "del"], usage="<repo_name>")
@repo.command(name="delete", aliases=["remove", "del"])
async def _repo_del(self, ctx: commands.Context, repo: Repo) -> None:
"""Remove a repo and its files."""
"""
Remove a repo and its files.
Example:
- `[p]repo delete 26-Cogs`
**Arguments**
- `<repo>` The name of an already added repo
"""
await self._repo_manager.delete_repo(repo.name)
await ctx.send(
@@ -596,9 +626,17 @@ class Downloader(commands.Cog):
for page in pagify(joined, ["\n"], shorten_by=16):
await ctx.send(box(page.lstrip(" "), lang="diff"))
@repo.command(name="info", usage="<repo_name>")
@repo.command(name="info")
async def _repo_info(self, ctx: commands.Context, repo: Repo) -> None:
"""Show information about a repo."""
"""Show information about a repo.
Example:
- `[p]repo info 26-Cogs`
**Arguments**
- `<repo>` The name of the repo to show info about.
"""
made_by = ", ".join(repo.author) or _("Missing from info.json")
information = _("Repo url: {repo_url}\n").format(repo_url=repo.clean_url)
@@ -616,7 +654,19 @@ class Downloader(commands.Cog):
@repo.command(name="update")
async def _repo_update(self, ctx: commands.Context, *repos: Repo) -> None:
"""Update all repos, or ones of your choosing."""
"""Update all repos, or ones of your choosing.
This will *not* update the cogs installed from those repos.
Examples:
- `[p]repo update`
- `[p]repo update 26-Cogs`
- `[p]repo update 26-Cogs Laggrons-Dumb-Cogs`
**Arguments**
- `[repos...]` The name or names of repos to update. If omitted, all repos are updated.
"""
async with ctx.typing():
updated: Set[str]
@@ -642,15 +692,17 @@ class Downloader(commands.Cog):
@commands.group()
@checks.is_owner()
async def cog(self, ctx: commands.Context) -> None:
"""Cog installation management commands."""
"""Base command for cog installation management commands."""
pass
@cog.command(name="reinstallreqs")
@cog.command(name="reinstallreqs", hidden=True)
async def _cog_reinstallreqs(self, ctx: commands.Context) -> None:
"""
This command should not be used unless Red specifically asks for it.
This command will reinstall cog requirements and shared libraries for all installed cogs.
Red might ask user to use this when it clears contents of lib folder
Red might ask the owner to use this when it clears contents of the lib folder
because of change in minor version of Python.
"""
async with ctx.typing():
@@ -699,24 +751,48 @@ class Downloader(commands.Cog):
)
)
@cog.command(name="install", usage="<repo_name> <cogs>")
@cog.command(name="install", usage="<repo> <cogs...>", require_var_positional=True)
async def _cog_install(self, ctx: commands.Context, repo: Repo, *cog_names: str) -> None:
"""Install a cog from the given repo."""
"""Install a cog from the given repo.
Examples:
- `[p]cog install 26-Cogs defender`
- `[p]cog install Laggrons-Dumb-Cogs say roleinvite`
**Arguments**
- `<repo>` The name of the repo to install cogs from.
- `<cogs...>` The cog or cogs to install.
"""
await self._cog_installrev(ctx, repo, None, cog_names)
@cog.command(name="installversion", usage="<repo_name> <revision> <cogs>")
@cog.command(
name="installversion", usage="<repo> <revision> <cogs...>", require_var_positional=True
)
async def _cog_installversion(
self, ctx: commands.Context, repo: Repo, rev: str, *cog_names: str
self, ctx: commands.Context, repo: Repo, revision: str, *cog_names: str
) -> None:
"""Install a cog from the specified revision of given repo."""
await self._cog_installrev(ctx, repo, rev, cog_names)
"""Install a cog from the specified revision of given repo.
Revisions are "commit ids" that point to the point in the code when a specific change was made.
The latest revision can be found in the URL bar for any GitHub repo by [pressing "y" on that repo](https://docs.github.com/en/free-pro-team@latest/github/managing-files-in-a-repository/getting-permanent-links-to-files#press-y-to-permalink-to-a-file-in-a-specific-commit).
Older revisions can be found in the URL bar by [viewing the commit history of any repo](https://cdn.discordapp.com/attachments/133251234164375552/775760247787749406/unknown.png)
Example:
- `[p]cog installversion Broken-Repo e798cc268e199612b1316a3d1f193da0770c7016 cog_name`
**Arguments**
- `<repo>` The name of the repo to install cogs from.
- `<revision>` The revision to install from.
- `<cogs...>` The cog or cogs to install.
"""
await self._cog_installrev(ctx, repo, revision, cog_names)
async def _cog_installrev(
self, ctx: commands.Context, repo: Repo, rev: Optional[str], cog_names: Iterable[str]
) -> None:
if not cog_names:
await ctx.send_help()
return
commit = None
async with ctx.typing():
if rev is not None:
@@ -796,8 +872,8 @@ class Downloader(commands.Cog):
"\nYou can load them using {command_1}."
" To see end user data statements, you can use {command_2}."
).format(
command_1=inline(f"{ctx.clean_prefix}load <cogs>"),
command_2=inline(f"{ctx.clean_prefix}cog info <repo_name> <cog_name>"),
command_1=inline(f"{ctx.clean_prefix}load <cogs...>"),
command_2=inline(f"{ctx.clean_prefix}cog info <repo> <cog>"),
)
+ message
)
@@ -807,16 +883,21 @@ class Downloader(commands.Cog):
if cog.install_msg:
await ctx.send(cog.install_msg.replace("[p]", ctx.clean_prefix))
@cog.command(name="uninstall", usage="<cogs>")
@cog.command(name="uninstall", require_var_positional=True)
async def _cog_uninstall(self, ctx: commands.Context, *cogs: InstalledCog) -> None:
"""Uninstall cogs.
You may only uninstall cogs which were previously installed
by Downloader.
Examples:
- `[p]cog uninstall 26-Cogs defender`
- `[p]cog uninstall Laggrons-Dumb-Cogs say roleinvite`
**Arguments**
- `<cogs...>` The cog or cogs to uninstall.
"""
if not cogs:
await ctx.send_help()
return
async with ctx.typing():
uninstalled_cogs = []
failed_cogs = []
@@ -869,12 +950,18 @@ class Downloader(commands.Cog):
)
await self.send_pagified(ctx, message)
@cog.command(name="pin", usage="<cogs>")
@cog.command(name="pin", require_var_positional=True)
async def _cog_pin(self, ctx: commands.Context, *cogs: InstalledCog) -> None:
"""Pin cogs - this will lock cogs on their current version."""
if not cogs:
await ctx.send_help()
return
"""Pin cogs - this will lock cogs on their current version.
Examples:
- `[p]cog pin defender`
- `[p]cog pin outdated_cog1 outdated_cog2`
**Arguments**
- `<cogs...>` The cog or cogs to pin. Must already be installed.
"""
already_pinned = []
pinned = []
for cog in set(cogs):
@@ -898,12 +985,17 @@ class Downloader(commands.Cog):
message += _("\n{cog} was already pinned.").format(cog=already_pinned[0])
await self.send_pagified(ctx, message)
@cog.command(name="unpin", usage="<cogs>")
@cog.command(name="unpin", require_var_positional=True)
async def _cog_unpin(self, ctx: commands.Context, *cogs: InstalledCog) -> None:
"""Unpin cogs - this will remove update lock from cogs."""
if not cogs:
await ctx.send_help()
return
"""Unpin cogs - this will remove the update lock from those cogs.
Examples:
- `[p]cog unpin defender`
- `[p]cog unpin updated_cog1 updated_cog2`
**Arguments**
- `<cogs...>` The cog or cogs to unpin. Must already be installed and pinned."""
not_pinned = []
unpinned = []
for cog in set(cogs):
@@ -999,28 +1091,54 @@ class Downloader(commands.Cog):
@cog.command(name="update")
async def _cog_update(self, ctx: commands.Context, *cogs: InstalledCog) -> None:
"""Update all cogs, or ones of your choosing."""
"""Update all cogs, or ones of your choosing.
Examples:
- `[p]cog update`
- `[p]cog update defender`
**Arguments**
- `[cogs...]` The cog or cogs to update. If omitted, all cogs are updated.
"""
await self._cog_update_logic(ctx, cogs=cogs)
@cog.command(name="updateallfromrepos", usage="<repos>")
@cog.command(name="updateallfromrepos", require_var_positional=True)
async def _cog_updateallfromrepos(self, ctx: commands.Context, *repos: Repo) -> None:
"""Update all cogs from repos of your choosing."""
if not repos:
await ctx.send_help()
return
"""Update all cogs from repos of your choosing.
Examples:
- `[p]cog updateallfromrepos 26-Cogs`
- `[p]cog updateallfromrepos Laggrons-Dumb-Cogs 26-Cogs`
**Arguments**
- `<repos...>` The repo or repos to update all cogs from.
"""
await self._cog_update_logic(ctx, repos=repos)
@cog.command(name="updatetoversion", usage="<repo_name> <revision> [cogs]")
@cog.command(name="updatetoversion")
async def _cog_updatetoversion(
self, ctx: commands.Context, repo: Repo, rev: str, *cogs: InstalledCog
self, ctx: commands.Context, repo: Repo, revision: str, *cogs: InstalledCog
) -> None:
"""Update all cogs, or ones of your choosing to chosen revision of one repo.
Note that update doesn't mean downgrade and therefore revision
has to be newer than the one that cog currently has. If you want to
Note that update doesn't mean downgrade and therefore `revision`
has to be newer than the version that cog currently has installed. If you want to
downgrade the cog, uninstall and install it again.
See `[p]cog installversion` for an explanation of `revision`.
Example:
- `[p]cog updatetoversion Broken-Repo e798cc268e199612b1316a3d1f193da0770c7016 cog_name`
**Arguments**
- `<repo>` The repo or repos to update all cogs from.
- `<revision>` The revision to update to.
- `[cogs...]` The cog or cogs to update.
"""
await self._cog_update_logic(ctx, repo=repo, rev=rev, cogs=cogs)
await self._cog_update_logic(ctx, repo=repo, rev=revision, cogs=cogs)
async def _cog_update_logic(
self,
@@ -1139,9 +1257,17 @@ class Downloader(commands.Cog):
if updates_available and updated_cognames:
await self._ask_for_cog_reload(ctx, updated_cognames)
@cog.command(name="list", usage="<repo_name>")
@cog.command(name="list")
async def _cog_list(self, ctx: commands.Context, repo: Repo) -> None:
"""List all available cogs from a single repo."""
"""List all available cogs from a single repo.
Example:
- `[p]cog list 26-Cogs`
**Arguments**
- `<repo>` The repo to list cogs from.
"""
available_cogs = 0
installed = await self.installed_cogs()
installed_str = "\n".join(
@@ -1189,9 +1315,18 @@ class Downloader(commands.Cog):
for page in pagify(cogs, ["\n"], shorten_by=16):
await ctx.send(box(page.lstrip(" "), lang="diff"))
@cog.command(name="info", usage="<repo_name> <cog_name>")
@cog.command(name="info", usage="<repo> <cog>")
async def _cog_info(self, ctx: commands.Context, repo: Repo, cog_name: str) -> None:
"""List information about a single cog."""
"""List information about a single cog.
Example:
- `[p]cog info 26-Cogs defender`
**Arguments**
- `<repo>` The repo to get cog info from.
- `<cog>` The cog to get info on.
"""
cog = discord.utils.get(repo.available_cogs, name=cog_name)
if cog is None:
await ctx.send(
@@ -1447,14 +1582,14 @@ class Downloader(commands.Cog):
_("\nEnd user data statements of these cogs have changed: ")
+ humanize_list(tuple(map(inline, cogs_with_changed_eud_statement)))
+ _("\nYou can use {command} to see the updated statements.\n").format(
command=inline(f"{ctx.clean_prefix}cog info <repo_name> <cog_name>")
command=inline(f"{ctx.clean_prefix}cog info <repo> <cog>")
)
)
else:
message += _("End user data statements for {cog} have been changed.").format(
cog=tuple(cogs_with_changed_eud_statement)[0]
) + _("\nYou can use {command} to see the updated statements.\n").format(
command=inline(f"{ctx.clean_prefix}cog info <repo_name> <cog_name>")
command=inline(f"{ctx.clean_prefix}cog info <repo> <cog>")
)
if failed_cogs:
cognames = [cog.name for cog in failed_cogs]
@@ -1559,6 +1694,13 @@ class Downloader(commands.Cog):
"""Find which cog a command comes from.
This will only work with loaded cogs.
Example:
- `[p]findcog ping`
**Arguments**
- `<command_name>` The command to search for.
"""
command = ctx.bot.all_commands.get(command_name)